Commit Graph
758 Commits
Author SHA1 Message Date
Lei Wang 85fd8fc2d3 [Refactor][Language] Make T.Kernel target-neutral with dialect-owned launch annotations (#3186)
* [Refactor][Language] Make T.Kernel target-neutral with dialect-owned launch annotations

T.Kernel is traced before the Target is known, yet it used to emit
threadIdx.* thread_binding loops with a hard-coded default of 128 threads.
That is a SIMT launch baked into the frontend: CPU lowering silently pinned
the thread index to 0 (so per-thread code computed 1/128 of the work), and
every backend inherited CUDA's launch vocabulary.

Split the launch into the part every target shares and the parts a backend
interprets:

- The frontend records the grid as blockIdx.* thread_binding loops (the
  program-index space all targets share) and reserves thread identities as
  `tx/ty/tz = tl.launch_thread_idx(axis)` Bind placeholders. `threads=`
  becomes the `tl.launch_threads` annotation on the tilelang_root block;
  the frontend no longer chooses a default.
- MaterializeKernelLaunch(lower_thread_binding, default_threads,
  unsupported_annotations) is where the target-dependent meaning is decided.
  SIMT backends rebind each placeholder as a threadIdx.* thread_extent over
  the same Var (extent from the annotation, else the backend default; the
  CUDA/ROCm/Metal/WebGPU pipelines pass 128). Backends without SIMT drop the
  placeholders and reject a body that references a thread index instead of
  miscomputing. Launch annotations a backend cannot honor (cluster_dims on
  cpu/rocm/metal/webgpu) are rejected here rather than ignored downstream.
- KernelLaunchFrame exposes grid_vars/grid_extents/thread_vars/
  thread_extents explicitly; get_thread_extent() raises at trace time when
  threads= was omitted, since only the backend knows the extent.
- Each language dialect owns its `Kernel` with explicit keyword parameters:
  cuda offers threads/prelude/cluster_dims, rocm/metal threads/prelude,
  webgpu threads, cpu prelude, and the common `Kernel(*grid)` none. All of
  them funnel into `tilelang.language.kernel.launch_kernel`. This is what
  editors show on hover and what type checkers verify; unknown keywords are
  rejected by Python itself. ClusterKernel keeps its interface.
- Cluster identity: `T.get_cluster_id/ids/dims/size/extent(s)` are
  program-space arithmetic (`bx // cluster_dims`) computed at trace time and
  therefore target-neutral, while `T.block_rank_in_cluster()` stays the
  CUDA hardware intrinsic. The two agree under the cluster-aware threadblock
  swizzle, which permutes the grid at cluster granularity.

Tests that applied passes directly to a traced function now materialize the
launch first (thread indices otherwise carry no extent), fixtures that wrote
per-thread code and compiled it for the `c` target are rewritten at the tile
level, and the span-preservation check asserts that no statement loses its
span rather than that the spanned count never decreases.

* [Fix][Language] Unwind kernel frames after tracing errors

Pass the active exception to the pending frame exits when tracing fails, so
the Python launch state (KernelLaunchFrame stack) is cleared without
finalizing incomplete TIR. Previously the next trace observed the failed
kernel's launch frame as KernelLaunchFrame.Current(). Covered for both the
prim_func and eager JIT tracing paths.

* [Fix][Language] Recognize every dialect's Kernel as a launch in the eager rewriter

Eager JIT phase 1 infers the signature with symbolic T.const values and must
not execute the kernel body; the AST rewriter guards `with T.Kernel(...)`
with `if __tb.skip_kernel_ctx(): return`. It found the launch by object
identity against the common `Kernel`, which no longer holds now that each
dialect (and the `tilelang.language` facade) exports its own `Kernel`: the
guard was not injected, phase 1 ran the body, and e.g. `T.gemm` on a tile
whose extent comes from `T.const` failed its static-shape check.

Mark every launch factory (`Kernel` of each dialect, `ClusterKernel`) with
`kernel_launch_factory` and let the rewriter test that mark instead. It now
resolves plain names and attribute chains only, so aliases such as
`K = T.Kernel` are recognized and no factory expression is executed at
rewrite time. Covered by a rewriter-level test over all dialects and an
end-to-end eager gemm whose tile extent depends on a const.
2026-09-10 17:33:50 +08:00
Yongqi Zhuo 752312c2a9 [Refactor] [CUDA] Rename AutoSchedule to AutoWarpSpecialization (#3185)
This avoids potential ODR violation against other backends.
2026-09-09 16:26:03 +08:00
Lei WangandClaude Fable 5 7525499330 [CUDA][Cache] Publish immutable binary cache directories (#3177)
* [CUDA][Cache] Publish immutable binary cache directories

* [Example] Drop stale torch JIT build locks in minference example

The vertical_slash_index extension builds into a cache directory shared
across CI runs. torch's FileBaton lock file is not tied to the owning
process, so a run cancelled mid-compile leaves it behind and every later
load() polls on it forever (hung CI at test_vs_sparse_attn). Guard the
build with an OS-level flock, which dies with its holder, and remove any
leftover FileBaton lock before invoking torch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-08 02:46:47 +08:00
Lei Wang e0e21ce646 [Layout] Consider scalar reducer plans in register-count search (#3171)
* [Layout] Consider scalar reducer plans in register-count search

* [Layout] Pass scalar plan limit through inference args

* [Layout] Clarify candidate limits and isolate attempt queues
2026-09-07 13:32:20 +08:00
Ziming Wang c63a2e7050 [BugFix][Transform] Keep shared FP32 atomics scalar on SM90 (#3129)
* [BugFix][Transform] Keep shared FP32 atomics scalar on SM90

Signed-off-by: ZenAlexa <zimingwang945@gmail.com>

* [Testing] Pin scalar atomic loop structure

Signed-off-by: ZenAlexa <zimingwang945@gmail.com>

* [Testing] Exercise lowered access_ptr atomics in vectorizer

Signed-off-by: ZenAlexa <zimingwang945@gmail.com>

---------

Signed-off-by: ZenAlexa <zimingwang945@gmail.com>
2026-09-07 11:37:13 +08:00
Rishabh Sinha 11ec2397fe [Cache] Store cached kernel params as JSON instead of cloudpickle (#3143)
The kernel cache and the autotuner result cache loaded params.pkl with
cloudpickle.load(), so a writable cache directory allowed arbitrary code
execution on the next cache hit. Kernel params are plain data, so store
them as JSON via TVM's reflection (tvm.ir.save_json / load_json), which
rebuilds IR nodes without executing code. Entries without params.json are
treated as incomplete and rebuilt.

Fixes #2817
2026-09-06 16:06:20 +08:00
andyluo7 479b9f6bd0 [ROCm] Support wave64 Hadamard transforms (#3154)
* [ROCm] Support wave64 Hadamard transforms

Signed-off-by: andyluo7 <andy.luo@amd.com>

* [ROCm] Derive Hadamard wave size from target

Signed-off-by: andyluo7 <andy.luo@amd.com>

* [ROCm] Fail closed on unknown wave size

Signed-off-by: andyluo7 <andy.luo@amd.com>

* [ROCm] Serialize Hadamard device validation

Signed-off-by: andyluo7 <andy.luo@amd.com>

* [ROCm] Use portable shuffle intrinsic for Hadamard

Signed-off-by: andyluo7 <andy.luo@amd.com>

* [ROCm] Fix Hadamard shuffle argument order

Signed-off-by: andyluo7 <andy.luo@amd.com>

* [ROCm] Isolate Hadamard dimension coverage

Signed-off-by: andyluo7 <andy.luo@amd.com>

---------

Signed-off-by: andyluo7 <andy.luo@amd.com>
2026-09-06 14:14:25 +08:00
Chaofan LinandLeiWang1999 1a1df62e94 [Language] Remove deprecated T.symbolic alias (#3122)
* [Cleanup] Remove stale deprecation deadlines

* [Language] Remove deprecated T.symbolic alias

---------

Co-authored-by: LeiWang1999 <leiwang1999@outlook.com>
2026-09-04 23:56:52 +08:00
Yongqi ZhuoandLeiWang1999 ccb48c39fb [Feature] [CUDA] Role-based automatic warp specialization (#3059)
* [Feature] [CUDA] Role-based automatic warp specialization

* Address review concerns

* Allocate registers more precisely

* Address reviewer concerns

---------

Co-authored-by: LeiWang1999 <leiwang1999@outlook.com>
2026-09-04 17:22:32 +08:00
Ziming Wang c9192939ce [CUDA] Add async-proxy fences for sparse MMA intrinsics (#3139)
* fix(cuda): classify sparse MMA intrinsics as async proxy operations

* test(cuda): assert sparse proxy fence placement
2026-09-04 14:50:02 +08:00
Rishabh Sinha bdbf32acf9 [Bugfix][Language] Support unary plus on PrimExpr in the eager frontend (#3141)
PrimExpr overloads unary minus and invert but not unary plus, so
`Out[i] = +A[i]` raised TypeError at trace time. Route unary plus through
the builder, the same way `not` already is, and return PrimExpr operands
unchanged; Python values keep their native unary plus.

Fixes #2991
2026-09-04 14:49:09 +08:00
Chennes 0f13a2c548 [CUDA] Add 16-bit hpow and hfmod bridges (#3163)
CUDA lowering emits hpow and hfmod for 16-bit pow and fmod, but no CUDA
toolkit declares either name, so fp16/bf16 fmod and variable-exponent
fp16 pow fail to compile. Integer-exponent pow is unaffected: TileLang
expands it into repeated multiplication before lowering.

Add half_t and bfloat16_t overloads that evaluate with powf or fmodf in
float32 and convert back, matching the existing bridge pattern. Remove
math.h's hpow-to-powf macro: it shadows the new overload at the call
site, and compiles only where the result is assigned directly.

Add codegen and numerical coverage for fp16 pow and both fmod dtypes.
The bfloat16 hpow bridge completes the backend layer, while T.pow on
bfloat16 remains blocked by an upstream TVM dtype check.
2026-09-03 23:14:49 +08:00
Lei Wang e07bd1d009 [Refactor][CUDA] Replace per-lane-count vector constructors with variadic packers (#3158)
* [BugFix][Blackwell] Fix 256-bit vectorized codegen for fp4/int4/fp16

256-bit vectorization (sm_100+) broke nvcc compilation for several
packed dtypes because every (dtype x lanes) combination relied on
hand-written per-type glue:

- fp4 x 64 lanes: predicated copy materializes a typed vector temporary,
  which needs `fp4_e2_64_t::operator=(ulonglong4)` (never defined; the
  operator was copy-pasted onto the 128-bit fp4_e2_32_t with a broken
  body) and `make_fp4_e2_64_t` (constructors stop at 32 lanes).
- int4/uint4 x 64 lanes: PrintType emitted the nonexistent CUDA type
  `(u)int8`, and the packed-nibble broadcast only handled 16/32 lanes.
- fp16 x 16 lanes: broadcast calls tl::pack_float16x4 whose parameters
  were `__half`, but codegen prints fp16 scalars as cutlass::half_t
  (the bf16 variant already took bfloat16_t).

Instead of patching each cell, make the contracts generic:

- tl::load_global_256 / _conditional now return the pointee type
  (static_assert sizeof == 32) and bit-cast internally, so assignment
  type-checks for any 32-byte vector struct. The hand-written
  operator=(ulonglong4) on fp8_e{4,5,8}_32_t become dead and are
  removed, along with the misplaced fp4_e2_32_t one. The T.ldg256
  builtin keeps its uint32x8 result via an explicit ulonglong4 cast.
- New tl::broadcast<V>(unit) replicates a packed unit across any vector
  width; fp4 broadcast now emits one packed fp4x2 byte + tl::broadcast
  for every lane count instead of a 64-arg make_ call.
- int4x64 maps to (u)longlong4 (like int8x32) and its broadcast packs
  two 8-nibble fields per 64-bit component.

Adds a compile matrix test (12 dtypes x {copy, predicated copy, fill}
x {128b, 256b}) plus numeric checks for the previously broken cells, so
the next dtype/width gap fails in CI instead of on a user's machine.
On < sm_100 targets the 256b params compile at 128 bits and stay green.

* [Refactor][CUDA] Replace per-lane-count vector constructors with variadic packers

Follow-up to #3153: the make_<type>_<N>_t constructor ladders (5 for fp4,
15 for fp8) and several BroadcastNode special cases enumerated the same
(dtype x lanes) matrix by hand, so every new dtype or vector width needed
more glue. Replace the enumeration with two generic templates:

- tl::make_vec<V>(e0, e1, ...): builds a vector struct from one scalar
  element per lane (byte-sized or larger elements).
- tl::make_fp4_vec<V>(e0, e1, ...): same for nibble-packed fp4.

and route the codegen through them:

- PrintVecConstructor emits tl::make_fp4_vec<V> / tl::make_vec<V> for
  fp4/fp8 vectors, covering the Shuffle and element-wise assembly paths
  (whose previous output for these types did not even compile).
- fp8 and int8 broadcasts of side-effect-free values emit
  tl::broadcast<carrier>(byte) instead of per-lane make_ calls; the int4
  16/32/64-lane packed broadcasts collapse into a single
  tl::broadcast branch.
- Side-effecting broadcast values (e.g. casts of rng calls) keep their
  evaluate-once-per-lane semantics: they fall through to the generic
  per-lane path, guarded via tirx::SideEffect. The int32 rng broadcast
  path and the fp16/bf16/f32x8 paths are intentionally untouched.

The make_fp4_e2_{2..32}_t and make_fp8_{e4,e5,e8}_{2..32}_t ladders are
deleted; the char-packing make_int* overloads in common.h stay because
the int8 Shuffle path still assembles vectors element-wise.

Verified on sm_103a: the 12-dtype x 3-op x 2-width compile matrix stays
green, new numeric tests cover non-constant fp4/fp8/int8 scalar fills,
and the ldg/ldst/vectorize/vectorized_cast/quantize suites pass
(228 tests) with TILELANG_DISABLE_CACHE=1.

* [Test] Update issue #2480 assertions for the tl::broadcast emission

The int8x32 broadcast is now emitted as tl::broadcast<(u)longlong4>(byte)
instead of make_(u)longlong4 with 32 scalar args; the exact-value checks
that guard the original issue (upper 32 bits of each field zeroed) are
unchanged.
2026-09-03 23:01:35 +08:00
Mocus Zhang 73bbff582d [BugFix][Carver] Compare sm_version numerically in plan_rasterization (#3144)
plan_rasterization compared the runtime compute-capability string lexicographically. That classified sm_100 and sm_120 as older than sm_80 and disabled rasterization on Blackwell targets.

Use the target-derived integer sm_version for CUDA targets while preserving existing non-CUDA behavior. Cover pre-Ampere, Ampere-and-newer, L2-fit, and non-CUDA cases without requiring a GPU.
2026-09-03 15:51:32 +08:00
Rishabh Sinha e155c440b3 [Bugfix][Language] Reject loop else clauses in the eager frontend (#3142)
`for ... else` and `while ... else` inside a kernel traced without error
while the `else` body was silently dropped from the IR. Raise a clear
NotImplementedError from the AST rewriter instead; `if ... else` is
unaffected.

Fixes #2946
2026-09-03 13:44:09 +08:00
andyluo7 f60fedf8a8 [ROCm] Support DeepSeek-V3.2 Top-K selector (#3147) 2026-09-03 12:49:52 +08:00
andyluo7 f797c02a3c [ROCm] Validate attention sink kernels (#3148) 2026-09-03 12:48:39 +08:00
andyluo7 c561bfa2b9 [ROCm] Validate block-causal attention kernels (#3146)
[ROCm] Validate block-causal attention
2026-09-03 12:33:28 +08:00
Mocus Zhangandcoderabbitai[bot] a0a478523b [BugFix][Carver] Gate _legalize_info fallback on sm_version (#3145)
* [BugFix][Carver] Gate _legalize_info fallback on sm_version

TensorCorePolicy._legalize_info compared the bare compute-capability values reported by CUDA against sm_-prefixed literals. The fallback therefore selected one pipeline stage and disabled asynchronous copies even for SM 80 and SM 90.

Gate the fallback on the normalized numeric sm_version while preserving non-CUDA behavior. Keep the membership at {80, 90}, matching the existing matmul_analysis tag path; do not enable targets above SM 90 without real-machine validation of the pipeline and asynchronous-copy effects.

Constraint: No GPU above SM 90 was available for functional or performance validation, so the supported fallback set remains {80, 90}.
Rejected: Broaden the fallback to additional SM versions | It would exceed the existing tag-path policy, and above-SM-90 behavior has not been validated on hardware.
Confidence: high
Scope-risk: narrow
Directive: Keep fallback and tag-path SM membership aligned until additional architectures have real-machine evidence.
Tested: Ruff check and format; Python syntax compilation; 10-case _legalize_info source behavior harness.

* Apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-09-03 12:30:17 +08:00
Diao Han 2c31e071c6 [BugFix][Hopper][Blackwell] Read the WGMMA/UMMA K-panel stride from the layout instead of the operand extent (#2965)
* [BugFix][Hopper][Blackwell] Read the WGMMA/UMMA K-panel stride from the layout

A shared operand sliced along MN silently computed wrong results whenever
block_K spanned more than one swizzle atom:

    T.gemm(a_s, b_s[0:64, :], c0, transpose_B=True)   # wrong past the first K atom

When block_K exceeds one swizzle atom the shared layout splits K into panels
stored panel-major -- a (128, 128) bf16 tile decodes as
(128,(64,2)):(64,(1,8192)) -- so stepping to the next K panel moves by the
*buffer's* MN extent. The atom offset formulas instead reconstructed that step
as `mn_extent * swizzle_atom_elems` using the extent of the operand, which is
smaller for a slice. The slice origin was already layout-derived and correct, so
only K atoms past the first were affected: the two halves of a split buffer read
each other's rows, in bounds and without any diagnostic.

block_K == 64 was correct only by accident -- at 16-bit dtypes that is exactly
one 128B atom, so `ki // k_atom_size` is always zero and the bad multiplier was
multiplied away. MN-major operands never reach the term at all.

Take the panel stride from the decoded layout instead of reconstructing it:
cute.restrict already returns the sublayout carrying it, and slicing does not
change a stride. Expose it as `k_panel_elems` on WGMMADescriptorParams /
TCGEN05DescriptorParams, None when the layout has a single K panel or the
operand is MN-major -- exactly the cases where the term is multiplied by zero,
so those keep the previous expression and behaviour.

The same defect was duplicated across all seven atom emitters: dense Hopper
(ss/rs), sparse Hopper (ss/rs) and Blackwell (ss/ts/block-scaled).

Verified on H200 (sm_90a):

- Whole-buffer path is unchanged: across 120 K-major layouts (fp16/bf16/fp8_e4m3/
  fp32 x 5 MN extents x 6 K extents), k_panel_elems is either None or exactly
  equal to the old reconstruction, for both descriptor builders. The fix is a
  strict generalization of the path that already worked.
- New test_tilelang_kernel_gemm_sliced_operand.py cross-checks a sliced operand
  against one-buffer-per-slice over operand x majorness x block_K; it fails on
  the four K-major block_K>64 combinations before this change and passes after.
- A layout-level assertion covers the Blackwell descriptor, which has no numeric
  coverage here for lack of the hardware.

Closes #2964

* [BugFix][Hopper][Blackwell] Refuse a multi-panel K mode with no constant stride

Review follow-up on the K-panel stride decode.

The decode returned None whenever the K mode was not a canonical 2-tuple, and
every consumer then fell back to `mn_extent * swizzle_atom_elems` -- the exact
reconstruction this series removes. The fallback is only sound for a single-panel
layout, where `ki // k_atom_size` is always zero, and nothing checked that. So a
swizzled multi-panel layout that failed to decode would silently re-enter the
wrong-code path: the same shape as the original defect, where a formula's
precondition was assumed but never enforced.

Move the decode into a shared `decode_k_panel_elems` used by both descriptor
builders, and make it assert instead of returning None when a swizzled operand
spans more than one panel without exposing a constant panel stride. Panel count
is rounded up, so a K extent that is not a whole number of atoms cannot slip
through as single-panel.

Also tighten the accept condition: reading `stride[-1]` as the panel step is only
valid once the leading sub-mode is confirmed to be the contiguous atom. On a
panels-first `(2, atom):(panel_stride, 1)` ordering the old condition would have
returned 1 -- a silently wrong step rather than a refusal.

Consumers now read the step through `k_panel_stride(mn_extent)` on the params
dataclass, so the contract and its single-panel default live in one place
instead of being restated at eleven call sites.

New test_tilelang_cuda_wgmma_operand_layout.py covers the decode directly
(hardware-independent): canonical multi-panel strides, the single-panel and
MN-major None cases, and each refusal -- panels-first, flat multi-atom, a
three-sub-mode K, and a partial-atom extent.

Re-verified on H200: the whole-buffer invariant is unchanged by the tightening
(120 K-major layouts x 2 builders, 60 single-panel, 0 disagreements), every
multi-panel K slice is still accepted with the buffer-derived stride, and the
full suite set passes (174 passed, 40 skipped).
2026-09-02 18:13:38 +08:00
Jinpeng Wang 5265e1ddee [BugFix][CUDA] Support non-constant int4/uint4 broadcast (#3114)
* [BugFix][CUDA] Support non-constant int4/uint4 broadcast

* Address review concerns
2026-09-02 16:45:13 +08:00
Yongqi ZhuoandClaude Fable 5 a0a131908d [Refactor] Restore LoopUnswitching test altered by #3121 (#3124)
Refactor issue-1734 test: pin row-chunk layout to keep C_local[i] loop-invariant

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 16:24:45 +08:00
Chennes dd8643948d [CUDA] Complete 16-bit bridges for CUDA-lowered unary math (#3132)
16-bit lowering emits half-style names for sinh, cosh, tanh, atan, erf,
and nearbyint, but no CUDA overload of those names accepts CUTLASS
half_t or bfloat16_t. Most toolkits do not declare the names at all, and
the overloads that do exist take native __half or __nv_bfloat16, which
the wrappers have no implicit conversion to, so these operations fail
everywhere.

Add hsinh, hcosh, htanh, hatan, herf, and hnearbyint overloads for both
wrapper types. Each evaluates in float32 and converts back, following
the existing htan bridge. This completes 16-bit bridge coverage for the
unary floating-point operations that CUDA lowering already handles.

Extend the 16-bit intrinsics test kernel to cover all six operations.
2026-09-02 16:21:31 +08:00
Lei Wang 1a10fd8d87 [Language][CUDA] Add T.fma and T.fmul round-to-nearest intrinsics (#3134)
Introduce two CUDA-specific math intrinsics with guaranteed instruction
selection:

- T.fma(x, y, z): fused multiply-add whose fusion (single rounding) is
  guaranteed regardless of NVCC contraction settings.
- T.fmul(x, y): multiply with an explicit boundary that is never
  contracted into a neighbouring FMA.

Unlike the ieee_* family (which carries an explicit rounding mode and
stays scalar), both ops fix round-to-nearest and are marked
TVectorizable, so T.Parallel loops containing them keep their vectorized
loads/stores:

- scalar: __fmul_rn/__fmaf_rn (fp32), __dmul_rn/__fma_rn (fp64),
  __hmul_rn/__hfma (fp16/bf16)
- vectorized on SM100+: packed x2 helpers tl::mul2/tl::fma2
- vectorized elsewhere: per-lane scalar calls
- CuTeDSL: tl.ieee_fmul/tl.ieee_fmaf with rounding="rn", expanded per
  lane through a register tensor for vector dtypes

The packed x2 pair-decomposition logic is extracted from
PrintVecBinaryOp into a reusable EmitPackedX2Call helper (no behavior
change), alongside a new EmitPerLaneScalarCall fallback.
2026-09-02 16:07:16 +08:00
Chaofan Lin 7e3bbf3703 [CUDA][Reduce] Add PassConfig for FP32x2 accumulation (#3128)
[CUDA][Reduce] Add global control for FP32x2 accumulation
2026-09-02 01:43:37 +08:00
HaoyangandSiriusNEO 336ac5305d [BugFix] Don't drop syncs from the other if branch (#3085)
* [BugFix] Preserve safe branch syncs during hoisting (#3042)

* [BugFix] Reject unsafe partial barrier participation

* [BugFix] Preserve legacy sync hoisting compatibility

* [BugFix] Respect masked warp synchronization

* [BugFix] Ignore bind definitions in warp participation

* [Debug] Print rejected barrier branch IR

* [BugFix] Prove unrolled loop access disjointness

* [BugFix] Narrow branch sync validation scope

---------

Co-authored-by: SiriusNEO <chaofan@deepseek.com>
2026-09-01 01:41:08 +08:00
Yongqi ZhuoandClaude Fable 5 2169b925ae [BugFix] Always vectorize T.Parallel loops (#3121)
* [BugFix] Always vectorize `T.Parallel` loops

* Fix CI failures

* Restore always-vectorize accidentally reverted by the CI-fix commit

f447919b captured a transient working-tree state from a concurrent
baseline-vs-patched benchmark flip, reverting the gate removal in src/
while keeping the new-policy tests: CI then ran the old gated compiler
against them (scalar var-loop -> no float2; positional if/for check
broken by the copy loops the larger tile introduces).

Bring back the parameter-less LowerParallelLoop and rewrite the issue
1734 assertion as containment: the guarded loop must sit inside the
hoisted if block, which holds on both sm90 and sm100 regardless of how
many copy loops precede it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 23:33:42 +08:00
KellyFrog beb9844555 [BugFix][Transform] Reject break in fully expanded loops (#3026) (#3078) 2026-08-31 21:38:55 +08:00
Ziming Wang 8798fca4d6 [Runtime][Cache] Export libraries after disk-cache hits (#3116)
Signed-off-by: ZenAlexa <zimingwang945@gmail.com>
2026-08-31 19:22:37 +08:00
Chennes e4fba8678a [CUDA] Wrap ldmatrix source offsets within shared-memory regions (#3110)
Some ldmatrix lane maps step beyond the final SM75 MMA micro-tile, and
column overflow must carry into the next row. Layout remapping previously
linearized the source indices and optional offset before converting them
back to multidimensional coordinates, which normalized these addresses as
a side effect. Since #2836 preserves the multidimensional indices, the
out-of-range coordinates reach the swizzle layout unchanged and the native
SM75 MMA GEMM paths fault on illegal shared-memory accesses.

Wrap each complete row-major source offset within its operand region in
ldmatrix_a and ldmatrix_b before rebuilding the source coordinates.
Leading dimensions remain untouched, so the wrap cannot cross into another
stage of a multi-version buffer.

When the coordinates are provably in range, the simplifier removes the
wrap. SM70 and SM80 generated sources remain byte-identical, while the
SM75 addresses match the pre-#2836 address mapping.

Add multi-stage SM75 GEMM coverage and a lowered-offset bounds regression
that cross-compiles explicitly for sm_75 and therefore runs on any CUDA
runner.
2026-08-31 19:17:04 +08:00
Jinpeng Wang 9f6cab208c [BugFix][CUDA][HIP] Handle logical not for vectorized bool (#3117) 2026-08-31 16:15:49 +08:00
Jinpeng Wang 09a9101f57 [Bugfix] Reject symbolic T.gemm tile dimensions with a clear message (#3113) 2026-08-31 14:54:21 +08:00
J.W (Jun) 25908d48a6 [Bugfix][Quantize] Fix unsigned zero-point decode underflow (#2947) (#3118)
_tir_packed_to_unsigned_convert_with_zeros performed the zero-point subtraction in the unsigned packed storage dtype before casting to the requested output dtype. Values below the zero-point therefore wrapped modulo the storage width.

Cast the unpacked field and zero-point to the output dtype before subtraction so asymmetric dequantization preserves negative values.

Add CUDA regression coverage for uint32-packed 4-bit values decoded with a non-zero zero-point.

Fixes #2947
2026-08-31 14:12:46 +08:00
ゆりandyurekami 958d6d3bd2 [Lang] Reject non-positive arrive_count in alloc_barrier and alloc_cluster_barrier (#3112)
Co-authored-by: yurekami <yurekami@users.noreply.github.com>
2026-08-30 14:53:11 +08:00
Yongqi ZhuoandClaude Fable 5 30c1904d3a [CUDA] Unify TMA copy lowering on CuTe algebra (#3106)
* [CUDA] Unify TMA copy lowering on CuTe algebra and support general swizzled layouts

Every descriptor-based TMA path (bulk copy, atomic add, gather4/scatter4,
im2col) now shares one CuTe-algebra box decomposition. Boxes follow the
driver contract (inner box bytes at most the swizzle span, per-dim caps),
and the recovered swizzle is widened on demand under an equivalence proof,
so general annotated layouts -- including phase-shifted swizzles -- lower
correctly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Address review concerns

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 15:43:29 +08:00
andyluo7 ab3202a25c [ROCm] Preserve FP8 bits in warp shuffles (#3104) 2026-08-29 13:27:01 +08:00
Lei Wang a1f8ebd4ed [Compiler][Z3] Bump 3rdparty/tvm to materialize Z3 solvers lazily (#3105)
* [Compiler][Z3] Bump 3rdparty/tvm to materialize Z3 solvers lazily

Z3Prover::Impl created a z3::solver eagerly in the Analyzer constructor
and translated every Bind/EnterConstraint into z3 constraints up front.
Analyzers are scratch objects created in huge numbers during lowering (a
reducer-heavy kernel compile creates ~67k of them, ~100k binds), while
only ~0.3% ever reach the Z3 fallback of CanProve, so the eager setup
dominated layout-inference-heavy compiles.

With the bump, binds and constraints are journaled and the solver is
created and replayed on first use. End-to-end compile of the worst
regressing reducer kernels drops 40-60%, and tilelang.lower roughly
halves across the board. Language suite 1168 passed / 137 skipped,
reducer_v2 75 passed, arith 89 passed; generated CUDA byte-identical
under disabled ASLR.

tvm changeset: https://github.com/tile-ai/tvm/pull/68

* [Cleanup] Drop Z3ContextScope wrappers

With the bumped tvm, every materialized Z3 solver owns a private context
(tile-ai/tvm#69), which subsumes the per-compilation isolation these
scopes provided; the scope functions are now documented no-ops. Remove
the wrappers around lowering and grouped compilation, and rewrite the
scope-lifetime arith test to assert what it actually guarded: a cloned
Analyzer's Z3 handles stay valid after the source is destroyed.

Validation (cold caches): layout suite 298 passed (including the
z3-context isolation tests, which cover the grouped-compile path),
language suite 1172 passed / 137 skipped, arith 89 passed, reducer_v2
75 passed.

* Point 3rdparty/tvm at the merged lazy-Z3 changes

tile-ai/tvm#68 and tile-ai/tvm#69 are both merged; replace the PR-branch
pin with the tilelang_main commit.
2026-08-29 00:51:12 +08:00
Lei Wang f91a8c9b07 [Layout][Reducer] Preserve vectorized reducer update plans (#3100)
[Layout] Preserve vectorized reducer update plans

Treat reducer_update as a transparent expression during layout vector-shape analysis. This lets contribution loads determine the planned width instead of forcing update nests onto scalar-shaped layouts before reducer materialization.\n\nAdd a CUDA regression that checks the shared-to-fragment copy remains packed and verifies the reducer result.
2026-08-27 22:20:13 +08:00
26035b09bb [BugFix][Transform] Avoid int32 overflow in vector analysis (#3066)
* [BugFix][Transform] Avoid int32 overflow in vector analysis

* [BugFix][Transform] Preserve BufferLoad lanes during vectorization

* fix(vectorize): guard analyzer simplification overflow

---------

Co-authored-by: caizelin <caizelin@caizelindeMacBook-Pro.local>
Co-authored-by: SiriusNEO <chaofan@deepseek.com>
2026-08-27 19:53:47 +08:00
YYDHandSiriusNEO a2e02cc5cd [Bugfix][CUDA] Fix UB in packed 8-bit vector stores (#3092)
* [Bugfix][CUDA] Fix UB in packed 8-bit vector stores

* test(cuda): check int8x32 field initialization

---------

Co-authored-by: SiriusNEO <chaofan@deepseek.com>
2026-08-27 19:47:41 +08:00
Chaofan Lin 5899e626c8 [Cleanup] Remove obsolete disable-fast-math pass config (#3098)
[Cleanup] Remove obsolete disable-fast-math config
2026-08-27 19:37:40 +08:00
Wenzhe WangandSiriusNEO 469c5d5cb8 [Bugfix] Validate T.gemm k_pack arguments (#3094)
* [Bugfix] Validate T.gemm k_pack arguments

* [Bugfix] Improve T.gemm k_pack diagnostic

* [Bugfix] Accept integral T.gemm k_pack values

* [Bugfix] Simplify T.gemm k_pack validation

---------

Co-authored-by: SiriusNEO <chaofan@deepseek.com>
2026-08-27 19:33:26 +08:00
KellyFrog b5b9e0431a [Layout] Reject non-round-tripping inferred inverses (#3090)
* [Layout] Reject non-round-tripping inferred inverses

* [Lint] Fix pytest import ordering

* [Testing] Gate shifted modulo copy test on CUDA
2026-08-27 18:04:12 +08:00
Chennes 035a2af35b [CUDA] Add 16-bit overloads for CUTLASS fast-math functions (#3097)
math.h aliases several half-style names to cutlass::fast_* when a kernel
uses selected fast-math intrinsics. CUTLASS provides only float and double
overloads for fast_log, fast_sqrt, fast_sin, and fast_cos, and adds half_t
overloads only for fast_exp and fast_tanh. Overload resolution can therefore
leave a float result that cannot copy-initialize the CUTLASS wrapper.

Once a kernel includes math.h, for example through T.__exp, these aliases
also affect matching plain math calls in the same kernel. Their compilation
could therefore depend on whether another intrinsic pulled math.h in.

Add half_t and bfloat16_t overloads for fast_log, fast_sqrt, fast_sin, and
fast_cos, plus bfloat16_t for fast_tanh. Each evaluates in float32 and
converts back, following the existing fast_exp(bfloat16_t) bridge. Calls
that already compiled retain the same numerical path.

Add compile-and-run coverage for both wrapper types.
2026-08-27 17:17:24 +08:00
Lei Wang 39a1a0bbee [BugFix] Bind symbolic coordinate ranges in FragmentThreadIndexProbe (#3096)
The probe inverts a candidate loop layout into symbolic per-thread
coordinates plus a symbolic thread variable, then checks whether any
fragment physical index still contains the thread variable. Proving a
strided distribution thread-free is range-dependent (e.g.
`(o0*512 + t*4 + o1) // 512 -> o0` only holds for t*4 + o1 < 512), so
with unbound ranges Simplify keeps the thread term and even an identity
access (loop layout == fragment layout) is falsely charged as a register
spill. The spill pricing then steers layout inference away from
conflict-free strided shared-memory loads toward chunk-contiguous
layouts whose 16-word stride bank-conflicts on every shared load,
observed as a 1.23-1.29x latency regression on a production
KL-divergence kernel (8.8ms vs 6.8ms at n=8192, d=262144 on H800).

Bind every per-thread output coordinate to its output-shape range and
the thread variable to the loop's thread range/extent so the legitimate
cancellations go through. Genuine thread dependence is unaffected: range
information only enables valid simplification, it cannot remove a real
thread term. Regression test distilled from the affected kernel.
2026-08-27 15:26:21 +08:00
Lei WangandClaude Fable 5 6279e735f9 [Refactor] Give reducers a first-class PartialFragment layout solved by layout inference (#3093)
* Steer reducer destinations during layout inference

* Remove extra reducer steering attempt filtering

* handle reducer problem3

* bug fix

* [Refactor] Give reducers a first-class PartialFragment layout solved by layout inference

The reducer's physical plan (narrow vs wide partials) used to be decided
after inference by ReducerPlanAndMaterialize, with dst-steering emulating
the missing propagation through side channels (wake tables, hint plumbing,
ownership gates); the same induced layout was computed twice and kept
consistent by convention only, and the reducer split the use-def graph
into disconnected components.

This makes the reducer's layout a first-class solver value that fully
determines the physical plan:

* New layout kind `tl.PartialFragment` (PartialFragmentNode : FragmentNode):
  Fragment algebra whose replication coordinate carries an explicit
  combine decomposition — under a low-bits convention enforced at
  construction, `_rep % combine_size` enumerates addend lanes the finalize
  collective must reduce and `_rep / combine_size` enumerates equal-value
  copy groups. (storage algebra, combine width) is the complete plan: the
  collective steps are derivable from the node alone (CombineSteps), the
  FullParticipant object (combine == replicate == participants, thread ==
  _rep) is the wide fallback, and combine width is part of layout identity
  (same-storage different-decomposition proposals widen at the commit
  point instead of unifying silently). A boundary-preserving condensation
  (CondenseReplicateVarKeepingBoundary) keeps the convention true through
  projection; kind-aware IsEqual in both dispatch directions prevents
  silent unification with plain Fragments.

* Update nests (ParallelOp) record their reducer_update sites and, once
  their loop layout solves, propose the induced partial (per-site
  AnalyzeReducerUpdateSite proofs) or the participant-wide plan. The
  commit point resolves multi-site disagreement with a monotone
  widen-on-conflict rule; zero-update epochs are seeded wide before any
  inference level runs; tl.reducer_force_baseline pins the proposal.

* finalize_reducer reads the solved partial and steers an unconstrained
  destination to its post-collective reading. The wake table, the
  LayoutInferArgs.reducer_update_sites hint plumbing and the
  reducer_use_list_ component glue are deleted: reducers travel ordinary
  use_list_ buffer edges.

* ReducerPlanAndMaterialize reads the plan off the node: storage =
  AsPostCollective(), steps = CombineSteps(), wide lowering iff the node
  is the FullParticipant object. TryNarrowPlan is retired; what remains
  (DeriveNarrowLowering) derives only the lowering details that live
  outside the layout — the packed-lane heuristic and the
  destination-containment gate (which still demotes gracefully to the
  wide plan, preserving the unsatisfiable-steering fallback contract).
  The destination override chains are kept as a verified-no-op fallback
  with retirement telemetry.

* T.annotate_layout accepts a PartialFragment on reducer buffers, pinning
  plans the automatic solution cannot reach (e.g. a middle plan between
  narrow and wide). Annotated partials are strict: a disagreeing update
  site raises with the narrow-rejection reason, and
  ComputeReducerPinnedCandidate back-propagates the annotation through
  the update loop into its input fragments.

* Layout cost models price register-array spills: a fragment access whose
  physical slot index depends on the thread variable (detected by the
  shared FragmentThreadIndexProbe, extracted from
  HasThreadDependentFragmentIndex) demotes the whole array to local
  memory, charged as byte-denominated traffic in both models' `mem`
  channel so it competes with — rather than vetoes — global-bandwidth
  estimates. ChooseBestCandidate's anti-spill preference now applies
  regardless of where the loop stores (a fragment->fragment publication
  copy spills exactly like a fragment->global one). With generation and
  pricing combined, inference produces the wide publication chain's
  replicated layouts on its own: the reducer_v2 suite and the
  mhc_post_bwd production kernels pass with the destination override
  fully disabled.

Testing (all with the kernel cache disabled): reducer_v2 suite 70 passed
(new coverage: pinned middle plans, annotation steering input fragments,
conflict diagnostics, combine-step roundtrip, same-storage
different-combine widening at commit); language suite 1261 passed;
layout-inference cost-model tests and maint/layout_inference goldens
unchanged; generated CUDA for existing reducer kernels is byte-identical;
mhc_post_bwd correctness passes and its six benchmark sizes show
no latency change with zero STL/LDL in SASS.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 14:20:55 +08:00
Yongqi ZhuoandClaude Fable 5 0ce2a7bacf [Bugfix] Make TMA layouts region-aware to keep slices contiguous (#3089)
[Bugfix] Make TMA linear layouts region-aware to keep versioned slices contiguous

The inferred "linear" shared layout hoisted every 256-split quotient above
all dims, so a pipeline-versioned slice became two gapped chunks: LowerBulk's
bijection check fired on warp-specialized wide reductions, and the TMA
atomic-add path (which has no such check) silently read the other version.

MakeTmaLinearLayout now takes the copied region and orders modes as
[region-fixed dims, box quotients, box contents], so a fixed slice owns one
contiguous run of whole TMA boxes and the existing rest-loop machinery emits
one instruction per box over the true (unaligned) global shape. The
atomic-add path shares the helper and computes the region base offset through
the layout instead of hand-rolled row-major strides over the physical shape.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 15:32:05 +08:00
Yongqi ZhuoandClaude Fable 5 728f2c88a1 [Bugfix] Fix wait parity for explicit mbarriers in pipelined loops (#3087)
A synchronous T.gemm(mbar=...) inside T.Pipelined waited on the wrong
mbarrier parity. InjectSoftwarePipeline annotated every copy/im2col/gemm
call with the ring parity (k / num_stages) % 2, but that law belongs to
the compiler-generated pipeline_mbar ring: an explicit mbarrier whose
arrive happens inside a tile op is deliberately excluded from
ExpandPipelineBarriers, so it remains a single slot that flips once per
iteration. The auto-emitted wait asked for a parity that had already
completed, returned immediately, and the next iteration's copies
overwrote a shared-memory stage the still-running MMA was reading
(wrong results observed at num_stages >= 3).

Annotate only the ops that consume the phase -- those that auto-emit a
paired arrive+wait on an explicit mbarrier: sync gemm with an mbar, and
copies carrying an explicit "barrier" that are not is_tma_copy -- and
annotate them with the logical iteration parity (k - min) % 2, written
against the original loop var. EmitImpl's existing per-block
Substitute(loop_var -> normalized_access_index) specializes the
expression for every prologue/body/epilogue clone, since the tirx
mutators already rewrite PrimExprs inside call annotations.
Pipeline-managed TMA copies keep their ring parity in the explicit
waits the pass inserts, and the explicit-async T.tcgen05_gemm never
auto-waits, so neither is annotated.

Drop the matching ring branch from LowerTileOp's fallback: it keyed on
the "num_stages" annotation, which InjectSoftwarePipeline strips, so it
was dead on pipelined loops and wrong on unpipelined ones -- a
compiler-generated per-site barrier flips once per loop iteration
regardless of pipeline depth. The fallback is now the zero-based epoch
of the nearest enclosing serial loop.

Add transform-level tests asserting the annotated phase and the emitted
wait parities on sm_90a, so the fix is covered without sm_100 hardware;
the loops start at a nonzero min to pin the epoch normalization. Add a
tcgen05 correctness test running the failing kernel at num_stages 2
and 3.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 15:18:10 +08:00
Chaofan Lin fe59bc6ccb [Refactor] Remove obsolete compiler and runtime paths (#3086)
Remove an unconsumed cluster-planning pass, duplicate sparse GEMM and fast-math implementations, the unused JIT environment module, and the superseded autotuner timeout machinery. Document and test the surviving portable timeout behavior.
2026-08-26 02:11:38 +08:00
Lei Wang cb7538b379 [Lang][Reducer] Vectorize contiguous reducer updates (#3079)
* Enable vectorized reducer updates

* Mark CUDA-only reducer tests
2026-08-25 21:08:44 +08:00