]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Various number casting functions |
2 | ||
3 | use crate::prelude::*; | |
4 | ||
5 | pub(crate) fn clif_intcast( | |
6a06907d | 6 | fx: &mut FunctionCx<'_, '_, '_>, |
29967ef6 XL |
7 | val: Value, |
8 | to: Type, | |
9 | signed: bool, | |
10 | ) -> Value { | |
11 | let from = fx.bcx.func.dfg.value_type(val); | |
12 | match (from, to) { | |
13 | // equal | |
14 | (_, _) if from == to => val, | |
15 | ||
16 | // extend | |
29967ef6 XL |
17 | (_, _) if to.wider_or_equal(from) => { |
18 | if signed { | |
19 | fx.bcx.ins().sextend(to, val) | |
20 | } else { | |
21 | fx.bcx.ins().uextend(to, val) | |
22 | } | |
23 | } | |
24 | ||
25 | // reduce | |
29967ef6 XL |
26 | (_, _) => fx.bcx.ins().ireduce(to, val), |
27 | } | |
28 | } | |
29 | ||
30 | pub(crate) fn clif_int_or_float_cast( | |
6a06907d | 31 | fx: &mut FunctionCx<'_, '_, '_>, |
29967ef6 XL |
32 | from: Value, |
33 | from_signed: bool, | |
34 | to_ty: Type, | |
35 | to_signed: bool, | |
36 | ) -> Value { | |
37 | let from_ty = fx.bcx.func.dfg.value_type(from); | |
38 | ||
39 | if from_ty.is_int() && to_ty.is_int() { | |
40 | // int-like -> int-like | |
41 | clif_intcast( | |
42 | fx, | |
43 | from, | |
44 | to_ty, | |
45 | // This is correct as either from_signed == to_signed (=> this is trivially correct) | |
46 | // Or from_clif_ty == to_clif_ty, which means this is a no-op. | |
47 | from_signed, | |
48 | ) | |
49 | } else if from_ty.is_int() && to_ty.is_float() { | |
50 | if from_ty == types::I128 { | |
51 | // _______ss__f_ | |
52 | // __float tisf: i128 -> f32 | |
53 | // __float tidf: i128 -> f64 | |
54 | // __floatuntisf: u128 -> f32 | |
55 | // __floatuntidf: u128 -> f64 | |
56 | ||
57 | let name = format!( | |
58 | "__float{sign}ti{flt}f", | |
59 | sign = if from_signed { "" } else { "un" }, | |
60 | flt = match to_ty { | |
61 | types::F32 => "s", | |
62 | types::F64 => "d", | |
63 | _ => unreachable!("{:?}", to_ty), | |
64 | }, | |
65 | ); | |
66 | ||
6a06907d | 67 | let from_rust_ty = if from_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }; |
29967ef6 XL |
68 | |
69 | let to_rust_ty = match to_ty { | |
70 | types::F32 => fx.tcx.types.f32, | |
71 | types::F64 => fx.tcx.types.f64, | |
72 | _ => unreachable!(), | |
73 | }; | |
74 | ||
75 | return fx | |
6a06907d | 76 | .easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty) |
29967ef6 XL |
77 | .load_scalar(fx); |
78 | } | |
79 | ||
80 | // int-like -> float | |
81 | if from_signed { | |
82 | fx.bcx.ins().fcvt_from_sint(to_ty, from) | |
83 | } else { | |
84 | fx.bcx.ins().fcvt_from_uint(to_ty, from) | |
85 | } | |
86 | } else if from_ty.is_float() && to_ty.is_int() { | |
04454e1e | 87 | let val = if to_ty == types::I128 { |
29967ef6 XL |
88 | // _____sssf___ |
89 | // __fix sfti: f32 -> i128 | |
90 | // __fix dfti: f64 -> i128 | |
91 | // __fixunssfti: f32 -> u128 | |
92 | // __fixunsdfti: f64 -> u128 | |
93 | ||
94 | let name = format!( | |
95 | "__fix{sign}{flt}fti", | |
96 | sign = if to_signed { "" } else { "uns" }, | |
97 | flt = match from_ty { | |
98 | types::F32 => "s", | |
99 | types::F64 => "d", | |
100 | _ => unreachable!("{:?}", to_ty), | |
101 | }, | |
102 | ); | |
103 | ||
104 | let from_rust_ty = match from_ty { | |
105 | types::F32 => fx.tcx.types.f32, | |
106 | types::F64 => fx.tcx.types.f64, | |
107 | _ => unreachable!(), | |
108 | }; | |
109 | ||
6a06907d | 110 | let to_rust_ty = if to_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }; |
29967ef6 | 111 | |
04454e1e FG |
112 | fx.easy_call(&name, &[CValue::by_val(from, fx.layout_of(from_rust_ty))], to_rust_ty) |
113 | .load_scalar(fx) | |
114 | } else if to_ty == types::I8 || to_ty == types::I16 { | |
29967ef6 XL |
115 | // FIXME implement fcvt_to_*int_sat.i8/i16 |
116 | let val = if to_signed { | |
117 | fx.bcx.ins().fcvt_to_sint_sat(types::I32, from) | |
118 | } else { | |
119 | fx.bcx.ins().fcvt_to_uint_sat(types::I32, from) | |
120 | }; | |
121 | let (min, max) = match (to_ty, to_signed) { | |
122 | (types::I8, false) => (0, i64::from(u8::MAX)), | |
123 | (types::I16, false) => (0, i64::from(u16::MAX)), | |
124 | (types::I8, true) => (i64::from(i8::MIN), i64::from(i8::MAX)), | |
125 | (types::I16, true) => (i64::from(i16::MIN), i64::from(i16::MAX)), | |
126 | _ => unreachable!(), | |
127 | }; | |
128 | let min_val = fx.bcx.ins().iconst(types::I32, min); | |
129 | let max_val = fx.bcx.ins().iconst(types::I32, max); | |
130 | ||
131 | let val = if to_signed { | |
132 | let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, min); | |
133 | let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, max); | |
134 | let bottom_capped = fx.bcx.ins().select(has_underflow, min_val, val); | |
135 | fx.bcx.ins().select(has_overflow, max_val, bottom_capped) | |
136 | } else { | |
137 | let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, max); | |
138 | fx.bcx.ins().select(has_overflow, max_val, val) | |
139 | }; | |
140 | fx.bcx.ins().ireduce(to_ty, val) | |
141 | } else if to_signed { | |
142 | fx.bcx.ins().fcvt_to_sint_sat(to_ty, from) | |
143 | } else { | |
144 | fx.bcx.ins().fcvt_to_uint_sat(to_ty, from) | |
04454e1e FG |
145 | }; |
146 | ||
147 | if let Some(false) = fx.tcx.sess.opts.debugging_opts.saturating_float_casts { | |
148 | return val; | |
149 | } | |
150 | ||
151 | let is_not_nan = fx.bcx.ins().fcmp(FloatCC::Equal, from, from); | |
152 | if to_ty == types::I128 { | |
153 | // FIXME(bytecodealliance/wasmtime#3963): select.i128 on fcmp eq miscompiles | |
154 | let (lsb, msb) = fx.bcx.ins().isplit(val); | |
155 | let zero = fx.bcx.ins().iconst(types::I64, 0); | |
156 | let lsb = fx.bcx.ins().select(is_not_nan, lsb, zero); | |
157 | let msb = fx.bcx.ins().select(is_not_nan, msb, zero); | |
158 | fx.bcx.ins().iconcat(lsb, msb) | |
159 | } else { | |
160 | let zero = fx.bcx.ins().iconst(to_ty, 0); | |
161 | fx.bcx.ins().select(is_not_nan, val, zero) | |
29967ef6 XL |
162 | } |
163 | } else if from_ty.is_float() && to_ty.is_float() { | |
164 | // float -> float | |
165 | match (from_ty, to_ty) { | |
166 | (types::F32, types::F64) => fx.bcx.ins().fpromote(types::F64, from), | |
167 | (types::F64, types::F32) => fx.bcx.ins().fdemote(types::F32, from), | |
168 | _ => from, | |
169 | } | |
170 | } else { | |
171 | unreachable!("cast value from {:?} to {:?}", from_ty, to_ty); | |
172 | } | |
173 | } |