Skip to content

Commit

Permalink
make floating point casts nicer with generics
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jun 9, 2019
1 parent de7bcca commit 2ad303e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 38 deletions.
8 changes: 8 additions & 0 deletions src/librustc/ty/sty.rs
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
68 changes: 34 additions & 34 deletions src/librustc_mir/interpret/cast.rs
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,33 @@ 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
_ => {
assert!(
src_layout.ty.is_bool() || src_layout.ty.is_char() ||
src_layout.ty.is_integral() || src_layout.ty.is_region_ptr() ||
src_layout.ty.is_unsafe_ptr() || src_layout.ty.is_fn_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 Down Expand Up @@ -190,46 +200,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_f32(Double::from_bits(bits).convert(&mut false).value)),
// f32 -> f64
Float(FloatTy::F64) if fty == FloatTy::F32 =>
Ok(Scalar::from_f64(Single::from_bits(bits).convert(&mut false).value)),
// identity cast
Float(FloatTy::F64) if fty == FloatTy::F64 =>
Ok(Scalar::from_uint(bits, Size::from_bits(64))),
Float(FloatTy::F32) if fty == 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
12 changes: 8 additions & 4 deletions src/librustc_mir/interpret/operator.rs
Expand Up @@ -292,10 +292,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
}
_ => {
// 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() ||
Expand Down

0 comments on commit 2ad303e

Please sign in to comment.