Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 23 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/assert-instr-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ test = false
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }
syn = { version = "3.0", features = ["full"] }

[lints.rust]
unexpected_cfgs = {level = "warn", check-cfg = ['cfg(optimized)'] }
1 change: 1 addition & 0 deletions crates/assert-instr-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub fn assert_instr(
let generic_ty_value = syn::TypePath {
qself: qself.clone(),
path: path.clone(),
attrs: Vec::new(),
};

// Replace any function arguments that use generic parameters with the
Expand Down
2 changes: 1 addition & 1 deletion crates/simd-test-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ test = false
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }
syn = { version = "3.0", features = ["full"] }
162 changes: 86 additions & 76 deletions crates/simd-test-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@
//!
//! This macro expands to a `#[test]` function which tests the local machine
//! for the appropriate cfg before calling the inner test function.
#![deny(rust_2018_idioms)]

#[macro_use]
extern crate quote;

use proc_macro2::{Ident, Span, TokenStream, TokenTree};
use quote::ToTokens;
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::{ToTokens, quote, quote_spanned};
use std::env;

#[proc_macro_attribute]
Expand All @@ -18,40 +14,32 @@ pub fn simd_test(
) -> proc_macro::TokenStream {
let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();

let target = env::var("TARGET").expect(
"TARGET environment variable should be set for rustc (e.g. TARGET=x86_64-apple-darwin cargo test)"
);
let target_arch = target
.split('-')
.next()
.unwrap_or_else(|| panic!("target triple contained no \"-\": {target}"));

let (target_features, target_feature_attr) = match &tokens[..] {
[] => (Vec::new(), TokenStream::new()),
[
TokenTree::Ident(enable),
TokenTree::Punct(equals),
TokenTree::Literal(literal),
] if enable == "enable" && equals.as_char() == '=' => {
let mut enable_feature = literal
.to_string()
.trim_start_matches('"')
.trim_end_matches('"')
.to_string();
let lit = literal.to_string();
let enable_feature = lit.trim_start_matches('"').trim_end_matches('"');
let target_features: Vec<_> = enable_feature
.replace('+', "")
.split(',')
.map(String::from)
.collect();
let mut enable_feature_arm = enable_feature.to_string();

// Allows using `#[simd_test(enable = "neon")]` on aarch64/armv7 shared tests.
if target_arch == "armv7" && target_features.iter().any(|feat| feat == "neon") {
enable_feature.push_str(",v7");
if target_features.iter().any(|feat| feat == "neon") {
enable_feature_arm.push_str(",v7");
}

(
target_features,
quote! {
#[target_feature(enable = #enable_feature)]
#[cfg_attr(target_arch = "arm", target_feature(enable = #enable_feature_arm))]
#[cfg_attr(not(target_arch = "arm"), target_feature(enable = #enable_feature))]
},
)
}
Expand All @@ -62,83 +50,105 @@ pub fn simd_test(
let item_attrs = std::mem::take(&mut item.attrs);
let name = &item.sig.ident;

let macro_test = match target_arch {
"i686" | "x86_64" | "i586" => "is_x86_feature_detected",
"arm" | "armv7" | "thumbv7neon" => "is_arm_feature_detected",
"aarch64" | "arm64ec" | "aarch64_be" => "is_aarch64_feature_detected",
maybe_riscv if maybe_riscv.starts_with("riscv") => "is_riscv_feature_detected",
"powerpc" | "powerpcle" | "powerpc64" | "powerpc64le" => "is_powerpc_feature_detected",
"loongarch32" | "loongarch64" => "is_loongarch_feature_detected",
"s390x" => "is_s390x_feature_detected",
"mips64" | "mips64el" => "is_mips64_feature_detected",
t => panic!("unknown target: {t}"),
};
let macro_test = Ident::new(macro_test, Span::call_site());

let skipped_functions = env::var("STDARCH_TEST_SKIP_FUNCTION").unwrap_or_default();
let skipped_features = env::var("STDARCH_TEST_SKIP_FEATURE").unwrap_or_default();

let mut name_str = &*name.to_string();
if name_str.starts_with("test_") {
name_str = &name_str[5..];
}

let skip_this = skipped_functions
let skipped_functions = env::var("STDARCH_TEST_SKIP_FUNCTION").unwrap_or_default();
let skipped_features = env::var("STDARCH_TEST_SKIP_FEATURE").unwrap_or_default();
let skipped_function = skipped_functions
.split(',')
.map(str::trim)
.any(|s| s == name_str);
let skipped_feature = skipped_features
.split(',')
.map(str::trim)
.any(|s| s == name_str)
|| skipped_features
.split(',')
.map(str::trim)
.any(|s| target_features.iter().any(|feature| s == feature));
.any(|s| target_features.iter().any(|feature| s == feature));

let mut detect_missing_features = TokenStream::new();
for feature in target_features {
let q = if target_arch == "armv7" && feature == "fp16" {
// "fp16" cannot be checked at runtime
quote_spanned! {
proc_macro2::Span::call_site() =>
if !cfg!(target_feature = #feature) {
missing_features.push(#feature);
}
let mut q = quote_spanned! { Span::call_site() =>
// Default target feature check
if !test_macro!(#feature) {
missing_features.push(#feature);
}
} else {
quote_spanned! {
proc_macro2::Span::call_site() =>
if !::std::arch::#macro_test!(#feature) {
missing_features.push(#feature);
};

// For features that cannot be checked at runtime (currently fp16 on arm32), use the
// static check instead.
if feature == "fp16" {
q = quote_spanned! { Span::call_site() =>
cfg_select! {
target_arch = "arm" => {
if !cfg!(target_feature = #feature) {
missing_features.push(#feature);
}
}
_ => {
#q
}
}
}
};
}

q.to_tokens(&mut detect_missing_features);
}

let maybe_ignore = if skip_this {
quote! { #[ignore] }
} else {
TokenStream::new()
};
let mut maybe_ignore = TokenStream::new();
let mut const_test = TokenStream::new();
let mut const_stability = TokenStream::new();

let (const_test, const_stability) = if item.sig.constness.is_some() {
(
quote! {
const _: () = unsafe { #name() };
},
quote! {
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
},
)
} else {
(TokenStream::new(), TokenStream::new())
};
if skipped_function || skipped_feature {
maybe_ignore = quote! { #[ignore] }
}

let ret: TokenStream = quote_spanned! {
proc_macro2::Span::call_site() =>
if item.sig.constness.is_some() {
const_test = quote! {
const _: () = unsafe { #name() };
};
const_stability = quote! {
#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
};
}

let ret: TokenStream = quote_spanned! { Span::call_site() =>
#[allow(non_snake_case)]
#[test]
#maybe_ignore
#(#item_attrs)*
fn #name() {
cfg_select! {
any(target_arch = "x86", target_arch = "x86_64") => {
use std::arch::is_x86_feature_detected as test_macro;
}
target_arch = "arm" => {
use std::arch::is_arm_feature_detected as test_macro;
}
any(target_arch = "aarch64", target_arch = "arm64ec") => {
use std::arch::is_aarch64_feature_detected as test_macro;
}
any(target_arch = "riscv32", target_arch = "riscv64") => {
use std::arch::is_riscv_feature_detected as test_macro;
}
any(target_arch = "powerpc", target_arch = "powerpc64") => {
use std::arch::is_powerpc_feature_detected as test_macro;
}
any(target_arch = "loongarch32", target_arch = "loongarch64") => {
use std::arch::is_loongarch_feature_detected as test_macro;
}
target_arch = "s390x" => {
use std::arch::is_s390x_feature_detected as test_macro;
}
any(target_arch = "mips", target_arch = "mips32r6") => {
use std::arch::is_mips_feature_detected as test_macro;
}
any(target_arch = "mips64", target_arch = "mips64r6") => {
use std::arch::is_mips64_feature_detected as test_macro;
}
_ => compile_error!("unknown target; need to update simd-test-macro"),
}

#const_test

let mut missing_features = ::std::vec::Vec::new();
Expand Down
2 changes: 1 addition & 1 deletion crates/stdarch-verify/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2024"
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }
syn = { version = "3.0", features = ["full"] }

[lib]
proc-macro = true
Expand Down
Loading
Loading