diff --git a/library/stdarch/src/runtime/linux/cpuinfo.rs b/library/stdarch/src/runtime/linux/cpuinfo.rs index 777be3de562d..efdac7083f2a 100644 --- a/library/stdarch/src/runtime/linux/cpuinfo.rs +++ b/library/stdarch/src/runtime/linux/cpuinfo.rs @@ -214,4 +214,89 @@ CPU revision : 1"; 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 test_cpuinfo_linux_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 test_cpuinfo_linux_power5p() { + let cpuinfo = CpuInfo::from_str(POWER5P).unwrap(); + assert_eq!(cpuinfo.field("cpu"), "POWER5+ (gs)"); + + assert!(!cpuinfo.field("cpu").has("altivec")); + } } diff --git a/library/stdarch/src/runtime/linux/mod.rs b/library/stdarch/src/runtime/linux/mod.rs index 0bd7a7940da0..de7ebfbaa74b 100644 --- a/library/stdarch/src/runtime/linux/mod.rs +++ b/library/stdarch/src/runtime/linux/mod.rs @@ -20,6 +20,10 @@ fn detect_features_impl(x: T) -> usize { { super::aarch64::detect_features(x) } + #[cfg(target_arch = "powerpc64")] + { + super::powerpc64::detect_features(x) + } } /// Detects CPU features: diff --git a/library/stdarch/src/runtime/mod.rs b/library/stdarch/src/runtime/mod.rs index 2ab5e246c122..4867ec95ff5e 100644 --- a/library/stdarch/src/runtime/mod.rs +++ b/library/stdarch/src/runtime/mod.rs @@ -17,12 +17,18 @@ mod aarch64; #[cfg(all(target_arch = "aarch64", target_os = "linux"))] pub use self::aarch64::__Feature; +#[cfg(all(target_arch = "powerpc64", target_os = "linux"))] +#[macro_use] +mod powerpc64; +#[cfg(all(target_arch = "powerpc64", target_os = "linux"))] +pub use self::powerpc64::__Feature; + #[cfg(all(target_os = "linux", - any(target_arch = "arm", target_arch = "aarch64")))] + any(target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc64")))] mod linux; #[cfg(all(target_os = "linux", - any(target_arch = "arm", target_arch = "aarch64")))] + any(target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc64")))] pub use self::linux::detect_features; /// Performs run-time feature detection. diff --git a/library/stdarch/src/runtime/powerpc64.rs b/library/stdarch/src/runtime/powerpc64.rs new file mode 100644 index 000000000000..0d6ebffbf6ce --- /dev/null +++ b/library/stdarch/src/runtime/powerpc64.rs @@ -0,0 +1,94 @@ +//! Run-time feature detection on PowerPC64. +use super::{bit, linux}; + +#[macro_export] +#[doc(hidden)] +macro_rules! __unstable_detect_feature { + ("altivec") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::altivec{}) + }; + ("vsx") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::vsx{}) + }; + ("power8") => { + $crate::vendor::__unstable_detect_feature($crate::vendor::__Feature::power8{}) + }; + ($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)] +pub enum __Feature { + /// Altivec + altivec, + /// VSX + vsx, + /// Power8 + power8, +} + +pub fn detect_features(mut x: T) -> usize { + let mut value: usize = 0; + { + let mut enable_feature = |f| { + if x.has_feature(&f) { + value = bit::set(value, f as u32); + } + }; + enable_feature(__Feature::altivec); + enable_feature(__Feature::vsx); + enable_feature(__Feature::power8); + } + value +} + +/// Probe the ELF Auxiliary vector for hardware capabilities +/// +/// 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 +impl linux::FeatureQuery for linux::AuxVec { + fn has_feature(&mut self, x: &__Feature) -> bool { + use self::__Feature::*; + match *x { + altivec => self.lookup(linux::AT::HWCAP) + .map(|caps| caps & 0x10000000 != 0) + .unwrap_or(false), + vsx => self.lookup(linux::AT::HWCAP) + .map(|caps| caps & 0x00000080 != 0) + .unwrap_or(false), + power8 => self.lookup(linux::AT::HWCAP2) + .map(|caps| caps & 0x80000000 != 0) + .unwrap_or(false), + } + } +} + +/// Check for altivec support only +/// +/// PowerPC's /proc/cpuinfo lacks a proper Feature field, +/// but `altivec` support is indicated in the `cpu` field. +impl linux::FeatureQuery for linux::CpuInfo { + fn has_feature(&mut self, x: &__Feature) -> bool { + use self::__Feature::*; + match *x { + altivec => self.field("cpu").has("altivec"), + _ => false + } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn detect_feature() { + println!("altivec {}", __unstable_detect_feature!("altivec")); + println!("vsx {}", __unstable_detect_feature!("vsx")); + println!("power8 {}", __unstable_detect_feature!("power8")); + } +}