Auto merge of #143412 - Kobzol:std-detect-in-stdlib, r=Amanieu
Move `std_detect` into stdlib This PR moves the `std_detect` crate from `stdarch` to be a part of rust-lang/rust instead. The first commit actually moves the whole directory from the stdarch Josh subtree, so that git blame history is kept intact. Then I had to make a few changes to appease `tidy`. The most complex thing here is porting the tests. We can't have `std_detect` both in r-l/r and stdarch, because they could get desynchronized, so we have to perform the move more or less "atomically", which means that we also have to port all the existing `std_detect` tests from the `stdarch` repository. The stdarch repo runs the following `std_detect` tests: ### Build The `build-std-detect.sh` script (e2b6512aed/ci/build-std-detect.sh) builds `std_detect` using the nightly compiler for several targets. This will be subsumed by normal `x build library` on our Tier 1/2 targets. However, the stdarch repository also tests the following targets: - aarch64-unknown-freebsd - armv6-unknown-freebsd - powerpc-unknown-freebsd - powerpc64-unknown-freebsd - aarch64-unknown-openbsd Which we don't build/test on our CI currently. I think we have mostly two options here: 1) Ignore these targets 2) Create a special CI job that will build stage 1 rustc and then cross-compile std (or just the `std_detect` crate?) for these targets. ### Documentation The `dox.sh` script (3fec5adcd5/ci/dox.sh) builds and documents `std_detect` for several targets. All of them are Tier 2/we have `dist-` jobs for them, so I think that we can just skip this and let our normal CI subsume it? ### Tests The `run.sh` script (1b201cec2c/ci/run.sh) runs `cargo test` on `std_detect` with a bunch of variations of feature flags. This will be subsumed by `x test library` in our CI. The only problem is that `stdarch` runs these tests for a ludicrous number of targets: ``` - tuple: i686-unknown-linux-gnu - tuple: x86_64-unknown-linux-gnu - tuple: arm-unknown-linux-gnueabihf - tuple: armv7-unknown-linux-gnueabihf - tuple: aarch64-unknown-linux-gnu - tuple: aarch64_be-unknown-linux-gnu - tuple: riscv32gc-unknown-linux-gnu - tuple: riscv64gc-unknown-linux-gnu - tuple: powerpc-unknown-linux-gnu - tuple: powerpc64-unknown-linux-gnu - tuple: powerpc64le-unknown-linux-gnu - tuple: s390x-unknown-linux-gnu - tuple: i586-unknown-linux-gnu - tuple: nvptx64-nvidia-cuda - tuple: thumbv6m-none-eabi - tuple: thumbv7m-none-eabi - tuple: thumbv7em-none-eabi - tuple: thumbv7em-none-eabihf - tuple: loongarch64-unknown-linux-gnu - tuple: wasm32-wasip1 - tuple: x86_64-apple-darwin - tuple: x86_64-apple-ios-macabi - tuple: aarch64-apple-darwin - tuple: aarch64-apple-ios-macabi - tuple: x86_64-pc-windows-msvc - tuple: i686-pc-windows-msvc - tuple: aarch64-pc-windows-msvc - tuple: x86_64-pc-windows-gnu - tuple: aarch64-unknown-linux-gnu - tuple: aarch64_be-unknown-linux-gnu - tuple: armv7-unknown-linux-gnueabihf - tuple: loongarch64-unknown-linux-gnu - tuple: powerpc-unknown-linux-gnu - tuple: powerpc64-unknown-linux-gnu - tuple: powerpc64le-unknown-linux-gnu - tuple: riscv32gc-unknown-linux-gnu - tuple: riscv64gc-unknown-linux-gnu - tuple: s390x-unknown-linux-gnu - tuple: x86_64-unknown-linux-gnu - tuple: aarch64-apple-darwin - tuple: aarch64-apple-ios-macabi ``` We definitely do not run *tests* for all of these targets on our CI. # Outcome We have decided to just subsume std_detect tests by our normal test suite for now, and not create a separate CI job. Therefore, this PR performs the following changes in target testing for `std_detect`: The following T3 targets would go from "build" to "nothing": ``` aarch64-unknown-freebsd (T3) armv6-unknown-freebsd (T3) powerpc-unknown-freebsd (T3) powerpc64-unknown-freebsd (T3) aarch64-unknown-openbsd (T3) ``` The following T3 targets would go from "test" to "nothing": ``` aarch64_be-unknown-linux-gnu (T3) riscv32gc-unknown-liux-gnu (T3) ``` The following T2 targets would go from "test" to "build": ``` arm-unknown-linux-gnueabihf (T2) armv7-unknown-linux-gnueabihf (T2) riscv64gc-unknown-linux-gnu (T2) powerpc-unknown-linux-gnu (T2) powerpc64-unknown-linux-gnu (T2) powerpc64le-unknown-linux-gnu (T2) s390x-unknown-linux-gnu (T2) i586-unknown-linux-gnu (T2) loongarch64-unknown-linux-gnu (T2) wasm32-wasip1 (T2) x86_64-apple-ios-macabi (T2) aarch64-apple-ios-macabi (T2) aarch64-pc-windows-msvc (T2) armv7-unknown-linux-gnueabihf (T2) loongarch64-unknown-linux-gnu (T2) powerpc-unknown-linux-gnu (T2) ``` I have confirmed in https://github.com/rust-lang/stdarch/pull/1873 that the current version of this PR would pass stdarch's CI testsuite. r? `@ghost` try-job: armhf-gnu try-job: arm-android
This commit is contained in:
commit
5a30e4307f
68 changed files with 377 additions and 817 deletions
|
|
@ -340,10 +340,10 @@ dependencies = [
|
|||
name = "std_detect"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"cfg-if",
|
||||
"core",
|
||||
"libc",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ unwind = { path = "../unwind" }
|
|||
hashbrown = { version = "0.15", default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
] }
|
||||
std_detect = { path = "../stdarch/crates/std_detect", public = true, default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
] }
|
||||
std_detect = { path = "../std_detect", public = true }
|
||||
|
||||
# Dependencies of the `backtrace` crate
|
||||
rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
|
||||
|
|
@ -118,8 +116,7 @@ optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]
|
|||
debug_refcell = ["core/debug_refcell"]
|
||||
|
||||
|
||||
# Enable std_detect default features for stdarch/crates/std_detect:
|
||||
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
|
||||
# Enable std_detect features:
|
||||
std_detect_file_io = ["std_detect/std_detect_file_io"]
|
||||
std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"]
|
||||
|
||||
|
|
|
|||
|
|
@ -22,20 +22,14 @@ maintenance = { status = "experimental" }
|
|||
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
# When built as part of libstd
|
||||
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
|
||||
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
|
||||
core = { path = "../core" }
|
||||
alloc = { path = "../alloc" }
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
libc = { version = "0.2.0", optional = true, default-features = false }
|
||||
|
||||
[features]
|
||||
default = [ "std_detect_dlsym_getauxval", "std_detect_file_io" ]
|
||||
default = []
|
||||
std_detect_file_io = [ "libc" ]
|
||||
std_detect_dlsym_getauxval = [ "libc" ]
|
||||
std_detect_env_override = [ "libc" ]
|
||||
rustc-dep-of-std = [
|
||||
"core",
|
||||
"alloc",
|
||||
]
|
||||
|
|
@ -3,9 +3,7 @@
|
|||
|
||||
#![allow(dead_code)] // not used on all platforms
|
||||
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
/// Sets the `bit` of `x`.
|
||||
#[inline]
|
||||
|
|
@ -40,20 +38,14 @@ impl Initializer {
|
|||
/// Tests the `bit` of the cache.
|
||||
#[inline]
|
||||
pub(crate) fn test(self, bit: u32) -> bool {
|
||||
debug_assert!(
|
||||
bit < CACHE_CAPACITY,
|
||||
"too many features, time to increase the cache size!"
|
||||
);
|
||||
debug_assert!(bit < CACHE_CAPACITY, "too many features, time to increase the cache size!");
|
||||
test_bit(self.0, bit)
|
||||
}
|
||||
|
||||
/// Sets the `bit` of the cache.
|
||||
#[inline]
|
||||
pub(crate) fn set(&mut self, bit: u32) {
|
||||
debug_assert!(
|
||||
bit < CACHE_CAPACITY,
|
||||
"too many features, time to increase the cache size!"
|
||||
);
|
||||
debug_assert!(bit < CACHE_CAPACITY, "too many features, time to increase the cache size!");
|
||||
let v = self.0;
|
||||
self.0 = set_bit(v, bit);
|
||||
}
|
||||
|
|
@ -61,10 +53,7 @@ impl Initializer {
|
|||
/// Unsets the `bit` of the cache.
|
||||
#[inline]
|
||||
pub(crate) fn unset(&mut self, bit: u32) {
|
||||
debug_assert!(
|
||||
bit < CACHE_CAPACITY,
|
||||
"too many features, time to increase the cache size!"
|
||||
);
|
||||
debug_assert!(bit < CACHE_CAPACITY, "too many features, time to increase the cache size!");
|
||||
let v = self.0;
|
||||
self.0 = unset_bit(v, bit);
|
||||
}
|
||||
|
|
@ -73,11 +62,7 @@ impl Initializer {
|
|||
/// This global variable is a cache of the features supported by the CPU.
|
||||
// Note: the third slot is only used in x86
|
||||
// Another Slot can be added if needed without any change to `Initializer`
|
||||
static CACHE: [Cache; 3] = [
|
||||
Cache::uninitialized(),
|
||||
Cache::uninitialized(),
|
||||
Cache::uninitialized(),
|
||||
];
|
||||
static CACHE: [Cache; 3] = [Cache::uninitialized(), Cache::uninitialized(), Cache::uninitialized()];
|
||||
|
||||
/// Feature cache with capacity for `size_of::<usize>() * 8 - 1` features.
|
||||
///
|
||||
|
|
@ -104,19 +89,14 @@ impl Cache {
|
|||
#[inline]
|
||||
pub(crate) fn test(&self, bit: u32) -> Option<bool> {
|
||||
let cached = self.0.load(Ordering::Relaxed);
|
||||
if cached == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(test_bit(cached as u128, bit))
|
||||
}
|
||||
if cached == 0 { None } else { Some(test_bit(cached as u128, bit)) }
|
||||
}
|
||||
|
||||
/// Initializes the cache.
|
||||
#[inline]
|
||||
fn initialize(&self, value: usize) -> usize {
|
||||
debug_assert_eq!((value & !Cache::MASK), 0);
|
||||
self.0
|
||||
.store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed);
|
||||
self.0.store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed);
|
||||
value
|
||||
}
|
||||
}
|
||||
|
|
@ -217,7 +197,5 @@ pub(crate) fn test(bit: u32) -> bool {
|
|||
} else {
|
||||
(bit - 2 * Cache::CAPACITY, 2)
|
||||
};
|
||||
CACHE[idx]
|
||||
.test(relative_bit)
|
||||
.unwrap_or_else(|| detect_and_initialize().test(bit))
|
||||
CACHE[idx].test(relative_bit).unwrap_or_else(|| detect_and_initialize().test(bit))
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ macro_rules! features {
|
|||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[test] //tidy:skip
|
||||
#[deny(unexpected_cfgs)]
|
||||
#[deny(unfulfilled_lint_expectations)]
|
||||
fn unexpected_cfgs() {
|
||||
|
|
@ -29,7 +29,6 @@ mod arch;
|
|||
#[doc(hidden)]
|
||||
#[unstable(feature = "stdarch_internal", issue = "none")]
|
||||
pub use self::arch::__is_feature_detected;
|
||||
|
||||
pub(crate) use self::arch::Feature;
|
||||
|
||||
mod bit;
|
||||
|
|
@ -17,9 +17,10 @@
|
|||
//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt)
|
||||
//! - [ARM documentation](https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers?lang=en)
|
||||
|
||||
use crate::detect::{Feature, cache};
|
||||
use core::arch::asm;
|
||||
|
||||
use crate::detect::{Feature, cache};
|
||||
|
||||
/// Try to read the features from the system registers.
|
||||
///
|
||||
/// This will cause SIGILL if the current OS is not trapping the mrs instruction.
|
||||
|
|
@ -104,10 +105,7 @@ pub(crate) fn parse_system_registers(
|
|||
let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
|
||||
enable_feature(Feature::sha2, asimd && sha1 && sha2);
|
||||
enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
|
||||
enable_feature(
|
||||
Feature::dotprod,
|
||||
asimd && bits_shift(aa64isar0, 47, 44) >= 1,
|
||||
);
|
||||
enable_feature(Feature::dotprod, asimd && bits_shift(aa64isar0, 47, 44) >= 1);
|
||||
enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);
|
||||
}
|
||||
|
||||
|
|
@ -2,9 +2,10 @@
|
|||
//!
|
||||
//! <https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics>
|
||||
|
||||
use crate::detect::{Feature, cache};
|
||||
use core::ffi::CStr;
|
||||
|
||||
use crate::detect::{Feature, cache};
|
||||
|
||||
#[inline]
|
||||
fn _sysctlbyname(name: &CStr) -> bool {
|
||||
use libc;
|
||||
|
|
@ -14,13 +15,7 @@ fn _sysctlbyname(name: &CStr) -> bool {
|
|||
let enabled_ptr = &mut enabled as *mut i32 as *mut libc::c_void;
|
||||
|
||||
let ret = unsafe {
|
||||
libc::sysctlbyname(
|
||||
name.as_ptr(),
|
||||
enabled_ptr,
|
||||
&mut enabled_len,
|
||||
core::ptr::null_mut(),
|
||||
0,
|
||||
)
|
||||
libc::sysctlbyname(name.as_ptr(), enabled_ptr, &mut enabled_len, core::ptr::null_mut(), 0)
|
||||
};
|
||||
|
||||
match ret {
|
||||
|
|
@ -54,11 +54,8 @@ fn archauxv(key: libc::c_int) -> usize {
|
|||
// https://github.com/freebsd/freebsd-src/blob/release/11.4.0/sys/sys/auxv.h
|
||||
// FreeBSD 11 support in std has been removed in Rust 1.75 (https://github.com/rust-lang/rust/pull/114521),
|
||||
// so we can safely use this function.
|
||||
let res = libc::elf_aux_info(
|
||||
key,
|
||||
&mut out as *mut libc::c_ulong as *mut libc::c_void,
|
||||
OUT_LEN,
|
||||
);
|
||||
let res =
|
||||
libc::elf_aux_info(key, &mut out as *mut libc::c_ulong as *mut libc::c_void, OUT_LEN);
|
||||
// If elf_aux_info fails, `out` will be left at zero (which is the proper default value).
|
||||
debug_assert!(res == 0 || out == 0);
|
||||
}
|
||||
|
|
@ -343,14 +343,8 @@ impl AtHwcap {
|
|||
enable_feature(Feature::sve2, sve2);
|
||||
enable_feature(Feature::sve2p1, self.sve2p1 && sve2);
|
||||
// SVE2 extensions require SVE2 and crypto features
|
||||
enable_feature(
|
||||
Feature::sve2_aes,
|
||||
self.sveaes && self.svepmull && sve2 && self.aes,
|
||||
);
|
||||
enable_feature(
|
||||
Feature::sve2_sm4,
|
||||
self.svesm4 && sve2 && self.sm3 && self.sm4,
|
||||
);
|
||||
enable_feature(Feature::sve2_aes, self.sveaes && self.svepmull && sve2 && self.aes);
|
||||
enable_feature(Feature::sve2_sm4, self.svesm4 && sve2 && self.sm3 && self.sm4);
|
||||
enable_feature(
|
||||
Feature::sve2_sha3,
|
||||
self.svesha3 && sve2 && self.sha512 && self.sha3 && self.sha1 && self.sha2,
|
||||
|
|
@ -401,84 +395,4 @@ impl AtHwcap {
|
|||
|
||||
#[cfg(target_endian = "little")]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
mod auxv_from_file {
|
||||
use super::auxvec::auxv_from_file;
|
||||
use super::*;
|
||||
// The baseline hwcaps used in the (artificial) auxv test files.
|
||||
fn baseline_hwcaps() -> AtHwcap {
|
||||
AtHwcap {
|
||||
fp: true,
|
||||
asimd: true,
|
||||
aes: true,
|
||||
pmull: true,
|
||||
sha1: true,
|
||||
sha2: true,
|
||||
crc32: true,
|
||||
atomics: true,
|
||||
fphp: true,
|
||||
asimdhp: true,
|
||||
asimdrdm: true,
|
||||
lrcpc: true,
|
||||
dcpop: true,
|
||||
asimddp: true,
|
||||
ssbs: true,
|
||||
..AtHwcap::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linux_empty_hwcap2_aarch64() {
|
||||
let file = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv"
|
||||
);
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
println!("HWCAP : 0x{:0x}", v.hwcap);
|
||||
println!("HWCAP2: 0x{:0x}", v.hwcap2);
|
||||
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
|
||||
}
|
||||
#[test]
|
||||
fn linux_no_hwcap2_aarch64() {
|
||||
let file = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"
|
||||
);
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
println!("HWCAP : 0x{:0x}", v.hwcap);
|
||||
println!("HWCAP2: 0x{:0x}", v.hwcap2);
|
||||
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
|
||||
}
|
||||
#[test]
|
||||
fn linux_hwcap2_aarch64() {
|
||||
let file = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/src/detect/test_data/linux-hwcap2-aarch64.auxv"
|
||||
);
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
println!("HWCAP : 0x{:0x}", v.hwcap);
|
||||
println!("HWCAP2: 0x{:0x}", v.hwcap2);
|
||||
assert_eq!(
|
||||
AtHwcap::from(v),
|
||||
AtHwcap {
|
||||
// Some other HWCAP bits.
|
||||
paca: true,
|
||||
pacg: true,
|
||||
// HWCAP2-only bits.
|
||||
dcpodp: true,
|
||||
frint: true,
|
||||
rng: true,
|
||||
bti: true,
|
||||
mte: true,
|
||||
..baseline_hwcaps()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
77
library/std_detect/src/detect/os/linux/aarch64/tests.rs
Normal file
77
library/std_detect/src/detect/os/linux/aarch64/tests.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
use super::*;
|
||||
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
mod auxv_from_file {
|
||||
use super::auxvec::auxv_from_file;
|
||||
use super::*;
|
||||
// The baseline hwcaps used in the (artificial) auxv test files.
|
||||
fn baseline_hwcaps() -> AtHwcap {
|
||||
AtHwcap {
|
||||
fp: true,
|
||||
asimd: true,
|
||||
aes: true,
|
||||
pmull: true,
|
||||
sha1: true,
|
||||
sha2: true,
|
||||
crc32: true,
|
||||
atomics: true,
|
||||
fphp: true,
|
||||
asimdhp: true,
|
||||
asimdrdm: true,
|
||||
lrcpc: true,
|
||||
dcpop: true,
|
||||
asimddp: true,
|
||||
ssbs: true,
|
||||
..AtHwcap::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linux_empty_hwcap2_aarch64() {
|
||||
let file = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv"
|
||||
);
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
println!("HWCAP : 0x{:0x}", v.hwcap);
|
||||
println!("HWCAP2: 0x{:0x}", v.hwcap2);
|
||||
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
|
||||
}
|
||||
#[test]
|
||||
fn linux_no_hwcap2_aarch64() {
|
||||
let file = concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"
|
||||
);
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
println!("HWCAP : 0x{:0x}", v.hwcap);
|
||||
println!("HWCAP2: 0x{:0x}", v.hwcap2);
|
||||
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
|
||||
}
|
||||
#[test]
|
||||
fn linux_hwcap2_aarch64() {
|
||||
let file =
|
||||
concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv");
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
println!("HWCAP : 0x{:0x}", v.hwcap);
|
||||
println!("HWCAP2: 0x{:0x}", v.hwcap2);
|
||||
assert_eq!(
|
||||
AtHwcap::from(v),
|
||||
AtHwcap {
|
||||
// Some other HWCAP bits.
|
||||
paca: true,
|
||||
pacg: true,
|
||||
// HWCAP2-only bits.
|
||||
dcpodp: true,
|
||||
frint: true,
|
||||
rng: true,
|
||||
bti: true,
|
||||
mte: true,
|
||||
..baseline_hwcaps()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
|
|||
{
|
||||
// If calling getauxval fails, try to read the auxiliary vector from
|
||||
// its file:
|
||||
auxv_from_file("/proc/self/auxv")
|
||||
auxv_from_file("/proc/self/auxv").map_err(|_| ())
|
||||
}
|
||||
#[cfg(not(feature = "std_detect_file_io"))]
|
||||
{
|
||||
|
|
@ -157,17 +157,22 @@ fn getauxval(key: usize) -> Result<usize, ()> {
|
|||
/// Tries to read the auxiliary vector from the `file`. If this fails, this
|
||||
/// function returns `Err`.
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
pub(super) fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
|
||||
pub(super) fn auxv_from_file(file: &str) -> Result<AuxVec, alloc::string::String> {
|
||||
let file = super::read_file(file)?;
|
||||
auxv_from_file_bytes(&file)
|
||||
}
|
||||
|
||||
/// Read auxiliary vector from a slice of bytes.
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result<AuxVec, alloc::string::String> {
|
||||
// See <https://github.com/torvalds/linux/blob/v5.15/include/uapi/linux/auxvec.h>.
|
||||
//
|
||||
// The auxiliary vector contains at most 34 (key,value) fields: from
|
||||
// `AT_MINSIGSTKSZ` to `AT_NULL`, but its number may increase.
|
||||
let len = file.len();
|
||||
let len = bytes.len();
|
||||
let mut buf = alloc::vec![0_usize; 1 + len / core::mem::size_of::<usize>()];
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(file.as_ptr(), buf.as_mut_ptr() as *mut u8, len);
|
||||
core::ptr::copy_nonoverlapping(bytes.as_ptr(), buf.as_mut_ptr() as *mut u8, len);
|
||||
}
|
||||
|
||||
auxv_from_buf(&buf)
|
||||
|
|
@ -176,7 +181,7 @@ pub(super) fn auxv_from_file(file: &str) -> Result<AuxVec, ()> {
|
|||
/// 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]) -> Result<AuxVec, ()> {
|
||||
fn auxv_from_buf(buf: &[usize]) -> Result<AuxVec, alloc::string::String> {
|
||||
// Targets with only AT_HWCAP:
|
||||
#[cfg(any(
|
||||
target_arch = "riscv32",
|
||||
|
|
@ -222,120 +227,8 @@ fn auxv_from_buf(buf: &[usize]) -> Result<AuxVec, ()> {
|
|||
}
|
||||
// Suppress unused variable
|
||||
let _ = buf;
|
||||
Err(())
|
||||
Err(alloc::string::String::from("hwcap not found"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv
|
||||
// does not always contain the AT_HWCAP key under qemu.
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
#[test]
|
||||
fn auxv_crate() {
|
||||
let v = auxv();
|
||||
if let Ok(hwcap) = 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 = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
{
|
||||
if let Ok(hwcap2) = 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::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]
|
||||
fn linux_macos_vb() {
|
||||
let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv");
|
||||
println!("file: {file}");
|
||||
// The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero.
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
assert_eq!(v.hwcap, 126614527);
|
||||
assert_eq!(v.hwcap2, 0);
|
||||
}
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
#[cfg(target_endian = "little")]
|
||||
#[test]
|
||||
fn linux_artificial_aarch64() {
|
||||
let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv");
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
assert_eq!(v.hwcap, 0x0123456789abcdef);
|
||||
assert_eq!(v.hwcap2, 0x02468ace13579bdf);
|
||||
}
|
||||
#[cfg(target_endian = "little")]
|
||||
#[test]
|
||||
fn linux_no_hwcap2_aarch64() {
|
||||
let file = concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv");
|
||||
println!("file: {file}");
|
||||
let v = auxv_from_file(file).unwrap();
|
||||
// An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP.
|
||||
assert_ne!(v.hwcap, 0);
|
||||
assert_eq!(v.hwcap2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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!");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
#[test]
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
fn auxv_crate_procfs() {
|
||||
if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") {
|
||||
assert_eq!(auxv().unwrap(), procfs_auxv);
|
||||
}
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
109
library/std_detect/src/detect/os/linux/auxvec/tests.rs
Normal file
109
library/std_detect/src/detect/os/linux/auxvec/tests.rs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use super::*;
|
||||
|
||||
// FIXME: on mips/mips64 getauxval returns 0, and /proc/self/auxv
|
||||
// does not always contain the AT_HWCAP key under qemu.
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
#[test]
|
||||
fn auxv_crate() {
|
||||
let v = auxv();
|
||||
if let Ok(hwcap) = 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 = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
{
|
||||
if let Ok(hwcap2) = 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::cfg_if! {
|
||||
if #[cfg(target_arch = "arm")] {
|
||||
// The tests below can be executed under qemu, where we do not have access to the test
|
||||
// files on disk, so we need to embed them with `include_bytes!`.
|
||||
#[test]
|
||||
fn linux_rpi3() {
|
||||
let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-rpi3.auxv"));
|
||||
let v = auxv_from_file_bytes(auxv).unwrap();
|
||||
assert_eq!(v.hwcap, 4174038);
|
||||
assert_eq!(v.hwcap2, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linux_macos_vb() {
|
||||
let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/macos-virtualbox-linux-x86-4850HQ.auxv"));
|
||||
// The file contains HWCAP but not HWCAP2. In that case, we treat HWCAP2 as zero.
|
||||
let v = auxv_from_file_bytes(auxv).unwrap();
|
||||
assert_eq!(v.hwcap, 126614527);
|
||||
assert_eq!(v.hwcap2, 0);
|
||||
}
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
#[cfg(target_endian = "little")]
|
||||
#[test]
|
||||
fn linux_artificial_aarch64() {
|
||||
let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-artificial-aarch64.auxv"));
|
||||
let v = auxv_from_file_bytes(auxv).unwrap();
|
||||
assert_eq!(v.hwcap, 0x0123456789abcdef);
|
||||
assert_eq!(v.hwcap2, 0x02468ace13579bdf);
|
||||
}
|
||||
#[cfg(target_endian = "little")]
|
||||
#[test]
|
||||
fn linux_no_hwcap2_aarch64() {
|
||||
let auxv = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"));
|
||||
let v = auxv_from_file_bytes(auxv).unwrap();
|
||||
// An absent HWCAP2 is treated as zero, and does not prevent acceptance of HWCAP.
|
||||
assert_ne!(v.hwcap, 0);
|
||||
assert_eq!(v.hwcap2, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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!");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
#[test]
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
fn auxv_crate_procfs() {
|
||||
if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") {
|
||||
assert_eq!(auxv().unwrap(), procfs_auxv);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
//! Run-time feature detection for LoongArch on Linux.
|
||||
|
||||
use core::arch::asm;
|
||||
|
||||
use super::auxvec;
|
||||
use crate::detect::{Feature, bit, cache};
|
||||
use core::arch::asm;
|
||||
|
||||
/// Try to read the features from the auxiliary vector.
|
||||
pub(crate) fn detect_features() -> cache::Initializer {
|
||||
|
|
@ -43,16 +44,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
//
|
||||
// [hwcap]: https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h
|
||||
if let Ok(auxv) = auxvec::auxv() {
|
||||
enable_feature(
|
||||
&mut value,
|
||||
Feature::f,
|
||||
bit::test(cpucfg2, 1) && bit::test(auxv.hwcap, 3),
|
||||
);
|
||||
enable_feature(
|
||||
&mut value,
|
||||
Feature::d,
|
||||
bit::test(cpucfg2, 2) && bit::test(auxv.hwcap, 3),
|
||||
);
|
||||
enable_feature(&mut value, Feature::f, bit::test(cpucfg2, 1) && bit::test(auxv.hwcap, 3));
|
||||
enable_feature(&mut value, Feature::d, bit::test(cpucfg2, 2) && bit::test(auxv.hwcap, 3));
|
||||
enable_feature(&mut value, Feature::lsx, bit::test(auxv.hwcap, 4));
|
||||
enable_feature(&mut value, Feature::lasx, bit::test(auxv.hwcap, 5));
|
||||
enable_feature(
|
||||
|
|
@ -6,14 +6,16 @@ use alloc::vec::Vec;
|
|||
mod auxvec;
|
||||
|
||||
#[cfg(feature = "std_detect_file_io")]
|
||||
fn read_file(path: &str) -> Result<Vec<u8>, ()> {
|
||||
let mut path = Vec::from(path.as_bytes());
|
||||
fn read_file(orig_path: &str) -> Result<Vec<u8>, alloc::string::String> {
|
||||
use alloc::format;
|
||||
|
||||
let mut path = Vec::from(orig_path.as_bytes());
|
||||
path.push(0);
|
||||
|
||||
unsafe {
|
||||
let file = libc::open(path.as_ptr() as *const libc::c_char, libc::O_RDONLY);
|
||||
if file == -1 {
|
||||
return Err(());
|
||||
return Err(format!("Cannot open file at {orig_path}"));
|
||||
}
|
||||
|
||||
let mut data = Vec::new();
|
||||
|
|
@ -23,7 +25,7 @@ fn read_file(path: &str) -> Result<Vec<u8>, ()> {
|
|||
match libc::read(file, spare.as_mut_ptr() as *mut _, spare.len()) {
|
||||
-1 => {
|
||||
libc::close(file);
|
||||
return Err(());
|
||||
return Err(format!("Error while reading from file at {orig_path}"));
|
||||
}
|
||||
0 => break,
|
||||
n => data.set_len(data.len() + n as usize),
|
||||
|
|
@ -119,16 +119,7 @@ fn _riscv_hwprobe(out: &mut [riscv_hwprobe]) -> bool {
|
|||
cpus: *mut libc::c_ulong,
|
||||
flags: libc::c_uint,
|
||||
) -> libc::c_long {
|
||||
unsafe {
|
||||
libc::syscall(
|
||||
__NR_riscv_hwprobe,
|
||||
pairs,
|
||||
pair_count,
|
||||
cpu_set_size,
|
||||
cpus,
|
||||
flags,
|
||||
)
|
||||
}
|
||||
unsafe { libc::syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_set_size, cpus, flags) }
|
||||
}
|
||||
|
||||
unsafe { __riscv_hwprobe(out.as_mut_ptr(), out.len(), 0, ptr::null_mut(), 0) == 0 }
|
||||
|
|
@ -4,8 +4,10 @@
|
|||
//! https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8
|
||||
//! https://github.com/golang/go/commit/cd54ef1f61945459486e9eea2f016d99ef1da925
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr;
|
||||
|
||||
use crate::detect::cache;
|
||||
use core::{mem::MaybeUninit, ptr};
|
||||
|
||||
// Defined in machine/cpu.h.
|
||||
// https://github.com/openbsd/src/blob/72ccc03bd11da614f31f7ff76e3f6fce99bc1c79/sys/arch/arm64/include/cpu.h#L25-L40
|
||||
|
|
@ -135,69 +135,4 @@ pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initialize
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple_direct() {
|
||||
let mut value = cache::Initializer::default();
|
||||
value.set(Feature::f as u32);
|
||||
// F (and other extensions with CSRs) -> Zicsr
|
||||
assert!(imply_features(value).test(Feature::zicsr as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_indirect() {
|
||||
let mut value = cache::Initializer::default();
|
||||
value.set(Feature::q as u32);
|
||||
// Q -> D, D -> F, F -> Zicsr
|
||||
assert!(imply_features(value).test(Feature::zicsr as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_zcd() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// C & D -> Zcd
|
||||
value.set(Feature::c as u32);
|
||||
assert!(!imply_features(value).test(Feature::zcd as u32));
|
||||
value.set(Feature::d as u32);
|
||||
assert!(imply_features(value).test(Feature::zcd as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_simple_forward() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// A -> Zalrsc & Zaamo (forward implication)
|
||||
value.set(Feature::a as u32);
|
||||
let value = imply_features(value);
|
||||
assert!(value.test(Feature::zalrsc as u32));
|
||||
assert!(value.test(Feature::zaamo as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_simple_backward() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// Zalrsc & Zaamo -> A (reverse implication)
|
||||
value.set(Feature::zalrsc as u32);
|
||||
value.set(Feature::zaamo as u32);
|
||||
assert!(imply_features(value).test(Feature::a as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_complex_convergence() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// Needs 3 iterations to converge
|
||||
// (and 4th iteration for convergence checking):
|
||||
// 1. [Zvksc] -> Zvks & Zvbc
|
||||
// 2. Zvks -> Zvksed & Zvksh & Zvkb & Zvkt
|
||||
// 3a. [Zvkned] & [Zvknhb] & [Zvkb] & Zvkt -> {Zvkn}
|
||||
// 3b. Zvkn & Zvbc -> {Zvknc}
|
||||
value.set(Feature::zvksc as u32);
|
||||
value.set(Feature::zvkned as u32);
|
||||
value.set(Feature::zvknhb as u32);
|
||||
value.set(Feature::zvkb as u32);
|
||||
let value = imply_features(value);
|
||||
assert!(value.test(Feature::zvkn as u32));
|
||||
assert!(value.test(Feature::zvknc as u32));
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
64
library/std_detect/src/detect/os/riscv/tests.rs
Normal file
64
library/std_detect/src/detect/os/riscv/tests.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple_direct() {
|
||||
let mut value = cache::Initializer::default();
|
||||
value.set(Feature::f as u32);
|
||||
// F (and other extensions with CSRs) -> Zicsr
|
||||
assert!(imply_features(value).test(Feature::zicsr as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_indirect() {
|
||||
let mut value = cache::Initializer::default();
|
||||
value.set(Feature::q as u32);
|
||||
// Q -> D, D -> F, F -> Zicsr
|
||||
assert!(imply_features(value).test(Feature::zicsr as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_zcd() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// C & D -> Zcd
|
||||
value.set(Feature::c as u32);
|
||||
assert!(!imply_features(value).test(Feature::zcd as u32));
|
||||
value.set(Feature::d as u32);
|
||||
assert!(imply_features(value).test(Feature::zcd as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_simple_forward() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// A -> Zalrsc & Zaamo (forward implication)
|
||||
value.set(Feature::a as u32);
|
||||
let value = imply_features(value);
|
||||
assert!(value.test(Feature::zalrsc as u32));
|
||||
assert!(value.test(Feature::zaamo as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_simple_backward() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// Zalrsc & Zaamo -> A (reverse implication)
|
||||
value.set(Feature::zalrsc as u32);
|
||||
value.set(Feature::zaamo as u32);
|
||||
assert!(imply_features(value).test(Feature::a as u32));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_complex_convergence() {
|
||||
let mut value = cache::Initializer::default();
|
||||
// Needs 3 iterations to converge
|
||||
// (and 4th iteration for convergence checking):
|
||||
// 1. [Zvksc] -> Zvks & Zvbc
|
||||
// 2. Zvks -> Zvksed & Zvksh & Zvkb & Zvkt
|
||||
// 3a. [Zvkned] & [Zvknhb] & [Zvkb] & Zvkt -> {Zvkn}
|
||||
// 3b. Zvkn & Zvbc -> {Zvknc}
|
||||
value.set(Feature::zvksc as u32);
|
||||
value.set(Feature::zvkned as u32);
|
||||
value.set(Feature::zvknhb as u32);
|
||||
value.set(Feature::zvkb as u32);
|
||||
let value = imply_features(value);
|
||||
assert!(value.test(Feature::zvkn as u32));
|
||||
assert!(value.test(Feature::zvknc as u32));
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
use core::mem;
|
||||
|
||||
use crate::detect::{Feature, bit, cache};
|
||||
|
|
@ -42,12 +41,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
// 0x8000_0000]. - The vendor ID is stored in 12 u8 ascii chars,
|
||||
// returned in EBX, EDX, and ECX (in that order):
|
||||
let (max_basic_leaf, vendor_id) = unsafe {
|
||||
let CpuidResult {
|
||||
eax: max_basic_leaf,
|
||||
ebx,
|
||||
ecx,
|
||||
edx,
|
||||
} = __cpuid(0);
|
||||
let CpuidResult { eax: max_basic_leaf, ebx, ecx, edx } = __cpuid(0);
|
||||
let vendor_id: [[u8; 4]; 3] = [ebx.to_ne_bytes(), edx.to_ne_bytes(), ecx.to_ne_bytes()];
|
||||
let vendor_id: [u8; 12] = mem::transmute(vendor_id);
|
||||
(max_basic_leaf, vendor_id)
|
||||
|
|
@ -60,11 +54,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
|
||||
// EAX = 1, ECX = 0: Queries "Processor Info and Feature Bits";
|
||||
// Contains information about most x86 features.
|
||||
let CpuidResult {
|
||||
ecx: proc_info_ecx,
|
||||
edx: proc_info_edx,
|
||||
..
|
||||
} = unsafe { __cpuid(0x0000_0001_u32) };
|
||||
let CpuidResult { ecx: proc_info_ecx, edx: proc_info_edx, .. } =
|
||||
unsafe { __cpuid(0x0000_0001_u32) };
|
||||
|
||||
// EAX = 7: Queries "Extended Features";
|
||||
// Contains information about bmi,bmi2, and avx2 support.
|
||||
|
|
@ -76,11 +67,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
extended_features_edx_leaf_1,
|
||||
) = if max_basic_leaf >= 7 {
|
||||
let CpuidResult { ebx, ecx, edx, .. } = unsafe { __cpuid(0x0000_0007_u32) };
|
||||
let CpuidResult {
|
||||
eax: eax_1,
|
||||
edx: edx_1,
|
||||
..
|
||||
} = unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) };
|
||||
let CpuidResult { eax: eax_1, edx: edx_1, .. } =
|
||||
unsafe { __cpuid_count(0x0000_0007_u32, 0x0000_0001_u32) };
|
||||
(ebx, ecx, edx, eax_1, edx_1)
|
||||
} else {
|
||||
(0, 0, 0, 0, 0) // CPUID does not support "Extended Features"
|
||||
|
|
@ -89,10 +77,7 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
// EAX = 0x8000_0000, ECX = 0: Get Highest Extended Function Supported
|
||||
// - EAX returns the max leaf value for extended information, that is,
|
||||
// `cpuid` calls in range [0x8000_0000; u32::MAX]:
|
||||
let CpuidResult {
|
||||
eax: extended_max_basic_leaf,
|
||||
..
|
||||
} = unsafe { __cpuid(0x8000_0000_u32) };
|
||||
let CpuidResult { eax: extended_max_basic_leaf, .. } = unsafe { __cpuid(0x8000_0000_u32) };
|
||||
|
||||
// EAX = 0x8000_0001, ECX=0: Queries "Extended Processor Info and Feature
|
||||
// Bits"
|
||||
|
|
@ -208,10 +193,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
// Processor Extended State Enumeration Sub-leaf (EAX = 0DH,
|
||||
// ECX = 1):
|
||||
if max_basic_leaf >= 0xd {
|
||||
let CpuidResult {
|
||||
eax: proc_extended_state1_eax,
|
||||
..
|
||||
} = unsafe { __cpuid_count(0xd_u32, 1) };
|
||||
let CpuidResult { eax: proc_extended_state1_eax, .. } =
|
||||
unsafe { __cpuid_count(0xd_u32, 1) };
|
||||
enable(proc_extended_state1_eax, 0, Feature::xsaveopt);
|
||||
enable(proc_extended_state1_eax, 1, Feature::xsavec);
|
||||
enable(proc_extended_state1_eax, 3, Feature::xsaves);
|
||||
|
|
@ -269,10 +252,8 @@ pub(crate) fn detect_features() -> cache::Initializer {
|
|||
enable(extended_features_edx_leaf_1, 8, Feature::amx_complex);
|
||||
|
||||
if max_basic_leaf >= 0x1e {
|
||||
let CpuidResult {
|
||||
eax: amx_feature_flags_eax,
|
||||
..
|
||||
} = unsafe { __cpuid_count(0x1e_u32, 1) };
|
||||
let CpuidResult { eax: amx_feature_flags_eax, .. } =
|
||||
unsafe { __cpuid_count(0x1e_u32, 1) };
|
||||
|
||||
enable(amx_feature_flags_eax, 4, Feature::amx_fp8);
|
||||
enable(amx_feature_flags_eax, 5, Feature::amx_transpose);
|
||||
|
|
@ -27,6 +27,16 @@
|
|||
),
|
||||
macro_use
|
||||
)]
|
||||
#[cfg(any(
|
||||
target_arch = "arm",
|
||||
target_arch = "aarch64",
|
||||
target_arch = "arm64ec",
|
||||
target_arch = "riscv32",
|
||||
target_arch = "riscv64",
|
||||
target_arch = "powerpc",
|
||||
target_arch = "powerpc64",
|
||||
target_arch = "s390x",
|
||||
))]
|
||||
extern crate std_detect;
|
||||
|
||||
#[test]
|
||||
|
|
@ -59,10 +69,7 @@ fn arm_linux() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
target_arch = "aarch64",
|
||||
any(target_os = "linux", target_os = "android")
|
||||
))]
|
||||
#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
|
||||
fn aarch64_linux() {
|
||||
println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
|
||||
println!("neon: {}", is_aarch64_feature_detected!("neon"));
|
||||
|
|
@ -97,10 +104,7 @@ fn aarch64_linux() {
|
|||
println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes"));
|
||||
println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4"));
|
||||
println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3"));
|
||||
println!(
|
||||
"sve2-bitperm: {}",
|
||||
is_aarch64_feature_detected!("sve2-bitperm")
|
||||
);
|
||||
println!("sve2-bitperm: {}", is_aarch64_feature_detected!("sve2-bitperm"));
|
||||
println!("frintts: {}", is_aarch64_feature_detected!("frintts"));
|
||||
println!("i8mm: {}", is_aarch64_feature_detected!("i8mm"));
|
||||
println!("f32mm: {}", is_aarch64_feature_detected!("f32mm"));
|
||||
|
|
@ -138,25 +142,13 @@ fn aarch64_linux() {
|
|||
println!("sme-lutv2: {}", is_aarch64_feature_detected!("sme-lutv2"));
|
||||
println!("sme-f8f16: {}", is_aarch64_feature_detected!("sme-f8f16"));
|
||||
println!("sme-f8f32: {}", is_aarch64_feature_detected!("sme-f8f32"));
|
||||
println!(
|
||||
"ssve-fp8fma: {}",
|
||||
is_aarch64_feature_detected!("ssve-fp8fma")
|
||||
);
|
||||
println!(
|
||||
"ssve-fp8dot4: {}",
|
||||
is_aarch64_feature_detected!("ssve-fp8dot4")
|
||||
);
|
||||
println!(
|
||||
"ssve-fp8dot2: {}",
|
||||
is_aarch64_feature_detected!("ssve-fp8dot2")
|
||||
);
|
||||
println!("ssve-fp8fma: {}", is_aarch64_feature_detected!("ssve-fp8fma"));
|
||||
println!("ssve-fp8dot4: {}", is_aarch64_feature_detected!("ssve-fp8dot4"));
|
||||
println!("ssve-fp8dot2: {}", is_aarch64_feature_detected!("ssve-fp8dot2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
any(target_arch = "aarch64", target_arch = "arm64ec"),
|
||||
target_os = "windows"
|
||||
))]
|
||||
#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_os = "windows"))]
|
||||
fn aarch64_windows() {
|
||||
println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
|
||||
println!("fp: {:?}", is_aarch64_feature_detected!("fp"));
|
||||
|
|
@ -171,10 +163,7 @@ fn aarch64_windows() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
target_arch = "aarch64",
|
||||
any(target_os = "freebsd", target_os = "openbsd")
|
||||
))]
|
||||
#[cfg(all(target_arch = "aarch64", any(target_os = "freebsd", target_os = "openbsd")))]
|
||||
fn aarch64_bsd() {
|
||||
println!("asimd: {:?}", is_aarch64_feature_detected!("asimd"));
|
||||
println!("pmull: {:?}", is_aarch64_feature_detected!("pmull"));
|
||||
|
|
@ -236,14 +225,8 @@ fn riscv_linux() {
|
|||
println!("rv32e: {}", is_riscv_feature_detected!("rv32e"));
|
||||
println!("rv64i: {}", is_riscv_feature_detected!("rv64i"));
|
||||
println!("rv128i: {}", is_riscv_feature_detected!("rv128i"));
|
||||
println!(
|
||||
"unaligned-scalar-mem: {}",
|
||||
is_riscv_feature_detected!("unaligned-scalar-mem")
|
||||
);
|
||||
println!(
|
||||
"unaligned-vector-mem: {}",
|
||||
is_riscv_feature_detected!("unaligned-vector-mem")
|
||||
);
|
||||
println!("unaligned-scalar-mem: {}", is_riscv_feature_detected!("unaligned-scalar-mem"));
|
||||
println!("unaligned-vector-mem: {}", is_riscv_feature_detected!("unaligned-vector-mem"));
|
||||
println!("zicsr: {}", is_riscv_feature_detected!("zicsr"));
|
||||
println!("zicntr: {}", is_riscv_feature_detected!("zicntr"));
|
||||
println!("zihpm: {}", is_riscv_feature_detected!("zihpm"));
|
||||
|
|
@ -336,10 +319,7 @@ fn powerpc_linux() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(
|
||||
target_arch = "powerpc64",
|
||||
any(target_os = "linux", target_os = "freebsd"),
|
||||
))]
|
||||
#[cfg(all(target_arch = "powerpc64", any(target_os = "linux", target_os = "freebsd"),))]
|
||||
fn powerpc64_linux_or_freebsd() {
|
||||
println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
|
||||
println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#![allow(internal_features)]
|
||||
#![feature(
|
||||
stdarch_internal,
|
||||
x86_amx_intrinsics,
|
||||
xop_target_feature,
|
||||
movrs_target_feature
|
||||
)]
|
||||
#![feature(stdarch_internal, x86_amx_intrinsics, xop_target_feature, movrs_target_feature)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate std_detect;
|
||||
|
|
@ -40,24 +35,15 @@ fn dump() {
|
|||
println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
|
||||
println!("avx512_ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
|
||||
println!("avx512vbmi {:?}", is_x86_feature_detected!("avx512vbmi"));
|
||||
println!(
|
||||
"avx512_vpopcntdq: {:?}",
|
||||
is_x86_feature_detected!("avx512vpopcntdq")
|
||||
);
|
||||
println!("avx512_vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
|
||||
println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
|
||||
println!("gfni: {:?}", is_x86_feature_detected!("gfni"));
|
||||
println!("vaes: {:?}", is_x86_feature_detected!("vaes"));
|
||||
println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq"));
|
||||
println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
|
||||
println!(
|
||||
"avx512bitalg: {:?}",
|
||||
is_x86_feature_detected!("avx512bitalg")
|
||||
);
|
||||
println!("avx512bitalg: {:?}", is_x86_feature_detected!("avx512bitalg"));
|
||||
println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16"));
|
||||
println!(
|
||||
"avx512vp2intersect: {:?}",
|
||||
is_x86_feature_detected!("avx512vp2intersect")
|
||||
);
|
||||
println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
|
||||
println!("avx512fp16: {:?}", is_x86_feature_detected!("avx512fp16"));
|
||||
println!("fma: {:?}", is_x86_feature_detected!("fma"));
|
||||
println!("abm: {:?}", is_x86_feature_detected!("abm"));
|
||||
|
|
@ -77,15 +63,9 @@ fn dump() {
|
|||
println!("movbe: {:?}", is_x86_feature_detected!("movbe"));
|
||||
println!("avxvnni: {:?}", is_x86_feature_detected!("avxvnni"));
|
||||
println!("avxvnniint8: {:?}", is_x86_feature_detected!("avxvnniint8"));
|
||||
println!(
|
||||
"avxneconvert: {:?}",
|
||||
is_x86_feature_detected!("avxneconvert")
|
||||
);
|
||||
println!("avxneconvert: {:?}", is_x86_feature_detected!("avxneconvert"));
|
||||
println!("avxifma: {:?}", is_x86_feature_detected!("avxifma"));
|
||||
println!(
|
||||
"avxvnniint16: {:?}",
|
||||
is_x86_feature_detected!("avxvnniint16")
|
||||
);
|
||||
println!("avxvnniint16: {:?}", is_x86_feature_detected!("avxvnniint16"));
|
||||
println!("amx-bf16: {:?}", is_x86_feature_detected!("amx-bf16"));
|
||||
println!("amx-tile: {:?}", is_x86_feature_detected!("amx-tile"));
|
||||
println!("amx-int8: {:?}", is_x86_feature_detected!("amx-int8"));
|
||||
|
|
@ -96,10 +76,7 @@ fn dump() {
|
|||
println!("widekl: {:?}", is_x86_feature_detected!("widekl"));
|
||||
println!("movrs: {:?}", is_x86_feature_detected!("movrs"));
|
||||
println!("amx-fp8: {:?}", is_x86_feature_detected!("amx-fp8"));
|
||||
println!(
|
||||
"amx-transpose: {:?}",
|
||||
is_x86_feature_detected!("amx-transpose")
|
||||
);
|
||||
println!("amx-transpose: {:?}", is_x86_feature_detected!("amx-transpose"));
|
||||
println!("amx-tf32: {:?}", is_x86_feature_detected!("amx-tf32"));
|
||||
println!("amx-avx512: {:?}", is_x86_feature_detected!("amx-avx512"));
|
||||
println!("amx-movrs: {:?}", is_x86_feature_detected!("amx-movrs"));
|
||||
|
|
@ -110,8 +87,5 @@ fn dump() {
|
|||
fn x86_deprecated() {
|
||||
println!("avx512gfni {:?}", is_x86_feature_detected!("avx512gfni"));
|
||||
println!("avx512vaes {:?}", is_x86_feature_detected!("avx512vaes"));
|
||||
println!(
|
||||
"avx512vpclmulqdq {:?}",
|
||||
is_x86_feature_detected!("avx512vpclmulqdq")
|
||||
);
|
||||
println!("avx512vpclmulqdq {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
|
||||
}
|
||||
13
library/stdarch/.github/workflows/main.yml
vendored
13
library/stdarch/.github/workflows/main.yml
vendored
|
|
@ -258,7 +258,7 @@ jobs:
|
|||
# Check that the generated files agree with the checked-in versions.
|
||||
check-stdarch-gen:
|
||||
needs: [style]
|
||||
name: Check stdarch-gen-{arm, loongarch} output
|
||||
name: Check stdarch-gen-{arm, loongarch} output
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -277,22 +277,11 @@ jobs:
|
|||
cargo run --bin=stdarch-gen-loongarch --release -- crates/stdarch-gen-loongarch/lasx.spec
|
||||
git diff --exit-code
|
||||
|
||||
build-std-detect:
|
||||
needs: [style]
|
||||
name: Build std_detect
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Rust
|
||||
run: rustup update nightly && rustup default nightly
|
||||
- run: ./ci/build-std-detect.sh
|
||||
|
||||
conclusion:
|
||||
needs:
|
||||
- docs
|
||||
- verify
|
||||
- test
|
||||
- build-std-detect
|
||||
- check-stdarch-gen
|
||||
runs-on: ubuntu-latest
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
|
|
|
|||
|
|
@ -580,18 +580,6 @@ version = "0.1.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-std-workspace-alloc"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9d441c3b2ebf55cebf796bfdc265d67fa09db17b7bb6bd4be75c509e1e8fec3"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-std-workspace-core"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa9c45b374136f52f2d6311062c7146bff20fec063c3f5d46a410bd937746955"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
|
|
@ -694,16 +682,6 @@ dependencies = [
|
|||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "std_detect"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdarch-gen-arm"
|
||||
version = "0.1.0"
|
||||
|
|
@ -756,7 +734,6 @@ dependencies = [
|
|||
"core_arch",
|
||||
"quickcheck",
|
||||
"rand",
|
||||
"std_detect",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -4,16 +4,8 @@ stdarch - Rust's standard library SIMD components
|
|||
[](https://github.com/rust-lang/stdarch/actions)
|
||||
|
||||
|
||||
# Crates
|
||||
|
||||
This repository contains two main crates:
|
||||
|
||||
* [`core_arch`](crates/core_arch/README.md) implements `core::arch` - Rust's
|
||||
core library architecture-specific intrinsics, and
|
||||
This repository contains the [`core_arch`](crates/core_arch/README.md) crate, which implements `core::arch` - Rust's core library architecture-specific intrinsics.
|
||||
|
||||
* [`std_detect`](crates/std_detect/README.md) implements `std::detect` - Rust's
|
||||
standard library run-time CPU feature detection.
|
||||
|
||||
The `std::simd` component now lives in the
|
||||
[`packed_simd_2`](https://github.com/rust-lang/packed_simd) crate.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Build std_detect on non-Linux & non-x86 targets.
|
||||
#
|
||||
# In std_detect, non-x86 targets have OS-specific implementations,
|
||||
# but we can test only Linux in CI. This script builds targets supported
|
||||
# by std_detect but cannot be tested in CI.
|
||||
|
||||
set -ex
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
targets=(
|
||||
# Linux
|
||||
aarch64-unknown-linux-musl
|
||||
armv5te-unknown-linux-musleabi
|
||||
aarch64-unknown-linux-ohos
|
||||
armv7-unknown-linux-ohos
|
||||
|
||||
# Android
|
||||
aarch64-linux-android
|
||||
arm-linux-androideabi
|
||||
|
||||
# FreeBSD
|
||||
aarch64-unknown-freebsd
|
||||
armv6-unknown-freebsd
|
||||
powerpc-unknown-freebsd
|
||||
powerpc64-unknown-freebsd
|
||||
|
||||
# OpenBSD
|
||||
aarch64-unknown-openbsd
|
||||
|
||||
# Windows
|
||||
aarch64-pc-windows-msvc
|
||||
)
|
||||
|
||||
rustup component add rust-src # for -Z build-std
|
||||
|
||||
cd crates/std_detect
|
||||
for target in "${targets[@]}"; do
|
||||
if rustup target add "${target}" &>/dev/null; then
|
||||
cargo build --target "${target}"
|
||||
else
|
||||
# tier 3 targets requires -Z build-std.
|
||||
cargo build -Z build-std="core,alloc" --target "${target}"
|
||||
fi
|
||||
done
|
||||
|
|
@ -16,10 +16,7 @@ dox() {
|
|||
cargo clean --target "${1}"
|
||||
|
||||
cargo build --verbose --target "${1}" --manifest-path crates/core_arch/Cargo.toml
|
||||
cargo build --verbose --target "${1}" --manifest-path crates/std_detect/Cargo.toml
|
||||
|
||||
cargo doc --verbose --target "${1}" --manifest-path crates/core_arch/Cargo.toml
|
||||
cargo doc --verbose --target "${1}" --manifest-path crates/std_detect/Cargo.toml
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ run() {
|
|||
--env NORUN \
|
||||
--env RUSTFLAGS \
|
||||
--env CARGO_UNSTABLE_BUILD_STD \
|
||||
--env RUST_STD_DETECT_UNSTABLE \
|
||||
--volume "${HOME}/.cargo":/cargo \
|
||||
--volume "$(rustc --print sysroot)":/rust:ro \
|
||||
--volume "$(pwd)":/checkout:ro \
|
||||
|
|
|
|||
|
|
@ -78,20 +78,12 @@ cargo_test() {
|
|||
}
|
||||
|
||||
CORE_ARCH="--manifest-path=crates/core_arch/Cargo.toml"
|
||||
STD_DETECT="--manifest-path=crates/std_detect/Cargo.toml"
|
||||
STDARCH_EXAMPLES="--manifest-path=examples/Cargo.toml"
|
||||
INTRINSIC_TEST="--manifest-path=crates/intrinsic-test/Cargo.toml"
|
||||
|
||||
cargo_test "${CORE_ARCH} ${PROFILE}"
|
||||
|
||||
if [ "$NOSTD" != "1" ]; then
|
||||
cargo_test "${STD_DETECT} ${PROFILE}"
|
||||
|
||||
cargo_test "${STD_DETECT} --no-default-features"
|
||||
cargo_test "${STD_DETECT} --no-default-features --features=std_detect_file_io"
|
||||
cargo_test "${STD_DETECT} --no-default-features --features=std_detect_dlsym_getauxval"
|
||||
cargo_test "${STD_DETECT} --no-default-features --features=std_detect_dlsym_getauxval,std_detect_file_io"
|
||||
|
||||
cargo_test "${STDARCH_EXAMPLES} ${PROFILE}"
|
||||
fi
|
||||
|
||||
|
|
@ -139,7 +131,7 @@ case ${TARGET} in
|
|||
cargo_test "${PROFILE}"
|
||||
;;
|
||||
|
||||
# Setup aarch64 & armv7 specific variables, the runner, along with some
|
||||
# Setup aarch64 & armv7 specific variables, the runner, along with some
|
||||
# tests to skip
|
||||
aarch64-unknown-linux-gnu*)
|
||||
TEST_CPPFLAGS="-fuse-ld=lld -I/usr/aarch64-linux-gnu/include/ -I/usr/aarch64-linux-gnu/include/c++/9/aarch64-linux-gnu/"
|
||||
|
|
|
|||
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2017 The Rust Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -12,7 +12,6 @@ default-run = "hex"
|
|||
|
||||
[dependencies]
|
||||
core_arch = { path = "../crates/core_arch" }
|
||||
std_detect = { path = "../crates/std_detect" }
|
||||
quickcheck = "1.0"
|
||||
rand = "0.8"
|
||||
|
||||
|
|
|
|||
|
|
@ -40,9 +40,13 @@ use std::cmp;
|
|||
use std::time::Instant;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
use {core_arch::arch::x86::*, std_detect::is_x86_feature_detected};
|
||||
use core_arch::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {core_arch::arch::x86_64::*, std_detect::is_x86_feature_detected};
|
||||
use core_arch::arch::x86_64::*;
|
||||
#[cfg(target_arch = "x86")]
|
||||
use std::is_x86_feature_detected;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::is_x86_feature_detected;
|
||||
|
||||
// types
|
||||
|
||||
|
|
@ -558,8 +562,12 @@ fn search(pos: &Pos, alpha: i32, beta: i32, depth: i32, _ply: i32) -> i32 {
|
|||
assert_ne!(bm, MOVE_NONE);
|
||||
assert!(bs >= -EVAL_INF && bs <= EVAL_INF);
|
||||
|
||||
// best move at the root node, best score elsewhere
|
||||
if _ply == 0 { bm } else { bs }
|
||||
//best move at the root node, best score elsewhere
|
||||
if _ply == 0 {
|
||||
bm
|
||||
} else {
|
||||
bs
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluation function: give different scores to different patterns after a fixed depth.
|
||||
|
|
|
|||
|
|
@ -36,9 +36,13 @@ use std::{
|
|||
};
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
use {core_arch::arch::x86::*, std_detect::is_x86_feature_detected};
|
||||
use core_arch::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use {core_arch::arch::x86_64::*, std_detect::is_x86_feature_detected};
|
||||
use core_arch::arch::x86_64::*;
|
||||
#[cfg(target_arch = "x86")]
|
||||
use std::is_x86_feature_detected;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::is_x86_feature_detected;
|
||||
|
||||
fn main() {
|
||||
let mut input = Vec::new();
|
||||
|
|
|
|||
|
|
@ -999,7 +999,7 @@ mod snapshot {
|
|||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustdoc 0 <host>
|
||||
[doc] std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
");
|
||||
}
|
||||
|
||||
|
|
@ -1048,7 +1048,7 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 0 <host> -> LintDocs 1 <host>
|
||||
[build] rustc 0 <host> -> RustInstaller 1 <host>
|
||||
|
|
@ -1090,7 +1090,7 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> WasmComponentLd 2 <host>
|
||||
[build] rustc 1 <host> -> LlvmBitcodeLinker 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 0 <host> -> LintDocs 1 <host>
|
||||
[build] rustc 0 <host> -> RustInstaller 1 <host>
|
||||
|
|
@ -1126,8 +1126,8 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 0 <host> -> LintDocs 1 <host>
|
||||
[build] rustc 0 <host> -> RustInstaller 1 <host>
|
||||
|
|
@ -1163,7 +1163,7 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 0 <host> -> LintDocs 1 <host>
|
||||
[build] rustc 1 <host> -> std 1 <target1>
|
||||
|
|
@ -1200,8 +1200,8 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 0 <host> -> LintDocs 1 <host>
|
||||
[build] rustc 1 <host> -> std 1 <target1>
|
||||
|
|
@ -1242,7 +1242,7 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> std 1 <host>
|
||||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 0 <host> -> RustInstaller 1 <host>
|
||||
[dist] docs <target1>
|
||||
|
|
@ -1274,7 +1274,7 @@ mod snapshot {
|
|||
[build] rustc 1 <host> -> rustc 2 <host>
|
||||
[build] rustc 1 <host> -> WasmComponentLd 2 <host>
|
||||
[build] rustdoc 1 <host>
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 2 <target1> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
[build] rustc 2 <host> -> std 2 <host>
|
||||
[build] rustc 1 <host> -> std 1 <target1>
|
||||
[build] rustc 2 <host> -> std 2 <target1>
|
||||
|
|
@ -1620,7 +1620,7 @@ mod snapshot {
|
|||
[build] llvm <host>
|
||||
[build] rustc 0 <host> -> rustc 1 <host>
|
||||
[build] rustdoc 0 <host>
|
||||
[doc] std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind]
|
||||
[doc] std 1 <host> crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,std_detect,sysroot,test,unwind]
|
||||
");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ use crate::walk::{filter_dirs, walk};
|
|||
// Paths that may contain platform-specific code.
|
||||
const EXCEPTION_PATHS: &[&str] = &[
|
||||
"library/compiler-builtins",
|
||||
"library/std_detect",
|
||||
"library/windows_targets",
|
||||
"library/panic_abort",
|
||||
"library/panic_unwind",
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ pub fn check(root_path: &Path, bad: &mut bool) {
|
|||
let line = line.trim();
|
||||
let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
|
||||
let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]");
|
||||
if !line.starts_with("//") && (is_test() || is_bench()) {
|
||||
let manual_skip = line.contains("//tidy:skip");
|
||||
if !line.starts_with("//") && (is_test() || is_bench()) && !manual_skip {
|
||||
let explanation = if is_core {
|
||||
"`core` unit tests and benchmarks must be placed into `coretests`"
|
||||
} else if is_alloc {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue