Skip to content

Introduce letstmt defined variables in auto schedule pipeline#3

Merged
silentCoder-dev merged 7 commits into
silentCoder-dev:auto-schedulefrom
Denverjin:auto-schedule
Apr 1, 2026
Merged

Introduce letstmt defined variables in auto schedule pipeline#3
silentCoder-dev merged 7 commits into
silentCoder-dev:auto-schedulefrom
Denverjin:auto-schedule

Conversation

@Denverjin

@Denverjin Denverjin commented Mar 30, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

Release Notes

  • Refactor
    • Improved IR structure ownership model and variable dependency tracking for more efficient auto-scheduling decisions
    • Enhanced variable and memory access analysis across the optimization pipeline
    • Streamlined condition handling in code generation

Comment thread tilelang/engine/phase.py

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The debugging info should be removed

Comment thread src/transform/auto_schedule.cc Outdated
}
}

// LOG(INFO) << "Cloned task: " << cloned_task->stmts[0];

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The debugging info should be removed

@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR refactors the auto-scheduling infrastructure to support shared pointer ownership semantics and variable-level dependency tracking. It switches IR node children from unique_ptr to shared_ptr, adds variable tracking via GetReadVars()/GetWriteVars() across IR nodes, replaces the if-binding pass with a new if-condition-extraction pass, and introduces let-declaration handling in warpgroup partitioning.

Changes

Cohort / File(s) Summary
IR Structure Ownership
src/transform/auto_schedule/ir_structure.h, src/transform/auto_schedule/ir_structure.cc
Changed Clone() return type and child storage from unique_ptr to shared_ptr across all node types (TaskNode, ControlNode, WrapperNode, ScheduleUnit, SequenceNode). Added task field to WrapperNode. Removed region mutation hooks (AddReadRegion/AddWriteRegion).
Variable Tracking System
src/transform/auto_schedule/ir_structure.h, src/transform/auto_schedule/ir_structure.cc, src/transform/auto_schedule/memory_detector.h
Introduced pure virtual GetReadVars()/GetWriteVars() in base IRStructure class with implementations across all node types. Added variable tracking in MemoryAccessDetector with GetReadVars()/GetWriteVars() accessors and visitor extensions for variable recording.
Auto-schedule Core Logic
src/transform/auto_schedule.cc
Added GatherTaskNodes utilities for flattening task-bearing nodes. Updated scheduling functions (Z3SchedulePythonLoop, ScheduleRecursive) to operate on shared_ptr children. Extended dependency analysis with variable-level RAW/WAR/WAW tracking. Introduced let-declaration handling pass with wrapper node creation, transitive let-decl analysis, and unused decl removal. Updated warpgroup cloning to use shared pointers and var remapping.
If Condition Extraction Pass
src/transform/if_condition_extract.cc, tilelang/engine/phase.py, tilelang/transform/__init__.py
Added new TIR pass IfConditionExtractor that extracts if conditions into let-bound variables and flattens nested sequences. Replaced IfStmtBinding() with IfConditionExtract() in the lower-and-legalize pipeline. Exposed new pass via FFI and Python wrapper.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A rabbit hops through code so tall,
With shared pointers catching all,
Variables tracked from start to end,
If-conditions now descend,
Scheduling flows in perfect accord! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Introduce letstmt defined variables in auto schedule pipeline' directly and clearly describes the main feature being added throughout the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@silentCoder-dev

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
src/transform/auto_schedule/ir_structure.cc (1)

337-349: ⚠️ Potential issue | 🟠 Major

ScheduleUnit::Clone() drops scheduled side statements.

Lines 337-349 clone the child and stage, but not before / after. Any clone-based path loses the inserted prologue/epilogue statements carried by the unit and can emit different IR than the source tree.

Suggested fix
 std::shared_ptr<IRStructure> ScheduleUnit::Clone() const {
   auto new_unit = std::make_shared<ScheduleUnit>();
   // Copy var and value (TVM objects with reference counting)
   new_unit->stage = stage;
+  new_unit->before = before;
+  new_unit->after = after;
   // Clone child if exists
   if (child) {
     new_unit->child = child->Clone();
   }
   // Copy latency and II
   new_unit->SetLatency(GetLatency());
   new_unit->SetII(GetII());
+  new_unit->SetStartTime(GetStartTime());
   return new_unit;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/transform/auto_schedule/ir_structure.cc` around lines 337 - 349,
ScheduleUnit::Clone currently copies stage, child, latency and II but omits the
scheduled prologue/epilogue statements (before/after), so cloned units lose
inserted side statements. Update ScheduleUnit::Clone (the method) to also copy
the unit's before and after fields (or call the existing accessors like
GetBefore()/GetAfter() or setters like SetBefore()/SetAfter() if present) into
new_unit; if the before/after are AST/TVM nodes and need deep copy use their
Clone/Copy method, otherwise perform a shallow copy/pointer assignment
consistent with how stage and child are handled so the cloned ScheduleUnit
preserves the scheduled side statements.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/transform/auto_schedule.cc`:
- Around line 856-862: The cloned TaskNode created as cloned_task currently only
contains the cloned_let_stmt and lacks dependency metadata, so
SolveConflictVar()'s HasDependency() treats it as independent; update the clone
creation (where cloned_task is made and cloned_let_stmt is pushed) to also
populate the cloned task's dependency info by copying/deriving read/write
regions and var usages from the original node_i_let_stmt (or its parent task)
into cloned_task (e.g., read_regions, write_regions, and any var sets used by
HasDependency()); ensure stage_map[cloned_task.get()] remains set to rem_stage_j
after these metadata fields are filled so later passes see correct dependencies.

In `@src/transform/auto_schedule/ir_structure.h`:
- Around line 297-299: The current containWarpgroupId(int id) always returns
true when ContainsLoopBreak() is true, causing loop_break tasks (which should be
neutral-only and have warpgroup_id_ == -1) to be duplicated into
wg0_structure/wg1_structure; change containWarpgroupId to treat loop_break tasks
as neutral by returning false when ContainsLoopBreak() is true, otherwise return
warpgroup_id_ == id; update the containWarpgroupId implementation in the
IRStructure class so that the ContainsLoopBreak() check yields false instead of
true and confirm ApplyWarpgroupPartitionToIRStructure() will continue to emit
those tasks via the neutral clone path.

In `@src/transform/auto_schedule/memory_detector.h`:
- Around line 266-270: VisitStmt_(const LetStmtNode *op) records the let binding
before traversing the initializer, so reads inside op->value are never recorded;
change the order to traverse the initializer first (visit op->value with the
appropriate visitor), then insert into let_bindings_ and call
UpdateWriteVar(op->var), then traverse op->body via StmtExprVisitor::VisitStmt;
reference symbols: VisitStmt_, LetStmtNode, let_bindings_, UpdateWriteVar, and
StmtExprVisitor::VisitStmt.

In `@src/transform/if_condition_extract.cc`:
- Around line 59-88: The rewrite currently alters control-flow by merging inner
if conditions and by splitting SeqStmt into independently guarded statements;
fix it by (1) changing bind_cond_var so it does NOT merge conditions for nested
IfThenElseNodes but instead wraps the entire sentence under cond (i.e., return
IfThenElse(cond, sentence) rather than combining cond & if_sentence->condition),
(2) changing bind_cond_var_body so that when body is a SeqStmtNode you do NOT
iterate and wrap each element individually but instead wrap the whole SeqStmt as
a single guarded statement (preserve LetStmt/AttrStmt scope), and (3) ensure the
parent else branch is guarded with the negation of cond_var (use !cond_var when
inserting else_case) so the else executes only when cond is false; adjust uses
of bind_cond_var, bind_cond_var_body, cond_var, then_case, and else_case
accordingly.

---

Outside diff comments:
In `@src/transform/auto_schedule/ir_structure.cc`:
- Around line 337-349: ScheduleUnit::Clone currently copies stage, child,
latency and II but omits the scheduled prologue/epilogue statements
(before/after), so cloned units lose inserted side statements. Update
ScheduleUnit::Clone (the method) to also copy the unit's before and after fields
(or call the existing accessors like GetBefore()/GetAfter() or setters like
SetBefore()/SetAfter() if present) into new_unit; if the before/after are
AST/TVM nodes and need deep copy use their Clone/Copy method, otherwise perform
a shallow copy/pointer assignment consistent with how stage and child are
handled so the cloned ScheduleUnit preserves the scheduled side statements.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3e7ea5c8-bbe9-4130-8d6b-b413b4ec70ec

📥 Commits

Reviewing files that changed from the base of the PR and between 1d96897 and 0687a3f.

📒 Files selected for processing (7)
  • src/transform/auto_schedule.cc
  • src/transform/auto_schedule/ir_structure.cc
  • src/transform/auto_schedule/ir_structure.h
  • src/transform/auto_schedule/memory_detector.h
  • src/transform/if_condition_extract.cc
  • tilelang/engine/phase.py
  • tilelang/transform/__init__.py

Comment thread src/transform/auto_schedule.cc
Comment thread src/transform/auto_schedule/ir_structure.h
Comment thread src/transform/auto_schedule/memory_detector.h
Comment thread src/transform/if_condition_extract.cc
@silentCoder-dev silentCoder-dev merged commit 22ecc7b into silentCoder-dev:auto-schedule Apr 1, 2026
3 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.

2 participants