Posts

Showing posts from September, 2026

OpenXLA PR #49368: Why Raw Float Comparisons Corrupted GPU TopK

OpenXLA PR #49368 fixes a specialized GPU TopK kernel whose comparator did not implement the ordering promised by the source operation. The old comparator was: return lhs.key == rhs.key ? lhs.idx < rhs.idx : lhs.key > rhs.key; For ordinary finite values, this usually behaves like a descending stable sort. For NaNs, neither equality nor greater-than establishes an order. For signed zero, equality removes the distinction between +0 and -0 . That was enough to make the bespoke GPU kernel disagree with XLA’s sort-based TopK path. The same HLO operation could therefore produce different values and indices depending on whether its shape crossed the threshold for the optimized kernel. The patch bitcasts float32 and bfloat16 keys to unsigned integers, transforms those bits into a monotonic total-order key, and compares the integer keys instead. One shape boundary changed the meaning of TopK XLA has more than one way to implement TopK. For smaller or unsupported configurations, it can ...

ONNX Runtime PR #32807: Why Shared CUDA Arenas Corrupted Graph Replay

ONNX Runtime PR #32807 fixes a CUDA Plugin Execution Provider allocator whose ownership boundary was smaller than the lifetime of the addresses captured from it. The factory kept one BFC device arena for each GPU and returned that arena to every allocator request: environment shared allocator session A session B other sessions on the same GPU A session could capture a CUDA graph while its intermediate tensors occupied chunks from that arena. After capture, the session released those chunks through the normal allocator path. The captured graph still contained the same device addresses and used them during every replay. Because the arena was shared, another session could receive one of those apparently free chunks and write unrelated data into it. The first graph would later replay against an address whose contents or ownership had changed. The failure did not require an invalid pointer. Both sessions could hold valid allocations while silently interpreting the same storage as different ...

OpenXLA PR #49441: Why Cropping and Padding Could Not Be Added Together

OpenXLA PR #49441 fixes an algebraic rewrite that treated cropping as negative padding and then added it to a consumer’s window padding. That arithmetic preserved output shapes. It did not preserve values. The failing graph had this form: input → pad with a negative edge amount → reduce-window or convolution with positive window padding In XLA, a negative edge amount on pad removes elements from the tensor. It is a crop. The simplifier merged the two operations by adding their padding numbers. If the pad cropped one element and the consumer added one padding element on the same side, the amounts canceled to zero. The compiler then used the original input element where the source program required a padding value. The program remained valid and executable. It silently computed a different function. Positive padding can be merged by addition For ordinary nonnegative padding, the rewrite is natural. Suppose an input is padded with one zero on the left: [x0, x1, x2] ↓ [0, x0, x1, x...

JAX PR #40803: Why sinc Needed Exact Range Reduction Before Autodiff

JAX PR #40803 replaces the real-valued implementation of jnp.sinc with an additive range-reduction algorithm. The mathematical definition is familiar: sinc(x) = sin(pi × x) / (pi × x) Computing that expression literally is not numerically equivalent to evaluating the mathematical function. Multiplying by a floating-point approximation of pi loses the exact location of every nonzero integer root. For sufficiently large finite inputs, pi × x can overflow even though sinc(x) should remain finite and close to zero. Repeated automatic differentiation also magnifies small polynomial and cancellation errors that may be harmless in the primal value. The new implementation does not send the full input into sin(pi × x) . It writes each finite real input as: x = n + r where: n = round_to_even(x) r = x - n r is in [-0.5, 0.5] It then evaluates a higher-degree polynomial only on the small remainder and reconstructs the sign and scale of the original result. The old branch still multiplied the fu...

ONNX Runtime PR #32489: Why Concurrent Startup Could Leave a Dangling Allocator

 ONNX Runtime PR #32489 fixes an XNNPACK startup race that could leave the library holding a pointer to an allocator whose owner had been replaced. The trigger was concurrent first-time session creation. Separate execution providers reached the same process-wide allocator through an unsynchronized null check. Both could decide to create it, while XNNPACK retained the context supplied during initialization. The patch puts allocator creation, context publication, and xnn_initialize() inside one std::call_once callback. Its regression test starts in a fresh process, releases 32 competing calls together, and checks that XNNPACK can still allocate after the individual provider owners are gone. The pointer crossed an ownership boundary The XNNPACK adapter keeps two static objects in GetStoredAllocator() : static AllocatorPtr ort_allocator; static xnn_allocator xnn_allocator_wrapper_ = { ... }; The first is a shared owner of an ONNX Runtime allocator. The second is a C callback table co...

PyTorch PR #196901: Why torch.compile Accepted Invalid Length Hints

PyTorch PR #196901 repairs a difference between ordinary Python execution and torch.compile : Dynamo could return a raw __length_hint__() result that CPython would reject or replace with a default. A negative estimate could escape as a negative integer. A string could escape as a string. NotImplemented could become the answer instead of asking the caller to use its fallback value. The problem was in Dynamo's handling of a Python operation, before any optimized tensor kernel was needed. The patch adds argument conversion, result validation, fallback handling, and iterator-state support. It landed through PyTorch MergeBot on September 19, 2026. A documented exception remains for subclasses of TypeError . That boundary matters when assessing what the tests actually prove. A length estimate still has rules operator.length_hint(obj, default) first tries the object's actual length, then its __length_hint__() estimate, and finally the default. An estimate may differ from the numbe...

JAX PR #40814: Why select_n Returned a Value but Lost Its Gradient

JAX PR #40814 fixes a disagreement between selecting a value and sending its gradient back to the input that supplied it. For an out-of-range integer selector, the reviewed forward implementation of lax.select_n chooses an endpoint case. Its old reverse-mode rule instead looked for an exact match between the original selector and each valid case number. No match meant zero gradients for every case, including the one returned by the forward calculation. The patch clamps the selector inside the reverse rule. It also handles a single candidate directly, preventing a boolean selector from sending that rule into a nonexistent second case. There is an important API boundary: JAX documents out-of-range select_n behavior as implementation-defined. This change makes reverse-mode differentiation agree with the reviewed lowering; it does not establish a new public guarantee that invalid indices will always be clipped. A returned value with no apparent dependency The mismatch can be reduced to t...