about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2019-07-07 18:08:38 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2019-07-26 11:29:35 +0200
commit641a210ff688d8101688b32650d09c270d381b02 (patch)
tree9977bfab9ba403a9224c0c923d9db1179477707f
parent3080c73f50a286a7a6199bf88d7bad7570c2e646 (diff)
downloadrust-641a210ff688d8101688b32650d09c270d381b02.tar.gz
rust-641a210ff688d8101688b32650d09c270d381b02.zip
Implement most 128bit binops
-rw-r--r--example/std_example.rs20
-rw-r--r--src/abi.rs2
-rw-r--r--src/base.rs151
-rw-r--r--src/codegen_i128.rs107
-rw-r--r--src/lib.rs1
5 files changed, 178 insertions, 103 deletions
diff --git a/example/std_example.rs b/example/std_example.rs
index ae77616a83d..c0ec0bb5b73 100644
--- a/example/std_example.rs
+++ b/example/std_example.rs
@@ -3,23 +3,5 @@
 use std::io::Write;
 
 fn main() {
-    assert_eq!((1u128 + 2) as u16, 3);
-}
-
-#[derive(PartialEq)]
-enum LoopState {
-    Continue(()),
-    Break(())
-}
-
-pub enum Instruction {
-    Increment,
-    Loop,
-}
-
-fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
-    match a {
-        None => None,
-        Some((_, instr)) => Some(instr),
-    }
+    assert_eq!(1u128 + 2, 3);
 }
diff --git a/src/abi.rs b/src/abi.rs
index b7e7d0a830a..c5dbe6dffa9 100644
--- a/src/abi.rs
+++ b/src/abi.rs
@@ -846,7 +846,7 @@ pub fn codegen_drop<'a, 'tcx: 'a>(
                 );
                 drop_place.write_place_ref(fx, arg_place);
                 let arg_value = arg_place.to_cvalue(fx);
-                crate::abi::codegen_call_inner(
+                codegen_call_inner(
                     fx,
                     None,
                     drop_fn_ty,
diff --git a/src/base.rs b/src/base.rs
index 88964a34ed1..8821a629519 100644
--- a/src/base.rs
+++ b/src/base.rs
@@ -831,18 +831,8 @@ pub fn trans_int_binop<'a, 'tcx: 'a>(
         );
     }
 
-    if lhs.layout().ty == fx.tcx.types.u128 || lhs.layout().ty == fx.tcx.types.i128 {
-        if out_ty == fx.tcx.types.bool {
-            let layout = fx.layout_of(fx.tcx.types.bool);
-            let val = fx.bcx.ins().iconst(types::I8, 0);
-            return CValue::by_val(val, layout);
-        } else {
-            let layout = fx.layout_of(out_ty);
-            let a = fx.bcx.ins().iconst(types::I64, 42);
-            let b = fx.bcx.ins().iconst(types::I64, 0);
-            let val = fx.bcx.ins().iconcat(a, b);
-            return CValue::by_val(val, layout);
-        }
+    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, signed, lhs, rhs, out_ty) {
+        return res;
     }
 
     binop_match! {
@@ -894,79 +884,74 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
 
     let lhs = in_lhs.load_scalar(fx);
     let rhs = in_rhs.load_scalar(fx);
-    let (res, has_overflow) = if in_lhs.layout().ty == fx.tcx.types.u128 || in_lhs.layout().ty == fx.tcx.types.i128 {
-        match (bin_op, signed) {
-            _ => {
-                let a = fx.bcx.ins().iconst(types::I64, 42);
-                let b = fx.bcx.ins().iconst(types::I64, 0);
-                (fx.bcx.ins().iconcat(a, b), fx.bcx.ins().bconst(types::B1, false))
-            }
+
+    if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, signed, in_lhs, in_rhs, out_ty) {
+        return res;
+    }
+
+    let (res, has_overflow) = match bin_op {
+        BinOp::Add => {
+            /*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs);
+            (val, c_out)*/
+            // FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16
+            let val = fx.bcx.ins().iadd(lhs, rhs);
+            let has_overflow = if !signed {
+                fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs)
+            } else {
+                let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
+                let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs);
+                fx.bcx.ins().bxor(rhs_is_negative, slt)
+            };
+            (val, has_overflow)
         }
-    } else {
-        match bin_op {
-            BinOp::Add => {
-                /*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs);
-                (val, c_out)*/
-                // FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16
-                let val = fx.bcx.ins().iadd(lhs, rhs);
-                let has_overflow = if !signed {
-                    fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs)
-                } else {
-                    let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
-                    let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs);
-                    fx.bcx.ins().bxor(rhs_is_negative, slt)
-                };
-                (val, has_overflow)
-            }
-            BinOp::Sub => {
-                /*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs);
-                (val, b_out)*/
-                // FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16
-                let val = fx.bcx.ins().isub(lhs, rhs);
-                let has_overflow = if !signed {
-                    fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs)
-                } else {
-                    let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
-                    let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs);
-                    fx.bcx.ins().bxor(rhs_is_negative, sgt)
-                };
-                (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)
-            }
-            BinOp::Shl => {
-                let val = fx.bcx.ins().ishl(lhs, rhs);
-                // TODO: check for overflow
-                let has_overflow = fx.bcx.ins().bconst(types::B1, false);
-                (val, has_overflow)
-            }
-            BinOp::Shr => {
-                let val = if !signed {
-                    fx.bcx.ins().ushr(lhs, rhs)
-                } else {
-                    fx.bcx.ins().sshr(lhs, rhs)
-                };
-                // TODO: check for overflow
-                let has_overflow = fx.bcx.ins().bconst(types::B1, false);
-                (val, has_overflow)
-            }
-            _ => bug!(
-                "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
-                bin_op,
-                in_lhs,
-                in_rhs
-            ),
+        BinOp::Sub => {
+            /*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs);
+            (val, b_out)*/
+            // FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16
+            let val = fx.bcx.ins().isub(lhs, rhs);
+            let has_overflow = if !signed {
+                fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs)
+            } else {
+                let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
+                let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs);
+                fx.bcx.ins().bxor(rhs_is_negative, sgt)
+            };
+            (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)
+        }
+        BinOp::Shl => {
+            let val = fx.bcx.ins().ishl(lhs, rhs);
+            // TODO: check for overflow
+            let has_overflow = fx.bcx.ins().bconst(types::B1, false);
+            (val, has_overflow)
+        }
+        BinOp::Shr => {
+            let val = if !signed {
+                fx.bcx.ins().ushr(lhs, rhs)
+            } else {
+                fx.bcx.ins().sshr(lhs, rhs)
+            };
+            // TODO: check for overflow
+            let has_overflow = fx.bcx.ins().bconst(types::B1, false);
+            (val, has_overflow)
         }
+        _ => bug!(
+            "binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
+            bin_op,
+            in_lhs,
+            in_rhs
+        ),
     };
 
     let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
diff --git a/src/codegen_i128.rs b/src/codegen_i128.rs
new file mode 100644
index 00000000000..ded6b597f26
--- /dev/null
+++ b/src/codegen_i128.rs
@@ -0,0 +1,107 @@
+//! Replaces 128-bit operators with lang item calls
+
+use crate::prelude::*;
+
+pub fn maybe_codegen<'a, 'tcx>(
+    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+    bin_op: BinOp,
+    checked: bool,
+    is_signed: 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;
+    }
+
+    let lhs_val = lhs.load_scalar(fx);
+    let rhs_val = rhs.load_scalar(fx);
+
+    match bin_op {
+        BinOp::Add | BinOp::Sub | BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => return None,
+        BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
+        BinOp::Mul => {
+            let res = if checked {
+                if is_signed {
+                    let oflow_place = CPlace::new_stack_slot(fx, fx.tcx.types.i32);
+                    let oflow_addr = oflow_place.to_addr(fx);
+                    let oflow_addr = CValue::by_val(oflow_addr, fx.layout_of(fx.tcx.mk_mut_ptr(fx.tcx.types.i32)));
+                    let val = fx.easy_call("__muloti4", &[lhs, rhs, oflow_addr], fx.tcx.types.i128);
+                    let val = val.load_scalar(fx);
+                    let oflow = oflow_place.to_cvalue(fx).load_scalar(fx);
+                    let oflow = fx.bcx.ins().icmp_imm(IntCC::NotEqual, oflow, 0);
+                    let oflow = fx.bcx.ins().bint(types::I8, oflow);
+                    CValue::by_val_pair(val, oflow, fx.layout_of(out_ty))
+                } else {
+                    // FIXME implement it
+                let out_layout = fx.layout_of(out_ty);
+                    return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit checked binop unsigned mul")));
+                }
+            } else {
+                let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
+                fx.easy_call("__multi3", &[lhs, rhs], val_ty)
+            };
+            return Some(res);
+        }
+        BinOp::Div => {
+            let res = if checked {
+                // FIXME implement it
+                let out_layout = fx.layout_of(out_ty);
+                return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit checked binop div")));
+            } else {
+                if is_signed {
+                    fx.easy_call("__divti3", &[lhs, rhs], fx.tcx.types.i128)
+                } else {
+                    fx.easy_call("__udivti3", &[lhs, rhs], fx.tcx.types.u128)
+                }
+            };
+            return Some(res);
+        }
+        BinOp::Rem => {
+            let res = if checked {
+                // FIXME implement it
+                let out_layout = fx.layout_of(out_ty);
+                return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit checked binop rem")));
+            } else {
+                if is_signed {
+                    fx.easy_call("__modti3", &[lhs, rhs], fx.tcx.types.i128)
+                } else {
+                    fx.easy_call("__umodti3", &[lhs, rhs], fx.tcx.types.u128)
+                }
+            };
+            return Some(res);
+        }
+        BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
+            assert!(!checked);
+            let (lhs_lsb, lhs_msb) = fx.bcx.ins().isplit(lhs_val);
+            let (rhs_lsb, rhs_msb) = fx.bcx.ins().isplit(rhs_val);
+            let res = match (bin_op, is_signed) {
+                (BinOp::Eq, _) => {
+                    let lsb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_lsb, rhs_lsb);
+                    let msb_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_msb, rhs_msb);
+                    fx.bcx.ins().band(lsb_eq, msb_eq)
+                }
+                (BinOp::Ne, _) => {
+                    let lsb_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_lsb, rhs_lsb);
+                    let msb_ne = fx.bcx.ins().icmp(IntCC::NotEqual, lhs_msb, rhs_msb);
+                    fx.bcx.ins().bor(lsb_ne, msb_ne)
+                }
+                _ => {
+                    // FIXME implement it
+                    let out_layout = fx.layout_of(out_ty);
+                    return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit binop {:?}", bin_op)));
+                },
+            };
+
+            let res = fx.bcx.ins().bint(types::I8, res);
+            let res = CValue::by_val(res, fx.layout_of(fx.tcx.types.bool));
+            return Some(res);
+        }
+        BinOp::Shl | BinOp::Shr => {
+            // FIXME implement it
+            let out_layout = fx.layout_of(out_ty);
+            return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit binop {:?}", bin_op)));
+        }
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index c6f77954a86..9bd985e3dc9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -34,6 +34,7 @@ mod allocator;
 mod analyze;
 mod archive;
 mod base;
+mod codegen_i128;
 mod common;
 mod constant;
 mod debuginfo;