diff options
| author | Félix Fischer <felix91gr@gmail.com> | 2020-04-29 18:59:13 -0400 |
|---|---|---|
| committer | Félix Fischer <felix91gr@gmail.com> | 2020-05-02 00:40:03 -0400 |
| commit | d0dea9f5887c8371279b0b07ce0380f060ca1e99 (patch) | |
| tree | 8430908727076b9c07bc05d20aadd975e76a6330 /src/librustc_mir/transform | |
| parent | e91aebc1a3835b9b420da0c021e211175a724b8d (diff) | |
| download | rust-d0dea9f5887c8371279b0b07ce0380f060ca1e99.tar.gz rust-d0dea9f5887c8371279b0b07ce0380f060ca1e99.zip | |
Added MIR constant propagation of Scalars into function call arguments
- Documented rationale of current solution - Polished documentation
Diffstat (limited to 'src/librustc_mir/transform')
| -rw-r--r-- | src/librustc_mir/transform/const_prop.rs | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 09d8f89676a..a34b9dac428 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -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: + + 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) { + 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( + 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); } |
