Selaa lähdekoodia

Use traits instead of macros for shift intrinsics

This is an attempt to tidy up the definition of intrinsics by making them more
rust-like at the definition site and using traits instead of macros for the
definition. Additionally the helper macro, `intrinsics!`, now fills in a
definition for #[cfg]'d off intrinsics when compiling with C code
Alex Crichton 7 vuotta sitten
vanhempi
commit
2f2bb32e40
4 muutettua tiedostoa jossa 166 lisäystä ja 61 poistoa
  1. 37 6
      src/int/mod.rs
  2. 75 55
      src/int/shift.rs
  3. 3 0
      src/lib.rs
  4. 51 0
      src/macros.rs

+ 37 - 6
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<u32, Output = Self> +
+    ops::Shr<u32, Output = Self> +
+    ops::BitOr<Output = Self> +
+    // ops::BitAnd<Output = Self> +
+{
     /// 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;

+ 75 - 55
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<HighHalf = <Self as 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<LowHalf = <<Self as 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<HighHalf = <Self as 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)
+    }
+
+    pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 {
+        a.ashl(b)
+    }
 
-#[cfg(not(all(feature = "c", target_arch = "x86")))]
-ashr!(__ashrdi3: i64);
+    #[cfg(not(all(feature = "c", target_arch = "x86")))]
+    pub extern "C" fn __ashrdi3(a: i64, b: u32) -> i64 {
+        a.ashr(b)
+    }
 
-ashr!(__ashrti3: i128);
+    pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 {
+        a.ashr(b)
+    }
 
-#[cfg(not(all(feature = "c", target_arch = "x86")))]
-lshr!(__lshrdi3: u64);
+    #[cfg(not(all(feature = "c", target_arch = "x86")))]
+    pub extern "C" fn __lshrdi3(a: u64, b: u32) -> u64 {
+        a.lshr(b)
+    }
 
-lshr!(__lshrti3: u128);
+    pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 {
+        a.lshr(b)
+    }
+}

+ 3 - 0
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;
 

+ 51 - 0
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)*);
+    );
+}