[Mlir-commits] [mlir] [mlir][spirv] Add in-bounds access chain conversion (PR #216984)
Hsiangkai Wang
llvmlistbot at llvm.org
Tue Aug 18 03:55:50 PDT 2026
https://github.com/Hsiangkai created https://github.com/llvm/llvm-project/pull/216984
Use spirv.InBoundsAccessChain for static StorageBuffer accesses whose linearized range fits the declared SPIR-V object.
Keep plain access chains for dynamic layouts and packed sub-16-bit storage.
>From 8c069fe01675e08e92b773466238ae7103361958 Mon Sep 17 00:00:00 2001
From: Hsiangkai Wang <hsiangkai.wang at arm.com>
Date: Mon, 17 Aug 2026 10:30:48 +0100
Subject: [PATCH] [mlir][spirv] Add in-bounds access chain conversion
Use spirv.InBoundsAccessChain for static StorageBuffer accesses whose
linearized range fits the declared SPIR-V object.
Keep plain access chains for dynamic layouts and packed sub-16-bit storage.
---
.../SPIRV/Transforms/SPIRVConversion.h | 14 ++++
.../VectorToSPIRV/VectorToSPIRV.cpp | 12 ++--
.../SPIRV/Transforms/SPIRVConversion.cpp | 71 ++++++++++++++++++-
.../MemRefToSPIRV/memref-to-spirv.mlir | 12 ++--
.../VectorToSPIRV/vector-to-spirv.mlir | 23 ++++--
5 files changed, 111 insertions(+), 21 deletions(-)
diff --git a/mlir/include/mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h b/mlir/include/mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h
index 577fa2c44496b..acb41b74384dc 100644
--- a/mlir/include/mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h
+++ b/mlir/include/mlir/Dialect/SPIRV/Transforms/SPIRVConversion.h
@@ -198,6 +198,13 @@ Value getElementPtr(const SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr, ValueRange indices,
Location loc, OpBuilder &builder);
+/// As above, with the number of contiguous memref elements accessed through
+/// the pointer. This lets vector conversions retain their full access range.
+Value getElementPtr(const SPIRVTypeConverter &typeConverter,
+ MemRefType baseType, Value basePtr, ValueRange indices,
+ Location loc, OpBuilder &builder,
+ uint64_t accessElementCount);
+
// GetElementPtr implementation for Kernel/OpenCL flavored SPIR-V.
Value getOpenCLElementPtr(const SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr,
@@ -208,6 +215,13 @@ Value getVulkanElementPtr(const SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr,
ValueRange indices, Location loc, OpBuilder &builder);
+/// As above, with the number of contiguous memref elements accessed through
+/// the pointer.
+Value getVulkanElementPtr(const SPIRVTypeConverter &typeConverter,
+ MemRefType baseType, Value basePtr,
+ ValueRange indices, Location loc, OpBuilder &builder,
+ uint64_t accessElementCount);
+
// Find the largest factor of size among {2,3,4} for the lowest dimension of
// the target shape.
int getComputeVectorSize(int64_t size);
diff --git a/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp b/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
index 78693e924c4d9..0808d13620be0 100644
--- a/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
+++ b/mlir/lib/Conversion/VectorToSPIRV/VectorToSPIRV.cpp
@@ -743,9 +743,9 @@ struct VectorLoadOpConverter final
const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
auto loc = loadOp.getLoc();
- Value accessChain =
- spirv::getElementPtr(typeConverter, memrefType, adaptor.getBase(),
- adaptor.getIndices(), loc, rewriter);
+ Value accessChain = spirv::getElementPtr(
+ typeConverter, memrefType, adaptor.getBase(), adaptor.getIndices(), loc,
+ rewriter, loadOp.getVectorType().getNumElements());
if (!accessChain)
return rewriter.notifyMatchFailure(
loadOp, "failed to get memref element pointer");
@@ -809,9 +809,9 @@ struct VectorStoreOpConverter final
const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
auto loc = storeOp.getLoc();
- Value accessChain =
- spirv::getElementPtr(typeConverter, memrefType, adaptor.getBase(),
- adaptor.getIndices(), loc, rewriter);
+ Value accessChain = spirv::getElementPtr(
+ typeConverter, memrefType, adaptor.getBase(), adaptor.getIndices(), loc,
+ rewriter, storeOp.getVectorType().getNumElements());
if (!accessChain)
return rewriter.notifyMatchFailure(
storeOp, "failed to get memref element pointer");
diff --git a/mlir/lib/Dialect/SPIRV/Transforms/SPIRVConversion.cpp b/mlir/lib/Dialect/SPIRV/Transforms/SPIRVConversion.cpp
index 1c8a22fb35639..59b716a48348c 100644
--- a/mlir/lib/Dialect/SPIRV/Transforms/SPIRVConversion.cpp
+++ b/mlir/lib/Dialect/SPIRV/Transforms/SPIRVConversion.cpp
@@ -1316,6 +1316,49 @@ static std::optional<uint64_t> getMaxLinearizedIndex(ArrayRef<int64_t> shape,
return maxLinearIndex;
}
+static std::optional<uint64_t> getStorageBufferElementCount(Value basePtr) {
+ auto pointerType = dyn_cast<spirv::PointerType>(basePtr.getType());
+ if (!pointerType ||
+ pointerType.getStorageClass() != spirv::StorageClass::StorageBuffer)
+ return std::nullopt;
+
+ Type pointeeType = pointerType.getPointeeType();
+ if (auto structType = dyn_cast<spirv::StructType>(pointeeType)) {
+ if (structType.getNumElements() != 1)
+ return std::nullopt;
+ pointeeType = structType.getElementType(0);
+ }
+ auto arrayType = dyn_cast<spirv::ArrayType>(pointeeType);
+ if (!arrayType)
+ return std::nullopt;
+ return arrayType.getNumElements();
+}
+
+static bool shouldEmitInBoundsAccessChain(MemRefType baseType, Value basePtr,
+ ArrayRef<int64_t> strides,
+ int64_t offset,
+ uint64_t accessElementCount) {
+ // Sub-16-bit integer memrefs may be stored using a wider SPIR-V array element
+ // than the source element. Keep a plain access chain so later bitwidth
+ // emulation can adjust the final index in storage-element units.
+ if (auto integerType = dyn_cast<IntegerType>(baseType.getElementType()))
+ if (integerType.getWidth() < 16)
+ return false;
+
+ std::optional<uint64_t> maxLinearIndex =
+ getMaxLinearizedIndex(baseType.getShape(), strides, offset);
+ std::optional<uint64_t> objectElementCount =
+ getStorageBufferElementCount(basePtr);
+ if (!maxLinearIndex || !objectElementCount || !accessElementCount ||
+ accessElementCount > *objectElementCount)
+ return false;
+
+ // The source memory operation guarantees that its dynamic indices, including
+ // a vector access width, are in bounds. The static layout proof here ensures
+ // that this contract describes the same fixed-size SPIR-V buffer object.
+ return *maxLinearIndex < *objectElementCount;
+}
+
} // namespace
//===----------------------------------------------------------------------===//
@@ -1431,7 +1474,8 @@ Value mlir::spirv::linearizeIndex(ValueRange indices, ArrayRef<int64_t> strides,
Value mlir::spirv::getVulkanElementPtr(const SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr,
ValueRange indices, Location loc,
- OpBuilder &builder) {
+ OpBuilder &builder,
+ uint64_t accessElementCount) {
// Get base and offset of the MemRefType and verify they are static.
int64_t offset;
@@ -1462,9 +1506,21 @@ Value mlir::spirv::getVulkanElementPtr(const SPIRVTypeConverter &typeConverter,
// Interface memrefs are wrapped in a struct: index to its first elem.
if (isa<spirv::StructType>(pointeeType))
linearizedIndices.insert(linearizedIndices.begin(), zero);
+ if (shouldEmitInBoundsAccessChain(baseType, basePtr, strides, offset,
+ accessElementCount))
+ return spirv::InBoundsAccessChainOp::create(builder, loc, basePtr,
+ linearizedIndices);
return spirv::AccessChainOp::create(builder, loc, basePtr, linearizedIndices);
}
+Value mlir::spirv::getVulkanElementPtr(const SPIRVTypeConverter &typeConverter,
+ MemRefType baseType, Value basePtr,
+ ValueRange indices, Location loc,
+ OpBuilder &builder) {
+ return getVulkanElementPtr(typeConverter, baseType, basePtr, indices, loc,
+ builder, /*accessElementCount=*/1);
+}
+
Value mlir::spirv::getOpenCLElementPtr(const SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr,
ValueRange indices, Location loc,
@@ -1506,7 +1562,8 @@ Value mlir::spirv::getOpenCLElementPtr(const SPIRVTypeConverter &typeConverter,
Value mlir::spirv::getElementPtr(const SPIRVTypeConverter &typeConverter,
MemRefType baseType, Value basePtr,
ValueRange indices, Location loc,
- OpBuilder &builder) {
+ OpBuilder &builder,
+ uint64_t accessElementCount) {
if (typeConverter.allows(spirv::Capability::Kernel)) {
return getOpenCLElementPtr(typeConverter, baseType, basePtr, indices, loc,
@@ -1514,7 +1571,15 @@ Value mlir::spirv::getElementPtr(const SPIRVTypeConverter &typeConverter,
}
return getVulkanElementPtr(typeConverter, baseType, basePtr, indices, loc,
- builder);
+ builder, accessElementCount);
+}
+
+Value mlir::spirv::getElementPtr(const SPIRVTypeConverter &typeConverter,
+ MemRefType baseType, Value basePtr,
+ ValueRange indices, Location loc,
+ OpBuilder &builder) {
+ return getElementPtr(typeConverter, baseType, basePtr, indices, loc, builder,
+ /*accessElementCount=*/1);
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Conversion/MemRefToSPIRV/memref-to-spirv.mlir b/mlir/test/Conversion/MemRefToSPIRV/memref-to-spirv.mlir
index ebddeadf3a31a..495b5bfc87a3c 100644
--- a/mlir/test/Conversion/MemRefToSPIRV/memref-to-spirv.mlir
+++ b/mlir/test/Conversion/MemRefToSPIRV/memref-to-spirv.mlir
@@ -24,12 +24,12 @@ func.func @load_store_zero_rank_float(%arg0: memref<f32, #spirv.storage_class<St
// CHECK-DAG: [[ARG0:%.*]] = builtin.unrealized_conversion_cast %[[OARG0]] : memref<f32, #spirv.storage_class<StorageBuffer>> to !spirv.ptr<!spirv.struct<(!spirv.array<1 x f32, stride=4> [0])>, StorageBuffer>
// CHECK-DAG: [[ARG1:%.*]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref<f32, #spirv.storage_class<StorageBuffer>> to !spirv.ptr<!spirv.struct<(!spirv.array<1 x f32, stride=4> [0])>, StorageBuffer>
// CHECK: [[ZERO:%.*]] = spirv.Constant 0 : i32
- // CHECK: spirv.AccessChain [[ARG0]][
+ // CHECK: spirv.InBoundsAccessChain [[ARG0]][
// CHECK-SAME: [[ZERO]], [[ZERO]]
// CHECK-SAME: ] :
// CHECK: spirv.Load "StorageBuffer" %{{.*}} : f32
%0 = memref.load %arg0[] : memref<f32, #spirv.storage_class<StorageBuffer>>
- // CHECK: spirv.AccessChain [[ARG1]][
+ // CHECK: spirv.InBoundsAccessChain [[ARG1]][
// CHECK-SAME: [[ZERO]], [[ZERO]]
// CHECK-SAME: ] :
// CHECK: spirv.Store "StorageBuffer" %{{.*}} : f32
@@ -43,12 +43,12 @@ func.func @load_store_zero_rank_int(%arg0: memref<i32, #spirv.storage_class<Stor
// CHECK-DAG: [[ARG0:%.*]] = builtin.unrealized_conversion_cast %[[OARG0]] : memref<i32, #spirv.storage_class<StorageBuffer>> to !spirv.ptr<!spirv.struct<(!spirv.array<1 x i32, stride=4> [0])>, StorageBuffer>
// CHECK-DAG: [[ARG1:%.*]] = builtin.unrealized_conversion_cast %[[OARG1]] : memref<i32, #spirv.storage_class<StorageBuffer>> to !spirv.ptr<!spirv.struct<(!spirv.array<1 x i32, stride=4> [0])>, StorageBuffer>
// CHECK: [[ZERO:%.*]] = spirv.Constant 0 : i32
- // CHECK: spirv.AccessChain [[ARG0]][
+ // CHECK: spirv.InBoundsAccessChain [[ARG0]][
// CHECK-SAME: [[ZERO]], [[ZERO]]
// CHECK-SAME: ] :
// CHECK: spirv.Load "StorageBuffer" %{{.*}} : i32
%0 = memref.load %arg0[] : memref<i32, #spirv.storage_class<StorageBuffer>>
- // CHECK: spirv.AccessChain [[ARG1]][
+ // CHECK: spirv.InBoundsAccessChain [[ARG1]][
// CHECK-SAME: [[ZERO]], [[ZERO]]
// CHECK-SAME: ] :
// CHECK: spirv.Store "StorageBuffer" %{{.*}} : i32
@@ -231,7 +231,7 @@ func.func @static_linearized_index(
// CHECK: %[[STRIDE:.+]] = spirv.Constant 4 : i32
// CHECK: %[[OFFSET:.+]] = spirv.IMul %{{.*}}, %[[STRIDE]] {no_signed_wrap, no_unsigned_wrap} : i32
// CHECK: %[[LINEAR:.+]] = spirv.IAdd %{{.*}}, %[[OFFSET]] {no_signed_wrap, no_unsigned_wrap} : i32
- // CHECK: spirv.AccessChain {{.*}}[%{{.*}}, %[[LINEAR]]]
+ // CHECK: spirv.InBoundsAccessChain {{.*}}[%{{.*}}, %[[LINEAR]]]
%0 = memref.load %arg0[%row, %column] : memref<2x4xf32, #spirv.storage_class<StorageBuffer>>
return %0 : f32
}
@@ -247,7 +247,7 @@ func.func @unsigned_only_linearized_index(
// CHECK-NOT: no_signed_wrap
// CHECK: %[[LINEAR:.+]] = spirv.IAdd %{{.*}}, %[[OFFSET]] {no_unsigned_wrap} : i32
// CHECK-NOT: no_signed_wrap
- // CHECK: spirv.AccessChain {{.*}}[%{{.*}}, %[[LINEAR]]]
+ // CHECK: spirv.InBoundsAccessChain {{.*}}[%{{.*}}, %[[LINEAR]]]
%0 = memref.load %arg0[%row, %column] : memref<2x1073741825xf32, #spirv.storage_class<StorageBuffer>>
return %0 : f32
}
diff --git a/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir b/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
index f904dd9d35c37..d8e187e919bf1 100644
--- a/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
+++ b/mlir/test/Conversion/VectorToSPIRV/vector-to-spirv.mlir
@@ -1117,7 +1117,7 @@ module attributes {
// CHECK: %[[CST1:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST2:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST3:.+]] = spirv.Constant 1 : i32
-// CHECK: %[[S4:.+]] = spirv.AccessChain %[[S0]][%[[CST1]], %[[S1]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
+// CHECK: %[[S4:.+]] = spirv.InBoundsAccessChain %[[S0]][%[[CST1]], %[[S1]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
// CHECK: %[[S5:.+]] = spirv.Bitcast %[[S4]] : !spirv.ptr<f32, StorageBuffer> to !spirv.ptr<vector<4xf32>, StorageBuffer>
// CHECK: %[[R0:.+]] = spirv.Load "StorageBuffer" %[[S5]] : vector<4xf32>
// CHECK: return %[[R0]] : vector<4xf32>
@@ -1128,6 +1128,17 @@ func.func @vector_load(%arg0 : memref<4xf32, #spirv.storage_class<StorageBuffer>
return %0: vector<4xf32>
}
+// Dynamic StorageBuffer layouts do not identify a fixed base object, so keep
+// the pointer calculation conservative even though the vector access itself
+// has in-bounds source semantics.
+// CHECK-LABEL: @vector_load_dynamic
+// CHECK: spirv.AccessChain {{.*}} !spirv.ptr<!spirv.struct<(!spirv.rtarray<f32, stride=4> [0])>, StorageBuffer>
+func.func @vector_load_dynamic(%arg0 : memref<?xf32, #spirv.storage_class<StorageBuffer>>) -> vector<4xf32> {
+ %idx = arith.constant 0 : index
+ %0 = vector.load %arg0[%idx] : memref<?xf32, #spirv.storage_class<StorageBuffer>>, vector<4xf32>
+ return %0: vector<4xf32>
+}
+
// CHECK-LABEL: @vector_load_single_elem
// CHECK-SAME: (%[[ARG0:.*]]: memref<4xf32, #spirv.storage_class<StorageBuffer>>)
@@ -1137,7 +1148,7 @@ func.func @vector_load(%arg0 : memref<4xf32, #spirv.storage_class<StorageBuffer>
// CHECK: %[[CST1:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST2:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST3:.+]] = spirv.Constant 1 : i32
-// CHECK: %[[S4:.+]] = spirv.AccessChain %[[S0]][%[[CST1]], %[[S1]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
+// CHECK: %[[S4:.+]] = spirv.InBoundsAccessChain %[[S0]][%[[CST1]], %[[S1]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
// CHECK: %[[S5:.+]] = spirv.Load "StorageBuffer" %[[S4]] : f32
// CHECK: %[[R0:.+]] = builtin.unrealized_conversion_cast %[[S5]] : f32 to vector<1xf32>
// CHECK: return %[[R0]] : vector<1xf32>
@@ -1170,7 +1181,7 @@ func.func @vector_load_aligned(%arg0 : memref<4xf32, #spirv.storage_class<Storag
// CHECK: %[[S3:.+]] = spirv.IMul %[[S1]], %[[CST4]] : i32
// CHECK: %[[CST1:.+]] = spirv.Constant 1 : i32
// CHECK: %[[S6:.+]] = spirv.IAdd %[[S2]], %[[S3]] : i32
-// CHECK: %[[S7:.+]] = spirv.AccessChain %[[S0]][%[[CST0_1]], %[[S6]]] : !spirv.ptr<!spirv.struct<(!spirv.array<16 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
+// CHECK: %[[S7:.+]] = spirv.InBoundsAccessChain %[[S0]][%[[CST0_1]], %[[S6]]] : !spirv.ptr<!spirv.struct<(!spirv.array<16 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
// CHECK: %[[S8:.+]] = spirv.Bitcast %[[S7]] : !spirv.ptr<f32, StorageBuffer> to !spirv.ptr<vector<4xf32>, StorageBuffer>
// CHECK: %[[R0:.+]] = spirv.Load "StorageBuffer" %[[S8]] : vector<4xf32>
// CHECK: return %[[R0]] : vector<4xf32>
@@ -1190,7 +1201,7 @@ func.func @vector_load_2d(%arg0 : memref<4x4xf32, #spirv.storage_class<StorageBu
// CHECK: %[[CST1:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST2:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST3:.+]] = spirv.Constant 1 : i32
-// CHECK: %[[S4:.+]] = spirv.AccessChain %[[S0]][%[[CST1]], %[[S1]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
+// CHECK: %[[S4:.+]] = spirv.InBoundsAccessChain %[[S0]][%[[CST1]], %[[S1]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
// CHECK: %[[S5:.+]] = spirv.Bitcast %[[S4]] : !spirv.ptr<f32, StorageBuffer> to !spirv.ptr<vector<4xf32>, StorageBuffer>
// CHECK: spirv.Store "StorageBuffer" %[[S5]], %[[ARG1]] : vector<4xf32>
func.func @vector_store(%arg0 : memref<4xf32, #spirv.storage_class<StorageBuffer>>, %arg1 : vector<4xf32>) {
@@ -1218,7 +1229,7 @@ func.func @vector_store_aligned(%arg0 : memref<4xf32, #spirv.storage_class<Stora
// CHECK: %[[CST1:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST2:.+]] = spirv.Constant 0 : i32
// CHECK: %[[CST3:.+]] = spirv.Constant 1 : i32
-// CHECK: %[[S4:.+]] = spirv.AccessChain %[[S0]][%[[CST1]], %[[S2]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<f32, StorageBuffer>
+// CHECK: %[[S4:.+]] = spirv.InBoundsAccessChain %[[S0]][%[[CST1]], %[[S2]]] : !spirv.ptr<!spirv.struct<(!spirv.array<4 x f32, stride=4> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<f32, StorageBuffer>
// CHECK: spirv.Store "StorageBuffer" %[[S4]], %[[S1]] : f32
func.func @vector_store_single_elem(%arg0 : memref<4xf32, #spirv.storage_class<StorageBuffer>>, %arg1 : vector<1xf32>) {
%idx = arith.constant 0 : index
@@ -1240,7 +1251,7 @@ func.func @vector_store_single_elem(%arg0 : memref<4xf32, #spirv.storage_class<S
// CHECK: %[[S3:.+]] = spirv.IMul %[[S1]], %[[CST4]] : i32
// CHECK: %[[CST1:.+]] = spirv.Constant 1 : i32
// CHECK: %[[S6:.+]] = spirv.IAdd %[[S2]], %[[S3]] : i32
-// CHECK: %[[S7:.+]] = spirv.AccessChain %[[S0]][%[[CST0_1]], %[[S6]]] : !spirv.ptr<!spirv.struct<(!spirv.array<16 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
+// CHECK: %[[S7:.+]] = spirv.InBoundsAccessChain %[[S0]][%[[CST0_1]], %[[S6]]] : !spirv.ptr<!spirv.struct<(!spirv.array<16 x f32, stride=4> [0])>, StorageBuffer>, i32, i32
// CHECK: %[[S8:.+]] = spirv.Bitcast %[[S7]] : !spirv.ptr<f32, StorageBuffer> to !spirv.ptr<vector<4xf32>, StorageBuffer>
// CHECK: spirv.Store "StorageBuffer" %[[S8]], %[[ARG1]] : vector<4xf32>
func.func @vector_store_2d(%arg0 : memref<4x4xf32, #spirv.storage_class<StorageBuffer>>, %arg1 : vector<4xf32>) {
More information about the Mlir-commits
mailing list