Skip to content

Commit 00c38d4

Browse files
committed
[MLIR][LLVMIR] Add support for the full form of global_ctor/dtor
Currently only ctor/dtor list and priorities are supported. This PR adds support for the data field. Few implementation notes: - The assembly printer has a fixed form now because just `attr_dict` will sort the dict by key name, making dtor and ctor differ in the order of arguments. - LLVM's `ptr null` is being converted to `#llvm.zero` otherwise we'd have to create a region to use the operation version of `ptr null`, which is silly given that the field only support null or an actual symbol.
1 parent e7e242e commit 00c38d4

File tree

9 files changed

+111
-66
lines changed

9 files changed

+111
-66
lines changed

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

Lines changed: 31 additions & 19 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 `#llvm.zero`,
1452+
functions only run if the data is not discarded.
14531453

14541454
Examples:
14551455

14561456
```mlir
1457-
llvm.mlir.global_ctors {@ctor}
1458-
1457+
llvm.mlir.global_ctors {ctors = [@ctor], data = [#llvm.zero],
1458+
priorities = [0]}
14591459
llvm.func @ctor() {
14601460
...
14611461
llvm.return
14621462
}
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
14791485
referenced by this array will be called in descending order of priority (i.e.
14801486
highest first) when the module is unloaded. The order of functions with the
14811487
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.
1488+
global_dtors global variable. The destruction functions are run at load time.
1489+
However, if the associated data is not `#llvm.zero`, functions only run if the data
1490+
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], data = [#llvm.zero],
1499+
priorities = [0]}
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>(v) || isa<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)