Skip to content

Commit 7c3ecff

Browse files
[MLIR][LLVMIR] Add support for the full form of global_{ctor,dtor} (#133176)
Currently only ctor/dtor list and their priorities are supported. This PR adds support for the missing data field. Few implementation notes: - The assembly printer has a fixed form because previous `attr_dict` will sort the dict by key name, making global_dtor and global_ctor differ in the order of printed arguments. - LLVM's `ptr null` is being converted to `#llvm.zero` otherwise we'd have to create a region to use the default operation conversion from `ptr null`, which is silly given that the field only support null or a symbol.
1 parent 0d4f12e commit 7c3ecff

File tree

11 files changed

+119
-71
lines changed

11 files changed

+119
-71
lines changed

flang/lib/Optimizer/Transforms/CUFAddConstructor.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "flang/Runtime/CUDA/registration.h"
2424
#include "flang/Runtime/entry-names.h"
2525
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
26+
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
2627
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
2728
#include "mlir/IR/Value.h"
2829
#include "mlir/Pass/Pass.h"
@@ -157,10 +158,12 @@ struct CUFAddConstructor
157158
funcs.push_back(
158159
mlir::FlatSymbolRefAttr::get(mod.getContext(), func.getSymName()));
159160
llvm::SmallVector<int> priorities;
161+
llvm::SmallVector<mlir::Attribute> data;
160162
priorities.push_back(0);
163+
data.push_back(mlir::LLVM::ZeroAttr::get(mod.getContext()));
161164
builder.create<mlir::LLVM::GlobalCtorsOp>(
162165
mod.getLoc(), builder.getArrayAttr(funcs),
163-
builder.getI32ArrayAttr(priorities));
166+
builder.getI32ArrayAttr(priorities), builder.getArrayAttr(data));
164167
}
165168
};
166169

flang/test/Fir/CUDA/cuda-constructor.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ program main
99
! CHECK: llvm.call @_FortranACUFRegisterAllocator() : () -> ()
1010
! CHECK: llvm.return
1111
! CHECK: }
12-
! CHECK: llvm.mlir.global_ctors {ctors = [@__cudaFortranConstructor], priorities = [0 : i32]}
12+
! CHECK: llvm.mlir.global_ctors ctors = [@__cudaFortranConstructor], priorities = [0 : i32], data = [#llvm.zero]

mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,61 +1438,73 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
14381438

14391439
def LLVM_GlobalCtorsOp : LLVM_Op<"mlir.global_ctors", [
14401440
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
1441-
let arguments = (ins FlatSymbolRefArrayAttr
1442-
: $ctors, I32ArrayAttr
1443-
: $priorities);
1441+
let arguments = (ins FlatSymbolRefArrayAttr:$ctors,
1442+
I32ArrayAttr:$priorities,
1443+
ArrayAttr:$data);
14441444
let summary = "LLVM dialect global_ctors.";
14451445
let description = [{
1446-
Specifies a list of constructor functions and priorities. The functions
1447-
referenced by this array will be called in ascending order of priority (i.e.
1448-
lowest first) when the module is loaded. The order of functions with the
1449-
same priority is not defined. This operation is translated to LLVM's
1450-
global_ctors global variable. The initializer functions are run at load
1451-
time. The `data` field present in LLVM's global_ctors variable is not
1452-
modeled here.
1446+
Specifies a list of constructor functions, priorities, and associated data.
1447+
The functions referenced by this array will be called in ascending order
1448+
of priority (i.e. lowest first) when the module is loaded. The order of
1449+
functions with the same priority is not defined. This operation is
1450+
translated to LLVM's global_ctors global variable. The initializer
1451+
functions are run at load time. However, if the associated data is not
1452+
`#llvm.zero`, functions only run if the data is not discarded.
14531453

14541454
Examples:
14551455

14561456
```mlir
1457-
llvm.mlir.global_ctors {@ctor}
1458-
14591457
llvm.func @ctor() {
14601458
...
14611459
llvm.return
14621460
}
1461+
llvm.mlir.global_ctors ctors = [@ctor], priorities = [0],
1462+
data = [#llvm.zero]
14631463
```
14641464

14651465
}];
1466-
let assemblyFormat = "attr-dict";
1466+
let assemblyFormat = [{
1467+
`ctors` `=` $ctors
1468+
`,` `priorities` `=` $priorities
1469+
`,` `data` `=` $data
1470+
attr-dict
1471+
}];
14671472
let hasVerifier = 1;
14681473
}
14691474

14701475
def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [
14711476
DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
14721477
let arguments = (ins
14731478
FlatSymbolRefArrayAttr:$dtors,
1474-
I32ArrayAttr:$priorities
1479+
I32ArrayAttr:$priorities,
1480+
ArrayAttr:$data
14751481
);
14761482
let summary = "LLVM dialect global_dtors.";
14771483
let description = [{
14781484
Specifies a list of destructor functions and priorities. The functions
1479-
referenced by this array will be called in descending order of priority (i.e.
1480-
highest first) when the module is unloaded. The order of functions with the
1481-
same priority is not defined. This operation is translated to LLVM's
1482-
global_dtors global variable. The `data` field present in LLVM's
1483-
global_dtors variable is not modeled here.
1485+
referenced by this array will be called in descending order of priority
1486+
(i.e. highest first) when the module is unloaded. The order of functions
1487+
with the same priority is not defined. This operation is translated to
1488+
LLVM's global_dtors global variable. The destruction functions are run at
1489+
load time. However, if the associated data is not `#llvm.zero`, functions
1490+
only run if the data is not discarded.
14841491

14851492
Examples:
14861493

14871494
```mlir
14881495
llvm.func @dtor() {
14891496
llvm.return
14901497
}
1491-
llvm.mlir.global_dtors {@dtor}
1498+
llvm.mlir.global_dtors dtors = [@dtor], priorities = [0],
1499+
data = [#llvm.zero]
14921500
```
1493-
14941501
}];
1495-
let assemblyFormat = "attr-dict";
1502+
let assemblyFormat = [{
1503+
`dtors` `=` $dtors
1504+
`,` `priorities` `=` $priorities
1505+
`,` `data` `=` $data
1506+
attr-dict
1507+
}];
14961508
let hasVerifier = 1;
14971509
}
14981510

mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,6 +2508,17 @@ LogicalResult GlobalOp::verifyRegions() {
25082508
// LLVM::GlobalCtorsOp
25092509
//===----------------------------------------------------------------------===//
25102510

2511+
LogicalResult checkGlobalXtorData(Operation *op, ArrayAttr data) {
2512+
if (data.empty())
2513+
return success();
2514+
2515+
if (llvm::all_of(data.getAsRange<Attribute>(), [](Attribute v) {
2516+
return isa<FlatSymbolRefAttr, ZeroAttr>(v);
2517+
}))
2518+
return success();
2519+
return op->emitError("data element must be symbol or #llvm.zero");
2520+
}
2521+
25112522
LogicalResult
25122523
GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
25132524
for (Attribute ctor : getCtors()) {
@@ -2519,10 +2530,14 @@ GlobalCtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
25192530
}
25202531

25212532
LogicalResult GlobalCtorsOp::verify() {
2522-
if (getCtors().size() != getPriorities().size())
2523-
return emitError(
2524-
"mismatch between the number of ctors and the number of priorities");
2525-
return success();
2533+
if (checkGlobalXtorData(*this, getData()).failed())
2534+
return failure();
2535+
2536+
if (getCtors().size() == getPriorities().size() &&
2537+
getCtors().size() == getData().size())
2538+
return success();
2539+
return emitError(
2540+
"ctors, priorities, and data must have the same number of elements");
25262541
}
25272542

25282543
//===----------------------------------------------------------------------===//
@@ -2540,10 +2555,14 @@ GlobalDtorsOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
25402555
}
25412556

25422557
LogicalResult GlobalDtorsOp::verify() {
2543-
if (getDtors().size() != getPriorities().size())
2544-
return emitError(
2545-
"mismatch between the number of dtors and the number of priorities");
2546-
return success();
2558+
if (checkGlobalXtorData(*this, getData()).failed())
2559+
return failure();
2560+
2561+
if (getDtors().size() == getPriorities().size() &&
2562+
getDtors().size() == getData().size())
2563+
return success();
2564+
return emitError(
2565+
"dtors, priorities, and data must have the same number of elements");
25472566
}
25482567

25492568
//===----------------------------------------------------------------------===//

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,7 @@ ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {
11151115

11161116
SmallVector<Attribute> funcs;
11171117
SmallVector<int32_t> priorities;
1118+
SmallVector<Attribute> dataList;
11181119
for (llvm::Value *operand : initializer->operands()) {
11191120
auto *aggregate = dyn_cast<llvm::ConstantAggregate>(operand);
11201121
if (!aggregate || aggregate->getNumOperands() != 3)
@@ -1126,12 +1127,18 @@ ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {
11261127
if (!priority || !func || !data)
11271128
return failure();
11281129

1129-
// GlobalCtorsOps and GlobalDtorsOps do not support non-null data fields.
1130-
if (!data->isNullValue())
1130+
auto *gv = dyn_cast_or_null<llvm::GlobalValue>(data);
1131+
Attribute dataAttr;
1132+
if (gv)
1133+
dataAttr = FlatSymbolRefAttr::get(context, gv->getName());
1134+
else if (data->isNullValue())
1135+
dataAttr = ZeroAttr::get(context);
1136+
else
11311137
return failure();
11321138

11331139
funcs.push_back(FlatSymbolRefAttr::get(context, func->getName()));
11341140
priorities.push_back(priority->getValue().getZExtValue());
1141+
dataList.push_back(dataAttr);
11351142
}
11361143

11371144
// Insert the global after the last one or at the start of the module.
@@ -1140,12 +1147,12 @@ ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {
11401147
if (globalVar->getName() == getGlobalCtorsVarName()) {
11411148
globalInsertionOp = builder.create<LLVM::GlobalCtorsOp>(
11421149
mlirModule.getLoc(), builder.getArrayAttr(funcs),
1143-
builder.getI32ArrayAttr(priorities));
1150+
builder.getI32ArrayAttr(priorities), builder.getArrayAttr(dataList));
11441151
return success();
11451152
}
11461153
globalInsertionOp = builder.create<LLVM::GlobalDtorsOp>(
11471154
mlirModule.getLoc(), builder.getArrayAttr(funcs),
1148-
builder.getI32ArrayAttr(priorities));
1155+
builder.getI32ArrayAttr(priorities), builder.getArrayAttr(dataList));
11491156
return success();
11501157
}
11511158

mlir/test/Dialect/LLVMIR/global.mlir

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,25 +228,25 @@ llvm.func @ctor() {
228228
llvm.return
229229
}
230230

231-
// CHECK: llvm.mlir.global_ctors {ctors = [@ctor], priorities = [0 : i32]}
232-
llvm.mlir.global_ctors { ctors = [@ctor], priorities = [0 : i32]}
231+
// CHECK: llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero]
232+
llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero]
233233

234234
// -----
235235

236-
// CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []}
237-
llvm.mlir.global_ctors {ctors = [], priorities = []}
236+
// CHECK: llvm.mlir.global_ctors ctors = [], priorities = [], data = []
237+
llvm.mlir.global_ctors ctors = [], priorities = [], data = []
238238

239-
// CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []}
240-
llvm.mlir.global_dtors {dtors = [], priorities = []}
239+
// CHECK: llvm.mlir.global_dtors dtors = [], priorities = [], data = []
240+
llvm.mlir.global_dtors dtors = [], priorities = [], data = []
241241

242242
// -----
243243

244244
llvm.func @dtor() {
245245
llvm.return
246246
}
247247

248-
// CHECK: llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32]}
249-
llvm.mlir.global_dtors { dtors = [@dtor], priorities = [0 : i32]}
248+
// CHECK: llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero]
249+
llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero]
250250

251251
// -----
252252

mlir/test/Dialect/LLVMIR/invalid.mlir

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,38 @@ llvm.func @ctor() {
99
llvm.return
1010
}
1111

12-
// expected-error@+1{{mismatch between the number of ctors and the number of priorities}}
13-
llvm.mlir.global_ctors {ctors = [@ctor], priorities = []}
12+
// expected-error@+1{{ctors, priorities, and data must have the same number of elements}}
13+
llvm.mlir.global_ctors ctors = [@ctor], priorities = [], data = [#llvm.zero]
1414

1515
// -----
1616

1717
llvm.func @dtor() {
1818
llvm.return
1919
}
2020

21-
// expected-error@+1{{mismatch between the number of dtors and the number of priorities}}
22-
llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32, 32767 : i32]}
21+
// expected-error@+1{{dtors, priorities, and data must have the same number of elements}}
22+
llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32, 32767 : i32], data = [#llvm.zero]
2323

2424
// -----
2525

2626
// expected-error@+1{{'ctor' does not reference a valid LLVM function}}
27-
llvm.mlir.global_ctors {ctors = [@ctor], priorities = [0 : i32]}
27+
llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero]
2828

2929
// -----
3030

3131
llvm.func @dtor()
3232

3333
// expected-error@+1{{'dtor' does not have a definition}}
34-
llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32]}
34+
llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero]
35+
36+
// -----
37+
38+
llvm.func @dtor() {
39+
llvm.return
40+
}
41+
42+
// expected-error@+1{{data element must be symbol or #llvm.zero}}
43+
llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [0 : i32]
3544

3645
////////////////////////////////////////////////////////////////////////////////
3746

mlir/test/Target/LLVMIR/Import/global-variables.ll

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@
241241

242242
; // -----
243243

244-
; CHECK: llvm.mlir.global_ctors {ctors = [@foo, @bar], priorities = [0 : i32, 42 : i32]}
245-
; CHECK: llvm.mlir.global_dtors {dtors = [@foo], priorities = [0 : i32]}
244+
; CHECK: llvm.mlir.global_ctors ctors = [@foo, @bar], priorities = [0 : i32, 42 : i32], data = [#llvm.zero, #llvm.zero]
245+
; CHECK: llvm.mlir.global_dtors dtors = [@foo], priorities = [0 : i32], data = [#llvm.zero]
246246
@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 }]
247247
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }]
248248

@@ -256,14 +256,23 @@ define void @bar() {
256256

257257
; // -----
258258

259-
; CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []}
259+
; CHECK: llvm.mlir.global_ctors ctors = [], priorities = [], data = []
260260
@llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
261261

262-
; CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []}
262+
; CHECK: llvm.mlir.global_dtors dtors = [], priorities = [], data = []
263263
@llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
264264

265265
; // -----
266266

267+
; llvm.mlir.global_dtors dtors = [@foo], priorities = [0 : i32], data = [@foo]
268+
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr @foo }]
269+
270+
define void @foo() {
271+
ret void
272+
}
273+
274+
; // -----
275+
267276
; Visibility attribute.
268277

269278
; CHECK: llvm.mlir.global external hidden constant @hidden("string")

mlir/test/Target/LLVMIR/Import/import-failure.ll

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,6 @@ define void @unsupported_argument(i64 %arg1) {
6464

6565
; // -----
6666

67-
; global_dtors with non-null data fields cannot be represented in MLIR.
68-
; CHECK: <unknown>
69-
; CHECK-SAME: error: unhandled global variable: @llvm.global_dtors
70-
@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr @foo }]
71-
72-
define void @foo() {
73-
ret void
74-
}
75-
76-
; // -----
77-
7867
; CHECK: import-failure.ll
7968
; CHECK-SAME: error: unsupported TBAA node format: !{{.*}} = !{!{{.*}}, i64 1, !"omnipotent char"}
8069
define dso_local void @tbaa(ptr %0) {

mlir/test/Target/LLVMIR/llvmir.mlir

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,7 +1851,7 @@ llvm.mlir.global linkonce @take_self_address() : !llvm.struct<(i32, !llvm.ptr)>
18511851
// -----
18521852

18531853
// CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }]
1854-
llvm.mlir.global_ctors { ctors = [@foo], priorities = [0 : i32]}
1854+
llvm.mlir.global_ctors ctors = [@foo], priorities = [0 : i32], data = [#llvm.zero]
18551855

18561856
llvm.func @foo() {
18571857
llvm.return
@@ -1860,15 +1860,15 @@ llvm.func @foo() {
18601860
// -----
18611861

18621862
// CHECK: @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
1863-
llvm.mlir.global_ctors {ctors = [], priorities = []}
1863+
llvm.mlir.global_ctors ctors = [], priorities = [], data = []
18641864

18651865
// CHECK: @llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
1866-
llvm.mlir.global_dtors {dtors = [], priorities = []}
1866+
llvm.mlir.global_dtors dtors = [], priorities = [], data = []
18671867

18681868
// -----
18691869

18701870
// CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }]
1871-
llvm.mlir.global_dtors { dtors = [@foo], priorities = [0 : i32]}
1871+
llvm.mlir.global_dtors dtors = [@foo], priorities = [0 : i32], data = [#llvm.zero]
18721872

18731873
llvm.func @foo() {
18741874
llvm.return

mlir/test/mlir-runner/global-constructors.mlir

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
module {
88
llvm.func @printNewline()
99
llvm.func @printI64(i64)
10-
llvm.mlir.global_ctors {ctors = [@ctor], priorities = [0 : i32]}
11-
llvm.mlir.global_dtors {dtors = [@dtor], priorities = [0 : i32]}
10+
llvm.mlir.global_ctors ctors = [@ctor], priorities = [0 : i32], data = [#llvm.zero]
11+
llvm.mlir.global_dtors dtors = [@dtor], priorities = [0 : i32], data = [#llvm.zero]
1212
llvm.func @ctor() {
1313
%0 = llvm.mlir.constant(1 : i64) : i64
1414
llvm.call @printI64(%0) : (i64) -> ()

0 commit comments

Comments
 (0)