Implement 128bit multiply with overflow
This commit is contained in:
parent
88ad25f45e
commit
65e337cdf3
3 changed files with 34 additions and 56 deletions
|
@ -22,4 +22,9 @@ fn main() {
|
||||||
checked_div_i128(0i128, 2i128);
|
checked_div_i128(0i128, 2i128);
|
||||||
checked_div_u128(0u128, 2u128);
|
checked_div_u128(0u128, 2u128);
|
||||||
assert_eq!(1u128 + 2, 3);
|
assert_eq!(1u128 + 2, 3);
|
||||||
|
|
||||||
|
println!("{}", 0b100010000000000000000000000000000u128 >> 10);
|
||||||
|
println!("{}", 0xFEDCBA987654321123456789ABCDEFu128 >> 64);
|
||||||
|
println!("{} >> 64 == {}", 0xFEDCBA987654321123456789ABCDEFu128 as i128, 0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64);
|
||||||
|
println!("{}", 353985398u128 * 932490u128);
|
||||||
}
|
}
|
||||||
|
|
36
src/abi.rs
36
src/abi.rs
|
@ -252,14 +252,12 @@ impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
input_tys: Vec<types::Type>,
|
input_tys: Vec<types::Type>,
|
||||||
output_ty: Option<types::Type>,
|
output_tys: Vec<types::Type>,
|
||||||
args: &[Value],
|
args: &[Value],
|
||||||
) -> Option<Value> {
|
) -> &[Value] {
|
||||||
let sig = Signature {
|
let sig = Signature {
|
||||||
params: input_tys.iter().cloned().map(AbiParam::new).collect(),
|
params: input_tys.iter().cloned().map(AbiParam::new).collect(),
|
||||||
returns: output_ty
|
returns: output_tys.iter().cloned().map(AbiParam::new).collect(),
|
||||||
.map(|output_ty| vec![AbiParam::new(output_ty)])
|
|
||||||
.unwrap_or(Vec::new()),
|
|
||||||
call_conv: CallConv::SystemV,
|
call_conv: CallConv::SystemV,
|
||||||
};
|
};
|
||||||
let func_id = self
|
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);
|
.declare_func_in_func(func_id, &mut self.bcx.func);
|
||||||
let call_inst = self.bcx.ins().call(func_ref, args);
|
let call_inst = self.bcx.ins().call(func_ref, args);
|
||||||
self.add_comment(call_inst, format!("easy_call {}", name));
|
self.add_comment(call_inst, format!("easy_call {}", name));
|
||||||
if output_ty.is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let results = self.bcx.inst_results(call_inst);
|
let results = self.bcx.inst_results(call_inst);
|
||||||
assert_eq!(results.len(), 1);
|
assert!(results.len() <= 2, "{}", results.len());
|
||||||
Some(results[0])
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn easy_call(
|
pub fn easy_call(
|
||||||
|
@ -295,23 +290,22 @@ impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
|
||||||
})
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
let return_layout = self.layout_of(return_ty);
|
let return_layout = self.layout_of(return_ty);
|
||||||
let return_ty = if let ty::Tuple(tup) = return_ty.sty {
|
let return_tys = if let ty::Tuple(tup) = return_ty.sty {
|
||||||
if !tup.is_empty() {
|
tup.types().map(|ty| self.clif_type(ty).unwrap()).collect()
|
||||||
bug!("easy_call( (...) -> <non empty tuple> ) is not allowed");
|
|
||||||
}
|
|
||||||
None
|
|
||||||
} else {
|
} 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) {
|
let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
|
||||||
CValue::by_val(val, return_layout)
|
match *ret_vals {
|
||||||
} else {
|
[] => CValue::by_ref(
|
||||||
CValue::by_ref(
|
|
||||||
self.bcx
|
self.bcx
|
||||||
.ins()
|
.ins()
|
||||||
.iconst(self.pointer_type, self.pointer_type.bytes() as i64),
|
.iconst(self.pointer_type, self.pointer_type.bytes() as i64),
|
||||||
return_layout,
|
return_layout,
|
||||||
)
|
),
|
||||||
|
[val] => CValue::by_val(val, return_layout),
|
||||||
|
[val, extra] => CValue::by_val_pair(val, extra, return_layout),
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,19 +30,9 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
BinOp::Mul => {
|
BinOp::Mul => {
|
||||||
let res = if checked {
|
let res = if checked {
|
||||||
if is_signed {
|
if is_signed {
|
||||||
let oflow_place = CPlace::new_stack_slot(fx, fx.tcx.types.i32);
|
fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty)
|
||||||
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 {
|
} else {
|
||||||
// FIXME implement it
|
fx.easy_call("__rust_u128_mulo", &[lhs, rhs], out_ty)
|
||||||
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 {
|
} else {
|
||||||
let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
|
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);
|
return Some(res);
|
||||||
}
|
}
|
||||||
BinOp::Div => {
|
BinOp::Div => {
|
||||||
let res = if checked {
|
assert!(!checked);
|
||||||
// FIXME implement it
|
if is_signed {
|
||||||
let out_layout = fx.layout_of(out_ty);
|
Some(fx.easy_call("__divti3", &[lhs, rhs], fx.tcx.types.i128))
|
||||||
return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit checked binop div")));
|
|
||||||
} else {
|
} else {
|
||||||
if is_signed {
|
Some(fx.easy_call("__udivti3", &[lhs, rhs], fx.tcx.types.u128))
|
||||||
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 => {
|
BinOp::Rem => {
|
||||||
let res = if checked {
|
assert!(!checked);
|
||||||
// FIXME implement it
|
if is_signed {
|
||||||
let out_layout = fx.layout_of(out_ty);
|
Some(fx.easy_call("__modti3", &[lhs, rhs], fx.tcx.types.i128))
|
||||||
return Some(crate::trap::trap_unreachable_ret_value(fx, out_layout, format!("unimplemented 128bit checked binop rem")));
|
|
||||||
} else {
|
} else {
|
||||||
if is_signed {
|
Some(fx.easy_call("__umodti3", &[lhs, rhs], fx.tcx.types.u128))
|
||||||
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 => {
|
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
|
||||||
assert!(!checked);
|
assert!(!checked);
|
||||||
|
@ -140,8 +118,9 @@ pub fn maybe_codegen<'a, 'tcx>(
|
||||||
Some(CValue::by_val(val, fx.layout_of(fx.tcx.types.i128)))
|
Some(CValue::by_val(val, fx.layout_of(fx.tcx.types.i128)))
|
||||||
}
|
}
|
||||||
(BinOp::Shl, _) => {
|
(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);
|
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
|
_ => None
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue