diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 29a3d5f068535..e5b0fc577a63d 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1001,6 +1001,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global", StrAttr:$sym_name, Linkage:$linkage, UnitAttr:$dso_local, + UnitAttr:$thread_local_, OptionalAttr:$value, OptionalAttr:$alignment, DefaultValuedAttr, "0">:$addr_space, @@ -1112,6 +1113,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global", CArg<"uint64_t", "0">:$alignment, CArg<"unsigned", "0">:$addrSpace, CArg<"bool", "false">:$dsoLocal, + CArg<"bool", "false">:$thread_local_, CArg<"ArrayRef", "{}">:$attrs)> ]; diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index bf8d487ccb498..3fc042d17c572 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1579,38 +1579,38 @@ LogicalResult AddressOfOp::verify() { // Builder, printer and verifier for LLVM::GlobalOp. //===----------------------------------------------------------------------===// -/// Returns the name used for the linkage attribute. This *must* correspond to -/// the name of the attribute in ODS. -static StringRef getLinkageAttrName() { return "linkage"; } - -/// Returns the name used for the unnamed_addr attribute. This *must* correspond -/// to the name of the attribute in ODS. -static StringRef getUnnamedAddrAttrName() { return "unnamed_addr"; } - void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type, bool isConstant, Linkage linkage, StringRef name, Attribute value, uint64_t alignment, unsigned addrSpace, - bool dsoLocal, ArrayRef attrs) { - result.addAttribute(SymbolTable::getSymbolAttrName(), + bool dsoLocal, bool threadLocal, + ArrayRef attrs) { + result.addAttribute(getSymNameAttrName(result.name), builder.getStringAttr(name)); - result.addAttribute("global_type", TypeAttr::get(type)); + result.addAttribute(getGlobalTypeAttrName(result.name), TypeAttr::get(type)); if (isConstant) - result.addAttribute("constant", builder.getUnitAttr()); + result.addAttribute(getConstantAttrName(result.name), + builder.getUnitAttr()); if (value) - result.addAttribute("value", value); + result.addAttribute(getValueAttrName(result.name), value); if (dsoLocal) - result.addAttribute("dso_local", builder.getUnitAttr()); + result.addAttribute(getDsoLocalAttrName(result.name), + builder.getUnitAttr()); + if (threadLocal) + result.addAttribute(getThreadLocal_AttrName(result.name), + builder.getUnitAttr()); // Only add an alignment attribute if the "alignment" input // is different from 0. The value must also be a power of two, but // this is tested in GlobalOp::verify, not here. if (alignment != 0) - result.addAttribute("alignment", builder.getI64IntegerAttr(alignment)); + result.addAttribute(getAlignmentAttrName(result.name), + builder.getI64IntegerAttr(alignment)); - result.addAttribute(::getLinkageAttrName(), + result.addAttribute(getLinkageAttrName(result.name), LinkageAttr::get(builder.getContext(), linkage)); if (addrSpace != 0) - result.addAttribute("addr_space", builder.getI32IntegerAttr(addrSpace)); + result.addAttribute(getAddrSpaceAttrName(result.name), + builder.getI32IntegerAttr(addrSpace)); result.attributes.append(attrs.begin(), attrs.end()); result.addRegion(); } @@ -1622,6 +1622,8 @@ void GlobalOp::print(OpAsmPrinter &p) { if (!str.empty()) p << str << ' '; } + if (getThreadLocal_()) + p << "thread_local "; if (getConstant()) p << "constant "; p.printSymbolName(getSymName()); @@ -1632,10 +1634,11 @@ void GlobalOp::print(OpAsmPrinter &p) { // Note that the alignment attribute is printed using the // default syntax here, even though it is an inherent attribute // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes) - p.printOptionalAttrDict((*this)->getAttrs(), - {SymbolTable::getSymbolAttrName(), "global_type", - "constant", "value", getLinkageAttrName(), - getUnnamedAddrAttrName()}); + p.printOptionalAttrDict( + (*this)->getAttrs(), + {SymbolTable::getSymbolAttrName(), getGlobalTypeAttrName(), + getConstantAttrName(), getValueAttrName(), getLinkageAttrName(), + getUnnamedAddrAttrName(), getThreadLocal_AttrName()}); // Print the trailing type unless it's a string global. if (getValueOrNull().dyn_cast_or_null()) @@ -1702,28 +1705,35 @@ static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser, ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) { MLIRContext *ctx = parser.getContext(); // Parse optional linkage, default to External. - result.addAttribute(::getLinkageAttrName(), + result.addAttribute(getLinkageAttrName(result.name), LLVM::LinkageAttr::get( ctx, parseOptionalLLVMKeyword( parser, result, LLVM::Linkage::External))); + + if (succeeded(parser.parseOptionalKeyword("thread_local"))) + result.addAttribute(getThreadLocal_AttrName(result.name), + parser.getBuilder().getUnitAttr()); + // Parse optional UnnamedAddr, default to None. - result.addAttribute(::getUnnamedAddrAttrName(), + result.addAttribute(getUnnamedAddrAttrName(result.name), parser.getBuilder().getI64IntegerAttr( parseOptionalLLVMKeyword( parser, result, LLVM::UnnamedAddr::None))); if (succeeded(parser.parseOptionalKeyword("constant"))) - result.addAttribute("constant", parser.getBuilder().getUnitAttr()); + result.addAttribute(getConstantAttrName(result.name), + parser.getBuilder().getUnitAttr()); StringAttr name; - if (parser.parseSymbolName(name, SymbolTable::getSymbolAttrName(), + if (parser.parseSymbolName(name, getSymNameAttrName(result.name), result.attributes) || parser.parseLParen()) return failure(); Attribute value; if (parser.parseOptionalRParen()) { - if (parser.parseAttribute(value, "value", result.attributes) || + if (parser.parseAttribute(value, getValueAttrName(result.name), + result.attributes) || parser.parseRParen()) return failure(); } @@ -1755,7 +1765,8 @@ ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) { return failure(); } - result.addAttribute("global_type", TypeAttr::get(types[0])); + result.addAttribute(getGlobalTypeAttrName(result.name), + TypeAttr::get(types[0])); return success(); } @@ -1976,7 +1987,7 @@ void LLVMFuncOp::build(OpBuilder &builder, OperationState &result, builder.getStringAttr(name)); result.addAttribute(getFunctionTypeAttrName(result.name), TypeAttr::get(type)); - result.addAttribute(::getLinkageAttrName(), + result.addAttribute(getLinkageAttrName(result.name), LinkageAttr::get(builder.getContext(), linkage)); result.attributes.append(attrs.begin(), attrs.end()); if (dsoLocal) @@ -2036,7 +2047,7 @@ buildLLVMFunctionType(OpAsmParser &parser, SMLoc loc, ArrayRef inputs, ParseResult LLVMFuncOp::parse(OpAsmParser &parser, OperationState &result) { // Default to external linkage if no keyword is provided. result.addAttribute( - ::getLinkageAttrName(), + getLinkageAttrName(result.name), LinkageAttr::get(parser.getContext(), parseOptionalLLVMKeyword( parser, result, LLVM::Linkage::External))); diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp index 2f866e10dd8ab..bda695c35ddbb 100644 --- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp +++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp @@ -432,10 +432,11 @@ GlobalOp Importer::processGlobal(llvm::GlobalVariable *gv) { alignment = align.value(); } - GlobalOp op = - b.create(UnknownLoc::get(context), type, gv->isConstant(), - convertLinkageFromLLVM(gv->getLinkage()), - gv->getName(), valueAttr, alignment); + GlobalOp op = b.create( + UnknownLoc::get(context), type, gv->isConstant(), + convertLinkageFromLLVM(gv->getLinkage()), gv->getName(), valueAttr, + alignment, /*addr_space=*/gv->getAddressSpace(), + /*dso_local=*/gv->isDSOLocal(), /*thread_local=*/gv->isThreadLocal()); if (gv->hasInitializer() && !valueAttr) { Region &r = op.getInitializerRegion(); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index 953fb2461520f..127e7e15ccab9 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -661,7 +661,10 @@ LogicalResult ModuleTranslation::convertGlobals() { auto *var = new llvm::GlobalVariable( *llvmModule, type, op.getConstant(), linkage, cst, op.getSymName(), - /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal, addrSpace); + /*InsertBefore=*/nullptr, + op.getThreadLocal_() ? llvm::GlobalValue::GeneralDynamicTLSModel + : llvm::GlobalValue::NotThreadLocal, + addrSpace); if (op.getUnnamedAddr().hasValue()) var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr())); diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir index bb0f6d7704e3c..ab0f0c48042a0 100644 --- a/mlir/test/Dialect/LLVMIR/global.mlir +++ b/mlir/test/Dialect/LLVMIR/global.mlir @@ -57,6 +57,10 @@ llvm.mlir.global extern_weak @extern_weak() : i64 llvm.mlir.global linkonce_odr @linkonce_odr() : i64 // CHECK: llvm.mlir.global weak_odr llvm.mlir.global weak_odr @weak_odr() : i64 +// CHECK: llvm.mlir.global external @has_thr_local(42 : i64) {thr_local} : i64 +llvm.mlir.global external @has_thr_local(42 : i64) {thr_local} : i64 +// CHECK: llvm.mlir.global external @has_dso_local(42 : i64) {dso_local} : i64 +llvm.mlir.global external @has_dso_local(42 : i64) {dso_local} : i64 // CHECK-LABEL: references func @references() { diff --git a/mlir/test/Target/LLVMIR/import.ll b/mlir/test/Target/LLVMIR/import.ll index c1deb500d1cf5..35176a301b88d 100644 --- a/mlir/test/Target/LLVMIR/import.ll +++ b/mlir/test/Target/LLVMIR/import.ll @@ -13,14 +13,14 @@ ; CHECK: llvm.mlir.global external @g5() : vector<8xi32> @g5 = external global <8 x i32> -; CHECK: llvm.mlir.global private @alig32(42 : i64) {alignment = 32 : i64} : i64 +; CHECK: llvm.mlir.global private @alig32(42 : i64) {alignment = 32 : i64, dso_local} : i64 @alig32 = private global i64 42, align 32 -; CHECK: llvm.mlir.global private @alig64(42 : i64) {alignment = 64 : i64} : i64 +; CHECK: llvm.mlir.global private @alig64(42 : i64) {alignment = 64 : i64, dso_local} : 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: llvm.mlir.global internal constant @int_gep() {dso_local} : !llvm.ptr { ; CHECK-DAG: %[[addr:[0-9]+]] = llvm.mlir.addressof @g4 : !llvm.ptr ; CHECK-DAG: %[[c2:[0-9]+]] = llvm.mlir.constant(2 : i32) : i32 ; CHECK-NEXT: %[[gepinit:[0-9]+]] = llvm.getelementptr %[[addr]][%[[c2]]] : (!llvm.ptr, i32) -> !llvm.ptr @@ -28,13 +28,34 @@ ; CHECK-NEXT: } @int_gep = internal constant i32* getelementptr (i32, i32* @g4, i32 2) +; +; dso_local attribute +; + +; CHECK: llvm.mlir.global external @dso_local_var() {dso_local} : !llvm.struct<"struct.s", (struct<"struct.t", ()>, i64)> +@dso_local_var = external dso_local global %struct.s + +; +; thread_local attribute +; + +; CHECK: llvm.mlir.global external thread_local @thread_local_var() : !llvm.struct<"struct.s", (struct<"struct.t", ()>, i64)> +@thread_local_var = external thread_local global %struct.s + +; +; addr_space attribute +; + +; CHECK: llvm.mlir.global external @addr_space_var(0 : i32) {addr_space = 6 : i32} : i32 +@addr_space_var = addrspace(6) global i32 0 + ; ; Linkage attribute. ; -; CHECK: llvm.mlir.global private @private(42 : i32) : i32 +; CHECK: llvm.mlir.global private @private(42 : i32) {dso_local} : i32 @private = private global i32 42 -; CHECK: llvm.mlir.global internal @internal(42 : i32) : i32 +; CHECK: llvm.mlir.global internal @internal(42 : i32) {dso_local} : i32 @internal = internal global i32 42 ; CHECK: llvm.mlir.global available_externally @available_externally(42 : i32) : i32 @available_externally = available_externally global i32 42 @@ -60,33 +81,33 @@ ; -; CHECK: llvm.mlir.global private constant @no_unnamed_addr(42 : i64) : i64 +; CHECK: llvm.mlir.global private constant @no_unnamed_addr(42 : i64) {dso_local} : i64 @no_unnamed_addr = private constant i64 42 -; CHECK: llvm.mlir.global private local_unnamed_addr constant @local_unnamed_addr(42 : i64) : i64 +; CHECK: llvm.mlir.global private local_unnamed_addr constant @local_unnamed_addr(42 : i64) {dso_local} : i64 @local_unnamed_addr = private local_unnamed_addr constant i64 42 -; CHECK: llvm.mlir.global private unnamed_addr constant @unnamed_addr(42 : i64) : i64 +; CHECK: llvm.mlir.global private unnamed_addr constant @unnamed_addr(42 : i64) {dso_local} : i64 @unnamed_addr = private unnamed_addr constant i64 42 ; ; Section attribute ; -; CHECK: llvm.mlir.global internal constant @sectionvar("teststring") {section = ".mysection"} +; CHECK: llvm.mlir.global internal constant @sectionvar("teststring") {dso_local, section = ".mysection"} @sectionvar = internal constant [10 x i8] c"teststring", section ".mysection" ; ; Sequential constants. ; -; CHECK: llvm.mlir.global internal constant @vector_constant(dense<[1, 2]> : vector<2xi32>) : vector<2xi32> +; CHECK: llvm.mlir.global internal constant @vector_constant(dense<[1, 2]> : vector<2xi32>) {dso_local} : vector<2xi32> @vector_constant = internal constant <2 x i32> -; CHECK: llvm.mlir.global internal constant @array_constant(dense<[1.000000e+00, 2.000000e+00]> : tensor<2xf32>) : !llvm.array<2 x f32> +; CHECK: llvm.mlir.global internal constant @array_constant(dense<[1.000000e+00, 2.000000e+00]> : tensor<2xf32>) {dso_local} : !llvm.array<2 x f32> @array_constant = internal constant [2 x float] [float 1., float 2.] -; CHECK: llvm.mlir.global internal constant @nested_array_constant(dense<[{{\[}}1, 2], [3, 4]]> : tensor<2x2xi32>) : !llvm.array<2 x array<2 x i32>> +; CHECK: llvm.mlir.global internal constant @nested_array_constant(dense<[{{\[}}1, 2], [3, 4]]> : tensor<2x2xi32>) {dso_local} : !llvm.array<2 x array<2 x i32>> @nested_array_constant = internal constant [2 x [2 x i32]] [[2 x i32] [i32 1, i32 2], [2 x i32] [i32 3, i32 4]] -; CHECK: llvm.mlir.global internal constant @nested_array_constant3(dense<[{{\[}}[1, 2], [3, 4]]]> : tensor<1x2x2xi32>) : !llvm.array<1 x array<2 x array<2 x i32>>> +; CHECK: llvm.mlir.global internal constant @nested_array_constant3(dense<[{{\[}}[1, 2], [3, 4]]]> : tensor<1x2x2xi32>) {dso_local} : !llvm.array<1 x array<2 x array<2 x i32>>> @nested_array_constant3 = internal constant [1 x [2 x [2 x i32]]] [[2 x [2 x i32]] [[2 x i32] [i32 1, i32 2], [2 x i32] [i32 3, i32 4]]] -; CHECK: llvm.mlir.global internal constant @nested_array_vector(dense<[{{\[}}[1, 2], [3, 4]]]> : vector<1x2x2xi32>) : !llvm.array<1 x array<2 x vector<2xi32>>> +; CHECK: llvm.mlir.global internal constant @nested_array_vector(dense<[{{\[}}[1, 2], [3, 4]]]> : vector<1x2x2xi32>) {dso_local} : !llvm.array<1 x array<2 x vector<2xi32>>> @nested_array_vector = internal constant [1 x [2 x <2 x i32>]] [[2 x <2 x i32>] [<2 x i32> , <2 x i32> ]] ; diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 99b3f38d766d6..cd14641944c30 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -128,6 +128,13 @@ llvm.mlir.global private unnamed_addr constant @unnamed_addr(42 : i64) : i64 llvm.mlir.global @has_dso_local(42 : i64) {dso_local} : i64 // CHECK: @has_dso_local = dso_local global i64 42 +// +// thr_local attribute. +// + +llvm.mlir.global thread_local @has_thr_local(42 : i64) : i64 +// CHECK: @has_thr_local = thread_local global i64 42 + // // Section attribute. //