]>
git.proxmox.com Git - rustc.git/blob - compiler/rustc_codegen_cranelift/src/codegen_i128.rs
1 //! Replaces 128-bit operators with lang item calls where necessary
5 pub(crate) fn maybe_codegen
<'tcx
>(
6 fx
: &mut FunctionCx
<'_
, 'tcx
, impl Module
>,
11 ) -> Option
<CValue
<'tcx
>> {
12 if lhs
.layout().ty
!= fx
.tcx
.types
.u128
&& lhs
.layout().ty
!= fx
.tcx
.types
.i128
{
16 let lhs_val
= lhs
.load_scalar(fx
);
17 let rhs_val
= rhs
.load_scalar(fx
);
19 let is_signed
= type_sign(lhs
.layout().ty
);
22 BinOp
::BitAnd
| BinOp
::BitOr
| BinOp
::BitXor
=> {
26 BinOp
::Add
| BinOp
::Sub
if !checked
=> None
,
28 let out_ty
= fx
.tcx
.mk_tup([lhs
.layout().ty
, fx
.tcx
.types
.bool
].iter());
29 return Some(if is_signed
{
30 fx
.easy_call("__rust_i128_addo", &[lhs
, rhs
], out_ty
)
32 fx
.easy_call("__rust_u128_addo", &[lhs
, rhs
], out_ty
)
36 let out_ty
= fx
.tcx
.mk_tup([lhs
.layout().ty
, fx
.tcx
.types
.bool
].iter());
37 return Some(if is_signed
{
38 fx
.easy_call("__rust_i128_subo", &[lhs
, rhs
], out_ty
)
40 fx
.easy_call("__rust_u128_subo", &[lhs
, rhs
], out_ty
)
43 BinOp
::Offset
=> unreachable
!("offset should only be used on pointers, not 128bit ints"),
45 let res
= if checked
{
46 let out_ty
= fx
.tcx
.mk_tup([lhs
.layout().ty
, fx
.tcx
.types
.bool
].iter());
48 fx
.easy_call("__rust_i128_mulo", &[lhs
, rhs
], out_ty
)
50 fx
.easy_call("__rust_u128_mulo", &[lhs
, rhs
], out_ty
)
53 let val_ty
= if is_signed
{
58 fx
.easy_call("__multi3", &[lhs
, rhs
], val_ty
)
65 Some(fx
.easy_call("__divti3", &[lhs
, rhs
], fx
.tcx
.types
.i128
))
67 Some(fx
.easy_call("__udivti3", &[lhs
, rhs
], fx
.tcx
.types
.u128
))
73 Some(fx
.easy_call("__modti3", &[lhs
, rhs
], fx
.tcx
.types
.i128
))
75 Some(fx
.easy_call("__umodti3", &[lhs
, rhs
], fx
.tcx
.types
.u128
))
78 BinOp
::Lt
| BinOp
::Le
| BinOp
::Eq
| BinOp
::Ge
| BinOp
::Gt
| BinOp
::Ne
=> {
82 BinOp
::Shl
| BinOp
::Shr
=> {
83 let is_overflow
= if checked
{
86 // FIXME support non 128bit rhs
87 /*let (rhs_lsb, rhs_msb) = fx.bcx.ins().isplit(rhs_val);
88 let rhs_msb_gt_0 = fx.bcx.ins().icmp_imm(IntCC::NotEqual, rhs_msb, 0);
89 let rhs_lsb_ge_128 = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, rhs_lsb, 127);
90 let is_overflow = fx.bcx.ins().bor(rhs_msb_gt_0, rhs_lsb_ge_128);*/
91 let is_overflow
= fx
.bcx
.ins().bconst(types
::B1
, false);
93 Some(fx
.bcx
.ins().bint(types
::I8
, is_overflow
))
98 // Optimize `val >> 64`, because compiler_builtins uses it to deconstruct an 128bit
99 // integer into its lsb and msb.
100 // https://github.com/rust-lang-nursery/compiler-builtins/blob/79a6a1603d5672cbb9187ff41ff4d9b5048ac1cb/src/int/mod.rs#L217
101 if resolve_value_imm(fx
.bcx
.func
, rhs_val
) == Some(64) {
102 let (lhs_lsb
, lhs_msb
) = fx
.bcx
.ins().isplit(lhs_val
);
103 let all_zeros
= fx
.bcx
.ins().iconst(types
::I64
, 0);
104 let val
= match (bin_op
, is_signed
) {
105 (BinOp
::Shr
, false) => {
106 let val
= fx
.bcx
.ins().iconcat(lhs_msb
, all_zeros
);
107 Some(CValue
::by_val(val
, fx
.layout_of(fx
.tcx
.types
.u128
)))
109 (BinOp
::Shr
, true) => {
110 let sign
= fx
.bcx
.ins().icmp_imm(IntCC
::SignedLessThan
, lhs_msb
, 0);
111 let all_ones
= fx
.bcx
.ins().iconst(types
::I64
, u64::MAX
as i64);
112 let all_sign_bits
= fx
.bcx
.ins().select(sign
, all_zeros
, all_ones
);
114 let val
= fx
.bcx
.ins().iconcat(lhs_msb
, all_sign_bits
);
115 Some(CValue
::by_val(val
, fx
.layout_of(fx
.tcx
.types
.i128
)))
118 let val_ty
= if is_signed
{
123 let val
= fx
.bcx
.ins().iconcat(all_zeros
, lhs_lsb
);
124 Some(CValue
::by_val(val
, fx
.layout_of(val_ty
)))
128 if let Some(val
) = val
{
129 if let Some(is_overflow
) = is_overflow
{
130 let out_ty
= fx
.tcx
.mk_tup([lhs
.layout().ty
, fx
.tcx
.types
.bool
].iter());
131 let val
= val
.load_scalar(fx
);
132 return Some(CValue
::by_val_pair(val
, is_overflow
, fx
.layout_of(out_ty
)));
139 let truncated_rhs
= clif_intcast(fx
, rhs_val
, types
::I32
, false);
140 let truncated_rhs
= CValue
::by_val(truncated_rhs
, fx
.layout_of(fx
.tcx
.types
.u32));
141 let val
= match (bin_op
, is_signed
) {
142 (BinOp
::Shl
, false) => {
143 fx
.easy_call("__ashlti3", &[lhs
, truncated_rhs
], fx
.tcx
.types
.u128
)
145 (BinOp
::Shl
, true) => {
146 fx
.easy_call("__ashlti3", &[lhs
, truncated_rhs
], fx
.tcx
.types
.i128
)
148 (BinOp
::Shr
, false) => {
149 fx
.easy_call("__lshrti3", &[lhs
, truncated_rhs
], fx
.tcx
.types
.u128
)
151 (BinOp
::Shr
, true) => {
152 fx
.easy_call("__ashrti3", &[lhs
, truncated_rhs
], fx
.tcx
.types
.i128
)
154 (_
, _
) => unreachable
!(),
156 if let Some(is_overflow
) = is_overflow
{
157 let out_ty
= fx
.tcx
.mk_tup([lhs
.layout().ty
, fx
.tcx
.types
.bool
].iter());
158 let val
= val
.load_scalar(fx
);
159 Some(CValue
::by_val_pair(val
, is_overflow
, fx
.layout_of(out_ty
)))