compiler_builtins/int/
shift.rs

1use crate::int::{DInt, HInt, Int, MinInt};
2
3trait Ashl: DInt {
4    /// Returns `a << b`, requires `b < Self::BITS`
5    fn ashl(self, shl: u32) -> Self {
6        let n_h = Self::H::BITS;
7        if shl & n_h != 0 {
8            // we only need `self.lo()` because `self.hi()` will be shifted out entirely
9            self.lo().wrapping_shl(shl - n_h).widen_hi()
10        } else if shl == 0 {
11            self
12        } else {
13            Self::from_lo_hi(
14                self.lo().wrapping_shl(shl),
15                self.lo().logical_shr(n_h.wrapping_sub(shl)) | self.hi().wrapping_shl(shl),
16            )
17        }
18    }
19}
20
21impl Ashl for u32 {}
22impl Ashl for u64 {}
23impl Ashl for u128 {}
24
25trait Ashr: DInt {
26    /// Returns arithmetic `a >> b`, requires `b < Self::BITS`
27    fn ashr(self, shr: u32) -> Self {
28        let n_h = Self::H::BITS;
29        if shr & n_h != 0 {
30            Self::from_lo_hi(
31                self.hi().wrapping_shr(shr - n_h),
32                // smear the sign bit
33                self.hi().wrapping_shr(n_h - 1),
34            )
35        } else if shr == 0 {
36            self
37        } else {
38            Self::from_lo_hi(
39                self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)),
40                self.hi().wrapping_shr(shr),
41            )
42        }
43    }
44}
45
46impl Ashr for i32 {}
47impl Ashr for i64 {}
48impl Ashr for i128 {}
49
50trait Lshr: DInt {
51    /// Returns logical `a >> b`, requires `b < Self::BITS`
52    fn lshr(self, shr: u32) -> Self {
53        let n_h = Self::H::BITS;
54        if shr & n_h != 0 {
55            self.hi().logical_shr(shr - n_h).zero_widen()
56        } else if shr == 0 {
57            self
58        } else {
59            Self::from_lo_hi(
60                self.lo().logical_shr(shr) | self.hi().wrapping_shl(n_h.wrapping_sub(shr)),
61                self.hi().logical_shr(shr),
62            )
63        }
64    }
65}
66
67impl Lshr for u32 {}
68impl Lshr for u64 {}
69impl Lshr for u128 {}
70
71intrinsics! {
72    #[maybe_use_optimized_c_shim]
73    pub extern "C" fn __ashlsi3(a: u32, b: u32) -> u32 {
74        a.ashl(b)
75    }
76
77    #[maybe_use_optimized_c_shim]
78    #[arm_aeabi_alias = __aeabi_llsl]
79    pub extern "C" fn __ashldi3(a: u64, b: core::ffi::c_uint) -> u64 {
80        a.ashl(b as u32)
81    }
82
83    pub extern "C" fn __ashlti3(a: u128, b: u32) -> u128 {
84        a.ashl(b)
85    }
86
87    #[maybe_use_optimized_c_shim]
88    pub extern "C" fn __ashrsi3(a: i32, b: u32) -> i32 {
89        a.ashr(b)
90    }
91
92    #[maybe_use_optimized_c_shim]
93    #[arm_aeabi_alias = __aeabi_lasr]
94    pub extern "C" fn __ashrdi3(a: i64, b: core::ffi::c_uint) -> i64 {
95        a.ashr(b as u32)
96    }
97
98    pub extern "C" fn __ashrti3(a: i128, b: u32) -> i128 {
99        a.ashr(b)
100    }
101
102    #[maybe_use_optimized_c_shim]
103    pub extern "C" fn __lshrsi3(a: u32, b: u32) -> u32 {
104        a.lshr(b)
105    }
106
107    #[maybe_use_optimized_c_shim]
108    #[arm_aeabi_alias = __aeabi_llsr]
109    pub extern "C" fn __lshrdi3(a: u64, b: core::ffi::c_uint) -> u64 {
110        a.lshr(b as u32)
111    }
112
113    pub extern "C" fn __lshrti3(a: u128, b: u32) -> u128 {
114        a.lshr(b)
115    }
116}