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(
257 IntCC::UnsignedGreaterThan,
259 (1 << ty.bits()) - 1,
261 let val = fx.bcx.ins().ireduce(ty, val);
264 types::I8 | types::I16 | types::I32 if signed => {
265 let lhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), lhs);
266 let rhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), rhs);
267 let val = fx.bcx.ins().imul(lhs, rhs);
271 .icmp_imm(IntCC::SignedLessThan, val, -(1 << (ty.bits() - 1)));
272 let has_overflow = fx.bcx.ins().icmp_imm(
273 IntCC::SignedGreaterThan,
275 (1 << (ty.bits() - 1)) - 1,
277 let val = fx.bcx.ins().ireduce(ty, val);
278 (val, fx.bcx.ins().bor(has_underflow, has_overflow))
281 //let val = fx.easy_call("__mulodi4", &[lhs, rhs, overflow_ptr], types::I64);
282 let val = fx.bcx.ins().imul(lhs, rhs);
283 let has_overflow = if !signed {
284 let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
285 fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
287 let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
288 let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
289 let not_all_ones = fx.bcx.ins().icmp_imm(
292 u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64,
294 fx.bcx.ins().band(not_all_zero, not_all_ones)
299 unreachable!("i128 should have been handled by codegen_i128::maybe_codegen")
301 _ => unreachable!("invalid non-integer type {}", ty),
305 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
306 let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
307 let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
308 let val = fx.bcx.ins().ishl(lhs, actual_shift);
309 let ty = fx.bcx.func.dfg.value_type(val);
310 let max_shift = i64::from(ty.bits()) - 1;
311 let has_overflow = fx
314 .icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
318 let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
319 let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
320 let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
321 let val = if !signed {
322 fx.bcx.ins().ushr(lhs, actual_shift)
324 fx.bcx.ins().sshr(lhs, actual_shift)
326 let ty = fx.bcx.func.dfg.value_type(val);
327 let max_shift = i64::from(ty.bits()) - 1;
328 let has_overflow = fx
331 .icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
335 "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
342 let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
344 // FIXME directly write to result place instead
345 let out_place = CPlace::new_stack_slot(
349 .mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter()),
352 let out_layout = out_place.layout();
353 out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));
355 out_place.to_cvalue(fx)
358 pub(crate) fn trans_float_binop<'tcx>(
359 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
361 in_lhs: CValue<'tcx>,
362 in_rhs: CValue<'tcx>,
364 assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty);
366 let lhs = in_lhs.load_scalar(fx);
367 let rhs = in_rhs.load_scalar(fx);
369 let b = fx.bcx.ins();
370 let res = match bin_op {
371 BinOp::Add => b.fadd(lhs, rhs),
372 BinOp::Sub => b.fsub(lhs, rhs),
373 BinOp::Mul => b.fmul(lhs, rhs),
374 BinOp::Div => b.fdiv(lhs, rhs),
376 let name = match in_lhs.layout().ty.kind {
377 ty::Float(FloatTy::F32) => "fmodf",
378 ty::Float(FloatTy::F64) => "fmod",
381 return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty);
383 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
384 let fltcc = match bin_op {
385 BinOp::Eq => FloatCC::Equal,
386 BinOp::Lt => FloatCC::LessThan,
387 BinOp::Le => FloatCC::LessThanOrEqual,
388 BinOp::Ne => FloatCC::NotEqual,
389 BinOp::Ge => FloatCC::GreaterThanOrEqual,
390 BinOp::Gt => FloatCC::GreaterThan,
393 let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs);
394 let val = fx.bcx.ins().bint(types::I8, val);
395 return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool));
397 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
400 CValue::by_val(res, in_lhs.layout())
403 pub(crate) fn trans_ptr_binop<'tcx>(
404 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
406 in_lhs: CValue<'tcx>,
407 in_rhs: CValue<'tcx>,
409 let is_thin_ptr = in_lhs
413 .map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty))
418 BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
419 let lhs = in_lhs.load_scalar(fx);
420 let rhs = in_rhs.load_scalar(fx);
422 return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs);
425 let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty;
426 let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
427 let pointee_size = fx.layout_of(pointee_ty).size.bytes();
428 let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
429 let base_val = base.load_scalar(fx);
430 let res = fx.bcx.ins().iadd(base_val, ptr_diff);
431 return CValue::by_val(res, base.layout());
433 _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs),
436 let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx);
437 let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx);
439 let res = match bin_op {
441 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
442 let extra_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_extra, rhs_extra);
443 fx.bcx.ins().band(ptr_eq, extra_eq)
446 let ptr_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_ptr, rhs_ptr);
447 let extra_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_extra, rhs_extra);
448 fx.bcx.ins().bor(ptr_ne, extra_ne)
450 BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
451 let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
456 .icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
457 let extra_cmp = fx.bcx.ins().icmp(
458 bin_op_to_intcc(bin_op, false).unwrap(),
463 fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
465 _ => panic!("bin_op {:?} on ptr", bin_op),
469 fx.bcx.ins().bint(types::I8, res),
470 fx.layout_of(fx.tcx.types.bool),