feat: allow T.const() variables used only in grid dims or computations - #2762
feat: allow T.const() variables used only in grid dims or computations#2762NolanHo wants to merge 6 commits into
Conversation
|
👋 Hi! Thank you for contributing to the TileLang project. Please remember to run We appreciate you taking this step! Our team will review your contribution, and we look forward to your awesome work! 🚀 |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe eager template matcher now retains ChangesConstexpr keyword support
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant TestKernelCall
participant TirTemplate
participant Phase2Matcher
participant CUDAKernel
TestKernelCall->>TirTemplate: create JIT kernel with T.const variables
TirTemplate->>Phase2Matcher: retain unmatched constexpr as __kwarg__
TestKernelCall->>Phase2Matcher: pass num_blocks and scale kwargs
Phase2Matcher->>CUDAKernel: resolve constexpr values and launch cached variant
CUDAKernel-->>TestKernelCall: produce output for assertions
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Constexpr variables declared via T.const() that are used only in grid dimensions (T.Kernel) or kernel-body computations (not in any buffer shape/stride) previously raised RuntimeError at template-creation time. The phase-2 value-resolution path (_parse_phase2_key) already supports resolving such variables via explicit keyword arguments at call time. This change records grid-only / computation-only constexpr vars with a sentinel source instead of raising, so they flow through the existing explicit-kwarg path. Closes tile-ai#2760
Tests that T.const() variables used only in grid dimensions or kernel-body computations are resolvable via explicit keyword arguments, plus a negative test that a missing kwarg raises a clear error.
17d5d2a to
88f9f03
Compare
|
@NolanHo Thanks for your contributions, but two comment left
import torch
import tilelang
import tilelang.language as T
@tilelang.jit
def copy_kernel(A, B):
N = T.const("N")
num_blocks = T.const("num_blocks")
A: T.Tensor((N,), T.float32)
B: T.Tensor((N,), T.float32)
with T.Kernel(num_blocks, threads=128) as bx:
B[bx] = A[bx]
def main() -> None:
A = torch.empty(4, dtype=torch.float32)
B = torch.empty_like(A)
try:
# Deliberately omit num_blocks. It is a kwarg-only constexpr and has no
# corresponding tensor argument from which TileLang could infer it.
copy_kernel(A, B)
except ValueError as error:
message = str(error)
print(message)
assert "Or provide the corresponding tensor argument `num_blocks`." in message
return
raise AssertionError("Expected a missing-constexpr ValueError")
if __name__ == "__main__":
main()the output is the
|
Problem
In eager (
@tilelang.jit) mode,T.const()is the only way to declare acompile-time symbolic variable resolved from tensor arguments at runtime.
TirTemplate.create()requires every such variable to appear directlyin some buffer's shape or stride, and raises otherwise:
This rules out two common patterns where a compile-time value is known at
call time but does not itself index a buffer — a grid-only variable (number
of CTAs) and a computation-only variable (e.g. a scale factor).
Closes #2760.
Solution
The phase-2 value-resolution path (
_parse_phase2_key) already supportsresolving a constexpr via an explicit keyword argument (
if name in kwargs),and the JIT argument binder (#2357) already routes extra kwargs into
compile_kwargs. The only thing blocking this path wascreate()raisingbefore the template was cached.
This PR replaces the raise with a sentinel entry so grid-only /
computation-only constexpr vars flow through the existing explicit-kwarg
path — no binder changes, no new code paths:
Value flow
Verification
Tested on 0.1.12 (wheel + source patch on the installed
builder.py,which is byte-identical to
main):test_const_grid_only—T.const("num_blocks")used only inT.Kernel(...), resolved vianum_blocks=4kwarg.test_const_computation_only—T.const("scale")used only in kernel body, resolved viascale=3.test_const_mixed— mix of shape-derived (N) and explicit-kwarg (num_blocks,scale).test_const_missing_kwarg_errors— omitting the kwarg raisesValueErrorwith a clear message.Note: I don't have a
mainsource build with CUDA locally, so verificationwas done by applying the source patch to the 0.1.12 wheel installation
(
builder.pyis identical between 0.1.12 andmain— 0 lines diff).Summary
T.const()constexpr variables used only for grid/kernel extent and/or inside kernel computations (i.e., not referenced by any buffer shape or stride) to be resolved via explicit call-time keyword arguments instead of being rejected duringTirTemplate.create().TirTemplate.create()to record such “missing from buffer shape/stride” constexpr variables into the template matcher using a"__kwarg__"sentinel (keyword-only substitution), so phase-2 matching/JIT argument binding can pull their values from provided**kwargs.#2760, including grid-only, computation-only, and mixed usage; cache isolation across different constexpr-kwarg configurations; float keyword handling; and a clear error when a required constexpr keyword is omitted (“Cannot find value for constexpr variable”).Testing
testing/python/issue/test_tilelang_issue_2760.pywith CUDA-gated tests:test_const_grid_onlytest_const_computation_onlytest_const_mixedtest_const_pipelined_gemmtest_const_missing_kwarg_errorstest_const_cache_isolationtest_const_float_value