diff --git a/src/base.rs b/src/base.rs index 26dfb1548daa..4af36117de02 100644 --- a/src/base.rs +++ b/src/base.rs @@ -264,18 +264,7 @@ fn trans_stmt<'a, 'tcx: 'a>( let lhs = trans_operand(fx, lhs); let rhs = trans_operand(fx, rhs); - let res = match lhs.layout().ty.sty { - ty::Bool => crate::num::trans_bool_binop(fx, *bin_op, lhs, rhs), - ty::Uint(_) | ty::Int(_ )=> { - crate::num::trans_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) - } - ty::Float(_) => crate::num::trans_float_binop(fx, *bin_op, lhs, rhs, lval.layout().ty), - ty::Char => crate::num::trans_char_binop(fx, *bin_op, lhs, rhs, lval.layout().ty), - ty::RawPtr(..) | ty::FnPtr(..) => { - crate::num::trans_ptr_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) - } - _ => unimplemented!("{:?}({:?}, {:?})", bin_op, lhs.layout().ty, rhs.layout().ty), - }; + let res = crate::num::codegen_binop(fx, *bin_op, lhs, rhs); lval.write_cvalue(fx, res); } Rvalue::CheckedBinaryOp(bin_op, lhs, rhs) => { @@ -283,11 +272,11 @@ fn trans_stmt<'a, 'tcx: 'a>( let rhs = trans_operand(fx, rhs); let res = if !fx.tcx.sess.overflow_checks() { - let val = crate::num::trans_int_binop(fx, *bin_op, lhs, rhs, lhs.layout().ty).load_scalar(fx); + let val = crate::num::trans_int_binop(fx, *bin_op, lhs, rhs).load_scalar(fx); let is_overflow = fx.bcx.ins().iconst(types::I8, 0); CValue::by_val_pair(val, is_overflow, lval.layout()) } else { - crate::num::trans_checked_int_binop(fx, *bin_op, lhs, rhs, lval.layout().ty) + crate::num::trans_checked_int_binop(fx, *bin_op, lhs, rhs) }; lval.write_cvalue(fx, res); @@ -314,6 +303,7 @@ fn trans_stmt<'a, 'tcx: 'a>( ty::Int(_) => { let clif_ty = fx.clif_type(layout.ty).unwrap(); if clif_ty == types::I128 { + // FIXME implement it crate::trap::trap_unreachable_ret_value(fx, layout, "i128 neg is not yet supported").load_scalar(fx) } else { let zero = fx.bcx.ins().iconst(clif_ty, 0); diff --git a/src/codegen_i128.rs b/src/codegen_i128.rs index 6fdd3042c526..87d69c2d9a71 100644 --- a/src/codegen_i128.rs +++ b/src/codegen_i128.rs @@ -8,7 +8,6 @@ pub fn maybe_codegen<'a, 'tcx>( checked: bool, lhs: CValue<'tcx>, rhs: CValue<'tcx>, - out_ty: Ty<'tcx>, ) -> Option> { if lhs.layout().ty != fx.tcx.types.u128 && lhs.layout().ty != fx.tcx.types.i128 { return None; @@ -26,6 +25,7 @@ pub fn maybe_codegen<'a, 'tcx>( } BinOp::Add | BinOp::Sub if !checked => return None, BinOp::Add => { + let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); return Some(if is_signed { fx.easy_call("__rust_i128_addo", &[lhs, rhs], out_ty) } else { @@ -33,6 +33,7 @@ pub fn maybe_codegen<'a, 'tcx>( }) } BinOp::Sub => { + let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); return Some(if is_signed { fx.easy_call("__rust_i128_subo", &[lhs, rhs], out_ty) } else { @@ -42,6 +43,7 @@ pub fn maybe_codegen<'a, 'tcx>( BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), BinOp::Mul => { let res = if checked { + let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); if is_signed { fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty) } else { @@ -91,18 +93,7 @@ pub fn maybe_codegen<'a, 'tcx>( // } else { // msb_cc // } - let cc = match (bin_op, is_signed) { - (BinOp::Ge, false) => IntCC::UnsignedGreaterThanOrEqual, - (BinOp::Gt, false) => IntCC::UnsignedGreaterThan, - (BinOp::Lt, false) => IntCC::UnsignedLessThan, - (BinOp::Le, false) => IntCC::UnsignedLessThanOrEqual, - - (BinOp::Ge, true) => IntCC::SignedGreaterThanOrEqual, - (BinOp::Gt, true) => IntCC::SignedGreaterThan, - (BinOp::Lt, true) => IntCC::SignedLessThan, - (BinOp::Le, true) => IntCC::SignedLessThanOrEqual, - _ => unreachable!(), - }; + let cc = crate::num::bin_op_to_intcc(bin_op, is_signed).unwrap(); let msb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_msb, rhs_msb); let lsb_cc = fx.bcx.ins().icmp(cc, lhs_lsb, rhs_lsb); @@ -160,6 +151,7 @@ pub fn maybe_codegen<'a, 'tcx>( }; if let Some(val) = val { if let Some(is_overflow) = is_overflow { + let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); let val = val.load_scalar(fx); return Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty))) } else { @@ -186,6 +178,7 @@ pub fn maybe_codegen<'a, 'tcx>( (_, _) => unreachable!(), }; if let Some(is_overflow) = is_overflow { + let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); let val = val.load_scalar(fx); Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty))) } else { diff --git a/src/intrinsics.rs b/src/intrinsics.rs index 45f8d82448e6..317da6f4aaf0 100644 --- a/src/intrinsics.rs +++ b/src/intrinsics.rs @@ -446,7 +446,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>( "unchecked_shr" => BinOp::Shr, _ => unimplemented!("intrinsic {}", intrinsic), }; - let res = crate::num::trans_int_binop(fx, bin_op, x, y, ret.layout().ty); + let res = crate::num::trans_int_binop(fx, bin_op, x, y); ret.write_cvalue(fx, res); }; _ if intrinsic.ends_with("_with_overflow"), (c x, c y) { @@ -463,7 +463,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>( bin_op, x, y, - ret.layout().ty, ); ret.write_cvalue(fx, res); }; @@ -480,7 +479,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>( bin_op, x, y, - ret.layout().ty, ); ret.write_cvalue(fx, res); }; @@ -499,7 +497,6 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>( bin_op, x, y, - fx.tcx.mk_tup([T, fx.tcx.types.bool].into_iter()), ); let (val, has_overflow) = checked_res.load_scalar_pair(fx); diff --git a/src/num.rs b/src/num.rs index 9210c040ff37..1a8aed8f902b 100644 --- a/src/num.rs +++ b/src/num.rs @@ -1,147 +1,141 @@ use crate::prelude::*; -macro_rules! binop_match { - (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, bug) => { - bug!("binop {} on {} lhs: {:?} rhs: {:?}", stringify!($var), $bug_fmt, $lhs, $rhs) - }; - (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, icmp($cc:ident)) => {{ - assert_eq!($fx.tcx.types.bool, $ret_ty); - let ret_layout = $fx.layout_of($ret_ty); +pub fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option { + use BinOp::*; + use IntCC::*; + Some(match bin_op { + Eq => Equal, + Lt => if signed { SignedLessThan } else { UnsignedLessThan}, + Le => if signed { SignedLessThanOrEqual } else { UnsignedLessThanOrEqual}, + Ne => NotEqual, + Ge => if signed { SignedGreaterThanOrEqual } else { UnsignedGreaterThanOrEqual }, + Gt => if signed { SignedGreaterThan } else { UnsignedGreaterThan }, + _ => return None, + }) +} - let b = $fx.bcx.ins().icmp(IntCC::$cc, $lhs, $rhs); - CValue::by_val($fx.bcx.ins().bint(types::I8, b), ret_layout) - }}; - (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, fcmp($cc:ident)) => {{ - assert_eq!($fx.tcx.types.bool, $ret_ty); - let ret_layout = $fx.layout_of($ret_ty); - let b = $fx.bcx.ins().fcmp(FloatCC::$cc, $lhs, $rhs); - CValue::by_val($fx.bcx.ins().bint(types::I8, b), ret_layout) - }}; - (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, custom(|| $body:expr)) => {{ - $body - }}; - (@single $fx:expr, $bug_fmt:expr, $var:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $name:ident) => {{ - let ret_layout = $fx.layout_of($ret_ty); - CValue::by_val($fx.bcx.ins().$name($lhs, $rhs), ret_layout) - }}; - ( - $fx:expr, $bin_op:expr, $signed:expr, $lhs:expr, $rhs:expr, $ret_ty:expr, $bug_fmt:expr; - $( - $var:ident ($sign:pat) $name:tt $( ( $($next:tt)* ) )? ; - )* - ) => {{ - let lhs = $lhs.load_scalar($fx); - let rhs = $rhs.load_scalar($fx); - match ($bin_op, $signed) { - $( - (BinOp::$var, $sign) => binop_match!(@single $fx, $bug_fmt, $var, $signed, lhs, rhs, $ret_ty, $name $( ( $($next)* ) )?), - )* +fn codegen_compare_bin_op<'tcx>( + fx: &mut FunctionCx<'_, 'tcx, impl Backend>, + bin_op: BinOp, + signed: bool, + lhs: Value, + rhs: Value, +) -> CValue<'tcx> { + let val = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, signed).unwrap(), 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>( + fx: &mut FunctionCx<'_, 'tcx, impl Backend>, + bin_op: BinOp, + in_lhs: CValue<'tcx>, + in_rhs: CValue<'tcx>, +) -> CValue<'tcx> { + match bin_op { + BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { + match in_lhs.layout().ty.sty { + ref sty if *sty == fx.tcx.types.u128.sty || *sty == fx.tcx.types.i128.sty => {} + ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => { + let signed = type_sign(in_lhs.layout().ty); + let lhs = in_lhs.load_scalar(fx); + let rhs = in_rhs.load_scalar(fx); + + let (lhs, rhs) = if + (bin_op == BinOp::Eq || bin_op == BinOp::Ne) + && (in_lhs.layout().ty.sty == fx.tcx.types.i8.sty || in_lhs.layout().ty.sty == fx.tcx.types.i16.sty) + { + // FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong. + ( + fx.bcx.ins().sextend(types::I32, lhs), + fx.bcx.ins().sextend(types::I32, rhs), + ) + } else { + (lhs, rhs) + }; + + return codegen_compare_bin_op(fx, bin_op, signed, lhs, rhs); + } + _ => {} + } } - }} + _ => {} + } + + match in_lhs.layout().ty.sty { + ty::Bool => crate::num::trans_bool_binop(fx, bin_op, in_lhs, in_rhs), + ty::Uint(_) | ty::Int(_)=> { + crate::num::trans_int_binop(fx, bin_op, in_lhs, in_rhs) + } + ty::Float(_) => crate::num::trans_float_binop(fx, bin_op, in_lhs, in_rhs), + ty::RawPtr(..) | ty::FnPtr(..) => { + crate::num::trans_ptr_binop(fx, bin_op, in_lhs, in_rhs) + } + _ => unimplemented!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty), + } } pub fn trans_bool_binop<'a, 'tcx: 'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, + in_lhs: CValue<'tcx>, + in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let res = binop_match! { - fx, bin_op, false, lhs, rhs, fx.tcx.types.bool, "bool"; - Add (_) bug; - Sub (_) bug; - Mul (_) bug; - Div (_) bug; - Rem (_) bug; - BitXor (_) bxor; - BitAnd (_) band; - BitOr (_) bor; - Shl (_) bug; - Shr (_) bug; + let lhs = in_lhs.load_scalar(fx); + let rhs = in_rhs.load_scalar(fx); - Eq (_) icmp(Equal); - Lt (_) icmp(UnsignedLessThan); - Le (_) icmp(UnsignedLessThanOrEqual); - Ne (_) icmp(NotEqual); - Ge (_) icmp(UnsignedGreaterThanOrEqual); - Gt (_) icmp(UnsignedGreaterThan); - - Offset (_) bug; + let b = fx.bcx.ins(); + let res = match bin_op { + BinOp::BitXor => b.bxor(lhs, rhs), + BinOp::BitAnd => b.band(lhs, rhs), + BinOp::BitOr => b.bor(lhs, rhs), + // Compare binops handles by `codegen_binop`. + _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), }; - res + CValue::by_val(res, fx.layout_of(fx.tcx.types.bool)) } pub fn trans_int_binop<'a, 'tcx: 'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, - out_ty: Ty<'tcx>, + in_lhs: CValue<'tcx>, + in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { if bin_op != BinOp::Shl && bin_op != BinOp::Shr { assert_eq!( - lhs.layout().ty, - rhs.layout().ty, + in_lhs.layout().ty, + in_rhs.layout().ty, "int binop requires lhs and rhs of same type" ); } - match out_ty.sty { - ty::Bool | ty::Uint(_) | ty::Int(_) => {} - _ => unreachable!("Out ty {:?} is not an integer or bool", out_ty), - } - - if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, lhs, rhs, out_ty) { + if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) { return res; } - let signed = type_sign(lhs.layout().ty); + let signed = type_sign(in_lhs.layout().ty); - let (lhs, rhs) = if - (bin_op == BinOp::Eq || bin_op == BinOp::Ne) - && (lhs.layout().ty.sty == fx.tcx.types.i8.sty || lhs.layout().ty.sty == fx.tcx.types.i16.sty) - { - // FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong. - let lhs = lhs.load_scalar(fx); - let rhs = rhs.load_scalar(fx); - ( - CValue::by_val(fx.bcx.ins().sextend(types::I32, lhs), fx.layout_of(fx.tcx.types.i32)), - CValue::by_val(fx.bcx.ins().sextend(types::I32, rhs), fx.layout_of(fx.tcx.types.i32)), - ) - } else { - (lhs, rhs) + let lhs = in_lhs.load_scalar(fx); + let rhs = in_rhs.load_scalar(fx); + + let b = fx.bcx.ins(); + let val = match bin_op { + BinOp::Add => b.iadd(lhs, rhs), + BinOp::Sub => b.isub(lhs, rhs), + BinOp::Mul => b.imul(lhs, rhs), + BinOp::Div => if signed { b.sdiv(lhs, rhs) } else { b.udiv(lhs, rhs) }, + BinOp::Rem => if signed { b.srem(lhs, rhs) } else { b.urem(lhs, rhs) }, + BinOp::BitXor => b.bxor(lhs, rhs), + BinOp::BitAnd => b.band(lhs, rhs), + BinOp::BitOr => b.bor(lhs, rhs), + BinOp::Shl => b.ishl(lhs, rhs), + BinOp::Shr => if signed { b.sshr(lhs, rhs) } else { b.ushr(lhs, rhs) }, + // Compare binops handles by `codegen_binop`. + _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty), }; - binop_match! { - fx, bin_op, signed, lhs, rhs, out_ty, "int/uint"; - Add (_) iadd; - Sub (_) isub; - Mul (_) imul; - Div (false) udiv; - Div (true) sdiv; - Rem (false) urem; - Rem (true) srem; - BitXor (_) bxor; - BitAnd (_) band; - BitOr (_) bor; - Shl (_) ishl; - Shr (false) ushr; - Shr (true) sshr; - - Eq (_) icmp(Equal); - Lt (false) icmp(UnsignedLessThan); - Lt (true) icmp(SignedLessThan); - Le (false) icmp(UnsignedLessThanOrEqual); - Le (true) icmp(SignedLessThanOrEqual); - Ne (_) icmp(NotEqual); - Ge (false) icmp(UnsignedGreaterThanOrEqual); - Ge (true) icmp(SignedGreaterThanOrEqual); - Gt (false) icmp(UnsignedGreaterThan); - Gt (true) icmp(SignedGreaterThan); - - Offset (_) bug; - } + CValue::by_val(val, in_lhs.layout()) } pub fn trans_checked_int_binop<'a, 'tcx: 'a>( @@ -149,7 +143,6 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>( bin_op: BinOp, in_lhs: CValue<'tcx>, in_rhs: CValue<'tcx>, - out_ty: Ty<'tcx>, ) -> CValue<'tcx> { if bin_op != BinOp::Shl && bin_op != BinOp::Shr { assert_eq!( @@ -162,7 +155,7 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>( let lhs = in_lhs.load_scalar(fx); let rhs = in_rhs.load_scalar(fx); - if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs, out_ty) { + if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) { return res; } @@ -234,7 +227,7 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>( }; let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow); - let out_place = CPlace::new_stack_slot(fx, out_ty); + let out_place = CPlace::new_stack_slot(fx, fx.tcx.mk_tup([in_lhs.layout().ty, fx.tcx.types.bool].iter())); let out_layout = out_place.layout(); out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout)); @@ -244,85 +237,55 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>( pub fn trans_float_binop<'a, 'tcx: 'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, - ty: Ty<'tcx>, + in_lhs: CValue<'tcx>, + in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let res = binop_match! { - fx, bin_op, false, lhs, rhs, ty, "float"; - Add (_) fadd; - Sub (_) fsub; - Mul (_) fmul; - Div (_) fdiv; - Rem (_) custom(|| { - assert_eq!(lhs.layout().ty, ty); - assert_eq!(rhs.layout().ty, ty); - match ty.sty { - ty::Float(FloatTy::F32) => fx.easy_call("fmodf", &[lhs, rhs], ty), - ty::Float(FloatTy::F64) => fx.easy_call("fmod", &[lhs, rhs], ty), + assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty); + + let lhs = in_lhs.load_scalar(fx); + let rhs = in_rhs.load_scalar(fx); + + let b = fx.bcx.ins(); + let res = match bin_op { + BinOp::Add => b.fadd(lhs, rhs), + BinOp::Sub => b.fsub(lhs, rhs), + BinOp::Mul => b.fmul(lhs, rhs), + BinOp::Div => b.fdiv(lhs, rhs), + BinOp::Rem => { + let name = match in_lhs.layout().ty.sty { + ty::Float(FloatTy::F32) => "fmodf", + ty::Float(FloatTy::F64) => "fmod", _ => bug!(), - } - }); - BitXor (_) bxor; - BitAnd (_) band; - BitOr (_) bor; - Shl (_) bug; - Shr (_) bug; - - Eq (_) fcmp(Equal); - Lt (_) fcmp(LessThan); - Le (_) fcmp(LessThanOrEqual); - Ne (_) fcmp(NotEqual); - Ge (_) fcmp(GreaterThanOrEqual); - Gt (_) fcmp(GreaterThan); - - Offset (_) bug; + }; + return fx.easy_call(name, &[in_lhs, in_rhs], in_lhs.layout().ty); + } + BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { + let fltcc = match bin_op { + BinOp::Eq => FloatCC::Equal, + BinOp::Lt => FloatCC::LessThan, + BinOp::Le => FloatCC::LessThanOrEqual, + BinOp::Ne => FloatCC::NotEqual, + BinOp::Ge => FloatCC::GreaterThanOrEqual, + BinOp::Gt => FloatCC::GreaterThan, + _ => unreachable!(), + }; + let val = fx.bcx.ins().fcmp(fltcc, lhs, rhs); + let val = fx.bcx.ins().bint(types::I8, val); + return CValue::by_val(val, fx.layout_of(fx.tcx.types.bool)); + } + _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), }; - res -} - -pub fn trans_char_binop<'a, 'tcx: 'a>( - fx: &mut FunctionCx<'a, 'tcx, impl Backend>, - bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, - ty: Ty<'tcx>, -) -> CValue<'tcx> { - let res = binop_match! { - fx, bin_op, false, lhs, rhs, ty, "char"; - Add (_) bug; - Sub (_) bug; - Mul (_) bug; - Div (_) bug; - Rem (_) bug; - BitXor (_) bug; - BitAnd (_) bug; - BitOr (_) bug; - Shl (_) bug; - Shr (_) bug; - - Eq (_) icmp(Equal); - Lt (_) icmp(UnsignedLessThan); - Le (_) icmp(UnsignedLessThanOrEqual); - Ne (_) icmp(NotEqual); - Ge (_) icmp(UnsignedGreaterThanOrEqual); - Gt (_) icmp(UnsignedGreaterThan); - - Offset (_) bug; - }; - - res + CValue::by_val(res, in_lhs.layout()) } pub fn trans_ptr_binop<'a, 'tcx: 'a>( fx: &mut FunctionCx<'a, 'tcx, impl Backend>, bin_op: BinOp, - lhs: CValue<'tcx>, - rhs: CValue<'tcx>, - ret_ty: Ty<'tcx>, + in_lhs: CValue<'tcx>, + in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let not_fat = match lhs.layout().ty.sty { + let not_fat = match in_lhs.layout().ty.sty { ty::RawPtr(TypeAndMut { ty, mutbl: _ }) => { ty.is_sized(fx.tcx.at(DUMMY_SP), ParamEnv::reveal_all()) } @@ -330,41 +293,27 @@ pub fn trans_ptr_binop<'a, 'tcx: 'a>( _ => bug!("trans_ptr_binop on non ptr"), }; if not_fat { - if let BinOp::Offset = bin_op { - let (base, offset) = (lhs, rhs.load_scalar(fx)); - let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; - let pointee_size = fx.layout_of(pointee_ty).size.bytes(); - let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); - let base_val = base.load_scalar(fx); - let res = fx.bcx.ins().iadd(base_val, ptr_diff); - return CValue::by_val(res, base.layout()); - } + match bin_op { + BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { + let lhs = in_lhs.load_scalar(fx); + let rhs = in_rhs.load_scalar(fx); - binop_match! { - fx, bin_op, false, lhs, rhs, ret_ty, "ptr"; - Add (_) bug; - Sub (_) bug; - Mul (_) bug; - Div (_) bug; - Rem (_) bug; - BitXor (_) bug; - BitAnd (_) bug; - BitOr (_) bug; - Shl (_) bug; - Shr (_) bug; - - Eq (_) icmp(Equal); - Lt (_) icmp(UnsignedLessThan); - Le (_) icmp(UnsignedLessThanOrEqual); - Ne (_) icmp(NotEqual); - Ge (_) icmp(UnsignedGreaterThanOrEqual); - Gt (_) icmp(UnsignedGreaterThan); - - Offset (_) bug; // Handled above - } + return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs); + } + BinOp::Offset => { + let (base, offset) = (in_lhs, in_rhs.load_scalar(fx)); + let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_size = fx.layout_of(pointee_ty).size.bytes(); + let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); + let base_val = base.load_scalar(fx); + let res = fx.bcx.ins().iadd(base_val, ptr_diff); + return CValue::by_val(res, base.layout()); + } + _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), + }; } else { - let (lhs_ptr, lhs_extra) = lhs.load_scalar_pair(fx); - let (rhs_ptr, rhs_extra) = rhs.load_scalar_pair(fx); + let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx); + let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx); let res = match bin_op { BinOp::Eq => { @@ -380,29 +329,14 @@ pub fn trans_ptr_binop<'a, 'tcx: 'a>( BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => { let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr); - let ptr_cmp = fx.bcx.ins().icmp(match bin_op { - BinOp::Lt => IntCC::UnsignedLessThan, - BinOp::Le => IntCC::UnsignedLessThanOrEqual, - BinOp::Ge => IntCC::UnsignedGreaterThanOrEqual, - BinOp::Gt => IntCC::UnsignedGreaterThan, - _ => unreachable!(), - }, lhs_ptr, rhs_ptr); - - let extra_cmp = fx.bcx.ins().icmp(match bin_op { - BinOp::Lt => IntCC::UnsignedLessThan, - BinOp::Le => IntCC::UnsignedLessThanOrEqual, - BinOp::Ge => IntCC::UnsignedGreaterThanOrEqual, - BinOp::Gt => IntCC::UnsignedGreaterThan, - _ => unreachable!(), - }, lhs_extra, rhs_extra); + let ptr_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr); + let extra_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_extra, rhs_extra); fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp) } _ => panic!("bin_op {:?} on ptr", bin_op), }; - assert_eq!(fx.tcx.types.bool, ret_ty); - let ret_layout = fx.layout_of(ret_ty); - CValue::by_val(fx.bcx.ins().bint(types::I8, res), ret_layout) + CValue::by_val(fx.bcx.ins().bint(types::I8, res), fx.layout_of(fx.tcx.types.bool)) } }