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};
Ok(())
}
- pub(super) fn cast_scalar(
+ fn cast_scalar(
&self,
val: Scalar<M::PointerTag>,
src_layout: TyLayout<'tcx>,
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)
}
}
- 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),
}
}