Skip to content

Commit 2ad7e1a

Browse files
[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
1 parent 01b99c6 commit 2ad7e1a

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,22 @@ static Optional<Type> convertStructType(spirv::StructType type,
273273

274274
namespace {
275275

276+
class AddressOfPattern : public SPIRVToLLVMConversion<spirv::AddressOfOp> {
277+
public:
278+
using SPIRVToLLVMConversion<spirv::AddressOfOp>::SPIRVToLLVMConversion;
279+
280+
LogicalResult
281+
matchAndRewrite(spirv::AddressOfOp op, ArrayRef<Value> operands,
282+
ConversionPatternRewriter &rewriter) const override {
283+
auto dstType = typeConverter.convertType(op.pointer().getType());
284+
if (!dstType)
285+
return failure();
286+
rewriter.replaceOpWithNewOp<LLVM::AddressOfOp>(
287+
op, dstType.cast<LLVM::LLVMType>(), op.variable());
288+
return success();
289+
}
290+
};
291+
276292
class BitFieldInsertPattern
277293
: public SPIRVToLLVMConversion<spirv::BitFieldInsertOp> {
278294
public:
@@ -507,6 +523,55 @@ class DirectConversionPattern : public SPIRVToLLVMConversion<SPIRVOp> {
507523
}
508524
};
509525

526+
/// Converts `spv.globalVariable` to `llvm.mlir.global`. Note that SPIR-V global
527+
/// returns a pointer, whereas in LLVM dialect the global holds an actual value.
528+
/// This difference is handled by `spv._address_of` and `llvm.mlir.addressof`ops
529+
/// that both return a pointer.
530+
class GlobalVariablePattern
531+
: public SPIRVToLLVMConversion<spirv::GlobalVariableOp> {
532+
public:
533+
using SPIRVToLLVMConversion<spirv::GlobalVariableOp>::SPIRVToLLVMConversion;
534+
535+
LogicalResult
536+
matchAndRewrite(spirv::GlobalVariableOp op, ArrayRef<Value> operands,
537+
ConversionPatternRewriter &rewriter) const override {
538+
// Currently, there is no support of initialization with a constant value in
539+
// SPIR-V dialect. Specialization constants are not considered as well.
540+
if (op.initializer())
541+
return failure();
542+
543+
auto srcType = op.type().cast<spirv::PointerType>();
544+
auto dstType = typeConverter.convertType(srcType.getPointeeType());
545+
if (!dstType)
546+
return failure();
547+
548+
// Limit conversion to the current invocation only for now.
549+
auto storageClass = srcType.getStorageClass();
550+
if (storageClass != spirv::StorageClass::Input &&
551+
storageClass != spirv::StorageClass::Private &&
552+
storageClass != spirv::StorageClass::Output) {
553+
return failure();
554+
}
555+
556+
// LLVM dialect spec: "If the global value is a constant, storing into it is
557+
// not allowed.". This corresponds to SPIR-V 'Input' storage class that is
558+
// read-only.
559+
bool isConstant = storageClass == spirv::StorageClass::Input;
560+
// SPIR-V spec: "By default, functions and global variables are private to a
561+
// module and cannot be accessed by other modules. However, a module may be
562+
// written to export or import functions and global (module scope)
563+
// variables.". Therefore, map 'Private' storage class to private linkage,
564+
// 'Input' and 'Output' to external linkage.
565+
auto linkage = storageClass == spirv::StorageClass::Private
566+
? LLVM::Linkage::Private
567+
: LLVM::Linkage::External;
568+
rewriter.replaceOpWithNewOp<LLVM::GlobalOp>(
569+
op, dstType.cast<LLVM::LLVMType>(), isConstant, linkage, op.sym_name(),
570+
Attribute());
571+
return success();
572+
}
573+
};
574+
510575
/// Converts SPIR-V cast ops that do not have straightforward LLVM
511576
/// equivalent in LLVM dialect.
512577
template <typename SPIRVOp, typename LLVMExtOp, typename LLVMTruncOp>
@@ -1230,8 +1295,8 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
12301295
NotPattern<spirv::LogicalNotOp>,
12311296

12321297
// Memory ops
1233-
LoadStorePattern<spirv::LoadOp>, LoadStorePattern<spirv::StoreOp>,
1234-
VariablePattern,
1298+
AddressOfPattern, GlobalVariablePattern, LoadStorePattern<spirv::LoadOp>,
1299+
LoadStorePattern<spirv::StoreOp>, VariablePattern,
12351300

12361301
// Miscellaneous ops
12371302
DirectConversionPattern<spirv::SelectOp, LLVM::SelectOp>,

mlir/test/Conversion/SPIRVToLLVM/memory-ops-to-llvm.mlir

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
// RUN: mlir-opt -convert-spirv-to-llvm %s | FileCheck %s
22

3+
//===----------------------------------------------------------------------===//
4+
// spv.globalVariable and spv._address_of
5+
//===----------------------------------------------------------------------===//
6+
7+
spv.module Logical GLSL450 {
8+
// CHECK: llvm.mlir.global external constant @var() : !llvm.float
9+
spv.globalVariable @var : !spv.ptr<f32, Input>
10+
}
11+
12+
spv.module Logical GLSL450 {
13+
// CHECK: llvm.mlir.global private @struct() : !llvm.struct<packed (float, array<10 x float>)>
14+
// CHECK-LABEL: @func
15+
// CHECK: llvm.mlir.addressof @struct : !llvm.ptr<struct<packed (float, array<10 x float>)>>
16+
spv.globalVariable @struct : !spv.ptr<!spv.struct<f32, !spv.array<10xf32>>, Private>
17+
spv.func @func() -> () "None" {
18+
%0 = spv._address_of @struct : !spv.ptr<!spv.struct<f32, !spv.array<10xf32>>, Private>
19+
spv.Return
20+
}
21+
}
22+
323
//===----------------------------------------------------------------------===//
424
// spv.Load
525
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)