This is an automated email from the ASF dual-hosted git repository.

syfeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new f1ba5ed5f3 [BugFix][TIR] Schedule support reverse-inline with 
reduction blocks (#17838)
f1ba5ed5f3 is described below

commit f1ba5ed5f38198947648a00bfeef8f8da86e9f7c
Author: Ruihang Lai <[email protected]>
AuthorDate: Tue Apr 15 04:34:59 2025 -0400

    [BugFix][TIR] Schedule support reverse-inline with reduction blocks (#17838)
    
    This PR fixes a bug in reverse-compute-inline of tir Schedule, which
    generates incorrect TIR after inlining a transpose block into a
    reduction block.
---
 src/tir/schedule/primitive/compute_inline.cc       | 28 ++++++++++++-
 .../test_tir_schedule_compute_inline.py            | 49 ++++++++++++++++++++++
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/src/tir/schedule/primitive/compute_inline.cc 
b/src/tir/schedule/primitive/compute_inline.cc
index df74497b4a..85f3a0f82f 100644
--- a/src/tir/schedule/primitive/compute_inline.cc
+++ b/src/tir/schedule/primitive/compute_inline.cc
@@ -586,6 +586,30 @@ class ReverseComputeInliner : public BaseInliner {
     ReverseComputeInliner* self_;
   };
 
+  class RecursionResolver : public StmtExprMutator {
+   public:
+    explicit RecursionResolver(ReverseComputeInliner* self) : self_(self) {}
+
+   private:
+    PrimExpr VisitExpr_(const VarNode* var) final {
+      auto it = self_->idx_sub_.find(var);
+      if (it == self_->idx_sub_.end()) {
+        return GetRef<Var>(var);
+      }
+      return (*it).second;
+    }
+
+    PrimExpr VisitExpr_(const BufferLoadNode* _load) final {
+      BufferLoad load = 
Downcast<BufferLoad>(StmtExprMutator::VisitExpr_(_load));
+      return load->buffer.same_as(self_->inlined_buffer_)
+                 ? StmtExprMutator::VisitExpr(
+                       BufferLoad(self_->inlined_store_->buffer, 
self_->inlined_store_->indices))
+                 : load;
+    }
+
+    ReverseComputeInliner* self_;
+  };
+
  public:
   explicit ReverseComputeInliner(const Buffer& inlined_buffer, const 
BlockNode* producer_block,
                                  const BlockRealize& consumer_block_realize,
@@ -784,7 +808,9 @@ class ReverseComputeInliner : public BaseInliner {
   }
 
   Stmt ReplaceInlinedBuffer(BufferStore producer) {
-    producer_rhs_ = producer->value;
+    // "producer->value" may contain the buffer that is inlined in cases of 
reduction,
+    // so we need to resolve the recursion first
+    producer_rhs_ = RecursionResolver(this)(producer->value);
     return Substituter(this)(GetRef<BufferStore>(inlined_store_));
   }
 
diff --git a/tests/python/tir-schedule/test_tir_schedule_compute_inline.py 
b/tests/python/tir-schedule/test_tir_schedule_compute_inline.py
index 2f779612a7..066070f763 100644
--- a/tests/python/tir-schedule/test_tir_schedule_compute_inline.py
+++ b/tests/python/tir-schedule/test_tir_schedule_compute_inline.py
@@ -1529,5 +1529,54 @@ def 
test_reverse_compute_inline_slicing_then_cachewrite():
     assert_structural_equal_ignore_global_symbol(after, sch.mod["main"])
 
 
+def test_inline_with_reduction():
+    @T.prim_func
+    def before(
+        T_softmax_norm: T.Buffer((T.int64(6), T.int64(1), T.int64(1)), 
"float32"),
+        T_reshape_2: T.Buffer((T.int64(6), T.int64(1), T.int64(64)), 
"float32"),
+        T_transpose: T.Buffer((T.int64(1), T.int64(1), T.int64(6), 
T.int64(64)), "float32"),
+    ):
+        T_batch_matmul_NN = T.alloc_buffer((T.int64(6), T.int64(1), 
T.int64(64)))
+        for ax0, ax1 in T.grid(T.int64(6), T.int64(64)):
+            with T.block("bmm"):
+                v0, v1 = T.axis.remap("SS", [ax0, ax1])
+                T.reads(T_softmax_norm[v0, T.int64(0), T.int64(0)], 
T_reshape_2[v0, T.int64(0), v1])
+                T.writes(T_batch_matmul_NN[v0, T.int64(0), v1])
+                with T.init():
+                    T_batch_matmul_NN[v0, T.int64(0), v1] = T.float32(0.0)
+                T_batch_matmul_NN[v0, T.int64(0), v1] = (
+                    T_batch_matmul_NN[v0, T.int64(0), v1]
+                    + T_softmax_norm[v0, T.int64(0), T.int64(0)] * 
T_reshape_2[v0, T.int64(0), v1]
+                )
+        for ax0, ax1 in T.grid(T.int64(6), T.int64(64)):
+            with T.block("transpose"):
+                v0, v1 = T.axis.remap("SS", [ax0, ax1])
+                T.reads(T_batch_matmul_NN[v0, T.int64(0), v1])
+                T.writes(T_transpose[T.int64(0), T.int64(0), v0, v1])
+                T_transpose[T.int64(0), T.int64(0), v0, v1] = 
T_batch_matmul_NN[v0, T.int64(0), v1]
+
+    @T.prim_func
+    def after(
+        T_softmax_norm: T.Buffer((T.int64(6), T.int64(1), T.int64(1)), 
"float32"),
+        T_reshape_2: T.Buffer((T.int64(6), T.int64(1), T.int64(64)), 
"float32"),
+        T_transpose: T.Buffer((T.int64(1), T.int64(1), T.int64(6), 
T.int64(64)), "float32"),
+    ):
+        for ax0, ax1 in T.grid(T.int64(6), T.int64(64)):
+            with T.block("bmm"):
+                v0, v1 = T.axis.remap("SS", [ax0, ax1])
+                T.reads(T_softmax_norm[v0, T.int64(0), T.int64(0)], 
T_reshape_2[v0, T.int64(0), v1])
+                T.writes(T_transpose[T.int64(0), T.int64(0), v0, v1])
+                with T.init():
+                    T_transpose[T.int64(0), T.int64(0), v0, v1] = 
T.float32(0.0)
+                T_transpose[T.int64(0), T.int64(0), v0, v1] = (
+                    T_transpose[T.int64(0), T.int64(0), v0, v1]
+                    + T_softmax_norm[v0, T.int64(0), T.int64(0)] * 
T_reshape_2[v0, T.int64(0), v1]
+                )
+
+    sch = tir.Schedule(before)
+    sch.reverse_compute_inline(sch.get_block("transpose"))
+    assert_structural_equal_ignore_global_symbol(after, sch.mod["main"])
+
+
 if __name__ == "__main__":
     tvm.testing.main()

Reply via email to