2 use rustc::ty::layout::LayoutOf;
3 use syntax::ast::{FloatTy, IntTy, UintTy};
5 use rustc_apfloat::ieee::{Single, Double};
6 use super::{EvalContext, Machine};
7 use rustc::mir::interpret::{Scalar, EvalResult, Pointer, PointerArithmetic};
8 use rustc_apfloat::Float;
10 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
11 pub(super) fn cast_scalar(
16 ) -> EvalResult<'tcx, Scalar> {
17 use rustc::ty::TypeVariants::*;
18 trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
21 Scalar::Bits { defined: 0, .. } => Ok(val),
22 Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
23 Scalar::Bits { bits, .. } => {
24 // TODO(oli-obk): check defined bits here
26 TyFloat(fty) => self.cast_from_float(bits, fty, dest_ty),
27 _ => self.cast_from_int(bits, src_ty, dest_ty),
38 ) -> EvalResult<'tcx, Scalar> {
39 let signed = self.layout_of(src_ty)?.abi.is_signed();
41 self.sign_extend(v, src_ty)?
45 trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
46 use rustc::ty::TypeVariants::*;
48 TyInt(_) | TyUint(_) => {
49 let v = self.truncate(v, dest_ty)?;
52 defined: self.layout_of(dest_ty).unwrap().size.bits() as u8,
56 TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bits {
57 bits: Single::from_i128(v as i128).value.to_bits(),
60 TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bits {
61 bits: Double::from_i128(v as i128).value.to_bits(),
64 TyFloat(FloatTy::F32) => Ok(Scalar::Bits {
65 bits: Single::from_u128(v).value.to_bits(),
68 TyFloat(FloatTy::F64) => Ok(Scalar::Bits {
69 bits: Double::from_u128(v).value.to_bits(),
73 TyChar if v as u8 as u128 == v => Ok(Scalar::Bits { bits: v, defined: 32 }),
74 TyChar => err!(InvalidChar(v)),
76 // No alignment check needed for raw pointers. But we have to truncate to target ptr size.
79 bits: self.memory.truncate_to_ptr(v).0 as u128,
80 defined: self.memory.pointer_size().bits() as u8,
84 // Casts to bool are not permitted by rustc, no need to handle them here.
85 _ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
89 fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
90 use rustc::ty::TypeVariants::*;
91 use rustc_apfloat::FloatConvert;
95 let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
97 FloatTy::F32 => Ok(Scalar::Bits {
98 bits: Single::from_bits(bits).to_u128(width).value,
101 FloatTy::F64 => Ok(Scalar::Bits {
102 bits: Double::from_bits(bits).to_u128(width).value,
103 defined: width as u8,
109 let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
111 FloatTy::F32 => Ok(Scalar::Bits {
112 bits: Single::from_bits(bits).to_i128(width).value as u128,
113 defined: width as u8,
115 FloatTy::F64 => Ok(Scalar::Bits {
116 bits: Double::from_bits(bits).to_i128(width).value as u128,
117 defined: width as u8,
122 TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
124 bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
129 TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
131 bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
136 TyFloat(FloatTy:: F64) => Ok(Scalar::Bits {
140 TyFloat(FloatTy:: F32) => Ok(Scalar::Bits {
144 _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
148 fn cast_from_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
149 use rustc::ty::TypeVariants::*;
151 // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
153 TyInt(IntTy::Isize) |
154 TyUint(UintTy::Usize) => Ok(ptr.into()),
155 TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
156 _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),