]>
Commit | Line | Data |
---|---|---|
0531ce1d XL |
1 | extern crate proc_macro; |
2 | extern crate proc_macro2; | |
3 | #[macro_use] | |
4 | extern crate quote; | |
5 | #[macro_use] | |
6 | extern crate syn; | |
7 | ||
0531ce1d XL |
8 | use std::fs::File; |
9 | use std::io::Read; | |
83c7162d | 10 | use std::path::Path; |
0531ce1d XL |
11 | |
12 | use proc_macro::TokenStream; | |
0531ce1d XL |
13 | |
14 | #[proc_macro] | |
15 | pub 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] | |
20 | pub fn arm_functions(input: TokenStream) -> TokenStream { | |
9fa01778 | 21 | functions(input, &["core_arch/src/arm", "core_arch/src/aarch64"]) |
0731742a XL |
22 | } |
23 | ||
24 | fn 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 | 102 | fn 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 | ||
195 | fn 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 | ||
220 | fn 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 | ||
249 | fn 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 | ||
280 | fn 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 | ||
304 | fn 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 | ||
319 | struct RustcArgsRequiredConst { | |
320 | args: Vec<usize>, | |
321 | } | |
322 | ||
0bf4aa26 | 323 | impl 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 | } |