5
5
6
6
use crate :: sync:: atomic:: Ordering ;
7
7
8
- #[ cfg( target_pointer_width = "64" ) ]
9
- use crate :: sync:: atomic:: AtomicU64 ;
10
-
11
- #[ cfg( target_pointer_width = "32" ) ]
12
- use crate :: sync:: atomic:: AtomicU32 ;
8
+ use crate :: sync:: atomic:: AtomicUsize ;
13
9
14
10
/// Sets the `bit` of `x`.
15
11
#[ inline]
@@ -30,7 +26,7 @@ const fn unset_bit(x: u64, bit: u32) -> u64 {
30
26
}
31
27
32
28
/// Maximum number of features that can be cached.
33
- const CACHE_CAPACITY : u32 = 63 ;
29
+ const CACHE_CAPACITY : u32 = 62 ;
34
30
35
31
/// This type is used to initialize the cache
36
32
#[ derive( Copy , Clone ) ]
@@ -81,83 +77,44 @@ impl Initializer {
81
77
}
82
78
83
79
/// This global variable is a cache of the features supported by the CPU.
80
+ #[ cfg( target_pointer_width = "64" ) ]
84
81
static CACHE : Cache = Cache :: uninitialized ( ) ;
85
82
86
- /// Feature cache with capacity for `CACHE_CAPACITY` features.
83
+ /// This global variable is a cache of the features supported by the CPU.
84
+ #[ cfg( target_pointer_width = "32" ) ]
85
+ static CACHE : [ Cache ; 2 ] = [ Cache :: uninitialized ( ) , Cache :: uninitialized ( ) ] ;
86
+
87
+ /// Feature cache with capacity for `usize::max_value() - 1` features.
87
88
///
88
89
/// Note: the last feature bit is used to represent an
89
90
/// uninitialized cache.
90
- #[ cfg( target_pointer_width = "64" ) ]
91
- struct Cache ( AtomicU64 ) ;
91
+ struct Cache ( AtomicUsize ) ;
92
92
93
- #[ cfg( target_pointer_width = "64" ) ]
94
- #[ allow( clippy:: use_self) ]
95
93
impl Cache {
96
94
/// Creates an uninitialized cache.
97
95
#[ allow( clippy:: declare_interior_mutable_const) ]
98
96
const fn uninitialized ( ) -> Self {
99
- Cache ( AtomicU64 :: new ( u64 :: max_value ( ) ) )
97
+ Cache ( AtomicUsize :: new ( usize :: max_value ( ) ) )
100
98
}
101
99
/// Is the cache uninitialized?
102
100
#[ inline]
103
101
pub ( crate ) fn is_uninitialized ( & self ) -> bool {
104
- self . 0 . load ( Ordering :: Relaxed ) == u64 :: max_value ( )
102
+ self . 0 . load ( Ordering :: Relaxed ) == usize :: max_value ( )
105
103
}
106
104
107
105
/// Is the `bit` in the cache set?
108
106
#[ inline]
109
107
pub ( crate ) fn test ( & self , bit : u32 ) -> bool {
110
- test_bit ( CACHE . 0 . load ( Ordering :: Relaxed ) , bit)
108
+ test_bit ( self . 0 . load ( Ordering :: Relaxed ) as u64 , bit)
111
109
}
112
110
113
111
/// Initializes the cache.
114
112
#[ inline]
115
- pub ( crate ) fn initialize ( & self , value : Initializer ) {
116
- self . 0 . store ( value. 0 , Ordering :: Relaxed ) ;
113
+ fn initialize ( & self , value : usize ) {
114
+ self . 0 . store ( value, Ordering :: Relaxed ) ;
117
115
}
118
116
}
119
117
120
- /// Feature cache with capacity for `CACHE_CAPACITY` features.
121
- ///
122
- /// Note: the last feature bit is used to represent an
123
- /// uninitialized cache.
124
- #[ cfg( target_pointer_width = "32" ) ]
125
- struct Cache ( AtomicU32 , AtomicU32 ) ;
126
-
127
- #[ cfg( target_pointer_width = "32" ) ]
128
- impl Cache {
129
- /// Creates an uninitialized cache.
130
- const fn uninitialized ( ) -> Self {
131
- Cache (
132
- AtomicU32 :: new ( u32:: max_value ( ) ) ,
133
- AtomicU32 :: new ( u32:: max_value ( ) ) ,
134
- )
135
- }
136
- /// Is the cache uninitialized?
137
- #[ inline]
138
- pub ( crate ) fn is_uninitialized ( & self ) -> bool {
139
- self . 1 . load ( Ordering :: Relaxed ) == u32:: max_value ( )
140
- }
141
-
142
- /// Is the `bit` in the cache set?
143
- #[ inline]
144
- pub ( crate ) fn test ( & self , bit : u32 ) -> bool {
145
- if bit < 32 {
146
- test_bit ( CACHE . 0 . load ( Ordering :: Relaxed ) as u64 , bit)
147
- } else {
148
- test_bit ( CACHE . 1 . load ( Ordering :: Relaxed ) as u64 , bit - 32 )
149
- }
150
- }
151
-
152
- /// Initializes the cache.
153
- #[ inline]
154
- pub ( crate ) fn initialize ( & self , value : Initializer ) {
155
- let lo: u32 = value. 0 as u32 ;
156
- let hi: u32 = ( value. 0 >> 32 ) as u32 ;
157
- self . 0 . store ( lo, Ordering :: Relaxed ) ;
158
- self . 1 . store ( hi, Ordering :: Relaxed ) ;
159
- }
160
- }
161
118
cfg_if:: cfg_if! {
162
119
if #[ cfg( feature = "std_detect_env_override" ) ] {
163
120
#[ inline( never) ]
@@ -167,12 +124,27 @@ cfg_if::cfg_if! {
167
124
let _ = super :: Feature :: from_str( v) . map( |v| value. unset( v as u32 ) ) ;
168
125
}
169
126
}
170
- CACHE . initialize ( value) ;
127
+ do_initialize ( value) ;
171
128
}
172
129
} else {
173
130
#[ inline]
174
131
fn initialize( value: Initializer ) {
175
- CACHE . initialize( value) ;
132
+ do_initialize( value) ;
133
+ }
134
+ }
135
+ }
136
+
137
+ #[ inline]
138
+ fn do_initialize ( value : Initializer ) {
139
+ cfg_if:: cfg_if! {
140
+ if #[ cfg( target_pointer_width = "64" ) ] {
141
+ CACHE . initialize( value. 0 as usize )
142
+ } else if #[ cfg( target_pointer_width = "32" ) ] {
143
+ const LOW_31_BIT : usize = 0x7FFF_FFFF ;
144
+ CACHE [ 0 ] . initialize( ( value. 0 ) as usize & LOW_31_BIT ) ;
145
+ CACHE [ 1 ] . initialize( ( value. 0 >> 31 ) as usize & LOW_31_BIT ) ;
146
+ } else {
147
+ compile_error!( "unsupported target_pointer_width" ) ;
176
148
}
177
149
}
178
150
}
@@ -194,8 +166,26 @@ pub(crate) fn test<F>(bit: u32, f: F) -> bool
194
166
where
195
167
F : FnOnce ( ) -> Initializer ,
196
168
{
197
- if CACHE . is_uninitialized ( ) {
198
- initialize ( f ( ) ) ;
169
+ cfg_if:: cfg_if! {
170
+ if #[ cfg( target_pointer_width = "64" ) ] {
171
+ if CACHE . is_uninitialized( ) {
172
+ initialize( f( ) ) ;
173
+ }
174
+ return CACHE . test( bit) ;
175
+ } else if #[ cfg( target_pointer_width = "32" ) ] {
176
+ if bit < 31 {
177
+ if CACHE [ 0 ] . is_uninitialized( ) {
178
+ initialize( f( ) )
179
+ }
180
+ return CACHE [ 0 ] . test( bit)
181
+ } else {
182
+ if CACHE [ 1 ] . is_uninitialized( ) {
183
+ initialize( f( ) )
184
+ }
185
+ return CACHE [ 1 ] . test( bit - 31 )
186
+ }
187
+ } else {
188
+ compile_error!( "unsupported target_pointer_width" ) ;
189
+ }
199
190
}
200
- CACHE . test ( bit)
201
191
}
0 commit comments