about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2019-07-20 17:57:00 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2019-07-26 11:29:35 +0200
commit65e337cdf3e9a54dbabcdb92aebdfb79b5660e24 (patch)
tree6697b3ac7c90f56af6ca4b4cbbface7054716348
parent88ad25f45e9adbf08871ce77449e1b1193d23df4 (diff)
downloadrust-65e337cdf3e9a54dbabcdb92aebdfb79b5660e24.tar.gz
rust-65e337cdf3e9a54dbabcdb92aebdfb79b5660e24.zip
Implement 128bit multiply with overflow
-rw-r--r--example/std_example.rs5
-rw-r--r--src/abi.rs36
-rw-r--r--src/codegen_i128.rs49
3 files changed, 34 insertions, 56 deletions
diff --git a/example/std_example.rs b/example/std_example.rs
index a67ca2f79c7..9e9a7a67e05 100644
--- a/example/std_example.rs
+++ b/example/std_example.rs
@@ -22,4 +22,9 @@ fn main() {
     checked_div_i128(0i128, 2i128);
     checked_div_u128(0u128, 2u128);
     assert_eq!(1u128 + 2, 3);
+
+    println!("{}", 0b100010000000000000000000000000000u128 >> 10);
+    println!("{}", 0xFEDCBA987654321123456789ABCDEFu128 >> 64);
+    println!("{} >> 64 == {}", 0xFEDCBA987654321123456789ABCDEFu128 as i128, 0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64);
+    println!("{}", 353985398u128 * 932490u128);
 }
diff --git a/src/abi.rs b/src/abi.rs
index 1c9f84b37e4..b884d80b394 100644
--- a/src/abi.rs
+++ b/src/abi.rs
@@ -252,14 +252,12 @@ impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
         &mut self,
         name: &str,
         input_tys: Vec<types::Type>,
-        output_ty: Option<types::Type>,
+        output_tys: Vec<types::Type>,
         args: &[Value],
-    ) -> Option<Value> {
+    ) -> &[Value] {
         let sig = Signature {
             params: input_tys.iter().cloned().map(AbiParam::new).collect(),
-            returns: output_ty
-                .map(|output_ty| vec![AbiParam::new(output_ty)])
-                .unwrap_or(Vec::new()),
+            returns: output_tys.iter().cloned().map(AbiParam::new).collect(),
             call_conv: CallConv::SystemV,
         };
         let func_id = self
@@ -271,12 +269,9 @@ impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
             .declare_func_in_func(func_id, &mut self.bcx.func);
         let call_inst = self.bcx.ins().call(func_ref, args);
         self.add_comment(call_inst, format!("easy_call {}", name));
-        if output_ty.is_none() {
-            return None;
-        }
         let results = self.bcx.inst_results(call_inst);
-        assert_eq!(results.len(), 1);
-        Some(results[0])
+        assert!(results.len() <= 2, "{}", results.len());
+        results
     }
 
     pub fn easy_call(
@@ -295,23 +290,22 @@ impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
             })
             .unzip();
         let return_layout = self.layout_of(return_ty);
-        let return_ty = if let ty::Tuple(tup) = return_ty.sty {
-            if !tup.is_empty() {
-                bug!("easy_call( (...) -> <non empty tuple> ) is not allowed");
-            }
-            None
+        let return_tys = if let ty::Tuple(tup) = return_ty.sty {
+            tup.types().map(|ty| self.clif_type(ty).unwrap()).collect()
         } else {
-            Some(self.clif_type(return_ty).unwrap())
+            vec![self.clif_type(return_ty).unwrap()]
         };
-        if let Some(val) = self.lib_call(name, input_tys, return_ty, &args) {
-            CValue::by_val(val, return_layout)
-        } else {
-            CValue::by_ref(
+        let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
+        match *ret_vals {
+            [] => CValue::by_ref(
                 self.bcx
                     .ins()
                     .iconst(self.pointer_type, self.pointer_type.bytes() as i64),
                 return_layout,
-            )
+            ),
+            [val] => CValue::by_val(val, return_layout),
+            [val, extra] => CValue::by_val_pair(val, extra, return_layout),
+            _ => unreachable!(),
         }
     }
 
diff --git a/src/codegen_i128.rs b/src/codegen_i128.rs
index 81388573c9e..b5e2bb6b3c9 100644
--- a/src/codegen_i128.rs
+++ b/src/codegen_i128.rs
@@ -30,19 +30,9 @@ pub fn maybe_codegen<'a, 'tcx>(
         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))
+                    fx.easy_call("__rust_i128_mulo", &[lhs, rhs], 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")));
+                    fx.easy_call("__rust_u128_mulo", &[lhs, rhs], out_ty)
                 }
             } else {
                 let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
@@ -51,32 +41,20 @@ pub fn maybe_codegen<'a, 'tcx>(
             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")));
+            assert!(!checked);
+            if is_signed {
+                Some(fx.easy_call("__divti3", &[lhs, rhs], fx.tcx.types.i128))
             } 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);
+                Some(fx.easy_call("__udivti3", &[lhs, rhs], fx.tcx.types.u128))
+            }
         }
         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")));
+            assert!(!checked);
+            if is_signed {
+                Some(fx.easy_call("__modti3", &[lhs, rhs], fx.tcx.types.i128))
             } 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);
+                Some(fx.easy_call("__umodti3", &[lhs, rhs], fx.tcx.types.u128))
+            }
         }
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
             assert!(!checked);
@@ -140,8 +118,9 @@ pub fn maybe_codegen<'a, 'tcx>(
                         Some(CValue::by_val(val, fx.layout_of(fx.tcx.types.i128)))
                     }
                     (BinOp::Shl, _) => {
+                        let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
                         let val = fx.bcx.ins().iconcat(all_zeros, lhs_lsb);
-                        Some(CValue::by_val(val, fx.layout_of(out_ty)))
+                        Some(CValue::by_val(val, fx.layout_of(val_ty)))
                     }
                     _ => None
                 };