2017-12-12 17:14:49 +01:00
|
|
|
use rustc::mir;
|
2019-06-08 23:30:33 +02:00
|
|
|
use rustc::ty::{self, layout::TyLayout};
|
2017-09-15 15:05:51 +02:00
|
|
|
use syntax::ast::FloatTy;
|
2018-04-25 15:26:12 +02:00
|
|
|
use rustc_apfloat::ieee::{Double, Single};
|
|
|
|
use rustc_apfloat::Float;
|
2019-06-07 18:56:27 +02:00
|
|
|
use rustc::mir::interpret::{InterpResult, Scalar};
|
2016-03-13 01:43:28 -06:00
|
|
|
|
2019-03-26 13:06:15 +09:00
|
|
|
use super::{InterpretCx, PlaceTy, Immediate, Machine, ImmTy};
|
2017-08-10 08:48:38 -07:00
|
|
|
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2019-03-26 13:06:15 +09:00
|
|
|
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
|
2016-12-10 17:03:12 -08:00
|
|
|
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
|
|
|
|
/// and a boolean signifying the potential overflow to the destination.
|
2018-08-13 16:14:22 +02:00
|
|
|
pub fn binop_with_overflow(
|
2016-12-10 17:03:12 -08:00
|
|
|
&mut self,
|
|
|
|
op: mir::BinOp,
|
2018-10-26 12:33:26 +02:00
|
|
|
left: ImmTy<'tcx, M::PointerTag>,
|
|
|
|
right: ImmTy<'tcx, M::PointerTag>,
|
2018-09-21 23:32:59 +02:00
|
|
|
dest: PlaceTy<'tcx, M::PointerTag>,
|
2019-06-07 18:56:27 +02:00
|
|
|
) -> InterpResult<'tcx> {
|
2019-02-08 14:00:52 +01:00
|
|
|
let (val, overflowed) = self.binary_op(op, left, right)?;
|
2018-10-26 12:33:26 +02:00
|
|
|
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
|
|
|
|
self.write_immediate(val, dest)
|
2016-12-10 17:03:12 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Applies the binary operation `op` to the arguments and writes the result to the
|
2018-08-13 16:14:22 +02:00
|
|
|
/// destination.
|
|
|
|
pub fn binop_ignore_overflow(
|
2016-12-10 17:03:12 -08:00
|
|
|
&mut self,
|
|
|
|
op: mir::BinOp,
|
2018-10-26 12:33:26 +02:00
|
|
|
left: ImmTy<'tcx, M::PointerTag>,
|
|
|
|
right: ImmTy<'tcx, M::PointerTag>,
|
2018-09-21 23:32:59 +02:00
|
|
|
dest: PlaceTy<'tcx, M::PointerTag>,
|
2019-06-07 18:56:27 +02:00
|
|
|
) -> InterpResult<'tcx> {
|
2019-02-08 14:00:52 +01:00
|
|
|
let (val, _overflowed) = self.binary_op(op, left, right)?;
|
2018-08-13 16:14:22 +02:00
|
|
|
self.write_scalar(val, dest)
|
2016-12-10 17:03:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-26 13:06:15 +09:00
|
|
|
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> {
|
2018-08-26 14:22:59 +02:00
|
|
|
fn binary_char_op(
|
2017-06-04 17:26:19 -07:00
|
|
|
&self,
|
|
|
|
bin_op: mir::BinOp,
|
2018-08-26 14:22:59 +02:00
|
|
|
l: char,
|
|
|
|
r: char,
|
2019-06-09 00:41:20 +02:00
|
|
|
) -> (Scalar<M::PointerTag>, bool) {
|
2017-12-12 17:14:49 +01:00
|
|
|
use rustc::mir::BinOp::*;
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2018-08-26 14:22:59 +02:00
|
|
|
let res = match bin_op {
|
|
|
|
Eq => l == r,
|
|
|
|
Ne => l != r,
|
|
|
|
Lt => l < r,
|
|
|
|
Le => l <= r,
|
|
|
|
Gt => l > r,
|
|
|
|
Ge => l >= r,
|
|
|
|
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
|
|
|
};
|
2019-06-09 00:41:20 +02:00
|
|
|
return (Scalar::from_bool(res), false);
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
2018-05-24 11:21:23 +02:00
|
|
|
|
2018-08-26 14:22:59 +02:00
|
|
|
fn binary_bool_op(
|
|
|
|
&self,
|
|
|
|
bin_op: mir::BinOp,
|
|
|
|
l: bool,
|
|
|
|
r: bool,
|
2019-06-09 00:41:20 +02:00
|
|
|
) -> (Scalar<M::PointerTag>, bool) {
|
2018-08-26 14:22:59 +02:00
|
|
|
use rustc::mir::BinOp::*;
|
2018-08-24 18:36:52 +02:00
|
|
|
|
2018-08-26 14:22:59 +02:00
|
|
|
let res = match bin_op {
|
|
|
|
Eq => l == r,
|
|
|
|
Ne => l != r,
|
|
|
|
Lt => l < r,
|
|
|
|
Le => l <= r,
|
|
|
|
Gt => l > r,
|
|
|
|
Ge => l >= r,
|
|
|
|
BitAnd => l & r,
|
|
|
|
BitOr => l | r,
|
|
|
|
BitXor => l ^ r,
|
|
|
|
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
|
|
|
};
|
2019-06-09 00:41:20 +02:00
|
|
|
return (Scalar::from_bool(res), false);
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
|
|
|
|
2019-06-09 00:41:20 +02:00
|
|
|
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
|
2018-08-26 14:22:59 +02:00
|
|
|
&self,
|
|
|
|
bin_op: mir::BinOp,
|
2019-06-09 00:41:20 +02:00
|
|
|
l: F,
|
|
|
|
r: F,
|
|
|
|
) -> (Scalar<M::PointerTag>, bool) {
|
2018-08-26 14:22:59 +02:00
|
|
|
use rustc::mir::BinOp::*;
|
|
|
|
|
2019-06-09 00:41:20 +02:00
|
|
|
let val = match bin_op {
|
|
|
|
Eq => Scalar::from_bool(l == r),
|
|
|
|
Ne => Scalar::from_bool(l != r),
|
|
|
|
Lt => Scalar::from_bool(l < r),
|
|
|
|
Le => Scalar::from_bool(l <= r),
|
|
|
|
Gt => Scalar::from_bool(l > r),
|
|
|
|
Ge => Scalar::from_bool(l >= r),
|
|
|
|
Add => (l + r).value.into(),
|
|
|
|
Sub => (l - r).value.into(),
|
|
|
|
Mul => (l * r).value.into(),
|
|
|
|
Div => (l / r).value.into(),
|
|
|
|
Rem => (l % r).value.into(),
|
|
|
|
_ => bug!("invalid float op: `{:?}`", bin_op),
|
|
|
|
};
|
|
|
|
return (val, false);
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2018-08-26 14:22:59 +02:00
|
|
|
fn binary_int_op(
|
|
|
|
&self,
|
|
|
|
bin_op: mir::BinOp,
|
|
|
|
// passing in raw bits
|
|
|
|
l: u128,
|
|
|
|
left_layout: TyLayout<'tcx>,
|
|
|
|
r: u128,
|
|
|
|
right_layout: TyLayout<'tcx>,
|
2019-06-07 18:56:27 +02:00
|
|
|
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
2018-08-26 14:22:59 +02:00
|
|
|
use rustc::mir::BinOp::*;
|
2018-02-22 14:59:18 +01:00
|
|
|
|
2018-08-24 18:36:52 +02:00
|
|
|
// Shift ops can have an RHS with a different numeric type.
|
|
|
|
if bin_op == Shl || bin_op == Shr {
|
2018-02-22 14:59:18 +01:00
|
|
|
let signed = left_layout.abi.is_signed();
|
2018-06-27 13:47:19 +02:00
|
|
|
let mut oflo = (r as u32 as u128) != r;
|
2018-02-22 14:59:18 +01:00
|
|
|
let mut r = r as u32;
|
2018-07-24 18:28:53 +02:00
|
|
|
let size = left_layout.size;
|
|
|
|
oflo |= r >= size.bits() as u32;
|
2018-02-22 14:59:18 +01:00
|
|
|
if oflo {
|
2018-07-24 18:28:53 +02:00
|
|
|
r %= size.bits() as u32;
|
2018-02-22 14:59:18 +01:00
|
|
|
}
|
|
|
|
let result = if signed {
|
2018-07-24 18:28:53 +02:00
|
|
|
let l = self.sign_extend(l, left_layout) as i128;
|
2018-02-22 14:59:18 +01:00
|
|
|
let result = match bin_op {
|
|
|
|
Shl => l << r,
|
|
|
|
Shr => l >> r,
|
|
|
|
_ => bug!("it has already been checked that this is a shift op"),
|
|
|
|
};
|
|
|
|
result as u128
|
2018-02-21 22:02:52 +01:00
|
|
|
} else {
|
2018-02-22 14:59:18 +01:00
|
|
|
match bin_op {
|
|
|
|
Shl => l << r,
|
|
|
|
Shr => l >> r,
|
|
|
|
_ => bug!("it has already been checked that this is a shift op"),
|
|
|
|
}
|
2018-02-21 22:02:52 +01:00
|
|
|
};
|
2018-07-24 18:28:53 +02:00
|
|
|
let truncated = self.truncate(result, left_layout);
|
2018-08-26 20:42:52 +02:00
|
|
|
return Ok((Scalar::from_uint(truncated, size), oflo));
|
2017-06-04 17:26:19 -07:00
|
|
|
}
|
|
|
|
|
2018-08-24 18:36:52 +02:00
|
|
|
// For the remaining ops, the types must be the same on both sides
|
|
|
|
if left_layout.ty != right_layout.ty {
|
2017-08-10 08:48:38 -07:00
|
|
|
let msg = format!(
|
2018-08-26 14:22:59 +02:00
|
|
|
"unimplemented asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
2017-08-10 08:48:38 -07:00
|
|
|
bin_op,
|
2018-08-26 14:22:59 +02:00
|
|
|
l,
|
2018-08-24 18:36:52 +02:00
|
|
|
left_layout.ty,
|
2018-08-26 14:22:59 +02:00
|
|
|
r,
|
2018-08-24 18:36:52 +02:00
|
|
|
right_layout.ty
|
2017-08-10 08:48:38 -07:00
|
|
|
);
|
2017-08-02 16:59:01 +02:00
|
|
|
return err!(Unimplemented(msg));
|
2016-10-20 04:42:19 -06:00
|
|
|
}
|
2016-03-18 23:03:46 -06:00
|
|
|
|
2018-08-24 18:36:52 +02:00
|
|
|
// Operations that need special treatment for signed integers
|
2018-02-22 14:59:18 +01:00
|
|
|
if left_layout.abi.is_signed() {
|
2018-02-21 22:02:52 +01:00
|
|
|
let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
|
|
|
|
Lt => Some(i128::lt),
|
|
|
|
Le => Some(i128::le),
|
|
|
|
Gt => Some(i128::gt),
|
|
|
|
Ge => Some(i128::ge),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
if let Some(op) = op {
|
2018-07-24 18:28:53 +02:00
|
|
|
let l = self.sign_extend(l, left_layout) as i128;
|
|
|
|
let r = self.sign_extend(r, right_layout) as i128;
|
2018-05-20 23:43:16 +02:00
|
|
|
return Ok((Scalar::from_bool(op(&l, &r)), false));
|
2018-02-21 22:02:52 +01:00
|
|
|
}
|
|
|
|
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
|
2018-04-28 13:35:35 +02:00
|
|
|
Div if r == 0 => return err!(DivisionByZero),
|
|
|
|
Rem if r == 0 => return err!(RemainderByZero),
|
2018-02-21 22:02:52 +01:00
|
|
|
Div => Some(i128::overflowing_div),
|
|
|
|
Rem => Some(i128::overflowing_rem),
|
|
|
|
Add => Some(i128::overflowing_add),
|
|
|
|
Sub => Some(i128::overflowing_sub),
|
|
|
|
Mul => Some(i128::overflowing_mul),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
if let Some(op) = op {
|
2018-07-24 18:28:53 +02:00
|
|
|
let l128 = self.sign_extend(l, left_layout) as i128;
|
|
|
|
let r = self.sign_extend(r, right_layout) as i128;
|
|
|
|
let size = left_layout.size;
|
2018-02-21 22:02:52 +01:00
|
|
|
match bin_op {
|
|
|
|
Rem | Div => {
|
|
|
|
// int_min / -1
|
2018-07-24 18:28:53 +02:00
|
|
|
if r == -1 && l == (1 << (size.bits() - 1)) {
|
2018-08-26 20:42:52 +02:00
|
|
|
return Ok((Scalar::from_uint(l, size), true));
|
2018-02-21 22:02:52 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
trace!("{}, {}, {}", l, l128, r);
|
|
|
|
let (result, mut oflo) = op(l128, r);
|
|
|
|
trace!("{}, {}", result, oflo);
|
2018-07-24 18:28:53 +02:00
|
|
|
if !oflo && size.bits() != 128 {
|
|
|
|
let max = 1 << (size.bits() - 1);
|
2018-02-21 22:02:52 +01:00
|
|
|
oflo = result >= max || result < -max;
|
|
|
|
}
|
2018-08-26 20:42:52 +02:00
|
|
|
// this may be out-of-bounds for the result type, so we have to truncate ourselves
|
2018-02-21 22:02:52 +01:00
|
|
|
let result = result as u128;
|
2018-07-24 18:28:53 +02:00
|
|
|
let truncated = self.truncate(result, left_layout);
|
2018-08-26 20:42:52 +02:00
|
|
|
return Ok((Scalar::from_uint(truncated, size), oflo));
|
2018-02-21 22:02:52 +01:00
|
|
|
}
|
|
|
|
}
|
2017-06-04 17:26:19 -07:00
|
|
|
|
2018-08-26 20:42:52 +02:00
|
|
|
let size = left_layout.size;
|
2018-05-22 10:28:46 +02:00
|
|
|
|
2018-02-21 22:02:52 +01:00
|
|
|
// only ints left
|
|
|
|
let val = match bin_op {
|
2018-05-20 23:43:16 +02:00
|
|
|
Eq => Scalar::from_bool(l == r),
|
|
|
|
Ne => Scalar::from_bool(l != r),
|
2018-02-21 22:02:52 +01:00
|
|
|
|
2018-05-20 23:43:16 +02:00
|
|
|
Lt => Scalar::from_bool(l < r),
|
|
|
|
Le => Scalar::from_bool(l <= r),
|
|
|
|
Gt => Scalar::from_bool(l > r),
|
|
|
|
Ge => Scalar::from_bool(l >= r),
|
2018-02-21 22:02:52 +01:00
|
|
|
|
2018-08-26 20:42:52 +02:00
|
|
|
BitOr => Scalar::from_uint(l | r, size),
|
|
|
|
BitAnd => Scalar::from_uint(l & r, size),
|
|
|
|
BitXor => Scalar::from_uint(l ^ r, size),
|
2018-02-21 22:02:52 +01:00
|
|
|
|
|
|
|
Add | Sub | Mul | Rem | Div => {
|
2018-08-26 20:42:52 +02:00
|
|
|
debug_assert!(!left_layout.abi.is_signed());
|
2018-02-21 22:02:52 +01:00
|
|
|
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
|
|
|
|
Add => u128::overflowing_add,
|
|
|
|
Sub => u128::overflowing_sub,
|
|
|
|
Mul => u128::overflowing_mul,
|
2018-04-28 13:35:35 +02:00
|
|
|
Div if r == 0 => return err!(DivisionByZero),
|
|
|
|
Rem if r == 0 => return err!(RemainderByZero),
|
2018-02-21 22:02:52 +01:00
|
|
|
Div => u128::overflowing_div,
|
|
|
|
Rem => u128::overflowing_rem,
|
|
|
|
_ => bug!(),
|
|
|
|
};
|
|
|
|
let (result, oflo) = op(l, r);
|
2018-07-24 18:28:53 +02:00
|
|
|
let truncated = self.truncate(result, left_layout);
|
2018-08-26 20:42:52 +02:00
|
|
|
return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
|
2018-02-21 22:02:52 +01:00
|
|
|
}
|
2017-06-04 17:26:19 -07:00
|
|
|
|
|
|
|
_ => {
|
2017-08-10 08:48:38 -07:00
|
|
|
let msg = format!(
|
2018-08-26 14:22:59 +02:00
|
|
|
"unimplemented binary op {:?}: {:?}, {:?} (both {:?})",
|
2017-08-10 08:48:38 -07:00
|
|
|
bin_op,
|
2018-08-26 14:22:59 +02:00
|
|
|
l,
|
|
|
|
r,
|
2018-08-13 16:14:22 +02:00
|
|
|
right_layout.ty,
|
2017-08-10 08:48:38 -07:00
|
|
|
);
|
2017-08-02 16:59:01 +02:00
|
|
|
return err!(Unimplemented(msg));
|
2017-06-04 17:26:19 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok((val, false))
|
|
|
|
}
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2019-02-08 14:00:52 +01:00
|
|
|
/// Returns the result of the specified operation and whether it overflowed.
|
2018-08-28 01:14:29 +02:00
|
|
|
#[inline]
|
2019-02-08 14:00:52 +01:00
|
|
|
pub fn binary_op(
|
2018-08-28 01:14:29 +02:00
|
|
|
&self,
|
|
|
|
bin_op: mir::BinOp,
|
2018-10-26 12:33:26 +02:00
|
|
|
left: ImmTy<'tcx, M::PointerTag>,
|
|
|
|
right: ImmTy<'tcx, M::PointerTag>,
|
2019-06-07 18:56:27 +02:00
|
|
|
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
2018-08-26 14:22:59 +02:00
|
|
|
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
2019-02-08 14:00:52 +01:00
|
|
|
bin_op, *left, left.layout.ty, *right, right.layout.ty);
|
2018-08-26 14:22:59 +02:00
|
|
|
|
2019-02-08 14:00:52 +01:00
|
|
|
match left.layout.ty.sty {
|
2018-08-26 14:22:59 +02:00
|
|
|
ty::Char => {
|
2019-02-08 14:00:52 +01:00
|
|
|
assert_eq!(left.layout.ty, right.layout.ty);
|
2019-06-09 00:41:20 +02:00
|
|
|
let left = left.to_scalar()?;
|
|
|
|
let right = right.to_scalar()?;
|
|
|
|
Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?))
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
|
|
|
ty::Bool => {
|
2019-02-08 14:00:52 +01:00
|
|
|
assert_eq!(left.layout.ty, right.layout.ty);
|
2019-06-09 00:41:20 +02:00
|
|
|
let left = left.to_scalar()?;
|
|
|
|
let right = right.to_scalar()?;
|
|
|
|
Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?))
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
|
|
|
ty::Float(fty) => {
|
2019-02-08 14:00:52 +01:00
|
|
|
assert_eq!(left.layout.ty, right.layout.ty);
|
2019-06-09 00:41:20 +02:00
|
|
|
let left = left.to_scalar()?;
|
|
|
|
let right = right.to_scalar()?;
|
|
|
|
Ok(match fty {
|
|
|
|
FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?),
|
|
|
|
FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?),
|
|
|
|
})
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
|
|
|
_ => {
|
2018-08-26 15:13:01 +02:00
|
|
|
// Must be integer(-like) types. Don't forget about == on fn pointers.
|
2019-02-08 14:00:52 +01:00
|
|
|
assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() ||
|
|
|
|
left.layout.ty.is_fn());
|
|
|
|
assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() ||
|
|
|
|
right.layout.ty.is_fn());
|
2018-08-26 14:22:59 +02:00
|
|
|
|
|
|
|
// Handle operations that support pointer values
|
2019-02-08 14:00:52 +01:00
|
|
|
if left.to_scalar_ptr()?.is_ptr() ||
|
|
|
|
right.to_scalar_ptr()?.is_ptr() ||
|
|
|
|
bin_op == mir::BinOp::Offset
|
|
|
|
{
|
|
|
|
return M::ptr_op(self, bin_op, left, right);
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Everything else only works with "proper" bits
|
2019-02-08 14:00:52 +01:00
|
|
|
let l = left.to_bits().expect("we checked is_ptr");
|
|
|
|
let r = right.to_bits().expect("we checked is_ptr");
|
|
|
|
self.binary_int_op(bin_op, l, left.layout, r, right.layout)
|
2018-08-26 14:22:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-21 22:02:52 +01:00
|
|
|
pub fn unary_op(
|
|
|
|
&self,
|
|
|
|
un_op: mir::UnOp,
|
2019-02-08 14:00:52 +01:00
|
|
|
val: ImmTy<'tcx, M::PointerTag>,
|
2019-06-07 18:56:27 +02:00
|
|
|
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
2018-02-21 22:02:52 +01:00
|
|
|
use rustc::mir::UnOp::*;
|
2016-12-17 03:09:57 -08:00
|
|
|
|
2019-02-08 14:00:52 +01:00
|
|
|
let layout = val.layout;
|
|
|
|
let val = val.to_scalar()?;
|
2018-12-07 19:14:30 +02:00
|
|
|
trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty);
|
2016-10-20 04:42:19 -06:00
|
|
|
|
2018-08-26 15:13:01 +02:00
|
|
|
match layout.ty.sty {
|
|
|
|
ty::Bool => {
|
|
|
|
let val = val.to_bool()?;
|
|
|
|
let res = match un_op {
|
|
|
|
Not => !val,
|
|
|
|
_ => bug!("Invalid bool op {:?}", un_op)
|
|
|
|
};
|
|
|
|
Ok(Scalar::from_bool(res))
|
|
|
|
}
|
|
|
|
ty::Float(fty) => {
|
|
|
|
let val = val.to_bits(layout.size)?;
|
|
|
|
let res = match (un_op, fty) {
|
|
|
|
(Neg, FloatTy::F32) => Single::to_bits(-Single::from_bits(val)),
|
|
|
|
(Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)),
|
|
|
|
_ => bug!("Invalid float op {:?}", un_op)
|
|
|
|
};
|
2018-08-26 20:42:52 +02:00
|
|
|
Ok(Scalar::from_uint(res, layout.size))
|
2018-08-26 15:13:01 +02:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
assert!(layout.ty.is_integral());
|
|
|
|
let val = val.to_bits(layout.size)?;
|
|
|
|
let res = match un_op {
|
|
|
|
Not => !val,
|
|
|
|
Neg => {
|
|
|
|
assert!(layout.abi.is_signed());
|
|
|
|
(-(val as i128)) as u128
|
|
|
|
}
|
|
|
|
};
|
|
|
|
// res needs tuncating
|
2018-08-26 20:42:52 +02:00
|
|
|
Ok(Scalar::from_uint(self.truncate(res, layout), layout.size))
|
2018-08-26 15:13:01 +02:00
|
|
|
}
|
|
|
|
}
|
2018-02-21 22:02:52 +01:00
|
|
|
}
|
2016-03-13 01:43:28 -06:00
|
|
|
}
|