From 54c81ac989a6983d8a571482a8de64d2070f690c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Aug 2018 15:21:04 +0200 Subject: [PATCH] in a Use statement, exploit the fact that type and hence layout are the same for LHS and RHS --- src/librustc_mir/interpret/operand.rs | 46 ++++++++++++++++---- src/librustc_mir/interpret/step.rs | 9 ++-- src/librustc_mir/interpret/terminator/mod.rs | 4 +- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 1907b2beeaf..0d7ad146006 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -189,6 +189,22 @@ impl<'tcx> OpTy<'tcx> { } } +// Use the existing layout if given (but sanity check in debug mode), +// or compute the layout. +#[inline(always)] +fn from_known_layout<'tcx>( + layout: Option>, + compute: impl FnOnce() -> EvalResult<'tcx, TyLayout<'tcx>> +) -> EvalResult<'tcx, TyLayout<'tcx>> { + match layout { + None => compute(), + Some(layout) => { + debug_assert_eq!(layout.ty, compute()?.ty); + Ok(layout) + } + } +} + impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Try reading a value in memory; this is interesting particularily for ScalarPair. /// Return None if the layout does not permit loading this as a value. @@ -377,21 +393,25 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } // Evaluate a place with the goal of reading from it. This lets us sometimes - // avoid allocations. + // avoid allocations. If you already know the layout, you can pass it in + // to avoid looking it up again. fn eval_place_to_op( &mut self, mir_place: &mir::Place<'tcx>, + layout: Option>, ) -> EvalResult<'tcx, OpTy<'tcx>> { use rustc::mir::Place::*; Ok(match *mir_place { Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer), Local(local) => { let op = *self.frame().locals[local].access()?; - OpTy { op, layout: self.layout_of_local(self.cur_frame(), local)? } + let layout = from_known_layout(layout, + || self.layout_of_local(self.cur_frame(), local))?; + OpTy { op, layout } }, Projection(ref proj) => { - let op = self.eval_place_to_op(&proj.base)?; + let op = self.eval_place_to_op(&proj.base, None)?; self.operand_projection(op, &proj.elem)? } @@ -406,17 +426,25 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } /// Evaluate the operand, returning a place where you can then find the data. - pub fn eval_operand(&mut self, mir_op: &mir::Operand<'tcx>) -> EvalResult<'tcx, OpTy<'tcx>> { + /// if you already know the layout, you can save two some table lookups + /// by passing it in here. + pub fn eval_operand( + &mut self, + mir_op: &mir::Operand<'tcx>, + layout: Option>, + ) -> EvalResult<'tcx, OpTy<'tcx>> { use rustc::mir::Operand::*; let op = match *mir_op { // FIXME: do some more logic on `move` to invalidate the old location Copy(ref place) | Move(ref place) => - self.eval_place_to_op(place)?, + self.eval_place_to_op(place, layout)?, Constant(ref constant) => { - let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs()); - let layout = self.layout_of(ty)?; + let layout = from_known_layout(layout, || { + let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs()); + self.layout_of(ty) + })?; let op = self.const_value_to_op(constant.literal.val)?; OpTy { op, layout } } @@ -431,7 +459,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { ops: &[mir::Operand<'tcx>], ) -> EvalResult<'tcx, Vec>> { ops.into_iter() - .map(|op| self.eval_operand(op)) + .map(|op| self.eval_operand(op, None)) .collect() } @@ -473,7 +501,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { &mut self, op: &mir::Operand<'tcx>, ) -> EvalResult<'tcx, ValTy<'tcx>> { - let op = self.eval_operand(op)?; + let op = self.eval_operand(op, None)?; self.read_value(op) } pub fn eval_operand_and_read_scalar( diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index f313b486cfa..56281b6688e 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -141,7 +141,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { use rustc::mir::Rvalue::*; match *rvalue { Use(ref operand) => { - let op = self.eval_operand(operand)?; + // Avoid recomputing the layout + let op = self.eval_operand(operand, Some(dest.layout))?; self.copy_op(op, dest)?; } @@ -187,7 +188,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { }; for (i, operand) in operands.iter().enumerate() { - let op = self.eval_operand(operand)?; + let op = self.eval_operand(operand, None)?; // Ignore zero-sized fields. if !op.layout.is_zst() { let field_index = active_field_index.unwrap_or(i); @@ -198,7 +199,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } Repeat(ref operand, _) => { - let op = self.eval_operand(operand)?; + let op = self.eval_operand(operand, None)?; let dest = self.force_allocation(dest)?; let length = dest.len(); @@ -260,7 +261,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { Cast(kind, ref operand, cast_ty) => { debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest.layout.ty); - let src = self.eval_operand(operand)?; + let src = self.eval_operand(operand, None)?; self.cast(src, kind, dest)?; } diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 9b7df90979d..c8be3d1fbff 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -36,7 +36,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { ref targets, .. } => { - let discr_val = self.eval_operand(discr)?; + let discr_val = self.eval_operand(discr, None)?; let discr = self.read_value(discr_val)?; trace!("SwitchInt({:?})", *discr); @@ -70,7 +70,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { None => None, }; - let func = self.eval_operand(func)?; + let func = self.eval_operand(func, None)?; let (fn_def, sig) = match func.layout.ty.sty { ty::TyFnPtr(sig) => { let fn_ptr = self.read_scalar(func)?.to_ptr()?;