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