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