Skip to main content

core/intrinsics/
fallback.rs

1#![unstable(
2    feature = "core_intrinsics_fallbacks",
3    reason = "The fallbacks will never be stable, as they exist only to be called \
4              by the fallback MIR, but they're exported so they can be tested on \
5              platforms where the fallback MIR isn't actually used",
6    issue = "none"
7)]
8#![allow(missing_docs)]
9
10#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
11pub const trait CarryingMulAdd: Copy + 'static {
12    type Unsigned: Copy + 'static;
13    fn carrying_mul_add(
14        self,
15        multiplicand: Self,
16        addend: Self,
17        carry: Self,
18    ) -> (Self::Unsigned, Self);
19}
20
21macro_rules! impl_carrying_mul_add_by_widening {
22    ($($t:ident $u:ident $w:ident,)+) => {$(
23        #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
24        const impl CarryingMulAdd for $t {
25            type Unsigned = $u;
26            #[inline]
27            fn carrying_mul_add(self, a: Self, b: Self, c: Self) -> ($u, $t) {
28                let wide = (self as $w) * (a as $w) + (b as $w) + (c as $w);
29                (wide as _, (wide >> Self::BITS) as _)
30            }
31        }
32    )+};
33}
34impl_carrying_mul_add_by_widening! {
35    u8 u8 u16,
36    u16 u16 u32,
37    u32 u32 u64,
38    u64 u64 u128,
39    usize usize UDoubleSize,
40    i8 u8 i16,
41    i16 u16 i32,
42    i32 u32 i64,
43    i64 u64 i128,
44    isize usize UDoubleSize,
45}
46
47#[cfg(target_pointer_width = "16")]
48type UDoubleSize = u32;
49#[cfg(target_pointer_width = "32")]
50type UDoubleSize = u64;
51#[cfg(target_pointer_width = "64")]
52type UDoubleSize = u128;
53
54#[inline]
55const fn wide_mul_u128(a: u128, b: u128) -> (u128, u128) {
56    #[inline]
57    const fn to_low_high(x: u128) -> [u128; 2] {
58        const MASK: u128 = u64::MAX as _;
59        [x & MASK, x >> 64]
60    }
61    #[inline]
62    const fn from_low_high(x: [u128; 2]) -> u128 {
63        x[0] | (x[1] << 64)
64    }
65    #[inline]
66    const fn scalar_mul(low_high: [u128; 2], k: u128) -> [u128; 3] {
67        let [x, c] = to_low_high(k * low_high[0]);
68        let [y, z] = to_low_high(k * low_high[1] + c);
69        [x, y, z]
70    }
71    let a = to_low_high(a);
72    let b = to_low_high(b);
73    let low = scalar_mul(a, b[0]);
74    let high = scalar_mul(a, b[1]);
75    let r0 = low[0];
76    let [r1, c] = to_low_high(low[1] + high[0]);
77    let [r2, c] = to_low_high(low[2] + high[1] + c);
78    let r3 = high[2] + c;
79    (from_low_high([r0, r1]), from_low_high([r2, r3]))
80}
81
82#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
83const impl CarryingMulAdd for u128 {
84    type Unsigned = u128;
85    #[inline]
86    fn carrying_mul_add(self, b: u128, c: u128, d: u128) -> (u128, u128) {
87        let (low, mut high) = wide_mul_u128(self, b);
88        let (low, carry) = u128::overflowing_add(low, c);
89        high += carry as u128;
90        let (low, carry) = u128::overflowing_add(low, d);
91        high += carry as u128;
92        (low, high)
93    }
94}
95
96#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
97const impl CarryingMulAdd for i128 {
98    type Unsigned = u128;
99    #[inline]
100    fn carrying_mul_add(self, b: i128, c: i128, d: i128) -> (u128, i128) {
101        let (low, high) = wide_mul_u128(self as u128, b as u128);
102        let mut high = high as i128;
103        high = high.wrapping_add(i128::wrapping_mul(self >> 127, b));
104        high = high.wrapping_add(i128::wrapping_mul(self, b >> 127));
105        let (low, carry) = u128::overflowing_add(low, c as u128);
106        high = high.wrapping_add((carry as i128) + (c >> 127));
107        let (low, carry) = u128::overflowing_add(low, d as u128);
108        high = high.wrapping_add((carry as i128) + (d >> 127));
109        (low, high)
110    }
111}
112
113#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
114pub const trait DisjointBitOr: Copy + 'static {
115    /// We just need the trait indirection to handle different types
116    /// since calling intrinsics with generics doesn't work.
117    ///
118    /// # Safety
119    ///
120    /// See [`super::disjoint_bitor`], with `self` corresponding to `a` and
121    /// `other` corresponding to `b`.
122    unsafe fn disjoint_bitor(self, other: Self) -> Self;
123}
124macro_rules! zero {
125    (bool) => {
126        false
127    };
128    ($t:ident) => {
129        0
130    };
131}
132macro_rules! impl_disjoint_bitor {
133    ($($t:ident,)+) => {$(
134        #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
135        const impl DisjointBitOr for $t {
136            #[cfg_attr(miri, track_caller)]
137            #[inline]
138            unsafe fn disjoint_bitor(self, other: Self) -> Self {
139                // Note that the assume here is required for UB detection in Miri!
140
141                // SAFETY: our precondition is that there are no bits in common,
142                // so this is just telling that to the backend.
143                unsafe { super::assume((self & other) == zero!($t)) };
144                self | other
145            }
146        }
147    )+};
148}
149impl_disjoint_bitor! {
150    bool,
151    u8, u16, u32, u64, u128, usize,
152    i8, i16, i32, i64, i128, isize,
153}
154
155#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
156pub const trait FunnelShift: Copy + 'static {
157    /// We just need the trait indirection to handle different types
158    /// since calling intrinsics with generics doesn't work.
159    ///
160    /// # Safety
161    ///
162    /// See [`super::unchecked_funnel_shl`], with `self` corresponding to `a` and
163    /// `right` corresponding to `b`.
164    unsafe fn unchecked_funnel_shl(self, right: Self, shift: u32) -> Self;
165
166    /// We just need the trait indirection to handle different types
167    /// since calling intrinsics with generics doesn't work.
168    ///
169    /// # Safety
170    ///
171    /// See [`super::unchecked_funnel_shr`], with `self` corresponding to `a` and
172    /// `right` corresponding to `b`.
173    unsafe fn unchecked_funnel_shr(self, right: Self, shift: u32) -> Self;
174}
175
176macro_rules! impl_funnel_shifts {
177    ($($type:ident),*) => {$(
178        #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
179        const impl FunnelShift for $type {
180            #[cfg_attr(miri, track_caller)]
181            #[inline]
182            unsafe fn unchecked_funnel_shl(self, right: Self, shift: u32) -> Self {
183                // This implementation is also used by Miri so we have to check the precondition.
184                // SAFETY: this is guaranteed by the caller
185                unsafe { super::assume(shift < $type::BITS) };
186                if shift == 0 {
187                    self
188                } else {
189                    // SAFETY:
190                    //  - `shift < T::BITS`, which satisfies `unchecked_shl`
191                    //  - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
192                    //    above), which satisfies `unchecked_shr`
193                    //  - because the types are unsigned, the combination are disjoint bits (this is
194                    //    not true if they're signed, since SHR will fill in the empty space with a
195                    //    sign bit, not zero)
196                    unsafe {
197                        super::disjoint_bitor(
198                            super::unchecked_shl(self, shift),
199                            super::unchecked_shr(right, $type::BITS - shift),
200                        )
201                    }
202                }
203            }
204
205            #[cfg_attr(miri, track_caller)]
206            #[inline]
207            unsafe fn unchecked_funnel_shr(self, right: Self, shift: u32) -> Self {
208                // This implementation is also used by Miri so we have to check the precondition.
209                // SAFETY: this is guaranteed by the caller
210                unsafe { super::assume(shift < $type::BITS) };
211                if shift == 0 {
212                    right
213                } else {
214                    // SAFETY:
215                    //  - `shift < T::BITS`, which satisfies `unchecked_shr`
216                    //  - this also ensures that `T::BITS - shift < T::BITS` (shift = 0 is checked
217                    //    above), which satisfies `unchecked_shl`
218                    //  - because the types are unsigned, the combination are disjoint bits (this is
219                    //    not true if they're signed, since SHR will fill in the empty space with a
220                    //    sign bit, not zero)
221                    unsafe {
222                        super::disjoint_bitor(
223                            super::unchecked_shl(self, $type::BITS - shift),
224                            super::unchecked_shr(right, shift),
225                        )
226                    }
227                }
228            }
229        }
230    )*};
231}
232
233impl_funnel_shifts! {
234    u8, u16, u32, u64, u128, usize
235}
236
237#[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
238pub const trait CarrylessMul: Copy + 'static {
239    /// See [`super::carryless_mul`]; we just need the trait indirection to handle
240    /// different types since calling intrinsics with generics doesn't work.
241    fn carryless_mul(self, rhs: Self) -> Self;
242}
243
244macro_rules! impl_carryless_mul{
245    ($($type:ident),*) => {$(
246        #[rustc_const_unstable(feature = "core_intrinsics_fallbacks", issue = "none")]
247        const impl CarrylessMul for $type {
248            #[inline]
249            fn carryless_mul(self, rhs: Self) -> Self {
250                let mut result = 0;
251                let mut i = 0;
252
253                while i < $type::BITS {
254                    // If the i-th bit in rhs is set.
255                    if (rhs >> i) & 1 != 0 {
256                        // Then xor the result with `self` shifted to the left by i positions.
257                        result ^= self << i;
258                    }
259                    i += 1;
260                }
261
262                result
263            }
264        }
265    )*};
266}
267
268impl_carryless_mul! {
269    u8, u16, u32, u64, u128, usize
270}