Repository: intel/intel-xpu-backend-for-triton
Pull request #3867: Enhance `MaterializeBlockPointer` pass
Author: login: etiotto
Created: 2025-04-08T21:12:10Z | Merged: 2025-04-15T15:03:55Z

Fixes issue #3868. With this change 2D block reads can be generated for all the loads in the GEMM benchmark [here](https://github.com/intel/intel-xpu-backend-for-triton/blob/main/benchmarks/triton_kernels_benchmark/gemm_tensor_desc_benchmark.py). 

Performance of that benchmark increases and matches the performance of the equivalent benchmark using block pointers.


Diff:
diff --git a/benchmarks/triton_kernels_benchmark/gemm_tensor_desc_benchmark.py b/benchmarks/triton_kernels_benchmark/gemm_tensor_desc_benchmark.py
index 503a8d65c0..8a0c79221e 100644
--- a/benchmarks/triton_kernels_benchmark/gemm_tensor_desc_benchmark.py
+++ b/benchmarks/triton_kernels_benchmark/gemm_tensor_desc_benchmark.py
@@ -22,6 +22,13 @@
 
 @triton.autotune(
     configs=[
+        triton.Config(
+            {'BLOCK_SIZE_M': 256, 'BLOCK_SIZE_N': 256, 'BLOCK_SIZE_K': 32, 'GROUP_SIZE_M': 4, 'grf_mode': 'large'},
+            num_stages=s, num_warps=32) for s in [2]
+    ] + [
+        triton.Config({'BLOCK_SIZE_M': 256, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32, 'GROUP_SIZE_M': 4, 'grf_mode': m},
+                      num_stages=s, num_warps=w) for s in [2, 3, 4] for (m, w) in ([('large', 32), ('small', 64)])
+    ] + [
         triton.Config(
             {'BLOCK_SIZE_M': 64, 'BLOCK_SIZE_N': 128, 'BLOCK_SIZE_K': 32, 'GROUP_SIZE_M': 4, 'grf_mode': 'large'},
             num_stages=s, num_warps=32) for s in [2]
diff --git a/python/test/unit/intel/test_tensor_descriptor.py b/python/test/unit/intel/test_tensor_descriptor.py
index 76b003c276..c7f0ff9e74 100644
--- a/python/test/unit/intel/test_tensor_descriptor.py
+++ b/python/test/unit/intel/test_tensor_descriptor.py
@@ -413,11 +413,11 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
     (256, 64, 32, 2),
-    (64, 512, 32, 4),
+    (64, 512, 32, 2),
     (128, 128, 16, 4),
     (64, 128, 32, 4),
-    (32, 32, 32, 1),
-    (256, 128, 32, 1),
+    (32, 32, 32, 4),
+    (256, 128, 32, 4),
 ])
 def test_make_tensor_descriptor_matmul(num_stages, BLOCK_M, BLOCK_N, BLOCK_K):
     device = "xpu"
@@ -425,6 +425,10 @@ def test_make_tensor_descriptor_matmul(num_stages, BLOCK_M, BLOCK_N, BLOCK_K):
         M, N, K = BLOCK_M, BLOCK_N, BLOCK_K
     else:
         M, N, K = 1024, 512, 256
+
+    if (BLOCK_M, BLOCK_N, BLOCK_K) in [(64, 512, 32), (256, 128, 32)]:
+        pytest.skip("FIXME: issue #3923")
+
     torch.manual_seed(42)
     A = torch.randn((M, K), dtype=torch.float16, device=device)
     B = torch.randn((K, N), dtype=torch.float16, device=device)
diff --git a/python/tutorials/09-persistent-matmul.py b/python/tutorials/09-persistent-matmul.py
index f8eb9e9e6f..89203c9642 100644
--- a/python/tutorials/09-persistent-matmul.py
+++ b/python/tutorials/09-persistent-matmul.py
@@ -32,6 +32,26 @@
 from typing import Optional
 
 DEVICE = triton.runtime.driver.active.get_active_torch_device()
+DEVICE_TOTAL_MEMORY = torch.xpu.get_device_properties().total_memory
+
+
+def is_enough_memory(M, N, K, dtype):
+    # a: (M, K) dtype
+    # b: (N, K) dtype
+    # c: (M, N) float32
+    # d: (M, N) float32
+    finfo = torch.finfo(dtype)
+    dtype_size = finfo.bits // 8
+    required_memory = 2 * (M * K * dtype_size + N * K * dtype_size + 2 * M * N * 4)
+    enough_memory = required_memory < DEVICE_TOTAL_MEMORY
+
+    if not enough_memory:
+        deviceName = torch.xpu.get_device_name()
+        print(
+            f"'{M , N, K, dtype}' combination skipped for '{deviceName}'; {required_memory=} but {DEVICE_TOTAL_MEMORY=}"
+        )
+    return enough_memory
+
 
 if torch.cuda.is_available():
     from triton._C.libtriton import nvidia
@@ -729,9 +749,12 @@ def bench_fn(label, reps, warmup_reps, fn, *args):
     print(f"\rBenchmarking {label}: done")
 
 
-def bench(K, dtype, reps=10000, warmup_reps=10000):
+def bench(K, dtype, reps=100, warmup_reps=100):
     M = 8192
     N = 8192
+    if not is_enough_memory(M, N, K, dtype):
+        return
+
     a = torch.randn((M, K), device=DEVICE, dtype=torch.float16).to(dtype)
     b = torch.randn((K, N), device=DEVICE, dtype=torch.float16).to(dtype)
 
@@ -766,6 +789,9 @@ def run_test(expect, fn, a, b, label, enabled=True):
 
 
 def validate(M, N, K, dtype):
+    if not is_enough_memory(M, N, K, dtype):
+        return
+
     print(f"{M=}, {N=}, {K=}, verification naive vs: ")
     a = torch.randn((M, K), device=DEVICE, dtype=torch.float16).to(dtype)
     b = torch.randn((K, N), device=DEVICE, dtype=torch.float16).to(dtype)
diff --git a/third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp b/third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
index a0e6539228..cf001bef0e 100644
--- a/third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
+++ b/third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
@@ -7,6 +7,7 @@
 #include "mlir/IR/Visitors.h"
 #include "triton/Analysis/Utility.h"
 #include "triton/Dialect/Triton/IR/Dialect.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Debug.h"
 #include <optional>
 
@@ -54,12 +55,13 @@ struct TritonIntelGPUMaterializeBlockPointerPass
       assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
              "Expected 'loadOp' to load a tensor value.");
 
+      // Find the make tensor ptr operation that created the base ptr.
       tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
       if (!makeTensorPtrOp) {
-        LDBG("Could not find make tensor ptr op.");
+        LDBG("Could not find make tensor ptr op for: " << loadOp);
         return;
       }
-      LDBG("Found make tensor ptr op: " << makeTensorPtrOp);
+      LDBG("Make tensor ptr op: " << makeTensorPtrOp);
 
       Operation::operand_range shape = makeTensorPtrOp.getShape();
       unsigned rank = shape.size();
@@ -317,27 +319,70 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     // Analyze the shape of the stride one dimension to ensure it satisfies HW
     // constraints.
-    Value baseWidth = shape[strideOneDimVal];
+    Value baseWidth = tt::intel::getFinalValue(shape[strideOneDimVal]);
     unsigned divisor = std::ceil(32 / elementWidth);
     if (!ttgi::isDivisible(baseWidth, divisor)) {
-      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      LLVM_DEBUG({
+        llvm::dbgs() << "baseWidth does not satisfies HW constraint: ";
+        baseWidth.printAsOperand(llvm::dbgs(), {});
+        llvm::dbgs() << "\ndivisor: " << divisor << "\n";
+      });
       return false;
     }
     LDBG("baseWidth: " << baseWidth);
 
     // Analyze the initial offset corresponding to the stride one dimension to
     // ensure it satisfies HW constraints.
-    Value offset = makeTensorPtrOp.getOffsets()[strideOneDimVal];
+    Value offset =
+        tt::intel::getFinalValue(makeTensorPtrOp.getOffsets()[strideOneDimVal]);
     if (!ttgi::isDivisible(offset, divisor)) {
-      LDBG("offset does not satisfies HW constraints: " << offset);
+      LLVM_DEBUG({
+        llvm::dbgs() << "offset does not satisfies HW constraints: ";
+        offset.printAsOperand(llvm::dbgs(), {});
+        llvm::dbgs() << "\ndivisor: " << divisor << "\n";
+      });
       return false;
     }
     LDBG("offset: " << offset);
 
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
     // TODO: analyze tt.advance (issue #3762).
 
     return true;
   }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
+    assert(divisor != 0 && "Expected divisor to be non-zero");
+
+    auto checkUsers = [&](Value::user_range users) {
+      return llvm::all_of(users, [&](Operation *user) {
+        if (isa<tt::MakeTensorPtrOp>(user))
+          return true;
+        if (Operation *addOp = dyn_cast<arith::AddIOp>(user)) {
+          auto other = llvm::find_if(addOp->getOperands(),
+                                     [&](Value op) { return op != offset; });
+          if (!ttgi::isDivisible(*other, divisor)) {
+            LDBG("Found a non-divisible increment: " << *addOp);
+            return false;
+          }
+          return true;
+        }
+        LDBG("Unhandled user kind: " << user);
+        return false;
+      });
+    };
+
+    // Ensure that the offset is incremented by a multiple of the divisor.
+    if (auto blockArg = dyn_cast<BlockArgument>(offset))
+      return checkUsers(blockArg.getUsers());
+
+    return true;
+  }
 };
 
 } // anonymous namespace


Reviews:
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T16:01:27Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T19:14:11Z
user: login: alexbaden
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T20:26:12Z
user: login: chengjunlu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T01:07:36Z
user: login: chengjunlu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T01:12:02Z
user: login: chengjunlu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T01:12:31Z
user: login: chengjunlu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T01:23:58Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T13:23:25Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T17:35:45Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:41:58Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:45:01Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:45:15Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:46:16Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:48:30Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:50:42Z
user: login: whitneywhtsang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:55:19Z
user: login: whitneywhtsang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T16:56:13Z
user: login: whitneywhtsang
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:06:36Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:21:57Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:23:31Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:23:54Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:24:46Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:29:49Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T17:30:06Z
user: login: etiotto
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T18:29:40Z
user: login: chengjunlu
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T00:43:56Z
user: login: whitneywhtsang
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T07:56:20Z

Review comments:
diff_hunk: @@ -413,11 +413,11 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
     (256, 64, 32, 1),
-    (64, 512, 32, 1),
+    (64, 256, 32, 1),
path: python/test/unit/intel/test_tensor_descriptor.py
user: login: etiotto
body: The original size cause the bmk to crash at runtime. Probably we have some issues in the 2D block read codegen because this PR causes both loads in the GEMM to be lowered to 2D block reads.
created_at: 2025-04-09T16:01:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -412,12 +412,12 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.interpreter
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
-    (256, 64, 32, 1),
-    (64, 512, 32, 1),
-    (128, 128, 16, 1),
-    (64, 128, 32, 1),
-    (32, 32, 32, 1),
-    (256, 128, 32, 1),
+    (256, 64, 32, 2),
path: python/test/unit/intel/test_tensor_descriptor.py
user: login: etiotto
body: Changing `num_stages" to match NVIDIA 
created_at: 2025-04-09T19:14:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: alexbaden
body: the boolean operator works too: 
`if (!strideOneDim) { ...`
created_at: 2025-04-09T20:14:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,84 +52,55 @@ struct TritonIntelGPUMaterializeBlockPointerPass
       assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
              "Expected 'loadOp' to load a tensor value.");
 
+      // Find the make tensor ptr operation that created the base ptr.
       tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
-      LDBG("Found make tensor ptr op: " << makeTensorPtrOp);
-      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
-      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
-      auto elementWidth = tensorType.getElementTypeBitWidth();
-      LDBG("elementWidth: " << elementWidth);
+      if (!makeTensorPtrOp) {
+        LDBG("Could not find make tensor ptr op for: " << loadOp);
+        return;
+      }
+      LDBG("Make tensor ptr op: " << makeTensorPtrOp);
 
       Operation::operand_range shape = makeTensorPtrOp.getShape();
       unsigned rank = shape.size();
       LDBG("Rank: " << rank);
       if (rank == 1)
         return;
 
-      // We will compensate the offset of non-64 bytes aligned base to the
-      // OffsetX and BaseWidth. The OffsetX and BaseWidth has extra restriction
-      // that it has to be 4 bytes aligned.
-      auto base = makeTensorPtrOp.getBase();
-      if (!ttgi::isDivisible(base, 4)) {
-        LDBG("Found Non 4 bytes aligned base: " << base);
-        return;
-      }
-
-      Operation::operand_range strides = makeTensorPtrOp.getStrides();
-      int fastChangeDim = -1;
-      for (size_t i = 0; i < strides.size(); ++i) {
-        if (tt::intel::isConstant(strides[i], 1)) {
-          fastChangeDim = i;
-          break;
-        }
-      }
-
-      LDBG("Fast change dim: " << fastChangeDim);
-      if (fastChangeDim < 0) {
+      // Note: we will compensate the offset of non-64 bytes aligned base to the
+      // offsetX and baseWidth.
+      if (!satisfies2DBlockReadAlignment(loadOp)) {
+        LDBG("Alignment checks failed for: " << loadOp);
         return;
       }
 
-      // Check the BaseWidth.
-      Value BaseWidth = shape[fastChangeDim];
-      if (!ttgi::isDivisible(BaseWidth, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned BaseWidth: " << BaseWidth);
-        return;
-      }
-
-      // Check the OffsetX
-      Operation::operand_range offsets = makeTensorPtrOp.getOffsets();
-      Value OffsetX = offsets[fastChangeDim];
-      if (!ttgi::isDivisible(OffsetX, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned offsetX: " << OffsetX);
-        return;
-      }
+      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+      unsigned elementWidth = tensorType.getElementTypeBitWidth();
+      LDBG("elementWidth: " << elementWidth);
 
-      // TODO: Check the OffsetX from tl.advance
+      Operation::operand_range strides = makeTensorPtrOp.getStrides();
+      std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: alexbaden
body: What about `getContiguousDim` and `contiguousDim`?
created_at: 2025-04-09T20:15:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,84 +52,55 @@ struct TritonIntelGPUMaterializeBlockPointerPass
       assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
              "Expected 'loadOp' to load a tensor value.");
 
+      // Find the make tensor ptr operation that created the base ptr.
       tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
-      LDBG("Found make tensor ptr op: " << makeTensorPtrOp);
-      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
-      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
-      auto elementWidth = tensorType.getElementTypeBitWidth();
-      LDBG("elementWidth: " << elementWidth);
+      if (!makeTensorPtrOp) {
+        LDBG("Could not find make tensor ptr op for: " << loadOp);
+        return;
+      }
+      LDBG("Make tensor ptr op: " << makeTensorPtrOp);
 
       Operation::operand_range shape = makeTensorPtrOp.getShape();
       unsigned rank = shape.size();
       LDBG("Rank: " << rank);
       if (rank == 1)
         return;
 
-      // We will compensate the offset of non-64 bytes aligned base to the
-      // OffsetX and BaseWidth. The OffsetX and BaseWidth has extra restriction
-      // that it has to be 4 bytes aligned.
-      auto base = makeTensorPtrOp.getBase();
-      if (!ttgi::isDivisible(base, 4)) {
-        LDBG("Found Non 4 bytes aligned base: " << base);
-        return;
-      }
-
-      Operation::operand_range strides = makeTensorPtrOp.getStrides();
-      int fastChangeDim = -1;
-      for (size_t i = 0; i < strides.size(); ++i) {
-        if (tt::intel::isConstant(strides[i], 1)) {
-          fastChangeDim = i;
-          break;
-        }
-      }
-
-      LDBG("Fast change dim: " << fastChangeDim);
-      if (fastChangeDim < 0) {
+      // Note: we will compensate the offset of non-64 bytes aligned base to the
+      // offsetX and baseWidth.
+      if (!satisfies2DBlockReadAlignment(loadOp)) {
+        LDBG("Alignment checks failed for: " << loadOp);
         return;
       }
 
-      // Check the BaseWidth.
-      Value BaseWidth = shape[fastChangeDim];
-      if (!ttgi::isDivisible(BaseWidth, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned BaseWidth: " << BaseWidth);
-        return;
-      }
-
-      // Check the OffsetX
-      Operation::operand_range offsets = makeTensorPtrOp.getOffsets();
-      Value OffsetX = offsets[fastChangeDim];
-      if (!ttgi::isDivisible(OffsetX, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned offsetX: " << OffsetX);
-        return;
-      }
+      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+      unsigned elementWidth = tensorType.getElementTypeBitWidth();
+      LDBG("elementWidth: " << elementWidth);
 
-      // TODO: Check the OffsetX from tl.advance
+      Operation::operand_range strides = makeTensorPtrOp.getStrides();
+      std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
 
-      if (fastChangeDim == rank - 2 && elementWidth == 8) {
+      if (strideOneDim.value() == rank - 2 && elementWidth == 8) {
         // TODO: column major layout w/ fp8 has performance regression
         return;
       }
 
-      if (fastChangeDim >= (rank - 2)) {
+      if (strideOneDim.value() >= (rank - 2)) {
         // HW 2D block read instruction only supports contiguous access.
-        Value fastChangeStride = strides[fastChangeDim];
-        LLVM_DEBUG({
-          DBGS() << "fastChangeStride: ";
-          fastChangeStride.print(llvm::dbgs());
-          llvm::dbgs() << "\n";
-        });
+        Value fastChangeStride = strides[strideOneDim.value()];
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: alexbaden
body: Since the strides and the tensor ptr op are now decoupled suggest adding an assert 
```
assert(strideOneDim.value() < strides.size())
```
created_at: 2025-04-09T20:17:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: alexbaden
body: How does this TODO effect supported cases? 
created_at: 2025-04-09T20:18:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
+
+    return true;
+  }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
+    assert(divisor != 0 && "Expected divisor to be non-zero");
+
+    // Ensure the initial offset is divisible by the divisor.
+    Value initialOffset = tt::intel::getFinalValue(offset);
+    if (!ttgi::isDivisible(initialOffset, divisor)) {
+      LDBG("initialOffset does not satisfies HW constraint: " << initialOffset);
+      return false;
+    }
+
+    auto checkUsers = [&](Value::user_range users) {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: alexbaden
body: Can you get this info from AxisInfo analysis? 
created_at: 2025-04-09T20:26:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: chengjunlu
body: It is possible that the rank of tensor is 1. It is better to return false instead of assertion error.
created_at: 2025-04-10T01:07:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
+
+    return true;
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: chengjunlu
body: Should we be conservative to return false if the offset is not checked? 
created_at: 2025-04-10T01:12:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: chengjunlu
body: We should analysis the initial offset value in MakeTensorPtrOp even if the loadOp is not in same region as the makeTensorPtr.
created_at: 2025-04-10T01:12:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
+
+    return true;
+  }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
+    assert(divisor != 0 && "Expected divisor to be non-zero");
+
+    // Ensure the initial offset is divisible by the divisor.
+    Value initialOffset = tt::intel::getFinalValue(offset);
+    if (!ttgi::isDivisible(initialOffset, divisor)) {
+      LDBG("initialOffset does not satisfies HW constraint: " << initialOffset);
+      return false;
+    }
+
+    auto checkUsers = [&](Value::user_range users) {
+      return llvm::all_of(users, [&](Operation *user) {
+        if (isa<tt::MakeTensorPtrOp>(user))
+          return true;
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: chengjunlu
body: It is not safe to return true directly here.
We need to check the initial value and step distance of the iterator of the SCF.For.
created_at: 2025-04-10T01:23:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: The TODO was there before this PR. That means loops containing a tt.advance operation will potentially (and unsafely) lower `tt.load` to use 2D block reads. I intentionally did not fix this bug in this PR, and left the TODO.

I could post an "NFC" PR to refactor the code (call member functions) and then add my functional changes on top of it.

We should actually reference issue #3762 in the TODO. So whoever reads the code will understand there is an issue to track the TODO.
created_at: 2025-04-10T13:23:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
+
+    return true;
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: I'd say yes but that would cause a change in behavior. We have issue #3762 for that part. 
created_at: 2025-04-10T17:35:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,84 +52,55 @@ struct TritonIntelGPUMaterializeBlockPointerPass
       assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
              "Expected 'loadOp' to load a tensor value.");
 
+      // Find the make tensor ptr operation that created the base ptr.
       tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
-      LDBG("Found make tensor ptr op: " << makeTensorPtrOp);
-      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
-      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
-      auto elementWidth = tensorType.getElementTypeBitWidth();
-      LDBG("elementWidth: " << elementWidth);
+      if (!makeTensorPtrOp) {
+        LDBG("Could not find make tensor ptr op for: " << loadOp);
+        return;
+      }
+      LDBG("Make tensor ptr op: " << makeTensorPtrOp);
 
       Operation::operand_range shape = makeTensorPtrOp.getShape();
       unsigned rank = shape.size();
       LDBG("Rank: " << rank);
       if (rank == 1)
         return;
 
-      // We will compensate the offset of non-64 bytes aligned base to the
-      // OffsetX and BaseWidth. The OffsetX and BaseWidth has extra restriction
-      // that it has to be 4 bytes aligned.
-      auto base = makeTensorPtrOp.getBase();
-      if (!ttgi::isDivisible(base, 4)) {
-        LDBG("Found Non 4 bytes aligned base: " << base);
-        return;
-      }
-
-      Operation::operand_range strides = makeTensorPtrOp.getStrides();
-      int fastChangeDim = -1;
-      for (size_t i = 0; i < strides.size(); ++i) {
-        if (tt::intel::isConstant(strides[i], 1)) {
-          fastChangeDim = i;
-          break;
-        }
-      }
-
-      LDBG("Fast change dim: " << fastChangeDim);
-      if (fastChangeDim < 0) {
+      // Note: we will compensate the offset of non-64 bytes aligned base to the
+      // offsetX and baseWidth.
+      if (!satisfies2DBlockReadAlignment(loadOp)) {
+        LDBG("Alignment checks failed for: " << loadOp);
         return;
       }
 
-      // Check the BaseWidth.
-      Value BaseWidth = shape[fastChangeDim];
-      if (!ttgi::isDivisible(BaseWidth, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned BaseWidth: " << BaseWidth);
-        return;
-      }
-
-      // Check the OffsetX
-      Operation::operand_range offsets = makeTensorPtrOp.getOffsets();
-      Value OffsetX = offsets[fastChangeDim];
-      if (!ttgi::isDivisible(OffsetX, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned offsetX: " << OffsetX);
-        return;
-      }
+      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+      unsigned elementWidth = tensorType.getElementTypeBitWidth();
+      LDBG("elementWidth: " << elementWidth);
 
-      // TODO: Check the OffsetX from tl.advance
+      Operation::operand_range strides = makeTensorPtrOp.getStrides();
+      std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
 
-      if (fastChangeDim == rank - 2 && elementWidth == 8) {
+      if (strideOneDim.value() == rank - 2 && elementWidth == 8) {
         // TODO: column major layout w/ fp8 has performance regression
         return;
       }
 
-      if (fastChangeDim >= (rank - 2)) {
+      if (strideOneDim.value() >= (rank - 2)) {
         // HW 2D block read instruction only supports contiguous access.
-        Value fastChangeStride = strides[fastChangeDim];
-        LLVM_DEBUG({
-          DBGS() << "fastChangeStride: ";
-          fastChangeStride.print(llvm::dbgs());
-          llvm::dbgs() << "\n";
-        });
+        Value fastChangeStride = strides[strideOneDim.value()];
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: assertion added at line 84
created_at: 2025-04-11T16:41:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: This is not possible here because we return at line 170 when the rank isn't 2.
created_at: 2025-04-11T16:44:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: This is done now.
created_at: 2025-04-11T16:45:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: we already do
created_at: 2025-04-11T16:46:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: This is done.
created_at: 2025-04-11T16:48:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
+
+    return true;
+  }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
+    assert(divisor != 0 && "Expected divisor to be non-zero");
+
+    // Ensure the initial offset is divisible by the divisor.
+    Value initialOffset = tt::intel::getFinalValue(offset);
+    if (!ttgi::isDivisible(initialOffset, divisor)) {
+      LDBG("initialOffset does not satisfies HW constraint: " << initialOffset);
+      return false;
+    }
+
+    auto checkUsers = [&](Value::user_range users) {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: AFAIK no
created_at: 2025-04-11T16:50:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -334,10 +336,51 @@ struct TritonIntelGPUMaterializeBlockPointerPass
     }
     LDBG("offset: " << offset);
 
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
     // TODO: analyze tt.advance (issue #3762).
 
     return true;
   }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: whitneywhtsang
body: Should we expand `ttgi::isDivisible` instead?
created_at: 2025-04-11T16:55:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -412,12 +412,12 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.interpreter
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
-    (256, 64, 32, 1),
-    (64, 512, 32, 1),
-    (128, 128, 16, 1),
-    (64, 128, 32, 1),
-    (32, 32, 32, 1),
-    (256, 128, 32, 1),
+    (256, 64, 32, 2),
+    (64, 256, 32, 2),
path: python/test/unit/intel/test_tensor_descriptor.py
user: login: whitneywhtsang
body: Do we know why we need to reduce BLOCK_N or BLOCK_K? If not, can we create an issue to investigate that?
created_at: 2025-04-11T16:56:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: whitneywhtsang
body: I thought `ttgi::isDivisible(offset, divisor)` would return false for the case for tensor descriptor?
created_at: 2025-04-11T17:04:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -412,12 +412,12 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.interpreter
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
-    (256, 64, 32, 1),
-    (64, 512, 32, 1),
-    (128, 128, 16, 1),
-    (64, 128, 32, 1),
-    (32, 32, 32, 1),
-    (256, 128, 32, 1),
+    (256, 64, 32, 2),
+    (64, 256, 32, 2),
path: python/test/unit/intel/test_tensor_descriptor.py
user: login: etiotto
body: This no longer fails.
created_at: 2025-04-11T17:21:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -729,9 +749,12 @@ def bench_fn(label, reps, warmup_reps, fn, *args):
     print(f"\rBenchmarking {label}: done")
 
 
-def bench(K, dtype, reps=10000, warmup_reps=10000):
+def bench(K, dtype, reps=100, warmup_reps=100):
path: python/tutorials/09-persistent-matmul.py
user: login: etiotto
body: I have reduced the number of time the bmk is run to limit the time it takes to run it.
created_at: 2025-04-11T17:23:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -334,10 +336,51 @@ struct TritonIntelGPUMaterializeBlockPointerPass
     }
     LDBG("offset: " << offset);
 
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
     // TODO: analyze tt.advance (issue #3762).
 
     return true;
   }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: I don't understand the question.
created_at: 2025-04-11T17:23:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -413,11 +413,11 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
     (256, 64, 32, 1),
-    (64, 512, 32, 1),
+    (64, 256, 32, 1),
path: python/test/unit/intel/test_tensor_descriptor.py
user: login: etiotto
body: This is no longer a problem. Reverted this change
created_at: 2025-04-11T17:24:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -201,6 +173,118 @@ struct TritonIntelGPUMaterializeBlockPointerPass
 
     return std::nullopt;
   }
+
+  std::optional<unsigned>
+  getStrideOneDim(tt::MakeTensorPtrOp makeTensorPtrOp) const {
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+    Operation::operand_range strides = makeTensorPtrOp.getStrides();
+    std::optional<unsigned> strideOneDim{std::nullopt};
+    for (auto [idx, stride] : llvm::enumerate(strides)) {
+      if (!tt::intel::isConstant(stride, 1))
+        continue;
+      strideOneDim = idx;
+      break;
+    }
+
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return std::nullopt;
+    }
+    return strideOneDim;
+  }
+
+  bool satisfies2DBlockReadAlignment(tt::LoadOp loadOp) const {
+    Value ptr = loadOp.getPtr();
+    assert(tt::isTensorPointerType(ptr.getType()) &&
+           "Expected a ptr to a tensor of ptrs.");
+    assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
+           "Expected 'loadOp' to load a ranked tensor value.");
+
+    // Find the make tensor ptr operation that created the base ptr.
+    tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
+    assert(makeTensorPtrOp && "Expected a make tensor ptr op.");
+
+    Operation::operand_range shape = makeTensorPtrOp.getShape();
+    assert(shape.size() != 1 &&
+           "Expected a tensor of ptrs to have more than one dimension.");
+
+    // Ensure the base ptr is 4-byte aligned.
+    TypedValue<tt::PointerType> base = makeTensorPtrOp.getBase();
+    if (!ttgi::isDivisible(base, 4)) {
+      LDBG("Found non 4-bytes aligned base: " << base);
+      return false;
+    }
+
+    std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
+    if (!strideOneDim.has_value()) {
+      LDBG("Could not find stride one dimension in: " << makeTensorPtrOp);
+      return false;
+    }
+
+    auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+    auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+    unsigned elementWidth = tensorType.getElementTypeBitWidth();
+
+    // Analyze the shape of the stride one dimension to ensure it satisfies HW
+    // constraints.
+    Value baseWidth = shape[strideOneDim.value()];
+    unsigned divisor = std::ceil(32 / elementWidth);
+    if (!ttgi::isDivisible(baseWidth, divisor)) {
+      LDBG("baseWidth does not satisfies HW constraint: " << baseWidth);
+      return false;
+    }
+    LDBG("baseWidth: " << baseWidth);
+
+    // Analyze the initial offset corresponding to the stride one dimension to
+    // ensure it satisfies HW constraints.
+    Value offset = makeTensorPtrOp.getOffsets()[strideOneDim.value()];
+    LDBG("offset: " << offset);
+
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
+    // TODO: analyze tt.advance
+
+    return true;
+  }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
+    assert(divisor != 0 && "Expected divisor to be non-zero");
+
+    // Ensure the initial offset is divisible by the divisor.
+    Value initialOffset = tt::intel::getFinalValue(offset);
+    if (!ttgi::isDivisible(initialOffset, divisor)) {
+      LDBG("initialOffset does not satisfies HW constraint: " << initialOffset);
+      return false;
+    }
+
+    auto checkUsers = [&](Value::user_range users) {
+      return llvm::all_of(users, [&](Operation *user) {
+        if (isa<tt::MakeTensorPtrOp>(user))
+          return true;
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: We have already checked (at lines 354-358) above that the `make_tensor_ptr` operation that creates the block pointer has offset that is dicisable by the `divisor`. Note that `tt::intel::getFinalValue` will find the `make_tensor_ptr` operation even if that operation is outside the loop. 

Here (lines 362-363) we skip the `make_tensor_ptr` user because we have already processed it.
created_at: 2025-04-11T17:29:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,84 +52,55 @@ struct TritonIntelGPUMaterializeBlockPointerPass
       assert(isa<RankedTensorType>(loadOp.getResult().getType()) &&
              "Expected 'loadOp' to load a tensor value.");
 
+      // Find the make tensor ptr operation that created the base ptr.
       tt::MakeTensorPtrOp makeTensorPtrOp = getMakeTensorPtrOp(ptr);
-      LDBG("Found make tensor ptr op: " << makeTensorPtrOp);
-      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
-      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
-      auto elementWidth = tensorType.getElementTypeBitWidth();
-      LDBG("elementWidth: " << elementWidth);
+      if (!makeTensorPtrOp) {
+        LDBG("Could not find make tensor ptr op for: " << loadOp);
+        return;
+      }
+      LDBG("Make tensor ptr op: " << makeTensorPtrOp);
 
       Operation::operand_range shape = makeTensorPtrOp.getShape();
       unsigned rank = shape.size();
       LDBG("Rank: " << rank);
       if (rank == 1)
         return;
 
-      // We will compensate the offset of non-64 bytes aligned base to the
-      // OffsetX and BaseWidth. The OffsetX and BaseWidth has extra restriction
-      // that it has to be 4 bytes aligned.
-      auto base = makeTensorPtrOp.getBase();
-      if (!ttgi::isDivisible(base, 4)) {
-        LDBG("Found Non 4 bytes aligned base: " << base);
-        return;
-      }
-
-      Operation::operand_range strides = makeTensorPtrOp.getStrides();
-      int fastChangeDim = -1;
-      for (size_t i = 0; i < strides.size(); ++i) {
-        if (tt::intel::isConstant(strides[i], 1)) {
-          fastChangeDim = i;
-          break;
-        }
-      }
-
-      LDBG("Fast change dim: " << fastChangeDim);
-      if (fastChangeDim < 0) {
+      // Note: we will compensate the offset of non-64 bytes aligned base to the
+      // offsetX and baseWidth.
+      if (!satisfies2DBlockReadAlignment(loadOp)) {
+        LDBG("Alignment checks failed for: " << loadOp);
         return;
       }
 
-      // Check the BaseWidth.
-      Value BaseWidth = shape[fastChangeDim];
-      if (!ttgi::isDivisible(BaseWidth, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned BaseWidth: " << BaseWidth);
-        return;
-      }
-
-      // Check the OffsetX
-      Operation::operand_range offsets = makeTensorPtrOp.getOffsets();
-      Value OffsetX = offsets[fastChangeDim];
-      if (!ttgi::isDivisible(OffsetX, std::ceil(32 / elementWidth))) {
-        LDBG("Found Non 4 bytes aligned offsetX: " << OffsetX);
-        return;
-      }
+      auto ptrType = cast<tt::PointerType>(makeTensorPtrOp.getType());
+      auto tensorType = cast<RankedTensorType>(ptrType.getPointeeType());
+      unsigned elementWidth = tensorType.getElementTypeBitWidth();
+      LDBG("elementWidth: " << elementWidth);
 
-      // TODO: Check the OffsetX from tl.advance
+      Operation::operand_range strides = makeTensorPtrOp.getStrides();
+      std::optional<unsigned> strideOneDim = getStrideOneDim(makeTensorPtrOp);
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: what do you mean?
created_at: 2025-04-11T17:30:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -334,10 +336,51 @@ struct TritonIntelGPUMaterializeBlockPointerPass
     }
     LDBG("offset: " << offset);
 
+    Region *loadRgn = loadOp->getParentRegion();
+    Region *makeTensorPtrRgn = makeTensorPtrOp->getParentRegion();
+    bool inSameRegion = (loadRgn == makeTensorPtrRgn);
+    if (inSameRegion)
+      return satisfies2DBlockReadAlignment(offset, divisor);
+
     // TODO: analyze tt.advance (issue #3762).
 
     return true;
   }
+
+  bool satisfies2DBlockReadAlignment(Value offset, unsigned divisor) const {
path: third_party/intel/lib/TritonIntelGPUTransforms/MaterializeBlockPointer.cpp
user: login: etiotto
body: Oh I think I do now. No I think we can handle it here.
created_at: 2025-04-14T18:28:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -412,12 +412,12 @@ def matmul_kernel_make_tensor_desciptor(a_ptr, b_ptr, c_ptr,  #
 @pytest.mark.interpreter
 @pytest.mark.parametrize("BLOCK_M, BLOCK_N, BLOCK_K, num_stages", [
     (128, 128, 16, 1),
-    (256, 64, 32, 1),
-    (64, 512, 32, 1),
-    (128, 128, 16, 1),
-    (64, 128, 32, 1),
-    (32, 32, 32, 1),
-    (256, 128, 32, 1),
+    (256, 64, 32, 2),
path: python/test/unit/intel/test_tensor_descriptor.py
user: login: etiotto
body: Note: I split the change out into PR #3920
created_at: 2025-04-14T18:29:26Z
author_association: CONTRIBUTOR

PR comments:
user: login: etiotto
created_at: 2025-04-09T16:45:13Z
body: Benchmark results shows that Triton performance is on par with the one we get when tensor ptrs are used:
```
matmul-tensor-desc-performance:
         B        M        N        K  Triton-GB/s  OneDNN-GB/s  XeTLA-GB/s  Triton-GB/s-min  OneDNN-GB/s-min  XeTLA-GB/s-min  Triton-GB/s-max  OneDNN-GB/s-max  XeTLA-GB/s-max  Triton-TFlops  OneDNN-TFlops  XeTLA-TFlops  Triton-TFlops-min  OneDNN-TFlops-min  XeTLA-TFlops-min  Triton-TFlops-max  OneDNN-TFlops-max  XeTLA-TFlops-max  Triton-CV  OneDNN-CV  XeTLA-CV
0      1.0   1024.0   1024.0   1024.0   392.725117   357.570690  368.892189       183.317489       3[49](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:50).525330      349.525330       394.201504       364.088883      379.918832     100.537630      91.538097     94.436400          46.929277          89.478485         89.478485         100.915585          93.206754         97.259221   0.005662   0.012056  0.014290
1      1.0   2048.0   2048.0   2048.0   391.259714   481.274125  372.827007       197.286164       340.446760      191.345992       [50](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:51)4.123076       554.802129      488.846612     200.324973     246.412352    190.887428         101.010516         174.308741         97.969148         258.111015         284.058690        250.289465   0.413143   0.177490  0.421370
2      1.0   4096.0   4096.0   4096.0   256.385362   270.295098  250.958711       197.147068       223.576979      217.434109       291.980792       312.192342      284.456022     262.538610     276.782181    256.981720         201.878598         228.942827        222.652527         298.988331         319.684958        291.282967   0.109859   0.080915  0.108763
3      1.0   8192.0   8192.0   8192.0   120.050557   130.369224  119.773095        93.882182       100.315202       99.036133       146.852960       159.935325      147.914620     245.863540     266.996171    245.295298         192.270709         205.445533        202.826001         300.754861         327.547546        302.929142   0.139144   0.203739  0.144395
4      1.0      1.0  13824.0   [51](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:52)20.0   609.080064   621.372844  634.058447       547.061580       555.995975      543.034102       668.538961       664.523728      670.057253       0.608798       0.621085      0.633765           0.546808           0.555739          0.542783           0.668230           0.664216          0.669747   0.038742   0.027338  0.036116
5      1.0      4.0  12288.0   4096.0   645.258837   651.761519  667.809530       591.537703       601.697727      618.214880       685.412159       719.839298      719.018457       2.575167       2.601119      2.665165           2.360771           2.401319          2.467238           2.735416           2.872811          2.869535   0.049168   0.047900  0.043103
6      1.0    512.0   8192.0   8192.0   [52](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:53)7.830032   605.376593  514.704976       425.158872       456.738728      378.044466       601.901604       628.880826      587.350922     227.578085     261.012897    221.919114         183.310604         196.926508        162.996856         259.514628         271.146933        2[53](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:54).240987   0.148313   0.049338  0.138393
7      1.0    512.0   8192.0  32768.0   525.385659   543.716135  530.790194       415.583271       451.360983      469.731989       568.289865       592.702858      593.181821     245.940533     254.521290    248.470473         194.[54](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:55)0466         211.288524        219.888255         266.024604         277.452675        277.676884   0.044534   0.055889  0.082067
8      1.0    512.0  32768.0   8192.0   546.269720   578.480946  519.317180       504.921150       514.976080      458.634217       596.060199       654.687366      567.849012     245.207756     259.666625    233.109388         226.647346         231.160770        205.870219         267.[55](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:56)7543         293.873912        254.894198   0.049259   0.076659  0.047689
9      1.0   1024.0   8192.0  16384.0   333.689035   333.861641  322.167909       293.266947       296.249752      281.534690       362.390181       382.622158      364.848991     273.358058     273.4994[56](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:57)    263.919951         240.244283         242.687797        230.633218         296.870036         313.444072        298.884294   0.042997   0.062295  0.075950
10     1.0   1024.0   8192.0  28672.0   288.259451   305.308744  311.439820       255.378385       245.062749      270.688889       327.832897       355.467473      343.174043     246.715671     261.307830    266.555299         218.[57](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:58)3405         209.744452        231.677368         280.585816         304.237713        293.716005   0.074947   0.123430  0.074933
11     1.0   3072.0   3072.0   4096.0   236.343195   309.249272  280.367924       151.195385       177.696060      203.437692       269.854108       353.793312      325.548437     207.441799     271.432504    246.082932         132.706349         155.966371        178.560169         236.854806         310.529444        285.738514   0.147948   0.195262  0.190186
12     1.0   4096.0   8192.0  16384.0   117.904464   132.682593  122.7088[58](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:59)        94.636826       110.890745      109.361943       138.884234       150.853892      136.817255     241.468342     271.733951    251.307740         193.816220         227.104246        223.973260         284.434912         308.948770        280.201738   0.084853   0.049050  0.072336
13     1.0   8192.0   1024.0  16384.0   323.353898   232.355318  326.043454       292.489822       218.840862      236.432027       360.211617       247.422361      381.231060     264.891513     190.345477    267.094798         239.607662         179.274434        193.685117         295.085357         202.688398        312.304484   0.052946   0.019370  0.143634
14     1.0   8192.0   4096.0  16384.0   119.842601   128.991624  127.617355        96.050933       115.724885      104.151327       147.401298       145.888832      144.718504     245.437647     264.174846    261.360344         196.712310         237.004565        213.301918         301.8778[59](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:60)         298.780328        296.383497   0.125490   0.075739  0.070078
15     1.0  16384.0   1024.0   8192.0   349.379762   343.292947  325.596568       303.140081       235.862212      181.864018       368.784058       376.669443      378.222198     272.582763     267.833888    254.027341         236.507004         184.017452        141.888575         287.721810         293.873912        295.085357   0.059499   0.0[60](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:61)443  0.105811
16     1.0  16384.0   4096.0   8192.0   140.553239   151.348344  141.159650       112.760214       116.724604      121.546627       165.318105       176.875341      164.367915     255.869362     275.521252    256.973300         205.273704         212.490658        221.268881         300.952425         321.991733        299.222657   0.086305   0.129233  0.073921
17     1.0  16384.0   8192.0   1024.0   501.942589   598.587711  369.607312       479.239470       518.437065      324.006004       552.131211       653.260231      401.489537     234.966497     280.207459    173.018463         224.338842         242.687797        151.671839         258.460507         305.800447        187.942988   0.025399   0.023453  0.035541
18     1.0  16384.0   8192.0   4096.0   170.332571   180.319085  1[61](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:62).107445       147.131013       142.645764      149.495636       188.192790       212.565509      176.527953     253.702623     268.577080    239.962216         219.144956         212.464382        222.666954         280.304606         316.606664        2[62](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:63).930362   0.079402   0.053053  0.053964
19     4.0  32768.0    128.0   4096.0   747.350156   739.377890  690.793192       719.755711       732.950756      687.863458       767.456437       749.374996      706.957522      89.703919      88.747014     82.915426          86.391777          87.975569         82.5[63](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:64)772          92.117262          89.946959         84.855619   0.004513   0.005834  0.004817
20     4.0  32768.0   4096.0    128.0  1060.761511  1949.707663  520.055681      1021.136578      1874.770498      514.201345      1078.637101      2034.515496      523.243512      66.715995     122.625759     32.708608          [64](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:65).223807         117.912629         32.340402          67.840270         127.959700         32.909104   0.011211   0.024812  0.003955
21    32.0   4096.0    128.0   4096.0   745.852960   718.211526  626.062252       743.219107       704.958885      601.937993       762.997115       731.151693      638.874740      87.286106      84.051269     73.267171          86.977870          82.500331         70.443943          89.292462          85.5[65](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:66)638         74.766598   0.001937   0.007473  0.005593
22  4096.0      8.0    128.0  16384.0   913.573255   924.240619  913.037369       904.582166       919.485064      909.039649       916.952509       928.101722      920.062923       6.872353       6.952598      6.868322           6.804717           6.916824          6.838249           6.897773           6.981643          6.921171   0.002925   0.002554  0.002043
23  4096.0      8.0  16384.0    128.0  1009.516817  1057.757400  903.[66](https://github.com/intel/intel-xpu-backend-for-triton/actions/runs/14360581875/job/40260798974?pr=3867#step:17:67)8526      1008.061131      1057.032231      902.945246      1011.833914      1059.107371      905.034772       7.175672       7.518567      6.423299           7.165325           7.513413          6.418158           7.192142           7.528163          6.433011   0.000577   0.000352  0.000654
```
author_association: CONTRIBUTOR
user: login: etiotto
created_at: 2025-04-10T17:38:10Z
body: I created a NFI pull request (#3897) to refactor the existing code without changing current behavior.  Let's review and land that one first, and then I will rebase this PR and address code review comments that are specific to the functional improvement in this PR. 
author_association: CONTRIBUTOR