1 //! Various number casting functions
5 pub(crate) fn clif_intcast(
6 fx: &mut FunctionCx<'_, '_, '_>,
11 let from = fx.bcx.func.dfg.value_type(val);
14 (_, _) if from == to => val,
18 let lo = if from == types::I64 {
21 fx.bcx.ins().sextend(types::I64, val)
23 fx.bcx.ins().uextend(types::I64, val)
26 fx.bcx.ins().sshr_imm(lo, 63)
28 fx.bcx.ins().iconst(types::I64, 0)
30 fx.bcx.ins().iconcat(lo, hi)
32 (_, _) if to.wider_or_equal(from) => {
34 fx.bcx.ins().sextend(to, val)
36 fx.bcx.ins().uextend(to, val)
42 let (lsb, _msb) = fx.bcx.ins().isplit(val);
43 if to == types::I64 { lsb } else { fx.bcx.ins().ireduce(to, lsb) }
45 (_, _) => fx.bcx.ins().ireduce(to, val),
49 pub(crate) fn clif_int_or_float_cast(
50 fx: &mut FunctionCx<'_, '_, '_>,
56 let from_ty = fx.bcx.func.dfg.value_type(from);
58 if from_ty.is_int() && to_ty.is_int() {
59 // int-like -> int-like
64 // This is correct as either from_signed == to_signed (=> this is trivially correct)
65 // Or from_clif_ty == to_clif_ty, which means this is a no-op.
68 } else if from_ty.is_int() && to_ty.is_float() {
69 if from_ty == types::I128 {
71 // __float tisf: i128 -> f32
72 // __float tidf: i128 -> f64
73 // __floatuntisf: u128 -> f32
74 // __floatuntidf: u128 -> f64
77 "__float{sign}ti{flt}f",
78 sign = if from_signed { "" } else { "un" },
82 _ => unreachable!("{:?}", to_ty),
86 let from_rust_ty = if from_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
88 let to_rust_ty = match to_ty {
89 types::F32 => fx.tcx.types.f32,
90 types::F64 => fx.tcx.types.f64,
95 .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
101 fx.bcx.ins().fcvt_from_sint(to_ty, from)
103 fx.bcx.ins().fcvt_from_uint(to_ty, from)
105 } else if from_ty.is_float() && to_ty.is_int() {
106 if to_ty == types::I128 {
108 // __fix sfti: f32 -> i128
109 // __fix dfti: f64 -> i128
110 // __fixunssfti: f32 -> u128
111 // __fixunsdfti: f64 -> u128
114 "__fix{sign}{flt}fti",
115 sign = if to_signed { "" } else { "uns" },
116 flt = match from_ty {
119 _ => unreachable!("{:?}", to_ty),
123 let from_rust_ty = match from_ty {
124 types::F32 => fx.tcx.types.f32,
125 types::F64 => fx.tcx.types.f64,
129 let to_rust_ty = if to_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
132 .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty)
137 if to_ty == types::I8 || to_ty == types::I16 {
138 // FIXME implement fcvt_to_*int_sat.i8/i16
139 let val = if to_signed {
140 fx.bcx.ins().fcvt_to_sint_sat(types::I32, from)
142 fx.bcx.ins().fcvt_to_uint_sat(types::I32, from)
144 let (min, max) = match (to_ty, to_signed) {
145 (types::I8, false) => (0, i64::from(u8::MAX)),
146 (types::I16, false) => (0, i64::from(u16::MAX)),
147 (types::I8, true) => (i64::from(i8::MIN), i64::from(i8::MAX)),
148 (types::I16, true) => (i64::from(i16::MIN), i64::from(i16::MAX)),
151 let min_val = fx.bcx.ins().iconst(types::I32, min);
152 let max_val = fx.bcx.ins().iconst(types::I32, max);
154 let val = if to_signed {
155 let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, min);
156 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, max);
157 let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val);
158 fx.bcx.ins().select(has_overflow, max_val, bottom_capped)
160 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, max);
161 fx.bcx.ins().select(has_overflow, max_val, val)
163 fx.bcx.ins().ireduce(to_ty, val)
164 } else if to_signed {
165 fx.bcx.ins().fcvt_to_sint_sat(to_ty, from)
167 fx.bcx.ins().fcvt_to_uint_sat(to_ty, from)
169 } else if from_ty.is_float() && to_ty.is_float() {
171 match (from_ty, to_ty) {
172 (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from),
173 (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from),
177 unreachable!("cast value from {:?} to {:?}", from_ty, to_ty);