]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Replaces 128-bit operators with lang item calls where necessary |
2 | ||
5869c6ff XL |
3 | use cranelift_codegen::ir::ArgumentPurpose; |
4 | ||
29967ef6 XL |
5 | use crate::prelude::*; |
6 | ||
7 | pub(crate) fn maybe_codegen<'tcx>( | |
6a06907d | 8 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
29967ef6 XL |
9 | bin_op: BinOp, |
10 | checked: bool, | |
11 | lhs: CValue<'tcx>, | |
12 | rhs: CValue<'tcx>, | |
13 | ) -> Option<CValue<'tcx>> { | |
6a06907d XL |
14 | if lhs.layout().ty != fx.tcx.types.u128 |
15 | && lhs.layout().ty != fx.tcx.types.i128 | |
16 | && rhs.layout().ty != fx.tcx.types.u128 | |
17 | && rhs.layout().ty != fx.tcx.types.i128 | |
18 | { | |
29967ef6 XL |
19 | return None; |
20 | } | |
21 | ||
29967ef6 XL |
22 | let is_signed = type_sign(lhs.layout().ty); |
23 | ||
24 | match bin_op { | |
25 | BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => { | |
26 | assert!(!checked); | |
27 | None | |
28 | } | |
29 | BinOp::Add | BinOp::Sub if !checked => None, | |
94222f64 XL |
30 | BinOp::Mul if !checked || is_signed => { |
31 | if !checked { | |
353b0b11 FG |
32 | let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; |
33 | let ret_val = fx.lib_call( | |
34 | "__multi3", | |
35 | vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], | |
36 | vec![AbiParam::new(types::I128)], | |
37 | &args, | |
38 | )[0]; | |
39 | Some(CValue::by_val( | |
40 | ret_val, | |
41 | fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }), | |
42 | )) | |
94222f64 | 43 | } else { |
9ffffee4 | 44 | let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]); |
94222f64 XL |
45 | let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32)); |
46 | let lhs = lhs.load_scalar(fx); | |
47 | let rhs = rhs.load_scalar(fx); | |
48 | let oflow_ptr = oflow.to_ptr().get_addr(fx); | |
353b0b11 | 49 | let res = fx.lib_call_unadjusted( |
94222f64 | 50 | "__muloti4", |
cdc7bbd5 | 51 | vec![ |
94222f64 XL |
52 | AbiParam::new(types::I128), |
53 | AbiParam::new(types::I128), | |
54 | AbiParam::new(fx.pointer_type), | |
cdc7bbd5 | 55 | ], |
94222f64 XL |
56 | vec![AbiParam::new(types::I128)], |
57 | &[lhs, rhs, oflow_ptr], | |
58 | )[0]; | |
59 | let oflow = oflow.to_cvalue(fx).load_scalar(fx); | |
60 | let oflow = fx.bcx.ins().ireduce(types::I8, oflow); | |
61 | Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty))) | |
cdc7bbd5 | 62 | } |
29967ef6 | 63 | } |
5869c6ff XL |
64 | BinOp::Add | BinOp::Sub | BinOp::Mul => { |
65 | assert!(checked); | |
9ffffee4 | 66 | let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]); |
5869c6ff | 67 | let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); |
353b0b11 FG |
68 | let param_types = vec![ |
69 | AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), | |
70 | AbiParam::new(types::I128), | |
71 | AbiParam::new(types::I128), | |
72 | ]; | |
73 | let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)]; | |
5869c6ff XL |
74 | let name = match (bin_op, is_signed) { |
75 | (BinOp::Add, false) => "__rust_u128_addo", | |
76 | (BinOp::Add, true) => "__rust_i128_addo", | |
77 | (BinOp::Sub, false) => "__rust_u128_subo", | |
78 | (BinOp::Sub, true) => "__rust_i128_subo", | |
79 | (BinOp::Mul, false) => "__rust_u128_mulo", | |
5869c6ff | 80 | _ => unreachable!(), |
29967ef6 | 81 | }; |
5869c6ff XL |
82 | fx.lib_call(name, param_types, vec![], &args); |
83 | Some(out_place.to_cvalue(fx)) | |
29967ef6 | 84 | } |
5869c6ff | 85 | BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), |
cdc7bbd5 | 86 | BinOp::Div | BinOp::Rem => { |
29967ef6 | 87 | assert!(!checked); |
cdc7bbd5 XL |
88 | let name = match (bin_op, is_signed) { |
89 | (BinOp::Div, false) => "__udivti3", | |
90 | (BinOp::Div, true) => "__divti3", | |
91 | (BinOp::Rem, false) => "__umodti3", | |
92 | (BinOp::Rem, true) => "__modti3", | |
93 | _ => unreachable!(), | |
94 | }; | |
95 | if fx.tcx.sess.target.is_like_windows { | |
353b0b11 | 96 | let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; |
cdc7bbd5 XL |
97 | let ret = fx.lib_call( |
98 | name, | |
353b0b11 | 99 | vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], |
cdc7bbd5 XL |
100 | vec![AbiParam::new(types::I64X2)], |
101 | &args, | |
102 | )[0]; | |
103 | // FIXME use bitcast instead of store to get from i64x2 to i128 | |
104 | let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); | |
105 | ret_place.to_ptr().store(fx, ret, MemFlags::trusted()); | |
106 | Some(ret_place.to_cvalue(fx)) | |
29967ef6 | 107 | } else { |
353b0b11 FG |
108 | let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)]; |
109 | let ret_val = fx.lib_call( | |
110 | name, | |
111 | vec![AbiParam::new(types::I128), AbiParam::new(types::I128)], | |
112 | vec![AbiParam::new(types::I128)], | |
113 | &args, | |
114 | )[0]; | |
115 | Some(CValue::by_val(ret_val, lhs.layout())) | |
29967ef6 XL |
116 | } |
117 | } | |
118 | BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => { | |
119 | assert!(!checked); | |
120 | None | |
121 | } | |
94222f64 | 122 | BinOp::Shl | BinOp::Shr => None, |
29967ef6 XL |
123 | } |
124 | } |