]>
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 { | |
32 | let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }; | |
33 | if fx.tcx.sess.target.is_like_windows { | |
34 | let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); | |
35 | let (lhs_ptr, lhs_extra) = lhs.force_stack(fx); | |
36 | let (rhs_ptr, rhs_extra) = rhs.force_stack(fx); | |
37 | assert!(lhs_extra.is_none()); | |
38 | assert!(rhs_extra.is_none()); | |
39 | let args = [ | |
40 | ret_place.to_ptr().get_addr(fx), | |
41 | lhs_ptr.get_addr(fx), | |
42 | rhs_ptr.get_addr(fx), | |
43 | ]; | |
44 | fx.lib_call( | |
45 | "__multi3", | |
46 | vec![ | |
47 | AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), | |
48 | AbiParam::new(fx.pointer_type), | |
49 | AbiParam::new(fx.pointer_type), | |
50 | ], | |
51 | vec![], | |
52 | &args, | |
53 | ); | |
54 | Some(ret_place.to_cvalue(fx)) | |
55 | } else { | |
56 | Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty)) | |
57 | } | |
58 | } else { | |
9ffffee4 | 59 | let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]); |
94222f64 XL |
60 | let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32)); |
61 | let lhs = lhs.load_scalar(fx); | |
62 | let rhs = rhs.load_scalar(fx); | |
63 | let oflow_ptr = oflow.to_ptr().get_addr(fx); | |
64 | let res = fx.lib_call( | |
65 | "__muloti4", | |
cdc7bbd5 | 66 | vec![ |
94222f64 XL |
67 | AbiParam::new(types::I128), |
68 | AbiParam::new(types::I128), | |
69 | AbiParam::new(fx.pointer_type), | |
cdc7bbd5 | 70 | ], |
94222f64 XL |
71 | vec![AbiParam::new(types::I128)], |
72 | &[lhs, rhs, oflow_ptr], | |
73 | )[0]; | |
74 | let oflow = oflow.to_cvalue(fx).load_scalar(fx); | |
75 | let oflow = fx.bcx.ins().ireduce(types::I8, oflow); | |
76 | Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty))) | |
cdc7bbd5 | 77 | } |
29967ef6 | 78 | } |
5869c6ff XL |
79 | BinOp::Add | BinOp::Sub | BinOp::Mul => { |
80 | assert!(checked); | |
9ffffee4 | 81 | let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]); |
5869c6ff | 82 | let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); |
cdc7bbd5 XL |
83 | let (param_types, args) = if fx.tcx.sess.target.is_like_windows { |
84 | let (lhs_ptr, lhs_extra) = lhs.force_stack(fx); | |
85 | let (rhs_ptr, rhs_extra) = rhs.force_stack(fx); | |
86 | assert!(lhs_extra.is_none()); | |
87 | assert!(rhs_extra.is_none()); | |
88 | ( | |
89 | vec![ | |
94222f64 XL |
90 | AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), |
91 | AbiParam::new(fx.pointer_type), | |
92 | AbiParam::new(fx.pointer_type), | |
cdc7bbd5 XL |
93 | ], |
94 | [out_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)], | |
95 | ) | |
96 | } else { | |
97 | ( | |
98 | vec![ | |
94222f64 | 99 | AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn), |
cdc7bbd5 XL |
100 | AbiParam::new(types::I128), |
101 | AbiParam::new(types::I128), | |
102 | ], | |
103 | [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)], | |
104 | ) | |
105 | }; | |
5869c6ff XL |
106 | let name = match (bin_op, is_signed) { |
107 | (BinOp::Add, false) => "__rust_u128_addo", | |
108 | (BinOp::Add, true) => "__rust_i128_addo", | |
109 | (BinOp::Sub, false) => "__rust_u128_subo", | |
110 | (BinOp::Sub, true) => "__rust_i128_subo", | |
111 | (BinOp::Mul, false) => "__rust_u128_mulo", | |
5869c6ff | 112 | _ => unreachable!(), |
29967ef6 | 113 | }; |
5869c6ff XL |
114 | fx.lib_call(name, param_types, vec![], &args); |
115 | Some(out_place.to_cvalue(fx)) | |
29967ef6 | 116 | } |
5869c6ff | 117 | BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), |
cdc7bbd5 | 118 | BinOp::Div | BinOp::Rem => { |
29967ef6 | 119 | assert!(!checked); |
cdc7bbd5 XL |
120 | let name = match (bin_op, is_signed) { |
121 | (BinOp::Div, false) => "__udivti3", | |
122 | (BinOp::Div, true) => "__divti3", | |
123 | (BinOp::Rem, false) => "__umodti3", | |
124 | (BinOp::Rem, true) => "__modti3", | |
125 | _ => unreachable!(), | |
126 | }; | |
127 | if fx.tcx.sess.target.is_like_windows { | |
128 | let (lhs_ptr, lhs_extra) = lhs.force_stack(fx); | |
129 | let (rhs_ptr, rhs_extra) = rhs.force_stack(fx); | |
130 | assert!(lhs_extra.is_none()); | |
131 | assert!(rhs_extra.is_none()); | |
132 | let args = [lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)]; | |
133 | let ret = fx.lib_call( | |
134 | name, | |
94222f64 | 135 | vec![AbiParam::new(fx.pointer_type), AbiParam::new(fx.pointer_type)], |
cdc7bbd5 XL |
136 | vec![AbiParam::new(types::I64X2)], |
137 | &args, | |
138 | )[0]; | |
139 | // FIXME use bitcast instead of store to get from i64x2 to i128 | |
140 | let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); | |
141 | ret_place.to_ptr().store(fx, ret, MemFlags::trusted()); | |
142 | Some(ret_place.to_cvalue(fx)) | |
29967ef6 | 143 | } else { |
cdc7bbd5 | 144 | Some(fx.easy_call(name, &[lhs, rhs], lhs.layout().ty)) |
29967ef6 XL |
145 | } |
146 | } | |
147 | BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => { | |
148 | assert!(!checked); | |
149 | None | |
150 | } | |
94222f64 | 151 | BinOp::Shl | BinOp::Shr => None, |
29967ef6 XL |
152 | } |
153 | } |