21 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
22 fn binop_with_overflow(
25 left: &mir::Operand<'tcx>,
26 right: &mir::Operand<'tcx>,
27 ) -> EvalResult<'tcx, (PrimVal, bool)> {
28 let left_ty = self.operand_ty(left);
29 let right_ty = self.operand_ty(right);
30 let left_val = self.eval_operand_to_primval(left)?;
31 let right_val = self.eval_operand_to_primval(right)?;
32 self.binary_op(op, left_val, left_ty, right_val, right_ty)
35 /// Applies the binary operation `op` to the two operands and writes a tuple of the result
36 /// and a boolean signifying the potential overflow to the destination.
37 pub fn intrinsic_with_overflow(
40 left: &mir::Operand<'tcx>,
41 right: &mir::Operand<'tcx>,
44 ) -> EvalResult<'tcx> {
45 let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
46 let val = Value::ByValPair(val, PrimVal::from_bool(overflowed));
47 self.write_value(val, dest, dest_ty)
50 /// Applies the binary operation `op` to the arguments and writes the result to the
51 /// destination. Returns `true` if the operation overflowed.
52 pub fn intrinsic_overflowing(
55 left: &mir::Operand<'tcx>,
56 right: &mir::Operand<'tcx>,
59 ) -> EvalResult<'tcx, bool> {
60 let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
61 self.write_primval(dest, val, dest_ty)?;
66 macro_rules! overflow {
67 ($op:ident, $l:expr, $r:expr) => ({
68 let (val, overflowed) = $l.$op($r);
69 let primval = PrimVal::Bytes(val as u128);
70 Ok((primval, overflowed))
74 macro_rules! int_arithmetic {
75 ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({
78 use super::PrimValKind::*;
80 I8 => overflow!($int_op, l as i8, r as i8),
81 I16 => overflow!($int_op, l as i16, r as i16),
82 I32 => overflow!($int_op, l as i32, r as i32),
83 I64 => overflow!($int_op, l as i64, r as i64),
84 I128 => overflow!($int_op, l as i128, r as i128),
85 U8 => overflow!($int_op, l as u8, r as u8),
86 U16 => overflow!($int_op, l as u16, r as u16),
87 U32 => overflow!($int_op, l as u32, r as u32),
88 U64 => overflow!($int_op, l as u64, r as u64),
89 U128 => overflow!($int_op, l as u128, r as u128),
90 _ => bug!("int_arithmetic should only be called on int primvals"),
95 macro_rules! int_shift {
96 ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({
99 let r_wrapped = r as u32;
101 I8 => overflow!($int_op, l as i8, r_wrapped),
102 I16 => overflow!($int_op, l as i16, r_wrapped),
103 I32 => overflow!($int_op, l as i32, r_wrapped),
104 I64 => overflow!($int_op, l as i64, r_wrapped),
105 I128 => overflow!($int_op, l as i128, r_wrapped),
106 U8 => overflow!($int_op, l as u8, r_wrapped),
107 U16 => overflow!($int_op, l as u16, r_wrapped),
108 U32 => overflow!($int_op, l as u32, r_wrapped),
109 U64 => overflow!($int_op, l as u64, r_wrapped),
110 U128 => overflow!($int_op, l as u128, r_wrapped),
111 _ => bug!("int_shift should only be called on int primvals"),
112 }.map(|(val, over)| (val, over || r != r_wrapped as u128))
116 macro_rules! float_arithmetic {
117 ($from_bytes:ident, $to_bytes:ident, $float_op:tt, $l:expr, $r:expr) => ({
118 let l = $from_bytes($l);
119 let r = $from_bytes($r);
120 let bytes = $to_bytes(l $float_op r);
121 PrimVal::Bytes(bytes)
125 macro_rules! f32_arithmetic {
126 ($float_op:tt, $l:expr, $r:expr) => (
127 float_arithmetic!(bytes_to_f32, f32_to_bytes, $float_op, $l, $r)
131 macro_rules! f64_arithmetic {
132 ($float_op:tt, $l:expr, $r:expr) => (
133 float_arithmetic!(bytes_to_f64, f64_to_bytes, $float_op, $l, $r)
137 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
138 /// Returns the result of the specified operation and whether it overflowed.
146 ) -> EvalResult<'tcx, (PrimVal, bool)> {
147 use rustc::mir::BinOp::*;
148 use super::PrimValKind::*;
150 let left_kind = self.ty_to_primval_kind(left_ty)?;
151 let right_kind = self.ty_to_primval_kind(right_ty)?;
152 //trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
154 // I: Handle operations that support pointers
155 if !left_kind.is_float() && !right_kind.is_float() {
156 if let Some(handled) = M::ptr_op(self, bin_op, left, left_ty, right, right_ty)? {
161 // II: From now on, everything must be bytes, no pointers
162 let l = left.to_bytes()?;
163 let r = right.to_bytes()?;
165 // These ops can have an RHS with a different numeric type.
166 if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
167 return match bin_op {
168 Shl => int_shift!(left_kind, overflowing_shl, l, r),
169 Shr => int_shift!(left_kind, overflowing_shr, l, r),
170 _ => bug!("it has already been checked that this is a shift op"),
174 if left_kind != right_kind {
175 let msg = format!("unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
176 return Err(EvalError::Unimplemented(msg));
179 let val = match (bin_op, left_kind) {
180 (Eq, F32) => PrimVal::from_bool(bytes_to_f32(l) == bytes_to_f32(r)),
181 (Ne, F32) => PrimVal::from_bool(bytes_to_f32(l) != bytes_to_f32(r)),
182 (Lt, F32) => PrimVal::from_bool(bytes_to_f32(l) < bytes_to_f32(r)),
183 (Le, F32) => PrimVal::from_bool(bytes_to_f32(l) <= bytes_to_f32(r)),
184 (Gt, F32) => PrimVal::from_bool(bytes_to_f32(l) > bytes_to_f32(r)),
185 (Ge, F32) => PrimVal::from_bool(bytes_to_f32(l) >= bytes_to_f32(r)),
187 (Eq, F64) => PrimVal::from_bool(bytes_to_f64(l) == bytes_to_f64(r)),
188 (Ne, F64) => PrimVal::from_bool(bytes_to_f64(l) != bytes_to_f64(r)),
189 (Lt, F64) => PrimVal::from_bool(bytes_to_f64(l) < bytes_to_f64(r)),
190 (Le, F64) => PrimVal::from_bool(bytes_to_f64(l) <= bytes_to_f64(r)),
191 (Gt, F64) => PrimVal::from_bool(bytes_to_f64(l) > bytes_to_f64(r)),
192 (Ge, F64) => PrimVal::from_bool(bytes_to_f64(l) >= bytes_to_f64(r)),
194 (Add, F32) => f32_arithmetic!(+, l, r),
195 (Sub, F32) => f32_arithmetic!(-, l, r),
196 (Mul, F32) => f32_arithmetic!(*, l, r),
197 (Div, F32) => f32_arithmetic!(/, l, r),
198 (Rem, F32) => f32_arithmetic!(%, l, r),
200 (Add, F64) => f64_arithmetic!(+, l, r),
201 (Sub, F64) => f64_arithmetic!(-, l, r),
202 (Mul, F64) => f64_arithmetic!(*, l, r),
203 (Div, F64) => f64_arithmetic!(/, l, r),
204 (Rem, F64) => f64_arithmetic!(%, l, r),
206 (Eq, _) => PrimVal::from_bool(l == r),
207 (Ne, _) => PrimVal::from_bool(l != r),
209 (Lt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) < (r as i128)),
210 (Lt, _) => PrimVal::from_bool(l < r),
211 (Le, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) <= (r as i128)),
212 (Le, _) => PrimVal::from_bool(l <= r),
213 (Gt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) > (r as i128)),
214 (Gt, _) => PrimVal::from_bool(l > r),
215 (Ge, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) >= (r as i128)),
216 (Ge, _) => PrimVal::from_bool(l >= r),
218 (BitOr, _) => PrimVal::Bytes(l | r),
219 (BitAnd, _) => PrimVal::Bytes(l & r),
220 (BitXor, _) => PrimVal::Bytes(l ^ r),
222 (Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, l, r),
223 (Sub, k) if k.is_int() => return int_arithmetic!(k, overflowing_sub, l, r),
224 (Mul, k) if k.is_int() => return int_arithmetic!(k, overflowing_mul, l, r),
225 (Div, k) if k.is_int() => return int_arithmetic!(k, overflowing_div, l, r),
226 (Rem, k) if k.is_int() => return int_arithmetic!(k, overflowing_rem, l, r),
229 let msg = format!("unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
230 return Err(EvalError::Unimplemented(msg));
238 pub fn unary_op<'tcx>(
241 val_kind: PrimValKind,
242 ) -> EvalResult<'tcx, PrimVal> {
243 use rustc::mir::UnOp::*;
244 use super::PrimValKind::*;
246 let bytes = val.to_bytes()?;
248 let result_bytes = match (un_op, val_kind) {
249 (Not, Bool) => !val.to_bool()? as u128,
251 (Not, U8) => !(bytes as u8) as u128,
252 (Not, U16) => !(bytes as u16) as u128,
253 (Not, U32) => !(bytes as u32) as u128,
254 (Not, U64) => !(bytes as u64) as u128,
255 (Not, U128) => !bytes,
257 (Not, I8) => !(bytes as i8) as u128,
258 (Not, I16) => !(bytes as i16) as u128,
259 (Not, I32) => !(bytes as i32) as u128,
260 (Not, I64) => !(bytes as i64) as u128,
261 (Not, I128) => !(bytes as i128) as u128,
263 (Neg, I8) => -(bytes as i8) as u128,
264 (Neg, I16) => -(bytes as i16) as u128,
265 (Neg, I32) => -(bytes as i32) as u128,
266 (Neg, I64) => -(bytes as i64) as u128,
267 (Neg, I128) => -(bytes as i128) as u128,
269 (Neg, F32) => f32_to_bytes(-bytes_to_f32(bytes)),
270 (Neg, F64) => f64_to_bytes(-bytes_to_f64(bytes)),
273 let msg = format!("unimplemented unary op: {:?}, {:?}", un_op, val);
274 return Err(EvalError::Unimplemented(msg));
278 Ok(PrimVal::Bytes(result_bytes))