summaryrefslogtreecommitdiffstats
path: root/vendor/cpufeatures/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vendor/cpufeatures/src/lib.rs183
1 files changed, 183 insertions, 0 deletions
diff --git a/vendor/cpufeatures/src/lib.rs b/vendor/cpufeatures/src/lib.rs
new file mode 100644
index 0000000..974dc78
--- /dev/null
+++ b/vendor/cpufeatures/src/lib.rs
@@ -0,0 +1,183 @@
+//! This crate provides macros for runtime CPU feature detection. It's intended
+//! as a stopgap until Rust [RFC 2725] adding first-class target feature detection
+//! macros to `libcore` is implemented.
+//!
+//! # Supported target architectures
+//!
+//! *NOTE: target features with an asterisk are unstable (nightly-only) and
+//! subject to change to match upstream name changes in the Rust standard
+//! library.
+//!
+//! ## `aarch64`
+//!
+//! Linux, iOS, and macOS/ARM only (ARM64 does not support OS-independent feature detection)
+//!
+//! Target features:
+//!
+//! - `aes`*
+//! - `sha2`*
+//! - `sha3`*
+//!
+//! ## `x86`/`x86_64`
+//!
+//! OS independent and `no_std`-friendly
+//!
+//! Target features:
+//!
+//! - `adx`
+//! - `aes`
+//! - `avx`
+//! - `avx2`
+//! - `avx512bw`*
+//! - `avx512cd`*
+//! - `avx512dq`*
+//! - `avx512er`*
+//! - `avx512f`*
+//! - `avx512ifma`*
+//! - `avx512pf`*
+//! - `avx512vl`*
+//! - `bmi1`
+//! - `bmi2`
+//! - `fma`,
+//! - `mmx`
+//! - `pclmulqdq`
+//! - `popcnt`
+//! - `rdrand`
+//! - `rdseed`
+//! - `sgx`
+//! - `sha`
+//! - `sse`
+//! - `sse2`
+//! - `sse3`
+//! - `sse4.1`
+//! - `sse4.2`
+//! - `ssse3`
+//!
+//! If you would like detection support for a target feature which is not on
+//! this list, please [open a GitHub issue][gh].
+//!
+//! # Example
+//! ```
+//! # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+//! # {
+//! // This macro creates `cpuid_aes_sha` module
+//! cpufeatures::new!(cpuid_aes_sha, "aes", "sha");
+//!
+//! // `token` is a Zero Sized Type (ZST) value, which guarantees
+//! // that underlying static storage got properly initialized,
+//! // which allows to omit initialization branch
+//! let token: cpuid_aes_sha::InitToken = cpuid_aes_sha::init();
+//!
+//! if token.get() {
+//! println!("CPU supports both SHA and AES extensions");
+//! } else {
+//! println!("SHA and AES extensions are not supported");
+//! }
+//!
+//! // If stored value needed only once you can get stored value
+//! // omitting the token
+//! let val = cpuid_aes_sha::get();
+//! assert_eq!(val, token.get());
+//!
+//! // Additionally you can get both token and value
+//! let (token, val) = cpuid_aes_sha::init_get();
+//! assert_eq!(val, token.get());
+//! # }
+//! ```
+//!
+//! Note that if all tested target features are enabled via compiler options
+//! (e.g. by using `RUSTFLAGS`), the `get` method will always return `true`
+//! and `init` will not use CPUID instruction. Such behavior allows
+//! compiler to completely eliminate fallback code.
+//!
+//! After first call macro caches result and returns it in subsequent
+//! calls, thus runtime overhead for them is minimal.
+//!
+//! [RFC 2725]: https://github.com/rust-lang/rfcs/pull/2725
+//! [gh]: https://github.com/RustCrypto/utils/issues/new?title=cpufeatures:%20requesting%20support%20for%20CHANGEME%20target%20feature
+
+#![no_std]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
+ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
+)]
+
+#[cfg(not(miri))]
+#[cfg(all(target_arch = "aarch64"))]
+#[doc(hidden)]
+pub mod aarch64;
+
+#[cfg(not(miri))]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+mod x86;
+
+#[cfg(miri)]
+mod miri;
+
+//#[cfg(not(any(target_arch = "aarch64", target_arch = "x86", target_arch = "x86_64")))]
+//compile_error!("This crate works only on `aarch64`, `x86`, and `x86-64` targets.");
+
+/// Create module with CPU feature detection code.
+#[macro_export]
+macro_rules! new {
+ ($mod_name:ident, $($tf:tt),+ $(,)?) => {
+ mod $mod_name {
+ use core::sync::atomic::{AtomicU8, Ordering::Relaxed};
+
+ const UNINIT: u8 = u8::max_value();
+ static STORAGE: AtomicU8 = AtomicU8::new(UNINIT);
+
+ /// Initialization token
+ #[derive(Copy, Clone, Debug)]
+ pub struct InitToken(());
+
+ impl InitToken {
+ /// Get initialized value
+ #[inline(always)]
+ pub fn get(&self) -> bool {
+ $crate::__unless_target_features! {
+ $($tf),+ => {
+ STORAGE.load(Relaxed) == 1
+ }
+ }
+ }
+ }
+
+ /// Initialize underlying storage if needed and get
+ /// stored value and initialization token.
+ #[inline]
+ pub fn init_get() -> (InitToken, bool) {
+ let res = $crate::__unless_target_features! {
+ $($tf),+ => {
+ // Relaxed ordering is fine, as we only have a single atomic variable.
+ let val = STORAGE.load(Relaxed);
+
+ if val == UNINIT {
+ let res = $crate::__detect_target_features!($($tf),+);
+ STORAGE.store(res as u8, Relaxed);
+ res
+ } else {
+ val == 1
+ }
+ }
+ };
+
+ (InitToken(()), res)
+ }
+
+ /// Initialize underlying storage if needed and get
+ /// initialization token.
+ #[inline]
+ pub fn init() -> InitToken {
+ init_get().0
+ }
+
+ /// Initialize underlying storage if needed and get
+ /// stored value.
+ #[inline]
+ pub fn get() -> bool {
+ init_get().1
+ }
+ }
+ };
+}