Skip to content

[Enhancement] Update LetStmtNode handling in loop vectorization to support variable binding overrides#1649

Merged
LeiWang1999 merged 2 commits intotile-ai:mainfrom
Rachmanino:fix-conv
Jan 11, 2026
Merged

[Enhancement] Update LetStmtNode handling in loop vectorization to support variable binding overrides#1649
LeiWang1999 merged 2 commits intotile-ai:mainfrom
Rachmanino:fix-conv

Conversation

@Rachmanino
Copy link
Collaborator

@Rachmanino Rachmanino commented Jan 9, 2026

fix #1472

Summary by CodeRabbit

  • Bug Fixes
    • Improved loop vectorization to better handle certain let-variable bindings, yielding more reliable optimized code generation and preserving correctness in compiled loops. No changes to public APIs or exported interfaces.

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

@github-actions
Copy link

github-actions bot commented Jan 9, 2026

👋 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
Copy link
Contributor

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Adds a private override VisitStmt_(const LetStmtNode*) in VectorizePlanner to handle LetStmt: visits the let value, conditionally binds the let variable with allow_override when side effects are pure, visits the body, and reconstructs the LetStmt only if children changed.

Changes

Cohort / File(s) Summary
LetStmt handling in VectorizePlanner
src/transform/loop_vectorize.cc
Add VisitStmt_(const LetStmtNode* op) override that visits the let value, binds the let variable using allow_override when the value has pure side effects, visits the body, and rebuilds the LetStmt only if value or body changed to avoid conflicting analyzer bindings during vectorization.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Poem

🐰 I nibble on binds and hop through each line,
Visiting values where clean side-effects shine,
A gentle allow_override lets my paws roam,
Rebuild only when children have changed home,
Vectorized hops — quick, neat, and fine.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: updating LetStmtNode handling in loop vectorization to support variable binding overrides, which directly addresses the variable binding issue reported in #1472.
Linked Issues check ✅ Passed The PR adds LetStmtNode handling to VectorizePlanner that allows variable binding overrides with pure side effects, directly addressing the var-update error in #1472 where in_bound variables couldn't be re-bound with semantically equivalent expressions during vectorization.
Out of Scope Changes check ✅ Passed All changes are scoped to LetStmt handling in loop vectorization, directly supporting the objective of fixing variable binding issues in #1472 without modifying unrelated code paths.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 5de1904 and b73eb8a.

📒 Files selected for processing (1)
  • src/transform/loop_vectorize.cc
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/transform/loop_vectorize.cc
⏰ 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)

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.

@Rachmanino Rachmanino changed the title fix a bug in conv example by inlining variable [BugFix] Fix a bug in conv example by inlining variable Jan 9, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (1)
examples/convolution/example_convolution.py (1)

32-33: Remove redundant reassignments.

Lines 32-33 reassign dtype and accum_dtype to the same values already set as parameter defaults on line 28. These assignments serve no purpose and can be removed.

♻️ Suggested cleanup
-    dtype = T.float16
-    accum_dtype = T.float32
     is_hopper = check_hopper()
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e43953 and cb910ff.

📒 Files selected for processing (1)
  • examples/convolution/example_convolution.py
⏰ 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). (1)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
🔇 Additional comments (1)
examples/convolution/example_convolution.py (1)

61-65: LGTM! The inline fix correctly resolves the var update error.

The inlined boundary condition eliminates the TVM compilation error by avoiding an intermediate variable assignment. The logic is correct:

  • All four boundary checks are properly combined with and operators
  • Data access and zero-fill paths are unchanged from the original intent
  • The im2col addressing for access_h and access_w remains valid

@LeiWang1999
Copy link
Member

would be better to know why for this bug? do you have any thoughts @Rachmanino

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (1)
src/transform/loop_vectorize.cc (1)

217-228: Consider reconstructing LetStmt with mutated children for correctness.

The current implementation visits op->value and op->body but returns the original op unchanged, discarding any mutations from child visits. While this may be acceptable since Plan() only uses the vector_size_ side-effect (line 91-92), it violates the mutator contract and creates inconsistency with other VisitStmt_ methods in this class (lines 117, 141, 146) that delegate to the parent.

♻️ Recommended pattern: reconstruct with mutated children
  Stmt VisitStmt_(const LetStmtNode *op) final {
    // Visit value and body without binding the variable to analyzer
-   this->VisitExpr(op->value);
-   this->VisitStmt(op->body);
-   return ffi::GetRef<Stmt>(op);
+   PrimExpr value = this->VisitExpr(op->value);
+   Stmt body = this->VisitStmt(op->body);
+   if (value.same_as(op->value) && body.same_as(op->body)) {
+     return ffi::GetRef<Stmt>(op);
+   } else {
+     return LetStmt(op->var, value, body, op->span);
+   }
  }

This preserves mutations while still avoiding analyzer binding.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb910ff and 45d022f.

📒 Files selected for processing (1)
  • src/transform/loop_vectorize.cc
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-12T09:47:46.474Z
Learnt from: kurisu6912
Repo: tile-ai/tilelang PR: 794
File: tilelang/transform/add_bufstore_wrapper.py:30-33
Timestamp: 2025-09-12T09:47:46.474Z
Learning: In TVM's PyStmtExprMutator, visit_block_ methods typically call super().visit_block_(op) to process child nodes and update internal state, but return the original op when the block itself doesn't need transformation. The pattern `return op` is correct for blocks that serve as containers where mutations happen at deeper levels.

Applied to files:

  • src/transform/loop_vectorize.cc
🧬 Code graph analysis (1)
src/transform/loop_vectorize.cc (1)
src/transform/layout_inference.cc (16)
  • op (45-51)
  • op (45-45)
  • op (482-549)
  • op (482-482)
  • op (610-700)
  • op (610-610)
  • op (702-757)
  • op (702-702)
  • op (759-768)
  • op (759-759)
  • op (770-775)
  • op (770-770)
  • op (794-822)
  • op (794-794)
  • op (824-852)
  • op (824-824)
⏰ 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 (1)
src/transform/loop_vectorize.cc (1)

217-228: Verify this resolves the variable binding issue in pipelined loops (PR #1639).

The fix prevents analyzer binding of let variables to avoid internal TVM errors when variables are rebound with different values (e.g., in pipelined/unrolled loops). The code change is already implemented in commit 45d022f. Confirm that:

  1. The convolution example (examples/convolution/example_convolution.py) runs without errors
  2. Skipping let-variable bindings doesn't break vectorization analysis for other cases
  3. The vector size computation remains correct when let statements are present

Likely an incorrect or invalid review comment.

@Rachmanino Rachmanino changed the title [BugFix] Fix a bug in conv example by inlining variable [Enhancement] Update LetStmtNode handling in loop vectorization to support variable binding overrides Jan 9, 2026
…pport variable binding overrides

* Implemented a new VisitStmt_ method for LetStmtNode to allow the analyzer to override variable bindings, addressing issues with duplicated variable names in pipelined loops.
* Enhanced the logic to continue visiting the body of the statement for vectorization information collection while ensuring correct handling of side effects.
* This change improves the robustness of loop vectorization in scenarios with complex variable bindings.
@Rachmanino Rachmanino requested a review from LeiWang1999 January 9, 2026 12:56
@LeiWang1999 LeiWang1999 merged commit efdeadc into tile-ai:main Jan 11, 2026
6 checks passed
@Rachmanino Rachmanino deleted the fix-conv branch January 11, 2026 09:25
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.

Var update error in the convolution example

2 participants