1 //! Replaces 128-bit operators with lang item calls where necessary
3 use cranelift_codegen::ir::ArgumentPurpose;
7 pub(crate) fn maybe_codegen<'tcx>(
8 fx: &mut FunctionCx<'_, '_, 'tcx>,
13 ) -> Option<CValue<'tcx>> {
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
22 let is_signed = type_sign(lhs.layout().ty);
25 BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
29 BinOp::Add | BinOp::Sub if !checked => None,
30 BinOp::Mul if !checked => {
31 let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
32 if fx.tcx.sess.target.is_like_windows {
33 let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
34 let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
35 let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
36 assert!(lhs_extra.is_none());
37 assert!(rhs_extra.is_none());
39 [ret_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)];
43 AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
44 AbiParam::new(fx.pointer_type),
45 AbiParam::new(fx.pointer_type),
50 Some(ret_place.to_cvalue(fx))
52 Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty))
55 BinOp::Add | BinOp::Sub | BinOp::Mul => {
57 let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
58 let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
59 let (param_types, args) = if fx.tcx.sess.target.is_like_windows {
60 let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
61 let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
62 assert!(lhs_extra.is_none());
63 assert!(rhs_extra.is_none());
66 AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
67 AbiParam::new(fx.pointer_type),
68 AbiParam::new(fx.pointer_type),
70 [out_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)],
75 AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
76 AbiParam::new(types::I128),
77 AbiParam::new(types::I128),
79 [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)],
82 let name = match (bin_op, is_signed) {
83 (BinOp::Add, false) => "__rust_u128_addo",
84 (BinOp::Add, true) => "__rust_i128_addo",
85 (BinOp::Sub, false) => "__rust_u128_subo",
86 (BinOp::Sub, true) => "__rust_i128_subo",
87 (BinOp::Mul, false) => "__rust_u128_mulo",
88 (BinOp::Mul, true) => "__rust_i128_mulo",
91 fx.lib_call(name, param_types, vec![], &args);
92 Some(out_place.to_cvalue(fx))
94 BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
95 BinOp::Div | BinOp::Rem => {
97 let name = match (bin_op, is_signed) {
98 (BinOp::Div, false) => "__udivti3",
99 (BinOp::Div, true) => "__divti3",
100 (BinOp::Rem, false) => "__umodti3",
101 (BinOp::Rem, true) => "__modti3",
104 if fx.tcx.sess.target.is_like_windows {
105 let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
106 let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
107 assert!(lhs_extra.is_none());
108 assert!(rhs_extra.is_none());
109 let args = [lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)];
110 let ret = fx.lib_call(
112 vec![AbiParam::new(fx.pointer_type), AbiParam::new(fx.pointer_type)],
113 vec![AbiParam::new(types::I64X2)],
116 // FIXME use bitcast instead of store to get from i64x2 to i128
117 let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
118 ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
119 Some(ret_place.to_cvalue(fx))
121 Some(fx.easy_call(name, &[lhs, rhs], lhs.layout().ty))
124 BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
128 BinOp::Shl | BinOp::Shr => None,