From f14e746b2fb11c638904247ef6764f83448de641 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 23 Jan 2018 16:36:55 +0100 Subject: [PATCH] Enable const prop to also evaluate constants, not just literals --- src/librustc_mir/transform/instcombine.rs | 64 ++++++++++++++++------- 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index 6079e1929b5..25787608e39 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -11,7 +11,7 @@ //! Performs various peephole optimizations. use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local}; -use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock}; +use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; use rustc::mir::{SourceInfo, ARGUMENT_VISIBILITY_SCOPE, TerminatorKind}; use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::middle::const_val::ConstVal; @@ -34,6 +34,7 @@ impl MirPass for InstCombine { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, mir: &mut Mir<'tcx>) { + trace!("InstCombine starting for {:?}", source.def_id); // First, find optimization opportunities. This is done in a pre-pass to keep the MIR // read-only so that we can do global analyses on the MIR in the process (e.g. @@ -46,6 +47,7 @@ impl MirPass for InstCombine { // Then carry out those optimizations. MutVisitor::visit_mir(&mut InstCombineVisitor { optimizations, tcx }, mir); + trace!("InstCombine done for {:?}", source.def_id); } } @@ -199,7 +201,6 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { ConstVal::Value(v) => Some((v, value.ty, c.span)), ConstVal::Unevaluated(did, substs) => { let param_env = self.tcx.param_env(self.source.def_id); - let span = self.tcx.def_span(did); let instance = Instance::resolve( self.tcx, param_env, @@ -211,7 +212,7 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { promoted: None, }; let (value, _, ty) = eval_body(self.tcx, cid, param_env)?; - let val = (value, ty, span); + let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); self.optimizations.constants.insert(c.clone(), val); Some(val) @@ -269,7 +270,24 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { span: Span, ) -> Option> { match *rvalue { - Rvalue::Use(ref op) => self.simplify_operand(op), + // No need to overwrite an already evaluated constant + Rvalue::Use(Operand::Constant(box Constant { + literal: Literal::Value { + value: &ty::Const { + val: ConstVal::Value(_), + .. + }, + }, + .. + })) => None, + // This branch exists for the sanity type check + Rvalue::Use(Operand::Constant(ref c)) => { + assert_eq!(c.ty, place_ty); + self.eval_constant(c) + }, + Rvalue::Use(ref op) => { + self.eval_operand(op) + }, Rvalue::Repeat(..) | Rvalue::Ref(..) | Rvalue::Cast(..) | @@ -392,6 +410,17 @@ impl ConstPropVisitor { cpv.visit_mir(mir); cpv.can_const_prop } + + fn is_our_local(&mut self, mut place: &Place) -> bool { + while let Place::Projection(ref proj) = place { + place = &proj.base; + } + if let Place::Local(local) = *place { + local == self.local + } else { + false + } + } } impl<'tcx> Visitor<'tcx> for ConstPropVisitor { @@ -403,9 +432,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { ) { self.super_statement(block, statement, location); match statement.kind { - StatementKind::SetDiscriminant { place: Place::Local(local), .. } | - StatementKind::Assign(Place::Local(local), _) => { - if local == self.local { + StatementKind::SetDiscriminant { ref place, .. } | + StatementKind::Assign(ref place, _) => { + if self.is_our_local(place) { if self.found_assignment { self.can_const_prop = false; } else { @@ -415,15 +444,13 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { }, StatementKind::InlineAsm { ref outputs, .. } => { for place in outputs { - if let Place::Local(local) = *place { - if local == self.local { - if self.found_assignment { - self.can_const_prop = false; - } else { - self.found_assignment = true - } - return; + if self.is_our_local(place) { + if self.found_assignment { + self.can_const_prop = false; + } else { + self.found_assignment = true } + return; } } } @@ -432,8 +459,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropVisitor { } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { self.super_rvalue(rvalue, location); - if let Rvalue::Ref(_, _, Place::Local(local)) = *rvalue { - if local == self.local { + if let Rvalue::Ref(_, _, ref place) = *rvalue { + if self.is_our_local(place) { self.can_const_prop = false; } } @@ -517,12 +544,13 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { if let Some(value) = self.const_prop(rval, place_ty, span) { self.optimizations.const_prop.insert(location, value); if let Place::Local(local) = *place { - if !self.mir.local_decls[local].is_user_variable + if self.mir.local_kind(local) == LocalKind::Temp && ConstPropVisitor::check(local, self.mir) { trace!("storing {:?} to {:?}", value, local); assert!(self.optimizations.places.insert(local, value).is_none()); } } + return; } } self.super_statement(block, statement, location);