compiler-builtins-zynq/src/int/shift.rs

95 lines
2.8 KiB
Rust
Raw Normal View History

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)
}
}
}
}
ashl!(__ashldi3: u64);
ashr!(__ashrdi3: i64);
lshr!(__lshrdi3: u64);
#[cfg(test)]
mod tests {
use qc::{I64, U64};
// NOTE We purposefully stick to `u32` for `b` here because we want "small" values (b < 64)
check! {
fn __ashldi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
let a = a.0;
2016-08-13 16:51:54 +08:00
if b >= 64 {
None
2016-08-13 16:51:54 +08:00
} else {
Some(f(a, b))
2016-08-13 16:51:54 +08:00
}
}
fn __ashrdi3(f: extern fn(i64, u32) -> i64, a: I64, b: u32) -> Option<i64> {
let a = a.0;
2016-08-13 16:51:54 +08:00
if b >= 64 {
None
2016-08-13 16:51:54 +08:00
} else {
Some(f(a, b))
2016-08-13 16:51:54 +08:00
}
}
fn __lshrdi3(f: extern fn(u64, u32) -> u64, a: U64, b: u32) -> Option<u64> {
let a = a.0;
2016-08-13 16:51:54 +08:00
if b >= 64 {
None
2016-08-13 16:51:54 +08:00
} else {
Some(f(a, b))
2016-08-13 16:51:54 +08:00
}
}
}
}