-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
[WIP] Remove StorageDead
and StorageLive
statements using MIR locals of type ()
#70004
Conversation
@bors try @rust-timer queue |
Awaiting bors try build completion |
[WIP] Remove `StorageDead` and `StorageLive` statements using MIR locals of type `()` r? @oli-obk
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
let unit_locals: SmallVec<[_; 32]> = | ||
body.local_decls.iter().map(|local| local.ty == tcx.types.unit).collect(); |
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 far from an expert in this code, but what's the need to allocate an array here instead of just indexing into body.local_decls
and comparing the types on line 20?
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.
the code below mutates the body, so we can't hold an immutable at the same time. technically it is doable, but not with the current API. Maybe basic_block_mut
could return a reference to the rest of the body... not sure, but there's still quite some design space available here
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.
Shouldn't you be able to use https://doc.rust-lang.org/nightly/nightly-rustc/rustc/mir/struct.BodyAndCache.html#method.basic_blocks_and_local_decls_mut for that?
☀️ Try build successful - checks-azure |
Queued ba94172 with parent 0f1e814, future comparison URL. |
for block in body.basic_blocks_mut() { | ||
for stmt in &mut block.statements { | ||
match &stmt.kind { | ||
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { |
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.
StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { | |
if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = &stmt.kind { |
Finished benchmarking try commit ba94172, comparison URL. |
|
What uses |
MIR borrowck if I'm not mistaken. From #68622:
|
The failing test looks like this: // https://github.com/rust-lang/rust/issues/55223
union Foo<'a> {
y: &'a (),
long_live_the_unit: &'static (),
}
const FOO: &() = { //~ ERROR any use of this value will cause an error
let y = ();
unsafe { Foo { y: &y }.long_live_the_unit }
};
fn main() {} The error is no longer emitted, which makes sense given the changes |
This runs after borrowck. |
@bjorn3 yeah, was about to comment that. There still seem to be things relying on this though, do const checking passes use optimized MIR maybe? |
If we do this for |
@wesleywiser Yes. My goal was to improve the compiler performance here, so I just checked for |
Maybe do this during codegen of StorageLive and StorageDead? That way const eval won't notice the change, and layout info is already computed previously. |
we should not diverge codegen and const eval. cc @RalfJung a while back I tried making all zsts have integer addresses, that would have worked here, too. there were some problems with it though. please run |
I think Miri will be fine in the sense that this strictly removes UB. The question is, is anything relying on that being UB? But all the relevant analyses should be looking at StorageDead/Live, I assume that will just mean they will be less precise for optimizations that run after this. This removal means that address of ZST locals are (after this pass) guaranteed to remain the same throughout the execution of the function, including ZST locals inside a loop remaining the same for multiple loop iterations: loop {
let x = ();
println!("{:?}", &x as *const _); // prints the same thing each round
} @ecstatic-morse @eddyb I hope our dataflow analyses treat this correctly, i.e. they will treat these locals as being alive throughout the entire function? |
I think the test failure happens because Miri does not mark the locals as deallocated on return like it should. I also noticed that it doesn't initialize locals as dead if It seems like the semantics for Mir used for constant contexts diverge from Mir intended to execute that run-time. I'm not sure how intentional this is, but it doesn't seem great. |
c0ea8f3
to
ee403d6
Compare
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
Hmm, do we use |
I don't think Miri depends on whether this is CTFE or run-time code. We should make sure our dataflow analyses agree! This is observable to the program by checking address identity: by removing This is just an optimization to avoid having to scan the entire body, as that's slow for some big constants: rust/src/librustc_mir/interpret/eval_context.rs Lines 540 to 541 in 5f13820
It should not change anything, as those do not have Storage* anyway. That is a difference in MIR building between constants and run-time, nor a difference in Miri semantics. (Another difference is that MIR in constants gets arithmetic overflow checks even in release mode. Not sure if there are more differences.)
|
That's not true though, except at the outermost scope (and there we might still emit |
I guess this means MIR building changed since @oli-obk introduced this optimization. |
What's more likely IMO is @oli-obk only tried simple examples, and nothing actually needing If you remind me (e.g. later on Zulip) I can try to craft an example that produced (oops, if you saw @RalfJung's comment being edited, it's because apparently, "Quote Reply" on the new GitHub mobile app edits the original comment?! just reported it, I'll try to avoid it until it's fixed) |
… r=tmandry Add utility to find locals that don't use `StorageLive` annotations and use it for `MaybeStorageLive` Addresses rust-lang#70004 (comment) (cc @RalfJung). The only dataflow analysis that is incorrect in this case is `MaybeStorageLive`. `transform/generator.rs` implemented custom handling for this class of locals, but other consumers of this analysis (there's one in [clippy](https://github.com/rust-lang/rust-clippy/blob/513b46793e98ce5b412d388a91f6371d6a9b290b/clippy_lints/src/redundant_clone.rs#L402)) would be incorrect. r? @tmandry
…=tmandry Add utility to find locals that don't use `StorageLive` annotations and use it for `MaybeStorageLive` Addresses rust-lang#70004 (comment) (cc @RalfJung). The only dataflow analysis that is incorrect in this case is `MaybeStorageLive`. `transform/generator.rs` implemented custom handling for this class of locals, but other consumers of this analysis (there's one in [clippy](https://github.com/rust-lang/rust-clippy/blob/513b46793e98ce5b412d388a91f6371d6a9b290b/clippy_lints/src/redundant_clone.rs#L402)) would be incorrect. r? @tmandry
Closing this pull request as Zoxc is stepping back from compiler development; see rust-lang/team#316. |
r? @oli-obk