Reorganize and refactor source tree (#324)
With RFC 2325 looking close to being accepted, I took a crack at reorganizing this repository to being more amenable for inclusion in libstd/libcore. My current plan is to add stdsimd as a submodule in rust-lang/rust and then use `#[path]` to include the modules directly into libstd/libcore. Before this commit, however, the source code of coresimd/stdsimd themselves were not quite ready for this. Imports wouldn't compile for one reason or another, and the organization was also different than the RFC itself! In addition to moving a lot of files around, this commit has the following major changes: * The `cfg_feature_enabled!` macro is now renamed to `is_target_feature_detected!` * The `vendor` module is now called `arch`. * Under the `arch` module is a suite of modules like `x86`, `x86_64`, etc. One per `cfg!(target_arch)`. * The `is_target_feature_detected!` macro was removed from coresimd. Unfortunately libcore has no ability to export unstable macros, so for now all feature detection is canonicalized in stdsimd. The `coresimd` and `stdsimd` crates have been updated to the planned organization in RFC 2325 as well. The runtime bits saw the largest amount of refactoring, seeing a good deal of simplification without the core/std split.
This commit is contained in:
155
library/stdarch/crates/assert-instr-macro/src/lib.rs
Normal file
155
library/stdarch/crates/assert-instr-macro/src/lib.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
//! Implementation of the `#[assert_instr]` macro
|
||||
//!
|
||||
//! This macro is used when testing the `stdsimd` crate and is used to generate
|
||||
//! test cases to assert that functions do indeed contain the instructions that
|
||||
//! we're expecting them to contain.
|
||||
//!
|
||||
//! The procedural macro here is relatively simple, it simply appends a
|
||||
//! `#[test]` function to the original token stream which asserts that the
|
||||
//! function itself contains the relevant instruction.
|
||||
|
||||
#![feature(proc_macro)]
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate proc_macro2;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
#[macro_use]
|
||||
extern crate syn;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn assert_instr(
|
||||
attr: proc_macro::TokenStream, item: proc_macro::TokenStream
|
||||
) -> proc_macro::TokenStream {
|
||||
let invoc = syn::parse::<Invoc>(attr)
|
||||
.expect("expected #[assert_instr(instr, a = b, ...)]");
|
||||
let item =
|
||||
syn::parse::<syn::Item>(item).expect("must be attached to an item");
|
||||
let func = match item {
|
||||
syn::Item::Fn(ref f) => f,
|
||||
_ => panic!("must be attached to a function"),
|
||||
};
|
||||
|
||||
let instr = &invoc.instr;
|
||||
let maybe_ignore = if cfg!(optimized) {
|
||||
TokenStream::empty()
|
||||
} else {
|
||||
(quote! { #[ignore] }).into()
|
||||
};
|
||||
let name = &func.ident;
|
||||
let assert_name = syn::Ident::from(
|
||||
&format!("assert_{}_{}", name.as_ref(), instr.as_ref())[..],
|
||||
);
|
||||
let shim_name = syn::Ident::from(format!("{}_shim", name.as_ref()));
|
||||
let mut inputs = Vec::new();
|
||||
let mut input_vals = Vec::new();
|
||||
let ret = &func.decl.output;
|
||||
for arg in func.decl.inputs.iter() {
|
||||
let capture = match *arg {
|
||||
syn::FnArg::Captured(ref c) => c,
|
||||
_ => panic!("arguments must not have patterns"),
|
||||
};
|
||||
let ident = match capture.pat {
|
||||
syn::Pat::Ident(ref i) => &i.ident,
|
||||
_ => panic!("must have bare arguments"),
|
||||
};
|
||||
match invoc.args.iter().find(|a| a.0 == ident.as_ref()) {
|
||||
Some(&(_, ref tts)) => {
|
||||
input_vals.push(quote! { #tts });
|
||||
}
|
||||
None => {
|
||||
inputs.push(capture);
|
||||
input_vals.push(quote! { #ident });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let attrs = func.attrs
|
||||
.iter()
|
||||
.filter(|attr| {
|
||||
attr.path
|
||||
.segments
|
||||
.first()
|
||||
.unwrap()
|
||||
.value()
|
||||
.ident
|
||||
.as_ref()
|
||||
.starts_with("target")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let attrs = Append(&attrs);
|
||||
|
||||
// Use an ABI on Windows that passes SIMD values in registers, like what
|
||||
// happens on Unix (I think?) by default.
|
||||
let abi = if cfg!(windows) {
|
||||
syn::LitStr::new("vectorcall", proc_macro2::Span::call_site())
|
||||
} else {
|
||||
syn::LitStr::new("C", proc_macro2::Span::call_site())
|
||||
};
|
||||
let to_test = quote! {
|
||||
#attrs
|
||||
unsafe extern #abi fn #shim_name(#(#inputs),*) #ret {
|
||||
#name(#(#input_vals),*)
|
||||
}
|
||||
};
|
||||
|
||||
let tts: TokenStream = quote_spanned! {
|
||||
proc_macro2::Span::call_site() =>
|
||||
#[test]
|
||||
#[allow(non_snake_case)]
|
||||
#maybe_ignore
|
||||
fn #assert_name() {
|
||||
#to_test
|
||||
|
||||
::stdsimd_test::assert(#shim_name as usize,
|
||||
stringify!(#shim_name),
|
||||
stringify!(#instr));
|
||||
}
|
||||
}.into();
|
||||
// why? necessary now to get tests to work?
|
||||
let tts: TokenStream = tts.to_string().parse().unwrap();
|
||||
|
||||
let tts: TokenStream = quote! {
|
||||
#item
|
||||
#tts
|
||||
}.into();
|
||||
tts.into()
|
||||
}
|
||||
|
||||
struct Invoc {
|
||||
instr: syn::Ident,
|
||||
args: Vec<(syn::Ident, syn::Expr)>,
|
||||
}
|
||||
|
||||
impl syn::synom::Synom for Invoc {
|
||||
named!(parse -> Self, map!(parens!(do_parse!(
|
||||
instr: syn!(syn::Ident) >>
|
||||
args: many0!(do_parse!(
|
||||
syn!(syn::token::Comma) >>
|
||||
name: syn!(syn::Ident) >>
|
||||
syn!(syn::token::Eq) >>
|
||||
expr: syn!(syn::Expr) >>
|
||||
(name, expr)
|
||||
)) >>
|
||||
(Invoc {
|
||||
instr,
|
||||
args,
|
||||
})
|
||||
)), |p| p.1));
|
||||
}
|
||||
|
||||
struct Append<T>(T);
|
||||
|
||||
impl<T> quote::ToTokens for Append<T>
|
||||
where
|
||||
T: Clone + IntoIterator,
|
||||
T::Item: quote::ToTokens,
|
||||
{
|
||||
fn to_tokens(&self, tokens: &mut quote::Tokens) {
|
||||
for item in self.0.clone() {
|
||||
item.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user