]> git.proxmox.com Git - rustc.git/blame - src/stdsimd/crates/stdsimd-verify/src/lib.rs
New upstream version 1.35.0+dfsg1
[rustc.git] / src / stdsimd / crates / stdsimd-verify / src / lib.rs
CommitLineData
0531ce1d
XL
1extern crate proc_macro;
2extern crate proc_macro2;
3#[macro_use]
4extern crate quote;
5#[macro_use]
6extern crate syn;
7
0531ce1d
XL
8use std::fs::File;
9use std::io::Read;
83c7162d 10use std::path::Path;
0531ce1d
XL
11
12use proc_macro::TokenStream;
0531ce1d
XL
13
14#[proc_macro]
15pub fn x86_functions(input: TokenStream) -> TokenStream {
9fa01778 16 functions(input, &["core_arch/src/x86", "core_arch/src/x86_64"])
0731742a
XL
17}
18
19#[proc_macro]
20pub fn arm_functions(input: TokenStream) -> TokenStream {
9fa01778 21 functions(input, &["core_arch/src/arm", "core_arch/src/aarch64"])
0731742a
XL
22}
23
24fn functions(input: TokenStream, dirs: &[&str]) -> TokenStream {
0531ce1d 25 let dir = Path::new(env!("CARGO_MANIFEST_DIR"));
532ac7d7 26 let root = dir.parent().expect("root-dir not found");
0531ce1d
XL
27
28 let mut files = Vec::new();
0731742a
XL
29 for dir in dirs {
30 walk(&root.join(dir), &mut files);
31 }
32 assert!(!files.is_empty());
0531ce1d
XL
33
34 let mut functions = Vec::new();
0731742a 35 for &mut (ref mut file, ref path) in &mut files {
0531ce1d 36 for item in file.items.drain(..) {
0731742a
XL
37 if let syn::Item::Fn(f) = item {
38 functions.push((f, path))
0531ce1d
XL
39 }
40 }
41 }
0731742a 42 assert!(!functions.is_empty());
0531ce1d
XL
43
44 functions.retain(|&(ref f, _)| {
0731742a
XL
45 if let syn::Visibility::Public(_) = f.vis {
46 if f.unsafety.is_some() {
47 return true;
48 }
0531ce1d 49 }
0731742a 50 false
0531ce1d 51 });
0731742a 52 assert!(!functions.is_empty());
0531ce1d
XL
53
54 let input = proc_macro2::TokenStream::from(input);
55
56 let functions = functions
57 .iter()
58 .map(|&(ref f, path)| {
8faf50e0 59 let name = &f.ident;
0531ce1d
XL
60 // println!("{}", name);
61 let mut arguments = Vec::new();
62 for input in f.decl.inputs.iter() {
63 let ty = match *input {
64 syn::FnArg::Captured(ref c) => &c.ty,
65 _ => panic!("invalid argument on {}", name),
66 };
67 arguments.push(to_type(ty));
68 }
69 let ret = match f.decl.output {
8faf50e0 70 syn::ReturnType::Default => quote! { None },
0531ce1d
XL
71 syn::ReturnType::Type(_, ref t) => {
72 let ty = to_type(t);
8faf50e0 73 quote! { Some(#ty) }
0531ce1d
XL
74 }
75 };
76 let instrs = find_instrs(&f.attrs);
0731742a
XL
77 let target_feature = if let Some(i) = find_target_feature(&f.attrs) {
78 quote! { Some(#i) }
79 } else {
80 quote! { None }
0531ce1d
XL
81 };
82 let required_const = find_required_const(&f.attrs);
8faf50e0 83 quote! {
0531ce1d
XL
84 Function {
85 name: stringify!(#name),
86 arguments: &[#(#arguments),*],
87 ret: #ret,
88 target_feature: #target_feature,
89 instrs: &[#(stringify!(#instrs)),*],
90 file: stringify!(#path),
91 required_const: &[#(#required_const),*],
92 }
93 }
0731742a
XL
94 })
95 .collect::<Vec<_>>();
0531ce1d 96
8faf50e0 97 let ret = quote! { #input: &[Function] = &[#(#functions),*]; };
0531ce1d
XL
98 // println!("{}", ret);
99 ret.into()
100}
101
8faf50e0 102fn to_type(t: &syn::Type) -> proc_macro2::TokenStream {
0531ce1d 103 match *t {
0731742a
XL
104 syn::Type::Path(ref p) => match extract_path_ident(&p.path).to_string().as_ref() {
105 // x86 ...
106 "__m128" => quote! { &M128 },
107 "__m128d" => quote! { &M128D },
108 "__m128i" => quote! { &M128I },
109 "__m256" => quote! { &M256 },
110 "__m256d" => quote! { &M256D },
111 "__m256i" => quote! { &M256I },
112 "__m512" => quote! { &M512 },
113 "__m512d" => quote! { &M512D },
114 "__m512i" => quote! { &M512I },
115 "__mmask16" => quote! { &MMASK16 },
116 "__m64" => quote! { &M64 },
117 "bool" => quote! { &BOOL },
118 "f32" => quote! { &F32 },
119 "f64" => quote! { &F64 },
120 "i16" => quote! { &I16 },
121 "i32" => quote! { &I32 },
122 "i64" => quote! { &I64 },
123 "i8" => quote! { &I8 },
124 "u16" => quote! { &U16 },
125 "u32" => quote! { &U32 },
126 "u64" => quote! { &U64 },
127 "u128" => quote! { &U128 },
128 "u8" => quote! { &U8 },
129 "Ordering" => quote! { &ORDERING },
130 "CpuidResult" => quote! { &CPUID },
131
132 // arm ...
133 "int8x4_t" => quote! { &I8X4 },
134 "int8x8_t" => quote! { &I8X8 },
135 "int8x8x2_t" => quote! { &I8X8X2 },
136 "int8x8x3_t" => quote! { &I8X8X3 },
137 "int8x8x4_t" => quote! { &I8X8X4 },
138 "int8x16x2_t" => quote! { &I8X16X2 },
139 "int8x16x3_t" => quote! { &I8X16X3 },
140 "int8x16x4_t" => quote! { &I8X16X4 },
141 "int8x16_t" => quote! { &I8X16 },
142 "int16x2_t" => quote! { &I16X2 },
143 "int16x4_t" => quote! { &I16X4 },
144 "int16x8_t" => quote! { &I16X8 },
145 "int32x2_t" => quote! { &I32X2 },
146 "int32x4_t" => quote! { &I32X4 },
147 "int64x1_t" => quote! { &I64X1 },
148 "int64x2_t" => quote! { &I64X2 },
149 "uint8x8_t" => quote! { &U8X8 },
150 "uint8x8x2_t" => quote! { &U8X8X2 },
151 "uint8x16x2_t" => quote! { &U8X16X2 },
152 "uint8x16x3_t" => quote! { &U8X16X3 },
153 "uint8x16x4_t" => quote! { &U8X16X4 },
154 "uint8x8x3_t" => quote! { &U8X8X3 },
155 "uint8x8x4_t" => quote! { &U8X8X4 },
156 "uint8x16_t" => quote! { &U8X16 },
157 "uint16x4_t" => quote! { &U16X4 },
158 "uint16x8_t" => quote! { &U16X8 },
159 "uint32x2_t" => quote! { &U32X2 },
160 "uint32x4_t" => quote! { &U32X4 },
161 "uint64x1_t" => quote! { &U64X1 },
162 "uint64x2_t" => quote! { &U64X2 },
163 "float32x2_t" => quote! { &F32X2 },
164 "float32x4_t" => quote! { &F32X4 },
165 "float64x1_t" => quote! { &F64X1 },
166 "float64x2_t" => quote! { &F64X2 },
167 "poly8x8_t" => quote! { &POLY8X8 },
168 "poly8x8x2_t" => quote! { &POLY8X8X2 },
169 "poly8x8x3_t" => quote! { &POLY8X8X3 },
170 "poly8x8x4_t" => quote! { &POLY8X8X4 },
171 "poly8x16x2_t" => quote! { &POLY8X16X2 },
172 "poly8x16x3_t" => quote! { &POLY8X16X3 },
173 "poly8x16x4_t" => quote! { &POLY8X16X4 },
174 "poly64x1_t" => quote! { &POLY64X1 },
175 "poly64x2_t" => quote! { &POLY64X2 },
176 "poly8x16_t" => quote! { &POLY8X16 },
177 "poly16x4_t" => quote! { &POLY16X4 },
178 "poly16x8_t" => quote! { &POLY16X8 },
179
180 s => panic!("unspported type: \"{}\"", s),
181 },
0531ce1d
XL
182 syn::Type::Ptr(syn::TypePtr { ref elem, .. })
183 | syn::Type::Reference(syn::TypeReference { ref elem, .. }) => {
184 let tokens = to_type(&elem);
8faf50e0 185 quote! { &Type::Ptr(#tokens) }
0531ce1d
XL
186 }
187 syn::Type::Slice(_) => panic!("unsupported slice"),
188 syn::Type::Array(_) => panic!("unsupported array"),
8faf50e0 189 syn::Type::Tuple(_) => quote! { &TUPLE },
0731742a 190 syn::Type::Never(_) => quote! { &NEVER },
0531ce1d
XL
191 _ => panic!("unsupported type"),
192 }
193}
194
195fn extract_path_ident(path: &syn::Path) -> syn::Ident {
196 if path.leading_colon.is_some() {
197 panic!("unsupported leading colon in path")
198 }
199 if path.segments.len() != 1 {
200 panic!("unsupported path that needs name resolution")
201 }
532ac7d7
XL
202 match path
203 .segments
204 .first()
205 .expect("segment not found")
206 .value()
207 .arguments
208 {
0531ce1d
XL
209 syn::PathArguments::None => {}
210 _ => panic!("unsupported path that has path arguments"),
211 }
532ac7d7
XL
212 path.segments
213 .first()
214 .expect("segment not found")
215 .value()
216 .ident
217 .clone()
0531ce1d
XL
218}
219
220fn walk(root: &Path, files: &mut Vec<(syn::File, String)>) {
221 for file in root.read_dir().unwrap() {
222 let file = file.unwrap();
223 if file.file_type().unwrap().is_dir() {
224 walk(&file.path(), files);
225 continue;
226 }
227 let path = file.path();
228 if path.extension().and_then(|s| s.to_str()) != Some("rs") {
229 continue;
230 }
231
232 if path.file_name().and_then(|s| s.to_str()) == Some("test.rs") {
233 continue;
234 }
235
236 let mut contents = String::new();
237 File::open(&path)
532ac7d7 238 .expect(&format!("can't open file at path: {}", path.display()))
0531ce1d 239 .read_to_string(&mut contents)
532ac7d7 240 .expect("failed to read file to string");
0531ce1d
XL
241
242 files.push((
243 syn::parse_str::<syn::File>(&contents).expect("failed to parse"),
244 path.display().to_string(),
245 ));
246 }
247}
248
249fn find_instrs(attrs: &[syn::Attribute]) -> Vec<syn::Ident> {
250 attrs
251 .iter()
252 .filter_map(|a| a.interpret_meta())
253 .filter_map(|a| match a {
254 syn::Meta::List(i) => {
255 if i.ident == "cfg_attr" {
256 i.nested.into_iter().nth(1)
257 } else {
258 None
259 }
260 }
261 _ => None,
0731742a
XL
262 })
263 .filter_map(|nested| match nested {
0531ce1d
XL
264 syn::NestedMeta::Meta(syn::Meta::List(i)) => {
265 if i.ident == "assert_instr" {
266 i.nested.into_iter().next()
267 } else {
268 None
269 }
270 }
271 _ => None,
0731742a
XL
272 })
273 .filter_map(|nested| match nested {
0531ce1d
XL
274 syn::NestedMeta::Meta(syn::Meta::Word(i)) => Some(i),
275 _ => None,
0731742a
XL
276 })
277 .collect()
0531ce1d
XL
278}
279
280fn find_target_feature(attrs: &[syn::Attribute]) -> Option<syn::Lit> {
281 attrs
282 .iter()
0731742a
XL
283 .flat_map(|a| {
284 if let Some(a) = a.interpret_meta() {
285 if let syn::Meta::List(i) = a {
286 if i.ident == "target_feature" {
287 return i.nested;
288 }
0531ce1d
XL
289 }
290 }
0731742a
XL
291 syn::punctuated::Punctuated::new()
292 })
0531ce1d
XL
293 .filter_map(|nested| match nested {
294 syn::NestedMeta::Meta(m) => Some(m),
295 syn::NestedMeta::Literal(_) => None,
0731742a
XL
296 })
297 .filter_map(|m| match m {
298 syn::Meta::NameValue(ref i) if i.ident == "enable" => Some(i.clone().lit),
0531ce1d 299 _ => None,
0731742a
XL
300 })
301 .next()
0531ce1d
XL
302}
303
304fn find_required_const(attrs: &[syn::Attribute]) -> Vec<usize> {
305 attrs
306 .iter()
0731742a
XL
307 .flat_map(|a| {
308 if a.path.segments[0].ident == "rustc_args_required_const" {
309 syn::parse::<RustcArgsRequiredConst>(a.tts.clone().into())
310 .unwrap()
311 .args
312 } else {
313 Vec::new()
314 }
315 })
0531ce1d
XL
316 .collect()
317}
318
319struct RustcArgsRequiredConst {
320 args: Vec<usize>,
321}
322
0bf4aa26 323impl syn::parse::Parse for RustcArgsRequiredConst {
0731742a 324 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_possible_truncation))]
0bf4aa26
XL
325 fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> {
326 let content;
327 parenthesized!(content in input);
0731742a
XL
328 let list =
329 syn::punctuated::Punctuated::<syn::LitInt, Token![,]>::parse_terminated(&content)?;
330 Ok(Self {
331 args: list.into_iter().map(|a| a.value() as usize).collect(),
0531ce1d 332 })
0bf4aa26 333 }
0531ce1d 334}