Skip to content

feat(ir): fix ForStmt loop-carry MemRef handling in InitMemRef and BasicMemoryReuse#622

Merged
lyfne123 merged 1 commit intohw-native-sys:mainfrom
zhangqi-chen:memref
Mar 19, 2026
Merged

feat(ir): fix ForStmt loop-carry MemRef handling in InitMemRef and BasicMemoryReuse#622
lyfne123 merged 1 commit intohw-native-sys:mainfrom
zhangqi-chen:memref

Conversation

@zhangqi-chen
Copy link
Contributor

Summary

Fix ForStmt loop-carry variable MemRef assignment in InitMemRef and BasicMemoryReuse passes.

InitMemRef changes

  • Refactored VisitStmt_(ForStmtPtr) to manually traverse ForStmt fields, ensuring correct MemRef inheritance order:
    • Group A: initValue + iter_arg share the same MemRef (iter_arg inherits from initValue)
    • Group B: yield value + return_var share the same MemRef (return_var inherits from yield value)
  • Previously, return_var incorrectly inherited from iter_arg instead of yield value

BasicMemoryReuse changes

  • Added ForStmtYieldFixupMutator (Step 4.5) to reconcile Group A and Group B after memory reuse:
    • When yield and iter_arg MemRefs diverge, inserts tile.move before yield to copy into initValue's buffer
    • Patches all 4 loop-carry variables to use the same MemRef (initValue's)

Shared utilities

  • Extracted FindYieldStmt from both passes into memref_utils.h to eliminate duplication

Testing

  • All 735 transform tests pass
  • All 6 init_memref tests pass (including new test_init_memref_for_stmt_loop_carry_memref_relationships)
  • All 30 basic_memory_reuse tests pass
  • Code review completed
  • clang-tidy clean
  • pyright clean
  • Documentation updated (EN + ZH-CN)

Files Changed

  • include/pypto/ir/transforms/utils/memref_utils.h — Added shared FindYieldStmt
  • src/ir/transforms/init_memref.cpp — Refactored ForStmt MemRef assignment
  • src/ir/transforms/basic_memory_reuse_pass.cpp — Added ForStmtYieldFixupMutator
  • tests/ut/ir/transforms/test_init_memref.py — Updated test for two-group MemRef model
  • docs/en/dev/passes/12-init_memref.md — Added ForStmt loop-carry section
  • docs/en/dev/passes/13-basic_memory_reuse.md — Added yield fixup step
  • docs/zh-cn/dev/passes/12-init_memref.md — Chinese translation
  • docs/zh-cn/dev/passes/13-basic_memory_reuse.md — Chinese translation

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical aspect of memory management within loop structures by refining how memory references (MemRef) are assigned and reconciled for ForStmt loop-carry variables. It ensures that memory sharing relationships are correctly established during initial memory reference assignment and consistently maintained throughout subsequent memory reuse optimizations, preventing potential inconsistencies and improving the robustness of the IR transformation passes.

Highlights

  • InitMemRef Pass Refinement: Refactored the VisitStmt_(ForStmtPtr) method in the InitMemRef pass to manually traverse ForStmt fields, ensuring correct MemRef inheritance for loop-carry variables. This establishes two distinct sharing groups: initValue with iter_arg, and yield value with return_var.
  • BasicMemoryReuse Pass Enhancement: Introduced a new ForStmtYieldFixupMutator in the BasicMemoryReuse pass. This mutator reconciles MemRef mismatches between yield and iter_arg variables after memory reuse by inserting tile.move operations when necessary, ensuring all four loop-carry variables ultimately share the same MemRef.
  • Code Reusability: Extracted the FindYieldStmt utility function from both InitMemRef and BasicMemoryReuse passes into memref_utils.h to eliminate code duplication and improve maintainability.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

InitMemRef now derives ForStmt return_var MemRefs from the loop body Yield values and exposes a shared FindYieldStmt helper; BasicMemoryReuse adds a ForStmtYieldFixupMutator that inserts tile.move when iter_arg and yield MemRefs diverge and then unifies all four loop-carry variables' MemRefs.

Changes

Cohort / File(s) Summary
Documentation (EN & CN)
docs/en/dev/passes/12-init_memref.md, docs/en/dev/passes/13-basic_memory_reuse.md, docs/zh-cn/dev/passes/12-init_memref.md, docs/zh-cn/dev/passes/13-basic_memory_reuse.md
Documented ForStmt loop-carry roles and sharing groups (initValue+iter_arg, yield+return_var) and the new BasicMemoryReuse "ForStmt yield fixup" that may insert tile.move to unify MemRefs.
MemRef Utilities
include/pypto/ir/transforms/utils/memref_utils.h
Added inline FindYieldStmt(const StmtPtr&) to recursively locate a YieldStmt in a statement subtree; added necessary header includes.
InitMemRef Pass
src/ir/transforms/init_memref.cpp
Rewrote ForStmt visitation to explicit field-by-field mutation, use temporary var_remap_ for iter_args during body visit, removed local FindYieldStmt, and changed return_var MemRef/type derivation to use YieldStmt value types.
BasicMemoryReuse Pass
src/ir/transforms/basic_memory_reuse_pass.cpp
Added ForStmtYieldFixupMutator run after ApplyMemRefSharing: compares iter_arg vs yield MemRefs, inserts tile.move (as AssignStmt) before yield when needed, substitutes yield values, and patches iter_args/return_vars to a unified MemRef; added <any>/<utility> includes.
Tests
tests/ut/ir/transforms/test_init_memref.py
Replaced old regression test with _find_yield_stmt helper and added test_init_memref_for_stmt_loop_carry_memref_relationships asserting initValue/iter_arg and yield/return_var sharing and that yield and iter_arg may differ.

Sequence Diagram

sequenceDiagram
    participant ForStmt
    participant InitMemRef
    participant BasicMemoryReuse
    participant YieldFixup as ForStmtYieldFixupMutator

    ForStmt->>InitMemRef: Visit ForStmt
    Note over InitMemRef: Locate YieldStmt in body
    InitMemRef->>InitMemRef: Set initValue & iter_arg MemRef (group A)
    InitMemRef->>InitMemRef: Set yield & return_var MemRef (group B)
    InitMemRef-->>ForStmt: Emit mutated ForStmt

    ForStmt->>BasicMemoryReuse: Process ForStmt
    BasicMemoryReuse->>BasicMemoryReuse: ApplyMemRefSharing
    BasicMemoryReuse->>YieldFixup: Check iter_arg vs yield MemRef

    alt Divergent MemRefs
        YieldFixup->>YieldFixup: Create moved Var with initValue MemRef
        YieldFixup->>YieldFixup: Insert tile.move (AssignStmt) before YieldStmt
        YieldFixup->>YieldFixup: Replace YieldStmt values with moved Vars
        YieldFixup->>YieldFixup: Patch iter_args & return_vars to unified MemRef
    else Aligned or no moves needed
        YieldFixup->>YieldFixup: Patch iter_args & return_vars types as needed
    end

    YieldFixup-->>ForStmt: Return ForStmt with unified loop-carry MemRefs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • lyfne123
  • Hzfengsy

🐰 In loops where MemRefs hop and hide,
I dig a path where yields abide.
A tiny move, a gentle stitch,
Now four friends share the same small niche,
Hooray — no drifting MemRef glitch! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(ir): fix ForStmt loop-carry MemRef handling in InitMemRef and BasicMemoryReuse' clearly and specifically describes the main change: fixing ForStmt loop-carry MemRef handling across two key compiler passes.
Description check ✅ Passed The description comprehensively covers the changeset, detailing InitMemRef refactoring for correct MemRef inheritance order, BasicMemoryReuse additions for reconciling divergent MemRefs, shared utility extraction, and testing results.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.

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

📝 Coding Plan
  • Generate coding plan for human review comments

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.

Tip

You can customize the high-level summary generated by CodeRabbit.

Configure the reviews.high_level_summary_instructions setting to provide custom instructions for generating the high-level summary.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request significantly improves the handling of MemRef assignments for ForStmt loop-carry variables within the InitMemRef and BasicMemoryReuse passes. The refactoring in InitMemRefMutator provides more precise control over MemRef inheritance, ensuring iter_args inherit from initValue and return_vars from yield values. The introduction of ForStmtYieldFixupMutator in BasicMemoryReuse is a critical addition, correctly resolving potential MemRef mismatches between iter_arg and yield value by inserting tile.move operations. The extraction of FindYieldStmt into a shared utility header promotes code reuse. The updated documentation clearly explains these complex interactions, and the new test cases provide excellent validation for the revised MemRef relationships. Overall, these changes enhance the correctness and robustness of memory management within loop constructs.

Copy link

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
src/ir/transforms/basic_memory_reuse_pass.cpp (1)

915-924: ⚠️ Potential issue | 🔴 Critical

Run the loop-carry fixup even when generic reuse finds nothing.

Lines 915-917 return before ForStmtYieldFixupMutator and alloc cleanup run. That skips the new loop-only repair path for cases where yield still differs from initValue/iter_arg but no ordinary reuse candidate exists.

💡 Minimal fix
-  if (reuse_map.empty()) {
-    return func;
-  }
-
-  // Step 4: Apply MemRef sharing
-  StmtPtr new_body = ApplyMemRefSharing(func->body_, reuse_map, analysis_result.var_sharing_groups);
+  StmtPtr new_body = func->body_;
+  if (!reuse_map.empty()) {
+    new_body = ApplyMemRefSharing(func->body_, reuse_map, analysis_result.var_sharing_groups);
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ir/transforms/basic_memory_reuse_pass.cpp` around lines 915 - 924, The
early return when reuse_map.empty() skips loop-carry repairs and alloc cleanup;
change control flow so that even when reuse_map is empty you still run
ForStmtYieldFixupMutator and the alloc cleanup path on func->body_.
Specifically, remove or bypass the return that exits when reuse_map.empty(),
then always set StmtPtr new_body = (reuse_map.empty() ? func->body_ :
ApplyMemRefSharing(func->body_, reuse_map, analysis_result.var_sharing_groups));
then invoke ForStmtYieldFixupMutator yield_fixup; new_body =
yield_fixup.VisitStmt(new_body); and proceed with the existing alloc cleanup
logic so loop-only yield/iter_arg mismatches are fixed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/en/dev/passes/13-basic_memory_reuse.md`:
- Around line 47-48: Update the docs to reflect the actual pass order: move the
"ForStmt yield fixup" bullet so ForStmtYieldFixupMutator is listed before the
"Remove redundant allocs"/RemoveUnusedAllocStatements step (the C++
implementation in src/ir/transforms/basic_memory_reuse_pass.cpp runs
ForStmtYieldFixupMutator first), and make the same reordering in the
corresponding zh-CN page (also adjust the duplicate occurrence around lines
141-142 in the English doc to match); ensure the bullets reference the same step
names (ForStmtYieldFixupMutator and RemoveUnusedAllocStatements/Remove redundant
allocs) so documentation matches the code.

---

Outside diff comments:
In `@src/ir/transforms/basic_memory_reuse_pass.cpp`:
- Around line 915-924: The early return when reuse_map.empty() skips loop-carry
repairs and alloc cleanup; change control flow so that even when reuse_map is
empty you still run ForStmtYieldFixupMutator and the alloc cleanup path on
func->body_. Specifically, remove or bypass the return that exits when
reuse_map.empty(), then always set StmtPtr new_body = (reuse_map.empty() ?
func->body_ : ApplyMemRefSharing(func->body_, reuse_map,
analysis_result.var_sharing_groups)); then invoke ForStmtYieldFixupMutator
yield_fixup; new_body = yield_fixup.VisitStmt(new_body); and proceed with the
existing alloc cleanup logic so loop-only yield/iter_arg mismatches are fixed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dc947204-7489-4e28-a8f2-9dd293282c49

📥 Commits

Reviewing files that changed from the base of the PR and between 95925ed and a45b05c.

📒 Files selected for processing (8)
  • docs/en/dev/passes/12-init_memref.md
  • docs/en/dev/passes/13-basic_memory_reuse.md
  • docs/zh-cn/dev/passes/12-init_memref.md
  • docs/zh-cn/dev/passes/13-basic_memory_reuse.md
  • include/pypto/ir/transforms/utils/memref_utils.h
  • src/ir/transforms/basic_memory_reuse_pass.cpp
  • src/ir/transforms/init_memref.cpp
  • tests/ut/ir/transforms/test_init_memref.py

Copy link

@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.

🧹 Nitpick comments (1)
tests/ut/ir/transforms/test_init_memref.py (1)

500-503: Consider renaming to avoid variable shadowing.

init_tile is first defined as an ir.Var (line 427), then shadowed here as ir.TileType. This variable reuse across different types can be confusing when reading the test.

♻️ Suggested rename for clarity
-    init_tile = cast(ir.TileType, init_value.type)
-    iter_arg_tile = cast(ir.TileType, loop_iter_arg.type)
-    yield_tile = cast(ir.TileType, yield_var.type)
-    return_var_tile = cast(ir.TileType, loop_return_var.type)
+    init_tile_type = cast(ir.TileType, init_value.type)
+    iter_arg_tile_type = cast(ir.TileType, loop_iter_arg.type)
+    yield_tile_type = cast(ir.TileType, yield_var.type)
+    return_var_tile_type = cast(ir.TileType, loop_return_var.type)
 
-    assert init_tile.shares_memref_with(iter_arg_tile), "initValue and iter_arg must share MemRef"
+    assert init_tile_type.shares_memref_with(iter_arg_tile_type), "initValue and iter_arg must share MemRef"
 
     # Group B: yield value and return_var share the same MemRef
-    assert yield_tile.shares_memref_with(return_var_tile), "yield value and return_var must share MemRef"
+    assert yield_tile_type.shares_memref_with(return_var_tile_type), "yield value and return_var must share MemRef"
 
     # Group A and B have different MemRefs (yield gets independent MemRef from tile.add)
-    assert not yield_tile.shares_memref_with(iter_arg_tile), (
+    assert not yield_tile_type.shares_memref_with(iter_arg_tile_type), (
         "yield value should get its own MemRef from tile.add, not share with iter_arg"
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/ut/ir/transforms/test_init_memref.py` around lines 500 - 503, The
variable init_tile is shadowed: earlier it held an ir.Var and here it's
reassigned to an ir.TileType, which is confusing; rename the TileType instance
(e.g., init_tile_type or init_tile_ty) and update its usages (the casts of
init_value.type, loop_iter_arg.type, yield_var.type, loop_return_var.type) so
the original ir.Var named init_tile remains distinct from the newly named
TileType variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/ut/ir/transforms/test_init_memref.py`:
- Around line 500-503: The variable init_tile is shadowed: earlier it held an
ir.Var and here it's reassigned to an ir.TileType, which is confusing; rename
the TileType instance (e.g., init_tile_type or init_tile_ty) and update its
usages (the casts of init_value.type, loop_iter_arg.type, yield_var.type,
loop_return_var.type) so the original ir.Var named init_tile remains distinct
from the newly named TileType variables.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 51414509-f94b-4c1a-910f-157c239a4afc

📥 Commits

Reviewing files that changed from the base of the PR and between a45b05c and 4011a69.

📒 Files selected for processing (8)
  • docs/en/dev/passes/12-init_memref.md
  • docs/en/dev/passes/13-basic_memory_reuse.md
  • docs/zh-cn/dev/passes/12-init_memref.md
  • docs/zh-cn/dev/passes/13-basic_memory_reuse.md
  • include/pypto/ir/transforms/utils/memref_utils.h
  • src/ir/transforms/basic_memory_reuse_pass.cpp
  • src/ir/transforms/init_memref.cpp
  • tests/ut/ir/transforms/test_init_memref.py
✅ Files skipped from review due to trivial changes (2)
  • docs/en/dev/passes/12-init_memref.md
  • docs/zh-cn/dev/passes/12-init_memref.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • docs/en/dev/passes/13-basic_memory_reuse.md
  • include/pypto/ir/transforms/utils/memref_utils.h
  • docs/zh-cn/dev/passes/13-basic_memory_reuse.md
  • src/ir/transforms/basic_memory_reuse_pass.cpp

…sicMemoryReuse

InitMemRef now correctly assigns MemRefs to ForStmt loop-carry variables
in two groups: initValue+iter_arg share one MemRef, yield+return_var
share another. BasicMemoryReuse adds ForStmtYieldFixupMutator to
reconcile the two groups by inserting tile.move when needed.

Also extracts shared FindYieldStmt utility to memref_utils.h.
@lyfne123 lyfne123 merged commit 71603ab into hw-native-sys:main Mar 19, 2026
7 checks passed
@zhangqi-chen zhangqi-chen deleted the memref branch March 19, 2026 09:26
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