]> git.lizzy.rs Git - rust.git/commitdiff
also avoid recomputing the layout for unary and binary ops, where possible
authorRalf Jung <post@ralfj.de>
Mon, 20 Aug 2018 18:08:24 +0000 (20:08 +0200)
committerRalf Jung <post@ralfj.de>
Wed, 22 Aug 2018 11:08:40 +0000 (13:08 +0200)
src/librustc_mir/interpret/operand.rs
src/librustc_mir/interpret/step.rs
src/librustc_mir/interpret/terminator/mod.rs

index 0d7ad1460060b71890e437ffdafc51ac384f01a4..4257c29bfee1cca7b93dfd9d1113335f665da285 100644 (file)
@@ -497,19 +497,15 @@ pub(super) fn global_to_op(&mut self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, O
 
     /// 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(
index 56281b6688e3148d9f01df09a129b3f374c30a8c..f39a5ee3e4ef23929db5e20e6581935fae1b3435 100644 (file)
@@ -8,6 +8,33 @@
 
 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 @@ fn eval_rvalue_into_place(
             }
 
             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 @@ fn eval_rvalue_into_place(
             }
 
             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 @@ fn eval_rvalue_into_place(
             }
 
             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)?;
             }
 
index c8be3d1fbff2057a3f549d5b94acaa1a43573dd5..82455cacac2d4c759e2e487439068f88d20b3304 100644 (file)
@@ -144,18 +144,18 @@ pub(super) fn eval_terminator(
                 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 })
                         }