diff --git a/src/int/mod.rs b/src/int/mod.rs index 768b6b4..11a31ac 100755 --- a/src/int/mod.rs +++ b/src/int/mod.rs @@ -1,3 +1,5 @@ +use core::ops; + macro_rules! hty { ($ty:ty) => { <$ty as LargeInt>::HighHalf @@ -16,15 +18,25 @@ pub mod shift; pub mod udiv; /// Trait for some basic operations on integers -pub trait Int { +pub trait Int: + Copy + + PartialEq + + ops::Shl + + ops::Shr + + ops::BitOr + + // ops::BitAnd + +{ /// Type with the same width but other signedness - type OtherSign; + type OtherSign: Int; /// Unsigned version of Self - type UnsignedInt; + type UnsignedInt: Int; /// Returns the bitwidth of the int type fn bits() -> u32; + /// Returns the zero representation of this number + fn zero() -> Self; + /// Extracts the sign from self and returns a tuple. /// /// # Examples @@ -36,6 +48,9 @@ pub trait Int { /// assert_eq!(u, 25_u32); /// ``` fn extract_sign(self) -> (bool, Self::UnsignedInt); + + /// Convert to a signed representation + fn unsigned(self) -> Self::UnsignedInt; } macro_rules! int_impl { @@ -44,6 +59,10 @@ macro_rules! int_impl { type OtherSign = $ity; type UnsignedInt = $uty; + fn zero() -> Self { + 0 + } + fn bits() -> u32 { $bits } @@ -51,6 +70,10 @@ macro_rules! int_impl { fn extract_sign(self) -> (bool, $uty) { (false, self) } + + fn unsigned(self) -> $uty { + self + } } impl Int for $ity { @@ -61,6 +84,10 @@ macro_rules! int_impl { $bits } + fn zero() -> Self { + 0 + } + fn extract_sign(self) -> (bool, $uty) { if self < 0 { (true, (!(self as $uty)).wrapping_add(1)) @@ -68,6 +95,10 @@ macro_rules! int_impl { (false, self as $uty) } } + + fn unsigned(self) -> $uty { + self as $uty + } } } } @@ -77,9 +108,9 @@ int_impl!(i64, u64, 64); int_impl!(i128, u128, 128); /// Trait to convert an integer to/from smaller parts -pub trait LargeInt { - type LowHalf; - type HighHalf; +pub trait LargeInt: Int { + type LowHalf: Int; + type HighHalf: Int; fn low(self) -> Self::LowHalf; fn high(self) -> Self::HighHalf; diff --git a/src/int/shift.rs b/src/int/shift.rs index 8b5c4a1..23a49ac 100644 --- a/src/int/shift.rs +++ b/src/int/shift.rs @@ -1,74 +1,94 @@ use int::{Int, LargeInt}; -macro_rules! ashl { - ($intrinsic:ident: $ty:ty) => { - /// Returns `a << b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - 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))) - } +trait Ashl: Int + LargeInt { + /// Returns `a << b`, requires `b < $ty::bits()` + fn ashl(self, offset: u32) -> Self + where Self: LargeInt::LowHalf>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts(Int::zero(), self.low() << (offset - half_bits)) + } else if offset == 0 { + self + } else { + Self::from_parts(self.low() << offset, + (self.high() << offset) | + (self.low() >> (half_bits - offset))) } } } -macro_rules! ashr { - ($intrinsic:ident: $ty:ty) => { - /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - #[cfg_attr(all(not(test), not(target_arch = "arm")), no_mangle)] - #[cfg_attr(all(not(test), target_arch = "arm"), inline(always))] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - 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) - } +impl Ashl for u64 {} +impl Ashl for u128 {} + +trait Ashr: Int + LargeInt { + /// Returns arithmetic `a >> b`, requires `b < $ty::bits()` + fn ashr(self, offset: u32) -> Self + where Self: LargeInt::HighHalf as Int>::UnsignedInt>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts((self.high() >> (offset - half_bits)).unsigned(), + self.high() >> (half_bits - 1)) + } else if offset == 0 { + self + } else { + let high_unsigned = self.high().unsigned(); + Self::from_parts((high_unsigned << (half_bits - offset)) | (self.low() >> offset), + self.high() >> offset) } } } -macro_rules! lshr { - ($intrinsic:ident: $ty:ty) => { - /// Returns logical `a >> b`, requires `b < $ty::bits()` - #[cfg_attr(not(test), no_mangle)] - pub extern "C" fn $intrinsic(a: $ty, b: u32) -> $ty { - 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) - } +impl Ashr for i64 {} +impl Ashr for i128 {} + +trait Lshr: Int + LargeInt { + /// Returns logical `a >> b`, requires `b < $ty::bits()` + fn lshr(self, offset: u32) -> Self + where Self: LargeInt::LowHalf>, + { + let half_bits = Self::bits() / 2; + if offset & half_bits != 0 { + Self::from_parts(self.high() >> (offset - half_bits), Int::zero()) + } else if offset == 0 { + self + } else { + Self::from_parts((self.high() << (half_bits - offset)) | + (self.low() >> offset), + self.high() >> offset) } } } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -ashl!(__ashldi3: u64); +impl Lshr for u64 {} +impl Lshr for u128 {} -ashl!(__ashlti3: u128); +intrinsics! { + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __ashldi3(a: u64, b: u32) -> u64 { + a.ashl(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -ashr!(__ashrdi3: i64); + pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 { + a.ashl(b) + } -ashr!(__ashrti3: i128); + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 { + a.ashr(b) + } -#[cfg(not(all(feature = "c", target_arch = "x86")))] -lshr!(__lshrdi3: u64); + pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 { + a.ashr(b) + } -lshr!(__lshrti3: u128); + #[cfg(not(all(feature = "c", target_arch = "x86")))] + pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 { + a.lshr(b) + } + + pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 { + a.lshr(b) + } +} diff --git a/src/lib.rs b/src/lib.rs index 03f7258..b1e739f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,6 +99,9 @@ fn sconv(i: i128) -> U64x2 { #[cfg(test)] extern crate core; +#[macro_use] +mod macros; + pub mod int; pub mod float; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..a5a535b --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,51 @@ +macro_rules! intrinsics { + () => (); + ( + #[cfg(not(all(feature = "c", $($cfg_clause:tt)*)))] + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + + #[cfg(all(feature = "c", not($($cfg_clause)*)))] + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + extern $abi { + fn $name($($argname: $ty),*) -> $ret; + } + unsafe { + $name($($argname),*) + } + } + + #[cfg(not(all(feature = "c", not($($cfg_clause)*))))] + intrinsics! { + $(#[$attr])* + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + } + + intrinsics!($($rest)*); + ); + + ( + $(#[$attr:meta])* + pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty { + $($body:tt)* + } + + $($rest:tt)* + ) => ( + $(#[$attr])* + #[cfg_attr(not(test), no_mangle)] + pub extern $abi fn $name( $($argname: $ty),* ) -> $ret { + $($body)* + } + + intrinsics!($($rest)*); + ); +}