return os.str();
}
+/// Returns the name of the global_ctors global variables.
+static constexpr StringRef getGlobalCtorsVarName() {
+ return "llvm.global_ctors";
+}
+
+/// Returns the name of the global_dtors global variables.
+static constexpr StringRef getGlobalDtorsVarName() {
+ return "llvm.global_dtors";
+}
+
/// Creates an attribute containing ABI and preferred alignment numbers parsed
/// a string. The string may be either "abi:preferred" or just "abi". In the
/// latter case, the preferred alignment is considered equal to ABI alignment.
}
LogicalResult ModuleImport::convertGlobals() {
- for (llvm::GlobalVariable &globalVar : llvmModule->globals())
+ for (llvm::GlobalVariable &globalVar : llvmModule->globals()) {
+ if (globalVar.getName() == getGlobalCtorsVarName() ||
+ globalVar.getName() == getGlobalDtorsVarName()) {
+ if (failed(convertGlobalCtorsAndDtors(&globalVar))) {
+ return emitError(mlirModule.getLoc())
+ << "unhandled global variable " << diag(globalVar);
+ }
+ continue;
+ }
+
if (!processGlobal(&globalVar))
return failure();
+ }
return success();
}
return globals[globalVar] = globalOp;
}
+LogicalResult
+ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {
+ if (!globalVar->hasInitializer() || !globalVar->hasAppendingLinkage())
+ return failure();
+ auto *initializer =
+ dyn_cast<llvm::ConstantArray>(globalVar->getInitializer());
+ if (!initializer)
+ return failure();
+
+ SmallVector<Attribute> funcs;
+ SmallVector<int32_t> priorities;
+ for (llvm::Value *operand : initializer->operands()) {
+ auto *aggregate = dyn_cast<llvm::ConstantAggregate>(operand);
+ if (!aggregate || aggregate->getNumOperands() != 3)
+ return failure();
+
+ auto *priority = dyn_cast<llvm::ConstantInt>(aggregate->getOperand(0));
+ auto *func = dyn_cast<llvm::Function>(aggregate->getOperand(1));
+ auto *data = dyn_cast<llvm::Constant>(aggregate->getOperand(2));
+ if (!priority || !func || !data)
+ return failure();
+
+ // GlobalCtorsOps and GlobalDtorsOps do not support non-null data fields.
+ if (!data->isNullValue())
+ return failure();
+
+ funcs.push_back(FlatSymbolRefAttr::get(context, func->getName()));
+ priorities.push_back(priority->getValue().getZExtValue());
+ }
+
+ OpBuilder::InsertionGuard guard(builder);
+ if (!globalInsertionOp)
+ builder.setInsertionPointToStart(mlirModule.getBody());
+ else
+ builder.setInsertionPointAfter(globalInsertionOp);
+
+ if (globalVar->getName() == getGlobalCtorsVarName()) {
+ globalInsertionOp = builder.create<LLVM::GlobalCtorsOp>(
+ mlirModule.getLoc(), builder.getArrayAttr(funcs),
+ builder.getI32ArrayAttr(priorities));
+ return success();
+ }
+ globalInsertionOp = builder.create<LLVM::GlobalDtorsOp>(
+ mlirModule.getLoc(), builder.getArrayAttr(funcs),
+ builder.getI32ArrayAttr(priorities));
+ return success();
+}
+
SetVector<llvm::Constant *>
ModuleImport::getConstantsToConvert(llvm::Constant *constant) {
// Traverse the constant dependencies in post order.
; CHECK-SAME: (dense<[{{\[}}[1, 2], [3, 4]]]> : vector<1x2x2xi32>)
; CHECK-SAME: {addr_space = 0 : i32, 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> <i32 1, i32 2>, <2 x i32> <i32 3, i32 4>]]
+
+; // -----
+
+; CHECK: llvm.mlir.global_ctors {ctors = [@foo, @bar], priorities = [0 : i32, 42 : i32]}
+; CHECK: llvm.mlir.global_dtors {dtors = [@foo], priorities = [0 : i32]}
+@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 }]
+
+define void @foo() {
+ ret void
+}
+
+define void @bar() {
+ ret void
+}
!3 = !DILocalVariable(scope: !4, name: "arg", file: !2, line: 1, arg: 1, align: 32);
!4 = distinct !DISubprogram(name: "intrinsic", scope: !2, file: !2, spFlags: DISPFlagDefinition, unit: !1)
!5 = !DILocation(line: 1, column: 2, scope: !4)
+
+; // -----
+
+; global_ctors requires the appending linkage type.
+; CHECK: error: unhandled global variable @llvm.global_ctors
+@llvm.global_ctors = global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }]
+
+define void @foo() {
+ ret void
+}
+
+; // -----
+
+; global_dtors with non-null data fields cannot be represented in MLIR.
+; CHECK: 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
+}
+
+; // -----
+
+; global_ctors without a data field should not be imported.
+; CHECK: error: unhandled global variable @llvm.global_ctors
+@llvm.global_ctors = appending global [1 x { i32, ptr }] [{ i32, ptr } { i32 0, ptr @foo }]
+
+define void @foo() {
+ ret void
+}
+
+; // -----
+
+; global_dtors with a wrong argument order should not be imported.
+; CHECK: error: unhandled global variable @llvm.global_dtors
+@llvm.global_dtors = appending global [1 x { ptr, i32, ptr }] [{ ptr, i32, ptr } { ptr @foo, i32 0, ptr null }]
+
+define void @foo() {
+ ret void
+}