Coverage Report

Created: 2025-09-05 06:33

/rust/registry/src/index.crates.io-6f17d22bba15001f/ring-0.17.14/src/cpu.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2016 Brian Smith.
2
//
3
// Permission to use, copy, modify, and/or distribute this software for any
4
// purpose with or without fee is hereby granted, provided that the above
5
// copyright notice and this permission notice appear in all copies.
6
//
7
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15
pub(crate) use self::features::Features;
16
use core::mem::size_of;
17
18
macro_rules! impl_get_feature {
19
    {
20
      features: [
21
          $( { ( $( $arch:expr ),+ ) => $Name:ident }, )+
22
      ],
23
    } => {
24
        $(
25
            #[cfg(any( $( target_arch = $arch ),+ ))]
26
            #[derive(Clone, Copy)]
27
            pub(crate) struct $Name(crate::cpu::Features);
28
29
            #[cfg(any( $( target_arch = $arch ),+ ))]
30
            impl $Name {
31
0
                const fn mask() -> u32 {
32
0
                    1 << (Shift::$Name as u32)
33
0
                }
Unexecuted instantiation: <ring::cpu::intel::VAesClmul>::mask
Unexecuted instantiation: <ring::cpu::intel::ClMul>::mask
Unexecuted instantiation: <ring::cpu::intel::Ssse3>::mask
Unexecuted instantiation: <ring::cpu::intel::Sse41>::mask
Unexecuted instantiation: <ring::cpu::intel::Movbe>::mask
Unexecuted instantiation: <ring::cpu::intel::Aes>::mask
Unexecuted instantiation: <ring::cpu::intel::Avx>::mask
Unexecuted instantiation: <ring::cpu::intel::Bmi1>::mask
Unexecuted instantiation: <ring::cpu::intel::Avx2>::mask
Unexecuted instantiation: <ring::cpu::intel::Bmi2>::mask
Unexecuted instantiation: <ring::cpu::intel::Adx>::mask
Unexecuted instantiation: <ring::cpu::intel::Sha>::mask
34
            }
35
36
            #[cfg(any( $( target_arch = $arch ),+ ))]
37
            impl crate::cpu::GetFeature<$Name> for super::features::Values {
38
                #[inline(always)]
39
0
                fn get_feature(&self) -> Option<$Name> {
40
                    const MASK: u32 = $Name::mask();
41
                    const STATICALLY_DETECTED: bool = (crate::cpu::CAPS_STATIC & MASK) == MASK;
42
0
                    if STATICALLY_DETECTED { // TODO: `const`
43
0
                        return Some($Name(self.cpu()));
44
0
                    }
45
0
46
0
                    if (self.values() & MASK) == MASK {
47
0
                        Some($Name(self.cpu()))
48
                    } else {
49
0
                        None
50
                    }
51
0
                }
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Bmi1>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Bmi2>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Adx>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Ssse3>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Sse41>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Avx2>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Avx>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Sha>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::VAesClmul>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::ClMul>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Movbe>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<ring::cpu::intel::Aes>>::get_feature
52
            }
53
        )+
54
55
        #[repr(u32)]
56
        enum Shift {
57
            $(
58
                #[cfg(any( $( target_arch = $arch ),+ ))]
59
                $Name,
60
            )+
61
62
            #[cfg(target_arch = "x86_64")]
63
            IntelCpu,
64
65
            #[cfg(any(all(target_arch = "aarch64", target_endian = "little"),
66
                     all(target_arch = "arm", target_endian = "little"),
67
                     target_arch = "x86", target_arch = "x86_64"))]
68
            // Synthesized to ensure the dynamic flag set is always non-zero.
69
            //
70
            // Keep this at the end as it is never checked except during init.
71
            Initialized,
72
        }
73
    }
74
}
75
76
pub(crate) trait GetFeature<T> {
77
    fn get_feature(&self) -> Option<T>;
78
}
79
80
impl GetFeature<()> for features::Values {
81
    #[inline(always)]
82
0
    fn get_feature(&self) -> Option<()> {
83
0
        Some(())
84
0
    }
85
}
86
87
impl<A, B> GetFeature<(A, B)> for features::Values
88
where
89
    features::Values: GetFeature<A>,
90
    features::Values: GetFeature<B>,
91
{
92
    #[inline(always)]
93
0
    fn get_feature(&self) -> Option<(A, B)> {
94
0
        match (self.get_feature(), self.get_feature()) {
95
0
            (Some(a), Some(b)) => Some((a, b)),
96
0
            _ => None,
97
        }
98
0
    }
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Adx, ring::cpu::intel::Bmi2)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Avx2, ring::cpu::intel::Bmi2)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Avx, ring::cpu::intel::IntelCpu)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Sha, ring::cpu::intel::Ssse3)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Aes, ring::cpu::intel::Ssse3)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Avx2, ring::cpu::intel::VAesClmul)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::ClMul, ring::cpu::intel::Ssse3)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<((ring::cpu::intel::Aes, ring::cpu::intel::Ssse3), (ring::cpu::intel::ClMul, ring::cpu::intel::Ssse3))>>::get_feature
99
}
100
101
impl<A, B, C> GetFeature<(A, B, C)> for features::Values
102
where
103
    features::Values: GetFeature<A>,
104
    features::Values: GetFeature<B>,
105
    features::Values: GetFeature<C>,
106
{
107
    #[inline(always)]
108
0
    fn get_feature(&self) -> Option<(A, B, C)> {
109
0
        match (self.get_feature(), self.get_feature(), self.get_feature()) {
110
0
            (Some(a), Some(b), Some(c)) => Some((a, b, c)),
111
0
            _ => None,
112
        }
113
0
    }
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::Adx, ring::cpu::intel::Bmi1, ring::cpu::intel::Bmi2)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Values as ring::cpu::GetFeature<(ring::cpu::intel::ClMul, ring::cpu::intel::Avx, ring::cpu::intel::Movbe)>>::get_feature
114
}
115
116
impl<F> GetFeature<F> for Features
117
where
118
    features::Values: GetFeature<F>,
119
{
120
    #[inline(always)]
121
0
    fn get_feature(&self) -> Option<F> {
122
0
        self.values().get_feature()
123
0
    }
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<(ring::cpu::intel::Adx, ring::cpu::intel::Bmi1, ring::cpu::intel::Bmi2)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<(ring::cpu::intel::Adx, ring::cpu::intel::Bmi2)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<ring::cpu::intel::Sse41>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<(ring::cpu::intel::Avx2, ring::cpu::intel::Bmi2)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<ring::cpu::intel::Avx>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<ring::cpu::intel::Ssse3>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<(ring::cpu::intel::Aes, ring::cpu::intel::Ssse3)>>::get_feature
Unexecuted instantiation: <ring::cpu::features::Features as ring::cpu::GetFeature<(ring::cpu::intel::Avx, ring::cpu::intel::IntelCpu)>>::get_feature
124
}
125
126
#[inline(always)]
127
0
pub(crate) fn features() -> Features {
128
0
    featureflags::get_or_init()
129
0
}
130
131
mod features {
132
    use crate::polyfill::NotSend;
133
134
    /// A witness indicating that CPU features have been detected and cached.
135
    ///
136
    /// This is a zero-sized type so that it can be "stored" wherever convenient.
137
    #[derive(Copy, Clone)]
138
    pub(crate) struct Features(NotSend);
139
140
    impl Features {
141
0
        pub fn values(self) -> Values {
142
0
            Values {
143
0
                values: super::featureflags::get(self),
144
0
                cpu: self,
145
0
            }
146
0
        }
147
    }
148
149
    cfg_if::cfg_if! {
150
        if #[cfg(any(all(target_arch = "aarch64", target_endian = "little"), all(target_arch = "arm", target_endian = "little"),
151
                     target_arch = "x86", target_arch = "x86_64"))] {
152
            impl Features {
153
                // SAFETY: This must only be called after CPU features have been written
154
                // and synchronized.
155
0
                pub(super) unsafe fn new_after_feature_flags_written_and_synced_unchecked() -> Self {
156
0
                    Self(NotSend::VALUE)
157
0
                }
158
            }
159
        } else {
160
            impl Features {
161
                pub(super) fn new_no_features_to_detect() -> Self {
162
                    Self(NotSend::VALUE)
163
                }
164
            }
165
        }
166
    }
167
168
    pub struct Values {
169
        values: u32,
170
        cpu: Features,
171
    }
172
173
    impl Values {
174
        #[inline(always)]
175
0
        pub(super) fn values(&self) -> u32 {
176
0
            self.values
177
0
        }
178
179
        #[inline(always)]
180
0
        pub(super) fn cpu(&self) -> Features {
181
0
            self.cpu
182
0
        }
183
    }
184
}
185
186
const _: () = assert!(size_of::<Features>() == 0);
187
188
cfg_if::cfg_if! {
189
    if #[cfg(any(all(target_arch = "aarch64", target_endian = "little"), all(target_arch = "arm", target_endian = "little")))] {
190
        pub mod arm;
191
        use arm::featureflags;
192
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
193
        pub mod intel;
194
        use intel::featureflags;
195
    } else {
196
        mod featureflags {
197
            use super::Features;
198
199
            #[inline(always)]
200
            pub(super) fn get_or_init() -> Features {
201
                Features::new_no_features_to_detect()
202
            }
203
204
            #[inline(always)]
205
            pub(super) fn get(_cpu_features: Features) -> u32 {
206
                STATIC_DETECTED
207
            }
208
209
            pub(super) const STATIC_DETECTED: u32 = 0;
210
            pub(super) const FORCE_DYNAMIC_DETECTION: u32 = 0;
211
        }
212
    }
213
}
214
215
const CAPS_STATIC: u32 = featureflags::STATIC_DETECTED & !featureflags::FORCE_DYNAMIC_DETECTION;
216
217
#[allow(clippy::assertions_on_constants, clippy::bad_bit_mask)]
218
const _FORCE_DYNAMIC_DETECTION_HONORED: () =
219
    assert!((CAPS_STATIC & featureflags::FORCE_DYNAMIC_DETECTION) == 0);
220
221
#[cfg(test)]
222
mod tests {
223
    use super::*;
224
225
    #[test]
226
    fn test_static_is_subset_of_dynamic() {
227
        let cpu = features();
228
        let dynamic = featureflags::get(cpu);
229
        assert_eq!(dynamic & CAPS_STATIC, CAPS_STATIC);
230
    }
231
}