]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_cranelift/src/cast.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_codegen_cranelift / src / cast.rs
CommitLineData
29967ef6
XL
1//! Various number casting functions
2
3use crate::prelude::*;
4
5pub(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
30pub(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}