-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[MLIR][LLVMIR] Add support for empty global ctor/dtor lists #128969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MLIR][LLVMIR] Add support for empty global ctor/dtor lists #128969
Conversation
@llvm/pr-subscribers-mlir-llvm Author: Bruno Cardoso Lopes (bcardosolopes) ChangesFull diff: https://github.com/llvm/llvm-project/pull/128969.diff 5 Files Affected:
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 8445e609c2244..edaacb883f0c2 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1071,32 +1071,39 @@ LogicalResult
ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {
if (!globalVar->hasInitializer() || !globalVar->hasAppendingLinkage())
return failure();
- auto *initializer =
- dyn_cast<llvm::ConstantArray>(globalVar->getInitializer());
- if (!initializer)
+ llvm::Constant *initializer = globalVar->getInitializer();
+
+ bool knownInit = isa<llvm::ConstantArray>(initializer) ||
+ isa<llvm::ConstantAggregateZero>(initializer);
+ if (!knownInit)
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();
+ if (auto caInit = dyn_cast<llvm::ConstantArray>(initializer)) {
+ 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();
+ 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();
+ // 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());
+ funcs.push_back(FlatSymbolRefAttr::get(context, func->getName()));
+ priorities.push_back(priority->getValue().getZExtValue());
+ }
}
+ // Note: no action needed for ConstantAggregateZero, which implies empty
+ // ctor/dtor lists.
+
// Insert the global after the last one or at the start of the module.
OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 5cd841ee2df91..c6bfb9566a4e1 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1258,16 +1258,37 @@ LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
auto dtorOp = dyn_cast<GlobalDtorsOp>(op);
if (!ctorOp && !dtorOp)
continue;
- auto range = ctorOp ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
- : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
- auto appendGlobalFn =
- ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
- for (auto symbolAndPriority : range) {
- llvm::Function *f = lookupFunction(
- cast<FlatSymbolRefAttr>(std::get<0>(symbolAndPriority)).getValue());
- appendGlobalFn(*llvmModule, f,
- cast<IntegerAttr>(std::get<1>(symbolAndPriority)).getInt(),
- /*Data=*/nullptr);
+
+ // The empty / zero initialized version of llvm.global_(c|d)tors cannot be
+ // handled by appendGlobalFn logic below, which just ignores empty (c|d)tor
+ // lists. Make sure it gets emitted.
+ if ((ctorOp && ctorOp.getCtors().empty()) ||
+ (dtorOp && dtorOp.getDtors().empty())) {
+ llvm::IRBuilder<llvm::TargetFolder> builder(
+ llvmModule->getContext(),
+ llvm::TargetFolder(llvmModule->getDataLayout()));
+ llvm::Type *eltTy = llvm::StructType::get(
+ builder.getInt32Ty(), builder.getPtrTy(), builder.getPtrTy());
+ llvm::ArrayType *at = llvm::ArrayType::get(eltTy, 0);
+ llvm::Constant *zeroInit = llvm::Constant::getNullValue(at);
+ (void)new llvm::GlobalVariable(
+ *llvmModule, zeroInit->getType(), false,
+ llvm::GlobalValue::AppendingLinkage, zeroInit,
+ ctorOp ? "llvm.global_ctors" : "llvm.global_dtors");
+ } else {
+ auto range = ctorOp
+ ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
+ : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
+ auto appendGlobalFn =
+ ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
+ for (auto symbolAndPriority : range) {
+ llvm::Function *f = lookupFunction(
+ cast<FlatSymbolRefAttr>(std::get<0>(symbolAndPriority)).getValue());
+ appendGlobalFn(
+ *llvmModule, f,
+ cast<IntegerAttr>(std::get<1>(symbolAndPriority)).getInt(),
+ /*Data=*/nullptr);
+ }
}
}
diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir
index 79d1cafabfbed..bd3584de9a405 100644
--- a/mlir/test/Dialect/LLVMIR/global.mlir
+++ b/mlir/test/Dialect/LLVMIR/global.mlir
@@ -233,6 +233,14 @@ llvm.mlir.global_ctors { ctors = [@ctor], priorities = [0 : i32]}
// -----
+// CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []}
+llvm.mlir.global_ctors {ctors = [], priorities = []}
+
+// CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []}
+llvm.mlir.global_dtors {dtors = [], priorities = []}
+
+// -----
+
llvm.func @dtor() {
llvm.return
}
diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll
index fbeda4cd42af8..b809c93d772f5 100644
--- a/mlir/test/Target/LLVMIR/Import/global-variables.ll
+++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll
@@ -256,6 +256,14 @@ define void @bar() {
; // -----
+; CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []}
+@llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+
+; CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []}
+@llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+
+; // -----
+
; Visibility attribute.
; CHECK: llvm.mlir.global external hidden constant @hidden("string")
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 7f9a3ba79d724..db2e08742dbca 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -1859,6 +1859,14 @@ llvm.func @foo() {
// -----
+// CHECK: @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+llvm.mlir.global_ctors {ctors = [], priorities = []}
+
+// CHECK: @llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+llvm.mlir.global_dtors {dtors = [], priorities = []}
+
+// -----
+
// CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }]
llvm.mlir.global_dtors { dtors = [@foo], priorities = [0 : i32]}
|
@llvm/pr-subscribers-mlir Author: Bruno Cardoso Lopes (bcardosolopes) ChangesFull diff: https://github.com/llvm/llvm-project/pull/128969.diff 5 Files Affected:
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 8445e609c2244..edaacb883f0c2 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1071,32 +1071,39 @@ LogicalResult
ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {
if (!globalVar->hasInitializer() || !globalVar->hasAppendingLinkage())
return failure();
- auto *initializer =
- dyn_cast<llvm::ConstantArray>(globalVar->getInitializer());
- if (!initializer)
+ llvm::Constant *initializer = globalVar->getInitializer();
+
+ bool knownInit = isa<llvm::ConstantArray>(initializer) ||
+ isa<llvm::ConstantAggregateZero>(initializer);
+ if (!knownInit)
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();
+ if (auto caInit = dyn_cast<llvm::ConstantArray>(initializer)) {
+ 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();
+ 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();
+ // 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());
+ funcs.push_back(FlatSymbolRefAttr::get(context, func->getName()));
+ priorities.push_back(priority->getValue().getZExtValue());
+ }
}
+ // Note: no action needed for ConstantAggregateZero, which implies empty
+ // ctor/dtor lists.
+
// Insert the global after the last one or at the start of the module.
OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 5cd841ee2df91..c6bfb9566a4e1 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1258,16 +1258,37 @@ LogicalResult ModuleTranslation::convertGlobalsAndAliases() {
auto dtorOp = dyn_cast<GlobalDtorsOp>(op);
if (!ctorOp && !dtorOp)
continue;
- auto range = ctorOp ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
- : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
- auto appendGlobalFn =
- ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
- for (auto symbolAndPriority : range) {
- llvm::Function *f = lookupFunction(
- cast<FlatSymbolRefAttr>(std::get<0>(symbolAndPriority)).getValue());
- appendGlobalFn(*llvmModule, f,
- cast<IntegerAttr>(std::get<1>(symbolAndPriority)).getInt(),
- /*Data=*/nullptr);
+
+ // The empty / zero initialized version of llvm.global_(c|d)tors cannot be
+ // handled by appendGlobalFn logic below, which just ignores empty (c|d)tor
+ // lists. Make sure it gets emitted.
+ if ((ctorOp && ctorOp.getCtors().empty()) ||
+ (dtorOp && dtorOp.getDtors().empty())) {
+ llvm::IRBuilder<llvm::TargetFolder> builder(
+ llvmModule->getContext(),
+ llvm::TargetFolder(llvmModule->getDataLayout()));
+ llvm::Type *eltTy = llvm::StructType::get(
+ builder.getInt32Ty(), builder.getPtrTy(), builder.getPtrTy());
+ llvm::ArrayType *at = llvm::ArrayType::get(eltTy, 0);
+ llvm::Constant *zeroInit = llvm::Constant::getNullValue(at);
+ (void)new llvm::GlobalVariable(
+ *llvmModule, zeroInit->getType(), false,
+ llvm::GlobalValue::AppendingLinkage, zeroInit,
+ ctorOp ? "llvm.global_ctors" : "llvm.global_dtors");
+ } else {
+ auto range = ctorOp
+ ? llvm::zip(ctorOp.getCtors(), ctorOp.getPriorities())
+ : llvm::zip(dtorOp.getDtors(), dtorOp.getPriorities());
+ auto appendGlobalFn =
+ ctorOp ? llvm::appendToGlobalCtors : llvm::appendToGlobalDtors;
+ for (auto symbolAndPriority : range) {
+ llvm::Function *f = lookupFunction(
+ cast<FlatSymbolRefAttr>(std::get<0>(symbolAndPriority)).getValue());
+ appendGlobalFn(
+ *llvmModule, f,
+ cast<IntegerAttr>(std::get<1>(symbolAndPriority)).getInt(),
+ /*Data=*/nullptr);
+ }
}
}
diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir
index 79d1cafabfbed..bd3584de9a405 100644
--- a/mlir/test/Dialect/LLVMIR/global.mlir
+++ b/mlir/test/Dialect/LLVMIR/global.mlir
@@ -233,6 +233,14 @@ llvm.mlir.global_ctors { ctors = [@ctor], priorities = [0 : i32]}
// -----
+// CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []}
+llvm.mlir.global_ctors {ctors = [], priorities = []}
+
+// CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []}
+llvm.mlir.global_dtors {dtors = [], priorities = []}
+
+// -----
+
llvm.func @dtor() {
llvm.return
}
diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll
index fbeda4cd42af8..b809c93d772f5 100644
--- a/mlir/test/Target/LLVMIR/Import/global-variables.ll
+++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll
@@ -256,6 +256,14 @@ define void @bar() {
; // -----
+; CHECK: llvm.mlir.global_ctors {ctors = [], priorities = []}
+@llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+
+; CHECK: llvm.mlir.global_dtors {dtors = [], priorities = []}
+@llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+
+; // -----
+
; Visibility attribute.
; CHECK: llvm.mlir.global external hidden constant @hidden("string")
diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir
index 7f9a3ba79d724..db2e08742dbca 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -1859,6 +1859,14 @@ llvm.func @foo() {
// -----
+// CHECK: @llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+llvm.mlir.global_ctors {ctors = [], priorities = []}
+
+// CHECK: @llvm.global_dtors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
+llvm.mlir.global_dtors {dtors = [], priorities = []}
+
+// -----
+
// CHECK: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @foo, ptr null }]
llvm.mlir.global_dtors { dtors = [@foo], priorities = [0 : i32]}
|
Can you expand on why we should not just drop empty decls? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As stated before, can you give an explanation why this is even desired to import? Given that llvm::appendToGlobalCtors
ignores empty lists, this seems like only half way supported.
LLVM IR emitted in our C++ codebase contains If you think this should be represented differently (i.e. not by empty lists), please let me know what approach you'd like to see. |
FWIW, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM from my end.
I added some optional comments, feel free to apply if you think they make sense.
@Dinistro let me know your thoughts! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine for me. Make sure to include parts of this explanation in the commit description.
LGTM!
) LLVM IR emitted in from C++ may contain `@llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer`. Before this PR, if we try to roundtrip code like this from the importer, we'll end up with nothing in place. Note that `llvm::appendToGlobalCtors` ignores empty lists and this PR uses the same approach as `llvm-as`, which doesn't use the utilities from `llvm/lib/Transforms/Utils/ModuleUtils.cpp` in order to build this - it calls into creating a global variable from scratch.
LLVM IR emitted in from C++ may contain
@llvm.global_ctors = appending global [0 x { i32, ptr, ptr }] zeroinitializer
. Before this PR, if we try to roundtrip code like this from the importer, we'll end up with nothing in place.Note that
llvm::appendToGlobalCtors
ignores empty lists and this PR uses the same approach asllvm-as
, which doesn't use the utilities fromllvm/lib/Transforms/Utils/ModuleUtils.cpp
in order to build this - it calls into creating a global variable from scratch.