about summary refs log tree commit diff
path: root/library/compiler-builtins/src/int/trailing_zeros.rs
blob: dbc0cce9facc9479e84c7a18ecfae220c500dacf (plain)
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
#[cfg(feature = "public-test-deps")]
pub use implementation::trailing_zeros;
#[cfg(not(feature = "public-test-deps"))]
pub(crate) use implementation::trailing_zeros;

mod implementation {
    use crate::int::{CastInto, Int};

    /// Returns number of trailing binary zeros in `x`.
    #[allow(dead_code)]
    pub fn trailing_zeros<T: Int + CastInto<u32> + CastInto<u16> + CastInto<u8>>(x: T) -> usize {
        let mut x = x;
        let mut r: u32 = 0;
        let mut t: u32;

        const { assert!(T::BITS <= 64) };
        if T::BITS >= 64 {
            r += ((CastInto::<u32>::cast(x) == 0) as u32) << 5; // if (x has no 32 small bits) t = 32 else 0
            x >>= r; // remove 32 zero bits
        }

        if T::BITS >= 32 {
            t = ((CastInto::<u16>::cast(x) == 0) as u32) << 4; // if (x has no 16 small bits) t = 16 else 0
            r += t;
            x >>= t; // x = [0 - 0xFFFF] + higher garbage bits
        }

        const { assert!(T::BITS >= 16) };
        t = ((CastInto::<u8>::cast(x) == 0) as u32) << 3;
        x >>= t; // x = [0 - 0xFF] + higher garbage bits
        r += t;

        let mut x: u8 = x.cast();

        t = (((x & 0x0F) == 0) as u32) << 2;
        x >>= t; // x = [0 - 0xF] + higher garbage bits
        r += t;

        t = (((x & 0x3) == 0) as u32) << 1;
        x >>= t; // x = [0 - 0x3] + higher garbage bits
        r += t;

        x &= 3;

        r as usize + ((2 - (x >> 1) as usize) & (((x & 1) == 0) as usize).wrapping_neg())
    }
}

intrinsics! {
    /// Returns the number of trailing binary zeros in `x` (32 bit version).
    pub extern "C" fn __ctzsi2(x: u32) -> usize {
        trailing_zeros(x)
    }

    /// Returns the number of trailing binary zeros in `x` (64 bit version).
    pub extern "C" fn __ctzdi2(x: u64) -> usize {
        trailing_zeros(x)
    }

    /// Returns the number of trailing binary zeros in `x` (128 bit version).
    pub extern "C" fn __ctzti2(x: u128) -> usize {
        let lo = x as u64;
        if lo == 0 {
            64 + __ctzdi2((x >> 64) as u64)
        } else {
            __ctzdi2(lo)
        }
    }
}