add intrinsics for checked overflow add/sub/mul
This commit is contained in:
parent
eebcff1493
commit
076b91f8ad
@ -2740,6 +2740,60 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> {
|
||||
ifn!("llvm.bswap.i32",[Type::i32()], Type::i32());
|
||||
ifn!("llvm.bswap.i64",[Type::i64()], Type::i64());
|
||||
|
||||
ifn!("llvm.sadd.with.overflow.i8",
|
||||
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
|
||||
ifn!("llvm.sadd.with.overflow.i16",
|
||||
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
|
||||
ifn!("llvm.sadd.with.overflow.i32",
|
||||
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
|
||||
ifn!("llvm.sadd.with.overflow.i64",
|
||||
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
|
||||
|
||||
ifn!("llvm.uadd.with.overflow.i8",
|
||||
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
|
||||
ifn!("llvm.uadd.with.overflow.i16",
|
||||
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
|
||||
ifn!("llvm.uadd.with.overflow.i32",
|
||||
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
|
||||
ifn!("llvm.uadd.with.overflow.i64",
|
||||
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
|
||||
|
||||
ifn!("llvm.ssub.with.overflow.i8",
|
||||
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
|
||||
ifn!("llvm.ssub.with.overflow.i16",
|
||||
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
|
||||
ifn!("llvm.ssub.with.overflow.i32",
|
||||
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
|
||||
ifn!("llvm.ssub.with.overflow.i64",
|
||||
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
|
||||
|
||||
ifn!("llvm.usub.with.overflow.i8",
|
||||
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
|
||||
ifn!("llvm.usub.with.overflow.i16",
|
||||
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
|
||||
ifn!("llvm.usub.with.overflow.i32",
|
||||
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
|
||||
ifn!("llvm.usub.with.overflow.i64",
|
||||
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
|
||||
|
||||
ifn!("llvm.smul.with.overflow.i8",
|
||||
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
|
||||
ifn!("llvm.smul.with.overflow.i16",
|
||||
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
|
||||
ifn!("llvm.smul.with.overflow.i32",
|
||||
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
|
||||
ifn!("llvm.smul.with.overflow.i64",
|
||||
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
|
||||
|
||||
ifn!("llvm.umul.with.overflow.i8",
|
||||
[Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
|
||||
ifn!("llvm.umul.with.overflow.i16",
|
||||
[Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
|
||||
ifn!("llvm.umul.with.overflow.i32",
|
||||
[Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
|
||||
ifn!("llvm.umul.with.overflow.i64",
|
||||
[Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
|
||||
|
||||
return intrinsics;
|
||||
}
|
||||
|
||||
|
@ -714,9 +714,11 @@ pub fn ExtractValue(cx: @mut Block, AggVal: ValueRef, Index: uint) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) {
|
||||
if cx.unreachable { return; }
|
||||
B(cx).insert_value(AggVal, EltVal, Index)
|
||||
pub fn InsertValue(cx: @mut Block, AggVal: ValueRef, EltVal: ValueRef, Index: uint) -> ValueRef {
|
||||
unsafe {
|
||||
if cx.unreachable { return llvm::LLVMGetUndef(Type::nil().to_ref()); }
|
||||
B(cx).insert_value(AggVal, EltVal, Index)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn IsNull(cx: @mut Block, Val: ValueRef) -> ValueRef {
|
||||
|
@ -861,11 +861,11 @@ impl Builder {
|
||||
}
|
||||
|
||||
pub fn insert_value(&self, agg_val: ValueRef, elt: ValueRef,
|
||||
idx: uint) {
|
||||
idx: uint) -> ValueRef {
|
||||
self.count_insn("insertvalue");
|
||||
unsafe {
|
||||
llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint,
|
||||
noname());
|
||||
noname())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ impl FunctionContext {
|
||||
}
|
||||
|
||||
pub fn out_arg_pos(&self) -> uint {
|
||||
assert!(self.has_immediate_return_value);
|
||||
assert!(!self.has_immediate_return_value);
|
||||
0u
|
||||
}
|
||||
|
||||
|
@ -550,6 +550,24 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
|
||||
Ret(bcx, Call(bcx, llfn, args.slice(0, num_args)));
|
||||
}
|
||||
|
||||
fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str) {
|
||||
let first_real_arg = bcx.fcx.arg_pos(0u);
|
||||
let a = get_param(bcx.fcx.llfn, first_real_arg);
|
||||
let b = get_param(bcx.fcx.llfn, first_real_arg + 1);
|
||||
let llfn = bcx.ccx().intrinsics.get_copy(&name);
|
||||
|
||||
// convert `i1` to a `bool`, and write to the out parameter
|
||||
let val = Call(bcx, llfn, [a, b]);
|
||||
let result = ExtractValue(bcx, val, 0);
|
||||
let overflow = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool());
|
||||
let retptr = get_param(bcx.fcx.llfn, bcx.fcx.out_arg_pos());
|
||||
let ret = Load(bcx, retptr);
|
||||
let ret = InsertValue(bcx, ret, result, 0);
|
||||
let ret = InsertValue(bcx, ret, overflow, 1);
|
||||
Store(bcx, ret, retptr);
|
||||
RetVoid(bcx)
|
||||
}
|
||||
|
||||
fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
|
||||
let ccx = bcx.ccx();
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
@ -944,6 +962,37 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
|
||||
"bswap16" => simple_llvm_intrinsic(bcx, "llvm.bswap.i16", 1),
|
||||
"bswap32" => simple_llvm_intrinsic(bcx, "llvm.bswap.i32", 1),
|
||||
"bswap64" => simple_llvm_intrinsic(bcx, "llvm.bswap.i64", 1),
|
||||
|
||||
"i8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i8"),
|
||||
"i16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i16"),
|
||||
"i32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i32"),
|
||||
"i64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.sadd.with.overflow.i64"),
|
||||
|
||||
"u8_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i8"),
|
||||
"u16_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i16"),
|
||||
"u32_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i32"),
|
||||
"u64_add_with_overflow" => with_overflow_instrinsic(bcx, "llvm.uadd.with.overflow.i64"),
|
||||
|
||||
"i8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i8"),
|
||||
"i16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i16"),
|
||||
"i32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i32"),
|
||||
"i64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.ssub.with.overflow.i64"),
|
||||
|
||||
"u8_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i8"),
|
||||
"u16_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i16"),
|
||||
"u32_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i32"),
|
||||
"u64_sub_with_overflow" => with_overflow_instrinsic(bcx, "llvm.usub.with.overflow.i64"),
|
||||
|
||||
"i8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i8"),
|
||||
"i16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i16"),
|
||||
"i32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i32"),
|
||||
"i64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.smul.with.overflow.i64"),
|
||||
|
||||
"u8_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i8"),
|
||||
"u16_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i16"),
|
||||
"u32_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i32"),
|
||||
"u64_mul_with_overflow" => with_overflow_instrinsic(bcx, "llvm.umul.with.overflow.i64"),
|
||||
|
||||
_ => {
|
||||
// Could we make this an enum rather than a string? does it get
|
||||
// checked earlier?
|
||||
|
@ -168,6 +168,22 @@ pub fn type_uses_for(ccx: @mut CrateContext, fn_id: def_id, n_tps: uint)
|
||||
|
||||
"bswap16" | "bswap32" | "bswap64" => 0,
|
||||
|
||||
|
||||
"i8_add_with_overflow" | "u8_add_with_overflow" |
|
||||
"i16_add_with_overflow" | "u16_add_with_overflow" |
|
||||
"i32_add_with_overflow" | "u32_add_with_overflow" |
|
||||
"i64_add_with_overflow" | "u64_add_with_overflow" => 0,
|
||||
|
||||
"i8_sub_with_overflow" | "u8_sub_with_overflow" |
|
||||
"i16_sub_with_overflow" | "u16_sub_with_overflow" |
|
||||
"i32_sub_with_overflow" | "u32_sub_with_overflow" |
|
||||
"i64_sub_with_overflow" | "u64_sub_with_overflow" => 0,
|
||||
|
||||
"i8_mul_with_overflow" | "u8_mul_with_overflow" |
|
||||
"i16_mul_with_overflow" | "u16_mul_with_overflow" |
|
||||
"i32_mul_with_overflow" | "u32_mul_with_overflow" |
|
||||
"i64_mul_with_overflow" | "u64_mul_with_overflow" => 0,
|
||||
|
||||
// would be cool to make these an enum instead of
|
||||
// strings!
|
||||
_ => fail!("unknown intrinsic in type_use")
|
||||
|
@ -3647,6 +3647,39 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
||||
"bswap16" => (0, ~[ ty::mk_i16() ], ty::mk_i16()),
|
||||
"bswap32" => (0, ~[ ty::mk_i32() ], ty::mk_i32()),
|
||||
"bswap64" => (0, ~[ ty::mk_i64() ], ty::mk_i64()),
|
||||
|
||||
"i8_add_with_overflow" | "i8_sub_with_overflow" | "i8_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_i8(), ty::mk_i8()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_i8(), ty::mk_bool()])),
|
||||
|
||||
"i16_add_with_overflow" | "i16_sub_with_overflow" | "i16_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_i16(), ty::mk_i16()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_i16(), ty::mk_bool()])),
|
||||
|
||||
"i32_add_with_overflow" | "i32_sub_with_overflow" | "i32_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_i32(), ty::mk_i32()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_i32(), ty::mk_bool()])),
|
||||
|
||||
"i64_add_with_overflow" | "i64_sub_with_overflow" | "i64_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_i64(), ty::mk_i64()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_i64(), ty::mk_bool()])),
|
||||
|
||||
"u8_add_with_overflow" | "u8_sub_with_overflow" | "u8_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_u8(), ty::mk_u8()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_u8(), ty::mk_bool()])),
|
||||
|
||||
"u16_add_with_overflow" | "u16_sub_with_overflow" | "u16_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_u16(), ty::mk_u16()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_u16(), ty::mk_bool()])),
|
||||
|
||||
"u32_add_with_overflow" | "u32_sub_with_overflow" | "u32_mul_with_overflow"=>
|
||||
(0, ~[ty::mk_u32(), ty::mk_u32()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_u32(), ty::mk_bool()])),
|
||||
|
||||
"u64_add_with_overflow" | "u64_sub_with_overflow" | "u64_mul_with_overflow" =>
|
||||
(0, ~[ty::mk_u64(), ty::mk_u64()],
|
||||
ty::mk_tup(tcx, ~[ty::mk_u64(), ty::mk_bool()])),
|
||||
|
||||
ref other => {
|
||||
tcx.sess.span_err(it.span,
|
||||
fmt!("unrecognized intrinsic function: `%s`",
|
||||
|
@ -18,7 +18,9 @@
|
||||
use cmp::{Eq, ApproxEq, Ord};
|
||||
use ops::{Add, Sub, Mul, Div, Rem, Neg};
|
||||
use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr};
|
||||
use option::Option;
|
||||
use option::{Option, Some, None};
|
||||
#[cfg(not(stage0))]
|
||||
use unstable::intrinsics;
|
||||
|
||||
pub mod strconv;
|
||||
|
||||
@ -516,6 +518,414 @@ impl Saturating for u16 {}
|
||||
impl Saturating for u32 {}
|
||||
impl Saturating for u64 {}
|
||||
|
||||
pub trait CheckedAdd: Add<Self, Self> {
|
||||
fn checked_add(&self, v: &Self) -> Option<Self>;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for i8 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &i8) -> Option<i8> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i8_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for i16 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &i16) -> Option<i16> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i16_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for i32 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &i32) -> Option<i32> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i32_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for i64 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &i64) -> Option<i64> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i64_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "32")]
|
||||
impl CheckedAdd for int {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &int) -> Option<int> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i32_add_with_overflow(*self as i32, *v as i32);
|
||||
if y { None } else { Some(x as int) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "64")]
|
||||
impl CheckedAdd for int {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &int) -> Option<int> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i64_add_with_overflow(*self as i64, *v as i64);
|
||||
if y { None } else { Some(x as int) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for u8 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &u8) -> Option<u8> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u8_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for u16 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &u16) -> Option<u16> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u16_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for u32 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &u32) -> Option<u32> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u32_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedAdd for u64 {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &u64) -> Option<u64> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u64_add_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "32")]
|
||||
impl CheckedAdd for uint {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &uint) -> Option<uint> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u32_add_with_overflow(*self as u32, *v as u32);
|
||||
if y { None } else { Some(x as uint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "64")]
|
||||
impl CheckedAdd for uint {
|
||||
#[inline]
|
||||
fn checked_add(&self, v: &uint) -> Option<uint> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u64_add_with_overflow(*self as u64, *v as u64);
|
||||
if y { None } else { Some(x as uint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CheckedSub: Sub<Self, Self> {
|
||||
fn checked_sub(&self, v: &Self) -> Option<Self>;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for i8 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &i8) -> Option<i8> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i8_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for i16 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &i16) -> Option<i16> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i16_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for i32 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &i32) -> Option<i32> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i32_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for i64 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &i64) -> Option<i64> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i64_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "32")]
|
||||
impl CheckedSub for int {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &int) -> Option<int> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i32_sub_with_overflow(*self as i32, *v as i32);
|
||||
if y { None } else { Some(x as int) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "64")]
|
||||
impl CheckedSub for int {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &int) -> Option<int> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i64_sub_with_overflow(*self as i64, *v as i64);
|
||||
if y { None } else { Some(x as int) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for u8 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &u8) -> Option<u8> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u8_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for u16 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &u16) -> Option<u16> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u16_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for u32 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &u32) -> Option<u32> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u32_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedSub for u64 {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &u64) -> Option<u64> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u64_sub_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "32")]
|
||||
impl CheckedSub for uint {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &uint) -> Option<uint> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u32_sub_with_overflow(*self as u32, *v as u32);
|
||||
if y { None } else { Some(x as uint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "64")]
|
||||
impl CheckedSub for uint {
|
||||
#[inline]
|
||||
fn checked_sub(&self, v: &uint) -> Option<uint> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u64_sub_with_overflow(*self as u64, *v as u64);
|
||||
if y { None } else { Some(x as uint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CheckedMul: Mul<Self, Self> {
|
||||
fn checked_mul(&self, v: &Self) -> Option<Self>;
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for i8 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &i8) -> Option<i8> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i8_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for i16 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &i16) -> Option<i16> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i16_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for i32 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &i32) -> Option<i32> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i32_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for i64 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &i64) -> Option<i64> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i64_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "32")]
|
||||
impl CheckedMul for int {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &int) -> Option<int> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i32_mul_with_overflow(*self as i32, *v as i32);
|
||||
if y { None } else { Some(x as int) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "64")]
|
||||
impl CheckedMul for int {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &int) -> Option<int> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::i64_mul_with_overflow(*self as i64, *v as i64);
|
||||
if y { None } else { Some(x as int) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for u8 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &u8) -> Option<u8> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u8_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for u16 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &u16) -> Option<u16> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u16_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for u32 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &u32) -> Option<u32> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u32_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl CheckedMul for u64 {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &u64) -> Option<u64> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u64_mul_with_overflow(*self, *v);
|
||||
if y { None } else { Some(x) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "32")]
|
||||
impl CheckedMul for uint {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &uint) -> Option<uint> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u32_mul_with_overflow(*self as u32, *v as u32);
|
||||
if y { None } else { Some(x as uint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0), target_word_size = "64")]
|
||||
impl CheckedMul for uint {
|
||||
#[inline]
|
||||
fn checked_mul(&self, v: &uint) -> Option<uint> {
|
||||
unsafe {
|
||||
let (x, y) = intrinsics::u64_mul_with_overflow(*self as u64, *v as u64);
|
||||
if y { None } else { Some(x as uint) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function for testing numeric operations
|
||||
#[cfg(test)]
|
||||
pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
|
||||
@ -534,6 +944,8 @@ pub fn test_num<T:Num + NumCast>(ten: T, two: T) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use prelude::*;
|
||||
use uint;
|
||||
use super::*;
|
||||
|
||||
macro_rules! test_cast_20(
|
||||
@ -639,4 +1051,39 @@ mod tests {
|
||||
assert_eq!(max_value.saturating_sub(-max_value), max_value);
|
||||
assert_eq!((max_value-2).saturating_sub(-1), max_value-1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_checked_add() {
|
||||
let five_less = uint::max_value - 5;
|
||||
assert_eq!(five_less.checked_add(&0), Some(uint::max_value - 5));
|
||||
assert_eq!(five_less.checked_add(&1), Some(uint::max_value - 4));
|
||||
assert_eq!(five_less.checked_add(&2), Some(uint::max_value - 3));
|
||||
assert_eq!(five_less.checked_add(&3), Some(uint::max_value - 2));
|
||||
assert_eq!(five_less.checked_add(&4), Some(uint::max_value - 1));
|
||||
assert_eq!(five_less.checked_add(&5), Some(uint::max_value));
|
||||
assert_eq!(five_less.checked_add(&6), None);
|
||||
assert_eq!(five_less.checked_add(&7), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_checked_sub() {
|
||||
assert_eq!(5u.checked_sub(&0), Some(5));
|
||||
assert_eq!(5u.checked_sub(&1), Some(4));
|
||||
assert_eq!(5u.checked_sub(&2), Some(3));
|
||||
assert_eq!(5u.checked_sub(&3), Some(2));
|
||||
assert_eq!(5u.checked_sub(&4), Some(1));
|
||||
assert_eq!(5u.checked_sub(&5), Some(0));
|
||||
assert_eq!(5u.checked_sub(&6), None);
|
||||
assert_eq!(5u.checked_sub(&7), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_checked_mul() {
|
||||
let third = uint::max_value / 3;
|
||||
assert_eq!(third.checked_mul(&0), Some(0));
|
||||
assert_eq!(third.checked_mul(&1), Some(third));
|
||||
assert_eq!(third.checked_mul(&2), Some(third * 2));
|
||||
assert_eq!(third.checked_mul(&3), Some(third * 3));
|
||||
assert_eq!(third.checked_mul(&4), None);
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ pub use iter::Times;
|
||||
pub use iterator::Extendable;
|
||||
pub use iterator::{Iterator, DoubleEndedIterator};
|
||||
pub use iterator::{ClonableIterator, OrdIterator};
|
||||
pub use num::{Num, NumCast};
|
||||
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
|
||||
pub use num::{Orderable, Signed, Unsigned, Round};
|
||||
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
|
||||
pub use num::{Integer, Fractional, Real, RealExt};
|
||||
|
@ -428,6 +428,60 @@ extern "rust-intrinsic" {
|
||||
pub fn bswap16(x: i16) -> i16;
|
||||
pub fn bswap32(x: i32) -> i32;
|
||||
pub fn bswap64(x: i64) -> i64;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i8_add_with_overflow(x: i8, y: i8) -> (i8, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i16_add_with_overflow(x: i16, y: i16) -> (i16, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i32_add_with_overflow(x: i32, y: i32) -> (i32, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i64_add_with_overflow(x: i64, y: i64) -> (i64, bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u8_add_with_overflow(x: u8, y: u8) -> (u8, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u16_add_with_overflow(x: u16, y: u16) -> (u16, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u32_add_with_overflow(x: u32, y: u32) -> (u32, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u64_add_with_overflow(x: u64, y: u64) -> (u64, bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i8_sub_with_overflow(x: i8, y: i8) -> (i8, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i16_sub_with_overflow(x: i16, y: i16) -> (i16, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i32_sub_with_overflow(x: i32, y: i32) -> (i32, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i64_sub_with_overflow(x: i64, y: i64) -> (i64, bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u8_sub_with_overflow(x: u8, y: u8) -> (u8, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u16_sub_with_overflow(x: u16, y: u16) -> (u16, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u32_sub_with_overflow(x: u32, y: u32) -> (u32, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u64_sub_with_overflow(x: u64, y: u64) -> (u64, bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i8_mul_with_overflow(x: i8, y: i8) -> (i8, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i16_mul_with_overflow(x: i16, y: i16) -> (i16, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i32_mul_with_overflow(x: i32, y: i32) -> (i32, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn i64_mul_with_overflow(x: i64, y: i64) -> (i64, bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u8_mul_with_overflow(x: u8, y: u8) -> (u8, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u16_mul_with_overflow(x: u16, y: u16) -> (u16, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u32_mul_with_overflow(x: u32, y: u32) -> (u32, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn u64_mul_with_overflow(x: u64, y: u64) -> (u64, bool);
|
||||
}
|
||||
|
||||
#[cfg(target_endian = "little")] pub fn to_le16(x: i16) -> i16 { x }
|
||||
|
Loading…
Reference in New Issue
Block a user