diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h --- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h @@ -218,6 +218,9 @@ /// function entry block. FailureOr convertConstantExpr(llvm::Constant *constant); + /// Imports the magic globals "global_ctors" and "global_dtors". + LogicalResult convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar); + /// Builder pointing at where the next instruction should be generated. OpBuilder builder; /// Block to insert the next constant into. diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -48,6 +48,16 @@ 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. @@ -319,9 +329,19 @@ } 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(UnknownLoc::get(context)) + << "unhandled global variable " << diag(globalVar); + } + continue; + } + if (!processGlobal(&globalVar)) return failure(); + } return success(); } @@ -563,6 +583,54 @@ return globals[globalVar] = globalOp; } +LogicalResult +ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) { + if (!globalVar->hasInitializer() || !globalVar->hasAppendingLinkage()) + return failure(); + auto *initializer = + dyn_cast(globalVar->getInitializer()); + if (!initializer) + return failure(); + + SmallVector funcs; + SmallVector priorities; + for (llvm::Value *operand : initializer->operands()) { + auto *aggregate = dyn_cast(operand); + if (!aggregate || aggregate->getNumOperands() != 3) + return failure(); + + auto *priority = dyn_cast(aggregate->getOperand(0)); + auto *func = dyn_cast(aggregate->getOperand(1)); + auto *data = dyn_cast(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( + mlirModule->getLoc(), builder.getArrayAttr(funcs), + builder.getI32ArrayAttr(priorities)); + return success(); + } + globalInsertionOp = builder.create( + mlirModule->getLoc(), builder.getArrayAttr(funcs), + builder.getI32ArrayAttr(priorities)); + return success(); +} + SetVector ModuleImport::getConstantsToConvert(llvm::Constant *constant) { // Traverse the constant dependencies in post order. diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll --- a/mlir/test/Target/LLVMIR/Import/global-variables.ll +++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll @@ -174,3 +174,18 @@ ; 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> , <2 x i32> ]] + +; // ----- + +; 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 +} diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll --- a/mlir/test/Target/LLVMIR/Import/import-failure.ll +++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll @@ -67,3 +67,43 @@ !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 +}