1
Fork 0

in a Use statement, exploit the fact that type and hence layout are the same for LHS and RHS

This commit is contained in:
Ralf Jung 2018-08-20 15:21:04 +02:00
parent 8ad40479c5
commit 54c81ac989
3 changed files with 44 additions and 15 deletions

View file

@ -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<TyLayout<'tcx>>,
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> { 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. /// 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. /// 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 // 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( fn eval_place_to_op(
&mut self, &mut self,
mir_place: &mir::Place<'tcx>, mir_place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx>> { ) -> EvalResult<'tcx, OpTy<'tcx>> {
use rustc::mir::Place::*; use rustc::mir::Place::*;
Ok(match *mir_place { Ok(match *mir_place {
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer), Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
Local(local) => { Local(local) => {
let op = *self.frame().locals[local].access()?; 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) => { 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)? 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. /// 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<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx>> {
use rustc::mir::Operand::*; use rustc::mir::Operand::*;
let op = match *mir_op { let op = match *mir_op {
// FIXME: do some more logic on `move` to invalidate the old location // FIXME: do some more logic on `move` to invalidate the old location
Copy(ref place) | Copy(ref place) |
Move(ref place) => Move(ref place) =>
self.eval_place_to_op(place)?, self.eval_place_to_op(place, layout)?,
Constant(ref constant) => { Constant(ref constant) => {
let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs()); let layout = from_known_layout(layout, || {
let layout = self.layout_of(ty)?; 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)?; let op = self.const_value_to_op(constant.literal.val)?;
OpTy { op, layout } OpTy { op, layout }
} }
@ -431,7 +459,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
ops: &[mir::Operand<'tcx>], ops: &[mir::Operand<'tcx>],
) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> { ) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> {
ops.into_iter() ops.into_iter()
.map(|op| self.eval_operand(op)) .map(|op| self.eval_operand(op, None))
.collect() .collect()
} }
@ -473,7 +501,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
&mut self, &mut self,
op: &mir::Operand<'tcx>, op: &mir::Operand<'tcx>,
) -> EvalResult<'tcx, ValTy<'tcx>> { ) -> EvalResult<'tcx, ValTy<'tcx>> {
let op = self.eval_operand(op)?; let op = self.eval_operand(op, None)?;
self.read_value(op) self.read_value(op)
} }
pub fn eval_operand_and_read_scalar( pub fn eval_operand_and_read_scalar(

View file

@ -141,7 +141,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
use rustc::mir::Rvalue::*; use rustc::mir::Rvalue::*;
match *rvalue { match *rvalue {
Use(ref operand) => { 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)?; 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() { for (i, operand) in operands.iter().enumerate() {
let op = self.eval_operand(operand)?; let op = self.eval_operand(operand, None)?;
// Ignore zero-sized fields. // Ignore zero-sized fields.
if !op.layout.is_zst() { if !op.layout.is_zst() {
let field_index = active_field_index.unwrap_or(i); 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, _) => { Repeat(ref operand, _) => {
let op = self.eval_operand(operand)?; let op = self.eval_operand(operand, None)?;
let dest = self.force_allocation(dest)?; let dest = self.force_allocation(dest)?;
let length = dest.len(); 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) => { Cast(kind, ref operand, cast_ty) => {
debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest.layout.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)?; self.cast(src, kind, dest)?;
} }

View file

@ -36,7 +36,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
ref targets, ref targets,
.. ..
} => { } => {
let discr_val = self.eval_operand(discr)?; let discr_val = self.eval_operand(discr, None)?;
let discr = self.read_value(discr_val)?; let discr = self.read_value(discr_val)?;
trace!("SwitchInt({:?})", *discr); trace!("SwitchInt({:?})", *discr);
@ -70,7 +70,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
None => None, None => None,
}; };
let func = self.eval_operand(func)?; let func = self.eval_operand(func, None)?;
let (fn_def, sig) = match func.layout.ty.sty { let (fn_def, sig) = match func.layout.ty.sty {
ty::TyFnPtr(sig) => { ty::TyFnPtr(sig) => {
let fn_ptr = self.read_scalar(func)?.to_ptr()?; let fn_ptr = self.read_scalar(func)?.to_ptr()?;