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> {
/// 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<TyLayout<'tcx>>,
) -> 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<TyLayout<'tcx>>,
) -> 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<OpTy<'tcx>>> {
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(

View File

@ -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)?;
}

View File

@ -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()?;