[MLIR][SPIRVToLLVM] Conversion of SPIR-V variable op
The patch introduces the conversion pattern for function-level `spv.Variable`. It is modelled as `llvm.alloca` op. If initialized, then additional store instruction is used. Note that there is no initialization for arrays and structs since constants of these types are not supported in LLVM dialect yet. Also, at the moment initialisation is only possible via `spv.constant` (since `spv.GlobalVariable` conversion is not implemented yet). The input code has some scoping is not taken into account and will be addressed in a different patch. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D84224
This commit is contained in:
parent
0bbaacc8ca
commit
5c98631391
|
@ -177,6 +177,14 @@ static Type convertStructTypePacked(spirv::StructType type,
|
|||
/*isPacked=*/true);
|
||||
}
|
||||
|
||||
/// Creates LLVM dialect constant with the given value.
|
||||
static Value createI32ConstantOf(Location loc, PatternRewriter &rewriter,
|
||||
LLVMTypeConverter &converter, unsigned value) {
|
||||
return rewriter.create<LLVM::ConstantOp>(
|
||||
loc, LLVM::LLVMType::getInt32Ty(converter.getDialect()),
|
||||
rewriter.getIntegerAttr(rewriter.getI32Type(), value));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Type conversion
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -733,6 +741,37 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class VariablePattern : public SPIRVToLLVMConversion<spirv::VariableOp> {
|
||||
public:
|
||||
using SPIRVToLLVMConversion<spirv::VariableOp>::SPIRVToLLVMConversion;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(spirv::VariableOp varOp, ArrayRef<Value> operands,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
auto srcType = varOp.getType();
|
||||
// Initialization is supported for scalars and vectors only.
|
||||
auto pointerTo = srcType.cast<spirv::PointerType>().getPointeeType();
|
||||
auto init = varOp.initializer();
|
||||
if (init && !pointerTo.isIntOrFloat() && !pointerTo.isa<VectorType>())
|
||||
return failure();
|
||||
|
||||
auto dstType = typeConverter.convertType(srcType);
|
||||
if (!dstType)
|
||||
return failure();
|
||||
|
||||
Location loc = varOp.getLoc();
|
||||
Value size = createI32ConstantOf(loc, rewriter, typeConverter, 1);
|
||||
if (!init) {
|
||||
rewriter.replaceOpWithNewOp<LLVM::AllocaOp>(varOp, dstType, size);
|
||||
return success();
|
||||
}
|
||||
Value allocated = rewriter.create<LLVM::AllocaOp>(loc, dstType, size);
|
||||
rewriter.create<LLVM::StoreOp>(loc, init, allocated);
|
||||
rewriter.replaceOp(varOp, allocated);
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FuncOp conversion
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -933,6 +972,9 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
|
|||
IComparePattern<spirv::LogicalNotEqualOp, LLVM::ICmpPredicate::ne>,
|
||||
NotPattern<spirv::LogicalNotOp>,
|
||||
|
||||
// Memory ops
|
||||
VariablePattern,
|
||||
|
||||
// Miscellaneous ops
|
||||
DirectConversionPattern<spirv::SelectOp, LLVM::SelectOp>,
|
||||
DirectConversionPattern<spirv::UndefOp, LLVM::UndefOp>,
|
||||
|
|
49
mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir
Normal file
49
mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir
Normal file
|
@ -0,0 +1,49 @@
|
|||
// RUN: mlir-opt -convert-spirv-to-llvm %s | FileCheck %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.Variable
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func @variable_scalar() {
|
||||
// CHECK: %[[SIZE1:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
|
||||
// CHECK: %{{.*}} = llvm.alloca %[[SIZE1]] x !llvm.float : (!llvm.i32) -> !llvm<"float*">
|
||||
%0 = spv.Variable : !spv.ptr<f32, Function>
|
||||
// CHECK: %[[SIZE2:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
|
||||
// CHECK: %{{.*}} = llvm.alloca %[[SIZE2]] x !llvm.i8 : (!llvm.i32) -> !llvm<"i8*">
|
||||
%1 = spv.Variable : !spv.ptr<i8, Function>
|
||||
return
|
||||
}
|
||||
|
||||
func @variable_scalar_with_initialization() {
|
||||
// CHECK: %[[VALUE:.*]] = llvm.mlir.constant(0 : i64) : !llvm.i64
|
||||
// CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
|
||||
// CHECK: %[[ALLOCATED:.*]] = llvm.alloca %[[SIZE]] x !llvm.i64 : (!llvm.i32) -> !llvm<"i64*">
|
||||
// CHECK: llvm.store %[[VALUE]], %[[ALLOCATED]] : !llvm<"i64*">
|
||||
%c = spv.constant 0 : i64
|
||||
%0 = spv.Variable init(%c) : !spv.ptr<i64, Function>
|
||||
return
|
||||
}
|
||||
|
||||
func @variable_vector() {
|
||||
// CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
|
||||
// CHECK: %{{.*}} = llvm.alloca %[[SIZE]] x !llvm<"<3 x float>"> : (!llvm.i32) -> !llvm<"<3 x float>*">
|
||||
%0 = spv.Variable : !spv.ptr<vector<3xf32>, Function>
|
||||
return
|
||||
}
|
||||
|
||||
func @variable_vector_with_initialization() {
|
||||
// CHECK: %[[VALUE:.*]] = llvm.mlir.constant(dense<false> : vector<3xi1>) : !llvm<"<3 x i1>">
|
||||
// CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
|
||||
// CHECK: %[[ALLOCATED:.*]] = llvm.alloca %[[SIZE]] x !llvm<"<3 x i1>"> : (!llvm.i32) -> !llvm<"<3 x i1>*">
|
||||
// CHECK: llvm.store %[[VALUE]], %[[ALLOCATED]] : !llvm<"<3 x i1>*">
|
||||
%c = spv.constant dense<false> : vector<3xi1>
|
||||
%0 = spv.Variable init(%c) : !spv.ptr<vector<3xi1>, Function>
|
||||
return
|
||||
}
|
||||
|
||||
func @variable_array() {
|
||||
// CHECK: %[[SIZE:.*]] = llvm.mlir.constant(1 : i32) : !llvm.i32
|
||||
// CHECK: %{{.*}} = llvm.alloca %[[SIZE]] x !llvm<"[10 x i32]"> : (!llvm.i32) -> !llvm<"[10 x i32]*">
|
||||
%0 = spv.Variable : !spv.ptr<!spv.array<10 x i32>, Function>
|
||||
return
|
||||
}
|
Loading…
Reference in a new issue