about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-08-20 20:08:24 +0200
committerRalf Jung <post@ralfj.de>2018-08-22 13:08:40 +0200
commit128c634c7f14ad4a0400c53856e720bfb2cdff36 (patch)
tree70c64377991c1d7e7c13a152afba116c24de3caa
parent54c81ac989a6983d8a571482a8de64d2070f690c (diff)
downloadrust-128c634c7f14ad4a0400c53856e720bfb2cdff36.tar.gz
rust-128c634c7f14ad4a0400c53856e720bfb2cdff36.zip
also avoid recomputing the layout for unary and binary ops, where possible
-rw-r--r--src/librustc_mir/interpret/operand.rs12
-rw-r--r--src/librustc_mir/interpret/step.rs44
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs10
3 files changed, 47 insertions, 19 deletions
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 0d7ad146006..4257c29bfee 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -497,19 +497,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
     /// We cannot do self.read_value(self.eval_operand) due to eval_operand taking &mut self,
     /// so this helps avoid unnecessary let.
-    pub fn eval_operand_and_read_valty(
+    #[inline]
+    pub fn eval_operand_and_read_value(
         &mut self,
         op: &mir::Operand<'tcx>,
+        layout: Option<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, ValTy<'tcx>> {
-        let op = self.eval_operand(op, None)?;
+        let op = self.eval_operand(op, layout)?;
         self.read_value(op)
     }
-    pub fn eval_operand_and_read_scalar(
-        &mut self,
-        op: &mir::Operand<'tcx>,
-    ) -> EvalResult<'tcx, ScalarMaybeUndef> {
-        Ok(self.eval_operand_and_read_valty(op)?.to_scalar_or_undef())
-    }
 
     /// reads a tag and produces the corresponding variant index
     pub fn read_discriminant_as_variant_index(
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 56281b6688e..f39a5ee3e4e 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -8,6 +8,33 @@ use rustc::mir::interpret::{EvalResult, Scalar};
 
 use super::{EvalContext, Machine};
 
+/// Classify whether an operator is "left-homogeneous", i.e. the LHS has the
+/// same type as the result.
+#[inline]
+fn binop_left_homogeneous(op: mir::BinOp) -> bool {
+    use rustc::mir::BinOp::*;
+    match op {
+        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
+        Offset | Shl | Shr =>
+            true,
+        Eq | Ne | Lt | Le | Gt | Ge =>
+            false,
+    }
+}
+/// Classify whether an operator is "right-homogeneous", i.e. the RHS has the
+/// same type as the LHS.
+#[inline]
+fn binop_right_homogeneous(op: mir::BinOp) -> bool {
+    use rustc::mir::BinOp::*;
+    match op {
+        Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
+        Eq | Ne | Lt | Le | Gt | Ge =>
+            true,
+        Offset | Shl | Shr =>
+            false,
+    }
+}
+
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
         /// The number of steps between loop detector snapshots.
@@ -147,8 +174,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
 
             BinaryOp(bin_op, ref left, ref right) => {
-                let left = self.eval_operand_and_read_valty(left)?;
-                let right = self.eval_operand_and_read_valty(right)?;
+                let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None };
+                let left = self.eval_operand_and_read_value(left, layout)?;
+                let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
+                let right = self.eval_operand_and_read_value(right, layout)?;
                 self.binop_ignore_overflow(
                     bin_op,
                     left,
@@ -158,8 +187,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
 
             CheckedBinaryOp(bin_op, ref left, ref right) => {
-                let left = self.eval_operand_and_read_valty(left)?;
-                let right = self.eval_operand_and_read_valty(right)?;
+                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
+                let left = self.eval_operand_and_read_value(left, None)?;
+                let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
+                let right = self.eval_operand_and_read_value(right, layout)?;
                 self.binop_with_overflow(
                     bin_op,
                     left,
@@ -169,8 +200,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
 
             UnaryOp(un_op, ref operand) => {
-                let val = self.eval_operand_and_read_scalar(operand)?;
-                let val = self.unary_op(un_op, val.not_undef()?, dest.layout)?;
+                // The operand always has the same type as the result.
+                let val = self.eval_operand_and_read_value(operand, Some(dest.layout))?;
+                let val = self.unary_op(un_op, val.to_scalar()?, dest.layout)?;
                 self.write_scalar(val, dest)?;
             }
 
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index c8be3d1fbff..82455cacac2 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -144,18 +144,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 target,
                 ..
             } => {
-                let cond_val = self.eval_operand_and_read_scalar(cond)?.not_undef()?.to_bool()?;
+                let cond_val = self.eval_operand_and_read_value(cond, None)?.to_scalar()?.to_bool()?;
                 if expected == cond_val {
                     self.goto_block(target);
                 } else {
                     use rustc::mir::interpret::EvalErrorKind::*;
                     return match *msg {
                         BoundsCheck { ref len, ref index } => {
-                            let len = self.eval_operand_and_read_scalar(len)
-                                .expect("can't eval len")
+                            let len = self.eval_operand_and_read_value(len, None)
+                                .expect("can't eval len").to_scalar()?
                                 .to_bits(self.memory().pointer_size())? as u64;
-                            let index = self.eval_operand_and_read_scalar(index)
-                                .expect("can't eval index")
+                            let index = self.eval_operand_and_read_value(index, None)
+                                .expect("can't eval index").to_scalar()?
                                 .to_bits(self.memory().pointer_size())? as u64;
                             err!(BoundsCheck { len, index })
                         }