Implement 128bit multiply with overflow

This commit is contained in:
bjorn3 2019-07-20 17:57:00 +02:00
parent 88ad25f45e
commit 65e337cdf3
3 changed files with 34 additions and 56 deletions

View File

@ -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);
}

View File

@ -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!(),
}
}

View File

@ -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
};