1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use rustc::ty::Ty;
use rustc::ty::layout::LayoutOf;
use syntax::ast::{FloatTy, IntTy, UintTy};
use rustc_apfloat::ieee::{Single, Double};
use super::{EvalContext, Machine};
use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmetic};
use rustc_apfloat::Float;
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
pub(super) fn cast_primval(
&self,
val: PrimVal,
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
match val {
PrimVal::Undef => Ok(PrimVal::Undef),
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
PrimVal::Bytes(b) => {
match src_ty.sty {
TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
_ => self.cast_from_int(b, src_ty, dest_ty),
}
}
}
}
fn cast_from_int(
&self,
v: u128,
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
let signed = self.layout_of(src_ty)?.abi.is_signed();
let v = if signed {
self.sign_extend(v, src_ty)?
} else {
v
};
trace!("cast_from_int: {}, {}, {}", v, src_ty, dest_ty);
use rustc::ty::TypeVariants::*;
match dest_ty.sty {
TyInt(_) | TyUint(_) => {
let v = self.truncate(v, dest_ty)?;
Ok(PrimVal::Bytes(v))
}
TyFloat(FloatTy::F32) if signed => Ok(PrimVal::Bytes(Single::from_i128(v as i128).value.to_bits())),
TyFloat(FloatTy::F64) if signed => Ok(PrimVal::Bytes(Double::from_i128(v as i128).value.to_bits())),
TyFloat(FloatTy::F32) => Ok(PrimVal::Bytes(Single::from_u128(v).value.to_bits())),
TyFloat(FloatTy::F64) => Ok(PrimVal::Bytes(Double::from_u128(v).value.to_bits())),
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
TyChar => err!(InvalidChar(v)),
TyRawPtr(_) => {
Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
},
_ => err!(Unimplemented(format!("int to {:?} cast", dest_ty))),
}
}
fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
use rustc_apfloat::FloatConvert;
match dest_ty.sty {
TyUint(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
match fty {
FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)),
FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)),
}
},
TyInt(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8);
match fty {
FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)),
FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)),
}
},
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
Ok(PrimVal::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
},
TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
Ok(PrimVal::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
},
TyFloat(_) => Ok(PrimVal::Bytes(bits)),
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
}
}
fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
TyRawPtr(_) |
TyInt(IntTy::Isize) |
TyUint(UintTy::Usize) => Ok(PrimVal::Ptr(ptr)),
TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes),
_ => err!(Unimplemented(format!("ptr to {:?} cast", ty))),
}
}
}