diff --git a/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp b/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp index 43ef6822de302..ad39640235e91 100644 --- a/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp +++ b/flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp @@ -23,6 +23,7 @@ #include "flang/Runtime/CUDA/registration.h" #include "flang/Runtime/entry-names.h" #include "mlir/Dialect/GPU/IR/GPUDialect.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" #include "mlir/IR/Value.h" #include "mlir/Pass/Pass.h" @@ -157,10 +158,12 @@ struct CUFAddConstructor funcs.push_back( mlir::FlatSymbolRefAttr::get(mod.getContext(), func.getSymName())); llvm::SmallVector priorities; + llvm::SmallVector data; priorities.push_back(0); + data.push_back(mlir::LLVM::ZeroAttr::get(mod.getContext())); builder.create( mod.getLoc(), builder.getArrayAttr(funcs), - builder.getI32ArrayAttr(priorities)); + builder.getI32ArrayAttr(priorities), builder.getArrayAttr(data)); } }; diff --git a/flang/test/Fir/CUDA/cuda-constructor.f90 b/flang/test/Fir/CUDA/cuda-constructor.f90 index d02350b4f4198..1ba3fdc4a6b73 100644 --- a/flang/test/Fir/CUDA/cuda-constructor.f90 +++ b/flang/test/Fir/CUDA/cuda-constructor.f90 @@ -9,4 +9,4 @@ program main ! CHECK: llvm.call @_FortranACUFRegisterAllocator() : () -> () ! CHECK: llvm.return ! CHECK: } -! CHECK: llvm.mlir.global_ctors {ctors = [@__cudaFortranConstructor], priorities = [0 : i32]} +! CHECK: llvm.mlir.global_ctors ctors = [@__cudaFortranConstructor], priorities = [0 : i32], data = [#llvm.zero] diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 1c7229fee0dcf..3a03803ab04c7 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1438,32 +1438,37 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global", def LLVM_GlobalCtorsOp : LLVM_Op<"mlir.global_ctors", [ DeclareOpInterfaceMethods]> { - let arguments = (ins FlatSymbolRefArrayAttr - : $ctors, I32ArrayAttr - : $priorities); + let arguments = (ins FlatSymbolRefArrayAttr:$ctors, + I32ArrayAttr:$priorities, + ArrayAttr:$data); let summary = "LLVM dialect global_ctors."; let description = [{ - Specifies a list of constructor functions and priorities. The functions - referenced by this array will be called in ascending order of priority (i.e. - lowest first) when the module is loaded. The order of functions with the - same priority is not defined. This operation is translated to LLVM's - global_ctors global variable. The initializer functions are run at load - time. The `data` field present in LLVM's global_ctors variable is not - modeled here. + Specifies a list of constructor functions, priorities, and associated data. + The functions referenced by this array will be called in ascending order + of priority (i.e. lowest first) when the module is loaded. The order of + functions with the same priority is not defined. This operation is + translated to LLVM's global_ctors global variable. The initializer + functions are run at load time. However, if the associated data is not + `#llvm.zero`, functions only run if the data is not discarded. Examples: ```mlir - llvm.mlir.global_ctors {@ctor} - llvm.func @ctor() { ... llvm.return } + llvm.mlir.global_ctors ctors = [@ctor], priorities = [0], + data = [#llvm.zero] ``` }]; - let assemblyFormat = "attr-dict"; + let assemblyFormat = [{ + `ctors` `=` $ctors + `,` `priorities` `=` $priorities + `,` `data` `=` $data + attr-dict + }]; let hasVerifier = 1; } @@ -1471,16 +1476,18 @@ def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [ DeclareOpInterfaceMethods]> { let arguments = (ins FlatSymbolRefArrayAttr:$dtors, - I32ArrayAttr:$priorities + I32ArrayAttr:$priorities, + ArrayAttr:$data ); let summary = "LLVM dialect global_dtors."; let description = [{ Specifies a list of destructor functions and priorities. The functions - referenced by this array will be called in descending order of priority (i.e. - highest first) when the module is unloaded. The order of functions with the - same priority is not defined. This operation is translated to LLVM's - global_dtors global variable. The `data` field present in LLVM's - global_dtors variable is not modeled here. + referenced by this array will be called in descending order of priority + (i.e. highest first) when the module is unloaded. The order of functions + with the same priority is not defined. This operation is translated to + LLVM's global_dtors global variable. The destruction functions are run at + load time. However, if the associated data is not `#llvm.zero`, functions + only run if the data is not discarded. Examples: @@ -1488,11 +1495,16 @@ def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [ llvm.func @dtor() { llvm.return } - llvm.mlir.global_dtors {@dtor} + llvm.mlir.global_dtors dtors = [@dtor], priorities = [0], + data = [#llvm.zero] ``` - }]; - let assemblyFormat = "attr-dict"; + let assemblyFormat = [{ + `dtors` `=` $dtors + `,` `priorities` `=` $priorities + `,` `data` `=` $data + attr-dict + }]; let hasVerifier = 1; } diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index c504c77eac42e..22cb5f4cd88a4 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -2461,6 +2461,17 @@ LogicalResult GlobalOp::verifyRegions() { // LLVM::GlobalCtorsOp //===----------------------------------------------------------------------===// +LogicalResult checkGlobalXtorData(Operation *op, ArrayAttr data) { + if (data.empty()) + return success(); + + if (llvm::all_of(data.getAsRange(), [](Attribute v) { + return isa(v); + })) + return success(); + return op->emitError("data element must be symbol or #llvm.zero"); +} + LogicalResult GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) { for (Attribute ctor : getCtors()) { @@ -2472,10 +2483,14 @@ GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) { } LogicalResult GlobalCtorsOp::verify() { - if (getCtors().size() != getPriorities().size()) - return emitError( - "mismatch between the number of ctors and the number of priorities"); - return success(); + if (checkGlobalXtorData(*this, getData()).failed()) + return failure(); + + if (getCtors().size() == getPriorities().size() && + getCtors().size() == getData().size()) + return success(); + return emitError( + "ctors, priorities, and data must have the same number of elements"); } //===----------------------------------------------------------------------===// @@ -2493,10 +2508,14 @@ GlobalDtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) { } LogicalResult GlobalDtorsOp::verify() { - if (getDtors().size() != getPriorities().size()) - return emitError( - "mismatch between the number of dtors and the number of priorities"); - return success(); + if (checkGlobalXtorData(*this, getData()).failed()) + return failure(); + + if (getDtors().size() == getPriorities().size() && + getDtors().size() == getData().size()) + return success(); + return emitError( + "dtors, priorities, and data must have the same number of elements"); } //===----------------------------------------------------------------------===// @@ -2599,6 +2618,7 @@ LogicalResult AliasOp::verify() { case Linkage::Internal: case Linkage::Private: case Linkage::Weak: + case Linkage::WeakODR: case Linkage::Linkonce: case Linkage::LinkonceODR: case Linkage::AvailableExternally: diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index c15405a3a4650..cf058dd3e31e2 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -1115,6 +1115,7 @@ ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) { SmallVector funcs; SmallVector priorities; + SmallVector dataList; for (llvm::Value *operand : initializer->operands()) { auto *aggregate = dyn_cast(operand); if (!aggregate || aggregate->getNumOperands() != 3) @@ -1126,12 +1127,18 @@ ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) { if (!priority || !func || !data) return failure(); - // GlobalCtorsOps and GlobalDtorsOps do not support non-null data fields. - if (!data->isNullValue()) + auto *gv = dyn_cast_or_null(data); + Attribute dataAttr; + if (gv) + dataAttr = FlatSymbolRefAttr::get(context, gv->getName()); + else if (data->isNullValue()) + dataAttr = ZeroAttr::get(context); + else return failure(); funcs.push_back(FlatSymbolRefAttr::get(context, func->getName())); priorities.push_back(priority->getValue().getZExtValue()); + dataList.push_back(dataAttr); } // Insert the global after the last one or at the start of the module. @@ -1140,12 +1147,12 @@ ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) { if (globalVar->getName() == getGlobalCtorsVarName()) { globalInsertionOp = builder.create( mlirModule.getLoc(), builder.getArrayAttr(funcs), - builder.getI32ArrayAttr(priorities)); + builder.getI32ArrayAttr(priorities), builder.getArrayAttr(dataList)); return success(); } globalInsertionOp = builder.create( mlirModule.getLoc(), builder.getArrayAttr(funcs), - builder.getI32ArrayAttr(priorities)); + builder.getI32ArrayAttr(priorities), builder.getArrayAttr(dataList)); return success(); } diff --git a/mlir/test/Dialect/LLVMIR/alias.mlir b/mlir/test/Dialect/LLVMIR/alias.mlir index 807843a27e6fa..efba248534862 100644 --- a/mlir/test/Dialect/LLVMIR/alias.mlir +++ b/mlir/test/Dialect/LLVMIR/alias.mlir @@ -26,23 +26,23 @@ llvm.mlir.alias external @_ZTV1D : !llvm.struct<(array<3 x ptr>)> { // ----- -llvm.mlir.global external @zed(42 : i32) : i32 +llvm.mlir.global weak_odr @zed(42 : i32) : i32 -llvm.mlir.alias external @foo : i32 { +llvm.mlir.alias weak_odr @foo : i32 { %0 = llvm.mlir.addressof @zed : !llvm.ptr llvm.return %0 : !llvm.ptr } -llvm.mlir.alias external @foo2 : i16 { +llvm.mlir.alias weak_odr @foo2 : i16 { %0 = llvm.mlir.addressof @zed : !llvm.ptr llvm.return %0 : !llvm.ptr } -// CHECK: llvm.mlir.alias external @foo : i32 { +// CHECK: llvm.mlir.alias weak_odr @foo : i32 { // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @zed : !llvm.ptr // CHECK: llvm.return %[[ADDR]] : !llvm.ptr // CHECK: } -// CHECK: llvm.mlir.alias external @foo2 : i16 { +// CHECK: llvm.mlir.alias weak_odr @foo2 : i16 { // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @zed : !llvm.ptr // CHECK: llvm.return %[[ADDR]] : !llvm.ptr // CHECK: } diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir index bd3584de9a405..193ab7987a2b6 100644 --- a/mlir/test/Dialect/LLVMIR/global.mlir +++ b/mlir/test/Dialect/LLVMIR/global.mlir @@ -228,16 +228,16 @@ llvm.func @ctor() { llvm.return } -// CHECK: llvm.mlir.global_ctors {ctors = [@ctor], priorities = [0 : i32]} -llvm.mlir.global_ctors { ctors = [@ctor], priorities = [0 : i32]} +// CHECK: llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero] +llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero] // ----- -// CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []} -llvm.mlir.global_ctors {ctors = [], priorities = []} +// CHECK: llvm.mlir.global_ctors ctors = [], priorities = [], data = [] +llvm.mlir.global_ctors ctors = [], priorities = [], data = [] -// CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []} -llvm.mlir.global_dtors {dtors = [], priorities = []} +// CHECK: llvm.mlir.global_dtors dtors = [], priorities = [], data = [] +llvm.mlir.global_dtors dtors = [], priorities = [], data = [] // ----- @@ -245,8 +245,8 @@ llvm.func @dtor() { llvm.return } -// CHECK: llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32]} -llvm.mlir.global_dtors { dtors = [@dtor], priorities = [0 : i32]} +// CHECK: llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero] +llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero] // ----- diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir index 6d3d3937b651c..fb9631d99b91a 100644 --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -9,8 +9,8 @@ llvm.func @ctor() { llvm.return } -// expected-error@+1{{mismatch between the number of ctors and the number of priorities}} -llvm.mlir.global_ctors {ctors = [@ctor], priorities = []} +// expected-error@+1{{ctors, priorities, and data must have the same number of elements}} +llvm.mlir.global_ctors ctors = [@ctor], priorities = [], data = [#llvm.zero] // ----- @@ -18,20 +18,29 @@ llvm.func @dtor() { llvm.return } -// expected-error@+1{{mismatch between the number of dtors and the number of priorities}} -llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32, 32767 : i32]} +// expected-error@+1{{dtors, priorities, and data must have the same number of elements}} +llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32, 32767 : i32], data = [#llvm.zero] // ----- // expected-error@+1{{'ctor' does not reference a valid LLVM function}} -llvm.mlir.global_ctors {ctors = [@ctor], priorities = [0 : i32]} +llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero] // ----- llvm.func @dtor() // expected-error@+1{{'dtor' does not have a definition}} -llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32]} +llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero] + +// ----- + +llvm.func @dtor() { + llvm.return +} + +// expected-error@+1{{data element must be symbol or #llvm.zero}} +llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [0 : i32] //////////////////////////////////////////////////////////////////////////////// diff --git a/mlir/test/Target/LLVMIR/Import/alias.ll b/mlir/test/Target/LLVMIR/Import/alias.ll index 23eaecb9c9fa7..7015d120a7252 100644 --- a/mlir/test/Target/LLVMIR/Import/alias.ll +++ b/mlir/test/Target/LLVMIR/Import/alias.ll @@ -62,6 +62,13 @@ entry: ; // ----- +@glob.private2 = private constant [32 x i32] zeroinitializer +@glob2 = weak_odr hidden alias [32 x i32], inttoptr (i64 add (i64 ptrtoint (ptr @glob.private2 to i64), i64 1234) to ptr) + +; CHECK: llvm.mlir.alias weak_odr hidden @glob2 {dso_local} : !llvm.array<32 x i32> { + +; // ----- + @g1 = private global i32 0 @g2 = internal constant ptr @a1 @g3 = internal constant ptr @a2 diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll index b809c93d772f5..b8bbdbab2e2ca 100644 --- a/mlir/test/Target/LLVMIR/Import/global-variables.ll +++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll @@ -241,8 +241,8 @@ ; // ----- -; CHECK: llvm.mlir.global_ctors {ctors = [@foo, @bar], priorities = [0 : i32, 42 : i32]} -; CHECK: llvm.mlir.global_dtors {dtors = [@foo], priorities = [0 : i32]} +; CHECK: llvm.mlir.global_ctors ctors = [@foo, @bar], priorities = [0 : i32, 42 : i32], data = [#llvm.zero, #llvm.zero] +; CHECK: llvm.mlir.global_dtors dtors = [@foo], priorities = [0 : i32], data = [#llvm.zero] @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }, { i32, ptr, ptr } { i32 42, ptr @bar, ptr null }] @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }] @@ -256,14 +256,23 @@ define void @bar() { ; // ----- -; CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []} +; CHECK: llvm.mlir.global_ctors ctors = [], priorities = [], data = [] @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer -; CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []} +; CHECK: llvm.mlir.global_dtors dtors = [], priorities = [], data = [] @llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer ; // ----- +; llvm.mlir.global_dtors dtors = [@foo], priorities = [0 : i32], data = [@foo] +@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr @foo }] + +define void @foo() { + ret void +} + +; // ----- + ; Visibility attribute. ; CHECK: llvm.mlir.global external hidden constant @hidden("string") diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll index 66c8470b8782a..22f5a72e214d5 100644 --- a/mlir/test/Target/LLVMIR/Import/import-failure.ll +++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll @@ -64,17 +64,6 @@ define void @unsupported_argument(i64 %arg1) { ; // ----- -; global_dtors with non-null data fields cannot be represented in MLIR. -; CHECK: -; CHECK-SAME: error: unhandled global variable: @llvm.global_dtors -@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr @foo }] - -define void @foo() { - ret void -} - -; // ----- - ; CHECK: import-failure.ll ; CHECK-SAME: error: unsupported TBAA node format: !{{.*}} = !{!{{.*}}, i64 1, !"omnipotent char"} define dso_local void @tbaa(ptr %0) { diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 5a1f43ba1d018..9747fdf91760d 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1851,7 +1851,7 @@ llvm.mlir.global linkonce @take_self_address() : !llvm.struct<(i32, !llvm.ptr)> // ----- // CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }] -llvm.mlir.global_ctors { ctors = [@foo], priorities = [0 : i32]} +llvm.mlir.global_ctors ctors = [@foo], priorities = [0 : i32], data = [#llvm.zero] llvm.func @foo() { llvm.return @@ -1860,15 +1860,15 @@ llvm.func @foo() { // ----- // CHECK: @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer -llvm.mlir.global_ctors {ctors = [], priorities = []} +llvm.mlir.global_ctors ctors = [], priorities = [], data = [] // CHECK: @llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer -llvm.mlir.global_dtors {dtors = [], priorities = []} +llvm.mlir.global_dtors dtors = [], priorities = [], data = [] // ----- // CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }] -llvm.mlir.global_dtors { dtors = [@foo], priorities = [0 : i32]} +llvm.mlir.global_dtors dtors = [@foo], priorities = [0 : i32], data = [#llvm.zero] llvm.func @foo() { llvm.return diff --git a/mlir/test/mlir-runner/global-constructors.mlir b/mlir/test/mlir-runner/global-constructors.mlir index 593d6aa4945ef..8b19d9873b8b0 100644 --- a/mlir/test/mlir-runner/global-constructors.mlir +++ b/mlir/test/mlir-runner/global-constructors.mlir @@ -7,8 +7,8 @@ module { llvm.func @printNewline() llvm.func @printI64(i64) - llvm.mlir.global_ctors {ctors = [@ctor], priorities = [0 : i32]} - llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32]} + llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero] + llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero] llvm.func @ctor() { %0 = llvm.mlir.constant(1 : i64) : i64 llvm.call @printI64(%0) : (i64) -> ()