@@ -273,6 +273,22 @@ static Optional<Type> convertStructType(spirv::StructType type,
273
273
274
274
namespace {
275
275
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
+
276
292
class BitFieldInsertPattern
277
293
: public SPIRVToLLVMConversion<spirv::BitFieldInsertOp> {
278
294
public:
@@ -507,6 +523,55 @@ class DirectConversionPattern : public SPIRVToLLVMConversion<SPIRVOp> {
507
523
}
508
524
};
509
525
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
+
510
575
// / Converts SPIR-V cast ops that do not have straightforward LLVM
511
576
// / equivalent in LLVM dialect.
512
577
template <typename SPIRVOp, typename LLVMExtOp, typename LLVMTruncOp>
@@ -1230,8 +1295,8 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
1230
1295
NotPattern<spirv::LogicalNotOp>,
1231
1296
1232
1297
// Memory ops
1233
- LoadStorePattern<spirv::LoadOp>, LoadStorePattern<spirv::StoreOp >,
1234
- VariablePattern,
1298
+ AddressOfPattern, GlobalVariablePattern, LoadStorePattern<spirv::LoadOp >,
1299
+ LoadStorePattern<spirv::StoreOp>, VariablePattern,
1235
1300
1236
1301
// Miscellaneous ops
1237
1302
DirectConversionPattern<spirv::SelectOp, LLVM::SelectOp>,
0 commit comments