-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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
Option::map_or generates a bunch of garbage IR #46758
Comments
So the main problem is that this pollution goes further than |
@arielb1 I'd like to help with this. Would you consider this a good issue for mentorship? The linked issue suggests this might be hard to tackle...? |
Here is that IR transliterated into Rust syntax to be more readable at a glance. impl Option<String> {
fn map_or(self: *Option<String>, default: i32) {
let personalityslot: struct(*i8, i32);
let t: String;
let ret: i32;
let _12 = true;
let _11 = true;
let _10 = true;
let %3 = if self.ptr == null { 0i64 } else { 1i64 }
match %3 {
0 => goto 'bb2,
1 => goto 'bb4,
_ => goto 'bb3,
}
'bb1:
panic!(personalityslot);
'bb2:
_11 = false;
ret = default;
goto 'bb5;
'bb3:
unreachable!();
'bb4:
_10 = false;
t = *(self as *Some<String> as *String);
_12 = false;
try {
let %20 = (main::{{closure}})(&t);
goto 'bb7;
} catch_unwind {
goto 'cleanup;
}
'bb5:
if _12 {
goto 'bb15;
} else {
goto 'bb8;
}
'bb6:
let %26 = if self.ptr == null { 0i64 } else { 1i64 };
match %26 {
1 => goto 'bb10,
_ => goto 'bb12,
}
'bb7:
ret = %20;
goto 'bb5;
'bb8:
if _11 {
goto 'bb16;
} else {
goto 'bb9;
}
'bb9:
let %32 = if self.ptr == null { 0i64 } else { 1i64 };
match %32 {
1 => goto 'bb18,
_ => goto 'bb20,
}
'bb10:
if _10 {
goto 'bb11;
} else {
goto 'bb1;
}
'bb11:
_10 = false;
ptr::drop_in_place::<String>(self as *Some<String> as *String);
goto 'bb1;
'bb12:
ptr::drop_in_place::<Option<String>>(self);
goto 'bb1;
'bb13:
_11 = false;
goto 'bb6;
'bb14:
if _11 {
goto 'bb13;
} else {
goto 'bb6;
}
'bb15:
_12 = false;
goto 'bb8;
'bb16:
_11 = false;
goto 'bb9;
'bb17:
return ret;
'bb18:
if _10 {
goto 'bb19;
} else {
goto 'bb17;
}
'bb19:
_10 = false;
ptr::drop_in_place::<String>(self as *Some<String> as *String)
goto 'bb17;
'bb20:
ptr::drop_in_place::<Option<String>>(self);
goto 'bb17;
'cleanup:
personalityslot = landingpad();
goto 'bb14;
}
} |
The first thing that stands out is that some of these drop flags (?) are useless. In particular let mut _12 = true;
let mut _11 = true;
if _12 {
_12 = false;
}
if _11 {
_11 = false;
}
// never used again @arielb1 are these somehow tracking whether a non-Drop type has been dropped, which is unnecessary? Or is it more complicated? Eliminating these unused flags would cut the number of basic blocks by about a third. |
These drop flags should trivially disappear in near future as a consequence of us starting to do constant propagation with MIRI. |
Note that initially we'll only run the const-eval to produce warnings, without actually modifying the MIR , to avoid misoptimizations. But we do want to do const-prop soon after. |
Thanks @nagisa @eddyb. MIR constant propagation is nice but in this case some of the drop flags are not controlling any behavior. Check out the drop flags |
Response in #rustc:
I will investigate with Just from the LLVM IR it looks like @arielb1 do you have a sense of where this IR is "garbage"? Which of the basic blocks would you expect us not to be emitting or expect to be simpler? |
IIRC, these drop flags are used if the destructor of one of the types (i.e. |
Would you be able to briefly suggest a path forward for @mrhota or someone else to start working on? |
The MIR cfg is the following - see https://play.rust-lang.org/?gist=a642496d2949e24738b27b030644f833&version=stable (not sure how to upload graphviz graphs):
I'm actually quite unsure of the best way to do it, but it should be possible to turn this into a better generic MIR. This requires some work to look at it and find ways to optimize. |
Might it help to represent Are there MIR passes that need to see the control flow in a conditional drop as control flow? |
Adding more complexity to the MIR shouldn't be needed here IMO. |
Current optimized, generic MIR for Option::map_or contains only two drop flags: This is pretty good already, but not perfect. With I think jump threading, maybe some other opts on (-Zmir-opt-level=4), we get this: which eliminates the closure's drop flag entirely but not the alternative value's (_2) -- maybe too high cost in the pass, not entirely clear. The LLVM IR for the particular case at the top isn't ideal -- we still generate some no-op goto basic blocks -- but I don't think we can do much at the generic MIR level there, it's mostly due to drop(usize) being a no-op. |
I don't think there are any clear further opportunities left that need to be tracked here, vs. just enabling e.g. jump threading by default (as is planned: #117206). |
See e.g.
Which generates this initial IR:
Which is quite a bit of IR for such a little function:
I suspect #46525 might be involved in causing drop elaboration to go crazy
The text was updated successfully, but these errors were encountered: