2017-09-26 12:37:39 -07:00
|
|
|
//! Implementation of the `#[simd_test]` macro
|
|
|
|
|
//!
|
2017-10-27 17:55:29 +02:00
|
|
|
//! This macro expands to a `#[test]` function which tests the local machine
|
|
|
|
|
//! for the appropriate cfg before calling the inner test function.
|
2017-09-26 12:37:39 -07:00
|
|
|
|
|
|
|
|
#![feature(proc_macro)]
|
|
|
|
|
|
2017-10-27 17:55:29 +02:00
|
|
|
extern crate proc_macro;
|
2018-02-02 16:08:27 +01:00
|
|
|
extern crate proc_macro2;
|
2017-09-26 12:37:39 -07:00
|
|
|
#[macro_use]
|
|
|
|
|
extern crate quote;
|
|
|
|
|
|
2017-10-27 17:55:29 +02:00
|
|
|
use proc_macro2::{Term, TokenNode, TokenStream, TokenTree};
|
2017-09-26 12:37:39 -07:00
|
|
|
use proc_macro2::Literal;
|
|
|
|
|
|
|
|
|
|
fn string(s: &str) -> TokenTree {
|
2018-01-08 10:10:52 -08:00
|
|
|
TokenNode::Literal(Literal::string(s)).into()
|
2017-09-26 12:37:39 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[proc_macro_attribute]
|
2017-10-27 17:55:29 +02:00
|
|
|
pub fn simd_test(
|
|
|
|
|
attr: proc_macro::TokenStream, item: proc_macro::TokenStream
|
|
|
|
|
) -> proc_macro::TokenStream {
|
2017-09-26 12:37:39 -07:00
|
|
|
let tokens = TokenStream::from(attr).into_iter().collect::<Vec<_>>();
|
|
|
|
|
if tokens.len() != 2 {
|
|
|
|
|
panic!("expected #[simd_test = \"feature\"]");
|
|
|
|
|
}
|
|
|
|
|
match tokens[0].kind {
|
|
|
|
|
TokenNode::Op('=', _) => {}
|
|
|
|
|
_ => panic!("expected #[simd_test = \"feature\"]"),
|
|
|
|
|
}
|
2017-11-13 17:48:40 +01:00
|
|
|
let target_features = match tokens[1].kind {
|
|
|
|
|
TokenNode::Literal(ref l) => l.to_string(),
|
|
|
|
|
_ => panic!("expected #[simd_test = \"feature\"]"),
|
|
|
|
|
};
|
|
|
|
|
let target_features: Vec<String> = target_features
|
|
|
|
|
.replace('"', "")
|
|
|
|
|
.replace('+', "")
|
|
|
|
|
.split(',')
|
|
|
|
|
.map(|v| String::from(v))
|
|
|
|
|
.collect();
|
|
|
|
|
|
2017-09-26 12:37:39 -07:00
|
|
|
let enable_feature = match tokens[1].kind {
|
|
|
|
|
TokenNode::Literal(ref l) => l.to_string(),
|
|
|
|
|
_ => panic!("expected #[simd_test = \"feature\"]"),
|
|
|
|
|
};
|
2017-10-27 17:55:29 +02:00
|
|
|
let enable_feature = enable_feature
|
|
|
|
|
.trim_left_matches('"')
|
|
|
|
|
.trim_right_matches('"');
|
2018-01-17 09:45:02 -06:00
|
|
|
let enable_feature = string(enable_feature);
|
2017-09-26 12:37:39 -07:00
|
|
|
let item = TokenStream::from(item);
|
|
|
|
|
let name = find_name(item.clone());
|
|
|
|
|
|
|
|
|
|
let name: TokenStream = name.as_str().parse().unwrap();
|
|
|
|
|
|
2017-11-13 17:48:40 +01:00
|
|
|
let mut cfg_target_features = quote::Tokens::new();
|
|
|
|
|
use quote::ToTokens;
|
|
|
|
|
for feature in target_features {
|
2017-11-21 12:54:06 -06:00
|
|
|
let q = quote_spanned! {
|
2018-01-08 10:10:52 -08:00
|
|
|
proc_macro2::Span::call_site() =>
|
2018-02-18 10:07:35 +09:00
|
|
|
is_target_feature_detected!(#feature) &&
|
2017-11-13 17:48:40 +01:00
|
|
|
};
|
|
|
|
|
q.to_tokens(&mut cfg_target_features);
|
|
|
|
|
}
|
|
|
|
|
let q = quote!{ true };
|
|
|
|
|
q.to_tokens(&mut cfg_target_features);
|
|
|
|
|
|
2017-11-21 12:54:06 -06:00
|
|
|
let ret: TokenStream = quote_spanned! {
|
2018-01-08 10:10:52 -08:00
|
|
|
proc_macro2::Span::call_site() =>
|
2017-10-11 17:28:44 +02:00
|
|
|
#[allow(non_snake_case)]
|
2017-09-26 12:37:39 -07:00
|
|
|
#[test]
|
|
|
|
|
fn #name() {
|
2017-11-13 17:48:40 +01:00
|
|
|
if #cfg_target_features {
|
2017-09-27 10:16:35 -04:00
|
|
|
return unsafe { #name() };
|
2017-10-18 11:35:11 -04:00
|
|
|
} else {
|
|
|
|
|
::stdsimd_test::assert_skip_test_ok(stringify!(#name));
|
2017-09-26 12:37:39 -07:00
|
|
|
}
|
|
|
|
|
|
2018-01-17 09:45:02 -06:00
|
|
|
#[target_feature(enable = #enable_feature)]
|
2017-09-26 12:37:39 -07:00
|
|
|
#item
|
|
|
|
|
}
|
|
|
|
|
}.into();
|
|
|
|
|
ret.into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn find_name(item: TokenStream) -> Term {
|
|
|
|
|
let mut tokens = item.into_iter();
|
|
|
|
|
while let Some(tok) = tokens.next() {
|
|
|
|
|
if let TokenNode::Term(word) = tok.kind {
|
|
|
|
|
if word.as_str() == "fn" {
|
2017-10-27 17:55:29 +02:00
|
|
|
break;
|
2017-09-26 12:37:39 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match tokens.next().map(|t| t.kind) {
|
|
|
|
|
Some(TokenNode::Term(word)) => word,
|
|
|
|
|
_ => panic!("failed to find function name"),
|
|
|
|
|
}
|
|
|
|
|
}
|