Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miri: convert to/from apfloat instead of host floats #61673

Merged
merged 7 commits into from
Jun 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand All @@ -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]
Expand Down Expand Up @@ -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))
}
}

Expand Down Expand Up @@ -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()
}

Expand Down
8 changes: 8 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
11 changes: 5 additions & 6 deletions src/librustc_mir/hair/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand All @@ -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))
}
97 changes: 45 additions & 52 deletions src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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>,
Expand All @@ -135,23 +135,36 @@ 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),
}
}
}
}

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)
Expand All @@ -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 => {
Expand All @@ -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),
}
}

Expand Down
Loading