use crate::prelude::*;
-pub fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
+pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
use BinOp::*;
use IntCC::*;
Some(match bin_op {
rhs: Value,
) -> CValue<'tcx> {
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
- let val = codegen_icmp(fx, intcc, lhs, rhs);
+ let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
let val = fx.bcx.ins().bint(types::I8, val);
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
}
-pub fn codegen_binop<'tcx>(
+pub(crate) fn codegen_binop<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
bin_op: BinOp,
in_lhs: CValue<'tcx>,
}
}
-pub fn trans_bool_binop<'tcx>(
+pub(crate) fn trans_bool_binop<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
bin_op: BinOp,
in_lhs: CValue<'tcx>,
CValue::by_val(res, fx.layout_of(fx.tcx.types.bool))
}
-pub fn trans_int_binop<'tcx>(
+pub(crate) fn trans_int_binop<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
bin_op: BinOp,
in_lhs: CValue<'tcx>,
BinOp::BitOr => b.bor(lhs, rhs),
BinOp::Shl => {
let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let rhs = clif_intcast(fx, rhs, lhs_ty, false);
- fx.bcx.ins().ishl(lhs, rhs)
+ let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
+ let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
+ fx.bcx.ins().ishl(lhs, actual_shift)
}
BinOp::Shr => {
let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let rhs = clif_intcast(fx, rhs, lhs_ty, false);
+ let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
+ let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
if signed {
- fx.bcx.ins().sshr(lhs, rhs)
+ fx.bcx.ins().sshr(lhs, actual_shift)
} else {
- fx.bcx.ins().ushr(lhs, rhs)
+ fx.bcx.ins().ushr(lhs, actual_shift)
}
}
// Compare binops handles by `codegen_binop`.
CValue::by_val(val, in_lhs.layout())
}
-pub fn trans_checked_int_binop<'tcx>(
+pub(crate) fn trans_checked_int_binop<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
bin_op: BinOp,
in_lhs: CValue<'tcx>,
(val, has_overflow)
}
BinOp::Mul => {
- let val = fx.bcx.ins().imul(lhs, rhs);
- /*let val_hi = if !signed {
- fx.bcx.ins().umulhi(lhs, rhs)
- } else {
- fx.bcx.ins().smulhi(lhs, rhs)
- };
- let has_overflow = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);*/
- // TODO: check for overflow
- let has_overflow = fx.bcx.ins().bconst(types::B1, false);
- (val, has_overflow)
+ let ty = fx.bcx.func.dfg.value_type(lhs);
+ match ty {
+ types::I8 | types::I16 | types::I32 if !signed => {
+ let lhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), lhs);
+ let rhs = fx.bcx.ins().uextend(ty.double_width().unwrap(), rhs);
+ let val = fx.bcx.ins().imul(lhs, rhs);
+ let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, val, (1 << ty.bits()) - 1);
+ let val = fx.bcx.ins().ireduce(ty, val);
+ (val, has_overflow)
+ }
+ types::I8 | types::I16 | types::I32 if signed => {
+ let lhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), lhs);
+ let rhs = fx.bcx.ins().sextend(ty.double_width().unwrap(), rhs);
+ let val = fx.bcx.ins().imul(lhs, rhs);
+ let has_underflow = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, val, -(1 << (ty.bits() - 1)));
+ let has_overflow = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, val, (1 << (ty.bits() - 1)) - 1);
+ let val = fx.bcx.ins().ireduce(ty, val);
+ (val, fx.bcx.ins().bor(has_underflow, has_overflow))
+ }
+ types::I64 => {
+ //let val = fx.easy_call("__mulodi4", &[lhs, rhs, overflow_ptr], types::I64);
+ let val = fx.bcx.ins().imul(lhs, rhs);
+ let has_overflow = if !signed {
+ let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
+ fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0)
+ } else {
+ let val_hi = fx.bcx.ins().smulhi(lhs, rhs);
+ let not_all_zero = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);
+ let not_all_ones = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, u64::try_from((1u128 << ty.bits()) - 1).unwrap() as i64);
+ fx.bcx.ins().band(not_all_zero, not_all_ones)
+ };
+ (val, has_overflow)
+ }
+ types::I128 => unreachable!("i128 should have been handled by codegen_i128::maybe_codegen"),
+ _ => unreachable!("invalid non-integer type {}", ty),
+ }
}
BinOp::Shl => {
- let val = fx.bcx.ins().ishl(lhs, rhs);
+ let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
+ let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
+ let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
+ let val = fx.bcx.ins().ishl(lhs, actual_shift);
let ty = fx.bcx.func.dfg.value_type(val);
let max_shift = i64::from(ty.bits()) - 1;
let has_overflow =
(val, has_overflow)
}
BinOp::Shr => {
+ let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
+ let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
+ let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
let val = if !signed {
- fx.bcx.ins().ushr(lhs, rhs)
+ fx.bcx.ins().ushr(lhs, actual_shift)
} else {
- fx.bcx.ins().sshr(lhs, rhs)
+ fx.bcx.ins().sshr(lhs, actual_shift)
};
let ty = fx.bcx.func.dfg.value_type(val);
let max_shift = i64::from(ty.bits()) - 1;
out_place.to_cvalue(fx)
}
-pub fn trans_float_binop<'tcx>(
+pub(crate) fn trans_float_binop<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
bin_op: BinOp,
in_lhs: CValue<'tcx>,
CValue::by_val(res, in_lhs.layout())
}
-pub fn trans_ptr_binop<'tcx>(
+pub(crate) fn trans_ptr_binop<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
bin_op: BinOp,
in_lhs: CValue<'tcx>,