1 #![allow(bad_style)]
2 #![allow(unused)]
3 use std::{collections::HashMap, rc::Rc};
4 
5 use html5ever::{
6     driver::ParseOpts,
7     parse_document,
8     rcdom::{Node, NodeData, RcDom},
9     tendril::TendrilSink,
10     tree_builder::TreeBuilderOpts,
11 };
12 
13 struct Function {
14     name: &'static str,
15     arguments: &'static [&'static Type],
16     ret: Option<&'static Type>,
17     target_feature: Option<&'static str>,
18     instrs: &'static [&'static str],
19     file: &'static str,
20     required_const: &'static [usize],
21     has_test: bool,
22 }
23 
24 static F16: Type = Type::PrimFloat(16);
25 static F32: Type = Type::PrimFloat(32);
26 static F64: Type = Type::PrimFloat(64);
27 static I16: Type = Type::PrimSigned(16);
28 static I32: Type = Type::PrimSigned(32);
29 static I64: Type = Type::PrimSigned(64);
30 static I8: Type = Type::PrimSigned(8);
31 static U16: Type = Type::PrimUnsigned(16);
32 static U32: Type = Type::PrimUnsigned(32);
33 static U64: Type = Type::PrimUnsigned(64);
34 static U8: Type = Type::PrimUnsigned(8);
35 static NEVER: Type = Type::Never;
36 
37 static F16X4: Type = Type::F(16, 4, 1);
38 static F16X4X2: Type = Type::F(16, 4, 2);
39 static F16X4X3: Type = Type::F(16, 4, 3);
40 static F16X4X4: Type = Type::F(16, 4, 4);
41 static F16X8: Type = Type::F(16, 8, 1);
42 static F16X8X2: Type = Type::F(16, 8, 2);
43 static F16X8X3: Type = Type::F(16, 8, 3);
44 static F16X8X4: Type = Type::F(16, 8, 4);
45 static F32X2: Type = Type::F(32, 2, 1);
46 static F32X2X2: Type = Type::F(32, 2, 2);
47 static F32X2X3: Type = Type::F(32, 2, 3);
48 static F32X2X4: Type = Type::F(32, 2, 4);
49 static F32X4: Type = Type::F(32, 4, 1);
50 static F32X4X2: Type = Type::F(32, 4, 2);
51 static F32X4X3: Type = Type::F(32, 4, 3);
52 static F32X4X4: Type = Type::F(32, 4, 4);
53 static F64X1: Type = Type::F(64, 1, 1);
54 static F64X1X2: Type = Type::F(64, 1, 2);
55 static F64X1X3: Type = Type::F(64, 1, 3);
56 static F64X1X4: Type = Type::F(64, 1, 4);
57 static F64X2: Type = Type::F(64, 2, 1);
58 static F64X2X2: Type = Type::F(64, 2, 2);
59 static F64X2X3: Type = Type::F(64, 2, 3);
60 static F64X2X4: Type = Type::F(64, 2, 4);
61 static I16X2: Type = Type::I(16, 2, 1);
62 static I16X4: Type = Type::I(16, 4, 1);
63 static I16X4X2: Type = Type::I(16, 4, 2);
64 static I16X4X3: Type = Type::I(16, 4, 3);
65 static I16X4X4: Type = Type::I(16, 4, 4);
66 static I16X8: Type = Type::I(16, 8, 1);
67 static I16X8X2: Type = Type::I(16, 8, 2);
68 static I16X8X3: Type = Type::I(16, 8, 3);
69 static I16X8X4: Type = Type::I(16, 8, 4);
70 static I32X2: Type = Type::I(32, 2, 1);
71 static I32X2X2: Type = Type::I(32, 2, 2);
72 static I32X2X3: Type = Type::I(32, 2, 3);
73 static I32X2X4: Type = Type::I(32, 2, 4);
74 static I32X4: Type = Type::I(32, 4, 1);
75 static I32X4X2: Type = Type::I(32, 4, 2);
76 static I32X4X3: Type = Type::I(32, 4, 3);
77 static I32X4X4: Type = Type::I(32, 4, 4);
78 static I64X1: Type = Type::I(64, 1, 1);
79 static I64X1X2: Type = Type::I(64, 1, 2);
80 static I64X1X3: Type = Type::I(64, 1, 3);
81 static I64X1X4: Type = Type::I(64, 1, 4);
82 static I64X2: Type = Type::I(64, 2, 1);
83 static I64X2X2: Type = Type::I(64, 2, 2);
84 static I64X2X3: Type = Type::I(64, 2, 3);
85 static I64X2X4: Type = Type::I(64, 2, 4);
86 static I8X16: Type = Type::I(8, 16, 1);
87 static I8X16X2: Type = Type::I(8, 16, 2);
88 static I8X16X3: Type = Type::I(8, 16, 3);
89 static I8X16X4: Type = Type::I(8, 16, 4);
90 static I8X4: Type = Type::I(8, 4, 1);
91 static I8X8: Type = Type::I(8, 8, 1);
92 static I8X8X2: Type = Type::I(8, 8, 2);
93 static I8X8X3: Type = Type::I(8, 8, 3);
94 static I8X8X4: Type = Type::I(8, 8, 4);
95 static P128: Type = Type::PrimPoly(128);
96 static P16: Type = Type::PrimPoly(16);
97 static P16X4X2: Type = Type::P(16, 4, 2);
98 static P16X4X3: Type = Type::P(16, 4, 3);
99 static P16X4X4: Type = Type::P(16, 4, 4);
100 static P16X8X2: Type = Type::P(16, 8, 2);
101 static P16X8X3: Type = Type::P(16, 8, 3);
102 static P16X8X4: Type = Type::P(16, 8, 4);
103 static P64: Type = Type::PrimPoly(64);
104 static P64X1X2: Type = Type::P(64, 1, 2);
105 static P64X1X3: Type = Type::P(64, 1, 3);
106 static P64X1X4: Type = Type::P(64, 1, 4);
107 static P64X2X2: Type = Type::P(64, 2, 2);
108 static P64X2X3: Type = Type::P(64, 2, 3);
109 static P64X2X4: Type = Type::P(64, 2, 4);
110 static P8: Type = Type::PrimPoly(8);
111 static POLY16X4: Type = Type::P(16, 4, 1);
112 static POLY16X8: Type = Type::P(16, 8, 1);
113 static POLY64X1: Type = Type::P(64, 1, 1);
114 static POLY64X2: Type = Type::P(64, 2, 1);
115 static POLY8X16: Type = Type::P(8, 16, 1);
116 static POLY8X16X2: Type = Type::P(8, 16, 2);
117 static POLY8X16X3: Type = Type::P(8, 16, 3);
118 static POLY8X16X4: Type = Type::P(8, 16, 4);
119 static POLY8X8: Type = Type::P(8, 8, 1);
120 static POLY8X8X2: Type = Type::P(8, 8, 2);
121 static POLY8X8X3: Type = Type::P(8, 8, 3);
122 static POLY8X8X4: Type = Type::P(8, 8, 4);
123 static U16X4: Type = Type::U(16, 4, 1);
124 static U16X4X2: Type = Type::U(16, 4, 2);
125 static U16X4X3: Type = Type::U(16, 4, 3);
126 static U16X4X4: Type = Type::U(16, 4, 4);
127 static U16X8: Type = Type::U(16, 8, 1);
128 static U16X8X2: Type = Type::U(16, 8, 2);
129 static U16X8X3: Type = Type::U(16, 8, 3);
130 static U16X8X4: Type = Type::U(16, 8, 4);
131 static U32X2: Type = Type::U(32, 2, 1);
132 static U32X2X2: Type = Type::U(32, 2, 2);
133 static U32X2X3: Type = Type::U(32, 2, 3);
134 static U32X2X4: Type = Type::U(32, 2, 4);
135 static U32X4: Type = Type::U(32, 4, 1);
136 static U32X4X2: Type = Type::U(32, 4, 2);
137 static U32X4X3: Type = Type::U(32, 4, 3);
138 static U32X4X4: Type = Type::U(32, 4, 4);
139 static U64X1: Type = Type::U(64, 1, 1);
140 static U64X1X2: Type = Type::U(64, 1, 2);
141 static U64X1X3: Type = Type::U(64, 1, 3);
142 static U64X1X4: Type = Type::U(64, 1, 4);
143 static U64X2: Type = Type::U(64, 2, 1);
144 static U64X2X2: Type = Type::U(64, 2, 2);
145 static U64X2X3: Type = Type::U(64, 2, 3);
146 static U64X2X4: Type = Type::U(64, 2, 4);
147 static U8X16: Type = Type::U(8, 16, 1);
148 static U8X16X2: Type = Type::U(8, 16, 2);
149 static U8X16X3: Type = Type::U(8, 16, 3);
150 static U8X16X4: Type = Type::U(8, 16, 4);
151 static U8X8: Type = Type::U(8, 8, 1);
152 static U8X4: Type = Type::U(8, 4, 1);
153 static U8X8X2: Type = Type::U(8, 8, 2);
154 static U8X8X3: Type = Type::U(8, 8, 3);
155 static U8X8X4: Type = Type::U(8, 8, 4);
156 
157 #[derive(Debug, Copy, Clone, PartialEq)]
158 enum Type {
159     PrimFloat(u8),
160     PrimSigned(u8),
161     PrimUnsigned(u8),
162     PrimPoly(u8),
163     MutPtr(&'static Type),
164     ConstPtr(&'static Type),
165     I(u8, u8, u8),
166     U(u8, u8, u8),
167     P(u8, u8, u8),
168     F(u8, u8, u8),
169     Never,
170 }
171 
172 stdarch_verify::arm_functions!(static FUNCTIONS);
173 
174 macro_rules! bail {
175     ($($t:tt)*) => (return Err(format!($($t)*)))
176 }
177 
178 #[test]
verify_all_signatures()179 fn verify_all_signatures() {
180     // This is a giant HTML blob downloaded from
181     // https://developer.arm.com/technologies/neon/intrinsics which contains all
182     // NEON intrinsics at least. We do manual HTML parsing below.
183     let html = include_bytes!("../arm-intrinsics.html");
184     let mut html = &html[..];
185     let opts = ParseOpts {
186         tree_builder: TreeBuilderOpts {
187             drop_doctype: true,
188             ..Default::default()
189         },
190         ..Default::default()
191     };
192     let dom = parse_document(RcDom::default(), opts)
193         .from_utf8()
194         .read_from(&mut html)
195         .unwrap();
196 
197     let accordion = find_accordion(&dom.document).unwrap();
198     let map = parse_intrinsics(&accordion);
199 
200     let mut all_valid = true;
201     'outer: for rust in FUNCTIONS {
202         if !rust.has_test {
203             let skip = [
204                 "vaddq_s64",
205                 "vaddq_u64",
206                 "vrsqrte_f32",
207                 "vtbl1_s8",
208                 "vtbl1_u8",
209                 "vtbl1_p8",
210                 "vtbl2_s8",
211                 "vtbl2_u8",
212                 "vtbl2_p8",
213                 "vtbl3_s8",
214                 "vtbl3_u8",
215                 "vtbl3_p8",
216                 "vtbl4_s8",
217                 "vtbl4_u8",
218                 "vtbl4_p8",
219                 "vtbx1_s8",
220                 "vtbx1_u8",
221                 "vtbx1_p8",
222                 "vtbx2_s8",
223                 "vtbx2_u8",
224                 "vtbx2_p8",
225                 "vtbx3_s8",
226                 "vtbx3_u8",
227                 "vtbx3_p8",
228                 "vtbx4_s8",
229                 "vtbx4_u8",
230                 "vtbx4_p8",
231                 "udf",
232                 "_clz_u8",
233                 "_clz_u16",
234                 "_clz_u32",
235                 "_rbit_u32",
236                 "_rev_u16",
237                 "_rev_u32",
238                 "__breakpoint",
239                 "vpminq_f32",
240                 "vpminq_f64",
241                 "vpmaxq_f32",
242                 "vpmaxq_f64",
243                 "vcombine_s8",
244                 "vcombine_s16",
245                 "vcombine_s32",
246                 "vcombine_s64",
247                 "vcombine_u8",
248                 "vcombine_u16",
249                 "vcombine_u32",
250                 "vcombine_u64",
251                 "vcombine_p64",
252                 "vcombine_f32",
253                 "vcombine_p8",
254                 "vcombine_p16",
255                 "vcombine_f64",
256                 "vtbl1_s8",
257                 "vtbl1_u8",
258                 "vtbl1_p8",
259                 "vtbl2_s8",
260                 "vtbl2_u8",
261                 "vtbl2_p8",
262                 "vtbl3_s8",
263                 "vtbl3_u8",
264                 "vtbl3_p8",
265                 "vtbl4_s8",
266                 "vtbl4_u8",
267                 "vtbl4_p8",
268                 "vtbx1_s8",
269                 "vtbx1_u8",
270                 "vtbx1_p8",
271                 "vtbx2_s8",
272                 "vtbx2_u8",
273                 "vtbx2_p8",
274                 "vtbx3_s8",
275                 "vtbx3_u8",
276                 "vtbx3_p8",
277                 "vtbx4_s8",
278                 "vtbx4_u8",
279                 "vtbx4_p8",
280                 "vqtbl1_s8",
281                 "vqtbl1q_s8",
282                 "vqtbl1_u8",
283                 "vqtbl1q_u8",
284                 "vqtbl1_p8",
285                 "vqtbl1q_p8",
286                 "vqtbx1_s8",
287                 "vqtbx1q_s8",
288                 "vqtbx1_u8",
289                 "vqtbx1q_u8",
290                 "vqtbx1_p8",
291                 "vqtbx1q_p8",
292                 "vqtbl2_s8",
293                 "vqtbl2q_s8",
294                 "vqtbl2_u8",
295                 "vqtbl2q_u8",
296                 "vqtbl2_p8",
297                 "vqtbl2q_p8",
298                 "vqtbx2_s8",
299                 "vqtbx2q_s8",
300                 "vqtbx2_u8",
301                 "vqtbx2q_u8",
302                 "vqtbx2_p8",
303                 "vqtbx2q_p8",
304                 "vqtbl3_s8",
305                 "vqtbl3q_s8",
306                 "vqtbl3_u8",
307                 "vqtbl3q_u8",
308                 "vqtbl3_p8",
309                 "vqtbl3q_p8",
310                 "vqtbx3_s8",
311                 "vqtbx3q_s8",
312                 "vqtbx3_u8",
313                 "vqtbx3q_u8",
314                 "vqtbx3_p8",
315                 "vqtbx3q_p8",
316                 "vqtbl4_s8",
317                 "vqtbl4q_s8",
318                 "vqtbl4_u8",
319                 "vqtbl4q_u8",
320                 "vqtbl4_p8",
321                 "vqtbl4q_p8",
322                 "vqtbx4_s8",
323                 "vqtbx4q_s8",
324                 "vqtbx4_u8",
325                 "vqtbx4q_u8",
326                 "vqtbx4_p8",
327                 "vqtbx4q_p8",
328                 "brk",
329                 "_rev_u64",
330                 "_clz_u64",
331                 "_rbit_u64",
332                 "_cls_u32",
333                 "_cls_u64",
334                 "_prefetch",
335                 "vsli_n_s8",
336                 "vsliq_n_s8",
337                 "vsli_n_s16",
338                 "vsliq_n_s16",
339                 "vsli_n_s32",
340                 "vsliq_n_s32",
341                 "vsli_n_s64",
342                 "vsliq_n_s64",
343                 "vsli_n_u8",
344                 "vsliq_n_u8",
345                 "vsli_n_u16",
346                 "vsliq_n_u16",
347                 "vsli_n_u32",
348                 "vsliq_n_u32",
349                 "vsli_n_u64",
350                 "vsliq_n_u64",
351                 "vsli_n_p8",
352                 "vsliq_n_p8",
353                 "vsli_n_p16",
354                 "vsliq_n_p16",
355                 "vsli_n_p64",
356                 "vsliq_n_p64",
357                 "vsri_n_s8",
358                 "vsriq_n_s8",
359                 "vsri_n_s16",
360                 "vsriq_n_s16",
361                 "vsri_n_s32",
362                 "vsriq_n_s32",
363                 "vsri_n_s64",
364                 "vsriq_n_s64",
365                 "vsri_n_u8",
366                 "vsriq_n_u8",
367                 "vsri_n_u16",
368                 "vsriq_n_u16",
369                 "vsri_n_u32",
370                 "vsriq_n_u32",
371                 "vsri_n_u64",
372                 "vsriq_n_u64",
373                 "vsri_n_p8",
374                 "vsriq_n_p8",
375                 "vsri_n_p16",
376                 "vsriq_n_p16",
377                 "vsri_n_p64",
378                 "vsriq_n_p64",
379                 "__smulbb",
380                 "__smultb",
381                 "__smulbt",
382                 "__smultt",
383                 "__smulwb",
384                 "__smulwt",
385                 "__qadd",
386                 "__qsub",
387                 "__qdbl",
388                 "__smlabb",
389                 "__smlabt",
390                 "__smlatb",
391                 "__smlatt",
392                 "__smlawb",
393                 "__smlawt",
394                 "__qadd8",
395                 "__qsub8",
396                 "__qsub16",
397                 "__qadd16",
398                 "__qasx",
399                 "__qsax",
400                 "__sadd16",
401                 "__sadd8",
402                 "__smlad",
403                 "__smlsd",
404                 "__sasx",
405                 "__sel",
406                 "__shadd8",
407                 "__shadd16",
408                 "__shsub8",
409                 "__usub8",
410                 "__ssub8",
411                 "__shsub16",
412                 "__smuad",
413                 "__smuadx",
414                 "__smusd",
415                 "__smusdx",
416                 "__usad8",
417                 "__usada8",
418                 "__ldrex",
419                 "__strex",
420                 "__ldrexb",
421                 "__strexb",
422                 "__ldrexh",
423                 "__strexh",
424                 "__clrex",
425                 "__dbg",
426             ];
427             if !skip.contains(&rust.name) {
428                 println!(
429                     "missing run-time test named `test_{}` for `{}`",
430                     {
431                         let mut id = rust.name;
432                         while id.starts_with('_') {
433                             id = &id[1..];
434                         }
435                         id
436                     },
437                     rust.name
438                 );
439                 all_valid = false;
440             }
441         }
442 
443         // Skip some intrinsics that aren't NEON and are located in different
444         // places than the whitelists below.
445         match rust.name {
446             "brk" | "__breakpoint" | "udf" | "_prefetch" => continue,
447             _ => {}
448         }
449         // Skip some intrinsics that are present in GCC and Clang but
450         // are missing from the official documentation.
451         let skip_intrinsic_verify = [
452             "vmov_n_p64",
453             "vmovq_n_p64",
454             "vreinterpret_p64_s64",
455             "vreinterpret_f32_p64",
456             "vreinterpretq_f32_p64",
457             "vreinterpretq_p64_p128",
458             "vreinterpretq_p128_p64",
459             "vreinterpretq_f32_p128",
460             "vqrdmlahh_s16",
461             "vqrdmlahs_s32",
462             "vqrdmlahh_lane_s16",
463             "vqrdmlahh_laneq_s16",
464             "vqrdmlahs_lane_s32",
465             "vqrdmlahs_laneq_s32",
466             "vqrdmlah_s16",
467             "vqrdmlah_s32",
468             "vqrdmlahq_s16",
469             "vqrdmlahq_s32",
470             "vqrdmlah_lane_s16",
471             "vqrdmlah_laneq_s16",
472             "vqrdmlahq_lane_s16",
473             "vqrdmlahq_laneq_s16",
474             "vqrdmlah_lane_s32",
475             "vqrdmlah_laneq_s32",
476             "vqrdmlahq_lane_s32",
477             "vqrdmlahq_laneq_s32",
478             "vqrdmlshh_s16",
479             "vqrdmlshs_s32",
480             "vqrdmlshh_lane_s16",
481             "vqrdmlshh_laneq_s16",
482             "vqrdmlshs_lane_s32",
483             "vqrdmlshs_laneq_s32",
484             "vqrdmlsh_s16",
485             "vqrdmlshq_s16",
486             "vqrdmlsh_s32",
487             "vqrdmlshq_s32",
488             "vqrdmlsh_lane_s16",
489             "vqrdmlsh_laneq_s16",
490             "vqrdmlshq_lane_s16",
491             "vqrdmlshq_laneq_s16",
492             "vqrdmlsh_lane_s32",
493             "vqrdmlsh_laneq_s32",
494             "vqrdmlshq_lane_s32",
495             "vqrdmlshq_laneq_s32",
496             "vcadd_rot270_f32",
497             "vcadd_rot90_f32",
498             "vcaddq_rot270_f32",
499             "vcaddq_rot270_f64",
500             "vcaddq_rot90_f32",
501             "vcaddq_rot90_f64",
502             "vcmla_f32",
503             "vcmlaq_f32",
504             "vcmlaq_f64",
505             "vcmla_rot90_f32",
506             "vcmlaq_rot90_f32",
507             "vcmlaq_rot90_f64",
508             "vcmla_rot180_f32",
509             "vcmlaq_rot180_f32",
510             "vcmlaq_rot180_f64",
511             "vcmla_rot270_f32",
512             "vcmlaq_rot270_f32",
513             "vcmlaq_rot270_f64",
514             "vcmla_lane_f32",
515             "vcmla_laneq_f32",
516             "vcmlaq_lane_f32",
517             "vcmlaq_laneq_f32",
518             "vcmla_rot90_lane_f32",
519             "vcmla_rot90_laneq_f32",
520             "vcmlaq_rot90_lane_f32",
521             "vcmlaq_rot90_laneq_f32",
522             "vcmla_rot180_lane_f32",
523             "vcmla_rot180_laneq_f32",
524             "vcmlaq_rot180_lane_f32",
525             "vcmlaq_rot180_laneq_f32",
526             "vcmla_rot270_lane_f32",
527             "vcmla_rot270_laneq_f32",
528             "vcmlaq_rot270_lane_f32",
529             "vcmlaq_rot270_laneq_f32",
530             "vdot_s32",
531             "vdot_u32",
532             "vdotq_s32",
533             "vdotq_u32",
534             "vdot_lane_s32",
535             "vdot_laneq_s32",
536             "vdotq_lane_s32",
537             "vdotq_laneq_s32",
538             "vdot_lane_u32",
539             "vdot_laneq_u32",
540             "vdotq_lane_u32",
541             "vdotq_laneq_u32",
542             "vbcaxq_s8",
543             "vbcaxq_s16",
544             "vbcaxq_s32",
545             "vbcaxq_s64",
546             "vbcaxq_u8",
547             "vbcaxq_u16",
548             "vbcaxq_u32",
549             "vbcaxq_u64",
550             "veor3q_s8",
551             "veor3q_s16",
552             "veor3q_s32",
553             "veor3q_s64",
554             "veor3q_u8",
555             "veor3q_u16",
556             "veor3q_u32",
557             "veor3q_u64",
558             "vadd_p8",
559             "vadd_p16",
560             "vadd_p64",
561             "vaddq_p8",
562             "vaddq_p16",
563             "vaddq_p64",
564             "vaddq_p128",
565             "vsm4ekeyq_u32",
566             "vsm4eq_u32",
567             "vmmlaq_s32",
568             "vmmlaq_u32",
569             "vusmmlaq_s32",
570             "vsm3partw1q_u32",
571             "vsm3partw2q_u32",
572             "vsm3ss1q_u32",
573             "vsm3tt1aq_u32",
574             "vsm3tt1bq_u32",
575             "vsm3tt2aq_u32",
576             "vsm3tt2bq_u32",
577             "vrax1q_u64",
578             "vxarq_u64",
579             "vsha512hq_u64",
580             "vsha512h2q_u64",
581             "vsha512su0q_u64",
582             "vsha512su1q_u64",
583             "vrnd32x_f32",
584             "vrnd32xq_f32",
585             "vrnd32z_f32",
586             "vrnd32zq_f32",
587             "vrnd64x_f32",
588             "vrnd64xq_f32",
589             "vrnd64z_f32",
590             "vrnd64zq_f32",
591             "vcls_u8",
592             "vcls_u16",
593             "vcls_u32",
594             "vclsq_u8",
595             "vclsq_u16",
596             "vclsq_u32",
597             "__dbg",
598         ];
599         let arm = match map.get(rust.name) {
600             Some(i) => i,
601             None => {
602                 // Skip all these intrinsics as they're not listed in NEON
603                 // descriptions online.
604                 //
605                 // TODO: we still need to verify these intrinsics or find a
606                 // reference for them, need to figure out where though!
607                 if !rust.file.ends_with("dsp.rs\"")
608                     && !rust.file.ends_with("simd32.rs\"")
609                     && !rust.file.ends_with("cmsis.rs\"")
610                     && !rust.file.ends_with("v6.rs\"")
611                     && !rust.file.ends_with("v7.rs\"")
612                     && !rust.file.ends_with("v8.rs\"")
613                     && !rust.file.ends_with("tme.rs\"")
614                     && !rust.file.ends_with("ex.rs\"")
615                     && !skip_intrinsic_verify.contains(&rust.name)
616                 {
617                     println!(
618                         "missing arm definition for {:?} in {}",
619                         rust.name, rust.file
620                     );
621                     all_valid = false;
622                 }
623                 continue;
624             }
625         };
626 
627         if let Err(e) = matches(rust, arm) {
628             println!("failed to verify `{}`", rust.name);
629             println!("  * {}", e);
630             all_valid = false;
631         }
632     }
633     assert!(all_valid);
634 }
635 
matches(rust: &Function, arm: &Intrinsic) -> Result<(), String>636 fn matches(rust: &Function, arm: &Intrinsic) -> Result<(), String> {
637     if rust.ret != arm.ret.as_ref() {
638         bail!("mismatched return value")
639     }
640     if rust.arguments.len() != arm.arguments.len() {
641         bail!("mismatched argument lengths");
642     }
643 
644     let mut nconst = 0;
645     let iter = rust.arguments.iter().zip(&arm.arguments).enumerate();
646     for (i, (rust_ty, (arm, arm_const))) in iter {
647         if *rust_ty != arm {
648             bail!("mismatched arguments")
649         }
650         if *arm_const {
651             nconst += 1;
652             if !rust.required_const.contains(&i) {
653                 bail!("argument const mismatch");
654             }
655         }
656     }
657     if nconst != rust.required_const.len() {
658         bail!("wrong number of const arguments");
659     }
660 
661     if rust.instrs.is_empty() {
662         bail!(
663             "instruction not listed for `{}`, but arm lists {:?}",
664             rust.name,
665             arm.instruction
666         );
667     } else if false
668     /* not super reliable, but can be used to manually check */
669     {
670         for instr in rust.instrs {
671             if arm.instruction.starts_with(instr) {
672                 continue;
673             }
674             // sometimes arm says `foo` and disassemblers say `vfoo`, or
675             // sometimes disassemblers say `vfoo` and arm says `sfoo` or `ffoo`
676             if instr.starts_with('v')
677                 && (arm.instruction.starts_with(&instr[1..])
678                     || arm.instruction[1..].starts_with(&instr[1..]))
679             {
680                 continue;
681             }
682             bail!(
683                 "arm failed to list `{}` as an instruction for `{}` in {:?}",
684                 instr,
685                 rust.name,
686                 arm.instruction,
687             );
688         }
689     }
690 
691     // TODO: verify `target_feature`.
692 
693     Ok(())
694 }
695 
find_accordion(node: &Rc<Node>) -> Option<Rc<Node>>696 fn find_accordion(node: &Rc<Node>) -> Option<Rc<Node>> {
697     if let NodeData::Element { attrs, .. } = &node.data {
698         for attr in attrs.borrow().iter() {
699             if attr.name.local.eq_str_ignore_ascii_case("class")
700                 && attr.value.to_string() == "intrinsic-accordion"
701             {
702                 return Some(node.clone());
703             }
704         }
705     }
706 
707     node.children
708         .borrow()
709         .iter()
710         .filter_map(|node| find_accordion(node))
711         .next()
712 }
713 
714 #[derive(PartialEq)]
715 struct Intrinsic {
716     name: String,
717     ret: Option<Type>,
718     arguments: Vec<(Type, bool)>,
719     instruction: String,
720 }
721 
parse_intrinsics(node: &Rc<Node>) -> HashMap<String, Intrinsic>722 fn parse_intrinsics(node: &Rc<Node>) -> HashMap<String, Intrinsic> {
723     let mut ret = HashMap::new();
724     for child in node.children.borrow().iter() {
725         if let NodeData::Element { .. } = child.data {
726             let f = parse_intrinsic(child);
727             ret.insert(f.name.clone(), f);
728         }
729     }
730     ret
731 }
732 
parse_intrinsic(node: &Rc<Node>) -> Intrinsic733 fn parse_intrinsic(node: &Rc<Node>) -> Intrinsic {
734     // <div class='intrinsic'>
735     //  <input>...</input>
736     //  <label for=$name>
737     //    <div>
738     //      $signature...
739     //  <article>
740     //    ...
741 
742     let children = node.children.borrow();
743     let mut children = children
744         .iter()
745         .filter(|node| matches!(node.data, NodeData::Element { .. }));
746     let _input = children.next().expect("no <input>");
747     let label = children.next().expect("no <label>");
748     let article = children.next().expect("no <article>");
749     assert!(children.next().is_none());
750 
751     // Find `for="..."` in `<label>`
752     let name = match &label.data {
753         NodeData::Element { attrs, .. } => attrs
754             .borrow()
755             .iter()
756             .filter(|attr| attr.name.local.eq_str_ignore_ascii_case("for"))
757             .map(|attr| attr.value.to_string())
758             .next()
759             .expect("no `for` attribute"),
760         _ => panic!(),
761     };
762 
763     // Find contents of inner `<div>` in `<label>`
764     let label_children = label.children.borrow();
765     let mut label_children = label_children
766         .iter()
767         .filter(|node| matches!(node.data, NodeData::Element { .. }));
768     let label_div = label_children.next().expect("no <div> in <label>");
769     assert!(label_children.next().is_none());
770     let text = label_div.children.borrow();
771     let mut text = text.iter().filter_map(|node| match &node.data {
772         NodeData::Text { contents } => Some(contents.borrow().to_string()),
773         _ => None,
774     });
775     let ret = text.next().unwrap();
776     let ret = ret.trim();
777     let args = text.next().unwrap();
778     let args = args.trim();
779     assert!(text.next().is_none());
780 
781     // Find the instruction within the article
782     let article_children = article.children.borrow();
783     let mut article_children = article_children
784         .iter()
785         .filter(|node| matches!(node.data, NodeData::Element { .. }));
786     let mut instruction = None;
787     while let Some(child) = article_children.next() {
788         let mut header = String::new();
789         collect_text(&mut header, child);
790         if !header.ends_with(" Instruction") {
791             continue;
792         }
793         let next = article_children.next().expect("no next child");
794         assert!(instruction.is_none());
795         let mut instr = String::new();
796         collect_text(&mut instr, &next);
797         instruction = Some(instr);
798     }
799 
800     let instruction = match instruction {
801         Some(s) => s.trim().to_lowercase(),
802         None => panic!("can't find instruction for `{}`", name),
803     };
804 
805     Intrinsic {
806         name,
807         ret: if ret == "void" {
808             None
809         } else {
810             Some(parse_ty(ret))
811         },
812         instruction,
813         arguments: args // "(...)"
814             .trim_start_matches('(') // "...)"
815             .trim_end_matches(')') // "..."
816             .split(',') // " Type name ", ".."
817             .map(|s| s.trim()) // "Type name"
818             .map(|s| s.rsplitn(2, ' ').nth(1).unwrap()) // "Type"
819             .map(|s| {
820                 let const_ = "const ";
821                 if s.starts_with(const_) {
822                     (parse_ty(&s[const_.len()..]), true)
823                 } else {
824                     (parse_ty(s), false)
825                 }
826             })
827             .collect(),
828     }
829 }
830 
parse_ty(s: &str) -> Type831 fn parse_ty(s: &str) -> Type {
832     let suffix = " const *";
833     if s.ends_with(suffix) {
834         Type::ConstPtr(parse_ty_base(&s[..s.len() - suffix.len()]))
835     } else if s.ends_with(" *") {
836         Type::MutPtr(parse_ty_base(&s[..s.len() - 2]))
837     } else {
838         *parse_ty_base(s)
839     }
840 }
841 
parse_ty_base(s: &str) -> &'static Type842 fn parse_ty_base(s: &str) -> &'static Type {
843     match s {
844         "float16_t" => &F16,
845         "float16x4_t" => &F16X4,
846         "float16x4x2_t" => &F16X4X2,
847         "float16x4x3_t" => &F16X4X3,
848         "float16x4x4_t" => &F16X4X4,
849         "float16x8_t" => &F16X8,
850         "float16x8x2_t" => &F16X8X2,
851         "float16x8x3_t" => &F16X8X3,
852         "float16x8x4_t" => &F16X8X4,
853         "float32_t" => &F32,
854         "float32x2_t" => &F32X2,
855         "float32x2x2_t" => &F32X2X2,
856         "float32x2x3_t" => &F32X2X3,
857         "float32x2x4_t" => &F32X2X4,
858         "float32x4_t" => &F32X4,
859         "float32x4x2_t" => &F32X4X2,
860         "float32x4x3_t" => &F32X4X3,
861         "float32x4x4_t" => &F32X4X4,
862         "float64_t" => &F64,
863         "float64x1_t" => &F64X1,
864         "float64x1x2_t" => &F64X1X2,
865         "float64x1x3_t" => &F64X1X3,
866         "float64x1x4_t" => &F64X1X4,
867         "float64x2_t" => &F64X2,
868         "float64x2x2_t" => &F64X2X2,
869         "float64x2x3_t" => &F64X2X3,
870         "float64x2x4_t" => &F64X2X4,
871         "int16_t" => &I16,
872         "int16x2_t" => &I16X2,
873         "int16x4_t" => &I16X4,
874         "int16x4x2_t" => &I16X4X2,
875         "int16x4x3_t" => &I16X4X3,
876         "int16x4x4_t" => &I16X4X4,
877         "int16x8_t" => &I16X8,
878         "int16x8x2_t" => &I16X8X2,
879         "int16x8x3_t" => &I16X8X3,
880         "int16x8x4_t" => &I16X8X4,
881         "int32_t" | "int" => &I32,
882         "int32x2_t" => &I32X2,
883         "int32x2x2_t" => &I32X2X2,
884         "int32x2x3_t" => &I32X2X3,
885         "int32x2x4_t" => &I32X2X4,
886         "int32x4_t" => &I32X4,
887         "int32x4x2_t" => &I32X4X2,
888         "int32x4x3_t" => &I32X4X3,
889         "int32x4x4_t" => &I32X4X4,
890         "int64_t" => &I64,
891         "int64x1_t" => &I64X1,
892         "int64x1x2_t" => &I64X1X2,
893         "int64x1x3_t" => &I64X1X3,
894         "int64x1x4_t" => &I64X1X4,
895         "int64x2_t" => &I64X2,
896         "int64x2x2_t" => &I64X2X2,
897         "int64x2x3_t" => &I64X2X3,
898         "int64x2x4_t" => &I64X2X4,
899         "int8_t" => &I8,
900         "int8x16_t" => &I8X16,
901         "int8x16x2_t" => &I8X16X2,
902         "int8x16x3_t" => &I8X16X3,
903         "int8x16x4_t" => &I8X16X4,
904         "int8x4_t" => &I8X4,
905         "int8x8_t" => &I8X8,
906         "int8x8x2_t" => &I8X8X2,
907         "int8x8x3_t" => &I8X8X3,
908         "int8x8x4_t" => &I8X8X4,
909         "poly128_t" => &P128,
910         "poly16_t" => &P16,
911         "poly16x4_t" => &POLY16X4,
912         "poly16x4x2_t" => &P16X4X2,
913         "poly16x4x3_t" => &P16X4X3,
914         "poly16x4x4_t" => &P16X4X4,
915         "poly16x8_t" => &POLY16X8,
916         "poly16x8x2_t" => &P16X8X2,
917         "poly16x8x3_t" => &P16X8X3,
918         "poly16x8x4_t" => &P16X8X4,
919         "poly64_t" => &P64,
920         "poly64x1_t" => &POLY64X1,
921         "poly64x1x2_t" => &P64X1X2,
922         "poly64x1x3_t" => &P64X1X3,
923         "poly64x1x4_t" => &P64X1X4,
924         "poly64x2_t" => &POLY64X2,
925         "poly64x2x2_t" => &P64X2X2,
926         "poly64x2x3_t" => &P64X2X3,
927         "poly64x2x4_t" => &P64X2X4,
928         "poly8_t" => &P8,
929         "poly8x16_t" => &POLY8X16,
930         "poly8x16x2_t" => &POLY8X16X2,
931         "poly8x16x3_t" => &POLY8X16X3,
932         "poly8x16x4_t" => &POLY8X16X4,
933         "poly8x8_t" => &POLY8X8,
934         "poly8x8x2_t" => &POLY8X8X2,
935         "poly8x8x3_t" => &POLY8X8X3,
936         "poly8x8x4_t" => &POLY8X8X4,
937         "uint16_t" => &U16,
938         "uint16x4_t" => &U16X4,
939         "uint16x4x2_t" => &U16X4X2,
940         "uint16x4x3_t" => &U16X4X3,
941         "uint16x4x4_t" => &U16X4X4,
942         "uint16x8_t" => &U16X8,
943         "uint16x8x2_t" => &U16X8X2,
944         "uint16x8x3_t" => &U16X8X3,
945         "uint16x8x4_t" => &U16X8X4,
946         "uint32_t" => &U32,
947         "uint32x2_t" => &U32X2,
948         "uint32x2x2_t" => &U32X2X2,
949         "uint32x2x3_t" => &U32X2X3,
950         "uint32x2x4_t" => &U32X2X4,
951         "uint32x4_t" => &U32X4,
952         "uint32x4x2_t" => &U32X4X2,
953         "uint32x4x3_t" => &U32X4X3,
954         "uint32x4x4_t" => &U32X4X4,
955         "uint64_t" => &U64,
956         "uint64x1_t" => &U64X1,
957         "uint64x1x2_t" => &U64X1X2,
958         "uint64x1x3_t" => &U64X1X3,
959         "uint64x1x4_t" => &U64X1X4,
960         "uint64x2_t" => &U64X2,
961         "uint64x2x2_t" => &U64X2X2,
962         "uint64x2x3_t" => &U64X2X3,
963         "uint64x2x4_t" => &U64X2X4,
964         "uint8_t" => &U8,
965         "uint8x16_t" => &U8X16,
966         "uint8x16x2_t" => &U8X16X2,
967         "uint8x16x3_t" => &U8X16X3,
968         "uint8x16x4_t" => &U8X16X4,
969         "uint8x8_t" => &U8X8,
970         "uint8x8x2_t" => &U8X8X2,
971         "uint8x8x3_t" => &U8X8X3,
972         "uint8x8x4_t" => &U8X8X4,
973 
974         _ => panic!("failed to parse html type {:?}", s),
975     }
976 }
977 
collect_text(s: &mut String, node: &Node)978 fn collect_text(s: &mut String, node: &Node) {
979     if let NodeData::Text { contents } = &node.data {
980         s.push(' ');
981         s.push_str(&contents.borrow().to_string());
982     }
983     for child in node.children.borrow().iter() {
984         collect_text(s, child);
985     }
986 }
987