-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[LowerGlobalDtors] Skip __cxa_atexit call completely when arg0 is unused #68758
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
Conversation
@llvm/pr-subscribers-lld-wasm @llvm/pr-subscribers-llvm-transforms Author: Sam Clegg (sbc100) ChangesIn emscripten we have a build mode (the default actually) where the runtime never exits and there for Fixes: emscripten-core/emscripten#19993 Full diff: https://github.com/llvm/llvm-project/pull/68758.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp b/llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
index 195c274ff18e2cd..f67a1eb53b8976a 100644
--- a/llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
+++ b/llvm/lib/Transforms/Utils/LowerGlobalDtors.cpp
@@ -140,6 +140,17 @@ static bool runImpl(Module &M) {
{PointerType::get(AtExitFuncTy, 0), VoidStar, VoidStar},
/*isVarArg=*/false));
+ // If __cxa_atexit is defined (e.g. in the case of LTO) and arg0 is not
+ // actually used (i.e. it's dummy/stub function as used in emscripten when
+ // the program never exits) we can simply return early and clear out
+ // @llvm.global_dtors.
+ if (auto F = dyn_cast<Function>(AtExit.getCallee())) {
+ if (F && F->hasExactDefinition() && F->getArg(0)->getNumUses() == 0) {
+ GV->eraseFromParent();
+ return true;
+ }
+ }
+
// Declare __dso_local.
Type *DsoHandleTy = Type::getInt8Ty(C);
Constant *DsoHandle = M.getOrInsertGlobal("__dso_handle", DsoHandleTy, [&] {
diff --git a/llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors-unused.ll b/llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors-unused.ll
new file mode 100644
index 000000000000000..a6e7133b2947ee4
--- /dev/null
+++ b/llvm/test/Transforms/LowerGlobalDestructors/lower-global-dtors-unused.ll
@@ -0,0 +1,17 @@
+; RUN: opt -passes=lower-global-dtors -S < %s | FileCheck %s --implicit-check-not=llvm.global_dtors
+
+; Test that @llvm.global_dtors is completely removed if __cxa_atexit
+; is a no-op (i.e. doesn't use its first argument).
+
+declare void @orig_dtor()
+
+define i32 @__cxa_atexit(ptr, ptr, ptr) {
+ ret i32 0
+}
+
+@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [
+ { i32, ptr, ptr } { i32 0, ptr @orig_dtor, ptr null }
+]
+
+; CHECK-NOT: @llvm.global_dtors
+; CHECK-NOT: call void @orig_dtor()
|
I think another approach would be to somehow run GlobalDCE (or something like that) after we generate all the |
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, but I wonder if anyone else has any opinions, since I'm not too familiar with this part of the code base.
Those test failures on CI look real, though. |
In emscripten we have a build mode (the default actually) where the runtime never exits and there for `__cxa_atexit` is a dummy/stub function that does nothing. In this case we would like to be able completely DCE any otherwise-unused global dtor functions.
Adding @sunfishcode who originally wrote this pass and @yln who made it into a generic pass |
The change here looks good to me. I like how it does automatic detection so it avoids needing a flag. |
In emscripten we have a build mode (the default actually) where the runtime never exits and therefore
__cxa_atexit
is a dummy/stub function that does nothing. In this case we would like to be able completely DCE any otherwise-unused global dtor functions.Fixes: emscripten-core/emscripten#19993