3 pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
19 UnsignedLessThanOrEqual
25 SignedGreaterThanOrEqual
27 UnsignedGreaterThanOrEqual
41 fn codegen_compare_bin_op<'tcx>(
42 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
48 let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
49 let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
50 let val = fx.bcx.ins().bint(types::I8, val);
51 CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
54 pub(crate) fn codegen_binop<'tcx>(
55 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
61 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
62 match in_lhs.layout().ty.kind {
63 ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
64 let signed = type_sign(in_lhs.layout().ty);
65 let lhs = in_lhs.load_scalar(fx);
66 let rhs = in_rhs.load_scalar(fx);
68 let (lhs, rhs) = if (bin_op == BinOp::Eq || bin_op == BinOp::Ne)
69 && (in_lhs.layout().ty.kind == fx.tcx.types.i8.kind
70 || in_lhs.layout().ty.kind == fx.tcx.types.i16.kind)
72 // FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong.
74 fx.bcx.ins().sextend(types::I32, lhs),
75 fx.bcx.ins().sextend(types::I32, rhs),
81 return codegen_compare_bin_op(fx, bin_op, signed, lhs, rhs);
89 match in_lhs.layout().ty.kind {
90 ty::Bool => crate::num::trans_bool_binop(fx, bin_op, in_lhs, in_rhs),
91 ty::Uint(_) | ty::Int(_) => crate::num::trans_int_binop(fx, bin_op, in_lhs, in_rhs),
92 ty::Float(_) => crate::num::trans_float_binop(fx, bin_op, in_lhs, in_rhs),
93 ty::RawPtr(..) | ty::FnPtr(..) => crate::num::trans_ptr_binop(fx, bin_op, in_lhs, in_rhs),
103 pub(crate) fn trans_bool_binop<'tcx>(
104 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
106 in_lhs: CValue<'tcx>,
107 in_rhs: CValue<'tcx>,
109 let lhs = in_lhs.load_scalar(fx);
110 let rhs = in_rhs.load_scalar(fx);
112 let b = fx.bcx.ins();
113 let res = match bin_op {
114 BinOp::BitXor => b.bxor(lhs, rhs),
115 BinOp::BitAnd => b.band(lhs, rhs),
116 BinOp::BitOr => b.bor(lhs, rhs),
117 // Compare binops handles by `codegen_binop`.
118 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
121 CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
124 pub(crate) fn trans_int_binop<'tcx>(
125 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
127 in_lhs: CValue<'tcx>,
128 in_rhs: CValue<'tcx>,
130 if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
134 "int binop requires lhs and rhs of same type"
138 if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) {
142 let signed = type_sign(in_lhs.layout().ty);
144 let lhs = in_lhs.load_scalar(fx);
145 let rhs = in_rhs.load_scalar(fx);
147 let b = fx.bcx.ins();
148 let val = match bin_op {
149 BinOp::Add => b.iadd(lhs, rhs),
150 BinOp::Sub => b.isub(lhs, rhs),
151 BinOp::Mul => b.imul(lhs, rhs),
166 BinOp::BitXor => b.bxor(lhs, rhs),
167 BinOp::BitAnd => b.band(lhs, rhs),
168 BinOp::BitOr => b.bor(lhs, rhs),
170 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
171 let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
172 let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
173 fx.bcx.ins().ishl(lhs, actual_shift)
176 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
177 let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
178 let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
180 fx.bcx.ins().sshr(lhs, actual_shift)
182 fx.bcx.ins().ushr(lhs, actual_shift)
185 // Compare binops handles by `codegen_binop`.
194 CValue::by_val(val, in_lhs.layout())
197 pub(crate) fn trans_checked_int_binop<'tcx>(
198 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
200 in_lhs: CValue<'tcx>,
201 in_rhs: CValue<'tcx>,
203 if bin_op != BinOp::Shl && bin_op != BinOp::Shr {
207 "checked int binop requires lhs and rhs of same type"
211 let lhs = in_lhs.load_scalar(fx);
212 let rhs = in_rhs.load_scalar(fx);
214 if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) {
218 let signed = type_sign(in_lhs.layout().ty);
220 let (res, has_overflow) = match bin_op {
222 /*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs);
224 // FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16
225 let val = fx.bcx.ins().iadd(lhs, rhs);
226 let has_overflow = if !signed {
227 fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs)
229 let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
230 let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs);
231 fx.bcx.ins().bxor(rhs_is_negative, slt)
236 /*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs);
238 // FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16
239 let val = fx.bcx.ins().isub(lhs, rhs);
240 let has_overflow = if !signed {
241 fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs)
243 let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
244 let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs);
245 fx.bcx.ins().bxor(rhs_is_negative, sgt)
250 let ty = fx.bcx.func.dfg.value_type(lhs);
252 types::I8 | types::I16 | types::I32 if !signed => {
253 let lhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), lhs);
254 let rhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), rhs);
255 let val = fx.bcx.ins().imul(lhs, rhs);
256 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, (1 << ty.bits()) - 1);
257 let val = fx.bcx.ins().ireduce(ty, val);
260 types::I8 | types::I16 | types::I32 if signed => {
261 let lhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), lhs);
262 let rhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), rhs);
263 let val = fx.bcx.ins().imul(lhs, rhs);
264 let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, -(1 << (ty.bits() - 1)));
265 let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, (1 << (ty.bits() - 1)) - 1);
266 let val = fx.bcx.ins().ireduce(ty, val);
267 (val, fx.bcx.ins().bor(has_underflow, has_overflow))
270 //let val = fx.easy_call("__mulodi4", &[lhs, rhs, overflow_ptr], types::I64);
271 let val = fx.bcx.ins().imul(lhs, rhs);
272 let has_overflow = if !signed {
273 let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
274 fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
276 let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
277 let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
278 let not_all_ones = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64);
279 fx.bcx.ins().band(not_all_zero, not_all_ones)
283 types::I128 => unreachable!("i128 should have been handled by codegen_i128::maybe_codegen"),
284 _ => unreachable!("invalid non-integer type {}", ty),
288 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
289 let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
290 let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
291 let val = fx.bcx.ins().ishl(lhs, actual_shift);
292 let ty = fx.bcx.func.dfg.value_type(val);
293 let max_shift = i64::from(ty.bits()) - 1;
295 fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
299 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
300 let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
301 let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
302 let val = if !signed {
303 fx.bcx.ins().ushr(lhs, actual_shift)
305 fx.bcx.ins().sshr(lhs, actual_shift)
307 let ty = fx.bcx.func.dfg.value_type(val);
308 let max_shift = i64::from(ty.bits()) - 1;
310 fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
314 "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
321 let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
323 // FIXME directly write to result place instead
324 let out_place = CPlace::new_stack_slot(
326 fx.layout_of(fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter())),
328 let out_layout = out_place.layout();
329 out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));
331 out_place.to_cvalue(fx)
334 pub(crate) fn trans_float_binop<'tcx>(
335 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
337 in_lhs: CValue<'tcx>,
338 in_rhs: CValue<'tcx>,
340 assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty);
342 let lhs = in_lhs.load_scalar(fx);
343 let rhs = in_rhs.load_scalar(fx);
345 let b = fx.bcx.ins();
346 let res = match bin_op {
347 BinOp::Add => b.fadd(lhs, rhs),
348 BinOp::Sub => b.fsub(lhs, rhs),
349 BinOp::Mul => b.fmul(lhs, rhs),
350 BinOp::Div => b.fdiv(lhs, rhs),
352 let name = match in_lhs.layout().ty.kind {
353 ty::Float(FloatTy::F32) => "fmodf",
354 ty::Float(FloatTy::F64) => "fmod",
357 return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty);
359 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
360 let fltcc = match bin_op {
361 BinOp::Eq => FloatCC::Equal,
362 BinOp::Lt => FloatCC::LessThan,
363 BinOp::Le => FloatCC::LessThanOrEqual,
364 BinOp::Ne => FloatCC::NotEqual,
365 BinOp::Ge => FloatCC::GreaterThanOrEqual,
366 BinOp::Gt => FloatCC::GreaterThan,
369 let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
370 let val = fx.bcx.ins().bint(types::I8, val);
371 return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
373 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
376 CValue::by_val(res, in_lhs.layout())
379 pub(crate) fn trans_ptr_binop<'tcx>(
380 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
382 in_lhs: CValue<'tcx>,
383 in_rhs: CValue<'tcx>,
385 let is_thin_ptr = in_lhs.layout().ty.builtin_deref(true).map(|TypeAndMut { ty, mutbl: _}| {
386 !has_ptr_meta(fx.tcx, ty)
391 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
392 let lhs = in_lhs.load_scalar(fx);
393 let rhs = in_rhs.load_scalar(fx);
395 return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs);
398 let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty;
399 let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
400 let pointee_size = fx.layout_of(pointee_ty).size.bytes();
401 let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
402 let base_val = base.load_scalar(fx);
403 let res = fx.bcx.ins().iadd(base_val, ptr_diff);
404 return CValue::by_val(res, base.layout());
406 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
409 let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx);
410 let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx);
412 let res = match bin_op {
414 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
415 let extra_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_extra, rhs_extra);
416 fx.bcx.ins().band(ptr_eq, extra_eq)
419 let ptr_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_ptr, rhs_ptr);
420 let extra_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_extra, rhs_extra);
421 fx.bcx.ins().bor(ptr_ne, extra_ne)
423 BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
424 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
429 .icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
430 let extra_cmp = fx.bcx.ins().icmp(
431 bin_op_to_intcc(bin_op, false).unwrap(),
436 fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
438 _ => panic!("bin_op {:?} on ptr", bin_op),
442 fx.bcx.ins().bint(types::I8, res),
443 fx.layout_of(fx.tcx.types.bool),