Skip to content

Commit 128c634

Browse files
committed
also avoid recomputing the layout for unary and binary ops, where possible
1 parent 54c81ac commit 128c634

File tree

3 files changed

+47
-19
lines changed

3 files changed

+47
-19
lines changed

src/librustc_mir/interpret/operand.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -497,19 +497,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
497497

498498
/// We cannot do self.read_value(self.eval_operand) due to eval_operand taking &mut self,
499499
/// so this helps avoid unnecessary let.
500-
pub fn eval_operand_and_read_valty(
500+
#[inline]
501+
pub fn eval_operand_and_read_value(
501502
&mut self,
502503
op: &mir::Operand<'tcx>,
504+
layout: Option<TyLayout<'tcx>>,
503505
) -> EvalResult<'tcx, ValTy<'tcx>> {
504-
let op = self.eval_operand(op, None)?;
506+
let op = self.eval_operand(op, layout)?;
505507
self.read_value(op)
506508
}
507-
pub fn eval_operand_and_read_scalar(
508-
&mut self,
509-
op: &mir::Operand<'tcx>,
510-
) -> EvalResult<'tcx, ScalarMaybeUndef> {
511-
Ok(self.eval_operand_and_read_valty(op)?.to_scalar_or_undef())
512-
}
513509

514510
/// reads a tag and produces the corresponding variant index
515511
pub fn read_discriminant_as_variant_index(

src/librustc_mir/interpret/step.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,33 @@ use rustc::mir::interpret::{EvalResult, Scalar};
88

99
use super::{EvalContext, Machine};
1010

11+
/// Classify whether an operator is "left-homogeneous", i.e. the LHS has the
12+
/// same type as the result.
13+
#[inline]
14+
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
15+
use rustc::mir::BinOp::*;
16+
match op {
17+
Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
18+
Offset | Shl | Shr =>
19+
true,
20+
Eq | Ne | Lt | Le | Gt | Ge =>
21+
false,
22+
}
23+
}
24+
/// Classify whether an operator is "right-homogeneous", i.e. the RHS has the
25+
/// same type as the LHS.
26+
#[inline]
27+
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
28+
use rustc::mir::BinOp::*;
29+
match op {
30+
Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
31+
Eq | Ne | Lt | Le | Gt | Ge =>
32+
true,
33+
Offset | Shl | Shr =>
34+
false,
35+
}
36+
}
37+
1138
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
1239
pub fn inc_step_counter_and_detect_loops(&mut self) -> EvalResult<'tcx, ()> {
1340
/// 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> {
147174
}
148175

149176
BinaryOp(bin_op, ref left, ref right) => {
150-
let left = self.eval_operand_and_read_valty(left)?;
151-
let right = self.eval_operand_and_read_valty(right)?;
177+
let layout = if binop_left_homogeneous(bin_op) { Some(dest.layout) } else { None };
178+
let left = self.eval_operand_and_read_value(left, layout)?;
179+
let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
180+
let right = self.eval_operand_and_read_value(right, layout)?;
152181
self.binop_ignore_overflow(
153182
bin_op,
154183
left,
@@ -158,8 +187,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
158187
}
159188

160189
CheckedBinaryOp(bin_op, ref left, ref right) => {
161-
let left = self.eval_operand_and_read_valty(left)?;
162-
let right = self.eval_operand_and_read_valty(right)?;
190+
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
191+
let left = self.eval_operand_and_read_value(left, None)?;
192+
let layout = if binop_right_homogeneous(bin_op) { Some(left.layout) } else { None };
193+
let right = self.eval_operand_and_read_value(right, layout)?;
163194
self.binop_with_overflow(
164195
bin_op,
165196
left,
@@ -169,8 +200,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
169200
}
170201

171202
UnaryOp(un_op, ref operand) => {
172-
let val = self.eval_operand_and_read_scalar(operand)?;
173-
let val = self.unary_op(un_op, val.not_undef()?, dest.layout)?;
203+
// The operand always has the same type as the result.
204+
let val = self.eval_operand_and_read_value(operand, Some(dest.layout))?;
205+
let val = self.unary_op(un_op, val.to_scalar()?, dest.layout)?;
174206
self.write_scalar(val, dest)?;
175207
}
176208

src/librustc_mir/interpret/terminator/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
144144
target,
145145
..
146146
} => {
147-
let cond_val = self.eval_operand_and_read_scalar(cond)?.not_undef()?.to_bool()?;
147+
let cond_val = self.eval_operand_and_read_value(cond, None)?.to_scalar()?.to_bool()?;
148148
if expected == cond_val {
149149
self.goto_block(target);
150150
} else {
151151
use rustc::mir::interpret::EvalErrorKind::*;
152152
return match *msg {
153153
BoundsCheck { ref len, ref index } => {
154-
let len = self.eval_operand_and_read_scalar(len)
155-
.expect("can't eval len")
154+
let len = self.eval_operand_and_read_value(len, None)
155+
.expect("can't eval len").to_scalar()?
156156
.to_bits(self.memory().pointer_size())? as u64;
157-
let index = self.eval_operand_and_read_scalar(index)
158-
.expect("can't eval index")
157+
let index = self.eval_operand_and_read_value(index, None)
158+
.expect("can't eval index").to_scalar()?
159159
.to_bits(self.memory().pointer_size())? as u64;
160160
err!(BoundsCheck { len, index })
161161
}

0 commit comments

Comments
 (0)