From 3bf42c252c978f735914273b3ecc9991f7a5ef86 Mon Sep 17 00:00:00 2001 From: Joshua James Venter Date: Tue, 21 Apr 2026 13:34:29 +0200 Subject: [PATCH 1/4] . --- RFC-0053-assets/liger.png | Bin 0 -> 68959 bytes RFC-0053-assets/triton-tuts.png | Bin 0 -> 57617 bytes RFC-0053-user-kernel-fusion.md | 266 ++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 RFC-0053-assets/liger.png create mode 100644 RFC-0053-assets/triton-tuts.png create mode 100644 RFC-0053-user-kernel-fusion.md diff --git a/RFC-0053-assets/liger.png b/RFC-0053-assets/liger.png new file mode 100644 index 0000000000000000000000000000000000000000..d5457ce92f699fd82f1c29cf985f34ce8072e213 GIT binary patch literal 68959 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ʓ!uC+#O=owQGjjsti30_S07x4Xd}7g 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 I?f$F(19}tfbpQYW literal 0 HcmV?d00001 diff --git a/RFC-0053-assets/triton-tuts.png b/RFC-0053-assets/triton-tuts.png new file mode 100644 index 0000000000000000000000000000000000000000..18ba2e0fab33981eb1e937ea9814a2c1a15da6c1 GIT binary patch literal 57617 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 literal 0 HcmV?d00001 diff --git a/RFC-0053-user-kernel-fusion.md b/RFC-0053-user-kernel-fusion.md new file mode 100644 index 0000000..21fd7c0 --- /dev/null +++ b/RFC-0053-user-kernel-fusion.md @@ -0,0 +1,266 @@ +# Broaden Coverage of Fusion for User-Defined Triton Kernels + +Author: + +* Joshua James Venter (@jjvraw) + +## **Summary** + +Recently, support for user-defined kernel fusion in TorchInductor was added. +Current fusion legality checks are intentionally conservative. In turn, many +common operator patterns are rejected. Some of these restrictions may be relaxed +with incremental changes, while others require more substantial implementation. +For the latter, the approach is to extract index expressions with minimal +compilation overhead of custom kernels to reason about fusion more formally. + +The broad goal is to allow user-defined kernels to be reused as part of different +compositions, rather than authoring many fused variants for each. When surrounding +pointwise operations are left out of the kernel, Inductor can fuse them at compile +time, while the user retains explicit schedule control over the kernel's core computation. + +This RFC proposes a roadmap to incrementally broaden the coverage of fusion cases, and may +serve as a tracker as the work progresses. + +## **Background** + +Currently, user-defined kernel fusion is supported under the following conditions +([#173662](https://github.com/pytorch/pytorch/pull/173662/changes)): + +1. The user-kernel’s mutated / output buffer must operate on an empty tensor. + - The said buffer must be a non-atomic, single write-only buffer within the kernel body. +2. The user-kernel must only have one output. +3. The intermediary buffer layout must be equal. +4. The epilogue must be a unary pointwise operation, registered as a `SchedulerNode` in the scheduler. +5. The epilogue cannot introduce any additional load expressions. +6. Sanity checks for removing the intermediate buffer must be met. + - i.e. No other references to said buffer. + +Condition (4) implies (5), but (5) covers separate cases such as: +```python +user_kernel[GRID](out, …) +torch.tril(out) +``` + +Constraining the user kernel's fusion legality to empty tensors eliminates the need +to reason about index equality between the two kernels. When the epilogue inherits the +user kernel’s schedule, any unwritten inbound memory remains undefined after the epilogue. +Correctness then holds by the semantics of epilogue(UB) = UB . That is, while this may +introduce numerical differences between eager and compiled execution, such differences are +a consequence of undefined behaviour in the user’s code. + +Together this covers the common pattern: +```python +def kernel_wrapper(input_1, ...): + single_out = torch.empty(...) # or torch.empty_like(...) + ... + kernel[GRID](input_1, ..., single_out, ...) + return out +``` + +## **Motivation** +It is given that Triton kernels are used to optimise specific parts of a model’s computation, +either because generated kernels may be less efficient for a given operation, and/or to explicitly +control how operations are grouped/fused, rather than relying on torch.compile fusion heuristics. +The latter targets memory-bound operations. It follows that the user is then aware of the model's +compute profile and intentionally authors appropriate pre-fused kernels. However, in the case of +shared layer implementations, as seen in inference and training libraries, the assumption of a +known compute profile no longer exists. As a result, varied composed custom kernels are authored, +sacrificing cross-operator fusion unless the conditions above are met. + +For reference, among the inference serving libraries [vLLM](https://github.com/vllm-project/vllm) +and [SGLang](https://github.com/sgl-project/sglang), there are recent parallel discussions +addressing tension between compiling a model with external kernels and delegating kernel +generation to Inductor: + +- **vLLM** + - [#24629](https://github.com/vllm-project/vllm/issues/24629) - Observation that custom op boundaries + are too coarse, fusing cheaper pointwise ops (quants, RMSNorm) alongside heavy kernels (GEMM, attention), + causing missed fusions at the boundary. The solution is to expose these cheaper ops to the compiler and + either let Inductor handle fusion or pattern-match specific cases via a custom pass to a pre-fused kernel + variants. + - [Fusion `torch.compile` passes (docs)](https://docs.vllm.ai/en/stable/design/fusions/) - *“Model authors + write declarative, modular code that focuses on correctness... rather than rewriting the models, vLLM + custom passes rewrite the torch.fx graph.”* + - [#36066](https://github.com/vllm-project/vllm/issues/36066) - Corresponding issue tracker. + - https://github.com/vllm-project/vllm/issues/25179 + - https://github.com/vllm-project/vllm/issues/32358 +- **SGLang** + - [#21855](https://github.com/sgl-project/sglang/issues/21855) - Similar observation as vLLM: hand-written kernels + for memory-bound ops prevent cross-operator fusion, but propose an opposite approach. Rather than building compiler + passes around existing custom kernels, the proposed solution is to replace them entirely with Inductor-generated + fusions via an opt-in flag. The argument is that these are competitive with their hand-written counterparts, + and offer a more maintainable path forward. + - [#10118](https://github.com/sgl-project/sglang/issues/10118) - Promotes a custom fusion pass, similar to vLLM. + +Both converge to similar solutions of unwrapping pre-fused compute-bound kernels, exposing +memory-bound ops to Inductor, and using a custom fusion pass for the remaining patterns. +As Inductor-generated kernels become competitive for more patterns (the recent work done on +RMSNorm being one example [blog](https://pytorch.org/blog/sota-normalization-performance-with-torch-compile/)) +this is increasingly a viable path. Broadening fusion coverage for user-defined kernels is +a complementary alternative, for cases where the user wants to remain in control of the kernel's +schedule without paying for it in many fused variants. + + +The following cases are currently not supported: + +- Multi-output user kernels + - Any kernel writing multiple buffers, including forward kernels that + write to intermediate results to HBM for backwards pass. +- In-place user kernels + - Kernels whose output depends on defined values in the output + buffer, such as RoPE. +- Non-unary pointwise epilogues / Additional load expressions +- Prologue pointwise +- Reduction epilogues + - The canonical example being per-token / per-channel quant following a + normalisation kernel. + + +## **Proposed Implementation and Timeline** + +The strategy is to incrementally broaden fusion cases. + +### **Multi-Output User Kernel** +Registering a user kernel in the compute graph relies on two representations of the user kernel. +For buffer mutation tracking, the TTIR representation is flattened into a linear def-use chain, +then a simple upward traversal from read/write sinks to the kernel’s parameters is performed. +The Python AST of the kernel’s source is traversed both during initialisation and code generation +to locate all `tl.store` expressions. All downstream logic (legality checks, code generation) is +predicated on a single mutated buffer. + +Several changes are required to relax this. In the scheduler, the mutated buffer can no longer +be assumed. It must be resolved per fusion-pair candidate, as the intersection of the user kernel’s +writes and the epilogue’s reads. Fusion legality checks and intermediate buffer pruning must then +be operated on this resolved buffer. On the AST side, the single `tl.store` restriction can be lifted, +and the empty-tensor check must be deferred until the target buffer is known. During code generation, +each `tl.store` node must be attributed to its corresponding buffer so that the correct store +is rewritten with the fused epilogue’s variable. + +Resolving the intermediate buffer of fusion candidates is straightforward. However, bridging the output +buffer to the correct `tl.store` AST node is slightly more involved. During TTIR parsing, we may +retrieve the line number of each `tl.store` from Triton’s MLIR bindings. Then, during the upward +traversal, we attach it to a new dependency type, `UserTritonDep`, in place of `StarDep`. Finally, +during code generation, the line number serves as the canonical reference between the resolved +buffer’s `UserTritonDep` and its corresponding AST node, allowing the correct `tl.store` to be +located and rewritten. + +In summary, all fusion-specific legality checks are deferred from initialisation to scheduling, where the +fusion candidate pair is known. AST manipulation is deferred to code generation, where it is performed +if fusion proceeds. + +> There may be opinions about removing AST parsing/unparsing entirely. My initial implementation of +user-kernel fusion (prior to what's been landed) did not rely on AST and instead involved string +manipulation of the kernel source, which may be less stable. + +### **Multiple Epilogue Operations** +In the case of an epilogue representated as multiple `SchedulerNode`s or a `FusedSchedulerNode`, +the initialisation of `FusedExternTritonKernelSchedulerNode` needs to be refactored for either case. +Currently, `FusedExternTritonKernelSchedulerNode` only holds a single `SchedulerNode` as reference +to the epilogue. + +It is unlikely (TODO: be more precise here) that more than one `SchedulerNode` composes pointwise epilogue operations. +However, to support prologue and non-pointwise, dicussed later, this refactor is necessary. + +TODO: Code-generation + + +### **Symbolic Analysis** +Lifting certain constraints, namely the UB restriction (empty tensor), non-unary, pointwise +and epilogue only, requires reasoning about the kernel configuration and/or the iteration +space. + +Draft PR [#179149](https://github.com/pytorch/pytorch/pull/179149/changes) offers a +potential solution. That is, to extract the index expression in terms of the kernel's +configuration. As a tractable example, for the following kernel, + +```python +@triton.jit +def vec_add_kernel( + a_ptr, b_ptr, out_ptr, N, + BLOCK_SIZE: tl.constexpr, +): + pid = tl.program_id(0) + offset = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) + mask = offset < N + + a = tl.load(a_ptr + offset, mask=mask) + b = tl.load(b_ptr + offset, mask=mask) + + tl.store(out_ptr + offset, a + b, mask=mask) +``` + +We may extract the following: + +```python +# Reads +[ + UserTritonDep( + name="a_ptr", + index=i0 * BLOCK_SIZE + i1, + var_names=(i0, i1), + size=(GRID[0], BLOCK_SIZE), + ), + UserTritonDep( + name="b_ptr", + index=i0 * BLOCK_SIZE + i1, + var_names=(i0, i1), + size=(GRID[0], BLOCK_SIZE), + ), +] +# Writes +[ + UserTritonDep( + name="out_ptr", + index=i0 * BLOCK_SIZE + i1, + var_names=(i0, i1), + size=(GRID[0], BLOCK_SIZE), + ), +], +``` +where the `GRID`, `BLOCK_SIZE` is resolved at compile time. + +At a high level, we recurse through the flattened TTIR building the index expression +while encountering pointer arithmetic operations. We mint symbols when encountering +appropriate leaves (`tt.get_program_id`, `tt.make_range`). A recursion cache is +maintained, keying on both the operation's index and the current "shape". This memoises the +traversal, but more importantly provides semantics for our iteration symbols/bounds. +When encountering a shape-context op (e.g. `tt.expand_dims`, `tt.broadcast`, `tt.reshape`) +the shape key changes, allowing a new axis/symbol bound to be minted. +For loop-carried pointer arithmetic, expression simplifications and the full implementation +ill defer to the [PR's description](https://github.com/pytorch/pytorch/pull/179149#issue-4195425124). + + +As a measure of the added compilation overhead, the following benchmarks +`identify_accesses_tensor` against upstream across a selection of kernels from Liger and +the [Triton tutorials](https://triton-lang.org/main/getting-started/tutorials/). + +![liger](RFC-0053-assets/liger.png) +![triton-tuts](RFC-0053-assets/triton-tuts.png) + +Downstream usage of these extracted index expressions requires reasoning beyond just +the syntactic equality of expressions. This arises from tension between `SchedulerNode`'s +expression, in terms of shapes and strides, and the user kernel's, in terms of kernel +configuration. Typically, we would rely on tooling such as [ISL](https://www.jeremykun.com/2025/10/19/isl-a-primer/). +A more practical path is to extend Inductor's existing `sizevar`, to bridge the two +expression domains. + + +#### UB Restriction + + +#### Non-unary Pointwise Epilogues + + +#### Persistent Reduction Epilogues + + +#### Prologue Fusion + + +## **Metrics** + + +## **Drawbacks and Alternatives** + + +## **Unresolved Questions** From 9e39933d56e665a2d53669d71e0dfc8fcc3eca80 Mon Sep 17 00:00:00 2001 From: Joshua James Venter Date: Tue, 21 Apr 2026 17:40:41 +0200 Subject: [PATCH 2/4] . --- RFC-0053-user-kernel-fusion.md | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/RFC-0053-user-kernel-fusion.md b/RFC-0053-user-kernel-fusion.md index 21fd7c0..fecd946 100644 --- a/RFC-0053-user-kernel-fusion.md +++ b/RFC-0053-user-kernel-fusion.md @@ -229,7 +229,6 @@ the shape key changes, allowing a new axis/symbol bound to be minted. For loop-carried pointer arithmetic, expression simplifications and the full implementation ill defer to the [PR's description](https://github.com/pytorch/pytorch/pull/179149#issue-4195425124). - As a measure of the added compilation overhead, the following benchmarks `identify_accesses_tensor` against upstream across a selection of kernels from Liger and the [Triton tutorials](https://triton-lang.org/main/getting-started/tutorials/). @@ -241,20 +240,32 @@ Downstream usage of these extracted index expressions requires reasoning beyond the syntactic equality of expressions. This arises from tension between `SchedulerNode`'s expression, in terms of shapes and strides, and the user kernel's, in terms of kernel configuration. Typically, we would rely on tooling such as [ISL](https://www.jeremykun.com/2025/10/19/isl-a-primer/). -A more practical path is to extend Inductor's existing `sizevar`, to bridge the two -expression domains. +A more practical path is to extend Inductor's existing `sizevars` / `SizeVarAllocator`, +to bridge between the two expression domains. + +#### In-place Kernels (non-empty mutated buffer) +For kernels operating on non-empty tensors, we may formally reason about index +expression / quasi-affine map equality. For unary pointwise epilogues, the compute/arithmetic +operations inherit the user kernel's schedule. Thus, loop order is not a concern in this case. +Typically, we would need to prove both injectivity of the write, and coverage in relation +to the read. In Triton, we assume we have injectivity for all non-atomic writes. +In any other case, the kernel will have undefined behaviour. +For coverage, without using the mask as a constraint on the domain, we normalise both index +expressions and assert both syntactic equality of expressions and such that the bounds of the +remaining symbols of the user-kernel are at least as large as the epilogue's. This will require +the normalisation in `sizevars` to be complete for this new class of expressions. -#### UB Restriction +> TODO: Normalisation here would be sound and complete for constant divisors. #### Non-unary Pointwise Epilogues -#### Persistent Reduction Epilogues +#### Pointwise Prologue Fusion -#### Prologue Fusion +#### Persistent Reduction Epilogues ## **Metrics** @@ -262,5 +273,3 @@ expression domains. ## **Drawbacks and Alternatives** - -## **Unresolved Questions** From d3c88621e7dafa29f553e328cddefae1ba441810 Mon Sep 17 00:00:00 2001 From: Joshua James Venter Date: Thu, 23 Apr 2026 17:42:04 +0200 Subject: [PATCH 3/4] reference refactor --- RFC-0053-user-kernel-fusion.md | 48 +++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/RFC-0053-user-kernel-fusion.md b/RFC-0053-user-kernel-fusion.md index fecd946..28f9979 100644 --- a/RFC-0053-user-kernel-fusion.md +++ b/RFC-0053-user-kernel-fusion.md @@ -124,33 +124,33 @@ The strategy is to incrementally broaden fusion cases. Registering a user kernel in the compute graph relies on two representations of the user kernel. For buffer mutation tracking, the TTIR representation is flattened into a linear def-use chain, then a simple upward traversal from read/write sinks to the kernel’s parameters is performed. -The Python AST of the kernel’s source is traversed both during initialisation and code generation -to locate all `tl.store` expressions. All downstream logic (legality checks, code generation) is -predicated on a single mutated buffer. - -Several changes are required to relax this. In the scheduler, the mutated buffer can no longer -be assumed. It must be resolved per fusion-pair candidate, as the intersection of the user kernel’s -writes and the epilogue’s reads. Fusion legality checks and intermediate buffer pruning must then -be operated on this resolved buffer. On the AST side, the single `tl.store` restriction can be lifted, -and the empty-tensor check must be deferred until the target buffer is known. During code generation, -each `tl.store` node must be attributed to its corresponding buffer so that the correct store -is rewritten with the fused epilogue’s variable. - -Resolving the intermediate buffer of fusion candidates is straightforward. However, bridging the output -buffer to the correct `tl.store` AST node is slightly more involved. During TTIR parsing, we may -retrieve the line number of each `tl.store` from Triton’s MLIR bindings. Then, during the upward -traversal, we attach it to a new dependency type, `UserTritonDep`, in place of `StarDep`. Finally, -during code generation, the line number serves as the canonical reference between the resolved -buffer’s `UserTritonDep` and its corresponding AST node, allowing the correct `tl.store` to be -located and rewritten. - -In summary, all fusion-specific legality checks are deferred from initialisation to scheduling, where the -fusion candidate pair is known. AST manipulation is deferred to code generation, where it is performed -if fusion proceeds. +The Python AST is traversed both at initialisation and during code generation to locate `tl.store` +expressions. During `UserDefinedTritonKernel` initialisation, a kernel-level `can_fuse_epilogue` +flag is set, derived from information from both the TTIR and AST traversals. All downstream logic +(additional legality checks, code generation) is then predicated on a single mutated buffer. +To support multi-output kernels, where a single output may have a fused epilogue, all fusion legality +checks must be deferred until the fusion candidate pair is known. The AST traversal during code +generation locates the `tl.store` AST node, and replaces it with the fused epilogue's computational +results. + +[#181138](https://github.com/pytorch/pytorch/pull/181138) is a NFC refactor for cleaner seperation. +TTIR parsing gathers buffer access information, AST traversal is deferred to code generation, +and all fusion legality checks are consolidated to the scheduler. Single `tl.store` kernels remain +the only supported case. + +Building ontop these changes, for multi-output kernels, the target buffer may be resolved as the +intersection of the user kernel's writes and epilogue's read. Bridging the resolved buffer to the +correct `tl.store` AST node during code generation is more involved. The AST contains multiple +`tl.store` nodes, so naive traversal cannot identify which node corresponds to the fused buffer when +rewriting the kernel. During TTIR parsing, we may retrieve the line number of each `tl.store` from +Triton’s MLIR bindings. Then, during the upward traversal of the flattened def-use chain, we store it +to the corresponding dependency, `UserTritonDep` (introduced in [#181138](https://github.com/pytorch/pytorch/pull/181138)). +Finally, during code generation, the line number serves as the canonical reference between the resolved buffer’s +`UserTritonDep` and its corresponding AST node, allowing the correct `tl.store` to be located and rewritten. > There may be opinions about removing AST parsing/unparsing entirely. My initial implementation of user-kernel fusion (prior to what's been landed) did not rely on AST and instead involved string -manipulation of the kernel source, which may be less stable. +manipulation of the kernel source, which may be hacky/less stable. ### **Multiple Epilogue Operations** In the case of an epilogue representated as multiple `SchedulerNode`s or a `FusedSchedulerNode`, From ae9cc95f9184b31445947c8759c079eb6168f81e Mon Sep 17 00:00:00 2001 From: Joshua James Venter Date: Fri, 24 Apr 2026 11:45:47 +0200 Subject: [PATCH 4/4] . --- RFC-0053-user-kernel-fusion.md | 242 ++++++++++++++++++++++++++++++--- 1 file changed, 222 insertions(+), 20 deletions(-) diff --git a/RFC-0053-user-kernel-fusion.md b/RFC-0053-user-kernel-fusion.md index 28f9979..9f6afe4 100644 --- a/RFC-0053-user-kernel-fusion.md +++ b/RFC-0053-user-kernel-fusion.md @@ -227,7 +227,189 @@ traversal, but more importantly provides semantics for our iteration symbols/bou When encountering a shape-context op (e.g. `tt.expand_dims`, `tt.broadcast`, `tt.reshape`) the shape key changes, allowing a new axis/symbol bound to be minted. For loop-carried pointer arithmetic, expression simplifications and the full implementation -ill defer to the [PR's description](https://github.com/pytorch/pytorch/pull/179149#issue-4195425124). +i'll defer to the [PR's description](https://github.com/pytorch/pytorch/pull/179149#issue-4195425124). + +See the below examples of kernels (grouped matmul and normalisation) and their extracted +index expressions. + +
+Examples + +#### Grouped MatMul + +```python +# Kernel adapted from: +# https://triton-lang.org/main/getting-started/tutorials/03-matrix-multiplication.html +@triton.jit +def grouped_matmul( + a_ptr, + b_ptr, + c_ptr, + M, + N, + K, + stride_am, + stride_ak, + stride_bk, + stride_bn, + stride_cm, + stride_cn, + BLOCK_SIZE_M: tl.constexpr, + BLOCK_SIZE_N: tl.constexpr, + BLOCK_SIZE_K: tl.constexpr, + GROUP_SIZE_M: tl.constexpr, +): + pid = tl.program_id(axis=0) + num_pid_m = tl.cdiv(M, BLOCK_SIZE_M) + num_pid_n = tl.cdiv(N, BLOCK_SIZE_N) + num_pid_in_group = GROUP_SIZE_M * num_pid_n + group_id = pid // num_pid_in_group + first_pid_m = group_id * GROUP_SIZE_M + group_size_m = min(num_pid_m - first_pid_m, GROUP_SIZE_M) + pid_m = first_pid_m + ((pid % num_pid_in_group) % group_size_m) + pid_n = (pid % num_pid_in_group) // group_size_m + + tl.assume(pid_m >= 0) + tl.assume(pid_n >= 0) + tl.assume(stride_am > 0) + tl.assume(stride_ak > 0) + tl.assume(stride_bn > 0) + tl.assume(stride_bk > 0) + tl.assume(stride_cm > 0) + tl.assume(stride_cn > 0) + + offs_am = (pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M)) % M + offs_bn = (pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N)) % N + offs_k = tl.arange(0, BLOCK_SIZE_K) + a_ptrs = a_ptr + ( + offs_am[:, None] * stride_am + offs_k[None, :] * stride_ak + ) + b_ptrs = b_ptr + ( + offs_k[:, None] * stride_bk + offs_bn[None, :] * stride_bn + ) + + accumulator = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32) + for k in range(tl.cdiv(K, BLOCK_SIZE_K)): + a = tl.load( + a_ptrs, mask=offs_k[None, :] < K - k * BLOCK_SIZE_K, other=0.0 + ) + b = tl.load( + b_ptrs, mask=offs_k[:, None] < K - k * BLOCK_SIZE_K, other=0.0 + ) + accumulator = tl.dot(a, b, accumulator) + + a_ptrs += BLOCK_SIZE_K * stride_ak + b_ptrs += BLOCK_SIZE_K * stride_bk + + c = accumulator.to(tl.float16) + + offs_cm = pid_m * BLOCK_SIZE_M + tl.arange(0, BLOCK_SIZE_M) + offs_cn = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N) + c_ptrs = c_ptr + stride_cm * offs_cm[:, None] + stride_cn * offs_cn[None, :] + c_mask = (offs_cm[:, None] < M) & (offs_cn[None, :] < N) + tl.store(c_ptrs, c, mask=c_mask) +``` + +**Reads & Writes** + +```python +# Reads +UserTritonDep( + name='a_ptr', + index=4096*i3 + i4 + 32*i5 + 262144*(PythonMod(i0, 8)), + var_names=(i0, i3, i4, i5), + size=(512, 64, 32, 128), + mask=None +) + +UserTritonDep( + name='b_ptr', + index=131072*i5 + 4096*i6 + i7 + 64*((i0//8)), + var_names=(i0, i5, i6, i7), + size=(512, 128, 32, 64), + mask=None +) + +# Writes +UserTritonDep( + name='c_ptr', + index=4096*i1 + i2 + 64*((i0//8)) + 262144*(PythonMod(i0, 8)), + var_names=(i0, i1, i2), + size=(512, 64, 64), + mask=None +) + +``` +#### Normalisation + +```python +@triton.jit +def normalization_fwd( + X, + X_row_stride: tl.constexpr, + Y, + Y_row_stride: tl.constexpr, + W, + r, + r_row_stride: tl.constexpr, + n_cols_X: tl.constexpr, + eps: tl.constexpr, + BLOCK_SIZE: tl.constexpr, +): + row_idx = tl.program_id(0) + col_offsets = tl.arange(0, BLOCK_SIZE) + mask = col_offsets < n_cols_X + + X += row_idx * X_row_stride + Y += row_idx * Y_row_stride + r += row_idx * r_row_stride + + X_row = tl.load(X + col_offsets, mask=mask, other=0).to(tl.float32) + W_row = tl.load(W + col_offsets, mask=mask, other=0).to(tl.float32) + + row_var = tl.sum(X_row * X_row, axis=0) / n_cols_X + inv_var = tl.math.rsqrt(row_var + eps) + tl.store(r, inv_var) + + normed = X_row * inv_var * W_row + tl.store(Y + col_offsets, normed.to(X_row.dtype), mask=mask) +``` + +**Reads & Writes** + +```python +# Reads +UserTritonDep( + name='X', + index=4096*i1 + i2, + var_names=(i1, i2), + size=(512, 4096), +) + +UserTritonDep( + name='W', + index=i2, + var_names=(i2,), + size=(4096,), +) + +# Writes +UserTritonDep( + name='Y', + index=4096*i1 + i2, + var_names=(i1, i2), + size=(512, 4096), +) + +UserTritonDep( + name='r', + index=i0, + var_names=(i0,), + size=(512,), +) +``` +
+ As a measure of the added compilation overhead, the following benchmarks `identify_accesses_tensor` against upstream across a selection of kernels from Liger and @@ -237,35 +419,53 @@ the [Triton tutorials](https://triton-lang.org/main/getting-started/tutorials/). ![triton-tuts](RFC-0053-assets/triton-tuts.png) Downstream usage of these extracted index expressions requires reasoning beyond just -the syntactic equality of expressions. This arises from tension between `SchedulerNode`'s -expression, in terms of shapes and strides, and the user kernel's, in terms of kernel -configuration. Typically, we would rely on tooling such as [ISL](https://www.jeremykun.com/2025/10/19/isl-a-primer/). +the structurual SymPy equality of expressions. This arises from tension between +`SchedulerNode`'s expression, in terms of shapes and strides, and the user kernel's, +in terms of kernel configuration. Typically, we would rely on tooling such as [ISL](https://www.jeremykun.com/2025/10/19/isl-a-primer/). A more practical path is to extend Inductor's existing `sizevars` / `SizeVarAllocator`, to bridge between the two expression domains. +#### In-place User Kernels (non-empty mutated buffer) +With Triton, we assume injectivity of the write for all non-atomic writes. In any other +case, the kernel will produce undefined behaviour for non-injective writes. Additionally, +for unary pointwise epilogues, the arithmetic operations inherit the user kernel's schedule. +Thus, loop order is not a concern. It follows that for fusion to be legal, we enforce +non-atomic writes, and need to prove at least equal coverage user's write in relation to the +read. In other words, the image of the `UserTritonDep` write index map contains the image of the +`MemoryDep` read index map. We may acheive this by comparing the normalised flattened bounds, +informally: -#### In-place Kernels (non-empty mutated buffer) -For kernels operating on non-empty tensors, we may formally reason about index -expression / quasi-affine map equality. For unary pointwise epilogues, the compute/arithmetic -operations inherit the user kernel's schedule. Thus, loop order is not a concern in this case. -Typically, we would need to prove both injectivity of the write, and coverage in relation -to the read. In Triton, we assume we have injectivity for all non-atomic writes. -In any other case, the kernel will have undefined behaviour. -For coverage, without using the mask as a constraint on the domain, we normalise both index -expressions and assert both syntactic equality of expressions and such that the bounds of the -remaining symbols of the user-kernel are at least as large as the epilogue's. This will require -the normalisation in `sizevars` to be complete for this new class of expressions. - -> TODO: Normalisation here would be sound and complete for constant divisors. +``` +flat_size(write) >= flat_size(read) +``` +For linear / affine `UserTritonDep` expression, e.g. the expression from `normalization_fwd` above, +normalising both expressions (`normalize_with_stride_order`, by merging loops) and comparing +structural equality coverage is sufficient. -#### Non-unary Pointwise Epilogues +For quasi-affine expressions, e.g. the expression related to `grouped_matmul` containing both +`PythonMod` and `FloorDiv`, requires linearising the expression first. This is achievable through +via convertions via the quoteint remainder theorem, similiar to MLIR's [`addLocalFloorDiv`](https://mlir.llvm.org/doxygen/classmlir_1_1presburger_1_1IntegerRelation.html#a98fc55bbe5ecfebc98eb2e4a7860e2a2) +and [`addLocalModulo`](https://mlir.llvm.org/doxygen/classmlir_1_1presburger_1_1IntegerRelation.html#a1d13523c706a90609cdea16f327d622c) +operations in [`mlir::presburger::IntegerRelation`](https://mlir.llvm.org/doxygen/classmlir_1_1presburger_1_1IntegerRelation.html). +`FloorDiv` and `PythonMod` expressions are replaced as linear integer contraints, resulting in +an affine expression. +Masks are restricted to the common `BinOp` case of simple out-of-bounds guards of the form `expr < N`, +under which the write's true image is exactly the buffer's valid range and the check remains sound. +More complex mask expressions are conservatively rejected. -#### Pointwise Prologue Fusion +Pointwise unary prologues, without introducing any additional load expressions, would follow the same +fusion legality constraints as described above. However, of course code generation would differ in that +the arithemtic operations are injected after the appropriate `tl.load`, and modification of the user kernel's +signature would have to be modified. +> Inductor's current existing expression normalisation handles quasi-affine forms that arise from +its own IR (`ModularIndexing`), but cannot generally handle the combinations that arise from user-defined +pid remappings, where the interaction between terms does no match Inductor's own decompositions. +This will require the normalisation in `sizevars` to be complete for this new class of expressions. -#### Persistent Reduction Epilogues +#### Additional Load and Store Expressions ## **Metrics** @@ -273,3 +473,5 @@ the normalisation in `sizevars` to be complete for this new class of expressions ## **Drawbacks and Alternatives** + +## Next Steps