-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Make -Clinker-plugin-lto compatible with ld64 #118377
Make -Clinker-plugin-lto compatible with ld64 #118377
Conversation
(rustbot has picked a reviewer for you, use r? to override) |
…o-wasm, r=petrochenkov Perform LTO optimisations with wasm-ld + -Clinker-plugin-lto Fixes (partially) rust-lang#60059. Technically, `--target wasm32-unknown-unknown -Clinker-plugin-lto` would complete without errors before, but it was not producing optimized code. At least, it may have been but it was probably not the opt-level people intended. Similarly to rust-lang#118377, this could benefit from a warning about using an explicit libLTO path with LLD, which will ignore it and use its internal LLVM. Especially given we always use lld on wasm targets. I left the code open to that possibility rather than making it perfectly neat.
Rollup merge of rust-lang#118378 - cormacrelf:bugfix/linker-plugin-lto-wasm, r=petrochenkov Perform LTO optimisations with wasm-ld + -Clinker-plugin-lto Fixes (partially) rust-lang#60059. Technically, `--target wasm32-unknown-unknown -Clinker-plugin-lto` would complete without errors before, but it was not producing optimized code. At least, it may have been but it was probably not the opt-level people intended. Similarly to rust-lang#118377, this could benefit from a warning about using an explicit libLTO path with LLD, which will ignore it and use its internal LLVM. Especially given we always use lld on wasm targets. I left the code open to that possibility rather than making it perfectly neat.
r? compiler |
r? compiler |
r? compiler |
It's not worth the potential trouble if it does nothing.
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.
I'm not especially familiar with LTO, but these changes seem reasonable to me from what I can surmise from the description and linked issue. I presume a test isn't possible for this?
cc @michaelwoerister @lqd who know more about linkers
Thanks for the PR, @cormacrelf! Taking a closer look at #60059 (comment) has been on my todo list for a while. I'll try to make some progress here this week. I don't have access to a macOS system these days, but we can try to make sure that CI tests cover this sufficiently. |
(I've assigned myself, but don't let this discourage you from also taking a look, @lqd 🙂) |
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.
First of all, thanks a lot for looking into this, @cormacrelf! The kind of research done in #60059 (comment) is really helpful.
The changes look good to me -- but I have no way of testing this locally. I think we should try to add regression tests for this. We have a test that invokes Clang + LLD, but none that uses ld or ld64. A test similar to this one but with -Clinker-plugin-lto
instead of -Clto
should do the trick. However, I'm wondering how we can mitigate the fact, that ld64's libLTO.dylib is probably too old for rustc's LLVM version...
arg.push(plugin_path); | ||
self.linker_arg(&arg); | ||
// Note that LLD silently ignores these flags. | ||
// It will always use the LLVM it was built with to perform LTO. |
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.
Is this documented somewhere? If so, it would be good to add a link.
I'm not sure if we should emit a warning. It could be super helpful -- but it could also be annoying if you know it's fine but for some reason cannot get rid of the commandline argument.
No worries! I have started doing that on long-standing issues with lots of people butting their head against the problem. It has been good. I agree about regression tests. These flags are going to be load-bearing for some big codebases. As for libLTO, it looks like |
Excellent idea! So, do we basically expect that |
It will work if you use an LLVM/clang version at least as new as rustc for linking. https://doc.rust-lang.org/rustc/linker-plugin-lto.html#toolchain-compatibility lists the compatibility table, but it seems like it hasn't been updated for a while. |
Yes, this observation makes me think that that's rarely the case 🙂:
|
That's a consideration for the docs and the real world users, but what version of clang is used for compiletest? If we know it to be always recent, then using its libLTO in the integration test is on the cards. |
If |
@rust-lang/infra, how realistic is it that we build clang (or at least libLTO.dylib) on macOS, so that we can have integration tests that make sure rustc-driven linker-plugin-LTO works on that platform? I think the clang build would be cached in the docker image alongside the rest of LLVM, right? |
macOS jobs don't run inside (our) Docker images, so we'd have to figure out some caching on Github Actions directly (AFAIK). I have created a Zulip topic for this. |
According to the Zulip discussion, our macOS builders will download their own version of clang and it seems reasonable that we can match that to the LLVM version of the rustc being built. @cormacrelf, do you know if that would help? If we can verify that that downloaded clang will invoke ld64 (instead of e.g. LLD), we should be in a position to regression test that rustc passes the correct arguments to the linker, right? |
I guess that should be part of the test: make rustc print the linker invocation and check that it's ld64 |
We can write some great tests if we get a recent clang and libLTO, that would be fantastic. Clang 16 and 17 should both work, I think, but 17 to be on the safe side. If there are complications upgrading clang, we could at least test the flags work against rust-lld's Darwin mode without it, but we wouldn't be able to do a smoke test for Rust + C cross language inlining, and actual ld64 support would be untested.
Rustc will invoke clang++. And while the linker itself is known as "ld64" to distinguish from the GNU linker, it is invoked by clang as I suppose you want to guard against clang switching its default linker to LLD? I doubt that it will, but we can also just tell clang++ to use an absolute path to a specific linker and pin that down. I forget the incantation for that, it's And may as well also run it with ld64.lld from the same clang build. Heck, you could even run it with a script that invokes |
We'll need to find out how we can get access to that version of clang within run-make tests. This looks promising: rust/src/tools/compiletest/src/lib.rs Line 232 in 767453e
|
I think the way to go here is to make the clang version used for these kinds of tests configurable via the compiler's config.toml (i.e. add an option to bootstrap). The option would then look something like: enum ClangUsedForCrossLangTesting {
/// Don't run the tests (or fail if RUSTBUILD_FORCE_CLANG_BASED_TESTS is set)
None,
/// An externally provided clang version. (we could try to do some sanity checking of versions)
External(Path),
/// Build clang from the LLVM sources used by the compiler
BuildMatching,
} Then the various builders could define what they want to do. If we allow an externally provided clang version, we should be able to run the tests on more builders. @cormacrelf, are you up for looking into this? |
According to LLVM@17 ld64.lld --help: lto_library is obsolete.
As of the optimization levels, there are multiple options for different purposes.
-O * is only for file size optimization. Perhaps, |
☔ The latest upstream changes (presumably #127216) made this pull request unmergeable. Please resolve the merge conflicts. |
@cormacrelf any updates on this? thanks |
Closing this as inactive. Feel free to reöpen this pr or create a new pr if you get the time to work on this. Thanks |
Fixes (partially) #60059. Works with ld64 and ld64.lld. There are other linkers that also need some attention here.
There are also a few warnings we could emit that could make
-Clinker-plugin-lto
easier to use correctly, in particular for Apple toolchains:-Clinker-plugin-lto=<path to libLTO>
, because using LLD, which will use its built-in LLVM-Clinker-plugin-lto
with Apple ld64, but no path to libLTO.dylib provided. LLVM versions likely incompatible-Clinker-plugin-lto=path/to/libLTO.dylib
from an appropriate LLVM toolchain. See [version compatibility table]This PR keeps it to what's necessary to make linker plugin LTO work, but I'm happy to deliver some warnings, seeing as I've just messed around with this particular code.