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 @@ -57,6 +57,9 @@ /// Converts all global variables of the LLVM module to MLIR global variables. LogicalResult convertGlobals(); + /// Imports the magic globals "global_ctors" and "global_dtors". + LogicalResult processGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar); + /// Stores the mapping between an LLVM value and its MLIR counterpart. void mapValue(llvm::Value *llvm, Value mlir) { mapValue(llvm) = mlir; } 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 @@ -318,9 +318,20 @@ } LogicalResult ModuleImport::convertGlobals() { - for (llvm::GlobalVariable &globalVar : llvmModule->globals()) + for (llvm::GlobalVariable &globalVar : llvmModule->globals()) { + if (globalVar.getName() == "llvm.global_ctors" || + globalVar.getName() == "llvm.global_dtors") { + + if (failed(processGlobalCtorsAndDtors(&globalVar))) + return emitError(UnknownLoc::get(context)) + << "unhandled global variable" << diag(globalVar); + + continue; + } + if (!processGlobal(&globalVar)) return failure(); + } return success(); } @@ -548,6 +559,54 @@ return globals[globalVar] = globalOp; } +LogicalResult +ModuleImport::processGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) { + if (!globalVar->hasInitializer() || !globalVar->hasAppendingLinkage()) + return failure(); + auto *init = dyn_cast(globalVar->getInitializer()); + if (!init) + return failure(); + + SmallVector funcs; + SmallVector prios; + for (llvm::Value *operand : init->operands()) { + auto *aggregate = dyn_cast(operand); + if (!aggregate || aggregate->getNumOperands() != 3) + return failure(); + + auto *prio = dyn_cast(aggregate->getOperand(0)); + auto *func = dyn_cast(aggregate->getOperand(1)); + auto *data = dyn_cast(aggregate->getOperand(2)); + if (!prio || !func || !data) + return failure(); + + // global_ctros and global_dtors with non-null data field are not supported + // in MLIR. + if (!data->isNullValue()) + return failure(); + + funcs.push_back(FlatSymbolRefAttr::get(context, func->getName())); + prios.push_back(prio->getValue().getZExtValue()); + } + + OpBuilder::InsertionGuard guard(builder); + if (!globalInsertionOp) + builder.setInsertionPointToStart(mlirModule.getBody()); + else + builder.setInsertionPointAfter(globalInsertionOp); + + if (globalVar->getName() == "llvm.global_ctors") { + builder.create(UnknownLoc::get(context), + builder.getArrayAttr(funcs), + builder.getI32ArrayAttr(prios)); + return success(); + } + builder.create(UnknownLoc::get(context), + builder.getArrayAttr(funcs), + builder.getI32ArrayAttr(prios)); + 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-DAG: llvm.mlir.global_ctors {ctors = [@foo, @bar], priorities = [0 : i32, 42 : i32]} +; CHECK-DAG: 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 @@ -34,3 +34,43 @@ call void @llvm.gcroot(ptr %arg0, ptr %arg1) ret void } + +; // ----- + +; CHECK: unhandled global variable + +@llvm.global_ctors = global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }] + +define void @foo() { + ret void +} + +; // ----- + +; CHECK: unhandled global variable + +@llvm.global_ctors = appending global [1 x { i32, ptr }] [{ i32, ptr } { i32 0, ptr @foo }] + +define void @foo() { + ret void +} + +; // ----- + +; CHECK: unhandled global variable + +@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr @foo }] + +define void @foo() { + ret void +} + +; // ----- + +; CHECK: unhandled global variable + +@llvm.global_ctors = appending global [1 x { ptr, i32, ptr }] [{ ptr, i32, ptr } { ptr @foo, i32 0, ptr null }] + +define void @foo() { + ret void +}