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,48 @@ impl Initializer {
81
77
}
82
78
83
79
/// This global variable is a cache of the features supported by the CPU.
84
- static CACHE : Cache = Cache :: uninitialized ( ) ;
85
-
86
- /// Feature cache with capacity for `CACHE_CAPACITY` features.
87
- ///
88
- /// Note: the last feature bit is used to represent an
89
- /// uninitialized cache.
90
- #[ cfg( target_pointer_width = "64" ) ]
91
- struct Cache ( AtomicU64 ) ;
92
-
93
80
#[ cfg( target_pointer_width = "64" ) ]
94
- #[ allow( clippy:: use_self) ]
95
- impl Cache {
96
- /// Creates an uninitialized cache.
97
- #[ allow( clippy:: declare_interior_mutable_const) ]
98
- const fn uninitialized ( ) -> Self {
99
- Cache ( AtomicU64 :: new ( u64:: max_value ( ) ) )
100
- }
101
- /// Is the cache uninitialized?
102
- #[ inline]
103
- pub ( crate ) fn is_uninitialized ( & self ) -> bool {
104
- self . 0 . load ( Ordering :: Relaxed ) == u64:: max_value ( )
105
- }
106
-
107
- /// Is the `bit` in the cache set?
108
- #[ inline]
109
- pub ( crate ) fn test ( & self , bit : u32 ) -> bool {
110
- test_bit ( CACHE . 0 . load ( Ordering :: Relaxed ) , bit)
111
- }
81
+ static CACHE : [ Cache ; 1 ] = [ Cache :: uninitialized ( ) ] ;
112
82
113
- /// Initializes the cache.
114
- #[ inline]
115
- pub ( crate ) fn initialize ( & self , value : Initializer ) {
116
- self . 0 . store ( value. 0 , Ordering :: Relaxed ) ;
117
- }
118
- }
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 ( ) ] ;
119
86
120
- /// Feature cache with capacity for `CACHE_CAPACITY ` features.
87
+ /// Feature cache with capacity for `usize::max_value() - 1 ` features.
121
88
///
122
89
/// Note: the last feature bit is used to represent an
123
90
/// uninitialized cache.
124
- #[ cfg( target_pointer_width = "32" ) ]
125
- struct Cache ( AtomicU32 , AtomicU32 ) ;
91
+ ///
92
+ /// Note: we use `Relaxed` atomic operations, because we are only interested
93
+ /// in the effects of operations on a single memory location. That is, we only
94
+ /// need "modification order", and not the full-blown "happens before".
95
+ struct Cache ( AtomicUsize ) ;
126
96
127
- #[ cfg( target_pointer_width = "32" ) ]
128
97
impl Cache {
129
98
/// Creates an uninitialized cache.
99
+ #[ allow( clippy:: declare_interior_mutable_const) ]
130
100
const fn uninitialized ( ) -> Self {
131
- Cache (
132
- AtomicU32 :: new ( u32:: max_value ( ) ) ,
133
- AtomicU32 :: new ( u32:: max_value ( ) ) ,
134
- )
101
+ Cache ( AtomicUsize :: new ( usize:: max_value ( ) ) )
135
102
}
136
103
/// Is the cache uninitialized?
137
104
#[ inline]
138
105
pub ( crate ) fn is_uninitialized ( & self ) -> bool {
139
- self . 1 . load ( Ordering :: Relaxed ) == u32 :: max_value ( )
106
+ self . 0 . load ( Ordering :: Relaxed ) == usize :: max_value ( )
140
107
}
141
108
142
109
/// Is the `bit` in the cache set?
143
110
#[ inline]
144
111
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
- }
112
+ test_bit ( self . 0 . load ( Ordering :: Relaxed ) as u64 , bit)
150
113
}
151
114
152
115
/// Initializes the cache.
153
116
#[ 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 ) ;
117
+ fn initialize ( & self , value : usize ) {
118
+ self . 0 . store ( value, Ordering :: Relaxed ) ;
159
119
}
160
120
}
121
+
161
122
cfg_if:: cfg_if! {
162
123
if #[ cfg( feature = "std_detect_env_override" ) ] {
163
124
#[ inline( never) ]
@@ -167,16 +128,32 @@ cfg_if::cfg_if! {
167
128
let _ = super :: Feature :: from_str( v) . map( |v| value. unset( v as u32 ) ) ;
168
129
}
169
130
}
170
- CACHE . initialize ( value) ;
131
+ do_initialize ( value) ;
171
132
}
172
133
} else {
173
134
#[ inline]
174
135
fn initialize( value: Initializer ) {
175
- CACHE . initialize ( value) ;
136
+ do_initialize ( value) ;
176
137
}
177
138
}
178
139
}
179
140
141
+ #[ cfg( target_pointer_width = "32" ) ]
142
+ const CACHE_BITS : u32 = 31 ;
143
+ #[ cfg( target_pointer_width = "64" ) ]
144
+ const CACHE_BITS : u32 = 63 ;
145
+
146
+ const CACHE_MASK : usize = 1 << CACHE_BITS - 1 ;
147
+
148
+ #[ inline]
149
+ fn do_initialize ( value : Initializer ) {
150
+ CACHE [ 0 ] . initialize ( ( value. 0 ) as usize & CACHE_MASK ) ;
151
+ #[ cfg( target_pointer_width = "32" ) ]
152
+ {
153
+ CACHE [ 1 ] . initialize ( ( value. 0 >> CACHE_BITS ) as usize & CACHE_MASK ) ;
154
+ }
155
+ }
156
+
180
157
/// Tests the `bit` of the storage. If the storage has not been initialized,
181
158
/// initializes it with the result of `f()`.
182
159
///
@@ -194,8 +171,18 @@ pub(crate) fn test<F>(bit: u32, f: F) -> bool
194
171
where
195
172
F : FnOnce ( ) -> Initializer ,
196
173
{
197
- if CACHE . is_uninitialized ( ) {
198
- initialize ( f ( ) ) ;
174
+ #[ cfg( target_pointer_width = "32" ) ]
175
+ {
176
+ if bit >= CACHE_BITS {
177
+ if CACHE [ 1 ] . is_uninitialized ( ) {
178
+ initialize ( f ( ) )
179
+ }
180
+ return CACHE [ 1 ] . test ( bit - CACHE_BITS ) ;
181
+ }
182
+ }
183
+
184
+ if CACHE [ 0 ] . is_uninitialized ( ) {
185
+ initialize ( f ( ) )
199
186
}
200
- CACHE . test ( bit)
187
+ CACHE [ 0 ] . test ( bit)
201
188
}
0 commit comments