about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2019-08-14 15:03:52 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2019-08-14 15:03:52 +0200
commitb4e55cdeddcf53953214aadb6eaa431a24aa2601 (patch)
treeeb1bcae64b348356b01eed16bb62da16fb3fcc04
parentdb071db95aa1ab24d961c961e18daee66fdc4af4 (diff)
downloadrust-b4e55cdeddcf53953214aadb6eaa431a24aa2601.tar.gz
rust-b4e55cdeddcf53953214aadb6eaa431a24aa2601.zip
Refactor num.rs
-rw-r--r--src/base.rs18
-rw-r--r--src/codegen_i128.rs19
-rw-r--r--src/intrinsics.rs5
-rw-r--r--src/num.rs410
4 files changed, 183 insertions, 269 deletions
diff --git a/src/base.rs b/src/base.rs
index 26dfb1548da..4af36117de0 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 6fdd3042c52..87d69c2d9a7 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<CValue<'tcx>> {
     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 45f8d82448e..317da6f4aaf 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 9210c040ff3..1a8aed8f902 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);
-
-        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)* ) )?),
-            )*
+pub fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
+    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,
+    })
+}
+
+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;
-
-        Eq (_) icmp(Equal);
-        Lt (_) icmp(UnsignedLessThan);
-        Le (_) icmp(UnsignedLessThanOrEqual);
-        Ne (_) icmp(NotEqual);
-        Ge (_) icmp(UnsignedGreaterThanOrEqual);
-        Gt (_) icmp(UnsignedGreaterThan);
-
-        Offset (_) bug;
+    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::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 (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 signed = type_sign(in_lhs.layout().ty);
+
+    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),
-                _ => 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;
-    };
+    assert_eq!(in_lhs.layout().ty, in_rhs.layout().ty);
 
-    res
-}
+    let lhs = in_lhs.load_scalar(fx);
+    let rhs = in_rhs.load_scalar(fx);
 
-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;
+    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!(),
+            };
+            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
+    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))
     }
 }