-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Added MIR constant propagation of Scalars into function call arguments #71697
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -787,6 +787,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { | |
| NonMutatingUse(NonMutatingUseContext::Inspect) | ||
| NonMutatingUse(NonMutatingUseContext::Projection) | ||
| NonUse(_) => {} | ||
// FIXME(felix91gr): explain the reasoning behind this | ||
MutatingUse(MutatingUseContext::Projection) => { | ||
if self.local_kinds[local] != LocalKind::Temp { | ||
self.can_const_prop[local] = ConstPropMode::NoPropagation; | ||
|
@@ -969,13 +970,58 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | |
| TerminatorKind::GeneratorDrop | ||
| TerminatorKind::FalseEdges { .. } | ||
| TerminatorKind::FalseUnwind { .. } => {} | ||
//FIXME(wesleywiser) Call does have Operands that could be const-propagated | ||
TerminatorKind::Call { .. } => {} | ||
// Every argument in our function calls can be const propagated. | ||
TerminatorKind::Call { ref mut args, .. } => { | ||
let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level; | ||
// Constant Propagation into function call arguments is gated | ||
// under mir-opt-level 2, because LLVM codegen gives performance | ||
// regressions with it. | ||
if mir_opt_level >= 2 { | ||
for opr in args { | ||
/* | ||
The following code would appear to be incomplete, because | ||
the function `Operand::place()` returns `None` if the | ||
`Operand` is of the variant `Operand::Constant`. In this | ||
context however, that variant will never appear. This is why: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fn main() {
foo(42);
}
fn foo(i: i32) {} But that's already "propagated" so it's fine and we don't need to care about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It took me a while to realize what you meant. But indeed! Those are already "propagated": https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9bfca57ccf6c252f7e601ed58beb7895 Should I add something to the comment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, I think the comment should be adjusted. It's not that an |
||
|
||
When constructing the MIR, all function call arguments are | ||
copied into `Locals` of `LocalKind::Temp`. At least, all arguments | ||
that are not unsized (Less than 0.1% are unsized. See #71170 | ||
to learn more about those). | ||
|
||
This means that, conversely, all `Operands` found as function call | ||
arguments are of the variant `Operand::Copy`. This allows us to | ||
simplify our handling of `Operands` in this case. | ||
*/ | ||
if let Some(l) = opr.place().and_then(|p| p.as_local()) { | ||
if let Some(value) = self.get_const(l) { | ||
felix91gr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if self.should_const_prop(value) { | ||
// FIXME(felix91gr): this code only handles `Scalar` cases. | ||
// For now, we're not handling `ScalarPair` cases because | ||
// doing so here would require a lot of code duplication. | ||
// We should hopefully generalize `Operand` handling into a fn, | ||
// and use it to do const-prop here and everywhere else | ||
// where it makes sense. | ||
if let interpret::Operand::Immediate( | ||
interpret::Immediate::Scalar( | ||
felix91gr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
interpret::ScalarMaybeUndef::Scalar(scalar), | ||
), | ||
) = *value | ||
{ | ||
*opr = self.operand_from_scalar( | ||
scalar, | ||
value.layout.ty, | ||
source_info.span, | ||
); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
// We remove all Locals which are restricted in propagation to their containing blocks. | ||
// We wouldn't need to clone, but the borrow checker can't see that we're not aliasing | ||
// the locals_of_current_block field, so we need to clone it first. | ||
// let ecx = &mut self.ecx; | ||
for local in self.locals_of_current_block.iter() { | ||
Self::remove_const(&mut self.ecx, local); | ||
} | ||
|
Uh oh!
There was an error while loading. Please reload this page.