[Mlir-commits] [mlir] [mlir][AMDGPU] Do not request nuw for negative-stride memrefs (PR #221419)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Sep 5 00:55:35 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Samarth Narang (snarang181)

<details>
<summary>Changes</summary>

AMDGPUToROCDL asked getStridedElementPtr for inbounds|nuw unconditionally when lowering amdgpu.global_transpose_load and non-speculative amdgpu.global_prefetch. nuw promises that each index*stride term does not wrap as an unsigned value, which a negative stride cannot satisfy: it is a large unsigned bit pattern, so idx * (-1 as u64) wraps for any positive index and LLVM may treat the resulting address as poison. 

Gate nuw on all strides being statically non-negative, matching what MemRefToLLVM already does for memref.load/store (#<!-- -->204309). A dynamic stride also fails the check, since non-negativity cannot be established for one. We do not touch the speculative prefetch path as it already requests no flags.

Fixes #<!-- -->221412.

---
Full diff: https://github.com/llvm/llvm-project/pull/221419.diff


3 Files Affected:

- (modified) mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp (+17-3) 
- (modified) mlir/test/Conversion/AMDGPUToROCDL/global-prefetch.mlir (+16) 
- (modified) mlir/test/Conversion/AMDGPUToROCDL/global_transpose_load.mlir (+19) 


``````````diff
diff --git a/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp b/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
index 2a846339b562e..42d0999ac9fc4 100644
--- a/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
+++ b/mlir/lib/Conversion/AMDGPUToROCDL/AMDGPUToROCDL.cpp
@@ -43,6 +43,21 @@ namespace mlir {
 using namespace mlir;
 using namespace mlir::amdgpu;
 
+/// Returns the GEP no-wrap flags valid for address arithmetic on `memRefType`.
+/// `inbounds` always holds, since these ops require in-bounds indices. `nuw`
+/// additionally promises that no `index * stride` term wraps as an unsigned
+/// value, which only holds when every stride is statically non-negative. This
+/// matches what MemRefToLLVM does for `memref.load`/`store`.
+static LLVM::GEPNoWrapFlags getNoWrapFlags(MemRefType memRefType) {
+  auto [strides, offset] = memRefType.getStridesAndOffset();
+  LLVM::GEPNoWrapFlags flags = LLVM::GEPNoWrapFlags::inbounds;
+  if (llvm::all_of(strides, [](int64_t stride) {
+        return ShapedType::isStatic(stride) && stride >= 0;
+      }))
+    flags = flags | LLVM::GEPNoWrapFlags::nuw;
+  return flags;
+}
+
 // Define commonly used chipsets versions for convenience.
 constexpr Chipset kGfx908 = Chipset(9, 0, 8);
 constexpr Chipset kGfx90a = Chipset(9, 0, 0xa);
@@ -2356,7 +2371,7 @@ struct GlobalTransposeLoadOpLowering
 
     Value srcPtr = getStridedElementPtr(
         rewriter, loc, srcMemRefType, adaptor.getSrc(), adaptor.getSrcIndices(),
-        LLVM::GEPNoWrapFlags::inbounds | LLVM::GEPNoWrapFlags::nuw);
+        getNoWrapFlags(srcMemRefType));
 
     size_t numElements = resultType.getNumElements();
     size_t elementTypeSize =
@@ -4505,8 +4520,7 @@ struct GlobalPrefetchOpLowering
     MemRefType memRefType = op.getSrc().getType();
     Location loc = op->getLoc();
     auto inboundsFlags = isSpeculative ? LLVM::GEPNoWrapFlags::none
-                                       : LLVM::GEPNoWrapFlags::inbounds |
-                                             LLVM::GEPNoWrapFlags::nuw;
+                                       : getNoWrapFlags(memRefType);
     Value prefetchPtr = getStridedElementPtr(
         rewriter, loc, memRefType, descriptor, indices, inboundsFlags);
 
diff --git a/mlir/test/Conversion/AMDGPUToROCDL/global-prefetch.mlir b/mlir/test/Conversion/AMDGPUToROCDL/global-prefetch.mlir
index f71de64cd071f..02a56c5c4b386 100644
--- a/mlir/test/Conversion/AMDGPUToROCDL/global-prefetch.mlir
+++ b/mlir/test/Conversion/AMDGPUToROCDL/global-prefetch.mlir
@@ -31,3 +31,19 @@ func.func @glb_prefetch3(%src : memref<64x64xf16, #gpu.address_space<global>>, %
   amdgpu.global_prefetch %src[%i, %j] NT_RT SE speculative : memref<64x64xf16, #gpu.address_space<global>>
   func.return
 }
+
+// -----
+
+// As above: a negative stride cannot carry the `nuw` promise.
+
+// CHECK-LABEL: @glb_prefetch_negative_stride
+func.func @glb_prefetch_negative_stride(
+    %src : memref<64x64xf16, strided<[64, -1], offset: 63>, #gpu.address_space<global>>,
+    %i : i64, %j : i64) {
+  // CHECK: llvm.getelementptr inbounds %{{.*}}[%{{.*}}]
+  // CHECK-NOT: inbounds|nuw
+  // CHECK: rocdl.global.prefetch
+  amdgpu.global_prefetch %src[%i, %j] HT WGP
+    : memref<64x64xf16, strided<[64, -1], offset: 63>, #gpu.address_space<global>>
+  func.return
+}
diff --git a/mlir/test/Conversion/AMDGPUToROCDL/global_transpose_load.mlir b/mlir/test/Conversion/AMDGPUToROCDL/global_transpose_load.mlir
index f378d7232d7b3..f22c6abc5f382 100644
--- a/mlir/test/Conversion/AMDGPUToROCDL/global_transpose_load.mlir
+++ b/mlir/test/Conversion/AMDGPUToROCDL/global_transpose_load.mlir
@@ -55,3 +55,22 @@ func.func @global_transpose_load_16xi6(%i : index, %j : index,
          : memref<128x32xi8, #gpu.address_space<global>> -> vector<16xi6>
   return %0 : vector<16xi6>
 }
+
+// -----
+
+// A negative stride makes the `index * stride` term wrap when computed as an
+// unsigned value, so `nuw` must not be requested even though the signed
+// address is correct and in bounds.
+
+// CHECK-LABEL: func @global_transpose_load_negative_stride
+func.func @global_transpose_load_negative_stride(%i : index, %j : index,
+    %src : memref<128x256xf16, strided<[256, -1], offset: 255>, #gpu.address_space<global>>)
+    -> vector<8xf16> {
+  // CHECK: llvm.mul %{{.*}}, %{{.*}} overflow<nsw> : i64
+  // CHECK-NOT: overflow<nsw, nuw>
+  // CHECK: llvm.getelementptr inbounds %{{.*}}[%{{.*}}]
+  // CHECK-NOT: inbounds|nuw
+  %0 = amdgpu.global_transpose_load %src[%i, %j]
+         : memref<128x256xf16, strided<[256, -1], offset: 255>, #gpu.address_space<global>> -> vector<8xf16>
+  return %0 : vector<8xf16>
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/221419


More information about the Mlir-commits mailing list