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