[mlir][llvm] Support importing magic globals
authorChristian Ulmann <christian.ulmann@nextsilicon.com>
Wed, 4 Jan 2023 10:16:11 +0000 (11:16 +0100)
committerTobias Gysi <tobias.gysi@nextsilicon.com>
Wed, 4 Jan 2023 10:25:55 +0000 (11:25 +0100)
This commit adds support for importing the magic globals "global_ctors"
and "global_dtors" from LLVM IR to the LLVM IR dialect. The import
fails when these globals have a non-null data pointer, as this can
currently not be represented in the corresponding MLIR operations.

Reviewed By: gysit

Differential Revision: https://reviews.llvm.org/D140877

mlir/include/mlir/Target/LLVMIR/ModuleImport.h
mlir/lib/Target/LLVMIR/ModuleImport.cpp
mlir/test/Target/LLVMIR/Import/global-variables.ll
mlir/test/Target/LLVMIR/Import/import-failure.ll

index 27e2b29..2493cbd 100644 (file)
@@ -218,6 +218,9 @@ private:
   /// function entry block.
   FailureOr<Value> 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.
index 750e967..1c0ac6b 100644 (file)
@@ -48,6 +48,16 @@ static std::string diag(llvm::Value &value) {
   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 @@ ModuleImport::ModuleImport(ModuleOp mlirModule,
 }
 
 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();
 }
 
@@ -563,6 +583,54 @@ GlobalOp ModuleImport::processGlobal(llvm::GlobalVariable *globalVar) {
   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.
index 9f6b426..3bf37da 100644 (file)
 ; 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
+}
index 740f055..cba4173 100644 (file)
@@ -67,3 +67,43 @@ define void @dropped_instruction(i64 %arg1) {
 !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
+}