33// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`.
44// Compilers will insert the check for zero in cases where it is needed.
55
6+ use crate :: int:: { CastInto , Int } ;
7+
68public_test_dep ! {
79/// Returns the number of leading binary zeros in `x`.
810 #[ allow( dead_code) ]
9- pub ( crate ) fn usize_leading_zeros_default ( x: usize ) -> usize {
11+ pub ( crate ) fn leading_zeros_default< T : Int + CastInto < usize >> ( x: T ) -> usize {
1012 // The basic idea is to test if the higher bits of `x` are zero and bisect the number
1113 // of leading zeros. It is possible for all branches of the bisection to use the same
1214 // code path by conditionally shifting the higher parts down to let the next bisection
@@ -16,46 +18,47 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize {
1618 // because it simplifies the final bisection step.
1719 let mut x = x;
1820 // the number of potential leading zeros
19- let mut z = usize :: MAX . count_ones ( ) as usize ;
21+ let mut z = T :: BITS as usize ;
2022 // a temporary
21- let mut t: usize ;
22- #[ cfg( target_pointer_width = "64" ) ]
23- {
23+ let mut t: T ;
24+
25+ const { assert!( T :: BITS <= 64 ) } ;
26+ if T :: BITS >= 64 {
2427 t = x >> 32 ;
25- if t != 0 {
28+ if t != T :: ZERO {
2629 z -= 32 ;
2730 x = t;
2831 }
2932 }
30- #[ cfg( any( target_pointer_width = "32" , target_pointer_width = "64" ) ) ]
31- {
33+ if T :: BITS >= 32 {
3234 t = x >> 16 ;
33- if t != 0 {
35+ if t != T :: ZERO {
3436 z -= 16 ;
3537 x = t;
3638 }
3739 }
40+ const { assert!( T :: BITS >= 16 ) } ;
3841 t = x >> 8 ;
39- if t != 0 {
42+ if t != T :: ZERO {
4043 z -= 8 ;
4144 x = t;
4245 }
4346 t = x >> 4 ;
44- if t != 0 {
47+ if t != T :: ZERO {
4548 z -= 4 ;
4649 x = t;
4750 }
4851 t = x >> 2 ;
49- if t != 0 {
52+ if t != T :: ZERO {
5053 z -= 2 ;
5154 x = t;
5255 }
5356 // the last two bisections are combined into one conditional
5457 t = x >> 1 ;
55- if t != 0 {
58+ if t != T :: ZERO {
5659 z - 2
5760 } else {
58- z - x
61+ z - x. cast ( )
5962 }
6063
6164 // We could potentially save a few cycles by using the LUT trick from
@@ -80,12 +83,12 @@ pub(crate) fn usize_leading_zeros_default(x: usize) -> usize {
8083public_test_dep ! {
8184/// Returns the number of leading binary zeros in `x`.
8285 #[ allow( dead_code) ]
83- pub ( crate ) fn usize_leading_zeros_riscv ( x: usize ) -> usize {
86+ pub ( crate ) fn leading_zeros_riscv< T : Int + CastInto < usize >> ( x: T ) -> usize {
8487 let mut x = x;
8588 // the number of potential leading zeros
86- let mut z = usize :: MAX . count_ones ( ) as usize ;
89+ let mut z = T :: BITS ;
8790 // a temporary
88- let mut t: usize ;
91+ let mut t: u32 ;
8992
9093 // RISC-V does not have a set-if-greater-than-or-equal instruction and
9194 // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is
@@ -95,55 +98,68 @@ pub(crate) fn usize_leading_zeros_riscv(x: usize) -> usize {
9598 // right). If we try to save an instruction by using `x < imm` for each bisection, we
9699 // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`,
97100 // but the immediate will never fit into 12 bits and never save an instruction.
98- # [ cfg ( target_pointer_width = "64" ) ]
99- {
101+ const { assert! ( T :: BITS <= 64 ) } ;
102+ if T :: BITS >= 64 {
100103 // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise
101104 // `t` is set to 0.
102- t = ( ( x >= ( 1 << 32 ) ) as usize ) << 5 ;
105+ t = ( ( x >= ( T :: ONE << 32 ) ) as u32 ) << 5 ;
103106 // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the
104107 // next step to process.
105108 x >>= t;
106109 // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential
107110 // leading zeros
108111 z -= t;
109112 }
110- #[ cfg( any( target_pointer_width = "32" , target_pointer_width = "64" ) ) ]
111- {
112- t = ( ( x >= ( 1 << 16 ) ) as usize ) << 4 ;
113+ if T :: BITS >= 32 {
114+ t = ( ( x >= ( T :: ONE << 16 ) ) as u32 ) << 4 ;
113115 x >>= t;
114116 z -= t;
115117 }
116- t = ( ( x >= ( 1 << 8 ) ) as usize ) << 3 ;
118+ const { assert!( T :: BITS >= 16 ) } ;
119+ t = ( ( x >= ( T :: ONE << 8 ) ) as u32 ) << 3 ;
117120 x >>= t;
118121 z -= t;
119- t = ( ( x >= ( 1 << 4 ) ) as usize ) << 2 ;
122+ t = ( ( x >= ( T :: ONE << 4 ) ) as u32 ) << 2 ;
120123 x >>= t;
121124 z -= t;
122- t = ( ( x >= ( 1 << 2 ) ) as usize ) << 1 ;
125+ t = ( ( x >= ( T :: ONE << 2 ) ) as u32 ) << 1 ;
123126 x >>= t;
124127 z -= t;
125- t = ( x >= ( 1 << 1 ) ) as usize ;
128+ t = ( x >= ( T :: ONE << 1 ) ) as u32 ;
126129 x >>= t;
127130 z -= t;
128131 // All bits except the LSB are guaranteed to be zero for this final bisection step.
129132 // If `x != 0` then `x == 1` and subtracts one potential zero from `z`.
130- z - x
133+ z as usize - x. cast ( )
131134}
132135}
133136
134137intrinsics ! {
135- #[ maybe_use_optimized_c_shim]
136- #[ cfg( any(
137- target_pointer_width = "16" ,
138- target_pointer_width = "32" ,
139- target_pointer_width = "64"
140- ) ) ]
141- /// Returns the number of leading binary zeros in `x`.
142- pub extern "C" fn __clzsi2( x: usize ) -> usize {
138+ /// Returns the number of leading binary zeros in `x`
139+ pub extern "C" fn __clzsi2( x: u32 ) -> usize {
143140 if cfg!( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) {
144- usize_leading_zeros_riscv( x)
141+ leading_zeros_riscv( x)
142+ } else {
143+ leading_zeros_default( x)
144+ }
145+ }
146+
147+ /// Returns the number of leading binary zeros in `x`
148+ pub extern "C" fn __clzdi2( x: u64 ) -> usize {
149+ if cfg!( any( target_arch = "riscv32" , target_arch = "riscv64" ) ) {
150+ leading_zeros_riscv( x)
151+ } else {
152+ leading_zeros_default( x)
153+ }
154+ }
155+
156+ /// Returns the number of leading binary zeros in `x`
157+ pub extern "C" fn __clzti2( x: u128 ) -> usize {
158+ let hi = ( x >> 64 ) as u64 ;
159+ if hi == 0 {
160+ 64 + __clzdi2( x as u64 )
145161 } else {
146- usize_leading_zeros_default ( x )
162+ __clzdi2 ( hi )
147163 }
148164 }
149165}
0 commit comments