summaryrefslogtreecommitdiffstats
path: root/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rustfmt/tests/target/cfg_if/detect/os/linux')
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/aarch64.rs160
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/arm.rs52
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/auxvec.rs304
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/cpuinfo.rs300
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mips.rs31
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mod.rs28
-rw-r--r--src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/powerpc.rs41
7 files changed, 916 insertions, 0 deletions
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/aarch64.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/aarch64.rs
new file mode 100644
index 000000000..8d874f228
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/aarch64.rs
@@ -0,0 +1,160 @@
+//! Run-time feature detection for Aarch64 on Linux.
+
+use super::{auxvec, cpuinfo};
+use crate::detect::{bit, cache, Feature};
+
+/// Performs run-time feature detection.
+#[inline]
+pub fn check_for(x: Feature) -> bool {
+ cache::test(x as u32, detect_features)
+}
+
+/// Try to read the features from the auxiliary vector, and if that fails, try
+/// to read them from /proc/cpuinfo.
+fn detect_features() -> cache::Initializer {
+ if let Ok(auxv) = auxvec::auxv() {
+ let hwcap: AtHwcap = auxv.into();
+ return hwcap.cache();
+ }
+ if let Ok(c) = cpuinfo::CpuInfo::new() {
+ let hwcap: AtHwcap = c.into();
+ return hwcap.cache();
+ }
+ cache::Initializer::default()
+}
+
+/// These values are part of the platform-specific [asm/hwcap.h][hwcap] .
+///
+/// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
+struct AtHwcap {
+ fp: bool, // 0
+ asimd: bool, // 1
+ // evtstrm: bool, // 2
+ aes: bool, // 3
+ pmull: bool, // 4
+ sha1: bool, // 5
+ sha2: bool, // 6
+ crc32: bool, // 7
+ atomics: bool, // 8
+ fphp: bool, // 9
+ asimdhp: bool, // 10
+ // cpuid: bool, // 11
+ asimdrdm: bool, // 12
+ // jscvt: bool, // 13
+ // fcma: bool, // 14
+ lrcpc: bool, // 15
+ // dcpop: bool, // 16
+ // sha3: bool, // 17
+ // sm3: bool, // 18
+ // sm4: bool, // 19
+ asimddp: bool, // 20
+ // sha512: bool, // 21
+ sve: bool, // 22
+}
+
+impl From<auxvec::AuxVec> for AtHwcap {
+ /// Reads AtHwcap from the auxiliary vector.
+ fn from(auxv: auxvec::AuxVec) -> Self {
+ AtHwcap {
+ fp: bit::test(auxv.hwcap, 0),
+ asimd: bit::test(auxv.hwcap, 1),
+ // evtstrm: bit::test(auxv.hwcap, 2),
+ aes: bit::test(auxv.hwcap, 3),
+ pmull: bit::test(auxv.hwcap, 4),
+ sha1: bit::test(auxv.hwcap, 5),
+ sha2: bit::test(auxv.hwcap, 6),
+ crc32: bit::test(auxv.hwcap, 7),
+ atomics: bit::test(auxv.hwcap, 8),
+ fphp: bit::test(auxv.hwcap, 9),
+ asimdhp: bit::test(auxv.hwcap, 10),
+ // cpuid: bit::test(auxv.hwcap, 11),
+ asimdrdm: bit::test(auxv.hwcap, 12),
+ // jscvt: bit::test(auxv.hwcap, 13),
+ // fcma: bit::test(auxv.hwcap, 14),
+ lrcpc: bit::test(auxv.hwcap, 15),
+ // dcpop: bit::test(auxv.hwcap, 16),
+ // sha3: bit::test(auxv.hwcap, 17),
+ // sm3: bit::test(auxv.hwcap, 18),
+ // sm4: bit::test(auxv.hwcap, 19),
+ asimddp: bit::test(auxv.hwcap, 20),
+ // sha512: bit::test(auxv.hwcap, 21),
+ sve: bit::test(auxv.hwcap, 22),
+ }
+ }
+}
+
+impl From<cpuinfo::CpuInfo> for AtHwcap {
+ /// Reads AtHwcap from /proc/cpuinfo .
+ fn from(c: cpuinfo::CpuInfo) -> Self {
+ let f = &c.field("Features");
+ AtHwcap {
+ // 64-bit names. FIXME: In 32-bit compatibility mode /proc/cpuinfo will
+ // map some of the 64-bit names to some 32-bit feature names. This does not
+ // cover that yet.
+ fp: f.has("fp"),
+ asimd: f.has("asimd"),
+ // evtstrm: f.has("evtstrm"),
+ aes: f.has("aes"),
+ pmull: f.has("pmull"),
+ sha1: f.has("sha1"),
+ sha2: f.has("sha2"),
+ crc32: f.has("crc32"),
+ atomics: f.has("atomics"),
+ fphp: f.has("fphp"),
+ asimdhp: f.has("asimdhp"),
+ // cpuid: f.has("cpuid"),
+ asimdrdm: f.has("asimdrdm"),
+ // jscvt: f.has("jscvt"),
+ // fcma: f.has("fcma"),
+ lrcpc: f.has("lrcpc"),
+ // dcpop: f.has("dcpop"),
+ // sha3: f.has("sha3"),
+ // sm3: f.has("sm3"),
+ // sm4: f.has("sm4"),
+ asimddp: f.has("asimddp"),
+ // sha512: f.has("sha512"),
+ sve: f.has("sve"),
+ }
+ }
+}
+
+impl AtHwcap {
+ /// Initializes the cache from the feature -bits.
+ ///
+ /// The features are enabled approximately like in LLVM host feature detection:
+ /// https://github.com/llvm-mirror/llvm/blob/master/lib/Support/Host.cpp#L1273
+ fn cache(self) -> cache::Initializer {
+ let mut value = cache::Initializer::default();
+ {
+ let mut enable_feature = |f, enable| {
+ if enable {
+ value.set(f as u32);
+ }
+ };
+
+ enable_feature(Feature::fp, self.fp);
+ // Half-float support requires float support
+ enable_feature(Feature::fp16, self.fp && self.fphp);
+ enable_feature(Feature::pmull, self.pmull);
+ enable_feature(Feature::crc, self.crc32);
+ enable_feature(Feature::lse, self.atomics);
+ enable_feature(Feature::rcpc, self.lrcpc);
+
+ // SIMD support requires float support - if half-floats are
+ // supported, it also requires half-float support:
+ let asimd = self.fp && self.asimd && (!self.fphp | self.asimdhp);
+ enable_feature(Feature::asimd, asimd);
+ // SIMD extensions require SIMD support:
+ enable_feature(Feature::rdm, self.asimdrdm && asimd);
+ enable_feature(Feature::dotprod, self.asimddp && asimd);
+ enable_feature(Feature::sve, self.sve && asimd);
+
+ // Crypto is specified as AES + PMULL + SHA1 + SHA2 per LLVM/hosts.cpp
+ enable_feature(
+ Feature::crypto,
+ self.aes && self.pmull && self.sha1 && self.sha2,
+ );
+ }
+ value
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/arm.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/arm.rs
new file mode 100644
index 000000000..9c89500cc
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/arm.rs
@@ -0,0 +1,52 @@
+//! Run-time feature detection for ARM on Linux.
+
+use super::{auxvec, cpuinfo};
+use crate::detect::{bit, cache, Feature};
+
+/// Performs run-time feature detection.
+#[inline]
+pub fn check_for(x: Feature) -> bool {
+ cache::test(x as u32, detect_features)
+}
+
+/// Try to read the features from the auxiliary vector, and if that fails, try
+/// to read them from /proc/cpuinfo.
+fn detect_features() -> cache::Initializer {
+ let mut value = cache::Initializer::default();
+ let enable_feature = |value: &mut cache::Initializer, f, enable| {
+ if enable {
+ value.set(f as u32);
+ }
+ };
+
+ // The values are part of the platform-specific [asm/hwcap.h][hwcap]
+ //
+ // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
+ if let Ok(auxv) = auxvec::auxv() {
+ enable_feature(&mut value, Feature::neon, bit::test(auxv.hwcap, 12));
+ enable_feature(&mut value, Feature::pmull, bit::test(auxv.hwcap2, 1));
+ return value;
+ }
+
+ if let Ok(c) = cpuinfo::CpuInfo::new() {
+ enable_feature(
+ &mut value,
+ Feature::neon,
+ c.field("Features").has("neon") && !has_broken_neon(&c),
+ );
+ enable_feature(&mut value, Feature::pmull, c.field("Features").has("pmull"));
+ return value;
+ }
+ value
+}
+
+/// Is the CPU known to have a broken NEON unit?
+///
+/// See https://crbug.com/341598.
+fn has_broken_neon(cpuinfo: &cpuinfo::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"
+}
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/auxvec.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/auxvec.rs
new file mode 100644
index 000000000..6ebae67fb
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/auxvec.rs
@@ -0,0 +1,304 @@
+//! Parses ELF auxiliary vectors.
+#![cfg_attr(not(target_arch = "aarch64"), allow(dead_code))]
+
+#[cfg(feature = "std_detect_file_io")]
+use crate::{fs::File, io::Read};
+
+/// Key to access the CPU Hardware capabilities bitfield.
+pub(crate) const AT_HWCAP: usize = 16;
+/// Key to access the CPU Hardware capabilities 2 bitfield.
+#[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+pub(crate) const AT_HWCAP2: usize = 26;
+
+/// Cache HWCAP bitfields of the ELF Auxiliary Vector.
+///
+/// If an entry cannot be read all the bits in the bitfield are set to zero.
+/// This should be interpreted as all the features being disabled.
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct AuxVec {
+ pub hwcap: usize,
+ #[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+ pub hwcap2: usize,
+}
+
+/// ELF Auxiliary Vector
+///
+/// The auxiliary vector is a memory region in a running ELF program's stack
+/// composed of (key: usize, value: usize) pairs.
+///
+/// The keys used in the aux vector are platform dependent. For Linux, they are
+/// defined in [linux/auxvec.h][auxvec_h]. The hardware capabilities of a given
+/// CPU can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys.
+///
+/// There is no perfect way of reading the auxiliary vector.
+///
+/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use
+/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation.
+/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is
+/// linked to the binary - if that is not the case the behavior is undefined.
+/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will
+/// try to read `/proc/self/auxv`.
+/// - If that fails, this function returns an error.
+///
+/// Note that run-time feature detection is not invoked for features that can
+/// be detected at compile-time. Also note that if this function returns an
+/// error, cpuinfo still can (and will) be used to try to perform run-time
+/// feature detecton on some platforms.
+///
+/// For more information about when `getauxval` is available check the great
+/// [`auxv` crate documentation][auxv_docs].
+///
+/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h
+/// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/
+pub(crate) fn auxv() -> Result<AuxVec, ()> {
+ #[cfg(feature = "std_detect_dlsym_getauxval")]
+ {
+ // Try to call a dynamically-linked getauxval function.
+ if let Ok(hwcap) = getauxval(AT_HWCAP) {
+ // Targets with only AT_HWCAP:
+ #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
+ {
+ if hwcap != 0 {
+ return Ok(AuxVec { hwcap });
+ }
+ }
+
+ // Targets with AT_HWCAP and AT_HWCAP2:
+ #[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+ {
+ if let Ok(hwcap2) = getauxval(AT_HWCAP2) {
+ if hwcap != 0 && hwcap2 != 0 {
+ return Ok(AuxVec { hwcap, hwcap2 });
+ }
+ }
+ }
+ drop(hwcap);
+ }
+ #[cfg(feature = "std_detect_file_io")]
+ {
+ // If calling getauxval fails, try to read the auxiliary vector from
+ // its file:
+ auxv_from_file("/proc/self/auxv")
+ }
+ #[cfg(not(feature = "std_detect_file_io"))]
+ {
+ Err(())
+ }
+ }
+
+ #[cfg(not(feature = "std_detect_dlsym_getauxval"))]
+ {
+ let hwcap = unsafe { ffi_getauxval(AT_HWCAP) };
+
+ // Targets with only AT_HWCAP:
+ #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
+ {
+ if hwcap != 0 {
+ return Ok(AuxVec { hwcap });
+ }
+ }
+
+ // Targets with AT_HWCAP and AT_HWCAP2:
+ #[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+ {
+ let hwcap2 = unsafe { ffi_getauxval(AT_HWCAP2) };
+ if hwcap != 0 && hwcap2 != 0 {
+ return Ok(AuxVec { hwcap, hwcap2 });
+ }
+ }
+ }
+}
+
+/// Tries to read the `key` from the auxiliary vector by calling the
+/// dynamically-linked `getauxval` function. If the function is not linked,
+/// this function return `Err`.
+#[cfg(feature = "std_detect_dlsym_getauxval")]
+fn getauxval(key: usize) -> Result<usize, ()> {
+ use libc;
+ pub type F = unsafe extern "C" fn(usize) -> usize;
+ unsafe {
+ let ptr = libc::dlsym(libc::RTLD_DEFAULT, "getauxval\0".as_ptr() as *const _);
+ if ptr.is_null() {
+ return Err(());
+ }
+
+ let ffi_getauxval: F = mem::transmute(ptr);
+ Ok(ffi_getauxval(key))
+ }
+}
+
+/// Tries to read the auxiliary vector from the `file`. If this fails, this
+/// function returns `Err`.
+#[cfg(feature = "std_detect_file_io")]
+fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
+ let mut file = File::open(file).map_err(|_| ())?;
+
+ // See <https://github.com/torvalds/linux/blob/v3.19/include/uapi/linux/auxvec.h>.
+ //
+ // The auxiliary vector contains at most 32 (key,value) fields: from
+ // `AT_EXECFN = 31` to `AT_NULL = 0`. That is, a buffer of
+ // 2*32 `usize` elements is enough to read the whole vector.
+ let mut buf = [0_usize; 64];
+ {
+ let raw: &mut [u8; 64 * mem::size_of::<usize>()] = unsafe { mem::transmute(&mut buf) };
+ file.read(raw).map_err(|_| ())?;
+ }
+ auxv_from_buf(&buf)
+}
+
+/// Tries to interpret the `buffer` as an auxiliary vector. If that fails, this
+/// function returns `Err`.
+#[cfg(feature = "std_detect_file_io")]
+fn auxv_from_buf(buf: &[usize; 64]) -> Result<AuxVec, ()> {
+ // Targets with only AT_HWCAP:
+ #[cfg(any(target_arch = "aarch64", target_arch = "mips", target_arch = "mips64"))]
+ {
+ for el in buf.chunks(2) {
+ match el[0] {
+ AT_HWCAP => return Ok(AuxVec { hwcap: el[1] }),
+ _ => (),
+ }
+ }
+ }
+ // Targets with AT_HWCAP and AT_HWCAP2:
+ #[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+ {
+ let mut hwcap = None;
+ let mut hwcap2 = None;
+ for el in buf.chunks(2) {
+ match el[0] {
+ AT_HWCAP => hwcap = Some(el[1]),
+ AT_HWCAP2 => hwcap2 = Some(el[1]),
+ _ => (),
+ }
+ }
+
+ if let (Some(hwcap), Some(hwcap2)) = (hwcap, hwcap2) {
+ return Ok(AuxVec { hwcap, hwcap2 });
+ }
+ }
+ drop(buf);
+ Err(())
+}
+
+#[cfg(test)]
+mod tests {
+ extern crate auxv as auxv_crate;
+ use super::*;
+
+ // Reads the Auxiliary Vector key from /proc/self/auxv
+ // using the auxv crate.
+ #[cfg(feature = "std_detect_file_io")]
+ fn auxv_crate_getprocfs(key: usize) -> Option<usize> {
+ use self::auxv_crate::procfs::search_procfs_auxv;
+ use self::auxv_crate::AuxvType;
+ let k = key as AuxvType;
+ match search_procfs_auxv(&[k]) {
+ Ok(v) => Some(v[&k] as usize),
+ Err(_) => None,
+ }
+ }
+
+ // Reads the Auxiliary Vector key from getauxval()
+ // using the auxv crate.
+ #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))]
+ fn auxv_crate_getauxval(key: usize) -> Option<usize> {
+ use self::auxv_crate::getauxval::Getauxval;
+ use self::auxv_crate::AuxvType;
+ let q = auxv_crate::getauxval::NativeGetauxval {};
+ match q.getauxval(key as AuxvType) {
+ Ok(v) => Some(v as usize),
+ Err(_) => None,
+ }
+ }
+
+ // FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv
+ // does not always contain the AT_HWCAP key under qemu.
+ #[cfg(not(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc")))]
+ #[test]
+ fn auxv_crate() {
+ let v = auxv();
+ if let Some(hwcap) = auxv_crate_getauxval(AT_HWCAP) {
+ let rt_hwcap = v.expect("failed to find hwcap key").hwcap;
+ assert_eq!(rt_hwcap, hwcap);
+ }
+
+ // Targets with AT_HWCAP and AT_HWCAP2:
+ #[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+ {
+ if let Some(hwcap2) = auxv_crate_getauxval(AT_HWCAP2) {
+ let rt_hwcap2 = v.expect("failed to find hwcap2 key").hwcap2;
+ assert_eq!(rt_hwcap2, hwcap2);
+ }
+ }
+ }
+
+ #[test]
+ fn auxv_dump() {
+ if let Ok(auxvec) = auxv() {
+ println!("{:?}", auxvec);
+ } else {
+ println!("both getauxval() and reading /proc/self/auxv failed!");
+ }
+ }
+
+ #[cfg(feature = "std_detect_file_io")]
+ cfg_if! {
+ if #[cfg(target_arch = "arm")] {
+ #[test]
+ fn linux_rpi3() {
+ let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv");
+ println!("file: {}", file);
+ let v = auxv_from_file(file).unwrap();
+ assert_eq!(v.hwcap, 4174038);
+ assert_eq!(v.hwcap2, 16);
+ }
+
+ #[test]
+ #[should_panic]
+ fn linux_macos_vb() {
+ let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv");
+ println!("file: {}", file);
+ let v = auxv_from_file(file).unwrap();
+ // this file is incomplete (contains hwcap but not hwcap2), we
+ // want to fall back to /proc/cpuinfo in this case, so
+ // reading should fail. assert_eq!(v.hwcap, 126614527);
+ // assert_eq!(v.hwcap2, 0);
+ }
+ } else if #[cfg(target_arch = "aarch64")] {
+ #[test]
+ fn linux_x64() {
+ let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-x64-i7-6850k.auxv");
+ println!("file: {}", file);
+ let v = auxv_from_file(file).unwrap();
+ assert_eq!(v.hwcap, 3219913727);
+ }
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "std_detect_file_io")]
+ fn auxv_dump_procfs() {
+ if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") {
+ println!("{:?}", auxvec);
+ } else {
+ println!("reading /proc/self/auxv failed!");
+ }
+ }
+
+ #[test]
+ fn auxv_crate_procfs() {
+ let v = auxv();
+ if let Some(hwcap) = auxv_crate_getprocfs(AT_HWCAP) {
+ assert_eq!(v.unwrap().hwcap, hwcap);
+ }
+
+ // Targets with AT_HWCAP and AT_HWCAP2:
+ #[cfg(any(target_arch = "arm", target_arch = "powerpc64"))]
+ {
+ if let Some(hwcap2) = auxv_crate_getprocfs(AT_HWCAP2) {
+ assert_eq!(v.unwrap().hwcap2, hwcap2);
+ }
+ }
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/cpuinfo.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/cpuinfo.rs
new file mode 100644
index 000000000..f76c48a4b
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/cpuinfo.rs
@@ -0,0 +1,300 @@
+//! Parses /proc/cpuinfo
+#![cfg_attr(not(target_arch = "arm"), allow(dead_code))]
+
+extern crate std;
+use self::std::{fs::File, io, io::Read, prelude::v1::*};
+
+/// cpuinfo
+pub(crate) struct CpuInfo {
+ raw: String,
+}
+
+impl CpuInfo {
+ /// Reads /proc/cpuinfo into CpuInfo.
+ pub(crate) fn new() -> Result<Self, io::Error> {
+ let mut file = File::open("/proc/cpuinfo")?;
+ let mut cpui = Self { raw: String::new() };
+ file.read_to_string(&mut cpui.raw)?;
+ Ok(cpui)
+ }
+ /// Returns the value of the cpuinfo `field`.
+ pub(crate) fn field(&self, field: &str) -> CpuInfoField {
+ for l in self.raw.lines() {
+ if l.trim().starts_with(field) {
+ return CpuInfoField::new(l.split(": ").nth(1));
+ }
+ }
+ CpuInfoField(None)
+ }
+
+ /// Returns the `raw` contents of `/proc/cpuinfo`
+ #[cfg(test)]
+ fn raw(&self) -> &String {
+ &self.raw
+ }
+
+ #[cfg(test)]
+ fn from_str(other: &str) -> Result<Self, ::std::io::Error> {
+ Ok(Self {
+ raw: String::from(other),
+ })
+ }
+}
+
+/// Field of cpuinfo
+#[derive(Debug)]
+pub(crate) 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.is_empty(),
+ Some(f) => f == other.trim(),
+ }
+ }
+}
+
+impl<'a> CpuInfoField<'a> {
+ pub(crate) 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?
+ #[cfg(test)]
+ pub(crate) fn exists(&self) -> bool {
+ self.0.is_some()
+ }
+ /// Does the field contain `other`?
+ pub(crate) fn has(&self, other: &str) -> bool {
+ match self.0 {
+ None => other.is_empty(),
+ Some(f) => {
+ let other = other.trim();
+ for v in f.split(' ') {
+ if v == other {
+ return true;
+ }
+ }
+ false
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn raw_dump() {
+ 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 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 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 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"));
+ }
+
+ const POWER8E_POWERKVM: &str = r"processor : 0
+cpu : POWER8E (raw), altivec supported
+clock : 3425.000000MHz
+revision : 2.1 (pvr 004b 0201)
+
+processor : 1
+cpu : POWER8E (raw), altivec supported
+clock : 3425.000000MHz
+revision : 2.1 (pvr 004b 0201)
+
+processor : 2
+cpu : POWER8E (raw), altivec supported
+clock : 3425.000000MHz
+revision : 2.1 (pvr 004b 0201)
+
+processor : 3
+cpu : POWER8E (raw), altivec supported
+clock : 3425.000000MHz
+revision : 2.1 (pvr 004b 0201)
+
+timebase : 512000000
+platform : pSeries
+model : IBM pSeries (emulated by qemu)
+machine : CHRP IBM pSeries (emulated by qemu)";
+
+ #[test]
+ fn power8_powerkvm() {
+ let cpuinfo = CpuInfo::from_str(POWER8E_POWERKVM).unwrap();
+ assert_eq!(cpuinfo.field("cpu"), "POWER8E (raw), altivec supported");
+
+ assert!(cpuinfo.field("cpu").has("altivec"));
+ }
+
+ const POWER5P: &str = r"processor : 0
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 1
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 2
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 3
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 4
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 5
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 6
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+processor : 7
+cpu : POWER5+ (gs)
+clock : 1900.098000MHz
+revision : 2.1 (pvr 003b 0201)
+
+timebase : 237331000
+platform : pSeries
+machine : CHRP IBM,9133-55A";
+
+ #[test]
+ fn power5p() {
+ let cpuinfo = CpuInfo::from_str(POWER5P).unwrap();
+ assert_eq!(cpuinfo.field("cpu"), "POWER5+ (gs)");
+
+ assert!(!cpuinfo.field("cpu").has("altivec"));
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mips.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mips.rs
new file mode 100644
index 000000000..46a47fb7b
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mips.rs
@@ -0,0 +1,31 @@
+//! Run-time feature detection for MIPS on Linux.
+
+use super::auxvec;
+use crate::detect::{bit, cache, Feature};
+
+/// Performs run-time feature detection.
+#[inline]
+pub fn check_for(x: Feature) -> bool {
+ cache::test(x as u32, detect_features)
+}
+
+/// Try to read the features from the auxiliary vector, and if that fails, try
+/// to read them from `/proc/cpuinfo`.
+fn detect_features() -> cache::Initializer {
+ let mut value = cache::Initializer::default();
+ let enable_feature = |value: &mut cache::Initializer, f, enable| {
+ if enable {
+ value.set(f as u32);
+ }
+ };
+
+ // The values are part of the platform-specific [asm/hwcap.h][hwcap]
+ //
+ // [hwcap]: https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
+ if let Ok(auxv) = auxvec::auxv() {
+ enable_feature(&mut value, Feature::msa, bit::test(auxv.hwcap, 1));
+ return value;
+ }
+ // TODO: fall back via `cpuinfo`.
+ value
+}
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mod.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mod.rs
new file mode 100644
index 000000000..e02d5e6dc
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/mod.rs
@@ -0,0 +1,28 @@
+//! Run-time feature detection on Linux
+
+mod auxvec;
+
+#[cfg(feature = "std_detect_file_io")]
+mod cpuinfo;
+
+cfg_if! {
+ if #[cfg(target_arch = "aarch64")] {
+ mod aarch64;
+ pub use self::aarch64::check_for;
+ } else if #[cfg(target_arch = "arm")] {
+ mod arm;
+ pub use self::arm::check_for;
+ } else if #[cfg(any(target_arch = "mips", target_arch = "mips64"))] {
+ mod mips;
+ pub use self::mips::check_for;
+ } else if #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] {
+ mod powerpc;
+ pub use self::powerpc::check_for;
+ } else {
+ use crate::detect::Feature;
+ /// Performs run-time feature detection.
+ pub fn check_for(_x: Feature) -> bool {
+ false
+ }
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/powerpc.rs b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/powerpc.rs
new file mode 100644
index 000000000..dc19bc8ed
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/cfg_if/detect/os/linux/powerpc.rs
@@ -0,0 +1,41 @@
+//! Run-time feature detection for PowerPC on Linux.
+
+use super::{auxvec, cpuinfo};
+use crate::detect::{cache, Feature};
+
+/// Performs run-time feature detection.
+#[inline]
+pub fn check_for(x: Feature) -> bool {
+ cache::test(x as u32, detect_features)
+}
+
+/// Try to read the features from the auxiliary vector, and if that fails, try
+/// to read them from /proc/cpuinfo.
+fn detect_features() -> cache::Initializer {
+ let mut value = cache::Initializer::default();
+ let enable_feature = |value: &mut cache::Initializer, f, enable| {
+ if enable {
+ value.set(f as u32);
+ }
+ };
+
+ // The values are part of the platform-specific [asm/cputable.h][cputable]
+ //
+ // [cputable]: https://github.com/torvalds/linux/blob/master/arch/powerpc/include/uapi/asm/cputable.h
+ if let Ok(auxv) = auxvec::auxv() {
+ // note: the PowerPC values are the mask to do the test (instead of the
+ // index of the bit to test like in ARM and Aarch64)
+ enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0);
+ enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0);
+ enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0);
+ return value;
+ }
+
+ // PowerPC's /proc/cpuinfo lacks a proper Feature field,
+ // but `altivec` support is indicated in the `cpu` field.
+ if let Ok(c) = cpuinfo::CpuInfo::new() {
+ enable_feature(&mut value, Feature::altivec, c.field("cpu").has("altivec"));
+ return value;
+ }
+ value
+}