[Mlir-commits] [mlir] de3ad5b - [MLIR][SPIRVToLLVM] Enhanced conversion for execution mode
George Mitenkov
llvmlistbot at llvm.org
Tue Nov 10 07:34:30 PST 2020
Author: George Mitenkov
Date: 2020-11-10T18:33:54+03:00
New Revision: de3ad5bb09032995941e6aab005e43a6d498b7c5
URL: https://github.com/llvm/llvm-project/commit/de3ad5bb09032995941e6aab005e43a6d498b7c5
DIFF: https://github.com/llvm/llvm-project/commit/de3ad5bb09032995941e6aab005e43a6d498b7c5.diff
LOG: [MLIR][SPIRVToLLVM] Enhanced conversion for execution mode
This patch introduces a new conversion pattern for `spv.ExecutionMode`.
`spv.ExecutionMode` may contain important information about the entry
point, which we want to preserve. For example, `LocalSize` provides
information about the work-group size that can be reused. Hence, the
pattern for entry-point ops changes to the following:
- `spv.EntryPoint` is still simply removed
- Info from `spv.ExecutionMode` is used to create a global struct variable,
which looks like:
```
struct {
int32_t executionMode;
int32_t values[]; // optional values
};
```
Reviewed By: mravishankar
Differential Revision: https://reviews.llvm.org/D89989
Added:
Modified:
mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
mlir/test/Conversion/SPIRVToLLVM/misc-ops-to-llvm.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
index 571e85c70dcd..f27bd640d67c 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
@@ -634,6 +634,82 @@ class DirectConversionPattern : public SPIRVToLLVMConversion<SPIRVOp> {
}
};
+/// Converts `spv.ExecutionMode` into a global struct constant that holds
+/// execution mode information.
+class ExecutionModePattern
+ : public SPIRVToLLVMConversion<spirv::ExecutionModeOp> {
+public:
+ using SPIRVToLLVMConversion<spirv::ExecutionModeOp>::SPIRVToLLVMConversion;
+
+ LogicalResult
+ matchAndRewrite(spirv::ExecutionModeOp op, ArrayRef<Value> operands,
+ ConversionPatternRewriter &rewriter) const override {
+ // First, create the global struct's name that would be associated with
+ // this entry point's execution mode. We set it to be:
+ // __spv__{SPIR-V module name}_{function name}_execution_mode_info
+ ModuleOp module = op.getParentOfType<ModuleOp>();
+ std::string moduleName;
+ if (module.getName().hasValue())
+ moduleName = "_" + module.getName().getValue().str();
+ else
+ moduleName = "";
+ std::string executionModeInfoName = llvm::formatv(
+ "__spv_{0}_{1}_execution_mode_info", moduleName, op.fn().str());
+
+ MLIRContext *context = rewriter.getContext();
+ OpBuilder::InsertionGuard guard(rewriter);
+ rewriter.setInsertionPointToStart(module.getBody());
+
+ // Create a struct type, corresponding to the C struct below.
+ // struct {
+ // int32_t executionMode;
+ // int32_t values[]; // optional values
+ // };
+ auto llvmI32Type = LLVM::LLVMType::getInt32Ty(context);
+ SmallVector<LLVM::LLVMType, 2> fields;
+ fields.push_back(llvmI32Type);
+ ArrayAttr values = op.values();
+ if (!values.empty()) {
+ auto arrayType = LLVM::LLVMType::getArrayTy(llvmI32Type, values.size());
+ fields.push_back(arrayType);
+ }
+ auto structType = LLVM::LLVMType::getStructTy(context, fields);
+
+ // Create `llvm.mlir.global` with initializer region containing one block.
+ auto global = rewriter.create<LLVM::GlobalOp>(
+ UnknownLoc::get(context), structType, /*isConstant=*/true,
+ LLVM::Linkage::External, executionModeInfoName, Attribute());
+ Location loc = global.getLoc();
+ Region ®ion = global.getInitializerRegion();
+ Block *block = rewriter.createBlock(®ion);
+
+ // Initialize the struct and set the execution mode value.
+ rewriter.setInsertionPoint(block, block->begin());
+ Value structValue = rewriter.create<LLVM::UndefOp>(loc, structType);
+ IntegerAttr executionModeAttr = op.execution_modeAttr();
+ Value executionMode =
+ rewriter.create<LLVM::ConstantOp>(loc, llvmI32Type, executionModeAttr);
+ structValue = rewriter.create<LLVM::InsertValueOp>(
+ loc, structType, structValue, executionMode,
+ ArrayAttr::get({rewriter.getIntegerAttr(rewriter.getI32Type(), 0)},
+ context));
+
+ // Insert extra operands if they exist into execution mode info struct.
+ for (unsigned i = 0, e = values.size(); i < e; ++i) {
+ auto attr = values.getValue()[i];
+ Value entry = rewriter.create<LLVM::ConstantOp>(loc, llvmI32Type, attr);
+ structValue = rewriter.create<LLVM::InsertValueOp>(
+ loc, structType, structValue, entry,
+ ArrayAttr::get({rewriter.getIntegerAttr(rewriter.getI32Type(), 1),
+ rewriter.getIntegerAttr(rewriter.getI32Type(), i)},
+ context));
+ }
+ rewriter.create<LLVM::ReturnOp>(loc, ArrayRef<Value>({structValue}));
+ rewriter.eraseOp(op);
+ return success();
+ }
+};
+
/// Converts `spv.globalVariable` to `llvm.mlir.global`. Note that SPIR-V global
/// returns a pointer, whereas in LLVM dialect the global holds an actual value.
/// This
diff erence is handled by `spv._address_of` and `llvm.mlir.addressof`ops
@@ -1386,12 +1462,8 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
FunctionCallPattern, LoopPattern, SelectionPattern,
ErasePattern<spirv::MergeOp>,
- // Entry points and execution mode
- // Module generated from SPIR-V could have other "internal" functions, so
- // having entry point and execution mode metadata can be useful. For now,
- // simply remove them.
- // TODO: Support EntryPoint/ExecutionMode properly.
- ErasePattern<spirv::EntryPointOp>, ErasePattern<spirv::ExecutionModeOp>,
+ // Entry points and execution mode are handled separately.
+ ErasePattern<spirv::EntryPointOp>, ExecutionModePattern,
// GLSL extended instruction set ops
DirectConversionPattern<spirv::GLSLCeilOp, LLVM::FCeilOp>,
diff --git a/mlir/test/Conversion/SPIRVToLLVM/misc-ops-to-llvm.mlir b/mlir/test/Conversion/SPIRVToLLVM/misc-ops-to-llvm.mlir
index 3c86a9f34ada..32841d1846b7 100644
--- a/mlir/test/Conversion/SPIRVToLLVM/misc-ops-to-llvm.mlir
+++ b/mlir/test/Conversion/SPIRVToLLVM/misc-ops-to-llvm.mlir
@@ -63,16 +63,47 @@ spv.func @select_vector(%arg0: vector<2xi1>, %arg1: vector<2xi32>) "None" {
//===----------------------------------------------------------------------===//
// CHECK: module {
+// CHECK-NEXT: llvm.mlir.global external constant @{{.*}}() : !llvm.struct<(i32)> {
+// CHECK-NEXT: %[[UNDEF:.*]] = llvm.mlir.undef : !llvm.struct<(i32)>
+// CHECK-NEXT: %[[VAL:.*]] = llvm.mlir.constant(31 : i32) : !llvm.i32
+// CHECK-NEXT: %[[RET:.*]] = llvm.insertvalue %[[VAL]], %[[UNDEF]][0 : i32] : !llvm.struct<(i32)>
+// CHECK-NEXT: llvm.return %[[RET]] : !llvm.struct<(i32)>
+// CHECK-NEXT: }
// CHECK-NEXT: llvm.func @empty
// CHECK-NEXT: llvm.return
// CHECK-NEXT: }
// CHECK-NEXT: }
-spv.module Logical GLSL450 {
+spv.module Logical OpenCL {
spv.func @empty() "None" {
spv.Return
}
- spv.EntryPoint "GLCompute" @empty
- spv.ExecutionMode @empty "LocalSize", 1, 1, 1
+ spv.EntryPoint "Kernel" @empty
+ spv.ExecutionMode @empty "ContractionOff"
+}
+
+// CHECK: module {
+// CHECK-NEXT: llvm.mlir.global external constant @{{.*}}() : !llvm.struct<(i32, array<3 x i32>)> {
+// CHECK-NEXT: %[[UNDEF:.*]] = llvm.mlir.undef : !llvm.struct<(i32, array<3 x i32>)>
+// CHECK-NEXT: %[[EM:.*]] = llvm.mlir.constant(18 : i32) : !llvm.i32
+// CHECK-NEXT: %[[T0:.*]] = llvm.insertvalue %[[EM]], %[[UNDEF]][0 : i32] : !llvm.struct<(i32, array<3 x i32>)>
+// CHECK-NEXT: %[[C0:.*]] = llvm.mlir.constant(32 : i32) : !llvm.i32
+// CHECK-NEXT: %[[T1:.*]] = llvm.insertvalue %[[C0]], %[[T0]][1 : i32, 0 : i32] : !llvm.struct<(i32, array<3 x i32>)>
+// CHECK-NEXT: %[[C1:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
+// CHECK-NEXT: %[[T2:.*]] = llvm.insertvalue %[[C1]], %[[T1]][1 : i32, 1 : i32] : !llvm.struct<(i32, array<3 x i32>)>
+// CHECK-NEXT: %[[C2:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
+// CHECK-NEXT: %[[RET:.*]] = llvm.insertvalue %[[C2]], %[[T2]][1 : i32, 2 : i32] : !llvm.struct<(i32, array<3 x i32>)>
+// CHECK-NEXT: llvm.return %[[RET]] : !llvm.struct<(i32, array<3 x i32>)>
+// CHECK-NEXT: }
+// CHECK-NEXT: llvm.func @bar
+// CHECK-NEXT: llvm.return
+// CHECK-NEXT: }
+// CHECK-NEXT: }
+spv.module Logical OpenCL {
+ spv.func @bar() "None" {
+ spv.Return
+ }
+ spv.EntryPoint "Kernel" @bar
+ spv.ExecutionMode @bar "LocalSizeHint", 32, 1, 1
}
//===----------------------------------------------------------------------===//
More information about the Mlir-commits
mailing list