[Mlir-commits] [mlir] 6248bfb - [mlir][SPIR-V] Derive Aligned memory operand for PhysicalStorageBuffer in vector.load/store (#214200)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Oct 14 02:11:48 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-10-14T11:11:37+02:00
New Revision: 6248bfbe99eb1409f2dfdbcb791df3a2c64b97e6

URL: https://github.com/llvm/llvm-project/commit/6248bfbe99eb1409f2dfdbcb791df3a2c64b97e6
DIFF: https://github.com/llvm/llvm-project/commit/6248bfbe99eb1409f2dfdbcb791df3a2c64b97e6.diff

LOG: [mlir][SPIR-V] Derive Aligned memory operand for PhysicalStorageBuffer in vector.load/store (#214200)

Mirror calculateMemoryRequirements from MemRefToSPIRV.cpp, since
PhysicalStorageBuffer pointers carry no implicit alignment guarantee

Added: 
    

Modified: 
    mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
    mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp b/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
index 7038f25119159..4b93f7b24e0a8 100644
--- a/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
+++ b/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
@@ -53,6 +53,49 @@ static int getNumBits(Type type) {
   return type.getIntOrFloatBitWidth();
 }
 
+namespace {
+struct MemoryRequirements {
+  spirv::MemoryAccessAttr memoryAccess;
+  IntegerAttr alignment;
+};
+} // namespace
+
+/// PhysicalStorageBuffer pointers always need Aligned, derived from pointee
+/// element size unless preferredAlignment is set. Other storage classes may
+/// omit it.
+static FailureOr<MemoryRequirements>
+calculateMemoryRequirements(Value accessedPtr, uint64_t preferredAlignment) {
+  if (preferredAlignment >= std::numeric_limits<uint32_t>::max())
+    return failure();
+
+  MLIRContext *ctx = accessedPtr.getContext();
+  auto ptrType = cast<spirv::PointerType>(accessedPtr.getType());
+  bool mayOmitAlignment =
+      !preferredAlignment &&
+      ptrType.getStorageClass() != spirv::StorageClass::PhysicalStorageBuffer;
+  if (mayOmitAlignment)
+    return MemoryRequirements{spirv::MemoryAccessAttr{}, IntegerAttr{}};
+
+  // PhysicalStorageBuffer pointers require Aligned. The vector pointer is a
+  // bitcast of a scalar element pointer, so only element alignment is known.
+  std::optional<int64_t> sizeInBytes;
+  Type pointeeType = ptrType.getPointeeType();
+  if (auto vecType = dyn_cast<VectorType>(pointeeType))
+    pointeeType = vecType.getElementType();
+  if (auto scalarType = dyn_cast<spirv::ScalarType>(pointeeType))
+    sizeInBytes = scalarType.getSizeInBytes();
+
+  if (!sizeInBytes)
+    return failure();
+
+  auto memoryAccess =
+      spirv::MemoryAccessAttr::get(ctx, spirv::MemoryAccess::Aligned);
+  uint64_t alignmentValue =
+      preferredAlignment ? preferredAlignment : *sizeInBytes;
+  auto alignment = IntegerAttr::get(IntegerType::get(ctx, 32), alignmentValue);
+  return MemoryRequirements{memoryAccess, alignment};
+}
+
 namespace {
 
 struct VectorShapeCast final : public OpConversionPattern<vector::ShapeCastOp> {
@@ -764,22 +807,6 @@ struct VectorLoadOpConverter final
 
     auto vectorPtrType = spirv::PointerType::get(spirvVectorType, storageClass);
 
-    std::optional<uint64_t> alignment = loadOp.getAlignment();
-    if (alignment > std::numeric_limits<uint32_t>::max()) {
-      return rewriter.notifyMatchFailure(loadOp,
-                                         "invalid alignment requirement");
-    }
-
-    auto memoryAccess = spirv::MemoryAccess::None;
-    spirv::MemoryAccessAttr memoryAccessAttr;
-    IntegerAttr alignmentAttr;
-    if (alignment.has_value()) {
-      memoryAccess |= spirv::MemoryAccess::Aligned;
-      memoryAccessAttr =
-          spirv::MemoryAccessAttr::get(rewriter.getContext(), memoryAccess);
-      alignmentAttr = rewriter.getI32IntegerAttr(alignment.value());
-    }
-
     // For single element vectors, we don't need to bitcast the access chain to
     // the original vector type. Both is going to be the same, a pointer
     // to a scalar.
@@ -789,9 +816,15 @@ struct VectorLoadOpConverter final
             : spirv::BitcastOp::create(rewriter, loc, vectorPtrType,
                                        accessChain);
 
-    rewriter.replaceOpWithNewOp<spirv::LoadOp>(loadOp, spirvVectorType,
-                                               castedAccessChain,
-                                               memoryAccessAttr, alignmentAttr);
+    auto memoryRequirements = calculateMemoryRequirements(
+        castedAccessChain, loadOp.getAlignment().value_or(0));
+    if (failed(memoryRequirements))
+      return rewriter.notifyMatchFailure(
+          loadOp, "failed to determine memory requirements");
+
+    auto [memoryAccess, alignment] = *memoryRequirements;
+    rewriter.replaceOpWithNewOp<spirv::LoadOp>(
+        loadOp, spirvVectorType, castedAccessChain, memoryAccess, alignment);
 
     return success();
   }
@@ -820,12 +853,6 @@ struct VectorStoreOpConverter final
       return rewriter.notifyMatchFailure(
           storeOp, "failed to get memref element pointer");
 
-    std::optional<uint64_t> alignment = storeOp.getAlignment();
-    if (alignment > std::numeric_limits<uint32_t>::max()) {
-      return rewriter.notifyMatchFailure(storeOp,
-                                         "invalid alignment requirement");
-    }
-
     spirv::StorageClass storageClass = attr.getValue();
     auto vectorType = storeOp.getVectorType();
     // Use the converted vector type instead of original (single element vector
@@ -845,19 +872,16 @@ struct VectorStoreOpConverter final
             : spirv::BitcastOp::create(rewriter, loc, vectorPtrType,
                                        accessChain);
 
-    auto memoryAccess = spirv::MemoryAccess::None;
-    spirv::MemoryAccessAttr memoryAccessAttr;
-    IntegerAttr alignmentAttr;
-    if (alignment.has_value()) {
-      memoryAccess |= spirv::MemoryAccess::Aligned;
-      memoryAccessAttr =
-          spirv::MemoryAccessAttr::get(rewriter.getContext(), memoryAccess);
-      alignmentAttr = rewriter.getI32IntegerAttr(alignment.value());
-    }
+    auto memoryRequirements = calculateMemoryRequirements(
+        castedAccessChain, storeOp.getAlignment().value_or(0));
+    if (failed(memoryRequirements))
+      return rewriter.notifyMatchFailure(
+          storeOp, "failed to determine memory requirements");
 
-    rewriter.replaceOpWithNewOp<spirv::StoreOp>(
-        storeOp, castedAccessChain, adaptor.getValueToStore(), memoryAccessAttr,
-        alignmentAttr);
+    auto [memoryAccess, alignment] = *memoryRequirements;
+    rewriter.replaceOpWithNewOp<spirv::StoreOp>(storeOp, castedAccessChain,
+                                                adaptor.getValueToStore(),
+                                                memoryAccess, alignment);
 
     return success();
   }

diff  --git a/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir b/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
index 6319e30500034..b3b27fde9f861 100644
--- a/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
+++ b/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
@@ -1312,3 +1312,33 @@ func.func @vector_load(%arg0 : memref<4xf32, #spirv.storage_class<StorageBuffer>
   %0 = vector.load %arg0[%idx] : memref<4xf32, #spirv.storage_class<StorageBuffer>>, vector<4xf32>
   return %0: vector<4xf32>
 }
+
+// -----
+
+// PhysicalStorageBuffer pointers get an Aligned memory operand, unlike StorageBuffer above.
+
+module attributes {
+  spirv.target_env = #spirv.target_env<
+    #spirv.vce<v1.6, [Shader, PhysicalStorageBufferAddresses],
+      [SPV_KHR_physical_storage_buffer]>, #spirv.resource_limits<>>
+  } {
+
+// CHECK-LABEL: @vector_load_physical
+//       CHECK:   spirv.Load "PhysicalStorageBuffer" {{%.*}} ["Aligned", 4] : vector<4xf32>
+func.func @vector_load_physical(%arg0 : memref<4xf32, #spirv.storage_class<PhysicalStorageBuffer>>
+    {spirv.decoration = #spirv.decoration<Aliased>}) -> vector<4xf32> {
+  %idx = arith.constant 0 : index
+  %0 = vector.load %arg0[%idx] : memref<4xf32, #spirv.storage_class<PhysicalStorageBuffer>>, vector<4xf32>
+  return %0: vector<4xf32>
+}
+
+// CHECK-LABEL: @vector_store_physical
+//       CHECK:   spirv.Store "PhysicalStorageBuffer" {{%.*}}, {{%.*}} ["Aligned", 4] : vector<4xf32>
+func.func @vector_store_physical(%arg0 : memref<4xf32, #spirv.storage_class<PhysicalStorageBuffer>>
+    {spirv.decoration = #spirv.decoration<Aliased>}, %arg1 : vector<4xf32>) {
+  %idx = arith.constant 0 : index
+  vector.store %arg1, %arg0[%idx] : memref<4xf32, #spirv.storage_class<PhysicalStorageBuffer>>, vector<4xf32>
+  return
+}
+
+}


        


More information about the Mlir-commits mailing list