Auto merge of #61673 - RalfJung:miri-no-hard-float, r=eddyb,oli-obk
Miri: convert to/from apfloat instead of host floats Cc @oli-obk @eddyb
This commit is contained in:
commit
912d22e369
@ -1,5 +1,6 @@
|
||||
use std::fmt;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_apfloat::{Float, ieee::{Double, Single}};
|
||||
|
||||
use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}, subst::SubstsRef};
|
||||
use crate::ty::PlaceholderConst;
|
||||
@ -131,6 +132,20 @@ impl<Tag> fmt::Display for Scalar<Tag> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> From<Single> for Scalar<Tag> {
|
||||
#[inline(always)]
|
||||
fn from(f: Single) -> Self {
|
||||
Scalar::from_f32(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tag> From<Double> for Scalar<Tag> {
|
||||
#[inline(always)]
|
||||
fn from(f: Double) -> Self {
|
||||
Scalar::from_f64(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Scalar<()> {
|
||||
#[inline(always)]
|
||||
fn check_data(data: u128, size: u8) {
|
||||
@ -279,6 +294,26 @@ impl<'tcx, Tag> Scalar<Tag> {
|
||||
Scalar::Raw { data: i, size: size.bytes() as u8 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u8(i: u8) -> Self {
|
||||
Scalar::Raw { data: i as u128, size: 1 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u16(i: u16) -> Self {
|
||||
Scalar::Raw { data: i as u128, size: 2 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u32(i: u32) -> Self {
|
||||
Scalar::Raw { data: i as u128, size: 4 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u64(i: u64) -> Self {
|
||||
Scalar::Raw { data: i as u128, size: 8 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
|
||||
let i = i.into();
|
||||
@ -292,13 +327,15 @@ impl<'tcx, Tag> Scalar<Tag> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_f32(f: f32) -> Self {
|
||||
Scalar::Raw { data: f.to_bits() as u128, size: 4 }
|
||||
pub fn from_f32(f: Single) -> Self {
|
||||
// We trust apfloat to give us properly truncated data.
|
||||
Scalar::Raw { data: f.to_bits(), size: 4 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_f64(f: f64) -> Self {
|
||||
Scalar::Raw { data: f.to_bits() as u128, size: 8 }
|
||||
pub fn from_f64(f: Double) -> Self {
|
||||
// We trust apfloat to give us properly truncated data.
|
||||
Scalar::Raw { data: f.to_bits(), size: 8 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -427,13 +464,15 @@ impl<'tcx, Tag> Scalar<Tag> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_f32(self) -> InterpResult<'static, f32> {
|
||||
Ok(f32::from_bits(self.to_u32()?))
|
||||
pub fn to_f32(self) -> InterpResult<'static, Single> {
|
||||
// Going through `u32` to check size and truncation.
|
||||
Ok(Single::from_bits(self.to_u32()? as u128))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_f64(self) -> InterpResult<'static, f64> {
|
||||
Ok(f64::from_bits(self.to_u64()?))
|
||||
pub fn to_f64(self) -> InterpResult<'static, Double> {
|
||||
// Going through `u64` to check size and truncation.
|
||||
Ok(Double::from_bits(self.to_u64()? as u128))
|
||||
}
|
||||
}
|
||||
|
||||
@ -517,12 +556,12 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_f32(self) -> InterpResult<'tcx, f32> {
|
||||
pub fn to_f32(self) -> InterpResult<'tcx, Single> {
|
||||
self.not_undef()?.to_f32()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_f64(self) -> InterpResult<'tcx, f64> {
|
||||
pub fn to_f64(self) -> InterpResult<'tcx, Double> {
|
||||
self.not_undef()?.to_f64()
|
||||
}
|
||||
|
||||
|
@ -2035,6 +2035,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_fn_ptr(&self) -> bool {
|
||||
match self.sty {
|
||||
FnPtr(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_impl_trait(&self) -> bool {
|
||||
match self.sty {
|
||||
Opaque(..) => true,
|
||||
|
@ -69,8 +69,7 @@ fn parse_float<'tcx>(
|
||||
) -> Result<ConstValue<'tcx>, ()> {
|
||||
let num = num.as_str();
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::Float;
|
||||
let (data, size) = match fty {
|
||||
let scalar = match fty {
|
||||
ast::FloatTy::F32 => {
|
||||
num.parse::<f32>().map_err(|_| ())?;
|
||||
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
|
||||
@ -79,19 +78,19 @@ fn parse_float<'tcx>(
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
(f.to_bits(), 4)
|
||||
Scalar::from_f32(f)
|
||||
}
|
||||
ast::FloatTy::F64 => {
|
||||
num.parse::<f64>().map_err(|_| ())?;
|
||||
let mut f = num.parse::<Double>().unwrap_or_else(|e| {
|
||||
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
|
||||
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
|
||||
});
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
(f.to_bits(), 8)
|
||||
Scalar::from_f64(f)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(ConstValue::Scalar(Scalar::from_uint(data, Size::from_bytes(size))))
|
||||
Ok(ConstValue::Scalar(scalar))
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
use syntax::symbol::sym;
|
||||
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::{Float, FloatConvert};
|
||||
use rustc::mir::interpret::{
|
||||
Scalar, InterpResult, Pointer, PointerArithmetic, InterpError,
|
||||
};
|
||||
use rustc::mir::CastKind;
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
use super::{InterpretCx, Machine, PlaceTy, OpTy, Immediate};
|
||||
|
||||
@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn cast_scalar(
|
||||
fn cast_scalar(
|
||||
&self,
|
||||
val: Scalar<M::PointerTag>,
|
||||
src_layout: TyLayout<'tcx>,
|
||||
@ -135,12 +135,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
use rustc::ty::TyKind::*;
|
||||
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
|
||||
|
||||
match val.to_bits_or_ptr(src_layout.size, self) {
|
||||
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
|
||||
Ok(data) => {
|
||||
match src_layout.ty.sty {
|
||||
Float(fty) => self.cast_from_float(data, fty, dest_layout.ty),
|
||||
_ => self.cast_from_int(data, src_layout, dest_layout),
|
||||
match src_layout.ty.sty {
|
||||
// Floating point
|
||||
Float(FloatTy::F32) => self.cast_from_float(val.to_f32()?, dest_layout.ty),
|
||||
Float(FloatTy::F64) => self.cast_from_float(val.to_f64()?, dest_layout.ty),
|
||||
// Integer(-like), including fn ptr casts and casts from enums that
|
||||
// are represented as integers (this excludes univariant enums, which
|
||||
// are handled in `cast` directly).
|
||||
_ => {
|
||||
assert!(
|
||||
src_layout.ty.is_bool() || src_layout.ty.is_char() ||
|
||||
src_layout.ty.is_enum() || src_layout.ty.is_integral() ||
|
||||
src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_ptr() ||
|
||||
src_layout.ty.is_region_ptr(),
|
||||
"Unexpected cast from type {:?}", src_layout.ty
|
||||
);
|
||||
match val.to_bits_or_ptr(src_layout.size, self) {
|
||||
Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
|
||||
Ok(data) => self.cast_from_int(data, src_layout, dest_layout),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,10 +160,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
|
||||
fn cast_from_int(
|
||||
&self,
|
||||
v: u128,
|
||||
v: u128, // raw bits
|
||||
src_layout: TyLayout<'tcx>,
|
||||
dest_layout: TyLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
||||
// Let's make sure v is sign-extended *if* it has a signed type.
|
||||
let signed = src_layout.abi.is_signed();
|
||||
let v = if signed {
|
||||
self.sign_extend(v, src_layout)
|
||||
@ -166,21 +179,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
Ok(Scalar::from_uint(v, dest_layout.size))
|
||||
}
|
||||
|
||||
Float(FloatTy::F32) if signed => Ok(Scalar::from_uint(
|
||||
Single::from_i128(v as i128).value.to_bits(),
|
||||
Size::from_bits(32)
|
||||
Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
|
||||
Single::from_i128(v as i128).value
|
||||
)),
|
||||
Float(FloatTy::F64) if signed => Ok(Scalar::from_uint(
|
||||
Double::from_i128(v as i128).value.to_bits(),
|
||||
Size::from_bits(64)
|
||||
Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
|
||||
Double::from_i128(v as i128).value
|
||||
)),
|
||||
Float(FloatTy::F32) => Ok(Scalar::from_uint(
|
||||
Single::from_u128(v).value.to_bits(),
|
||||
Size::from_bits(32)
|
||||
Float(FloatTy::F32) => Ok(Scalar::from_f32(
|
||||
Single::from_u128(v).value
|
||||
)),
|
||||
Float(FloatTy::F64) => Ok(Scalar::from_uint(
|
||||
Double::from_u128(v).value.to_bits(),
|
||||
Size::from_bits(64)
|
||||
Float(FloatTy::F64) => Ok(Scalar::from_f64(
|
||||
Double::from_u128(v).value
|
||||
)),
|
||||
|
||||
Char => {
|
||||
@ -194,52 +203,36 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
}
|
||||
}
|
||||
|
||||
fn cast_from_float(
|
||||
fn cast_from_float<F>(
|
||||
&self,
|
||||
bits: u128,
|
||||
fty: FloatTy,
|
||||
f: F,
|
||||
dest_ty: Ty<'tcx>
|
||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
||||
) -> InterpResult<'tcx, Scalar<M::PointerTag>>
|
||||
where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
|
||||
{
|
||||
use rustc::ty::TyKind::*;
|
||||
use rustc_apfloat::FloatConvert;
|
||||
match dest_ty.sty {
|
||||
// float -> uint
|
||||
Uint(t) => {
|
||||
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
|
||||
let v = match fty {
|
||||
FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
|
||||
FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
|
||||
};
|
||||
let v = f.to_u128(width).value;
|
||||
// This should already fit the bit width
|
||||
Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
|
||||
},
|
||||
// float -> int
|
||||
Int(t) => {
|
||||
let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
|
||||
let v = match fty {
|
||||
FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
|
||||
FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
|
||||
};
|
||||
let v = f.to_i128(width).value;
|
||||
Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
|
||||
},
|
||||
// f64 -> f32
|
||||
Float(FloatTy::F32) if fty == FloatTy::F64 => {
|
||||
Ok(Scalar::from_uint(
|
||||
Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
|
||||
Size::from_bits(32),
|
||||
))
|
||||
},
|
||||
// f32 -> f64
|
||||
Float(FloatTy::F64) if fty == FloatTy::F32 => {
|
||||
Ok(Scalar::from_uint(
|
||||
Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
|
||||
Size::from_bits(64),
|
||||
))
|
||||
},
|
||||
// identity cast
|
||||
Float(FloatTy:: F64) => Ok(Scalar::from_uint(bits, Size::from_bits(64))),
|
||||
Float(FloatTy:: F32) => Ok(Scalar::from_uint(bits, Size::from_bits(32))),
|
||||
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
|
||||
// float -> f32
|
||||
Float(FloatTy::F32) =>
|
||||
Ok(Scalar::from_f32(f.convert(&mut false).value)),
|
||||
// float -> f64
|
||||
Float(FloatTy::F64) =>
|
||||
Ok(Scalar::from_f64(f.convert(&mut false).value)),
|
||||
// That's it.
|
||||
_ => bug!("invalid float to {:?} cast", dest_ty),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, layout::{Size, TyLayout}};
|
||||
use rustc::ty::{self, layout::TyLayout};
|
||||
use syntax::ast::FloatTy;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_apfloat::Float;
|
||||
use rustc::mir::interpret::{InterpResult, Scalar};
|
||||
|
||||
@ -43,7 +42,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
bin_op: mir::BinOp,
|
||||
l: char,
|
||||
r: char,
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
) -> (Scalar<M::PointerTag>, bool) {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
let res = match bin_op {
|
||||
@ -55,7 +54,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
Ge => l >= r,
|
||||
_ => bug!("Invalid operation on char: {:?}", bin_op),
|
||||
};
|
||||
return Ok((Scalar::from_bool(res), false));
|
||||
return (Scalar::from_bool(res), false);
|
||||
}
|
||||
|
||||
fn binary_bool_op(
|
||||
@ -63,7 +62,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
bin_op: mir::BinOp,
|
||||
l: bool,
|
||||
r: bool,
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
) -> (Scalar<M::PointerTag>, bool) {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
let res = match bin_op {
|
||||
@ -78,46 +77,32 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
BitXor => l ^ r,
|
||||
_ => bug!("Invalid operation on bool: {:?}", bin_op),
|
||||
};
|
||||
return Ok((Scalar::from_bool(res), false));
|
||||
return (Scalar::from_bool(res), false);
|
||||
}
|
||||
|
||||
fn binary_float_op(
|
||||
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
fty: FloatTy,
|
||||
// passing in raw bits
|
||||
l: u128,
|
||||
r: u128,
|
||||
) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
|
||||
l: F,
|
||||
r: F,
|
||||
) -> (Scalar<M::PointerTag>, bool) {
|
||||
use rustc::mir::BinOp::*;
|
||||
|
||||
macro_rules! float_math {
|
||||
($ty:path, $size:expr) => {{
|
||||
let l = <$ty>::from_bits(l);
|
||||
let r = <$ty>::from_bits(r);
|
||||
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>|
|
||||
Scalar::from_uint(res.value.to_bits(), Size::from_bytes($size));
|
||||
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 => bitify(l + r),
|
||||
Sub => bitify(l - r),
|
||||
Mul => bitify(l * r),
|
||||
Div => bitify(l / r),
|
||||
Rem => bitify(l % r),
|
||||
_ => bug!("invalid float op: `{:?}`", bin_op),
|
||||
};
|
||||
return Ok((val, false));
|
||||
}};
|
||||
}
|
||||
match fty {
|
||||
FloatTy::F32 => float_math!(Single, 4),
|
||||
FloatTy::F64 => float_math!(Double, 8),
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
fn binary_int_op(
|
||||
@ -286,28 +271,35 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
match left.layout.ty.sty {
|
||||
ty::Char => {
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let left = left.to_scalar()?.to_char()?;
|
||||
let right = right.to_scalar()?.to_char()?;
|
||||
self.binary_char_op(bin_op, left, right)
|
||||
let left = left.to_scalar()?;
|
||||
let right = right.to_scalar()?;
|
||||
Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?))
|
||||
}
|
||||
ty::Bool => {
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let left = left.to_scalar()?.to_bool()?;
|
||||
let right = right.to_scalar()?.to_bool()?;
|
||||
self.binary_bool_op(bin_op, left, right)
|
||||
let left = left.to_scalar()?;
|
||||
let right = right.to_scalar()?;
|
||||
Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?))
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let left = left.to_bits()?;
|
||||
let right = right.to_bits()?;
|
||||
self.binary_float_op(bin_op, fty, left, right)
|
||||
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()?),
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
// Must be integer(-like) types. Don't forget about == on fn pointers.
|
||||
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());
|
||||
assert!(
|
||||
left.layout.ty.is_integral() ||
|
||||
left.layout.ty.is_unsafe_ptr() || left.layout.ty.is_fn_ptr(),
|
||||
"Unexpected LHS type {:?} for BinOp {:?}", left.layout.ty, bin_op);
|
||||
assert!(
|
||||
right.layout.ty.is_integral() ||
|
||||
right.layout.ty.is_unsafe_ptr() || right.layout.ty.is_fn_ptr(),
|
||||
"Unexpected RHS type {:?} for BinOp {:?}", right.layout.ty, bin_op);
|
||||
|
||||
// Handle operations that support pointer values
|
||||
if left.to_scalar_ptr()?.is_ptr() ||
|
||||
@ -346,13 +338,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||
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)),
|
||||
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
|
||||
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
||||
_ => bug!("Invalid float op {:?}", un_op)
|
||||
};
|
||||
Ok(Scalar::from_uint(res, layout.size))
|
||||
Ok(res)
|
||||
}
|
||||
_ => {
|
||||
assert!(layout.ty.is_integral());
|
||||
|
Loading…
x
Reference in New Issue
Block a user