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::{PrimVal, EvalResult, MemoryPointer, 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_primval(
16 ) -> EvalResult<'tcx, PrimVal> {
17 use rustc::ty::TypeVariants::*;
18 trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
21 PrimVal::Undef => Ok(PrimVal::Undef),
22 PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
23 PrimVal::Bytes(b) => {
25 TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
26 _ => self.cast_from_int(b, src_ty, dest_ty),
37 ) -> EvalResult<'tcx, PrimVal> {
38 let signed = self.layout_of(src_ty)?.abi.is_signed();
40 self.sign_extend(v, src_ty)?
44 trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
45 use rustc::ty::TypeVariants::*;
47 TyInt(_) | TyUint(_) => {
48 let v = self.truncate(v, dest_ty)?;
52 TyFloat(FloatTy::F32) if signed => Ok(PrimVal::Bytes(Single::from_i128(v as i128).value.to_bits())),
53 TyFloat(FloatTy::F64) if signed => Ok(PrimVal::Bytes(Double::from_i128(v as i128).value.to_bits())),
54 TyFloat(FloatTy::F32) => Ok(PrimVal::Bytes(Single::from_u128(v).value.to_bits())),
55 TyFloat(FloatTy::F64) => Ok(PrimVal::Bytes(Double::from_u128(v).value.to_bits())),
57 TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
58 TyChar => err!(InvalidChar(v)),
60 // No alignment check needed for raw pointers. But we have to truncate to target ptr size.
62 Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
65 // Casts to bool are not permitted by rustc, no need to handle them here.
66 _ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
70 fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
71 use rustc::ty::TypeVariants::*;
72 use rustc_apfloat::FloatConvert;
76 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
78 FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
79 FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
84 let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
86 FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
87 FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
91 TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
92 Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
95 TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
96 Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
99 TyFloat(_) => Ok(PrimVal::Bytes(bits)),
100 _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
104 fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
105 use rustc::ty::TypeVariants::*;
107 // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
109 TyInt(IntTy::Isize) |
110 TyUint(UintTy::Usize) => Ok(PrimVal::Ptr(ptr)),
111 TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
112 _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),