Skip to content

[Layout] Support annotating loop layout in frontend - #1579

Merged
LeiWang1999 merged 7 commits into
tile-ai:mainfrom
LeiWang1999:feat/parallel-loop-layout-outer-annotation
Jan 4, 2026
Merged

LeiWang1999 merged 7 commits into
tile-ai:mainfrom
LeiWang1999:feat/parallel-loop-layout-outer-annotation

Conversation

@LeiWang1999

@LeiWang1999 LeiWang1999 commented Dec 31, 2025 •

Copy link
Copy Markdown
Member

Summary

  • Add loop_layout to T.Parallel and document constraints/rationale
  • Enforce outermost annotation semantics across validator/lowering
  • Adopt annotated loop layout (and predicate) when present in annotations
  • Fuse parallel loops: reshape Fragment to fused 1D via Fragment::Reshape
  • Lower: strip parallel_loop_layout/predicate annotations in LowerParallelLoop
  • Tests: add lazy_jit tests for loop layout codegen (CUDA); remove old debug script
  • Docs: update control_flow guide for loop_layout

Why

  • Inner loops cannot govern outer loops; outermost loop is the right scope to manage and transform the entire nested region
  • Reshape on fuse produces correct, simplified 1D layout and avoids hand-crafted index/thread expressions
  • Removing annotations at lower prevents complex payloads from leaking into later passes that do not visit annotation bodies

Key Files

  • tilelang/language/loop.py: add loop_layout param; docstring notes + rationale
  • docs/programming_guides/control_flow.md: loop_layout attached to outermost loop
  • src/ir.cc: only outermost parallel loop carries annotations (with rationale)
  • src/transform/parallel_loop_layout_validator.h: validate outermost annotation; rationale comment
  • src/transform/layout_inference.cc: attach inferred loop layout/predicate on outermost loop
  • src/op/parallel.h/.cc: cache annotated layout/predicate; adopt in InferLayout; infer-only flag
  • src/transform/common/loop_fusion_utils.h: reshape layout on fuse; drop mismatched annotation
  • src/transform/loop_partition.cc: strip layout/predicate annotations in LowerParallelLoop
  • testing/python/layout/test_parallel_loop_layout.py: new lazy_jit tests

Validation

  • CUDA codegen asserts pass in new tests under testing/python/layout

Summary by CodeRabbit

  • Documentation

    • Clarified parallel-loop guidance and expanded optional hints; documented that layout annotations attach to the outermost parallel loop and added loop_layout usage guidance.
  • New Features

    • Added loop_layout keyword to parallel constructs and copy APIs to provide an optional thread/layout hint for vectorization.
  • Bug Fixes

    • Ensure layout annotations and coalescing hints apply only to the outermost parallel loop and strip stale annotations; copy validates compatible patterns when loop_layout is used.
  • Tests

    • Added tests validating parallel loop layout handling and vectorized copy generation.

✏️ Tip: You can customize this high-level summary in your review settings.

* Updated the handling of layout annotations in parallel loops to ensure they are only attached to the outermost loop. This change clarifies the rationale behind layout management, allowing for better reasoning and transformation of nested parallel regions.
* Introduced new parameters in the `Parallel` function to accept layout annotations directly, enhancing usability and validation during layout inference.
* Refactored the layout inference logic to prioritize annotated layouts over inferred ones, improving the efficiency of layout management in parallel operations.

This update aims to strengthen the integrity of layout annotations and streamline the handling of nested parallel loops in the system.
@github-actions

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the TileLang project.

Please remember to run pre-commit run --all-files in the root directory of the project to ensure your changes are properly linted and formatted. This will help ensure your contribution passes the format check.

We appreciate you taking this step! Our team will review your contribution, and we look forward to your awesome work! 🚀

@coderabbitai

coderabbitai Bot commented Dec 31, 2025 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Parallel-loop layout annotations are now attached only to the outermost parallel loop. TileLang Parallel and copy APIs accept a new loop_layout hint attached as parallel_loop_layout; IR construction, ParallelOp layout inference, copy lowering, and related transforms were updated to cache, bind, and respect only outermost-loop annotations. Tests added.

Changes

Cohort / File(s) Summary
Docs
docs/programming_guides/control_flow.md, docs/programming_guides/instructions.md, src/transform/parallel_loop_layout_validator.h
Clarified coalesced_width semantics; documented new loop_layout option and that parallel-loop layout annotations should live on the outermost parallel loop.
TileLang — Parallel API
tilelang/language/loop.py
Added optional loop_layout parameter; attaches it in annotations as parallel_loop_layout for the outermost loop.
TileLang — Copy API
tilelang/language/copy_op.py, docs/programming_guides/instructions.md
copy(...) gains keyword-only loop_layout; forwards it as parallel_loop_layout in annotations and documents the parameter.
IR construction
src/ir.cc
ParallelFor now propagates full annotations only for the outermost iteration (i == 0); inner iterations get empty annotations.
Parallel operator (caching & inference)
src/op/parallel.h, src/op/parallel.cc
ParallelOpNode caches outermost-loop annotations (annotated_layout_unbound_, annotated_predicate_) and tracks loop_layout_inferred_; InferLayout binds/uses cached annotations, gates alternate inference paths, and marks inference complete.
Copy lowering & validation
src/op/copy.h, src/op/copy.cc
Copy lowering attaches parallel_loop_layout only to the outermost generated parallel loop; InferLayout enforces that annotated loop_layout requires a SIMT (normal) copy instruction.
Transforms / Fusion / Partition / Lowering
src/transform/loop_fusion_utils.h, src/transform/loop_partition.cc, src/transform/lower_tile_op.cc, src/transform/layout_inference.cc
Fusion reshapes or drops an outermost Fragment-based layout when fusing; partition strips parallel-loop layout/predicate before further transforms; comments updated to note annotations live on outermost For.
Builder
tilelang/language/v2/builder.py
bind_immutable now wraps PrimExpr/BufferRegion into a LetStmt frame instead of attempting runtime conversion.
Atomic / Other ops
src/op/atomic_add.cc
Coalesced-width annotation is applied only to the outermost loop level in SIMT loop construction.
Tests
testing/python/layout/test_parallel_loop_layout.py
New CUDA-gated tests and lazy-JIT kernels exercising fragment-based, identity, and replicated loop_layout cases and asserting generated vectorized copy patterns.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as User code
    participant API as TileLang API (Parallel / copy)
    participant IR as ParallelFor ctor (src/ir.cc)
    participant Op as ParallelOpNode (src/op/parallel)
    participant Infer as InferLayout (layout_inference)
    participant Copy as Copy lowerer (src/op/copy)
    participant Trans as Transforms (fusion/partition)

    User->>API: call Parallel(..., loop_layout=Fragment)
    API->>API: attach `parallel_loop_layout` in annotations
    API->>IR: construct ParallelFor(extents, annotations)

    alt outermost iteration (i == 0)
        IR->>Op: propagate full annotations
        Op->>Op: cache annotated_layout_unbound_ & annotated_predicate_
    else inner iterations (i > 0)
        IR->>Op: propagate empty annotations
    end

    Trans->>Op: request InferLayout()
    alt first inference
        Op->>Infer: use annotated_layout_unbound_ (if present)
        Infer->>Op: bind fragment to thread bounds, apply predicate
        Op->>Op: set loop_layout_inferred_ = true
    else subsequent calls
        Op->>Infer: return early (already inferred)
    end

    Copy->>Copy: Lower SIMT loops — attach `parallel_loop_layout` only to outermost loop
    Trans->>Trans: fusion/partition may reshape or drop outermost layout annotation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐇 I placed a fragment on the outermost rung,
Inner hops stay quiet while outer threads hum,
Bindings snap to threads, predicates chime in tune,
Fusion may reshape, or drop what’s out of tune,
A tidy rabbit loop beneath the code-moon 🌙

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[Layout] Support annotating loop layout in frontend' accurately describes the main change: adding support for loop_layout parameter annotation to parallel loops in the frontend API.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb27876 and 80a5da4.

📒 Files selected for processing (2)
  • src/op/atomic_add.cc
  • src/op/copy.cc
🧰 Additional context used
🧬 Code graph analysis (1)
src/op/copy.cc (1)
src/op/copy.h (1)
  • CopyInstToString (32-55)
🔇 Additional comments (3)
src/op/atomic_add.cc (1)

288-299: LGTM: Annotation correctly restricted to outermost loop.

The logic properly attaches coalesced_width only to the outermost parallel loop (when i == 0). Since the loop iterates from loop_vars.size() - 1 down to 0, building the nest from innermost to outermost, the condition i == 0 correctly identifies the outermost loop. This aligns with the PR's objective to constrain parallel-loop annotations to the top level.

src/op/copy.cc (2)

316-335: LGTM: Annotations correctly restricted to outermost loop.

The implementation properly attaches both kCoalescedWidth and kParallelLoopLayout annotations only to the outermost parallel loop. The inline comment clearly documents the intent, and the logic is consistent with the parallel changes in atomic_add.cc.


370-382: LGTM: Appropriate validation for loop layout annotation.

The validation correctly enforces that parallel_loop_layout annotations can only be used with SIMT-style copies (CopyInst::kNormal). This makes sense because other copy instructions (TMA, LDSM, STSM, TMem) use different lowering strategies that don't generate the same parallel loop structure. The error message is clear and provides actionable guidance.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/transform/loop_partition.cc (1)

280-287: Consider combining CopyOnWrite() calls for efficiency.

The two consecutive CopyOnWrite() calls on result_loop can be combined into a single call to avoid redundant copy operations.

🔎 Proposed optimization
-  result_loop.CopyOnWrite()->annotations.erase(attr::kParallelLoopLayout);
-  result_loop.CopyOnWrite()->annotations.erase(attr::kParallelLoopPredicate);
+  auto* result_loop_ptr = result_loop.CopyOnWrite();
+  result_loop_ptr->annotations.erase(attr::kParallelLoopLayout);
+  result_loop_ptr->annotations.erase(attr::kParallelLoopPredicate);
testing/python/layout/test_parallel_loop_layout.py (1)

6-6: Address or track the TODO for comprehensive coverage.

The TODO indicates that more complex layout cases (replicated loops, etc.) should be tested. Consider either:

  1. Adding those test cases in this PR to ensure comprehensive coverage
  2. Creating a follow-up issue to track this work

Would you like me to generate additional test cases for replicated and more complex layout scenarios?

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53ea96c and d87db50.

📒 Files selected for processing (12)
  • docs/programming_guides/control_flow.md
  • src/ir.cc
  • src/op/parallel.cc
  • src/op/parallel.h
  • src/transform/common/loop_fusion_utils.h
  • src/transform/layout_inference.cc
  • src/transform/loop_partition.cc
  • src/transform/lower_tile_op.cc
  • src/transform/parallel_loop_layout_validator.h
  • testing/python/layout/test_parallel_loop_layout.py
  • tilelang/language/loop.py
  • tilelang/language/v2/builder.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-18T04:50:00.512Z
Learnt from: silentCoder-dev
Repo: tile-ai/tilelang PR: 1464
File: testing/python/language/test_tilelang_language_rand.py:14-14
Timestamp: 2025-12-18T04:50:00.512Z
Learning: In `testing/python/language/test_tilelang_language_rand.py`, the TileLang kernel uses `blk_M = M` (single block) and calls `rng_rand()` four times per element to align results with the Triton implementation, which uses `blk_M = 128` (multiple blocks) and calls the RNG once per element. These differences compensate for internal RNG behavior differences between TileLang and Triton.

Applied to files:

  • testing/python/layout/test_parallel_loop_layout.py
🧬 Code graph analysis (5)
src/ir.cc (1)
src/transform/lower_opaque_block.cc (4)
  • annotations (157-169)
  • annotations (158-158)
  • annotations (226-266)
  • annotations (227-230)
testing/python/layout/test_parallel_loop_layout.py (3)
tilelang/language/v2/builder.py (1)
  • const (831-842)
tilelang/language/kernel.py (1)
  • threads (214-218)
tilelang/language/loop.py (1)
  • Parallel (13-72)
src/transform/common/loop_fusion_utils.h (2)
src/layout/layout.h (1)
  • attr (258-267)
src/layout/layout.cc (2)
  • Fragment (518-540)
  • Fragment (542-552)
tilelang/language/v2/builder.py (1)
tilelang/language/ast/ir.py (1)
  • LetStmt (874-902)
src/op/parallel.cc (2)
src/layout/layout.h (1)
  • attr (258-267)
src/transform/layout_inference.cc (2)
  • level (247-263)
  • level (247-249)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test for Python 3.12 with Nightly-ROCm-7.1 (on self-hosted-amd)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
🔇 Additional comments (22)
src/transform/parallel_loop_layout_validator.h (1)

37-41: LGTM!

The added rationale comment clearly explains why layout annotations are placed on the outermost parallel loop—inner loops cannot control outer ones, and placing the annotation at the top level allows passes to reason about and transform the entire nested region. This aligns well with the broader PR changes.

src/transform/layout_inference.cc (1)

1225-1227: LGTM!

The updated comment accurately reflects that the loop layout annotation is stored on the outermost For node, which aligns with the PR's outermost-annotation semantics.

src/transform/lower_tile_op.cc (1)

711-715: LGTM!

The added rationale clarifies the design decision that inner loops cannot govern outer loops, and that the outermost loop is the correct place to carry layout annotations. This documentation improvement helps future maintainers understand the code.

src/transform/common/loop_fusion_utils.h (1)

221-242: LGTM!

The logic correctly handles the parallel loop layout annotation after fusion:

  1. When dimensions match, Fragment::Reshape preserves forward_index/thread semantics for the fused 1D layout.
  2. When dimensions mismatch, erasing the stale annotation allows downstream passes to re-infer a correct layout.

The dimension check old_dim == loop_chain.size() ensures the reshape operation is only performed when semantically valid.

tilelang/language/v2/builder.py (1)

500-506: LGTM!

The change properly handles PrimExpr values by wrapping them in a LetStmt frame for correct scoping and delayed evaluation. The frame is entered via enter_frame, which adds it to the builder's frame stack for proper lifecycle management. This aligns with the existing frame-based binding pattern used elsewhere in the class (e.g., for tir.frame.IRBuilderFrame).

src/ir.cc (1)

83-96: LGTM!

The logic correctly attaches annotations only to the outermost parallel loop. Since the loop builds the nested structure inside-out (from i = n-1 down to i = 0), i == 0 corresponds to the outermost loop after construction. This aligns with the PR's design that layout annotations should only be placed on the outermost loop.

docs/programming_guides/control_flow.md (1)

83-87: LGTM!

The documentation update clearly explains the new optional hints for T.Parallel:

  • coalesced_width= for memory coalescing control
  • loop_layout= for Fragment-based layout annotation

The note that the annotation attaches to the outermost loop and must have InputDim == number of nested parallel extents provides essential guidance for correct usage.

tilelang/language/loop.py (3)

13-17: LGTM: Clean parameter addition.

The loop_layout parameter is appropriately typed and positioned. Using Any is reasonable here since Fragment isn't imported in the language module, and the actual type checking happens in the C++ layer.


29-58: Excellent documentation.

The docstring provides comprehensive coverage of the loop_layout parameter, including constraints, validation behavior, and the rationale for outermost-loop attachment. This will help users understand both the what and the why.


66-72: LGTM: Clean annotation handling.

The implementation correctly attaches the optional loop_layout to the annotations dictionary. The direct assignment approach (line 67, 71) is cleaner than using update().

testing/python/layout/test_parallel_loop_layout.py (3)

7-15: LGTM: Simple and focused test kernel.

The kernel is appropriately minimal for testing loop layout functionality. It exercises the new loop_layout parameter in T.Parallel without introducing unnecessary complexity.


18-34: LGTM: Validates vectorized codegen correctly.

The test creates a Fragment with a forward function that maps to vectorized (float4) thread/local indices and validates that the generated code contains the expected vectorized copy pattern. The string assertion is brittle but necessary to confirm correct codegen.


37-51: LGTM: Good coverage of identity layout.

This test complements the vectorized test by validating the identity layout case. Together, the two tests provide reasonable coverage of the basic loop layout functionality.

src/op/parallel.h (3)

56-67: LGTM: Well-designed annotation caching fields.

The three new mutable fields (loop_layout_inferred_, annotated_layout_unbound_, annotated_predicate_) are appropriately typed and initialized. Using Optional<> for the annotation fields correctly models their optional nature, and the comments clearly explain their purpose.


92-98: LGTM: Copy constructor correctly propagates new fields.

The copy constructor properly initializes all three new fields from the source object, maintaining consistency across copies.


127-128: Helpful implementation note.

The comment clarifies that annotation parsing happens once in the constructor, simplifying the design by avoiding repeated parsing.

src/op/parallel.cc (6)

286-287: Verify early-exit safety in incremental inference.

The early return when loop_layout_inferred_ is true is an optimization to avoid redundant work. Ensure that this doesn't break scenarios where InferLayout might be called multiple times with different LayoutInferArgs (e.g., different buffer remaps or updated layout maps).

If the inference result should be sensitive to changes in T.layout_map or other args, you may need to invalidate loop_layout_inferred_ when those change, or track a hash/version of the inputs.


433-449: LGTM: Correct precedence for annotation-driven inference.

The inference logic correctly implements the documented precedence:

  1. Annotated layout (if provided via loop_layout parameter)
  2. Buffer-based inference (from source fragment)
  3. Free inference (when allowed)

This ensures that explicit user annotations take precedence over automatic inference, which is the expected behavior.


522-526: LGTM: Clear fallback for missing layout sources.

The fallback correctly handles the case where no layout source is available in non-free inference modes. The comment helpfully explains the condition.


580-581: Verify flag placement relative to potential exceptions.

Setting loop_layout_inferred_ = true at line 580 assumes that all validation and layout computation succeeded. However, there may be exceptions thrown after this point (e.g., in subsequent operations). Verify that:

  1. All validation that could fail has already occurred before line 580
  2. No operations after line 580 could fail in a way that would leave the object in an inconsistent state

If exceptions can occur after line 580, consider whether the flag should be set earlier or whether cleanup is needed.


259-260: LGTM: Helpful implementation note.

The comment clarifies the workflow, indicating that annotation parsing happens in the constructor and adoption happens in InferLayout.


197-209: No issues found. The annotation keys attr::kParallelLoopLayout and attr::kParallelLoopPredicate are correctly defined in src/layout/layout.h as "parallel_loop_layout" and "parallel_loop_predicate", matching their Python usage. The error handling via Downcast<> is standard practice throughout the codebase, with the type mismatch throwing an exception being the intended behavior to catch annotation contract violations.

@LeiWang1999 LeiWang1999 changed the title Parallel loop layout: outermost annotation, fuse via reshape, cleanup on lower [Layout] Support annotating loop layout in frontend Dec 31, 2025
…tionality

* Added print statements in `test_tilelang_language_let.py` to output the `main` function and the source of the compiled module, aiding in debugging.
* Modified the `bind_immutable` method in `builder.py` to include logging of the bound value type, enhancing traceability during the binding process.
* Commented out the call to `tilelang.testing.main()` in favor of directly invoking the test function, streamlining the testing workflow.
@LeiWang1999

Copy link
Copy Markdown
Member Author

@regression-perf

…loop handling

* Updated the T.copy function to accept a new keyword-only parameter, loop_layout, allowing users to specify a layout hint for the outermost parallel loop in SIMT copies.
* Enhanced the handling of layout annotations in the CopyNode class to enforce compatibility with SIMT copy operations, ensuring that layout hints are only applied when appropriate.
* Added tests to validate the functionality of loop layout annotations in copy operations, improving the robustness of the layout management system.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/programming_guides/instructions.md (1)

16-34: Document the loop_layout parameter and its behavior.

The loop_layout parameter is added to the signature but lacks documentation. Per the PR objectives, loop_layout is a layout hint for the outermost parallel loop in SIMT copies. The Semantics section should explain:

  • What loop_layout controls (e.g., how it annotates the outermost parallel loop)
  • Valid values or constraints
  • Impact on code generation/layout inference
  • An example showing usage with loop_layout
🔎 Suggested documentation addition

Add to the Semantics section (after line 34, before "Other helpers"):

- `loop_layout` (optional, keyword-only): Layout hint for the outermost parallel 
  loop in SIMT copies. When provided, it attaches a `parallel_loop_layout` 
  annotation to the outermost loop to guide layout inference and code generation. 
  Only annotations on the outermost parallel loop are enforced; inner loop 
  annotations are ignored. Example:
  ```python
  T.copy(A[by * BM, ko * BK], A_s, loop_layout=LoopLayout.ROW_MAJOR)

</details>

</blockquote></details>

</blockquote></details>
🧹 Nitpick comments (1)
testing/python/layout/test_parallel_loop_layout.py (1)

82-90: Consider consolidating duplicate kernel definitions.

replicate_loop_layout_kernel is identical to loop_layout_kernel (lines 7-15). Both kernels accept the same parameters and have the same body. Consider reusing loop_layout_kernel in test_annotate_replicate_loop_layout_vec4 instead of defining a duplicate kernel.

🔎 Proposed simplification
-@tilelang.lazy_jit
-def replicate_loop_layout_kernel(A, B, loop_layout):
-    M, N = T.const("M, N")
-    A: T.Tensor[(M, N), T.float32]
-    B: T.Tensor[(M, N), T.float32]
-
-    with T.Kernel(1, threads=128):
-        for i, j in T.Parallel(M, N, loop_layout=loop_layout):
-            B[i, j] = A[i, j]
-
-
 @tilelang.testing.requires_cuda
 def test_annotate_replicate_loop_layout_vec4():
     M, N = 128, 32
     A = T.Tensor((M, N), T.float32)
     B = T.Tensor((M, N), T.float32)

     def loop_layout_fn(i, j, rep):
         elems = i * 32 + j
         forward_thread = (elems // 4) % 64 + rep * 64
         forward_local = elems % 4 + (elems // (64 * 4)) * 4
         return forward_thread, forward_local

     loop_layout = T.Fragment((M, N), forward_fn=loop_layout_fn, replicate=2)

-    kernel = replicate_loop_layout_kernel.compile(A, B, loop_layout=loop_layout)
+    kernel = loop_layout_kernel.compile(A=A, B=B, loop_layout=loop_layout)
     code = kernel.get_kernel_source()
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bff7a5 and cb27876.

📒 Files selected for processing (5)
  • docs/programming_guides/instructions.md
  • src/op/copy.cc
  • src/op/copy.h
  • testing/python/layout/test_parallel_loop_layout.py
  • tilelang/language/copy_op.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-18T04:50:00.512Z
Learnt from: silentCoder-dev
Repo: tile-ai/tilelang PR: 1464
File: testing/python/language/test_tilelang_language_rand.py:14-14
Timestamp: 2025-12-18T04:50:00.512Z
Learning: In `testing/python/language/test_tilelang_language_rand.py`, the TileLang kernel uses `blk_M = M` (single block) and calls `rng_rand()` four times per element to align results with the Triton implementation, which uses `blk_M = 128` (multiple blocks) and calls the RNG once per element. These differences compensate for internal RNG behavior differences between TileLang and Triton.

Applied to files:

  • testing/python/layout/test_parallel_loop_layout.py
🧬 Code graph analysis (2)
src/op/copy.cc (1)
src/op/copy.h (1)
  • CopyInstToString (32-55)
testing/python/layout/test_parallel_loop_layout.py (3)
tilelang/language/loop.py (1)
  • Parallel (13-72)
tilelang/language/copy_op.py (1)
  • copy (14-116)
tilelang/layout/fragment.py (1)
  • replicate (138-152)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
  • GitHub Check: Test for Python 3.12 with Nightly-ROCm-7.1 (on self-hosted-amd)
🔇 Additional comments (6)
src/op/copy.h (1)

124-126: LGTM!

The documentation clearly describes the parallel_loop_layout annotation key and its semantics (applied to the outermost generated parallel loop for SIMT copies). This aligns well with the implementation in copy.cc and the broader PR objectives.

src/op/copy.cc (2)

315-331: LGTM!

The logic correctly attaches the parallel_loop_layout annotation only to the outermost loop (i == 0), while coalesced_width continues to be applied to all parallel loops. Since the loop is constructed from innermost to outermost (iterating i from loop_vars.size()-1 down to 0), the i == 0 condition correctly identifies the outermost loop.


369-381: LGTM!

The validation correctly enforces that parallel_loop_layout annotations are only valid for SIMT (normal) copies. The fatal error with a descriptive message guides users to either remove the loop_layout hint or adjust the copy pattern. This prevents silent misuse of the annotation with incompatible copy instructions like TMA/LDSM/STSM/TMem.

tilelang/language/copy_op.py (2)

112-114: LGTM!

The loop_layout parameter is correctly propagated to the parallel_loop_layout annotation, mirroring the pattern used in T.Parallel. The precedence logic (only set if not already in annotations) is consistent with the other annotation parameters.


35-37: LGTM!

The docstring clearly documents the loop_layout parameter's purpose, type hint, and constraints. The note about incompatibility with TMA/LDSM/STSM/TMem aligns with the C++ validation in copy.cc.

testing/python/layout/test_parallel_loop_layout.py (1)

1-117: Good test coverage for the new loop_layout feature.

The test file provides comprehensive coverage for:

  • T.Parallel with loop_layout parameter
  • T.copy with loop_layout parameter
  • Both simple and replicate Fragment layouts
  • Vectorized (float4) copy pattern verification

All tests are properly CUDA-guarded. The string-based code assertions are a reasonable approach for validating codegen behavior, though they may need updates if the code generator's formatting changes.

@github-actions

Copy link
Copy Markdown

Performance Regression Test Report

Triggered by: @LeiWang1999
Workflow run: https://github.com/tile-ai/tilelang/actions/runs/20614593820

Results

File Original Latency Current Latency Speedup
example_mha_inference 0.07248 0.074753 0.969593
example_gemm 0.022529 0.022912 0.983284
example_gemm_autotune 0.022176 0.022528 0.984375
example_warp_specialize_gemm_copy_0_gemm_1 0.039169 0.039778 0.98469
example_warp_specialize_gemm_softpipe_stage2 0.038113 0.038689 0.985112
example_gqa_decode 0.048833 0.049217 0.992198
example_gemm_schedule 0.0325772 0.0326215 0.998641
example_linear_attn_bwd 0.152262 0.15235 0.999427
example_elementwise_add 0.297485 0.297634 0.999497
example_tilelang_gemm_splitk 1.40815 1.40866 0.999638
example_linear_attn_fwd 0.036596 0.0366062 0.999721
example_tilelang_gemm_fp8_intrinsic 0.466903 0.467 0.999791
example_vertical_slash_sparse_attn 0.237792 0.237841 0.999796
example_mha_bwd_bhsd 0.0401148 0.0401204 0.99986
example_mha_bwd_bshd_wgmma_pipelined 0.0255909 0.0255929 0.999922
example_gemm_intrinsics 0.03504 0.03504 1
example_fusedmoe_tilelang 0.131038 0.13103 1.00006
example_mha_fwd_varlen 0.0454369 0.0454323 1.0001
example_tilelang_gemm_splitk_vectorize_atomicadd 1.40745 1.40721 1.00018
block_sparse_attn_tilelang 0.0102931 0.0102903 1.00027
example_mha_bwd_bshd 0.040888 0.0408757 1.0003
example_gqa_bwd_tma_reduce_varlen 0.0637609 0.0637393 1.00034
tilelang_example_sparse_tensorcore 0.0150965 0.0150907 1.00039
example_gemv 0.279269 0.279121 1.00053
example_gqa_bwd_wgmma_pipelined 0.074414 0.0743718 1.00057
example_dynamic 0.656173 0.655754 1.00064
example_gqa_bwd 0.0498605 0.0498285 1.00064
example_tilelang_gemm_fp8 0.32239 0.32151 1.00274
example_topk 0.011072 0.011041 1.00281
example_dequant_gemv_fp16xint4 0.0286686 0.0285552 1.00397
example_tilelang_gemm_fp8_2xAcc 0.187027 0.186068 1.00515
example_warp_specialize_gemm_barrierpipe_stage2 0.040289 0.039778 1.01285
example_per_token_cast_to_fp8 0.00755312 0.0074472 1.01422
example_convolution_autotune 1.00603 0.991027 1.01514
example_tilelang_nsa_decode 0.00688894 0.0067528 1.02016
example_tilelang_nsa_fwd 0.00721366 0.00706211 1.02146
example_dequant_gemm_w4a8 5.51637 5.39761 1.022
sparse_mla_fwd_pipelined 0.0966643 0.0944778 1.02314
sparse_mla_fwd 0.143962 0.140393 1.02542
example_dequant_gemm_bf16_fp4_hopper 0.593899 0.579016 1.0257
topk_selector 0.0554127 0.0540069 1.02603
example_dequant_groupedgemm_bf16_mxfp4_hopper 3.54952 3.4551 1.02733
example_warp_specialize_gemm_copy_1_gemm_0 0.03952 0.038464 1.02745
example_tilelang_block_sparse_attn 0.010477 0.0101819 1.02899
example_mha_sink_fwd_bhsd_sliding_window 0.016251 0.0157381 1.03259
example_mha_sink_fwd_bhsd_wgmma_pipelined 0.0159719 0.015453 1.03358
example_mha_sink_fwd_bhsd 0.0164361 0.0158936 1.03414
fp8_lighting_indexer 0.0372936 0.0360557 1.03433
example_mha_sink_fwd_bhsd_wgmma_pipelined_sliding_window 0.0160247 0.0154899 1.03452
example_mha_sink_bwd_bhsd_sliding_window 0.0462131 0.0446068 1.03601
example_gqa_sink_fwd_bhsd_wgmma_pipelined 0.0150008 0.0144686 1.03679
sparse_mla_bwd 0.396394 0.382157 1.03725
example_tilelang_sparse_gqa_decode_varlen_indice 0.0178466 0.0171974 1.03775
example_blocksparse_gemm 0.0235876 0.0227008 1.03906
example_gqa_sink_fwd_bhsd_wgmma_pipelined_sliding_window 0.0151598 0.0145891 1.03912
example_dequant_gemm_bf16_mxfp4_hopper 0.528999 0.508999 1.03929
example_tilelang_sparse_gqa_decode_varlen_mask 0.0243918 0.0234133 1.0418
example_mha_sink_bwd_bhsd 0.0641771 0.0615952 1.04192
example_group_per_split_token_cast_to_fp8 0.010713 0.0102774 1.04239
example_gqa_sink_bwd_bhsd_sliding_window 0.0268126 0.025582 1.0481
example_gqa_sink_bwd_bhsd 0.0438027 0.0416591 1.05146
example_convolution 1.40166 1.33286 1.05162
example_dequant_gemm_fp4_hopper 1.11941 1.06261 1.05345
example_mla_decode 0.487368 0.461322 1.05646

Artifacts

  • regression_result.png (speedup plot) is attached as a workflow artifact. Download it from the workflow run page above.

…perations

* Updated the handling of loop annotations in both AtomicAddNode and CopyNode classes to ensure that coalesced width and parallel loop layout annotations are only applied to the outermost loop.
* This change improves the clarity and correctness of loop management in SIMT operations, aligning with the recent enhancements made to layout annotation handling in parallel loops.
@LeiWang1999

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex review is not enabled for this repo. Please contact the admins of this repo to enable Codex.

@LeiWang1999
LeiWang1999 merged commit 5685c56 into tile-ai:main Jan 4, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant