[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:
George Mitenkov 2020-08-12 09:10:39 +03:00
parent 01b99c6e1d
commit 2ad7e1a301
2 changed files with 87 additions and 2 deletions

View File

@ -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>,

View File

@ -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
//===----------------------------------------------------------------------===//