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