forked from OSchip/llvm-project
[MLIR][SPIRVToLLVM] Conversion for global and addressof
Inital conversion of `spv._address_of` and `spv.globalVariable`. In SPIR-V, the global returns a pointer, whereas in LLVM dialect the global holds an actual value. This difference is handled by `spv._address_of` and `llvm.mlir.addressof`ops that both return a pointer. Moreover, only current invocation is in conversion's scope. Reviewed By: antiagainst, mravishankar Differential Revision: https://reviews.llvm.org/D84626
This commit is contained in:
parent
01b99c6e1d
commit
2ad7e1a301
|
@ -273,6 +273,22 @@ static Optional<Type> convertStructType(spirv::StructType type,
|
|||
|
||||
namespace {
|
||||
|
||||
class AddressOfPattern : public SPIRVToLLVMConversion<spirv::AddressOfOp> {
|
||||
public:
|
||||
using SPIRVToLLVMConversion<spirv::AddressOfOp>::SPIRVToLLVMConversion;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(spirv::AddressOfOp op, ArrayRef<Value> operands,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
auto dstType = typeConverter.convertType(op.pointer().getType());
|
||||
if (!dstType)
|
||||
return failure();
|
||||
rewriter.replaceOpWithNewOp<LLVM::AddressOfOp>(
|
||||
op, dstType.cast<LLVM::LLVMType>(), op.variable());
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
class BitFieldInsertPattern
|
||||
: public SPIRVToLLVMConversion<spirv::BitFieldInsertOp> {
|
||||
public:
|
||||
|
@ -507,6 +523,55 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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 difference is handled by `spv._address_of` and `llvm.mlir.addressof`ops
|
||||
/// that both return a pointer.
|
||||
class GlobalVariablePattern
|
||||
: public SPIRVToLLVMConversion<spirv::GlobalVariableOp> {
|
||||
public:
|
||||
using SPIRVToLLVMConversion<spirv::GlobalVariableOp>::SPIRVToLLVMConversion;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(spirv::GlobalVariableOp op, ArrayRef<Value> operands,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
// Currently, there is no support of initialization with a constant value in
|
||||
// SPIR-V dialect. Specialization constants are not considered as well.
|
||||
if (op.initializer())
|
||||
return failure();
|
||||
|
||||
auto srcType = op.type().cast<spirv::PointerType>();
|
||||
auto dstType = typeConverter.convertType(srcType.getPointeeType());
|
||||
if (!dstType)
|
||||
return failure();
|
||||
|
||||
// Limit conversion to the current invocation only for now.
|
||||
auto storageClass = srcType.getStorageClass();
|
||||
if (storageClass != spirv::StorageClass::Input &&
|
||||
storageClass != spirv::StorageClass::Private &&
|
||||
storageClass != spirv::StorageClass::Output) {
|
||||
return failure();
|
||||
}
|
||||
|
||||
// LLVM dialect spec: "If the global value is a constant, storing into it is
|
||||
// not allowed.". This corresponds to SPIR-V 'Input' storage class that is
|
||||
// read-only.
|
||||
bool isConstant = storageClass == spirv::StorageClass::Input;
|
||||
// SPIR-V spec: "By default, functions and global variables are private to a
|
||||
// module and cannot be accessed by other modules. However, a module may be
|
||||
// written to export or import functions and global (module scope)
|
||||
// variables.". Therefore, map 'Private' storage class to private linkage,
|
||||
// 'Input' and 'Output' to external linkage.
|
||||
auto linkage = storageClass == spirv::StorageClass::Private
|
||||
? LLVM::Linkage::Private
|
||||
: LLVM::Linkage::External;
|
||||
rewriter.replaceOpWithNewOp<LLVM::GlobalOp>(
|
||||
op, dstType.cast<LLVM::LLVMType>(), isConstant, linkage, op.sym_name(),
|
||||
Attribute());
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
/// Converts SPIR-V cast ops that do not have straightforward LLVM
|
||||
/// equivalent in LLVM dialect.
|
||||
template <typename SPIRVOp, typename LLVMExtOp, typename LLVMTruncOp>
|
||||
|
@ -1230,8 +1295,8 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
|
|||
NotPattern<spirv::LogicalNotOp>,
|
||||
|
||||
// Memory ops
|
||||
LoadStorePattern<spirv::LoadOp>, LoadStorePattern<spirv::StoreOp>,
|
||||
VariablePattern,
|
||||
AddressOfPattern, GlobalVariablePattern, LoadStorePattern<spirv::LoadOp>,
|
||||
LoadStorePattern<spirv::StoreOp>, VariablePattern,
|
||||
|
||||
// Miscellaneous ops
|
||||
DirectConversionPattern<spirv::SelectOp, LLVM::SelectOp>,
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
// RUN: mlir-opt -convert-spirv-to-llvm %s | FileCheck %s
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.globalVariable and spv._address_of
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
// CHECK: llvm.mlir.global external constant @var() : !llvm.float
|
||||
spv.globalVariable @var : !spv.ptr<f32, Input>
|
||||
}
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
// CHECK: llvm.mlir.global private @struct() : !llvm.struct<packed (float, array<10 x float>)>
|
||||
// CHECK-LABEL: @func
|
||||
// CHECK: llvm.mlir.addressof @struct : !llvm.ptr<struct<packed (float, array<10 x float>)>>
|
||||
spv.globalVariable @struct : !spv.ptr<!spv.struct<f32, !spv.array<10xf32>>, Private>
|
||||
spv.func @func() -> () "None" {
|
||||
%0 = spv._address_of @struct : !spv.ptr<!spv.struct<f32, !spv.array<10xf32>>, Private>
|
||||
spv.Return
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.Load
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
Loading…
Reference in New Issue