-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
Global destructors not optimized away even with LTO #19993
Comments
I reason
One option might be to allow it to be LTO, but somehow force it to always be included at LTO time (so new references to it don't cause LTO to fail). |
Ah 😄 the answer was right below the code I was reading, thanks! So it would be great to get this into LTO. But how can we force it to be included in order to handle new references? That would take changes inside LLVM I guess? |
it might be enough to just add |
I tried adding What does |
|
I guess it not enough to trigger the inclusion of the symbol at LTO time which is what we need here.. i'll see if I can figure out another way. |
I think I've found a (pretty nasty) way to make this work. |
…sed (#68758) 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
Consider this:
Building with
emcc a.cpp -O3 --profiling-funcs
I would expect the destructor to be optimized away, sinceEXIT_RUNTIME
defaults to false. However, it isn't:The destructor is there, and it calls that import which keeps more code alive.
The destructor is in the table, because an
atexit()
existed to it. WhenEXIT_RUNTIME
is not enabled we link withlibnoexit
, which makesatexit
a no-op. However, the function is already in the table, so later Binaryen optimizations can't remove it.LTO should fix this, but does not: adding
-flto
changes nothing in the output.Trying to investigate that, I added
--mllvm=--print-after-all
in thelld
command. Looking for atexit, I see this:But I never at any point see it defined. I'd expect to see it defined as a function returning 0, because that is what we have in
libnoexit
:emscripten/system/lib/libc/atexit_dummy.c
Line 16 in bc15162
It does get linked in properly, as I see the
lld
command starts with-lGL -lal -lhtml5 -lstubs -lnoexit -lc
(so it's before libc). And I see it properly in the wasm output when I build with say-O1
and without LTO:LTO is definitely running, and e.g. it tries to inline - I see e.g.
*** IR Dump After InlinerPass on (main) ***
- but it doesn't actually inline the trivialcxa_atexit
that is linked in, sadly...Also, I see those
Dump after InlinerPass on (NAME)
on all functions - even libc ones - but not oncxa_atexit
. In fact the only pass LTO runs that mentions it isGiven all that, my best guess is that LLVM LTO isn't looking at
cxa_atexit
for normal optimizations. It seems to treat it in a special way - is that possible?This seems like a pretty significant missed optimization for us. I noticed this on #19903 (comment) but IIUC it affects all default optimized builds that have any global destructors, keeping unneeded code.
cc @sbc100 @aheejin @tlively @dschuff as this is beyond my knowledge of LLVM.
The text was updated successfully, but these errors were encountered: