-
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
Fix cases where std accidentally relied on inline(never) #118770
Conversation
Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt |
1675ad6
to
5cf889e
Compare
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 left a couple of nits. I don't feel like I understand what's going on here well enough to confidently give an r+ :/
@@ -216,7 +216,11 @@ where | |||
// the bottom of the loop based on reachability. |
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.
This comment should be updated to explain why start_fn
gets special treatment.
Do you mean that you don't understand this part of the compiler, you don't understand the motivation for the change, or you don't understand the way I've decided to change the handling of |
A little bit of all three! |
Okay! I'll try to start from the beginning and explain everything. The standard library has a feature called rust/library/core/src/panicking.rs Lines 46 to 52 in 5b8bc56
and also all the formatting code they pull in. Currently (I hope to change this eventually), we use The LLVM With This can go wrong if So. The problem pattern here is that we add The best way to find these cases is to apply our So I made that change then tried to build the compiler with The first errors were for rust/library/core/src/intrinsics.rs Lines 1068 to 1092 in 028b6d1
rust/compiler/rustc_codegen_ssa/src/mir/block.rs Lines 682 to 685 in 028b6d1
MirUsedCollector adds mono items.
With that fixed, I got an undefined reference to rust/compiler/rustc_monomorphize/src/collector.rs Lines 1246 to 1256 in 028b6d1
InstantiationMode::GloballyShared items, then stick onto each CGU all the items that are reachable from the contents of the CGU. But if lang_start gets InstantiationMode::LocalCopy then it's not a root item and it's of course not called from anywhere. So CGU partitioning just forgets about it.
Then with that fixed, the compiler bootstraps with Phew that's a lot of text. Does this help? |
if let ty::InstanceDef::Intrinsic(def_id) = instance.def { | ||
let name = tcx.item_name(def_id); | ||
if let Some(_requirement) = ValidityRequirement::from_intrinsic(name) { | ||
let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap(); |
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.
A comment on this block, possibly mentioning assert_inhabited
, assert_zero_valid
, and assert_mem_uniniitalized_valid
, would help a lot.
Thanks, that explanation definitely helps. I think it'll be good to merge once the comments I've requested have been added. They don't need to be as long as the explanation above, but some information in comments will be very helpful. The chances of a casual reader following git blame back to this PR and then seeing that long explanation aren't that high. |
5cf889e
to
7c68407
Compare
Took a shot at adding such comments, don't hesitate to ask for more detail if you think it is merited. |
// Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items | ||
// are handled at the bottom of the loop based on reachability, with one exception. | ||
// The #[lang = "start"] item is the program entrypoint, so there are no calls to it in MIR. | ||
// So even if its mode is LocalCopy need to treat it like a root. |
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.
// So even if its mode is LocalCopy need to treat it like a root. | |
// So even if its mode is LocalCopy we need to treat it like a root. |
Much improved! Thanks. One tiny nit. @bors delegate=saethlin |
✌️ @saethlin, you can now approve this pull request! If @nnethercote told you to " |
7c68407
to
e559172
Compare
@bors r=nnethercote |
…nnethercote Fix cases where std accidentally relied on inline(never) This PR increases the power of `-Zcross-crate-inline-threshold=always` so that it applies through `#[inline(never)]`. Note that though this is called "cross-crate-inlining" in this case especially it is _just_ lazy per-CGU codegen. The MIR inliner and LLVM still respect the attribute as much as they ever have. Trying to bootstrap with the new `-Zcross-crate-inline-threshold=always` change revealed two bugs: We have special intrinsics `assert_inhabited`, `assert_zero_valid`, and `assert_mem_uniniitalized_valid` which codegen backends will lower to nothing or a call to `panic_nounwind`. Since we may not have any call to `panic_nounwind` in MIR but emit one anyway, we need to specially tell `MirUsedCollector` about this situation. `#[lang = "start"]` is special-cased already so that `MirUsedCollector` will collect it, but then when we make it cross-crate-inlinable it is only assigned to a CGU based on whether `MirUsedCollector` saw a call to it, which of course we didn't. --- I started looking into this because rust-lang#118683 revealed a case where we were accidentally relying on a function being `#[inline(never)]`, and cranking up cross-crate-inlinability seems like a way to find other situations like that. r? `@nnethercote` because I don't like what I'm doing to the CGU partitioning code here but I can't come up with something much better
…llaumeGomez Rollup of 4 pull requests Successful merges: - rust-lang#118770 (Fix cases where std accidentally relied on inline(never)) - rust-lang#118910 ([rustdoc] Use Map instead of Object for source files and search index) - rust-lang#118914 (Unconditionally register alias-relate in projection goal) - rust-lang#118935 (interpret: extend comment on the inhabitedness check in downcast) r? `@ghost` `@rustbot` modify labels: rollup
…ethercote Fix cases where std accidentally relied on inline(never) This PR increases the power of `-Zcross-crate-inline-threshold=always` so that it applies through `#[inline(never)]`. Note that though this is called "cross-crate-inlining" in this case especially it is _just_ lazy per-CGU codegen. The MIR inliner and LLVM still respect the attribute as much as they ever have. Trying to bootstrap with the new `-Zcross-crate-inline-threshold=always` change revealed two bugs: We have special intrinsics `assert_inhabited`, `assert_zero_valid`, and `assert_mem_uniniitalized_valid` which codegen backends will lower to nothing or a call to `panic_nounwind`. Since we may not have any call to `panic_nounwind` in MIR but emit one anyway, we need to specially tell `MirUsedCollector` about this situation. `#[lang = "start"]` is special-cased already so that `MirUsedCollector` will collect it, but then when we make it cross-crate-inlinable it is only assigned to a CGU based on whether `MirUsedCollector` saw a call to it, which of course we didn't. --- I started looking into this because rust-lang#118683 revealed a case where we were accidentally relying on a function being `#[inline(never)]`, and cranking up cross-crate-inlinability seems like a way to find other situations like that. r? `@nnethercote` because I don't like what I'm doing to the CGU partitioning code here but I can't come up with something much better
The job Click to see the possible cause of the failure (guessed by this bot)
|
💔 Test failed - checks-actions |
I don't remember if the thing to do here is re-add the approval or retry... @bors r=nnethercote |
💡 This pull request was already approved, no need to approve it again.
|
…ethercote Fix cases where std accidentally relied on inline(never) This PR increases the power of `-Zcross-crate-inline-threshold=always` so that it applies through `#[inline(never)]`. Note that though this is called "cross-crate-inlining" in this case especially it is _just_ lazy per-CGU codegen. The MIR inliner and LLVM still respect the attribute as much as they ever have. Trying to bootstrap with the new `-Zcross-crate-inline-threshold=always` change revealed two bugs: We have special intrinsics `assert_inhabited`, `assert_zero_valid`, and `assert_mem_uniniitalized_valid` which codegen backends will lower to nothing or a call to `panic_nounwind`. Since we may not have any call to `panic_nounwind` in MIR but emit one anyway, we need to specially tell `MirUsedCollector` about this situation. `#[lang = "start"]` is special-cased already so that `MirUsedCollector` will collect it, but then when we make it cross-crate-inlinable it is only assigned to a CGU based on whether `MirUsedCollector` saw a call to it, which of course we didn't. --- I started looking into this because rust-lang#118683 revealed a case where we were accidentally relying on a function being `#[inline(never)]`, and cranking up cross-crate-inlinability seems like a way to find other situations like that. r? `@nnethercote` because I don't like what I'm doing to the CGU partitioning code here but I can't come up with something much better
The job Click to see the possible cause of the failure (guessed by this bot)
|
still seems like a network issue? @bors retry rollup=iffy |
☀️ Test successful - checks-actions |
Finished benchmarking commit (1559dd2): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 670.068s -> 671.548s (0.22%) |
…lls, r=Nilstrieb Only allow compiler_builtins to call LLVM intrinsics, not any link_name function This is another case of accidental reliance on `inline(never)` like I rooted out in rust-lang#118770. Without this PR, attempting to build some large programs with `-Zcross-crate-inline-threshold=yes` with a sysroot also compiled with that flag will result in linker errors like this: ``` = note: /usr/bin/ld: /tmp/cargo-installNrfN4T/x86_64-unknown-linux-gnu/release/deps/libcompiler_builtins-d2a9b69f4e45b883.rlib(compiler_builtins-d2a9b69f4e45b883.compiler_builtins.dbbc6c2ca970faa4-cgu.0.rcgu.o): in function `core::panicking::panic_fmt': /home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:72:(.text.unlikely._ZN4core9panicking9panic_fmt17ha407cc99e97c942fE+0x31): undefined reference to `rust_begin_unwind' ``` With `-Zcross-crate-inline-threshold=yes` we can inline `panic_fmt` into `compiler_builtins`. Then we end up with a call to an upstream monomorphization, but one that has a `link_name` set. But unlike LLVM's magic intrinsic names, this link name is going to make it to the linker, and then we have a problem. This logic looks scuffed, but also we're doing this in 4 other places. Don't know if that means it's good or bad. https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_codegen_cranelift/src/abi/mod.rs#L386 https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_ast_passes/src/feature_gate.rs#L306 https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_codegen_ssa/src/codegen_attrs.rs#L609 https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_codegen_gcc/src/declare.rs#L170
…lstrieb Only allow compiler_builtins to call LLVM intrinsics, not any link_name function This is another case of accidental reliance on `inline(never)` like I rooted out in rust-lang/rust#118770. Without this PR, attempting to build some large programs with `-Zcross-crate-inline-threshold=yes` with a sysroot also compiled with that flag will result in linker errors like this: ``` = note: /usr/bin/ld: /tmp/cargo-installNrfN4T/x86_64-unknown-linux-gnu/release/deps/libcompiler_builtins-d2a9b69f4e45b883.rlib(compiler_builtins-d2a9b69f4e45b883.compiler_builtins.dbbc6c2ca970faa4-cgu.0.rcgu.o): in function `core::panicking::panic_fmt': /home/ben/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/panicking.rs:72:(.text.unlikely._ZN4core9panicking9panic_fmt17ha407cc99e97c942fE+0x31): undefined reference to `rust_begin_unwind' ``` With `-Zcross-crate-inline-threshold=yes` we can inline `panic_fmt` into `compiler_builtins`. Then we end up with a call to an upstream monomorphization, but one that has a `link_name` set. But unlike LLVM's magic intrinsic names, this link name is going to make it to the linker, and then we have a problem. This logic looks scuffed, but also we're doing this in 4 other places. Don't know if that means it's good or bad. https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_codegen_cranelift/src/abi/mod.rs#L386 https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_ast_passes/src/feature_gate.rs#L306 https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_codegen_ssa/src/codegen_attrs.rs#L609 https://github.com/rust-lang/rust/blob/1684a753dbca5d23b2e03568e6fbbb48eb72d0e6/compiler/rustc_codegen_gcc/src/declare.rs#L170
This PR increases the power of
-Zcross-crate-inline-threshold=always
so that it applies through#[inline(never)]
. Note that though this is called "cross-crate-inlining" in this case especially it is just lazy per-CGU codegen. The MIR inliner and LLVM still respect the attribute as much as they ever have.Trying to bootstrap with the new
-Zcross-crate-inline-threshold=always
change revealed two bugs:We have special intrinsics
assert_inhabited
,assert_zero_valid
, andassert_mem_uniniitalized_valid
which codegen backends will lower to nothing or a call topanic_nounwind
. Since we may not have any call topanic_nounwind
in MIR but emit one anyway, we need to specially tellMirUsedCollector
about this situation.#[lang = "start"]
is special-cased already so thatMirUsedCollector
will collect it, but then when we make it cross-crate-inlinable it is only assigned to a CGU based on whetherMirUsedCollector
saw a call to it, which of course we didn't.I started looking into this because #118683 revealed a case where we were accidentally relying on a function being
#[inline(never)]
, and cranking up cross-crate-inlinability seems like a way to find other situations like that.r? @nnethercote because I don't like what I'm doing to the CGU partitioning code here but I can't come up with something much better