[Mlir-commits] [mlir] f646f73 - [mlir][spirv] Add InBoundsAccessChain op (#216682)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Aug 17 11:20:35 PDT 2026
Author: Hsiangkai Wang
Date: 2026-08-17T19:20:30+01:00
New Revision: f646f7395fe1fbb05d78a42871cb72bc31e4d7f9
URL: https://github.com/llvm/llvm-project/commit/f646f7395fe1fbb05d78a42871cb72bc31e4d7f9
DIFF: https://github.com/llvm/llvm-project/commit/f646f7395fe1fbb05d78a42871cb72bc31e4d7f9.diff
LOG: [mlir][spirv] Add InBoundsAccessChain op (#216682)
Add the SPIR-V opcode, ODS definition, verifier hook, and
canonicalization support for spirv.InBoundsAccessChain.
Added:
Modified:
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td
mlir/lib/Dialect/SPIRV/IR/MemoryOps.cpp
mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.cpp
mlir/test/Dialect/SPIRV/IR/memory-ops.mlir
mlir/test/Dialect/SPIRV/Transforms/canonicalize.mlir
mlir/test/Target/SPIRV/memory-ops.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td
index 527e6082c5fcd..92653117a451a 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVBase.td
@@ -4493,6 +4493,7 @@ def SPIRV_OC_OpLoad : I32EnumAttrCase<"OpLoad", 61>;
def SPIRV_OC_OpStore : I32EnumAttrCase<"OpStore", 62>;
def SPIRV_OC_OpCopyMemory : I32EnumAttrCase<"OpCopyMemory", 63>;
def SPIRV_OC_OpAccessChain : I32EnumAttrCase<"OpAccessChain", 65>;
+def SPIRV_OC_OpInBoundsAccessChain : I32EnumAttrCase<"OpInBoundsAccessChain", 66>;
def SPIRV_OC_OpPtrAccessChain : I32EnumAttrCase<"OpPtrAccessChain", 67>;
def SPIRV_OC_OpInBoundsPtrAccessChain : I32EnumAttrCase<"OpInBoundsPtrAccessChain", 70>;
def SPIRV_OC_OpDecorate : I32EnumAttrCase<"OpDecorate", 71>;
@@ -4744,7 +4745,7 @@ def SPIRV_OpcodeAttr :
SPIRV_OC_OpSpecConstantOp, SPIRV_OC_OpFunction, SPIRV_OC_OpFunctionParameter,
SPIRV_OC_OpFunctionEnd, SPIRV_OC_OpFunctionCall, SPIRV_OC_OpVariable,
SPIRV_OC_OpLoad, SPIRV_OC_OpStore, SPIRV_OC_OpCopyMemory,
- SPIRV_OC_OpAccessChain, SPIRV_OC_OpPtrAccessChain,
+ SPIRV_OC_OpAccessChain, SPIRV_OC_OpInBoundsAccessChain, SPIRV_OC_OpPtrAccessChain,
SPIRV_OC_OpInBoundsPtrAccessChain, SPIRV_OC_OpDecorate,
SPIRV_OC_OpMemberDecorate, SPIRV_OC_OpVectorExtractDynamic,
SPIRV_OC_OpVectorInsertDynamic, SPIRV_OC_OpVectorShuffle,
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td
index e13909e8eeeae..5ae6c8af83003 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVMemoryOps.td
@@ -81,6 +81,40 @@ def SPIRV_AccessChainOp : SPIRV_Op<"AccessChain", [Pure]> {
// -----
+def SPIRV_InBoundsAccessChainOp : SPIRV_Op<"InBoundsAccessChain", [Pure]> {
+ let summary = [{
+ Create a pointer into a composite object that is known to stay within the
+ base object.
+ }];
+
+ let description = [{
+ Has the same operands, result, and type rules as `spirv.AccessChain`, with
+ the additional contract that the resulting pointer points within the base
+ object.
+ }];
+
+ let arguments = (ins
+ SPIRV_AnyPtr:$base_ptr,
+ Variadic<SPIRV_Integer>:$indices
+ );
+
+ let results = (outs
+ SPIRV_AnyPtr:$component_ptr
+ );
+
+ let builders = [OpBuilder<(ins "Value":$basePtr, "ValueRange":$indices)>];
+
+ let hasCanonicalizer = 1;
+
+ let hasCustomAssemblyFormat = 0;
+
+ let assemblyFormat = [{
+ $base_ptr `[` $indices `]` attr-dict `:` type($base_ptr) `,` type($indices) `->` type(results)
+ }];
+}
+
+// -----
+
def SPIRV_CopyMemoryOp : SPIRV_Op<"CopyMemory", [DeclareOpInterfaceMethods<AlignmentAttrOpInterface>]> {
let summary = [{
Copy from the memory pointed to by Source to the memory pointed to by
diff --git a/mlir/lib/Dialect/SPIRV/IR/MemoryOps.cpp b/mlir/lib/Dialect/SPIRV/IR/MemoryOps.cpp
index f9c03bf3b88c0..602ba932f8838 100644
--- a/mlir/lib/Dialect/SPIRV/IR/MemoryOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/MemoryOps.cpp
@@ -351,6 +351,21 @@ LogicalResult AccessChainOp::verify() {
return verifyAccessChain(*this, getIndices());
}
+//===----------------------------------------------------------------------===//
+// spirv.InBoundsAccessChainOp
+//===----------------------------------------------------------------------===//
+
+void InBoundsAccessChainOp::build(OpBuilder &builder, OperationState &state,
+ Value basePtr, ValueRange indices) {
+ Type type = getElementPtrType(basePtr.getType(), indices, state.location);
+ assert(type && "Unable to deduce return type based on basePtr and indices");
+ build(builder, state, type, basePtr, indices);
+}
+
+LogicalResult InBoundsAccessChainOp::verify() {
+ return verifyAccessChain(*this, getIndices());
+}
+
//===----------------------------------------------------------------------===//
// spirv.LoadOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.cpp
index 2d5c4d7d3fd0e..acc38dffe4a2b 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVCanonicalization.cpp
@@ -84,21 +84,20 @@ namespace {
} // namespace
//===----------------------------------------------------------------------===//
-// spirv.AccessChainOp
+// spirv.AccessChainOp / spirv.InBoundsAccessChainOp
//===----------------------------------------------------------------------===//
namespace {
-/// Combines chained `spirv::AccessChainOp` operations into one
-/// `spirv::AccessChainOp` operation.
-struct CombineChainedAccessChain final
- : OpRewritePattern<spirv::AccessChainOp> {
- using Base::Base;
+/// Combines chained SPIR-V access chain operations of the same kind into one.
+template <typename AccessChainOp>
+struct CombineChainedAccessChain final : OpRewritePattern<AccessChainOp> {
+ using OpRewritePattern<AccessChainOp>::OpRewritePattern;
- LogicalResult matchAndRewrite(spirv::AccessChainOp accessChainOp,
+ LogicalResult matchAndRewrite(AccessChainOp accessChainOp,
PatternRewriter &rewriter) const override {
auto parentAccessChainOp =
- accessChainOp.getBasePtr().getDefiningOp<spirv::AccessChainOp>();
+ accessChainOp.getBasePtr().template getDefiningOp<AccessChainOp>();
if (!parentAccessChainOp) {
return failure();
@@ -108,7 +107,7 @@ struct CombineChainedAccessChain final
SmallVector<Value, 4> indices(parentAccessChainOp.getIndices());
llvm::append_range(indices, accessChainOp.getIndices());
- rewriter.replaceOpWithNewOp<spirv::AccessChainOp>(
+ rewriter.replaceOpWithNewOp<AccessChainOp>(
accessChainOp, parentAccessChainOp.getBasePtr(), indices);
return success();
@@ -118,7 +117,12 @@ struct CombineChainedAccessChain final
void spirv::AccessChainOp::getCanonicalizationPatterns(
RewritePatternSet &results, MLIRContext *context) {
- results.add<CombineChainedAccessChain>(context);
+ results.add<CombineChainedAccessChain<spirv::AccessChainOp>>(context);
+}
+
+void spirv::InBoundsAccessChainOp::getCanonicalizationPatterns(
+ RewritePatternSet &results, MLIRContext *context) {
+ results.add<CombineChainedAccessChain<spirv::InBoundsAccessChainOp>>(context);
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir b/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir
index a3b96c698a344..c58f22cea5a4b 100644
--- a/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/memory-ops.mlir
@@ -35,6 +35,17 @@ func.func @access_chain_2D_array_2(%arg0 : i32) -> () {
return
}
+//===----------------------------------------------------------------------===//
+// spirv.InBoundsAccessChain
+//===----------------------------------------------------------------------===//
+
+func.func @inbounds_access_chain(%arg0 : i32) -> () {
+ %0 = spirv.Variable : !spirv.ptr<!spirv.array<4xf32>, Function>
+ // CHECK: spirv.InBoundsAccessChain {{.*}}[{{.*}}] : !spirv.ptr<!spirv.array<4 x f32>, Function>
+ %1 = spirv.InBoundsAccessChain %0[%arg0] : !spirv.ptr<!spirv.array<4xf32>, Function>, i32 -> !spirv.ptr<f32, Function>
+ return
+}
+
func.func @access_chain_rtarray(%arg0 : i32) -> () {
%0 = spirv.Variable : !spirv.ptr<!spirv.rtarray<f32>, Function>
// CHECK: spirv.AccessChain {{.*}}[{{.*}}] : !spirv.ptr<!spirv.rtarray<f32>, Function>
diff --git a/mlir/test/Dialect/SPIRV/Transforms/canonicalize.mlir b/mlir/test/Dialect/SPIRV/Transforms/canonicalize.mlir
index 94d9c53db0bbc..e80145419f8a8 100644
--- a/mlir/test/Dialect/SPIRV/Transforms/canonicalize.mlir
+++ b/mlir/test/Dialect/SPIRV/Transforms/canonicalize.mlir
@@ -19,6 +19,25 @@ func.func @combine_full_access_chain() -> f32 {
// -----
+//===----------------------------------------------------------------------===//
+// spirv.InBoundsAccessChain
+//===----------------------------------------------------------------------===//
+
+func.func @combine_full_inbounds_access_chain() -> f32 {
+ // CHECK: %[[INDEX:.*]] = spirv.Constant 0
+ // CHECK-NEXT: %[[VAR:.*]] = spirv.Variable
+ // CHECK-NEXT: %[[PTR:.*]] = spirv.InBoundsAccessChain %[[VAR]][%[[INDEX]], %[[INDEX]], %[[INDEX]]]
+ // CHECK-NEXT: spirv.Load "Function" %[[PTR]]
+ %c0 = spirv.Constant 0: i32
+ %0 = spirv.Variable : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>
+ %1 = spirv.InBoundsAccessChain %0[%c0] : !spirv.ptr<!spirv.struct<(!spirv.array<4x!spirv.array<4xf32>>, !spirv.array<4xi32>)>, Function>, i32 -> !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>
+ %2 = spirv.InBoundsAccessChain %1[%c0, %c0] : !spirv.ptr<!spirv.array<4x!spirv.array<4xf32>>, Function>, i32, i32 -> !spirv.ptr<f32, Function>
+ %3 = spirv.Load "Function" %2 : f32
+ spirv.ReturnValue %3 : f32
+}
+
+// -----
+
func.func @combine_access_chain_multi_use() -> !spirv.array<4xf32> {
// CHECK: %[[INDEX:.*]] = spirv.Constant 0
// CHECK-NEXT: %[[VAR:.*]] = spirv.Variable
diff --git a/mlir/test/Target/SPIRV/memory-ops.mlir b/mlir/test/Target/SPIRV/memory-ops.mlir
index 2d18394818611..fa786f18aac18 100644
--- a/mlir/test/Target/SPIRV/memory-ops.mlir
+++ b/mlir/test/Target/SPIRV/memory-ops.mlir
@@ -40,6 +40,17 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
// -----
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
+ spirv.func @inbounds_access_chain(%arg0 : !spirv.ptr<!spirv.array<4xf32>, Function>, %arg1 : i32) "None" {
+ // CHECK: {{%.*}} = spirv.InBoundsAccessChain {{%.*}}[{{%.*}}] : !spirv.ptr<!spirv.array<4 x f32>, Function>
+ %0 = spirv.InBoundsAccessChain %arg0[%arg1] : !spirv.ptr<!spirv.array<4xf32>, Function>, i32 -> !spirv.ptr<f32, Function>
+ %1 = spirv.Load "Function" %0 : f32
+ spirv.Return
+ }
+}
+
+// -----
+
spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], [SPV_KHR_storage_buffer_storage_class]> {
spirv.func @load_store_zero_rank_float(%arg0: !spirv.ptr<!spirv.struct<(!spirv.array<1 x f32, stride=4> [0]), Block>, StorageBuffer>, %arg1: !spirv.ptr<!spirv.struct<(!spirv.array<1 x f32, stride=4> [0]), Block>, StorageBuffer>) "None" {
// CHECK: [[LOAD_PTR:%.*]] = spirv.AccessChain {{%.*}}[{{%.*}}, {{%.*}}] : !spirv.ptr<!spirv.struct<(!spirv.array<1 x f32, stride=4> [0]), Block>, StorageBuffer>
@@ -122,4 +133,3 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.4, [Shader, Linkage], []> {
spirv.Return
}
}
-
More information about the Mlir-commits
mailing list