Change:
I got a segfault / LLVM assertion failure while compiling a target with ThinLTO enabled. This is the same failure as in , albeit with a different root cause. In my case, I was dealing with a global named . Note the presence of two extensions. This means that this was a local which was promoted to a global symbol twice. The of doesn't handle this case correctly; it strips off both extensions: The fix is actually trivial; just have to change to so that it only removes the last_ extension. Leaving this issue open to track the fix being cherry-picked.
Filed a bug .
This might still be a rustc bug, since apparently a double-promotion is unexpected. Working on a minimal repro now.
is this something that we could/should be pulling in the ICE-breakers on?
triage: P-high. Assigning to and removing I-nominated label.
Possibly, but I’ll need to put a usable reproducer somewhere. That tends to be more difficult when the target is Fuchsia. I’ve had limited success doing all the minimizing myself. I’ll see if I can reproduce on other targets, and upload a reproducer if so.
So, from the output of , what appears to be happening is that we run the same bitcode through the ThinLTO optimization pipeline twice. Once when outputting an rlib, and once when linking to that rlib. More specifically: rlib crate ( in this case) gets compiled with ThinLTO and optimizations enabled. We run the bitcode through the ThinLTO optimization pipeline. results in a lot of files that look like binary crate is compiled which depends on the rlib. It is also compiled with ThinLTO and optimizations. again results in a lot of files that look like (except and everything after it are missing, because it crashes) the file is the output of the ThinLTO pipeline from the previous step The offending symbol is promoted to a global once in the first optimization run and again in the second, which accounts for the two suffixes on it. The crash occurs because it's not expected for a symbol to be promoted twice. I can't think of a reason why we would run the same pipeline twice on the same bitcode. Is there one?
cc
are you compiling with , or just normal ? The former will run some bitcode through thinlto twice, but the latter shouldn't. If the bug happens by running bitcode through twice, that's like where it's coming from?
Ahh you were right, it has to do with the flags! For the rlib I wasn't passing , but for the executable I was. As soon as I started passing for both, the problem went away and we only sent the code through the pipeline once. (EDIT: I was using in both) Apparently we've been doing this for a very long time in Fuchsia without problems. So is it expected that we should be passing to both?
Oh weird, so I didn't expect that to fix anything nor did I think that the compiler does what it does! Looks like it boils down to which explains: The final executable means that all bitcode will run through ThinLTO. If the rlib bitcode was previously run through ThinLTO, then it would be run through twice. That match statement, however, means that if you () then we skip the thinlto step in rlibs assuming you'll do it at the end. So it looks like, yes, you'll want to pass to all compilations, not just the final one. And that should do the trick! I would still consider this an LLVM bug though because it should in theory work both ways...
Agreed on this still being a bug. Also, as it turns out, the old way of doing it is faster for our build! Presumably since we're doing more work up front. For progeny, I'm posting the data here. Here are a couple runs before adding to the rlib builds: Here are a couple runs after: This is on a 72-core machine building a pretty large graph of Rust crates (many executables).
Interesting, not the results I would have expected! If you have a lot of executables though and you're running ThinLTO on all of them then you're likely basically optimizing the same code over and over. Before each crate was individually pretty heavily optimized, doing those optimizations only once instead of once for each executable. Afterwards, however, ThinLTO-per-crate doesn't happen and only happens at the end. This probably produces roughly equivalent code in terms of speed, but each executable has to run more optimizations.
Right, so by doing more of that work upfront in the rlibs, we save time optimizing the code for each executable. I think there's still a more efficient way of doing all this. For one, we could disable the actual object file output for rlibs. Also, when compiling the executable, the whole ThinLTO pipeline is run again on the individual crate bitcode before building summaries and distributing the codegen to workers. If there were a way to disable that and tell the compiler to assume that rlib bitcode has already been optimized, we could save some time here. Perhaps we could make that automatic with a flag that emits the summary with the rlib, and detect that it's already there in the executable compile. Of course I'm talking about how to optimize a completely-unintended way of using Rust's ThinLTO pipeline. But since it happens to be faster, it might be worth experimenting with. :)
Heh perhaps! In theory optimization pipelines are quite flexible and we can basically design whatever we want, it's all just a matter of implementation and measurement at some point.
Teresa Johnson left some on the downside of doing it this way. To summarize, it can affect what gets inlined (for better or for worse), and it disables whole program devirtualization. We'd have to do some more tinkering with the pipeline and measurement to avoid those issues.
Also, a fix was landed upstream:
Oh something I forgot to reply to earlier This is one of the subjects on actually, and yeah would help quite a bit in your case since all the codegen happening in each crate isn't actually used. A good point! It sounds like this only happens though if we compile with the equivalent of which I don't think we're currently doing? If we do that though this is something good to keep in mind! Yay!
Ah that's all very relevant, thanks. Subscribed :) I opened to track this. Not expecting it to happen anytime soon, but it seems good to have a tracking issue for it.

Discussion:
<del> Subproject commit cd87134ab77e6bacb2128137065b328b9c35e0e5 </del> <ins> Subproject commit a6f4c1bb07d58df5956d2c49be68547143f77b18 </ins>