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

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


The following commit(s) were added to refs/heads/main by this push:
     new 27404a5eb [FIX] Remap logical tensor geometry before offset 
linearization (#47)
27404a5eb is described below

commit 27404a5eba659db7a0d0bd10c1d27f1360860613
Author: Tianqi Chen <[email protected]>
AuthorDate: Sat Oct 24 18:30:12 2026 -0400

    [FIX] Remap logical tensor geometry before offset linearization (#47)
    
    LowerTensorLayouts can retain references to an original tensor when
    another tensor uses its loads in shape-derived offsets. Remap the
    logical tensor type before applying its layout or computing element
    offsets so shape and layout expressions use the rebuilt bindings.
    Preserve the original logical rank and already-lowered access indices.
---
 src/tirx/transform/lower_tensor_layouts.cc         | 21 ++++++++--------
 .../tirx/transform/test_lower_tensor_layouts.py    | 28 ++++++++++++++++++++++
 2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/src/tirx/transform/lower_tensor_layouts.cc 
b/src/tirx/transform/lower_tensor_layouts.cc
index d06164a14..c65638175 100644
--- a/src/tirx/transform/lower_tensor_layouts.cc
+++ b/src/tirx/transform/lower_tensor_layouts.cc
@@ -301,17 +301,18 @@ class LayoutApplier : public StmtExprMutatorWithAnalyzer {
 
   ffi::Array<PrimExpr> GetSimplifiedElemOffset(const TensorVar& tensor,
                                                const ffi::Array<PrimExpr>& 
indices) {
-    if (tensor.ty()->layout.has_value()) {
-      if (auto tile = tensor.ty()->layout.value().as<TileLayoutObj>();
+    // Remap the ty first since the type may depend on previously remapped 
value in mutator.
+    auto logical_type = StmtExprMutator::Mutate(ffi::AnyView(tensor.ty()), 
InplaceMode::kDisallow)
+                            .ValueOrUnchanged(tensor.ty())
+                            .as_or_throw<TensorType>();
+    if (logical_type->layout.has_value()) {
+      if (auto tile = logical_type->layout.value().as<TileLayoutObj>();
           tile && ffi::GetRef<TileLayout>(tile).HasThreadAxis()) {
         LOG(FATAL) << "Cannot lower direct TensorLoad/TensorStore on a tensor 
with thread-axis "
                    << "layout: unable to verify that the coordinate matches 
the current thread. "
                    << "Use .view() + .local() to decompose thread and memory 
axes.";
       }
-      auto layout = tensor.ty()->layout.value();
-      layout = StmtExprMutator::Mutate(ffi::AnyView(layout), 
InplaceMode::kDisallow)
-                   .ValueOrUnchanged(layout)
-                   .as_or_throw<Layout>();
+      auto layout = logical_type->layout.value();
       auto flat = GetFlattenedTensor(tensor);
       auto pattern = MatchShapeStridePattern(flat.ty()).value();
       if (!prim::IsZero(pattern.get<2>())) {
@@ -319,14 +320,14 @@ class LayoutApplier : public StmtExprMutatorWithAnalyzer {
         auto tile = layout.as_or_throw<TileLayout>();
         layout = TileLayout(tile->shard, tile->replica, {});
       }
-      auto res = layout.Canonicalize().Apply(indices, tensor.shape());
-      if (res.empty() && tensor.shape().empty()) {
-        return {IntImm(tensor.ty()->DefaultIndexType(), 0)};
+      auto res = layout.Canonicalize().Apply(indices, logical_type->shape);
+      if (res.empty() && logical_type->shape.empty()) {
+        return {IntImm(logical_type->DefaultIndexType(), 0)};
       }
       TVM_FFI_ICHECK_EQ(res.size(), 1) << "Expected a single element offset";
       return {analyzer_->Simplify((*res.begin()).second)};
     }
-    auto flattened_indices = tensor.ty()->ElemOffset(indices);
+    auto flattened_indices = logical_type->ElemOffset(indices);
     TVM_FFI_ICHECK_EQ(flattened_indices.size(), 1) << "Expected a single 
element offset";
     return {analyzer_->Simplify(flattened_indices[0])};
   }
diff --git a/tests/python/tirx/transform/test_lower_tensor_layouts.py 
b/tests/python/tirx/transform/test_lower_tensor_layouts.py
index 91b470844..08ac5a11f 100644
--- a/tests/python/tirx/transform/test_lower_tensor_layouts.py
+++ b/tests/python/tirx/transform/test_lower_tensor_layouts.py
@@ -1536,3 +1536,31 @@ def test_alloc_tensor_swizzle_storage_span(scope):
     with tvm_tirx.target.Target({"kind": "cuda", "arch": "sm_100a"}):
         After = LowerTensorLayouts()(Before)
     tvm_tirx.ir.assert_structural_equal(After, Expected)
+
+
+def test_shape_tensor_load_is_remapped_in_flattened_offset():
+    @I.ir_module
+    class Before:
+        @T.function(private=True)
+        def main(out: T.Tensor((1,), "float32")):
+            d = T.alloc_local((1,), "int32", layout="default")
+            d[0] = 1
+            b = T.alloc_local((d[0] + 1, d[0] + 1), "float32", layout=None)
+            b[d[0], d[0]] = T.float32(1)
+            out[0] = b[d[0], d[0]]
+
+    @I.ir_module
+    class Expected:
+        @T.function(private=True)
+        def main(out: T.Tensor((1,), "float32")):
+            d = T.alloc_local((1,), "int32", layout=None)
+            d[0] = 1
+            b = T.alloc_local(((d[0] + 1) * (d[0] + 1),), "float32", 
layout=None)
+            b[(d[0] + 2) * d[0]] = T.float32(1)
+            out[0] = b[(d[0] + 2) * d[0]]
+
+    with tvm_tirx.target.Target("llvm"):
+        after = LowerTensorLayouts()(Before)
+    assert not tvm_tirx.tirx.analysis.undefined_vars(after["main"].body, 
after["main"].params)
+    tvm_tirx.ir.assert_structural_equal(after, Expected)
+    tvm_tirx.tirx.transform.FlattenTensor()(after)

Reply via email to