1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! bextr

/// Bit field extract
pub trait Bextr {
    /// Bit field extract.
    ///
    /// Extracts bits in range `[start, start + length)` from the `source` to
    /// the least significant bits of the result.
    ///
    /// Bits `[7,0]` of `range` specify the index to the first bit in the
    /// range to be extracted, and bits `[15,8]` specify the length of the
    /// range.
    ///
    /// Only bits up to `size_of::<T>()*8 - 1` are extracted.
    ///
    /// The extracted bits are written in the result starting from the
    /// least-significant bit. The high-order bits of the result are zeroed.
    ///
    /// # Instructions
    ///
    /// - [`BEXTR`](http://www.felixcloutier.com/x86/BEXTR.html):
    ///   - Description: Bit field extract.
    ///   - Architecture: x86.
    ///   - Instruction set: BMI.
    ///   - Registers: 32/64 bit.
    ///
    /// # Example
    ///
    /// ```
    /// # use bitintr::*;
    /// assert_eq!(0b0101_0000u8.bextr(4, 4), 0b0000_0101u8);
    /// ```
    fn bextr(self, start: Self, length: Self) -> Self;

    /// Bit Field Extract (with immediate operand).
    ///
    /// Extracts bits in `range` from the `source` to the least significant
    /// bits of the result. Bits `[7,0]` of `range` specify the index to
    /// the first bit in the range to be extracted, and bits `[15,8]`
    /// specify the length of the range.
    ///
    /// Only bits up to `size_of::<T>()*8 - 1` are extracted.
    ///
    /// The extracted bits are written in the result starting from the
    /// least-significant bit. The high-order bits of the result are zeroed.
    ///
    /// # Instructions
    ///
    /// - [`BEXTR`](https://support.amd.com/TechDocs/24594.pdf):
    ///   - Description: Bit field extract (with immediate).
    ///   - Architecture: x86.
    ///   - Instruction set: TBM.
    ///   - Registers: 32/64 bit.
    ///
    /// # Example
    ///
    /// ```
    /// # use bitintr::*;
    /// assert_eq!(
    ///     0b0000_0000_0101_0000_u16.bextri(0b0100_0000_0100_u32),
    ///     0b0000_0000_0000_0101_u16
    /// );
    /// ```
    fn bextri(self, range: u32) -> Self;
}

macro_rules! bextr_impl {
    ($ty:ty) => {
        #[inline]
        fn bextr_(value: $ty, start: $ty, length: $ty) -> $ty {
            (value >> start) & ((1 << length) - 1)
        }
    };
    ($ty:ty, $intr:ident) => {
        cfg_if! {
            if  #[cfg(all(
                  any(target_arch = "x86", target_arch = "x86_64"),
                  target_feature = "bmi2"
            ))] {
                #[inline]
                #[target_feature(enable = "bmi2")]
                unsafe fn bextr_(value: $ty, start: $ty, length: $ty) -> $ty {
                    crate::arch::$intr(
                        value as _,
                        start as u32,
                        length as u32,
                    ) as _
                }
            } else {
                bextr_impl!($ty);
            }
        }
    };
}

macro_rules! impl_bextr {
    ($id:ident $(,$args:ident)*) => {
        impl Bextr for $id {
            #[inline]
            #[allow(unused_unsafe)]
            fn bextr(self, start: Self, length: Self) -> Self {
                bextr_impl!($id $(,$args)*);
                // UNSAFETY: this is always safe, because
                // the unsafe `#[target_feature]` function
                // is only generated when the feature is
                // statically-enabled at compile-time.
                unsafe { bextr_(self, start, length) }
            }
            #[inline]
            fn bextri(self, range: u32) -> Self {
                self.bextr((range & 0xff) as Self, (range >> 8) as Self)
            }

        }
    };
}

impl_all!(impl_bextr: u8, u16, i8, i16);

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        impl_bextr!(u32, _bextr_u32);
        impl_bextr!(i32, _bextr_u32);
        cfg_if! {
            if #[cfg(target_arch = "x86_64")] {
                impl_bextr!(u64, _bextr_u64);
                impl_bextr!(i64, _bextr_u64);
            } else {
                impl_all!(impl_bextr: i64, u64);
            }
        }
    } else {
        impl_all!(impl_bextr: u32, i32, i64, u64);
    }
}