about summary refs log tree commit diff
path: root/library/stdarch/crates
diff options
context:
space:
mode:
authorgnzlbg <gonzalobg88@gmail.com>2019-04-23 15:51:20 +0200
committergnzlbg <gnzlbg@users.noreply.github.com>2019-09-16 23:43:01 +0200
commit1f44c1407dc6e6f91600f9303739ca8acbcc8194 (patch)
treefb4d4c554ce3aaceccc1ce679c33fc9003a259bc /library/stdarch/crates
parentf3140f4b25860a1aa6257c6afc064efe177b0b67 (diff)
downloadrust-1f44c1407dc6e6f91600f9303739ca8acbcc8194.tar.gz
rust-1f44c1407dc6e6f91600f9303739ca8acbcc8194.zip
Add std_detect::detect::features() -> impl Iterator<Item=(&'static str, bool)> API
Diffstat (limited to 'library/stdarch/crates')
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs114
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/arm.rs46
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/mips.rs32
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/mips64.rs32
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs45
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs45
-rw-r--r--library/stdarch/crates/std_detect/src/detect/arch/x86.rs406
-rw-r--r--library/stdarch/crates/std_detect/src/detect/macros.rs74
-rw-r--r--library/stdarch/crates/std_detect/src/detect/mod.rs36
-rw-r--r--library/stdarch/crates/std_detect/src/detect/os/x86.rs11
-rw-r--r--library/stdarch/crates/std_detect/tests/cpu-detection.rs31
11 files changed, 314 insertions, 558 deletions
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs
index ebae2bd2854..73e54052b82 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/aarch64.rs
@@ -1,106 +1,36 @@
 //! Aarch64 run-time features.
 
-/// Checks if `aarch64` feature is enabled.
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_aarch64_feature_detected {
-    ("neon") => {
-        // FIXME: this should be removed once we rename Aarch64 neon to asimd
-        cfg!(target_feature = "neon") ||
-            $crate::detect::check_for($crate::detect::Feature::asimd)
-    };
-    ("asimd") => {
-        cfg!(target_feature = "neon") ||
-            $crate::detect::check_for($crate::detect::Feature::asimd)
-    };
-    ("pmull") => {
-        cfg!(target_feature = "pmull") ||
-            $crate::detect::check_for($crate::detect::Feature::pmull)
-    };
-    ("fp") => {
-        cfg!(target_feature = "fp") ||
-            $crate::detect::check_for($crate::detect::Feature::fp)
-    };
-    ("fp16") => {
-        cfg!(target_feature = "fp16") ||
-            $crate::detect::check_for($crate::detect::Feature::fp16)
-    };
-    ("sve") => {
-        cfg!(target_feature = "sve") ||
-            $crate::detect::check_for($crate::detect::Feature::sve)
-    };
-    ("crc") => {
-        cfg!(target_feature = "crc") ||
-            $crate::detect::check_for($crate::detect::Feature::crc)
-    };
-    ("crypto") => {
-        cfg!(target_feature = "crypto") ||
-            $crate::detect::check_for($crate::detect::Feature::crypto)
-    };
-    ("lse") => {
-        cfg!(target_feature = "lse") ||
-            $crate::detect::check_for($crate::detect::Feature::lse)
-    };
-    ("rdm") => {
-        cfg!(target_feature = "rdm") ||
-            $crate::detect::check_for($crate::detect::Feature::rdm)
-    };
-    ("rcpc") => {
-        cfg!(target_feature = "rcpc") ||
-            $crate::detect::check_for($crate::detect::Feature::rcpc)
-    };
-    ("dotprod") => {
-        cfg!(target_feature = "dotprod") ||
-            $crate::detect::check_for($crate::detect::Feature::dotprod)
-    };
-    ("ras") => {
-        compile_error!("\"ras\" feature cannot be detected at run-time")
-    };
-    ("v8.1a") => {
-        compile_error!("\"v8.1a\" feature cannot be detected at run-time")
-    };
-    ("v8.2a") => {
-        compile_error!("\"v8.2a\" feature cannot be detected at run-time")
-    };
-    ("v8.3a") => {
-        compile_error!("\"v8.3a\" feature cannot be detected at run-time")
-    };
-    ($t:tt,) => {
-        is_aarch64_feature_detected!($t);
-    };
-    ($t:tt) => { compile_error!(concat!("unknown aarch64 target feature: ", $t)) };
-}
-
-/// ARM Aarch64 CPU Feature enum. Each variant denotes a position in a bitset
-/// for a particular feature.
-///
-/// PLEASE: do not use this, it is an implementation detail subject to change.
-#[doc(hidden)]
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: aarch64;
+    @MACRO_NAME: is_aarch64_feature_detected;
+    @MACRO_ATTRS:
+    /// Checks if `aarch64` feature is enabled.
+    #[unstable(feature = "stdsimd", issue = "27731")]
+    @BIND_FEATURE_NAME: "asimd"; "neon";
+    @NO_RUNTIME_DETECTION: "ras";
+    @NO_RUNTIME_DETECTION: "v8.1a";
+    @NO_RUNTIME_DETECTION: "v8.2a";
+    @NO_RUNTIME_DETECTION: "v8.3a";
+    @FEATURE: asimd: "neon";
     /// ARM Advanced SIMD (ASIMD)
-    asimd,
+    @FEATURE: pmull: "pmull";
     /// Polynomial Multiply
-    pmull,
+    @FEATURE: fp: "fp";
     /// Floating point support
-    fp,
+    @FEATURE: fp16: "fp16";
     /// Half-float support.
-    fp16,
+    @FEATURE: sve: "sve";
     /// Scalable Vector Extension (SVE)
-    sve,
+    @FEATURE: crc: "crc";
     /// CRC32 (Cyclic Redundancy Check)
-    crc,
+    @FEATURE: crypto: "crypto";
     /// Crypto: AES + PMULL + SHA1 + SHA2
-    crypto,
+    @FEATURE: lse: "lse";
     /// Atomics (Large System Extension)
-    lse,
+    @FEATURE: rdm: "rdm";
     /// Rounding Double Multiply (ASIMDRDM)
-    rdm,
+    @FEATURE: rcpc: "rcpc";
     /// Release consistent Processor consistent (RcPc)
-    rcpc,
+    @FEATURE: dotprod: "dotprod";
     /// Vector Dot-Product (ASIMDDP)
-    dotprod,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/arm.rs b/library/stdarch/crates/std_detect/src/detect/arch/arm.rs
index b2626bf2923..86dc6dbbf23 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/arm.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/arm.rs
@@ -1,39 +1,17 @@
 //! Run-time feature detection on ARM Aarch32.
 
-/// Checks if `arm` feature is enabled.
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_arm_feature_detected {
-    ("neon") => {
-        cfg!(target_feature = "neon") ||
-            $crate::detect::check_for($crate::detect::Feature::neon)
-    };
-    ("pmull") => {
-        cfg!(target_feature = "pmull") ||
-            $crate::detect::check_for($crate::detect::Feature::pmull)
-    };
-    ("v7") => { compile_error!("\"v7\" feature cannot be detected at run-time") };
-    ("vfp2") => { compile_error!("\"vfp2\" feature cannot be detected at run-time") };
-    ("vfp3") => { compile_error!("\"vfp3\" feature cannot be detected at run-time") };
-    ("vfp4") => { compile_error!("\"vfp4\" feature cannot be detected at run-time") };
-    ($t:tt,) => {
-        is_arm_feature_detected!($t);
-    };
-    ($t:tt) => { compile_error!(concat!("unknown arm target feature: ", $t)) };
-}
-
-/// ARM CPU Feature enum. Each variant denotes a position in a bitset for a
-/// particular feature.
-///
-/// PLEASE: do not use this, it is an implementation detail subject to change.
-#[doc(hidden)]
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: arm;
+    @MACRO_NAME: is_arm_feature_detected;
+    @MACRO_ATTRS:
+    /// Checks if `arm` feature is enabled.
+    #[unstable(feature = "stdsimd", issue = "27731")]
+    @NO_RUNTIME_DETECTION: "v7";
+    @NO_RUNTIME_DETECTION: "vfp2";
+    @NO_RUNTIME_DETECTION: "vfp3";
+    @NO_RUNTIME_DETECTION: "vfp4";
+    @FEATURE: neon: "neon";
     /// ARM Advanced SIMD (NEON) - Aarch32
-    neon,
+    @FEATURE: pmull: "pmull";
     /// Polynomial Multiply
-    pmull,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mips.rs b/library/stdarch/crates/std_detect/src/detect/arch/mips.rs
index f4381b811cd..1ac540ef737 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/mips.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/mips.rs
@@ -1,29 +1,11 @@
 //! Run-time feature detection on MIPS.
 
-/// Checks if `mips` feature is enabled.
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_mips_feature_detected {
-    ("msa") => {
-        cfg!(target_feature = "msa") ||
-            $crate::detect::check_for($crate::detect::Feature::msa)
-    };
-    ($t:tt,) => {
-        is_mips_feature_detected!($t);
-    };
-    ($t:tt) => { compile_error!(concat!("unknown mips target feature: ", $t)) };
-}
-
-/// MIPS CPU Feature enum. Each variant denotes a position in a bitset for a
-/// particular feature.
-///
-/// PLEASE: do not use this, it is an implementation detail subject to change.
-#[doc(hidden)]
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: mips;
+    @MACRO_NAME: is_mips_feature_detected;
+    @MACRO_ATTRS:
+    /// Checks if `mips` feature is enabled.
+    #[unstable(feature = "stdsimd", issue = "27731")]
+    @FEATURE: msa: "msa";
     /// MIPS SIMD Architecture (MSA)
-    msa,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs b/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs
index 2663bc68ba9..33ad3bca768 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/mips64.rs
@@ -1,29 +1,11 @@
 //! Run-time feature detection on MIPS64.
 
-/// Checks if `mips64` feature is enabled.
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_mips64_feature_detected {
-    ("msa") => {
-        cfg!(target_feature = "msa") ||
-            $crate::detect::check_for($crate::detect::Feature::msa)
-    };
-    ($t:tt,) => {
-        is_mips64_feature_detected!($t);
-    };
-    ($t:tt) => { compile_error!(concat!("unknown mips64 target feature: ", $t)) };
-}
-
-/// MIPS64 CPU Feature enum. Each variant denotes a position in a bitset
-/// for a particular feature.
-///
-/// PLEASE: do not use this, it is an implementation detail subject to change.
-#[doc(hidden)]
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: mips64;
+    @MACRO_NAME: is_mips64_feature_detected;
+    @MACRO_ATTRS:
+    /// Checks if `mips64` feature is enabled.
+    #[unstable(feature = "stdsimd", issue = "27731")]
+    @FEATURE: msa: "msa";
     /// MIPS SIMD Architecture (MSA)
-    msa,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs b/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs
index a342dc1aacc..6cc35a24110 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/powerpc.rs
@@ -1,42 +1,15 @@
 //! Run-time feature detection on PowerPC.
 
-/// Checks if `powerpc` feature is enabled.
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_powerpc_feature_detected {
-    ("altivec") => {
-        cfg!(target_feature = "altivec") ||
-            $crate::detect::check_for($crate::detect::Feature::altivec)
-    };
-    ("vsx") => {
-        cfg!(target_feature = "vsx") ||
-            $crate::detect::check_for($crate::detect::Feature::vsx)
-    };
-    ("power8") => {
-        cfg!(target_feature = "power8") ||
-            $crate::detect::check_for($crate::detect::Feature::power8)
-    };
-    ($t:tt,) => {
-        is_powerpc_feature_detected!($t);
-    };
-    ($t:tt) => { compile_error!(concat!("unknown powerpc target feature: ", $t)) };
-}
-
-
-/// PowerPC CPU Feature enum. Each variant denotes a position in a bitset
-/// for a particular feature.
-///
-/// PLEASE: do not use this, it is an implementation detail subject to change.
-#[doc(hidden)]
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: powerpc;
+    @MACRO_NAME: is_powerpc_feature_detected;
+    @MACRO_ATTRS:
+    /// Checks if `powerpc` feature is enabled.
+    #[unstable(feature = "stdsimd", issue = "27731")]
+    @FEATURE: altivec: "altivec";
     /// Altivec
-    altivec,
+    @FEATURE: vsx: "vsx";
     /// VSX
-    vsx,
+    @FEATURE: power8: "power8";
     /// Power8
-    power8,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs b/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs
index 2e82c569252..a075c94190e 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/powerpc64.rs
@@ -1,42 +1,15 @@
 //! Run-time feature detection on PowerPC64.
 
-/// Checks if `powerpc64` feature is enabled.
-#[macro_export]
-#[unstable(feature = "stdsimd", issue = "27731")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_powerpc64_feature_detected {
-    ("altivec") => {
-        cfg!(target_feature = "altivec") ||
-            $crate::detect::check_for($crate::detect::Feature::altivec)
-    };
-    ("vsx") => {
-        cfg!(target_feature = "vsx") ||
-            $crate::detect::check_for($crate::detect::Feature::vsx)
-    };
-    ("power8") => {
-        cfg!(target_feature = "power8") ||
-            $crate::detect::check_for($crate::detect::Feature::power8)
-    };
-    ($t:tt,) => {
-        is_powerpc64_feature_detected!($t);
-    };
-    ($t:tt) => { compile_error!(concat!("unknown powerpc64 target feature: ", $t)) };
-}
-
-
-/// PowerPC64 CPU Feature enum. Each variant denotes a position in a bitset
-/// for a particular feature.
-///
-/// PLEASE: do not use this, it is an implementation detail subject to change.
-#[doc(hidden)]
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: powerpc64;
+    @MACRO_NAME: is_powerpc64_feature_detected;
+    @MACRO_ATTRS:
+    /// Checks if `powerpc` feature is enabled.
+    #[unstable(feature = "stdsimd", issue = "27731")]
+    @FEATURE: altivec: "altivec";
     /// Altivec
-    altivec,
+    @FEATURE: vsx: "vsx";
     /// VSX
-    vsx,
+    @FEATURE: power8: "power8";
     /// Power8
-    power8,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/arch/x86.rs b/library/stdarch/crates/std_detect/src/detect/arch/x86.rs
index 50d5cfa87c4..470b8978dbc 100644
--- a/library/stdarch/crates/std_detect/src/detect/arch/x86.rs
+++ b/library/stdarch/crates/std_detect/src/detect/arch/x86.rs
@@ -15,334 +15,154 @@
 //! in a global `AtomicUsize` variable. The query is performed by just checking
 //! whether the feature bit in this global variable is set or cleared.
 
-/// A macro to test at *runtime* whether a CPU feature is available on
-/// x86/x86-64 platforms.
-///
-/// This macro is provided in the standard library and will detect at runtime
-/// whether the specified CPU feature is detected. This does **not** resolve at
-/// compile time unless the specified feature is already enabled for the entire
-/// crate. Runtime detection currently relies mostly on the `cpuid` instruction.
-///
-/// This macro only takes one argument which is a string literal of the feature
-/// being tested for. The feature names supported are the lowercase versions of
-/// the ones defined by Intel in [their documentation][docs].
-///
-/// ## Supported arguments
-///
-/// This macro supports the same names that `#[target_feature]` supports. Unlike
-/// `#[target_feature]`, however, this macro does not support names separated
-/// with a comma. Instead testing for multiple features must be done through
-/// separate macro invocations for now.
-///
-/// Supported arguments are:
-///
-/// * `"aes"`
-/// * `"pclmulqdq"`
-/// * `"rdrand"`
-/// * `"rdseed"`
-/// * `"tsc"`
-/// * `"mmx"`
-/// * `"sse"`
-/// * `"sse2"`
-/// * `"sse3"`
-/// * `"ssse3"`
-/// * `"sse4.1"`
-/// * `"sse4.2"`
-/// * `"sse4a"`
-/// * `"sha"`
-/// * `"avx"`
-/// * `"avx2"`
-/// * `"avx512f"`
-/// * `"avx512cd"`
-/// * `"avx512er"`
-/// * `"avx512pf"`
-/// * `"avx512bw"`
-/// * `"avx512dq"`
-/// * `"avx512vl"`
-/// * `"avx512ifma"`
-/// * `"avx512vbmi"`
-/// * `"avx512vpopcntdq"`
-/// * `"f16c"`
-/// * `"fma"`
-/// * `"bmi1"`
-/// * `"bmi2"`
-/// * `"abm"`
-/// * `"lzcnt"`
-/// * `"tbm"`
-/// * `"popcnt"`
-/// * `"fxsr"`
-/// * `"xsave"`
-/// * `"xsaveopt"`
-/// * `"xsaves"`
-/// * `"xsavec"`
-/// * `"adx"`
-/// * `"rtm"`
-///
-/// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide
-#[macro_export]
-#[stable(feature = "simd_x86", since = "1.27.0")]
-#[allow_internal_unstable(stdsimd_internal,stdsimd)]
-macro_rules! is_x86_feature_detected {
-    ("aes") => {
-        cfg!(target_feature = "aes") || $crate::detect::check_for(
-            $crate::detect::Feature::aes)  };
-    ("pclmulqdq") => {
-        cfg!(target_feature = "pclmulqdq") || $crate::detect::check_for(
-            $crate::detect::Feature::pclmulqdq)  };
-    ("rdrand") => {
-        cfg!(target_feature = "rdrand") || $crate::detect::check_for(
-            $crate::detect::Feature::rdrand)  };
-    ("rdseed") => {
-        cfg!(target_feature = "rdseed") || $crate::detect::check_for(
-            $crate::detect::Feature::rdseed)  };
-    ("tsc") => {
-        cfg!(target_feature = "tsc") || $crate::detect::check_for(
-            $crate::detect::Feature::tsc)  };
-    ("mmx") => {
-        cfg!(target_feature = "mmx") || $crate::detect::check_for(
-            $crate::detect::Feature::mmx)  };
-    ("sse") => {
-        cfg!(target_feature = "sse") || $crate::detect::check_for(
-            $crate::detect::Feature::sse)  };
-    ("sse2") => {
-        cfg!(target_feature = "sse2") || $crate::detect::check_for(
-            $crate::detect::Feature::sse2)
-    };
-    ("sse3") => {
-        cfg!(target_feature = "sse3") || $crate::detect::check_for(
-            $crate::detect::Feature::sse3)
-    };
-    ("ssse3") => {
-        cfg!(target_feature = "ssse3") || $crate::detect::check_for(
-            $crate::detect::Feature::ssse3)
-    };
-    ("sse4.1") => {
-        cfg!(target_feature = "sse4.1") || $crate::detect::check_for(
-            $crate::detect::Feature::sse4_1)
-    };
-    ("sse4.2") => {
-        cfg!(target_feature = "sse4.2") || $crate::detect::check_for(
-            $crate::detect::Feature::sse4_2)
-    };
-    ("sse4a") => {
-        cfg!(target_feature = "sse4a") || $crate::detect::check_for(
-            $crate::detect::Feature::sse4a)
-    };
-    ("sha") => {
-        cfg!(target_feature = "sha") || $crate::detect::check_for(
-            $crate::detect::Feature::sha)
-    };
-    ("avx") => {
-        cfg!(target_feature = "avx") || $crate::detect::check_for(
-            $crate::detect::Feature::avx)
-    };
-    ("avx2") => {
-        cfg!(target_feature = "avx2") || $crate::detect::check_for(
-            $crate::detect::Feature::avx2)
-    };
-    ("avx512f") => {
-        cfg!(target_feature = "avx512f") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512f)
-    };
-    ("avx512cd") => {
-        cfg!(target_feature = "avx512cd") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512cd)
-    };
-    ("avx512er") => {
-        cfg!(target_feature = "avx512er") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512er)
-    };
-    ("avx512pf") => {
-        cfg!(target_feature = "avx512pf") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512pf)
-    };
-    ("avx512bw") => {
-        cfg!(target_feature = "avx512bw") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512bw)
-    };
-    ("avx512dq") => {
-        cfg!(target_feature = "avx512dq") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512dq)
-    };
-    ("avx512vl") => {
-        cfg!(target_Feature = "avx512vl") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512vl)
-    };
-    ("avx512ifma") => {
-        cfg!(target_feature = "avx512ifma") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512_ifma)
-    };
-    ("avx512vbmi") => {
-        cfg!(target_feature = "avx512vbmi") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512_vbmi)
-    };
-    ("avx512vpopcntdq") => {
-        cfg!(target_feature = "avx512vpopcntdq") || $crate::detect::check_for(
-            $crate::detect::Feature::avx512_vpopcntdq)
-    };
-    ("f16c") => {
-        cfg!(target_feature = "f16c") || $crate::detect::check_for(
-            $crate::detect::Feature::f16c)
-    };
-    ("fma") => {
-        cfg!(target_feature = "fma") || $crate::detect::check_for(
-            $crate::detect::Feature::fma)
-    };
-    ("bmi1") => {
-        cfg!(target_feature = "bmi1") || $crate::detect::check_for(
-            $crate::detect::Feature::bmi)
-    };
-    ("bmi2") => {
-        cfg!(target_feature = "bmi2") || $crate::detect::check_for(
-            $crate::detect::Feature::bmi2)
-    };
-    ("abm") => {
-        cfg!(target_feature = "abm") || $crate::detect::check_for(
-            $crate::detect::Feature::abm)
-    };
-    ("lzcnt") => {
-        cfg!(target_feature = "lzcnt") || $crate::detect::check_for(
-            $crate::detect::Feature::abm)
-    };
-    ("tbm") => {
-        cfg!(target_feature = "tbm") || $crate::detect::check_for(
-            $crate::detect::Feature::tbm)
-    };
-    ("popcnt") => {
-        cfg!(target_feature = "popcnt") || $crate::detect::check_for(
-            $crate::detect::Feature::popcnt)
-    };
-    ("fxsr") => {
-        cfg!(target_feature = "fxsr") || $crate::detect::check_for(
-            $crate::detect::Feature::fxsr)
-    };
-    ("xsave") => {
-        cfg!(target_feature = "xsave") || $crate::detect::check_for(
-            $crate::detect::Feature::xsave)
-    };
-    ("xsaveopt") => {
-        cfg!(target_feature = "xsaveopt") || $crate::detect::check_for(
-            $crate::detect::Feature::xsaveopt)
-    };
-    ("xsaves") => {
-        cfg!(target_feature = "xsaves") || $crate::detect::check_for(
-            $crate::detect::Feature::xsaves)
-    };
-    ("xsavec") => {
-        cfg!(target_feature = "xsavec") || $crate::detect::check_for(
-            $crate::detect::Feature::xsavec)
-    };
-    ("cmpxchg16b") => {
-        cfg!(target_feature = "cmpxchg16b") || $crate::detect::check_for(
-            $crate::detect::Feature::cmpxchg16b)
-    };
-    ("adx") => {
-        cfg!(target_feature = "adx") || $crate::detect::check_for(
-            $crate::detect::Feature::adx)
-    };
-    ("rtm") => {
-        cfg!(target_feature = "rtm") || $crate::detect::check_for(
-            $crate::detect::Feature::rtm)
-    };
-    ($t:tt,) => {
-        is_x86_feature_detected!($t);
-    };
-    ($t:tt) => {
-        compile_error!(concat!("unknown target feature: ", $t))
-    };
-}
-
-/// X86 CPU Feature enum. Each variant denotes a position in a bitset for a
-/// particular feature.
-///
-/// This is an unstable implementation detail subject to change.
-#[allow(non_camel_case_types)]
-#[repr(u8)]
-#[doc(hidden)]
-#[unstable(feature = "stdsimd_internal", issue = "0")]
-pub enum Feature {
+features! {
+    @TARGET: x86;
+    @MACRO_NAME: is_x86_feature_detected;
+    @MACRO_ATTRS:
+    /// A macro to test at *runtime* whether a CPU feature is available on
+    /// x86/x86-64 platforms.
+    ///
+    /// This macro is provided in the standard library and will detect at runtime
+    /// whether the specified CPU feature is detected. This does **not** resolve at
+    /// compile time unless the specified feature is already enabled for the entire
+    /// crate. Runtime detection currently relies mostly on the `cpuid` instruction.
+    ///
+    /// This macro only takes one argument which is a string literal of the feature
+    /// being tested for. The feature names supported are the lowercase versions of
+    /// the ones defined by Intel in [their documentation][docs].
+    ///
+    /// ## Supported arguments
+    ///
+    /// This macro supports the same names that `#[target_feature]` supports. Unlike
+    /// `#[target_feature]`, however, this macro does not support names separated
+    /// with a comma. Instead testing for multiple features must be done through
+    /// separate macro invocations for now.
+    ///
+    /// Supported arguments are:
+    ///
+    /// * `"aes"`
+    /// * `"pclmulqdq"`
+    /// * `"rdrand"`
+    /// * `"rdseed"`
+    /// * `"tsc"`
+    /// * `"mmx"`
+    /// * `"sse"`
+    /// * `"sse2"`
+    /// * `"sse3"`
+    /// * `"ssse3"`
+    /// * `"sse4.1"`
+    /// * `"sse4.2"`
+    /// * `"sse4a"`
+    /// * `"sha"`
+    /// * `"avx"`
+    /// * `"avx2"`
+    /// * `"avx512f"`
+    /// * `"avx512cd"`
+    /// * `"avx512er"`
+    /// * `"avx512pf"`
+    /// * `"avx512bw"`
+    /// * `"avx512dq"`
+    /// * `"avx512vl"`
+    /// * `"avx512ifma"`
+    /// * `"avx512vbmi"`
+    /// * `"avx512vpopcntdq"`
+    /// * `"fma"`
+    /// * `"bmi1"`
+    /// * `"bmi2"`
+    /// * `"abm"`
+    /// * `"lzcnt"`
+    /// * `"tbm"`
+    /// * `"popcnt"`
+    /// * `"fxsr"`
+    /// * `"xsave"`
+    /// * `"xsaveopt"`
+    /// * `"xsaves"`
+    /// * `"xsavec"`
+    ///
+    /// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide
+    #[stable(feature = "simd_x86", since = "1.27.0")]
+    @BIND_FEATURE_NAME: "abm"; "lzcnt"; // abm is a synonym for lzcnt
+    @FEATURE: aes: "aes";
     /// AES (Advanced Encryption Standard New Instructions AES-NI)
-    aes,
+    @FEATURE: pclmulqdq: "pclmulqdq";
     /// CLMUL (Carry-less Multiplication)
-    pclmulqdq,
+    @FEATURE: rdrand: "rdrand";
     /// RDRAND
-    rdrand,
+    @FEATURE: rdseed: "rdseed";
     /// RDSEED
-    rdseed,
+    @FEATURE: tsc: "tsc";
     /// TSC (Time Stamp Counter)
-    tsc,
-    /// MMX
-    mmx,
+    @FEATURE: mmx: "mmx";
+    /// MMX (MultiMedia eXtensions)
+    @FEATURE: sse: "sse";
     /// SSE (Streaming SIMD Extensions)
-    sse,
+    @FEATURE: sse2: "sse2";
     /// SSE2 (Streaming SIMD Extensions 2)
-    sse2,
+    @FEATURE: sse3: "sse3";
     /// SSE3 (Streaming SIMD Extensions 3)
-    sse3,
+    @FEATURE: ssse3: "ssse3";
     /// SSSE3 (Supplemental Streaming SIMD Extensions 3)
-    ssse3,
+    @FEATURE: sse4_1: "sse4.1";
     /// SSE4.1 (Streaming SIMD Extensions 4.1)
-    sse4_1,
+    @FEATURE: sse4_2: "sse4.2";
     /// SSE4.2 (Streaming SIMD Extensions 4.2)
-    sse4_2,
+    @FEATURE: sse4a: "sse4a";
     /// SSE4a (Streaming SIMD Extensions 4a)
-    sse4a,
+    @FEATURE: sha: "sha";
     /// SHA
-    sha,
+    @FEATURE: avx: "avx";
     /// AVX (Advanced Vector Extensions)
-    avx,
+    @FEATURE: avx2: "avx2";
     /// AVX2 (Advanced Vector Extensions 2)
-    avx2,
+    @FEATURE: avx512f: "avx512f" ;
     /// AVX-512 F (Foundation)
-    avx512f,
+    @FEATURE: avx512cd: "avx512cd" ;
     /// AVX-512 CD (Conflict Detection Instructions)
-    avx512cd,
-    /// AVX-512 ER (Exponential and Reciprocal Instructions)
-    avx512er,
+    @FEATURE: avx512er: "avx512er";
+    /// AVX-512 ER (Expo nential and Reciprocal Instructions)
+    @FEATURE: avx512pf: "avx512pf";
     /// AVX-512 PF (Prefetch Instructions)
-    avx512pf,
+    @FEATURE: avx512bw: "avx512bw";
     /// AVX-512 BW (Byte and Word Instructions)
-    avx512bw,
+    @FEATURE: avx512dq: "avx512dq";
     /// AVX-512 DQ (Doubleword and Quadword)
-    avx512dq,
+    @FEATURE: avx512vl: "avx512vl";
     /// AVX-512 VL (Vector Length Extensions)
-    avx512vl,
+    @FEATURE: avx512ifma: "avx512ifma";
     /// AVX-512 IFMA (Integer Fused Multiply Add)
-    avx512_ifma,
+    @FEATURE: avx512vbmi: "avx512vbmi";
     /// AVX-512 VBMI (Vector Byte Manipulation Instructions)
-    avx512_vbmi,
+    @FEATURE: avx512vpopcntdq: "avx512vpopcntdq";
     /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and
     /// Quadword)
-    avx512_vpopcntdq,
+    @FEATURE: f16c: "f16c";
     /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats)
-    f16c,
+    @FEATURE: fma: "fma";
     /// FMA (Fused Multiply Add)
-    fma,
+    @FEATURE: bmi1: "bmi1" ;
     /// BMI1 (Bit Manipulation Instructions 1)
-    bmi,
-    /// BMI1 (Bit Manipulation Instructions 2)
-    bmi2,
-    /// ABM (Advanced Bit Manipulation) on AMD / LZCNT (Leading Zero
-    /// Count) on Intel
-    abm,
+    @FEATURE: bmi2: "bmi2" ;
+    /// BMI2 (Bit Manipulation Instructions 2)
+    @FEATURE: lzcnt: "lzcnt";
+    /// ABM (Advanced Bit Manipulation) / LZCNT (Leading Zero Count)
+    @FEATURE: tbm: "tbm";
     /// TBM (Trailing Bit Manipulation)
-    tbm,
+    @FEATURE: popcnt: "popcnt";
     /// POPCNT (Population Count)
-    popcnt,
+    @FEATURE: fxsr: "fxsr";
     /// FXSR (Floating-point context fast save and restor)
-    fxsr,
+    @FEATURE: xsave: "xsave";
     /// XSAVE (Save Processor Extended States)
-    xsave,
+    @FEATURE: xsaveopt: "xsaveopt";
     /// XSAVEOPT (Save Processor Extended States Optimized)
-    xsaveopt,
+    @FEATURE: xsaves: "xsaves";
     /// XSAVES (Save Processor Extended States Supervisor)
-    xsaves,
+    @FEATURE: xsavec: "xsavec";
     /// XSAVEC (Save Processor Extended States Compacted)
-    xsavec,
-    /// CMPXCH16B, a 16-byte compare-and-swap instruction
-    cmpxchg16b,
+    @FEATURE: cmpxchg16b: "cmpxchg16b";
+    /// CMPXCH16B (16-byte compare-and-swap instruction)
+    @FEATURE: adx: "adx";
     /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
-    adx,
+    @FEATURE: rtm: "rtm";
     /// RTM, Intel (Restricted Transactional Memory)
-    rtm,
 }
diff --git a/library/stdarch/crates/std_detect/src/detect/macros.rs b/library/stdarch/crates/std_detect/src/detect/macros.rs
new file mode 100644
index 00000000000..09f9f524b52
--- /dev/null
+++ b/library/stdarch/crates/std_detect/src/detect/macros.rs
@@ -0,0 +1,74 @@
+macro_rules! features {
+    (
+      @TARGET: $target:ident;
+      @MACRO_NAME: $macro_name:ident;
+      @MACRO_ATTRS: $(#[$macro_attrs:meta])*
+      $(@BIND_FEATURE_NAME: $bind_feature:tt; $feature_impl:tt; )*
+      $(@NO_RUNTIME_DETECTION: $nort_feature:tt; )*
+      $(@FEATURE: $feature:ident: $feature_lit:tt; $(#[$feature_comment:meta])*)*
+    ) => {
+        #[macro_export]
+        $(#[$macro_attrs])*
+        #[allow_internal_unstable(stdsimd_internal,stdsimd)]
+        macro_rules! $macro_name {
+            $(
+                ($feature_lit) => {
+                    cfg!(target_feature = $feature_lit) ||
+                        $crate::detect::check_for($crate::detect::Feature::$feature)
+                };
+            )*
+            $(
+                ($bind_feature) => { $macro_name!($feature_impl); };
+            )*
+            $(
+                ($nort_feature) => {
+                    compile_error!(
+                        concat!(
+                            stringify!(nort_feature),
+                            " feature cannot be detected at run-time"
+                        )
+                    )
+                };
+            )*
+            ($t:tt,) => {
+                    $macro_name!($t);
+            };
+            ($t:tt) => {
+                compile_error!(
+                    concat!(
+                        concat!("unknown ", stringify!($target)),
+                        concat!(" target feature: ", $t)
+                    )
+                )
+            };
+        }
+
+        /// Each variant denotes a position in a bitset for a particular feature.
+        ///
+        /// PLEASE: do not use this, it is an implementation detail subject
+        /// to change.
+        #[doc(hidden)]
+        #[allow(non_camel_case_types)]
+        #[derive(Copy, Clone)]
+        #[repr(u8)]
+        #[unstable(feature = "stdsimd_internal", issue = "0")]
+        pub enum Feature {
+            $(
+                $(#[$feature_comment])*
+                $feature,
+            )*
+
+            // Do not add variants after last:
+            _last
+        }
+
+        impl Feature {
+            pub fn to_str(self) -> &'static str {
+                match self {
+                    $(Feature::$feature => $feature_lit,)*
+                    Feature::_last => unreachable!(),
+                }
+            }
+        }
+    };
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs
index 3e00c205547..21062782b71 100644
--- a/library/stdarch/crates/std_detect/src/detect/mod.rs
+++ b/library/stdarch/crates/std_detect/src/detect/mod.rs
@@ -20,6 +20,9 @@
 #[macro_use]
 mod error_macros;
 
+#[macro_use]
+mod macros;
+
 cfg_if! {
     if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
         #[path = "arch/x86.rs"]
@@ -96,3 +99,36 @@ cfg_if! {
 pub fn check_for(x: Feature) -> bool {
     cache::test(x as u32, self::os::detect_features)
 }
+
+/// Returns an `Iterator<Item=(&'static str, bool)>` where
+/// `Item.0` is the feature name, and `Item.1` is a `bool` which
+/// is `true` if the feature is supported by the host and `false` otherwise.
+#[unstable(feature = "stdsimd", issue = "27731")]
+pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
+    cfg_if! {
+        if #[cfg(any(
+            target_arch = "x86",
+            target_arch = "x86_64",
+            target_arch = "arm",
+            target_arch = "aarch64",
+            target_arch = "powerpc",
+            target_arch = "powerpc64",
+            target_arch = "mips",
+            target_arch = "mips64",
+        ))] {
+            fn impl_() -> impl Iterator<Item=(&'static str, bool)> {
+                (0_u8..Feature::_last as u8).map(|discriminant: u8| {
+                    let f: Feature = unsafe { crate::mem::transmute(discriminant) };
+                    let name: &'static str = f.to_str();
+                    let enabled: bool = check_for(f);
+                    (name, enabled)
+                })
+            }
+        } else {
+            fn impl_() -> impl Iterator<Item=(&'static str, bool)> {
+                (0_u8..0_u8).map(|_x: u8| ("", false))
+            }
+        }
+    }
+    impl_()
+}
diff --git a/library/stdarch/crates/std_detect/src/detect/os/x86.rs b/library/stdarch/crates/std_detect/src/detect/os/x86.rs
index d9d286071a2..6daeb2d1a1e 100644
--- a/library/stdarch/crates/std_detect/src/detect/os/x86.rs
+++ b/library/stdarch/crates/std_detect/src/detect/os/x86.rs
@@ -126,7 +126,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
         enable(proc_info_edx, 26, Feature::sse2);
         enable(extended_features_ebx, 29, Feature::sha);
 
-        enable(extended_features_ebx, 3, Feature::bmi);
+        enable(extended_features_ebx, 3, Feature::bmi1);
         enable(extended_features_ebx, 8, Feature::bmi2);
 
         // `XSAVE` and `AVX` support:
@@ -203,17 +203,17 @@ pub(crate) fn detect_features() -> cache::Initializer {
                     if os_avx512_support {
                         enable(extended_features_ebx, 16, Feature::avx512f);
                         enable(extended_features_ebx, 17, Feature::avx512dq);
-                        enable(extended_features_ebx, 21, Feature::avx512_ifma);
+                        enable(extended_features_ebx, 21, Feature::avx512ifma);
                         enable(extended_features_ebx, 26, Feature::avx512pf);
                         enable(extended_features_ebx, 27, Feature::avx512er);
                         enable(extended_features_ebx, 28, Feature::avx512cd);
                         enable(extended_features_ebx, 30, Feature::avx512bw);
                         enable(extended_features_ebx, 31, Feature::avx512vl);
-                        enable(extended_features_ecx, 1, Feature::avx512_vbmi);
+                        enable(extended_features_ecx, 1, Feature::avx512vbmi);
                         enable(
                             extended_features_ecx,
                             14,
-                            Feature::avx512_vpopcntdq,
+                            Feature::avx512vpopcntdq,
                         );
                     }
                 }
@@ -227,7 +227,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
         //
         // The `is_x86_feature_detected!("lzcnt")` macro then
         // internally maps to Feature::abm.
-        enable(extended_proc_info_ecx, 5, Feature::abm);
+        enable(extended_proc_info_ecx, 5, Feature::lzcnt);
+
         // As Hygon Dhyana originates from AMD technology and shares most of the architecture with
         // AMD's family 17h, but with different CPU Vendor ID("HygonGenuine")/Family series
         // number(Family 18h).
diff --git a/library/stdarch/crates/std_detect/tests/cpu-detection.rs b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
index d0c9901c4cd..d441f4e1eff 100644
--- a/library/stdarch/crates/std_detect/tests/cpu-detection.rs
+++ b/library/stdarch/crates/std_detect/tests/cpu-detection.rs
@@ -1,7 +1,6 @@
 #![feature(stdsimd)]
 #![allow(clippy::option_unwrap_used, clippy::use_debug, clippy::print_stdout)]
-
-#[cfg(any(
+#![cfg(any(
     target_arch = "arm",
     target_arch = "aarch64",
     target_arch = "x86",
@@ -9,10 +8,18 @@
     target_arch = "powerpc",
     target_arch = "powerpc64"
 ))]
+
 #[macro_use]
 extern crate std_detect;
 
 #[test]
+fn all() {
+    for (f, e) in std_detect::detect::features() {
+        println!("{}: {}", f, e);
+    }
+}
+
+#[test]
 #[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
 fn arm_linux() {
     println!("neon: {}", is_arm_feature_detected!("neon"));
@@ -73,17 +80,17 @@ fn x86_all() {
     println!("sha: {:?}", is_x86_feature_detected!("sha"));
     println!("avx: {:?}", is_x86_feature_detected!("avx"));
     println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
-    println!("avx512f {:?}", is_x86_feature_detected!("avx512f"));
-    println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd"));
-    println!("avx512er {:?}", is_x86_feature_detected!("avx512er"));
-    println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf"));
-    println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw"));
-    println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq"));
-    println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl"));
-    println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma"));
-    println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi"));
+    println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
+    println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd"));
+    println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
+    println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
+    println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw"));
+    println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
+    println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
+    println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
+    println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
     println!(
-        "avx512_vpopcntdq {:?}",
+        "avx512vpopcntdq: {:?}",
         is_x86_feature_detected!("avx512vpopcntdq")
     );
     println!("f16c: {:?}", is_x86_feature_detected!("f16c"));