2016-08-18 04:50:24 +08:00
|
|
|
use int::{Int, LargeInt};
|
2016-08-13 16:51:54 +08:00
|
|
|
|
|
|
|
macro_rules! ashl {
|
|
|
|
($intrinsic:ident: $ty:ty) => {
|
|
|
|
/// Returns `a << b`, requires `b < $ty::bits()`
|
|
|
|
#[cfg_attr(not(test), no_mangle)]
|
2016-08-19 00:20:24 +08:00
|
|
|
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
2016-08-13 16:51:54 +08:00
|
|
|
let half_bits = <$ty>::bits() / 2;
|
|
|
|
if b & half_bits != 0 {
|
|
|
|
<$ty>::from_parts(0, a.low() << (b - half_bits))
|
|
|
|
} else if b == 0 {
|
|
|
|
a
|
|
|
|
} else {
|
|
|
|
<$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! ashr {
|
|
|
|
($intrinsic:ident: $ty:ty) => {
|
|
|
|
/// Returns arithmetic `a >> b`, requires `b < $ty::bits()`
|
|
|
|
#[cfg_attr(not(test), no_mangle)]
|
2016-08-19 00:20:24 +08:00
|
|
|
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
2016-08-13 16:51:54 +08:00
|
|
|
let half_bits = <$ty>::bits() / 2;
|
|
|
|
if b & half_bits != 0 {
|
|
|
|
<$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf,
|
|
|
|
a.high() >> (half_bits - 1))
|
|
|
|
} else if b == 0 {
|
|
|
|
a
|
|
|
|
} else {
|
|
|
|
let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf;
|
|
|
|
<$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b),
|
|
|
|
a.high() >> b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! lshr {
|
|
|
|
($intrinsic:ident: $ty:ty) => {
|
|
|
|
/// Returns logical `a >> b`, requires `b < $ty::bits()`
|
|
|
|
#[cfg_attr(not(test), no_mangle)]
|
2016-08-19 00:20:24 +08:00
|
|
|
pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty {
|
2016-08-13 16:51:54 +08:00
|
|
|
let half_bits = <$ty>::bits() / 2;
|
|
|
|
if b & half_bits != 0 {
|
|
|
|
<$ty>::from_parts(a.high() >> (b - half_bits), 0)
|
|
|
|
} else if b == 0 {
|
|
|
|
a
|
|
|
|
} else {
|
|
|
|
<$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 04:55:11 +08:00
|
|
|
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
2016-08-13 16:51:54 +08:00
|
|
|
ashl!(__ashldi3: u64);
|
2016-09-27 04:55:11 +08:00
|
|
|
|
2017-01-04 10:04:27 +08:00
|
|
|
ashl!(__ashlti3: u128);
|
|
|
|
|
2016-09-27 04:55:11 +08:00
|
|
|
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
2016-08-13 16:51:54 +08:00
|
|
|
ashr!(__ashrdi3: i64);
|
2016-09-27 04:55:11 +08:00
|
|
|
|
2017-01-04 10:04:27 +08:00
|
|
|
ashr!(__ashrti3: i128);
|
|
|
|
|
2016-09-27 04:55:11 +08:00
|
|
|
#[cfg(not(all(feature = "c", target_arch = "x86")))]
|
2016-08-13 16:51:54 +08:00
|
|
|
lshr!(__lshrdi3: u64);
|
|
|
|
|
2017-01-04 10:04:27 +08:00
|
|
|
lshr!(__lshrti3: u128);
|
|
|
|
|
2016-08-13 16:51:54 +08:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2016-09-22 10:38:06 +08:00
|
|
|
use qc::{I64, U64};
|
|
|
|
|
2016-08-14 05:58:44 +08:00
|
|
|
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
2016-09-27 13:22:10 +08:00
|
|
|
check! {
|
|
|
|
fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
2016-08-14 05:58:44 +08:00
|
|
|
let a = a.0;
|
2016-08-13 16:51:54 +08:00
|
|
|
if b >= 64 {
|
2016-09-27 13:22:10 +08:00
|
|
|
None
|
2016-08-13 16:51:54 +08:00
|
|
|
} else {
|
2016-09-27 13:22:10 +08:00
|
|
|
Some(f(a, b))
|
2016-08-13 16:51:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 13:22:10 +08:00
|
|
|
fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option<i64> {
|
2016-08-14 05:58:44 +08:00
|
|
|
let a = a.0;
|
2016-08-13 16:51:54 +08:00
|
|
|
if b >= 64 {
|
2016-09-27 13:22:10 +08:00
|
|
|
None
|
2016-08-13 16:51:54 +08:00
|
|
|
} else {
|
2016-09-27 13:22:10 +08:00
|
|
|
Some(f(a, b))
|
2016-08-13 16:51:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 13:22:10 +08:00
|
|
|
fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
|
2016-08-14 05:58:44 +08:00
|
|
|
let a = a.0;
|
2016-08-13 16:51:54 +08:00
|
|
|
if b >= 64 {
|
2016-09-27 13:22:10 +08:00
|
|
|
None
|
2016-08-13 16:51:54 +08:00
|
|
|
} else {
|
2016-09-27 13:22:10 +08:00
|
|
|
Some(f(a, b))
|
2016-08-13 16:51:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-04 05:06:36 +08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
2017-02-04 19:17:04 +08:00
|
|
|
#[cfg(all(not(windows),
|
|
|
|
not(target_arch = "mips64"),
|
|
|
|
not(target_arch = "mips64el"),
|
|
|
|
target_pointer_width="64"))]
|
2017-02-04 05:06:36 +08:00
|
|
|
mod tests_i128 {
|
|
|
|
use qc::{I128, U128};
|
|
|
|
|
|
|
|
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
|
|
|
|
check! {
|
|
|
|
fn __ashlti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
|
|
|
|
let a = a.0;
|
|
|
|
if b >= 64 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(f(a, b))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn __ashrti3(f: extern fn(i128, u32) -> i128, a: I128, b: u32) -> Option<i128> {
|
|
|
|
let a = a.0;
|
|
|
|
if b >= 64 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(f(a, b))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn __lshrti3(f: extern fn(u128, u32) -> u128, a: U128, b: u32) -> Option<u128> {
|
|
|
|
let a = a.0;
|
|
|
|
if b >= 128 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(f(a, b))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|