[arm] runtime-detection support

This commit is contained in:
gnzlbg
2017-10-26 22:00:03 +02:00
committed by gnzlbg
parent fe7da57403
commit ceef91aaba
16 changed files with 535 additions and 106 deletions
@@ -8,6 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
qemu-user \
make \
file
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -L /usr/aarch64-linux-gnu" \
OBJDUMP=aarch64-linux-gnu-objdump
+2 -1
View File
@@ -4,10 +4,11 @@
set -ex
run() {
echo $1
echo "Building docker container for TARGET=${1}"
docker build -t stdsimd ci/docker/$1
mkdir -p target
target=$(echo $1 | sed 's/-emulated//')
echo "Running docker"
docker run \
--user `id -u`:`id -g` \
--rm \
+5 -4
View File
@@ -20,9 +20,10 @@ FEATURES_STD="${FEATURES},std"
echo "RUSTFLAGS=${RUSTFLAGS}"
echo "FEATURES=${FEATURES}"
echo "OBJDUMP=${OBJDUMP}"
cargo test --target $TARGET --features $FEATURES
cargo test --release --target $TARGET --features $FEATURES
cargo test --target $TARGET --features $FEATURES --verbose -- --nocapture
cargo test --release --target $TARGET --features $FEATURES --verbose -- --nocapture
cargo test --target $TARGET --features $FEATURES_STD
cargo test --release --target $TARGET --features $FEATURES_STD
cargo test --target $TARGET --features $FEATURES_STD --verbose -- --nocapture
cargo test --release --target $TARGET --features $FEATURES_STD --verbose -- --nocapture
+21 -1
View File
@@ -159,8 +159,29 @@ pub mod vendor {
pub use aarch64::*;
pub use nvptx::*;
#[cfg(any(
// x86/x86_64:
any(target_arch = "x86", target_arch = "x86_64"),
// linux + std + (arm|aarch64):
all(target_os = "linux",
feature = "std",
any(target_arch = "arm", target_arch = "aarch64"))
))]
pub use runtime::{__unstable_detect_feature, __Feature};
}
#[cfg(any(
// x86/x86_64:
any(target_arch = "x86", target_arch = "x86_64"),
// linux + std + (arm|aarch64):
all(target_os = "linux",
feature = "std",
any(target_arch = "arm", target_arch = "aarch64"))
))]
#[macro_use]
mod runtime;
#[macro_use]
mod macros;
mod simd_llvm;
@@ -204,7 +225,6 @@ mod v16 {
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[macro_use]
mod x86;
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
-50
View File
@@ -373,56 +373,6 @@ pub fn $cast(self) -> ::simd::$toty {
}
}
/// Is a feature supported by the host CPU?
///
/// This macro performs run-time feature detection. It returns true if the host
/// CPU in which the binary is running on supports a particular feature.
#[macro_export]
macro_rules! cfg_feature_enabled {
($name:tt) => (
{
#[cfg(target_feature = $name)]
{
true
}
#[cfg(not(target_feature = $name))]
{
__unstable_detect_feature!($name)
}
}
)
}
/// On ARM features are only detected at compile-time using
/// cfg(target_feature), so if this macro is executed the
/// feature is not supported.
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
("neon") => { false };
($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}
/// In all unsupported architectures using the macro is an error
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64",
target_arch = "arm", target_arch = "aarch64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}
#[cfg(test)]
mod tests {
#[cfg(target_arch = "x86_64")]
#[test]
fn test_macros() {
assert!(cfg_feature_enabled!("sse"));
}
}
#[cfg(test)]
#[macro_export]
macro_rules! test_arithmetic_ {
+56
View File
@@ -0,0 +1,56 @@
//! Run-time feature detection on ARM Aarch64.
use super::{bit, linux};
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
("neon") => {
// FIXME: this should be removed once we rename Aarch64 neon to asimd
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::asimd{})
};
("asimd") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::asimd{})
};
("pmull") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::pmull{})
};
($t:tt) => { compile_error!(concat!("unknown arm 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)]
pub enum __Feature {
/// ARM Advanced SIMD (ASIMD) - Aarch64
asimd,
/// Polynomial Multiply
pmull,
}
pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
let value: usize = 0;
{
let mut enable_feature = |f| {
if x.has_feature(&f) {
bit::set(value, f as u32);
}
};
enable_feature(__Feature::asimd);
enable_feature(__Feature::pmull);
}
value
}
impl linux::FeatureQuery for linux::CpuInfo {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;
match *x {
asimd => self.field("Features").has("asimd"),
pmull => self.field("Features").has("pmull"),
}
}
}
+66
View File
@@ -0,0 +1,66 @@
//! Run-time feature detection on ARM Aarch32.
use super::{bit, linux};
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
("neon") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::neon{})
};
("pmull") => {
$crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::pmull{})
};
($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)]
pub enum __Feature {
/// ARM Advanced SIMD (NEON) - Aarch32
neon,
/// Polynomial Multiply
pmull,
}
pub fn detect_features<T: linux::FeatureQuery>(mut x: T) -> usize {
let value: usize = 0;
{
let mut enable_feature = |f| {
if x.has_feature(&f) {
bit::set(value, f as u32);
}
};
enable_feature(__Feature::neon);
enable_feature(__Feature::pmull);
}
value
}
/// Is the CPU known to have a broken NEON unit?
///
/// See https://crbug.com/341598.
fn has_broken_neon(cpuinfo: &linux::CpuInfo) -> bool {
cpuinfo.field("CPU implementer") == "0x51"
&& cpuinfo.field("CPU architecture") == "7"
&& cpuinfo.field("CPU variant") == "0x1"
&& cpuinfo.field("CPU part") == "0x04d"
&& cpuinfo.field("CPU revision") == "0"
}
impl linux::FeatureQuery for linux::CpuInfo {
fn has_feature(&mut self, x: &__Feature) -> bool {
use self::__Feature::*;
match *x {
neon => {
self.field("Features").has("neon") && !has_broken_neon(self)
}
pmull => self.field("Features").has("pmull"),
}
}
}
+11
View File
@@ -0,0 +1,11 @@
//! Bit manipulation utilities
/// Sets the `bit` of `x`.
pub const fn set(x: usize, bit: u32) -> usize {
x | 1 << bit
}
/// Tests the `bit` of `x`.
pub const fn test(x: usize, bit: u32) -> bool {
x & (1 << bit) != 0
}
+29
View File
@@ -0,0 +1,29 @@
//! Cache of run-time feature detection
use super::bit;
use std::sync::atomic::{AtomicUsize, Ordering};
/// This global variable is a bitset used to cache the features supported by
/// the
/// CPU.
static CACHE: AtomicUsize = AtomicUsize::new(::std::usize::MAX);
/// Test the `bit` of the storage. If the storage has not been initialized,
/// initializes it with the result of `f()`.
///
/// On its first invocation, it detects the CPU features and caches them in the
/// `FEATURES` global variable as an `AtomicUsize`.
///
/// It uses the `__Feature` variant to index into this variable as a bitset. If
/// the bit is set, the feature is enabled, and otherwise it is disabled.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
pub fn test<F>(bit: u32, f: F) -> bool
where
F: FnOnce() -> usize,
{
if CACHE.load(Ordering::Relaxed) == ::std::usize::MAX {
CACHE.store(f(), Ordering::Relaxed);
}
bit::test(CACHE.load(Ordering::Relaxed), bit)
}
@@ -0,0 +1,211 @@
//! Reads /proc/cpuinfo on Linux systems
/// cpuinfo
pub struct CpuInfo {
raw: String,
}
/// Field of cpuinfo
#[derive(Debug)]
pub struct CpuInfoField<'a>(Option<&'a str>);
impl<'a> PartialEq<&'a str> for CpuInfoField<'a> {
fn eq(&self, other: &&'a str) -> bool {
match self.0 {
None => other.len() == 0,
Some(f) => f == other.trim(),
}
}
}
impl<'a> CpuInfoField<'a> {
pub fn new<'b>(v: Option<&'b str>) -> CpuInfoField<'b> {
match v {
None => CpuInfoField::<'b>(None),
Some(f) => CpuInfoField::<'b>(Some(f.trim())),
}
}
/// Does the field exist?
pub fn exists(&self) -> bool {
self.0.is_some()
}
/// Does the field contain `other`?
pub fn has(&self, other: &str) -> bool {
match self.0 {
None => other.len() == 0,
Some(f) => {
let other = other.trim();
for v in f.split(" ") {
if v == other {
return true;
}
}
false
}
}
}
}
impl CpuInfo {
/// Reads /proc/cpuinfo into CpuInfo.
pub fn new() -> Result<CpuInfo, ::std::io::Error> {
use std::io::Read;
let mut file = ::std::fs::File::open("/proc/cpuinfo")?;
let mut cpui = CpuInfo { raw: String::new() };
file.read_to_string(&mut cpui.raw)?;
Ok(cpui)
}
/// Returns the value of the cpuinfo `field`.
pub fn field(&self, field: &str) -> CpuInfoField {
for l in self.raw.lines() {
if l.trim().starts_with(field) {
return CpuInfoField(l.split(": ").skip(1).next());
}
}
CpuInfoField(None)
}
/// Returns the `raw` contents of `/proc/cpuinfo`
fn raw(&self) -> &String {
&self.raw
}
fn from_str(other: &str) -> Result<CpuInfo, ::std::io::Error> {
Ok(CpuInfo {
raw: String::from(other),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "linux")]
#[test]
fn test_cpuinfo_linux() {
let cpuinfo = CpuInfo::new().unwrap();
if cpuinfo.field("vendor_id") == "GenuineIntel" {
assert!(cpuinfo.field("flags").exists());
assert!(!cpuinfo.field("vendor33_id").exists());
assert!(cpuinfo.field("flags").has("sse"));
assert!(!cpuinfo.field("flags").has("avx314"));
}
println!("{}", cpuinfo.raw());
}
const CORE_DUO_T6500: &str = r"processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 23
model name : Intel(R) Core(TM)2 Duo CPU T6500 @ 2.10GHz
stepping : 10
microcode : 0xa0b
cpu MHz : 1600.000
cache size : 2048 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm dtherm
bogomips : 4190.43
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
";
#[test]
fn test_cpuinfo_linux_core_duo_t6500() {
let cpuinfo = CpuInfo::from_str(CORE_DUO_T6500).unwrap();
assert_eq!(cpuinfo.field("vendor_id"), "GenuineIntel");
assert_eq!(cpuinfo.field("cpu family"), "6");
assert_eq!(cpuinfo.field("model"), "23");
assert_eq!(
cpuinfo.field("model name"),
"Intel(R) Core(TM)2 Duo CPU T6500 @ 2.10GHz"
);
assert_eq!(
cpuinfo.field("flags"),
"fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm sse4_1 xsave lahf_lm dtherm"
);
assert!(cpuinfo.field("flags").has("fpu"));
assert!(cpuinfo.field("flags").has("dtherm"));
assert!(cpuinfo.field("flags").has("sse2"));
assert!(!cpuinfo.field("flags").has("avx"));
}
const ARM_CORTEX_A53: &str = r"Processor : AArch64 Processor rev 3 (aarch64)
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: AArch64
CPU variant : 0x0
CPU part : 0xd03
CPU revision : 3
Hardware : HiKey Development Board
";
#[test]
fn test_cpuinfo_linux_arm_cortex_a53() {
let cpuinfo = CpuInfo::from_str(ARM_CORTEX_A53).unwrap();
assert_eq!(
cpuinfo.field("Processor"),
"AArch64 Processor rev 3 (aarch64)"
);
assert_eq!(
cpuinfo.field("Features"),
"fp asimd evtstrm aes pmull sha1 sha2 crc32"
);
assert!(cpuinfo.field("Features").has("pmull"));
assert!(!cpuinfo.field("Features").has("neon"));
assert!(cpuinfo.field("Features").has("asimd"));
}
const ARM_CORTEX_A57: &str = r"Processor : Cortex A57 Processor rev 1 (aarch64)
processor : 0
processor : 1
processor : 2
processor : 3
Features : fp asimd aes pmull sha1 sha2 crc32 wp half thumb fastmult vfp edsp neon vfpv3 tlsi vfpv4 idiva idivt
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd07
CPU revision : 1";
#[test]
fn test_cpuinfo_linux_arm_cortex_a57() {
let cpuinfo = CpuInfo::from_str(ARM_CORTEX_A57).unwrap();
assert_eq!(
cpuinfo.field("Processor"),
"Cortex A57 Processor rev 1 (aarch64)"
);
assert_eq!(
cpuinfo.field("Features"),
"fp asimd aes pmull sha1 sha2 crc32 wp half thumb fastmult vfp edsp neon vfpv3 tlsi vfpv4 idiva idivt"
);
assert!(cpuinfo.field("Features").has("pmull"));
assert!(cpuinfo.field("Features").has("neon"));
assert!(cpuinfo.field("Features").has("asimd"));
}
}
+31
View File
@@ -0,0 +1,31 @@
//! Run-time feature detection for ARM on linux
mod cpuinfo;
pub use self::cpuinfo::CpuInfo;
use super::__Feature;
pub trait FeatureQuery {
fn has_feature(&mut self, x: &__Feature) -> bool;
}
fn detect_features_impl<T: FeatureQuery>(x: T) -> usize {
#[cfg(target_arch = "arm")]
{
super::arm::detect_features(x)
}
#[cfg(target_arch = "aarch64")]
{
super::aarch64::detect_features(x)
}
}
/// Detects ARM features:
pub fn detect_features() -> usize {
// FIXME: use libc::getauxval, and if that fails /proc/auxv
// Try to read /proc/cpuinfo
if let Ok(v) = cpuinfo::CpuInfo::new() {
return detect_features_impl(v);
}
// Otherwise all features are disabled
0
}
+39
View File
@@ -0,0 +1,39 @@
//! Run-time feature detection macros.
/// Is a feature supported by the host CPU?
///
/// This macro performs run-time feature detection. It returns true if the host
/// CPU in which the binary is running on supports a particular feature.
#[macro_export]
macro_rules! cfg_feature_enabled {
($name:tt) => (
{
#[cfg(target_feature = $name)]
{
true
}
#[cfg(not(target_feature = $name))]
{
__unstable_detect_feature!($name)
}
}
)
}
/// In all unsupported architectures using the macro is an error
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64",
target_arch = "arm", target_arch = "aarch64")))]
#[macro_export]
#[doc(hidden)]
macro_rules! __unstable_detect_feature {
($t:tt) => { compile_error!(concat!("unknown target feature: ", $t)) };
}
#[cfg(test)]
mod tests {
#[cfg(target_arch = "x86_64")]
#[test]
fn test_macros() {
assert!(cfg_feature_enabled!("sse"));
}
}
+40
View File
@@ -0,0 +1,40 @@
//! Run-time feature detection
mod cache;
mod bit;
#[macro_use]
mod macros;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[macro_use]
mod x86;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub use self::x86::__Feature;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use self::x86::detect_features;
#[cfg(all(target_arch = "arm", target_os = "linux", feature = "std"))]
#[macro_use]
mod arm;
#[cfg(all(target_arch = "arm", target_os = "linux", feature = "std"))]
pub use self::arm::__Feature;
#[cfg(all(target_arch = "aarch64", target_os = "linux", feature = "std"))]
#[macro_use]
mod aarch64;
#[cfg(all(target_arch = "aarch64", target_os = "linux", feature = "std"))]
pub use self::aarch64::__Feature;
#[cfg(all(feature = "std", target_os = "linux",
any(target_arch = "arm", target_arch = "aarch64")))]
mod linux;
#[cfg(all(feature = "std", target_os = "linux",
any(target_arch = "arm", target_arch = "aarch64")))]
pub use self::linux::detect_features;
/// Performs run-time feature detection.
#[doc(hidden)]
pub fn __unstable_detect_feature(x: __Feature) -> bool {
cache::test(x as u32, detect_features)
}
@@ -15,7 +15,8 @@
//! this functions queries the CPU for the available features and stores them
//! in a global `AtomicUsize` variable. The query is performed by just checking
//! whether the feature bit in this global variable is set or cleared.
use std::sync::atomic::{AtomicUsize, Ordering};
use super::bit;
/// This macro maps the string-literal feature names to values of the
/// `__Feature` enum at compile-time. The feature names used are the same as
@@ -228,18 +229,6 @@ pub enum __Feature {
#[doc(hidden)] __NonExhaustive,
}
/// Sets the `bit`-th bit of `x`.
fn set_bit(x: usize, bit: u32) -> usize {
debug_assert!(32 > bit);
x | 1 << bit
}
/// Tests the `bit`-th bit of `x`.
fn test_bit(x: usize, bit: u32) -> bool {
debug_assert!(32 > bit);
x & (1 << bit) != 0
}
/// Run-time feature detection on x86 works by using the CPUID instruction.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains
@@ -255,9 +244,9 @@ fn test_bit(x: usize, bit: u32) -> bool {
/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
fn detect_features() -> usize {
use super::cpuid::{__cpuid, __cpuid_count, has_cpuid, CpuidResult};
use super::xsave::_xgetbv;
pub fn detect_features() -> usize {
use vendor::{__cpuid, __cpuid_count, has_cpuid, CpuidResult};
use vendor::_xgetbv;
let mut value: usize = 0;
// If the x86 CPU does not support the CPUID instruction then it is too
@@ -331,8 +320,8 @@ fn detect_features() -> usize {
{
// borrows value till the end of this scope:
let mut enable = |r, rb, f| if test_bit(r as usize, rb) {
value = set_bit(value, f as u32);
let mut enable = |r, rb, f| if bit::test(r as usize, rb) {
value = bit::set(value, f as u32);
};
enable(proc_info_ecx, 0, __Feature::sse3);
@@ -348,7 +337,7 @@ fn detect_features() -> usize {
enable(extended_features_ebx, 8, __Feature::bmi2);
// `XSAVE` and `AVX` support:
if test_bit(proc_info_ecx as usize, 26) {
if bit::test(proc_info_ecx as usize, 26) {
// 0. Here the CPU supports `XSAVE`.
// 1. Detect `OSXSAVE`, that is, whether the OS is AVX enabled and
@@ -359,7 +348,7 @@ fn detect_features() -> usize {
// com/en-us/blogs/2011/04/14/is-avx-enabled
// - https://hg.mozilla.
// org/mozilla-central/file/64bab5cbb9b6/mozglue/build/SSE.cpp#l190
let cpu_osxsave = test_bit(proc_info_ecx as usize, 27);
let cpu_osxsave = bit::test(proc_info_ecx as usize, 27);
// 2. The OS must have signaled the CPU that it supports saving and
// restoring the SSE and AVX registers by setting `XCR0.SSE[1]` and
@@ -431,27 +420,6 @@ fn detect_features() -> usize {
value
}
/// This global variable is a bitset used to cache the features supported by
/// the CPU.
static FEATURES: AtomicUsize = AtomicUsize::new(::std::usize::MAX);
/// Performs run-time feature detection.
///
/// On its first invocation, it detects the CPU features and caches them
/// in the `FEATURES` global variable as an `AtomicUsize`.
///
/// It uses the `__Feature` variant to index into this variable as a bitset. If
/// the bit is set, the feature is enabled, and otherwise it is disabled.
///
/// PLEASE: do not use this, it is an implementation detail subject to change.
#[doc(hidden)]
pub fn __unstable_detect_feature(x: __Feature) -> bool {
if FEATURES.load(Ordering::Relaxed) == ::std::usize::MAX {
FEATURES.store(detect_features(), Ordering::Relaxed);
}
test_bit(FEATURES.load(Ordering::Relaxed), x as u32)
}
#[cfg(test)]
mod tests {
#[cfg(feature = "std")]
-4
View File
@@ -20,8 +20,6 @@
#[cfg(not(feature = "intel_sde"))]
pub use self::tbm::*;
pub use self::runtime::{__unstable_detect_feature, __Feature};
/// 128-bit wide signed integer vector type
#[allow(non_camel_case_types)]
pub type __m128i = ::v128::i8x16;
@@ -31,8 +29,6 @@
#[macro_use]
mod macros;
#[macro_use]
mod runtime;
mod ia32;
mod cpuid;
+14 -5
View File
@@ -27,9 +27,12 @@ fn works() {
// assert_eq!(cfg_feature_enabled!("avx512bw"), information.avx512bw());
// assert_eq!(cfg_feature_enabled!("avx512dq"), information.avx512dq());
// assert_eq!(cfg_feature_enabled!("avx512vl"), information.avx512vl());
// assert_eq!(cfg_feature_enabled!("avx512ifma"), information.avx512ifma());
// assert_eq!(cfg_feature_enabled!("avx512vbmi"), information.avx512vbmi());
// assert_eq!(cfg_feature_enabled!("avx512vpopcntdq"), information.avx512vpopcntdq());
// assert_eq!(cfg_feature_enabled!("avx512ifma"),
// information.avx512_ifma());
// assert_eq!(cfg_feature_enabled!("avx512vbmi"),
// information.avx512_vbmi());
// assert_eq!(cfg_feature_enabled!("avx512vpopcntdq"),
// information.avx512_vpopcntdq());
assert_eq!(cfg_feature_enabled!("fma"), information.fma());
assert_eq!(cfg_feature_enabled!("bmi"), information.bmi1());
assert_eq!(cfg_feature_enabled!("bmi2"), information.bmi2());
@@ -40,6 +43,12 @@ fn works() {
assert_eq!(cfg_feature_enabled!("lzcnt"), information.lzcnt());
assert_eq!(cfg_feature_enabled!("xsave"), information.xsave());
assert_eq!(cfg_feature_enabled!("xsaveopt"), information.xsaveopt());
assert_eq!(cfg_feature_enabled!("xsavec"), information.xsavec_and_xrstor());
assert_eq!(cfg_feature_enabled!("xsavec"), information.xsaves_xrstors_and_ia32_xss());
assert_eq!(
cfg_feature_enabled!("xsavec"),
information.xsavec_and_xrstor()
);
assert_eq!(
cfg_feature_enabled!("xsavec"),
information.xsaves_xrstors_and_ia32_xss()
);
}