diff --git a/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp b/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp --- a/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp +++ b/mlir/examples/toy/Ch6/mlir/LowerToLLVM.cpp @@ -139,7 +139,8 @@ IntegerType::get(builder.getContext(), 8), value.size()); global = builder.create(loc, type, /*isConstant=*/true, LLVM::Linkage::Internal, name, - builder.getStringAttr(value)); + builder.getStringAttr(value), + /*align=*/Attribute()); } // Get the pointer to the first character in the global string. diff --git a/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp b/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp --- a/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp +++ b/mlir/examples/toy/Ch7/mlir/LowerToLLVM.cpp @@ -139,7 +139,8 @@ IntegerType::get(builder.getContext(), 8), value.size()); global = builder.create(loc, type, /*isConstant=*/true, LLVM::Linkage::Internal, name, - builder.getStringAttr(value)); + builder.getStringAttr(value), + /*align=*/Attribute()); } // Get the pointer to the first character in the global string. diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -896,6 +896,7 @@ StrAttr:$sym_name, Linkage:$linkage, OptionalAttr:$value, + OptionalAttr:$align, DefaultValuedAttr, "0">:$addr_space ); let summary = "LLVM dialect global."; @@ -969,6 +970,11 @@ `constant` keyword. If the attribute is omitted, `external` linkage is assumed by default. + Like global variables in LLVM IR, globals can have an (optional) + alignment attribute using keyword `align`. The integer value of the + alignment must be a positive integer that is a power of 2. In the + custom syntax, this attribute is placed just after the value definition. + Examples: ```mlir @@ -978,13 +984,16 @@ // By default, "external" linkage is assumed and the global participates in // symbol resolution at link-time. llvm.mlir.global @glob(0 : f32) : f32 + + // Alignment is optional + llvm.mlir.global private constant @y(dense<1.0> : tensor<8xf32>) align=32 : !llvm.array<8 x f32> ``` }]; let regions = (region AnyRegion:$initializer); let builders = [ OpBuilder<(ins "Type":$type, "bool":$isConstant, "Linkage":$linkage, - "StringRef":$name, "Attribute":$value, CArg<"unsigned", "0">:$addrSpace, + "StringRef":$name, "Attribute":$value, "Attribute":$alignment, CArg<"unsigned", "0">:$addrSpace, CArg<"ArrayRef", "{}">:$attrs)> ]; diff --git a/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp b/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp --- a/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp +++ b/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp @@ -38,7 +38,7 @@ auto globalOp = rewriter.create( gpuFuncOp.getLoc(), arrayType, /*isConstant=*/false, LLVM::Linkage::Internal, name, /*value=*/Attribute(), - gpu::GPUDialect::getWorkgroupAddressSpace()); + /*align=*/Attribute(), gpu::GPUDialect::getWorkgroupAddressSpace()); workgroupBuffers.push_back(globalOp); } diff --git a/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp b/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp --- a/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp +++ b/mlir/lib/Conversion/SPIRVToLLVM/ConvertLaunchFuncToLLVMCalls.cpp @@ -235,7 +235,8 @@ rewriter.setInsertionPointToStart(module.getBody()); dstGlobal = rewriter.create( loc, dstGlobalType, - /*isConstant=*/false, LLVM::Linkage::Linkonce, name, Attribute()); + /*isConstant=*/false, LLVM::Linkage::Linkonce, name, Attribute(), + Attribute()); rewriter.setInsertionPoint(launchOp); } diff --git a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp --- a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp +++ b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp @@ -674,7 +674,8 @@ // Create `llvm.mlir.global` with initializer region containing one block. auto global = rewriter.create( UnknownLoc::get(context), structType, /*isConstant=*/true, - LLVM::Linkage::External, executionModeInfoName, Attribute()); + LLVM::Linkage::External, executionModeInfoName, Attribute(), + Attribute()); Location loc = global.getLoc(); Region ®ion = global.getInitializerRegion(); Block *block = rewriter.createBlock(®ion); @@ -751,8 +752,9 @@ auto linkage = storageClass == spirv::StorageClass::Private ? LLVM::Linkage::Private : LLVM::Linkage::External; - rewriter.replaceOpWithNewOp( - op, dstType, isConstant, linkage, op.sym_name(), Attribute()); + rewriter.replaceOpWithNewOp(op, dstType, isConstant, + linkage, op.sym_name(), + Attribute(), Attribute()); return success(); } }; diff --git a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp --- a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp +++ b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp @@ -2297,7 +2297,7 @@ rewriter.replaceOpWithNewOp( global, arrayTy, global.constant(), linkage, global.sym_name(), - initialValue, type.getMemorySpaceAsInt()); + initialValue, /*align=*/Attribute(), type.getMemorySpaceAsInt()); return success(); } }; diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1246,7 +1246,7 @@ void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type, bool isConstant, Linkage linkage, StringRef name, - Attribute value, unsigned addrSpace, + Attribute value, Attribute align, unsigned addrSpace, ArrayRef attrs) { result.addAttribute(SymbolTable::getSymbolAttrName(), builder.getStringAttr(name)); @@ -1255,6 +1255,8 @@ result.addAttribute("constant", builder.getUnitAttr()); if (value) result.addAttribute("value", value); + if (align) + result.addAttribute("align", align); result.addAttribute(getLinkageAttrName(), builder.getI64IntegerAttr(static_cast(linkage))); if (addrSpace != 0) @@ -1272,9 +1274,12 @@ if (auto value = op.getValueOrNull()) p.printAttribute(value); p << ')'; + auto alignment = op.align(); + if (alignment.hasValue()) + p << " align=" << alignment.getValue() << " "; p.printOptionalAttrDict(op->getAttrs(), {SymbolTable::getSymbolAttrName(), "type", "constant", - "value", getLinkageAttrName()}); + "value", "align", getLinkageAttrName()}); // Print the trailing type unless it's a string global. if (op.getValueOrNull().dyn_cast_or_null()) @@ -1486,10 +1491,12 @@ } namespace { -template struct EnumTraits {}; +template +struct EnumTraits {}; #define REGISTER_ENUM_TYPE(Ty) \ - template <> struct EnumTraits { \ + template <> \ + struct EnumTraits { \ static StringRef stringify(Ty value) { return stringify##Ty(value); } \ static unsigned getMaxEnumVal() { return getMaxEnumValFor##Ty(); } \ } @@ -1513,7 +1520,8 @@ } // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier -// `(` attribute? `)` attribute-list? (`:` type)? region? +// `(` attribute? `)` align? attribute-list? (`:` type)? region? +// align ::= `align` `=` UINT64 // // The type can be omitted for string attributes, in which case it will be // inferred from the value of the string as [strlen(value) x i8]. @@ -1540,6 +1548,18 @@ return failure(); } + if (succeeded(parser.parseOptionalKeyword("align"))) { + int64_t val; + if (failed(parser.parseEqual()) || failed(parser.parseInteger(val))) + return failure(); + // Check that the value is a power of 2 + if(!llvm::isPowerOf2_64(val)) + return parser.emitError(parser.getNameLoc(), + "expected a power of 2 for alignment"); + auto alignAttr = parser.getBuilder().getI64IntegerAttr(val); + result.addAttribute("align", alignAttr); + } + SmallVector types; if (parser.parseOptionalAttrDict(result.attributes) || parser.parseOptionalColonTypeList(types)) @@ -2325,7 +2345,7 @@ auto type = LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), value.size()); auto global = moduleBuilder.create( loc, type, /*isConstant=*/true, linkage, name, - builder.getStringAttr(value)); + builder.getStringAttr(value), /*align=*/Attribute()); // Get the pointer to the first character in the global string. Value globalPtr = builder.create(loc, global); diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -474,9 +474,20 @@ Type type = processType(GV->getValueType()); if (!type) return nullptr; - GlobalOp op = b.create( - UnknownLoc::get(context), type, GV->isConstant(), - convertLinkageFromLLVM(GV->getLinkage()), GV->getName(), valueAttr); + + Attribute alignment = Attribute(); + llvm::MaybeAlign maybeAlign = GV->getAlign(); + if (maybeAlign.hasValue()) { + llvm::Align align = maybeAlign.getValue(); + uint64_t alignValue = align.value(); + alignment = b.getIntegerAttr(IntegerType::get(context, 64), alignValue); + } + + GlobalOp op = + b.create(UnknownLoc::get(context), type, GV->isConstant(), + convertLinkageFromLLVM(GV->getLinkage()), + GV->getName(), valueAttr, alignment); + if (GV->hasInitializer() && !valueAttr) { Region &r = op.getInitializerRegion(); currentEntryBlock = b.createBlock(&r); @@ -486,6 +497,7 @@ return nullptr; b.create(op.getLoc(), ArrayRef({v})); } + return globals[GV] = op; } diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -403,6 +403,10 @@ anyExternalLinkage ? nullptr : cst, op.sym_name(), /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal, addrSpace); + Optional alignment = op.align(); + if (alignment.hasValue()) + var->setAlignment(llvm::MaybeAlign(alignment.getValue())); + globalsMapping.try_emplace(op, var); } diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir --- a/mlir/test/Dialect/LLVMIR/global.mlir +++ b/mlir/test/Dialect/LLVMIR/global.mlir @@ -9,6 +9,15 @@ // CHECK: llvm.mlir.global internal @global(42 : i64) : i64 llvm.mlir.global internal @global(42 : i64) : i64 +// CHECK: llvm.mlir.global private @aligned_global(42 : i64) align=64 : i64 +llvm.mlir.global private @aligned_global(42 : i64) {align = 64 : i64} : i64 + +// CHECK: llvm.mlir.global private constant @aligned_global_const(42 : i64) align=32 : i64 +llvm.mlir.global private constant @aligned_global_const(42 : i64) {align = 32 : i64} : i64 + +// CHECK: llvm.mlir.global private constant @aligned_global_const_native(42 : i64) align=32 : i64 +llvm.mlir.global private constant @aligned_global_const_native(42 : i64) align=32 : i64 + // CHECK: llvm.mlir.global internal constant @constant(3.700000e+01 : f64) : f32 llvm.mlir.global internal constant @constant(37.0) : f32 diff --git a/mlir/test/Target/LLVMIR/import.ll b/mlir/test/Target/LLVMIR/import.ll --- a/mlir/test/Target/LLVMIR/import.ll +++ b/mlir/test/Target/LLVMIR/import.ll @@ -3,9 +3,9 @@ %struct.t = type {} %struct.s = type { %struct.t, i64 } -; CHECK: llvm.mlir.global external @g1() : !llvm.struct<"struct.s", (struct<"struct.t", ()>, i64)> +; CHECK: llvm.mlir.global external @g1() align=8 : !llvm.struct<"struct.s", (struct<"struct.t", ()>, i64)> @g1 = external global %struct.s, align 8 -; CHECK: llvm.mlir.global external @g2() : f64 +; CHECK: llvm.mlir.global external @g2() align=8 : f64 @g2 = external global double, align 8 ; CHECK: llvm.mlir.global internal @g3("string") @g3 = internal global [6 x i8] c"string" @@ -13,6 +13,12 @@ ; CHECK: llvm.mlir.global external @g5() : vector<8xi32> @g5 = external global <8 x i32> +; CHECK: llvm.mlir.global private @alig32(42 : i64) align=32 : i64 +@alig32 = private global i64 42, align 32 + +; CHECK: llvm.mlir.global private @alig64(42 : i64) align=64 : i64 +@alig64 = private global i64 42, align 64 + @g4 = external global i32, align 8 ; CHECK: llvm.mlir.global internal constant @int_gep() : !llvm.ptr { ; CHECK-DAG: %[[addr:[0-9]+]] = llvm.mlir.addressof @g4 : !llvm.ptr diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1,5 +1,14 @@ // RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s +// CHECK: @global_aligned32 = private global i64 42, align 32 +"llvm.mlir.global"() ({}) {sym_name = "global_aligned32", type = i64, value = 42 : i64, linkage = 0, align = 32} : () -> () + +// CHECK: @global_aligned64 = private global i64 42, align 64 +llvm.mlir.global private @global_aligned64(42 : i64) {align = 64 : i64} : i64 + +// CHECK: @global_aligned64_native = private global i64 42, align 64 +llvm.mlir.global private @global_aligned64_native(42 : i64) align=64 : i64 + // CHECK: @i32_global = internal global i32 42 llvm.mlir.global internal @i32_global(42: i32) : i32 @@ -1508,3 +1517,4 @@ // CHECK: ![[PIPELINE_DISABLE_NODE]] = !{!"llvm.loop.pipeline.disable", i1 true} // CHECK: ![[II_NODE]] = !{!"llvm.loop.pipeline.initiationinterval", i32 2} // CHECK: ![[ACCESS_GROUPS_NODE]] = !{![[GROUP_NODE1]], ![[GROUP_NODE2]]} +