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
,
17 (_
, _
) if to
.wider_or_equal(from
) => {
19 fx
.bcx
.ins().sextend(to
, val
)
21 fx
.bcx
.ins().uextend(to
, val
)
26 (_
, _
) => fx
.bcx
.ins().ireduce(to
, val
),
30 pub(crate) fn clif_int_or_float_cast(
31 fx
: &mut FunctionCx
<'_
, '_
, '_
>,
37 let from_ty
= fx
.bcx
.func
.dfg
.value_type(from
);
39 if from_ty
.is_int() && to_ty
.is_int() {
40 // int-like -> int-like
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.
49 } else if from_ty
.is_int() && to_ty
.is_float() {
50 if from_ty
== types
::I128
{
52 // __float tisf: i128 -> f32
53 // __float tidf: i128 -> f64
54 // __floatuntisf: u128 -> f32
55 // __floatuntidf: u128 -> f64
58 "__float{sign}ti{flt}f",
59 sign
= if from_signed { "" }
else { "un" }
,
63 _
=> unreachable
!("{:?}", to_ty
),
67 let from_rust_ty
= if from_signed { fx.tcx.types.i128 }
else { fx.tcx.types.u128 }
;
69 let to_rust_ty
= match to_ty
{
70 types
::F32
=> fx
.tcx
.types
.f32,
71 types
::F64
=> fx
.tcx
.types
.f64,
76 .easy_call(&name
, &[CValue
::by_val(from
, fx
.layout_of(from_rust_ty
))], to_rust_ty
)
82 fx
.bcx
.ins().fcvt_from_sint(to_ty
, from
)
84 fx
.bcx
.ins().fcvt_from_uint(to_ty
, from
)
86 } else if from_ty
.is_float() && to_ty
.is_int() {
87 if to_ty
== types
::I128
{
89 // __fix sfti: f32 -> i128
90 // __fix dfti: f64 -> i128
91 // __fixunssfti: f32 -> u128
92 // __fixunsdfti: f64 -> u128
95 "__fix{sign}{flt}fti",
96 sign
= if to_signed { "" }
else { "uns" }
,
100 _
=> unreachable
!("{:?}", to_ty
),
104 let from_rust_ty
= match from_ty
{
105 types
::F32
=> fx
.tcx
.types
.f32,
106 types
::F64
=> fx
.tcx
.types
.f64,
110 let to_rust_ty
= if to_signed { fx.tcx.types.i128 }
else { fx.tcx.types.u128 }
;
113 .easy_call(&name
, &[CValue
::by_val(from
, fx
.layout_of(from_rust_ty
))], to_rust_ty
)
118 if to_ty
== types
::I8
|| to_ty
== types
::I16
{
119 // FIXME implement fcvt_to_*int_sat.i8/i16
120 let val
= if to_signed
{
121 fx
.bcx
.ins().fcvt_to_sint_sat(types
::I32
, from
)
123 fx
.bcx
.ins().fcvt_to_uint_sat(types
::I32
, from
)
125 let (min
, max
) = match (to_ty
, to_signed
) {
126 (types
::I8
, false) => (0, i64::from(u8::MAX
)),
127 (types
::I16
, false) => (0, i64::from(u16::MAX
)),
128 (types
::I8
, true) => (i64::from(i8::MIN
), i64::from(i8::MAX
)),
129 (types
::I16
, true) => (i64::from(i16::MIN
), i64::from(i16::MAX
)),
132 let min_val
= fx
.bcx
.ins().iconst(types
::I32
, min
);
133 let max_val
= fx
.bcx
.ins().iconst(types
::I32
, max
);
135 let val
= if to_signed
{
136 let has_underflow
= fx
.bcx
.ins().icmp_imm(IntCC
::SignedLessThan
, val
, min
);
137 let has_overflow
= fx
.bcx
.ins().icmp_imm(IntCC
::SignedGreaterThan
, val
, max
);
138 let bottom_capped
= fx
.bcx
.ins().select(has_underflow
, min_val
, val
);
139 fx
.bcx
.ins().select(has_overflow
, max_val
, bottom_capped
)
141 let has_overflow
= fx
.bcx
.ins().icmp_imm(IntCC
::UnsignedGreaterThan
, val
, max
);
142 fx
.bcx
.ins().select(has_overflow
, max_val
, val
)
144 fx
.bcx
.ins().ireduce(to_ty
, val
)
145 } else if to_signed
{
146 fx
.bcx
.ins().fcvt_to_sint_sat(to_ty
, from
)
148 fx
.bcx
.ins().fcvt_to_uint_sat(to_ty
, from
)
150 } else if from_ty
.is_float() && to_ty
.is_float() {
152 match (from_ty
, to_ty
) {
153 (types
::F32
, types
::F64
) => fx
.bcx
.ins().fpromote(types
::F64
, from
),
154 (types
::F64
, types
::F32
) => fx
.bcx
.ins().fdemote(types
::F32
, from
),
158 unreachable
!("cast value from {:?} to {:?}", from_ty
, to_ty
);