1 // Copyright 2018, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of Arm Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include "cpu-features-auditor-aarch64.h"
28
29 #include "cpu-features.h"
30 #include "globals-vixl.h"
31 #include "utils-vixl.h"
32
33 #include "decoder-aarch64.h"
34
35 namespace vixl {
36 namespace aarch64 {
37
38 const CPUFeaturesAuditor::FormToVisitorFnMap*
GetFormToVisitorFnMap()39 CPUFeaturesAuditor::GetFormToVisitorFnMap() {
40 static const FormToVisitorFnMap FORM_TO_VISITOR = {
41 DEFAULT_FORM_TO_VISITOR_MAP(CPUFeaturesAuditor),
42 SIM_AUD_VISITOR_MAP(CPUFeaturesAuditor),
43 {"fcmla_asimdelem_c_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
44 {"fcmla_asimdelem_c_s"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
45 {"fmlal2_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
46 {"fmlal_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
47 {"fmla_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
48 {"fmla_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
49 {"fmlsl2_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
50 {"fmlsl_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
51 {"fmls_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
52 {"fmls_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
53 {"fmulx_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
54 {"fmulx_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
55 {"fmul_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
56 {"fmul_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
57 {"sdot_asimdelem_d"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
58 {"smlal_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
59 {"smlsl_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
60 {"smull_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
61 {"sqdmlal_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
62 {"sqdmlsl_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
63 {"sqdmull_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
64 {"udot_asimdelem_d"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
65 {"umlal_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
66 {"umlsl_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
67 {"umull_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
68 };
69 return &FORM_TO_VISITOR;
70 }
71
72 // Every instruction must update last_instruction_, even if only to clear it,
73 // and every instruction must also update seen_ once it has been fully handled.
74 // This scope makes that simple, and allows early returns in the decode logic.
75 class CPUFeaturesAuditor::RecordInstructionFeaturesScope {
76 public:
RecordInstructionFeaturesScope(CPUFeaturesAuditor * auditor)77 explicit RecordInstructionFeaturesScope(CPUFeaturesAuditor* auditor)
78 : auditor_(auditor) {
79 auditor_->last_instruction_ = CPUFeatures::None();
80 }
~RecordInstructionFeaturesScope()81 ~RecordInstructionFeaturesScope() {
82 auditor_->seen_.Combine(auditor_->last_instruction_);
83 }
84
Record(const CPUFeatures & features)85 void Record(const CPUFeatures& features) {
86 auditor_->last_instruction_.Combine(features);
87 }
88
Record(CPUFeatures::Feature feature0,CPUFeatures::Feature feature1=CPUFeatures::kNone,CPUFeatures::Feature feature2=CPUFeatures::kNone,CPUFeatures::Feature feature3=CPUFeatures::kNone)89 void Record(CPUFeatures::Feature feature0,
90 CPUFeatures::Feature feature1 = CPUFeatures::kNone,
91 CPUFeatures::Feature feature2 = CPUFeatures::kNone,
92 CPUFeatures::Feature feature3 = CPUFeatures::kNone) {
93 auditor_->last_instruction_.Combine(feature0, feature1, feature2, feature3);
94 }
95
96 // If exactly one of a or b is known to be available, record it. Otherwise,
97 // record both. This is intended for encodings that can be provided by two
98 // different features.
RecordOneOrBothOf(CPUFeatures::Feature a,CPUFeatures::Feature b)99 void RecordOneOrBothOf(CPUFeatures::Feature a, CPUFeatures::Feature b) {
100 bool hint_a = auditor_->available_.Has(a);
101 bool hint_b = auditor_->available_.Has(b);
102 if (hint_a && !hint_b) {
103 Record(a);
104 } else if (hint_b && !hint_a) {
105 Record(b);
106 } else {
107 Record(a, b);
108 }
109 }
110
111 private:
112 CPUFeaturesAuditor* auditor_;
113 };
114
LoadStoreHelper(const Instruction * instr)115 void CPUFeaturesAuditor::LoadStoreHelper(const Instruction* instr) {
116 RecordInstructionFeaturesScope scope(this);
117 switch (instr->Mask(LoadStoreMask)) {
118 case LDR_b:
119 case LDR_q:
120 case STR_b:
121 case STR_q:
122 scope.Record(CPUFeatures::kNEON);
123 return;
124 case LDR_h:
125 case LDR_s:
126 case LDR_d:
127 case STR_h:
128 case STR_s:
129 case STR_d:
130 scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
131 return;
132 default:
133 // No special CPU features.
134 return;
135 }
136 }
137
LoadStorePairHelper(const Instruction * instr)138 void CPUFeaturesAuditor::LoadStorePairHelper(const Instruction* instr) {
139 RecordInstructionFeaturesScope scope(this);
140 switch (instr->Mask(LoadStorePairMask)) {
141 case LDP_q:
142 case STP_q:
143 scope.Record(CPUFeatures::kNEON);
144 return;
145 case LDP_s:
146 case LDP_d:
147 case STP_s:
148 case STP_d: {
149 scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
150 return;
151 }
152 default:
153 // No special CPU features.
154 return;
155 }
156 }
157
VisitAddSubExtended(const Instruction * instr)158 void CPUFeaturesAuditor::VisitAddSubExtended(const Instruction* instr) {
159 RecordInstructionFeaturesScope scope(this);
160 USE(instr);
161 }
162
VisitAddSubImmediate(const Instruction * instr)163 void CPUFeaturesAuditor::VisitAddSubImmediate(const Instruction* instr) {
164 RecordInstructionFeaturesScope scope(this);
165 USE(instr);
166 }
167
VisitAddSubShifted(const Instruction * instr)168 void CPUFeaturesAuditor::VisitAddSubShifted(const Instruction* instr) {
169 RecordInstructionFeaturesScope scope(this);
170 USE(instr);
171 }
172
VisitAddSubWithCarry(const Instruction * instr)173 void CPUFeaturesAuditor::VisitAddSubWithCarry(const Instruction* instr) {
174 RecordInstructionFeaturesScope scope(this);
175 USE(instr);
176 }
177
VisitRotateRightIntoFlags(const Instruction * instr)178 void CPUFeaturesAuditor::VisitRotateRightIntoFlags(const Instruction* instr) {
179 RecordInstructionFeaturesScope scope(this);
180 switch (instr->Mask(RotateRightIntoFlagsMask)) {
181 case RMIF:
182 scope.Record(CPUFeatures::kFlagM);
183 return;
184 }
185 }
186
VisitEvaluateIntoFlags(const Instruction * instr)187 void CPUFeaturesAuditor::VisitEvaluateIntoFlags(const Instruction* instr) {
188 RecordInstructionFeaturesScope scope(this);
189 switch (instr->Mask(EvaluateIntoFlagsMask)) {
190 case SETF8:
191 case SETF16:
192 scope.Record(CPUFeatures::kFlagM);
193 return;
194 }
195 }
196
VisitAtomicMemory(const Instruction * instr)197 void CPUFeaturesAuditor::VisitAtomicMemory(const Instruction* instr) {
198 RecordInstructionFeaturesScope scope(this);
199 switch (instr->Mask(AtomicMemoryMask)) {
200 case LDAPRB:
201 case LDAPRH:
202 case LDAPR_w:
203 case LDAPR_x:
204 scope.Record(CPUFeatures::kRCpc);
205 return;
206 default:
207 // Everything else belongs to the Atomics extension.
208 scope.Record(CPUFeatures::kAtomics);
209 return;
210 }
211 }
212
VisitBitfield(const Instruction * instr)213 void CPUFeaturesAuditor::VisitBitfield(const Instruction* instr) {
214 RecordInstructionFeaturesScope scope(this);
215 USE(instr);
216 }
217
VisitCompareBranch(const Instruction * instr)218 void CPUFeaturesAuditor::VisitCompareBranch(const Instruction* instr) {
219 RecordInstructionFeaturesScope scope(this);
220 USE(instr);
221 }
222
VisitConditionalBranch(const Instruction * instr)223 void CPUFeaturesAuditor::VisitConditionalBranch(const Instruction* instr) {
224 RecordInstructionFeaturesScope scope(this);
225 USE(instr);
226 }
227
VisitConditionalCompareImmediate(const Instruction * instr)228 void CPUFeaturesAuditor::VisitConditionalCompareImmediate(
229 const Instruction* instr) {
230 RecordInstructionFeaturesScope scope(this);
231 USE(instr);
232 }
233
VisitConditionalCompareRegister(const Instruction * instr)234 void CPUFeaturesAuditor::VisitConditionalCompareRegister(
235 const Instruction* instr) {
236 RecordInstructionFeaturesScope scope(this);
237 USE(instr);
238 }
239
VisitConditionalSelect(const Instruction * instr)240 void CPUFeaturesAuditor::VisitConditionalSelect(const Instruction* instr) {
241 RecordInstructionFeaturesScope scope(this);
242 USE(instr);
243 }
244
VisitCrypto2RegSHA(const Instruction * instr)245 void CPUFeaturesAuditor::VisitCrypto2RegSHA(const Instruction* instr) {
246 RecordInstructionFeaturesScope scope(this);
247 USE(instr);
248 }
249
VisitCrypto3RegSHA(const Instruction * instr)250 void CPUFeaturesAuditor::VisitCrypto3RegSHA(const Instruction* instr) {
251 RecordInstructionFeaturesScope scope(this);
252 USE(instr);
253 }
254
VisitCryptoAES(const Instruction * instr)255 void CPUFeaturesAuditor::VisitCryptoAES(const Instruction* instr) {
256 RecordInstructionFeaturesScope scope(this);
257 USE(instr);
258 }
259
VisitDataProcessing1Source(const Instruction * instr)260 void CPUFeaturesAuditor::VisitDataProcessing1Source(const Instruction* instr) {
261 RecordInstructionFeaturesScope scope(this);
262 switch (instr->Mask(DataProcessing1SourceMask)) {
263 case PACIA:
264 case PACIB:
265 case PACDA:
266 case PACDB:
267 case AUTIA:
268 case AUTIB:
269 case AUTDA:
270 case AUTDB:
271 case PACIZA:
272 case PACIZB:
273 case PACDZA:
274 case PACDZB:
275 case AUTIZA:
276 case AUTIZB:
277 case AUTDZA:
278 case AUTDZB:
279 case XPACI:
280 case XPACD:
281 scope.Record(CPUFeatures::kPAuth);
282 return;
283 default:
284 // No special CPU features.
285 return;
286 }
287 }
288
VisitDataProcessing2Source(const Instruction * instr)289 void CPUFeaturesAuditor::VisitDataProcessing2Source(const Instruction* instr) {
290 RecordInstructionFeaturesScope scope(this);
291 switch (instr->Mask(DataProcessing2SourceMask)) {
292 case CRC32B:
293 case CRC32H:
294 case CRC32W:
295 case CRC32X:
296 case CRC32CB:
297 case CRC32CH:
298 case CRC32CW:
299 case CRC32CX:
300 scope.Record(CPUFeatures::kCRC32);
301 return;
302 case PACGA:
303 scope.Record(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric);
304 return;
305 default:
306 // No special CPU features.
307 return;
308 }
309 }
310
VisitLoadStoreRCpcUnscaledOffset(const Instruction * instr)311 void CPUFeaturesAuditor::VisitLoadStoreRCpcUnscaledOffset(
312 const Instruction* instr) {
313 RecordInstructionFeaturesScope scope(this);
314 switch (instr->Mask(LoadStoreRCpcUnscaledOffsetMask)) {
315 case LDAPURB:
316 case LDAPURSB_w:
317 case LDAPURSB_x:
318 case LDAPURH:
319 case LDAPURSH_w:
320 case LDAPURSH_x:
321 case LDAPUR_w:
322 case LDAPURSW:
323 case LDAPUR_x:
324
325 // These stores don't actually have RCpc semantics but they're included with
326 // the RCpc extensions.
327 case STLURB:
328 case STLURH:
329 case STLUR_w:
330 case STLUR_x:
331 scope.Record(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm);
332 return;
333 }
334 }
335
VisitLoadStorePAC(const Instruction * instr)336 void CPUFeaturesAuditor::VisitLoadStorePAC(const Instruction* instr) {
337 RecordInstructionFeaturesScope scope(this);
338 USE(instr);
339 scope.Record(CPUFeatures::kPAuth);
340 }
341
VisitDataProcessing3Source(const Instruction * instr)342 void CPUFeaturesAuditor::VisitDataProcessing3Source(const Instruction* instr) {
343 RecordInstructionFeaturesScope scope(this);
344 USE(instr);
345 }
346
VisitException(const Instruction * instr)347 void CPUFeaturesAuditor::VisitException(const Instruction* instr) {
348 RecordInstructionFeaturesScope scope(this);
349 USE(instr);
350 }
351
VisitExtract(const Instruction * instr)352 void CPUFeaturesAuditor::VisitExtract(const Instruction* instr) {
353 RecordInstructionFeaturesScope scope(this);
354 USE(instr);
355 }
356
VisitFPCompare(const Instruction * instr)357 void CPUFeaturesAuditor::VisitFPCompare(const Instruction* instr) {
358 RecordInstructionFeaturesScope scope(this);
359 // All of these instructions require FP.
360 scope.Record(CPUFeatures::kFP);
361 switch (instr->Mask(FPCompareMask)) {
362 case FCMP_h:
363 case FCMP_h_zero:
364 case FCMPE_h:
365 case FCMPE_h_zero:
366 scope.Record(CPUFeatures::kFPHalf);
367 return;
368 default:
369 // No special CPU features.
370 return;
371 }
372 }
373
VisitFPConditionalCompare(const Instruction * instr)374 void CPUFeaturesAuditor::VisitFPConditionalCompare(const Instruction* instr) {
375 RecordInstructionFeaturesScope scope(this);
376 // All of these instructions require FP.
377 scope.Record(CPUFeatures::kFP);
378 switch (instr->Mask(FPConditionalCompareMask)) {
379 case FCCMP_h:
380 case FCCMPE_h:
381 scope.Record(CPUFeatures::kFPHalf);
382 return;
383 default:
384 // No special CPU features.
385 return;
386 }
387 }
388
VisitFPConditionalSelect(const Instruction * instr)389 void CPUFeaturesAuditor::VisitFPConditionalSelect(const Instruction* instr) {
390 RecordInstructionFeaturesScope scope(this);
391 // All of these instructions require FP.
392 scope.Record(CPUFeatures::kFP);
393 if (instr->Mask(FPConditionalSelectMask) == FCSEL_h) {
394 scope.Record(CPUFeatures::kFPHalf);
395 }
396 }
397
VisitFPDataProcessing1Source(const Instruction * instr)398 void CPUFeaturesAuditor::VisitFPDataProcessing1Source(
399 const Instruction* instr) {
400 RecordInstructionFeaturesScope scope(this);
401 // All of these instructions require FP.
402 scope.Record(CPUFeatures::kFP);
403 switch (instr->Mask(FPDataProcessing1SourceMask)) {
404 case FMOV_h:
405 case FABS_h:
406 case FNEG_h:
407 case FSQRT_h:
408 case FRINTN_h:
409 case FRINTP_h:
410 case FRINTM_h:
411 case FRINTZ_h:
412 case FRINTA_h:
413 case FRINTX_h:
414 case FRINTI_h:
415 scope.Record(CPUFeatures::kFPHalf);
416 return;
417 case FRINT32X_s:
418 case FRINT32X_d:
419 case FRINT32Z_s:
420 case FRINT32Z_d:
421 case FRINT64X_s:
422 case FRINT64X_d:
423 case FRINT64Z_s:
424 case FRINT64Z_d:
425 scope.Record(CPUFeatures::kFrintToFixedSizedInt);
426 return;
427 default:
428 // No special CPU features.
429 // This category includes some half-precision FCVT instructions that do
430 // not require FPHalf.
431 return;
432 }
433 }
434
VisitFPDataProcessing2Source(const Instruction * instr)435 void CPUFeaturesAuditor::VisitFPDataProcessing2Source(
436 const Instruction* instr) {
437 RecordInstructionFeaturesScope scope(this);
438 // All of these instructions require FP.
439 scope.Record(CPUFeatures::kFP);
440 switch (instr->Mask(FPDataProcessing2SourceMask)) {
441 case FMUL_h:
442 case FDIV_h:
443 case FADD_h:
444 case FSUB_h:
445 case FMAX_h:
446 case FMIN_h:
447 case FMAXNM_h:
448 case FMINNM_h:
449 case FNMUL_h:
450 scope.Record(CPUFeatures::kFPHalf);
451 return;
452 default:
453 // No special CPU features.
454 return;
455 }
456 }
457
VisitFPDataProcessing3Source(const Instruction * instr)458 void CPUFeaturesAuditor::VisitFPDataProcessing3Source(
459 const Instruction* instr) {
460 RecordInstructionFeaturesScope scope(this);
461 // All of these instructions require FP.
462 scope.Record(CPUFeatures::kFP);
463 switch (instr->Mask(FPDataProcessing3SourceMask)) {
464 case FMADD_h:
465 case FMSUB_h:
466 case FNMADD_h:
467 case FNMSUB_h:
468 scope.Record(CPUFeatures::kFPHalf);
469 return;
470 default:
471 // No special CPU features.
472 return;
473 }
474 }
475
VisitFPFixedPointConvert(const Instruction * instr)476 void CPUFeaturesAuditor::VisitFPFixedPointConvert(const Instruction* instr) {
477 RecordInstructionFeaturesScope scope(this);
478 // All of these instructions require FP.
479 scope.Record(CPUFeatures::kFP);
480 switch (instr->Mask(FPFixedPointConvertMask)) {
481 case FCVTZS_wh_fixed:
482 case FCVTZS_xh_fixed:
483 case FCVTZU_wh_fixed:
484 case FCVTZU_xh_fixed:
485 case SCVTF_hw_fixed:
486 case SCVTF_hx_fixed:
487 case UCVTF_hw_fixed:
488 case UCVTF_hx_fixed:
489 scope.Record(CPUFeatures::kFPHalf);
490 return;
491 default:
492 // No special CPU features.
493 return;
494 }
495 }
496
VisitFPImmediate(const Instruction * instr)497 void CPUFeaturesAuditor::VisitFPImmediate(const Instruction* instr) {
498 RecordInstructionFeaturesScope scope(this);
499 // All of these instructions require FP.
500 scope.Record(CPUFeatures::kFP);
501 if (instr->Mask(FPImmediateMask) == FMOV_h_imm) {
502 scope.Record(CPUFeatures::kFPHalf);
503 }
504 }
505
VisitFPIntegerConvert(const Instruction * instr)506 void CPUFeaturesAuditor::VisitFPIntegerConvert(const Instruction* instr) {
507 RecordInstructionFeaturesScope scope(this);
508 switch (instr->Mask(FPIntegerConvertMask)) {
509 case FCVTAS_wh:
510 case FCVTAS_xh:
511 case FCVTAU_wh:
512 case FCVTAU_xh:
513 case FCVTMS_wh:
514 case FCVTMS_xh:
515 case FCVTMU_wh:
516 case FCVTMU_xh:
517 case FCVTNS_wh:
518 case FCVTNS_xh:
519 case FCVTNU_wh:
520 case FCVTNU_xh:
521 case FCVTPS_wh:
522 case FCVTPS_xh:
523 case FCVTPU_wh:
524 case FCVTPU_xh:
525 case FCVTZS_wh:
526 case FCVTZS_xh:
527 case FCVTZU_wh:
528 case FCVTZU_xh:
529 case FMOV_hw:
530 case FMOV_hx:
531 case FMOV_wh:
532 case FMOV_xh:
533 case SCVTF_hw:
534 case SCVTF_hx:
535 case UCVTF_hw:
536 case UCVTF_hx:
537 scope.Record(CPUFeatures::kFP);
538 scope.Record(CPUFeatures::kFPHalf);
539 return;
540 case FMOV_dx:
541 scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
542 return;
543 case FMOV_d1_x:
544 case FMOV_x_d1:
545 scope.Record(CPUFeatures::kFP);
546 scope.Record(CPUFeatures::kNEON);
547 return;
548 case FJCVTZS:
549 scope.Record(CPUFeatures::kFP);
550 scope.Record(CPUFeatures::kJSCVT);
551 return;
552 default:
553 scope.Record(CPUFeatures::kFP);
554 return;
555 }
556 }
557
VisitLoadLiteral(const Instruction * instr)558 void CPUFeaturesAuditor::VisitLoadLiteral(const Instruction* instr) {
559 RecordInstructionFeaturesScope scope(this);
560 switch (instr->Mask(LoadLiteralMask)) {
561 case LDR_s_lit:
562 case LDR_d_lit:
563 scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
564 return;
565 case LDR_q_lit:
566 scope.Record(CPUFeatures::kNEON);
567 return;
568 default:
569 // No special CPU features.
570 return;
571 }
572 }
573
VisitLoadStoreExclusive(const Instruction * instr)574 void CPUFeaturesAuditor::VisitLoadStoreExclusive(const Instruction* instr) {
575 RecordInstructionFeaturesScope scope(this);
576 switch (instr->Mask(LoadStoreExclusiveMask)) {
577 case CAS_w:
578 case CASA_w:
579 case CASL_w:
580 case CASAL_w:
581 case CAS_x:
582 case CASA_x:
583 case CASL_x:
584 case CASAL_x:
585 case CASB:
586 case CASAB:
587 case CASLB:
588 case CASALB:
589 case CASH:
590 case CASAH:
591 case CASLH:
592 case CASALH:
593 case CASP_w:
594 case CASPA_w:
595 case CASPL_w:
596 case CASPAL_w:
597 case CASP_x:
598 case CASPA_x:
599 case CASPL_x:
600 case CASPAL_x:
601 scope.Record(CPUFeatures::kAtomics);
602 return;
603 case STLLRB:
604 case LDLARB:
605 case STLLRH:
606 case LDLARH:
607 case STLLR_w:
608 case LDLAR_w:
609 case STLLR_x:
610 case LDLAR_x:
611 scope.Record(CPUFeatures::kLORegions);
612 return;
613 default:
614 // No special CPU features.
615 return;
616 }
617 }
618
VisitLoadStorePairNonTemporal(const Instruction * instr)619 void CPUFeaturesAuditor::VisitLoadStorePairNonTemporal(
620 const Instruction* instr) {
621 LoadStorePairHelper(instr);
622 }
623
VisitLoadStorePairOffset(const Instruction * instr)624 void CPUFeaturesAuditor::VisitLoadStorePairOffset(const Instruction* instr) {
625 LoadStorePairHelper(instr);
626 }
627
VisitLoadStorePairPostIndex(const Instruction * instr)628 void CPUFeaturesAuditor::VisitLoadStorePairPostIndex(const Instruction* instr) {
629 LoadStorePairHelper(instr);
630 }
631
VisitLoadStorePairPreIndex(const Instruction * instr)632 void CPUFeaturesAuditor::VisitLoadStorePairPreIndex(const Instruction* instr) {
633 LoadStorePairHelper(instr);
634 }
635
VisitLoadStorePostIndex(const Instruction * instr)636 void CPUFeaturesAuditor::VisitLoadStorePostIndex(const Instruction* instr) {
637 LoadStoreHelper(instr);
638 }
639
VisitLoadStorePreIndex(const Instruction * instr)640 void CPUFeaturesAuditor::VisitLoadStorePreIndex(const Instruction* instr) {
641 LoadStoreHelper(instr);
642 }
643
VisitLoadStoreRegisterOffset(const Instruction * instr)644 void CPUFeaturesAuditor::VisitLoadStoreRegisterOffset(
645 const Instruction* instr) {
646 LoadStoreHelper(instr);
647 }
648
VisitLoadStoreUnscaledOffset(const Instruction * instr)649 void CPUFeaturesAuditor::VisitLoadStoreUnscaledOffset(
650 const Instruction* instr) {
651 LoadStoreHelper(instr);
652 }
653
VisitLoadStoreUnsignedOffset(const Instruction * instr)654 void CPUFeaturesAuditor::VisitLoadStoreUnsignedOffset(
655 const Instruction* instr) {
656 LoadStoreHelper(instr);
657 }
658
VisitLogicalImmediate(const Instruction * instr)659 void CPUFeaturesAuditor::VisitLogicalImmediate(const Instruction* instr) {
660 RecordInstructionFeaturesScope scope(this);
661 USE(instr);
662 }
663
VisitLogicalShifted(const Instruction * instr)664 void CPUFeaturesAuditor::VisitLogicalShifted(const Instruction* instr) {
665 RecordInstructionFeaturesScope scope(this);
666 USE(instr);
667 }
668
VisitMoveWideImmediate(const Instruction * instr)669 void CPUFeaturesAuditor::VisitMoveWideImmediate(const Instruction* instr) {
670 RecordInstructionFeaturesScope scope(this);
671 USE(instr);
672 }
673
VisitNEON2RegMisc(const Instruction * instr)674 void CPUFeaturesAuditor::VisitNEON2RegMisc(const Instruction* instr) {
675 RecordInstructionFeaturesScope scope(this);
676 // All of these instructions require NEON.
677 scope.Record(CPUFeatures::kNEON);
678 switch (instr->Mask(NEON2RegMiscFPMask)) {
679 case NEON_FABS:
680 case NEON_FNEG:
681 case NEON_FSQRT:
682 case NEON_FCVTL:
683 case NEON_FCVTN:
684 case NEON_FCVTXN:
685 case NEON_FRINTI:
686 case NEON_FRINTX:
687 case NEON_FRINTA:
688 case NEON_FRINTM:
689 case NEON_FRINTN:
690 case NEON_FRINTP:
691 case NEON_FRINTZ:
692 case NEON_FCVTNS:
693 case NEON_FCVTNU:
694 case NEON_FCVTPS:
695 case NEON_FCVTPU:
696 case NEON_FCVTMS:
697 case NEON_FCVTMU:
698 case NEON_FCVTZS:
699 case NEON_FCVTZU:
700 case NEON_FCVTAS:
701 case NEON_FCVTAU:
702 case NEON_SCVTF:
703 case NEON_UCVTF:
704 case NEON_FRSQRTE:
705 case NEON_FRECPE:
706 case NEON_FCMGT_zero:
707 case NEON_FCMGE_zero:
708 case NEON_FCMEQ_zero:
709 case NEON_FCMLE_zero:
710 case NEON_FCMLT_zero:
711 scope.Record(CPUFeatures::kFP);
712 return;
713 case NEON_FRINT32X:
714 case NEON_FRINT32Z:
715 case NEON_FRINT64X:
716 case NEON_FRINT64Z:
717 scope.Record(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt);
718 return;
719 default:
720 // No additional features.
721 return;
722 }
723 }
724
VisitNEON2RegMiscFP16(const Instruction * instr)725 void CPUFeaturesAuditor::VisitNEON2RegMiscFP16(const Instruction* instr) {
726 RecordInstructionFeaturesScope scope(this);
727 // All of these instructions require NEONHalf.
728 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
729 USE(instr);
730 }
731
VisitNEON3Different(const Instruction * instr)732 void CPUFeaturesAuditor::VisitNEON3Different(const Instruction* instr) {
733 RecordInstructionFeaturesScope scope(this);
734 // All of these instructions require NEON.
735 scope.Record(CPUFeatures::kNEON);
736 USE(instr);
737 }
738
VisitNEON3Same(const Instruction * instr)739 void CPUFeaturesAuditor::VisitNEON3Same(const Instruction* instr) {
740 RecordInstructionFeaturesScope scope(this);
741 // All of these instructions require NEON.
742 scope.Record(CPUFeatures::kNEON);
743 if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
744 scope.Record(CPUFeatures::kFP);
745 }
746 switch (instr->Mask(NEON3SameFHMMask)) {
747 case NEON_FMLAL:
748 case NEON_FMLAL2:
749 case NEON_FMLSL:
750 case NEON_FMLSL2:
751 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf, CPUFeatures::kFHM);
752 return;
753 default:
754 // No additional features.
755 return;
756 }
757 }
758
VisitNEON3SameExtra(const Instruction * instr)759 void CPUFeaturesAuditor::VisitNEON3SameExtra(const Instruction* instr) {
760 RecordInstructionFeaturesScope scope(this);
761 // All of these instructions require NEON.
762 scope.Record(CPUFeatures::kNEON);
763 if ((instr->Mask(NEON3SameExtraFCMLAMask) == NEON_FCMLA) ||
764 (instr->Mask(NEON3SameExtraFCADDMask) == NEON_FCADD)) {
765 scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma);
766 if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf);
767 } else {
768 switch (instr->Mask(NEON3SameExtraMask)) {
769 case NEON_SDOT:
770 case NEON_UDOT:
771 scope.Record(CPUFeatures::kDotProduct);
772 return;
773 case NEON_SQRDMLAH:
774 case NEON_SQRDMLSH:
775 scope.Record(CPUFeatures::kRDM);
776 return;
777 default:
778 // No additional features.
779 return;
780 }
781 }
782 }
783
VisitNEON3SameFP16(const Instruction * instr)784 void CPUFeaturesAuditor::VisitNEON3SameFP16(const Instruction* instr) {
785 RecordInstructionFeaturesScope scope(this);
786 // All of these instructions require NEON FP16 support.
787 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
788 USE(instr);
789 }
790
VisitNEONAcrossLanes(const Instruction * instr)791 void CPUFeaturesAuditor::VisitNEONAcrossLanes(const Instruction* instr) {
792 RecordInstructionFeaturesScope scope(this);
793 // All of these instructions require NEON.
794 scope.Record(CPUFeatures::kNEON);
795 if (instr->Mask(NEONAcrossLanesFP16FMask) == NEONAcrossLanesFP16Fixed) {
796 // FMAXV_H, FMINV_H, FMAXNMV_H, FMINNMV_H
797 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf);
798 } else if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
799 // FMAXV, FMINV, FMAXNMV, FMINNMV
800 scope.Record(CPUFeatures::kFP);
801 }
802 }
803
VisitNEONByIndexedElement(const Instruction * instr)804 void CPUFeaturesAuditor::VisitNEONByIndexedElement(const Instruction* instr) {
805 RecordInstructionFeaturesScope scope(this);
806 // All of these instructions require NEON.
807 scope.Record(CPUFeatures::kNEON);
808 switch (instr->Mask(NEONByIndexedElementMask)) {
809 case NEON_SDOT_byelement:
810 case NEON_UDOT_byelement:
811 scope.Record(CPUFeatures::kDotProduct);
812 return;
813 case NEON_SQRDMLAH_byelement:
814 case NEON_SQRDMLSH_byelement:
815 scope.Record(CPUFeatures::kRDM);
816 return;
817 default:
818 // Fall through to check other instructions.
819 break;
820 }
821 switch (instr->Mask(NEONByIndexedElementFPLongMask)) {
822 case NEON_FMLAL_H_byelement:
823 case NEON_FMLAL2_H_byelement:
824 case NEON_FMLSL_H_byelement:
825 case NEON_FMLSL2_H_byelement:
826 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf, CPUFeatures::kFHM);
827 return;
828 default:
829 // Fall through to check other instructions.
830 break;
831 }
832 switch (instr->Mask(NEONByIndexedElementFPMask)) {
833 case NEON_FMLA_H_byelement:
834 case NEON_FMLS_H_byelement:
835 case NEON_FMUL_H_byelement:
836 case NEON_FMULX_H_byelement:
837 scope.Record(CPUFeatures::kNEONHalf);
838 VIXL_FALLTHROUGH();
839 case NEON_FMLA_byelement:
840 case NEON_FMLS_byelement:
841 case NEON_FMUL_byelement:
842 case NEON_FMULX_byelement:
843 scope.Record(CPUFeatures::kFP);
844 return;
845 default:
846 switch (instr->Mask(NEONByIndexedElementFPComplexMask)) {
847 case NEON_FCMLA_byelement:
848 scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma);
849 if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf);
850 return;
851 }
852 // No additional features.
853 return;
854 }
855 }
856
VisitNEONCopy(const Instruction * instr)857 void CPUFeaturesAuditor::VisitNEONCopy(const Instruction* instr) {
858 RecordInstructionFeaturesScope scope(this);
859 // All of these instructions require NEON.
860 scope.Record(CPUFeatures::kNEON);
861 USE(instr);
862 }
863
VisitNEONExtract(const Instruction * instr)864 void CPUFeaturesAuditor::VisitNEONExtract(const Instruction* instr) {
865 RecordInstructionFeaturesScope scope(this);
866 // All of these instructions require NEON.
867 scope.Record(CPUFeatures::kNEON);
868 USE(instr);
869 }
870
VisitNEONLoadStoreMultiStruct(const Instruction * instr)871 void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStruct(
872 const Instruction* instr) {
873 RecordInstructionFeaturesScope scope(this);
874 // All of these instructions require NEON.
875 scope.Record(CPUFeatures::kNEON);
876 USE(instr);
877 }
878
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)879 void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStructPostIndex(
880 const Instruction* instr) {
881 RecordInstructionFeaturesScope scope(this);
882 // All of these instructions require NEON.
883 scope.Record(CPUFeatures::kNEON);
884 USE(instr);
885 }
886
VisitNEONLoadStoreSingleStruct(const Instruction * instr)887 void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStruct(
888 const Instruction* instr) {
889 RecordInstructionFeaturesScope scope(this);
890 // All of these instructions require NEON.
891 scope.Record(CPUFeatures::kNEON);
892 USE(instr);
893 }
894
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)895 void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStructPostIndex(
896 const Instruction* instr) {
897 RecordInstructionFeaturesScope scope(this);
898 // All of these instructions require NEON.
899 scope.Record(CPUFeatures::kNEON);
900 USE(instr);
901 }
902
VisitNEONModifiedImmediate(const Instruction * instr)903 void CPUFeaturesAuditor::VisitNEONModifiedImmediate(const Instruction* instr) {
904 RecordInstructionFeaturesScope scope(this);
905 // All of these instructions require NEON.
906 scope.Record(CPUFeatures::kNEON);
907 if (instr->GetNEONCmode() == 0xf) {
908 // FMOV (vector, immediate), double-, single- or half-precision.
909 scope.Record(CPUFeatures::kFP);
910 if (instr->ExtractBit(11)) scope.Record(CPUFeatures::kNEONHalf);
911 }
912 }
913
VisitNEONPerm(const Instruction * instr)914 void CPUFeaturesAuditor::VisitNEONPerm(const Instruction* instr) {
915 RecordInstructionFeaturesScope scope(this);
916 // All of these instructions require NEON.
917 scope.Record(CPUFeatures::kNEON);
918 USE(instr);
919 }
920
VisitNEONScalar2RegMisc(const Instruction * instr)921 void CPUFeaturesAuditor::VisitNEONScalar2RegMisc(const Instruction* instr) {
922 RecordInstructionFeaturesScope scope(this);
923 // All of these instructions require NEON.
924 scope.Record(CPUFeatures::kNEON);
925 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
926 case NEON_FRECPE_scalar:
927 case NEON_FRECPX_scalar:
928 case NEON_FRSQRTE_scalar:
929 case NEON_FCMGT_zero_scalar:
930 case NEON_FCMGE_zero_scalar:
931 case NEON_FCMEQ_zero_scalar:
932 case NEON_FCMLE_zero_scalar:
933 case NEON_FCMLT_zero_scalar:
934 case NEON_SCVTF_scalar:
935 case NEON_UCVTF_scalar:
936 case NEON_FCVTNS_scalar:
937 case NEON_FCVTNU_scalar:
938 case NEON_FCVTPS_scalar:
939 case NEON_FCVTPU_scalar:
940 case NEON_FCVTMS_scalar:
941 case NEON_FCVTMU_scalar:
942 case NEON_FCVTZS_scalar:
943 case NEON_FCVTZU_scalar:
944 case NEON_FCVTAS_scalar:
945 case NEON_FCVTAU_scalar:
946 case NEON_FCVTXN_scalar:
947 scope.Record(CPUFeatures::kFP);
948 return;
949 default:
950 // No additional features.
951 return;
952 }
953 }
954
VisitNEONScalar2RegMiscFP16(const Instruction * instr)955 void CPUFeaturesAuditor::VisitNEONScalar2RegMiscFP16(const Instruction* instr) {
956 RecordInstructionFeaturesScope scope(this);
957 // All of these instructions require NEONHalf.
958 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
959 USE(instr);
960 }
961
VisitNEONScalar3Diff(const Instruction * instr)962 void CPUFeaturesAuditor::VisitNEONScalar3Diff(const Instruction* instr) {
963 RecordInstructionFeaturesScope scope(this);
964 // All of these instructions require NEON.
965 scope.Record(CPUFeatures::kNEON);
966 USE(instr);
967 }
968
VisitNEONScalar3Same(const Instruction * instr)969 void CPUFeaturesAuditor::VisitNEONScalar3Same(const Instruction* instr) {
970 RecordInstructionFeaturesScope scope(this);
971 // All of these instructions require NEON.
972 scope.Record(CPUFeatures::kNEON);
973 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
974 scope.Record(CPUFeatures::kFP);
975 }
976 }
977
VisitNEONScalar3SameExtra(const Instruction * instr)978 void CPUFeaturesAuditor::VisitNEONScalar3SameExtra(const Instruction* instr) {
979 RecordInstructionFeaturesScope scope(this);
980 // All of these instructions require NEON and RDM.
981 scope.Record(CPUFeatures::kNEON, CPUFeatures::kRDM);
982 USE(instr);
983 }
984
VisitNEONScalar3SameFP16(const Instruction * instr)985 void CPUFeaturesAuditor::VisitNEONScalar3SameFP16(const Instruction* instr) {
986 RecordInstructionFeaturesScope scope(this);
987 // All of these instructions require NEONHalf.
988 scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf);
989 USE(instr);
990 }
991
VisitNEONScalarByIndexedElement(const Instruction * instr)992 void CPUFeaturesAuditor::VisitNEONScalarByIndexedElement(
993 const Instruction* instr) {
994 RecordInstructionFeaturesScope scope(this);
995 // All of these instructions require NEON.
996 scope.Record(CPUFeatures::kNEON);
997 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
998 case NEON_SQRDMLAH_byelement_scalar:
999 case NEON_SQRDMLSH_byelement_scalar:
1000 scope.Record(CPUFeatures::kRDM);
1001 return;
1002 default:
1003 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
1004 case NEON_FMLA_H_byelement_scalar:
1005 case NEON_FMLS_H_byelement_scalar:
1006 case NEON_FMUL_H_byelement_scalar:
1007 case NEON_FMULX_H_byelement_scalar:
1008 scope.Record(CPUFeatures::kNEONHalf);
1009 VIXL_FALLTHROUGH();
1010 case NEON_FMLA_byelement_scalar:
1011 case NEON_FMLS_byelement_scalar:
1012 case NEON_FMUL_byelement_scalar:
1013 case NEON_FMULX_byelement_scalar:
1014 scope.Record(CPUFeatures::kFP);
1015 return;
1016 }
1017 // No additional features.
1018 return;
1019 }
1020 }
1021
VisitNEONScalarCopy(const Instruction * instr)1022 void CPUFeaturesAuditor::VisitNEONScalarCopy(const Instruction* instr) {
1023 RecordInstructionFeaturesScope scope(this);
1024 // All of these instructions require NEON.
1025 scope.Record(CPUFeatures::kNEON);
1026 USE(instr);
1027 }
1028
VisitNEONScalarPairwise(const Instruction * instr)1029 void CPUFeaturesAuditor::VisitNEONScalarPairwise(const Instruction* instr) {
1030 RecordInstructionFeaturesScope scope(this);
1031 // All of these instructions require NEON.
1032 scope.Record(CPUFeatures::kNEON);
1033 switch (instr->Mask(NEONScalarPairwiseMask)) {
1034 case NEON_FMAXNMP_h_scalar:
1035 case NEON_FADDP_h_scalar:
1036 case NEON_FMAXP_h_scalar:
1037 case NEON_FMINNMP_h_scalar:
1038 case NEON_FMINP_h_scalar:
1039 scope.Record(CPUFeatures::kNEONHalf);
1040 VIXL_FALLTHROUGH();
1041 case NEON_FADDP_scalar:
1042 case NEON_FMAXP_scalar:
1043 case NEON_FMAXNMP_scalar:
1044 case NEON_FMINP_scalar:
1045 case NEON_FMINNMP_scalar:
1046 scope.Record(CPUFeatures::kFP);
1047 return;
1048 default:
1049 // No additional features.
1050 return;
1051 }
1052 }
1053
VisitNEONScalarShiftImmediate(const Instruction * instr)1054 void CPUFeaturesAuditor::VisitNEONScalarShiftImmediate(
1055 const Instruction* instr) {
1056 RecordInstructionFeaturesScope scope(this);
1057 // All of these instructions require NEON.
1058 scope.Record(CPUFeatures::kNEON);
1059 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
1060 case NEON_FCVTZS_imm_scalar:
1061 case NEON_FCVTZU_imm_scalar:
1062 case NEON_SCVTF_imm_scalar:
1063 case NEON_UCVTF_imm_scalar:
1064 scope.Record(CPUFeatures::kFP);
1065 // If immh is 0b001x then the data type is FP16, and requires kNEONHalf.
1066 if ((instr->GetImmNEONImmh() & 0xe) == 0x2) {
1067 scope.Record(CPUFeatures::kNEONHalf);
1068 }
1069 return;
1070 default:
1071 // No additional features.
1072 return;
1073 }
1074 }
1075
VisitNEONShiftImmediate(const Instruction * instr)1076 void CPUFeaturesAuditor::VisitNEONShiftImmediate(const Instruction* instr) {
1077 RecordInstructionFeaturesScope scope(this);
1078 // All of these instructions require NEON.
1079 scope.Record(CPUFeatures::kNEON);
1080 switch (instr->Mask(NEONShiftImmediateMask)) {
1081 case NEON_SCVTF_imm:
1082 case NEON_UCVTF_imm:
1083 case NEON_FCVTZS_imm:
1084 case NEON_FCVTZU_imm:
1085 scope.Record(CPUFeatures::kFP);
1086 // If immh is 0b001x then the data type is FP16, and requires kNEONHalf.
1087 if ((instr->GetImmNEONImmh() & 0xe) == 0x2) {
1088 scope.Record(CPUFeatures::kNEONHalf);
1089 }
1090 return;
1091 default:
1092 // No additional features.
1093 return;
1094 }
1095 }
1096
VisitNEONTable(const Instruction * instr)1097 void CPUFeaturesAuditor::VisitNEONTable(const Instruction* instr) {
1098 RecordInstructionFeaturesScope scope(this);
1099 // All of these instructions require NEON.
1100 scope.Record(CPUFeatures::kNEON);
1101 USE(instr);
1102 }
1103
VisitPCRelAddressing(const Instruction * instr)1104 void CPUFeaturesAuditor::VisitPCRelAddressing(const Instruction* instr) {
1105 RecordInstructionFeaturesScope scope(this);
1106 USE(instr);
1107 }
1108
1109 // Most SVE visitors require only SVE.
1110 #define VIXL_SIMPLE_SVE_VISITOR_LIST(V) \
1111 V(SVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets) \
1112 V(SVE32BitGatherLoad_VectorPlusImm) \
1113 V(SVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets) \
1114 V(SVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets) \
1115 V(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets) \
1116 V(SVE32BitGatherPrefetch_VectorPlusImm) \
1117 V(SVE32BitScatterStore_ScalarPlus32BitScaledOffsets) \
1118 V(SVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets) \
1119 V(SVE32BitScatterStore_VectorPlusImm) \
1120 V(SVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets) \
1121 V(SVE64BitGatherLoad_ScalarPlus64BitScaledOffsets) \
1122 V(SVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets) \
1123 V(SVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets) \
1124 V(SVE64BitGatherLoad_VectorPlusImm) \
1125 V(SVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets) \
1126 V(SVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets) \
1127 V(SVE64BitGatherPrefetch_VectorPlusImm) \
1128 V(SVE64BitScatterStore_ScalarPlus64BitScaledOffsets) \
1129 V(SVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets) \
1130 V(SVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets) \
1131 V(SVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets) \
1132 V(SVE64BitScatterStore_VectorPlusImm) \
1133 V(SVEAddressGeneration) \
1134 V(SVEBitwiseLogicalUnpredicated) \
1135 V(SVEBitwiseShiftUnpredicated) \
1136 V(SVEFFRInitialise) \
1137 V(SVEFFRWriteFromPredicate) \
1138 V(SVEFPAccumulatingReduction) \
1139 V(SVEFPArithmeticUnpredicated) \
1140 V(SVEFPCompareVectors) \
1141 V(SVEFPCompareWithZero) \
1142 V(SVEFPComplexAddition) \
1143 V(SVEFPComplexMulAdd) \
1144 V(SVEFPComplexMulAddIndex) \
1145 V(SVEFPFastReduction) \
1146 V(SVEFPMulIndex) \
1147 V(SVEFPMulAdd) \
1148 V(SVEFPMulAddIndex) \
1149 V(SVEFPUnaryOpUnpredicated) \
1150 V(SVEIncDecByPredicateCount) \
1151 V(SVEIndexGeneration) \
1152 V(SVEIntArithmeticUnpredicated) \
1153 V(SVEIntCompareSignedImm) \
1154 V(SVEIntCompareUnsignedImm) \
1155 V(SVEIntCompareVectors) \
1156 V(SVEIntMulAddPredicated) \
1157 V(SVEIntMulAddUnpredicated) \
1158 V(SVEIntReduction) \
1159 V(SVEIntUnaryArithmeticPredicated) \
1160 V(SVEMovprfx) \
1161 V(SVEMulIndex) \
1162 V(SVEPermuteVectorExtract) \
1163 V(SVEPermuteVectorInterleaving) \
1164 V(SVEPredicateCount) \
1165 V(SVEPredicateLogical) \
1166 V(SVEPropagateBreak) \
1167 V(SVEStackFrameAdjustment) \
1168 V(SVEStackFrameSize) \
1169 V(SVEVectorSelect) \
1170 V(SVEBitwiseLogical_Predicated) \
1171 V(SVEBitwiseLogicalWithImm_Unpredicated) \
1172 V(SVEBitwiseShiftByImm_Predicated) \
1173 V(SVEBitwiseShiftByVector_Predicated) \
1174 V(SVEBitwiseShiftByWideElements_Predicated) \
1175 V(SVEBroadcastBitmaskImm) \
1176 V(SVEBroadcastFPImm_Unpredicated) \
1177 V(SVEBroadcastGeneralRegister) \
1178 V(SVEBroadcastIndexElement) \
1179 V(SVEBroadcastIntImm_Unpredicated) \
1180 V(SVECompressActiveElements) \
1181 V(SVEConditionallyBroadcastElementToVector) \
1182 V(SVEConditionallyExtractElementToSIMDFPScalar) \
1183 V(SVEConditionallyExtractElementToGeneralRegister) \
1184 V(SVEConditionallyTerminateScalars) \
1185 V(SVEConstructivePrefix_Unpredicated) \
1186 V(SVEContiguousFirstFaultLoad_ScalarPlusScalar) \
1187 V(SVEContiguousLoad_ScalarPlusImm) \
1188 V(SVEContiguousLoad_ScalarPlusScalar) \
1189 V(SVEContiguousNonFaultLoad_ScalarPlusImm) \
1190 V(SVEContiguousNonTemporalLoad_ScalarPlusImm) \
1191 V(SVEContiguousNonTemporalLoad_ScalarPlusScalar) \
1192 V(SVEContiguousNonTemporalStore_ScalarPlusImm) \
1193 V(SVEContiguousNonTemporalStore_ScalarPlusScalar) \
1194 V(SVEContiguousPrefetch_ScalarPlusImm) \
1195 V(SVEContiguousPrefetch_ScalarPlusScalar) \
1196 V(SVEContiguousStore_ScalarPlusImm) \
1197 V(SVEContiguousStore_ScalarPlusScalar) \
1198 V(SVECopySIMDFPScalarRegisterToVector_Predicated) \
1199 V(SVECopyFPImm_Predicated) \
1200 V(SVECopyGeneralRegisterToVector_Predicated) \
1201 V(SVECopyIntImm_Predicated) \
1202 V(SVEElementCount) \
1203 V(SVEExtractElementToSIMDFPScalarRegister) \
1204 V(SVEExtractElementToGeneralRegister) \
1205 V(SVEFPArithmetic_Predicated) \
1206 V(SVEFPArithmeticWithImm_Predicated) \
1207 V(SVEFPConvertPrecision) \
1208 V(SVEFPConvertToInt) \
1209 V(SVEFPExponentialAccelerator) \
1210 V(SVEFPRoundToIntegralValue) \
1211 V(SVEFPTrigMulAddCoefficient) \
1212 V(SVEFPTrigSelectCoefficient) \
1213 V(SVEFPUnaryOp) \
1214 V(SVEIncDecRegisterByElementCount) \
1215 V(SVEIncDecVectorByElementCount) \
1216 V(SVEInsertSIMDFPScalarRegister) \
1217 V(SVEInsertGeneralRegister) \
1218 V(SVEIntAddSubtractImm_Unpredicated) \
1219 V(SVEIntAddSubtractVectors_Predicated) \
1220 V(SVEIntCompareScalarCountAndLimit) \
1221 V(SVEIntConvertToFP) \
1222 V(SVEIntDivideVectors_Predicated) \
1223 V(SVEIntMinMaxImm_Unpredicated) \
1224 V(SVEIntMinMaxDifference_Predicated) \
1225 V(SVEIntMulImm_Unpredicated) \
1226 V(SVEIntMulVectors_Predicated) \
1227 V(SVELoadAndBroadcastElement) \
1228 V(SVELoadAndBroadcastQOWord_ScalarPlusImm) \
1229 V(SVELoadAndBroadcastQOWord_ScalarPlusScalar) \
1230 V(SVELoadMultipleStructures_ScalarPlusImm) \
1231 V(SVELoadMultipleStructures_ScalarPlusScalar) \
1232 V(SVELoadPredicateRegister) \
1233 V(SVELoadVectorRegister) \
1234 V(SVEPartitionBreakCondition) \
1235 V(SVEPermutePredicateElements) \
1236 V(SVEPredicateFirstActive) \
1237 V(SVEPredicateInitialize) \
1238 V(SVEPredicateNextActive) \
1239 V(SVEPredicateReadFromFFR_Predicated) \
1240 V(SVEPredicateReadFromFFR_Unpredicated) \
1241 V(SVEPredicateTest) \
1242 V(SVEPredicateZero) \
1243 V(SVEPropagateBreakToNextPartition) \
1244 V(SVEReversePredicateElements) \
1245 V(SVEReverseVectorElements) \
1246 V(SVEReverseWithinElements) \
1247 V(SVESaturatingIncDecRegisterByElementCount) \
1248 V(SVESaturatingIncDecVectorByElementCount) \
1249 V(SVEStoreMultipleStructures_ScalarPlusImm) \
1250 V(SVEStoreMultipleStructures_ScalarPlusScalar) \
1251 V(SVEStorePredicateRegister) \
1252 V(SVEStoreVectorRegister) \
1253 V(SVETableLookup) \
1254 V(SVEUnpackPredicateElements) \
1255 V(SVEUnpackVectorElements) \
1256 V(SVEVectorSplice)
1257
1258 #define VIXL_DEFINE_SIMPLE_SVE_VISITOR(NAME) \
1259 void CPUFeaturesAuditor::Visit##NAME(const Instruction* instr) { \
1260 RecordInstructionFeaturesScope scope(this); \
1261 scope.Record(CPUFeatures::kSVE); \
1262 USE(instr); \
1263 }
VIXL_SIMPLE_SVE_VISITOR_LIST(VIXL_DEFINE_SIMPLE_SVE_VISITOR)1264 VIXL_SIMPLE_SVE_VISITOR_LIST(VIXL_DEFINE_SIMPLE_SVE_VISITOR)
1265 #undef VIXL_DEFINE_SIMPLE_SVE_VISITOR
1266 #undef VIXL_SIMPLE_SVE_VISITOR_LIST
1267
1268 void CPUFeaturesAuditor::VisitSystem(const Instruction* instr) {
1269 RecordInstructionFeaturesScope scope(this);
1270 if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1271 CPUFeatures required;
1272 switch (instr->GetInstructionBits()) {
1273 case PACIA1716:
1274 case PACIB1716:
1275 case AUTIA1716:
1276 case AUTIB1716:
1277 case PACIAZ:
1278 case PACIASP:
1279 case PACIBZ:
1280 case PACIBSP:
1281 case AUTIAZ:
1282 case AUTIASP:
1283 case AUTIBZ:
1284 case AUTIBSP:
1285 case XPACLRI:
1286 required.Combine(CPUFeatures::kPAuth);
1287 break;
1288 default:
1289 switch (instr->GetImmHint()) {
1290 case ESB:
1291 required.Combine(CPUFeatures::kRAS);
1292 break;
1293 case BTI:
1294 case BTI_j:
1295 case BTI_c:
1296 case BTI_jc:
1297 required.Combine(CPUFeatures::kBTI);
1298 break;
1299 default:
1300 break;
1301 }
1302 break;
1303 }
1304
1305 // These are all HINT instructions, and behave as NOPs if the corresponding
1306 // features are not implemented, so we record the corresponding features
1307 // only if they are available.
1308 if (available_.Has(required)) scope.Record(required);
1309 } else if (instr->Mask(SystemSysMask) == SYS) {
1310 switch (instr->GetSysOp()) {
1311 // DC instruction variants.
1312 case CGVAC:
1313 case CGDVAC:
1314 case CGVAP:
1315 case CGDVAP:
1316 case CIGVAC:
1317 case CIGDVAC:
1318 case GVA:
1319 case GZVA:
1320 scope.Record(CPUFeatures::kMTE);
1321 break;
1322 case CVAP:
1323 scope.Record(CPUFeatures::kDCPoP);
1324 break;
1325 case CVADP:
1326 scope.Record(CPUFeatures::kDCCVADP);
1327 break;
1328 case IVAU:
1329 case CVAC:
1330 case CVAU:
1331 case CIVAC:
1332 case ZVA:
1333 // No special CPU features.
1334 break;
1335 }
1336 } else if (instr->Mask(SystemPStateFMask) == SystemPStateFixed) {
1337 switch (instr->Mask(SystemPStateMask)) {
1338 case CFINV:
1339 scope.Record(CPUFeatures::kFlagM);
1340 break;
1341 case AXFLAG:
1342 case XAFLAG:
1343 scope.Record(CPUFeatures::kAXFlag);
1344 break;
1345 }
1346 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1347 if (instr->Mask(SystemSysRegMask) == MRS) {
1348 switch (instr->GetImmSystemRegister()) {
1349 case RNDR:
1350 case RNDRRS:
1351 scope.Record(CPUFeatures::kRNG);
1352 break;
1353 }
1354 }
1355 }
1356 }
1357
VisitTestBranch(const Instruction * instr)1358 void CPUFeaturesAuditor::VisitTestBranch(const Instruction* instr) {
1359 RecordInstructionFeaturesScope scope(this);
1360 USE(instr);
1361 }
1362
VisitUnallocated(const Instruction * instr)1363 void CPUFeaturesAuditor::VisitUnallocated(const Instruction* instr) {
1364 RecordInstructionFeaturesScope scope(this);
1365 USE(instr);
1366 }
1367
VisitUnconditionalBranch(const Instruction * instr)1368 void CPUFeaturesAuditor::VisitUnconditionalBranch(const Instruction* instr) {
1369 RecordInstructionFeaturesScope scope(this);
1370 USE(instr);
1371 }
1372
VisitUnconditionalBranchToRegister(const Instruction * instr)1373 void CPUFeaturesAuditor::VisitUnconditionalBranchToRegister(
1374 const Instruction* instr) {
1375 RecordInstructionFeaturesScope scope(this);
1376 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
1377 case BRAAZ:
1378 case BRABZ:
1379 case BLRAAZ:
1380 case BLRABZ:
1381 case RETAA:
1382 case RETAB:
1383 case BRAA:
1384 case BRAB:
1385 case BLRAA:
1386 case BLRAB:
1387 scope.Record(CPUFeatures::kPAuth);
1388 return;
1389 default:
1390 // No additional features.
1391 return;
1392 }
1393 }
1394
VisitReserved(const Instruction * instr)1395 void CPUFeaturesAuditor::VisitReserved(const Instruction* instr) {
1396 RecordInstructionFeaturesScope scope(this);
1397 USE(instr);
1398 }
1399
VisitUnimplemented(const Instruction * instr)1400 void CPUFeaturesAuditor::VisitUnimplemented(const Instruction* instr) {
1401 RecordInstructionFeaturesScope scope(this);
1402 USE(instr);
1403 }
1404
Visit(Metadata * metadata,const Instruction * instr)1405 void CPUFeaturesAuditor::Visit(Metadata* metadata, const Instruction* instr) {
1406 VIXL_ASSERT(metadata->count("form") > 0);
1407 const std::string& form = (*metadata)["form"];
1408 uint32_t form_hash = Hash(form.c_str());
1409 const FormToVisitorFnMap* fv = CPUFeaturesAuditor::GetFormToVisitorFnMap();
1410 FormToVisitorFnMap::const_iterator it = fv->find(form_hash);
1411 if (it == fv->end()) {
1412 RecordInstructionFeaturesScope scope(this);
1413 std::map<uint32_t, const CPUFeatures> features = {
1414 {"adclb_z_zzz"_h, CPUFeatures::kSVE2},
1415 {"adclt_z_zzz"_h, CPUFeatures::kSVE2},
1416 {"addhnb_z_zz"_h, CPUFeatures::kSVE2},
1417 {"addhnt_z_zz"_h, CPUFeatures::kSVE2},
1418 {"addp_z_p_zz"_h, CPUFeatures::kSVE2},
1419 {"bcax_z_zzz"_h, CPUFeatures::kSVE2},
1420 {"bdep_z_zz"_h,
1421 CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)},
1422 {"bext_z_zz"_h,
1423 CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)},
1424 {"bgrp_z_zz"_h,
1425 CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)},
1426 {"bsl1n_z_zzz"_h, CPUFeatures::kSVE2},
1427 {"bsl2n_z_zzz"_h, CPUFeatures::kSVE2},
1428 {"bsl_z_zzz"_h, CPUFeatures::kSVE2},
1429 {"cadd_z_zz"_h, CPUFeatures::kSVE2},
1430 {"cdot_z_zzz"_h, CPUFeatures::kSVE2},
1431 {"cdot_z_zzzi_d"_h, CPUFeatures::kSVE2},
1432 {"cdot_z_zzzi_s"_h, CPUFeatures::kSVE2},
1433 {"cmla_z_zzz"_h, CPUFeatures::kSVE2},
1434 {"cmla_z_zzzi_h"_h, CPUFeatures::kSVE2},
1435 {"cmla_z_zzzi_s"_h, CPUFeatures::kSVE2},
1436 {"eor3_z_zzz"_h, CPUFeatures::kSVE2},
1437 {"eorbt_z_zz"_h, CPUFeatures::kSVE2},
1438 {"eortb_z_zz"_h, CPUFeatures::kSVE2},
1439 {"ext_z_zi_con"_h, CPUFeatures::kSVE2},
1440 {"faddp_z_p_zz"_h, CPUFeatures::kSVE2},
1441 {"fcvtlt_z_p_z_h2s"_h, CPUFeatures::kSVE2},
1442 {"fcvtlt_z_p_z_s2d"_h, CPUFeatures::kSVE2},
1443 {"fcvtnt_z_p_z_d2s"_h, CPUFeatures::kSVE2},
1444 {"fcvtnt_z_p_z_s2h"_h, CPUFeatures::kSVE2},
1445 {"fcvtx_z_p_z_d2s"_h, CPUFeatures::kSVE2},
1446 {"fcvtxnt_z_p_z_d2s"_h, CPUFeatures::kSVE2},
1447 {"flogb_z_p_z"_h, CPUFeatures::kSVE2},
1448 {"fmaxnmp_z_p_zz"_h, CPUFeatures::kSVE2},
1449 {"fmaxp_z_p_zz"_h, CPUFeatures::kSVE2},
1450 {"fminnmp_z_p_zz"_h, CPUFeatures::kSVE2},
1451 {"fminp_z_p_zz"_h, CPUFeatures::kSVE2},
1452 {"fmlalb_z_zzz"_h, CPUFeatures::kSVE2},
1453 {"fmlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1454 {"fmlalt_z_zzz"_h, CPUFeatures::kSVE2},
1455 {"fmlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1456 {"fmlslb_z_zzz"_h, CPUFeatures::kSVE2},
1457 {"fmlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1458 {"fmlslt_z_zzz"_h, CPUFeatures::kSVE2},
1459 {"fmlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1460 {"histcnt_z_p_zz"_h, CPUFeatures::kSVE2},
1461 {"histseg_z_zz"_h, CPUFeatures::kSVE2},
1462 {"ldnt1b_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1463 {"ldnt1b_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1464 {"ldnt1d_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1465 {"ldnt1h_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1466 {"ldnt1h_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1467 {"ldnt1sb_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1468 {"ldnt1sb_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1469 {"ldnt1sh_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1470 {"ldnt1sh_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1471 {"ldnt1sw_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1472 {"ldnt1w_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1473 {"ldnt1w_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1474 {"match_p_p_zz"_h, CPUFeatures::kSVE2},
1475 {"mla_z_zzzi_d"_h, CPUFeatures::kSVE2},
1476 {"mla_z_zzzi_h"_h, CPUFeatures::kSVE2},
1477 {"mla_z_zzzi_s"_h, CPUFeatures::kSVE2},
1478 {"mls_z_zzzi_d"_h, CPUFeatures::kSVE2},
1479 {"mls_z_zzzi_h"_h, CPUFeatures::kSVE2},
1480 {"mls_z_zzzi_s"_h, CPUFeatures::kSVE2},
1481 {"mul_z_zz"_h, CPUFeatures::kSVE2},
1482 {"mul_z_zzi_d"_h, CPUFeatures::kSVE2},
1483 {"mul_z_zzi_h"_h, CPUFeatures::kSVE2},
1484 {"mul_z_zzi_s"_h, CPUFeatures::kSVE2},
1485 {"nbsl_z_zzz"_h, CPUFeatures::kSVE2},
1486 {"nmatch_p_p_zz"_h, CPUFeatures::kSVE2},
1487 {"pmul_z_zz"_h, CPUFeatures::kSVE2},
1488 {"pmullb_z_zz"_h, CPUFeatures::kSVE2},
1489 {"pmullt_z_zz"_h, CPUFeatures::kSVE2},
1490 {"raddhnb_z_zz"_h, CPUFeatures::kSVE2},
1491 {"raddhnt_z_zz"_h, CPUFeatures::kSVE2},
1492 {"rshrnb_z_zi"_h, CPUFeatures::kSVE2},
1493 {"rshrnt_z_zi"_h, CPUFeatures::kSVE2},
1494 {"rsubhnb_z_zz"_h, CPUFeatures::kSVE2},
1495 {"rsubhnt_z_zz"_h, CPUFeatures::kSVE2},
1496 {"saba_z_zzz"_h, CPUFeatures::kSVE2},
1497 {"sabalb_z_zzz"_h, CPUFeatures::kSVE2},
1498 {"sabalt_z_zzz"_h, CPUFeatures::kSVE2},
1499 {"sabdlb_z_zz"_h, CPUFeatures::kSVE2},
1500 {"sabdlt_z_zz"_h, CPUFeatures::kSVE2},
1501 {"sadalp_z_p_z"_h, CPUFeatures::kSVE2},
1502 {"saddlb_z_zz"_h, CPUFeatures::kSVE2},
1503 {"saddlbt_z_zz"_h, CPUFeatures::kSVE2},
1504 {"saddlt_z_zz"_h, CPUFeatures::kSVE2},
1505 {"saddwb_z_zz"_h, CPUFeatures::kSVE2},
1506 {"saddwt_z_zz"_h, CPUFeatures::kSVE2},
1507 {"sbclb_z_zzz"_h, CPUFeatures::kSVE2},
1508 {"sbclt_z_zzz"_h, CPUFeatures::kSVE2},
1509 {"shadd_z_p_zz"_h, CPUFeatures::kSVE2},
1510 {"shrnb_z_zi"_h, CPUFeatures::kSVE2},
1511 {"shrnt_z_zi"_h, CPUFeatures::kSVE2},
1512 {"shsub_z_p_zz"_h, CPUFeatures::kSVE2},
1513 {"shsubr_z_p_zz"_h, CPUFeatures::kSVE2},
1514 {"sli_z_zzi"_h, CPUFeatures::kSVE2},
1515 {"smaxp_z_p_zz"_h, CPUFeatures::kSVE2},
1516 {"sminp_z_p_zz"_h, CPUFeatures::kSVE2},
1517 {"smlalb_z_zzz"_h, CPUFeatures::kSVE2},
1518 {"smlalb_z_zzzi_d"_h, CPUFeatures::kSVE2},
1519 {"smlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1520 {"smlalt_z_zzz"_h, CPUFeatures::kSVE2},
1521 {"smlalt_z_zzzi_d"_h, CPUFeatures::kSVE2},
1522 {"smlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1523 {"smlslb_z_zzz"_h, CPUFeatures::kSVE2},
1524 {"smlslb_z_zzzi_d"_h, CPUFeatures::kSVE2},
1525 {"smlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1526 {"smlslt_z_zzz"_h, CPUFeatures::kSVE2},
1527 {"smlslt_z_zzzi_d"_h, CPUFeatures::kSVE2},
1528 {"smlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1529 {"smulh_z_zz"_h, CPUFeatures::kSVE2},
1530 {"smullb_z_zz"_h, CPUFeatures::kSVE2},
1531 {"smullb_z_zzi_d"_h, CPUFeatures::kSVE2},
1532 {"smullb_z_zzi_s"_h, CPUFeatures::kSVE2},
1533 {"smullt_z_zz"_h, CPUFeatures::kSVE2},
1534 {"smullt_z_zzi_d"_h, CPUFeatures::kSVE2},
1535 {"smullt_z_zzi_s"_h, CPUFeatures::kSVE2},
1536 {"splice_z_p_zz_con"_h, CPUFeatures::kSVE2},
1537 {"sqabs_z_p_z"_h, CPUFeatures::kSVE2},
1538 {"sqadd_z_p_zz"_h, CPUFeatures::kSVE2},
1539 {"sqcadd_z_zz"_h, CPUFeatures::kSVE2},
1540 {"sqdmlalb_z_zzz"_h, CPUFeatures::kSVE2},
1541 {"sqdmlalb_z_zzzi_d"_h, CPUFeatures::kSVE2},
1542 {"sqdmlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1543 {"sqdmlalbt_z_zzz"_h, CPUFeatures::kSVE2},
1544 {"sqdmlalt_z_zzz"_h, CPUFeatures::kSVE2},
1545 {"sqdmlalt_z_zzzi_d"_h, CPUFeatures::kSVE2},
1546 {"sqdmlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1547 {"sqdmlslb_z_zzz"_h, CPUFeatures::kSVE2},
1548 {"sqdmlslb_z_zzzi_d"_h, CPUFeatures::kSVE2},
1549 {"sqdmlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1550 {"sqdmlslbt_z_zzz"_h, CPUFeatures::kSVE2},
1551 {"sqdmlslt_z_zzz"_h, CPUFeatures::kSVE2},
1552 {"sqdmlslt_z_zzzi_d"_h, CPUFeatures::kSVE2},
1553 {"sqdmlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1554 {"sqdmulh_z_zz"_h, CPUFeatures::kSVE2},
1555 {"sqdmulh_z_zzi_d"_h, CPUFeatures::kSVE2},
1556 {"sqdmulh_z_zzi_h"_h, CPUFeatures::kSVE2},
1557 {"sqdmulh_z_zzi_s"_h, CPUFeatures::kSVE2},
1558 {"sqdmullb_z_zz"_h, CPUFeatures::kSVE2},
1559 {"sqdmullb_z_zzi_d"_h, CPUFeatures::kSVE2},
1560 {"sqdmullb_z_zzi_s"_h, CPUFeatures::kSVE2},
1561 {"sqdmullt_z_zz"_h, CPUFeatures::kSVE2},
1562 {"sqdmullt_z_zzi_d"_h, CPUFeatures::kSVE2},
1563 {"sqdmullt_z_zzi_s"_h, CPUFeatures::kSVE2},
1564 {"sqneg_z_p_z"_h, CPUFeatures::kSVE2},
1565 {"sqrdcmlah_z_zzz"_h, CPUFeatures::kSVE2},
1566 {"sqrdcmlah_z_zzzi_h"_h, CPUFeatures::kSVE2},
1567 {"sqrdcmlah_z_zzzi_s"_h, CPUFeatures::kSVE2},
1568 {"sqrdmlah_z_zzz"_h, CPUFeatures::kSVE2},
1569 {"sqrdmlah_z_zzzi_d"_h, CPUFeatures::kSVE2},
1570 {"sqrdmlah_z_zzzi_h"_h, CPUFeatures::kSVE2},
1571 {"sqrdmlah_z_zzzi_s"_h, CPUFeatures::kSVE2},
1572 {"sqrdmlsh_z_zzz"_h, CPUFeatures::kSVE2},
1573 {"sqrdmlsh_z_zzzi_d"_h, CPUFeatures::kSVE2},
1574 {"sqrdmlsh_z_zzzi_h"_h, CPUFeatures::kSVE2},
1575 {"sqrdmlsh_z_zzzi_s"_h, CPUFeatures::kSVE2},
1576 {"sqrdmulh_z_zz"_h, CPUFeatures::kSVE2},
1577 {"sqrdmulh_z_zzi_d"_h, CPUFeatures::kSVE2},
1578 {"sqrdmulh_z_zzi_h"_h, CPUFeatures::kSVE2},
1579 {"sqrdmulh_z_zzi_s"_h, CPUFeatures::kSVE2},
1580 {"sqrshl_z_p_zz"_h, CPUFeatures::kSVE2},
1581 {"sqrshlr_z_p_zz"_h, CPUFeatures::kSVE2},
1582 {"sqrshrnb_z_zi"_h, CPUFeatures::kSVE2},
1583 {"sqrshrnt_z_zi"_h, CPUFeatures::kSVE2},
1584 {"sqrshrunb_z_zi"_h, CPUFeatures::kSVE2},
1585 {"sqrshrunt_z_zi"_h, CPUFeatures::kSVE2},
1586 {"sqshl_z_p_zi"_h, CPUFeatures::kSVE2},
1587 {"sqshl_z_p_zz"_h, CPUFeatures::kSVE2},
1588 {"sqshlr_z_p_zz"_h, CPUFeatures::kSVE2},
1589 {"sqshlu_z_p_zi"_h, CPUFeatures::kSVE2},
1590 {"sqshrnb_z_zi"_h, CPUFeatures::kSVE2},
1591 {"sqshrnt_z_zi"_h, CPUFeatures::kSVE2},
1592 {"sqshrunb_z_zi"_h, CPUFeatures::kSVE2},
1593 {"sqshrunt_z_zi"_h, CPUFeatures::kSVE2},
1594 {"sqsub_z_p_zz"_h, CPUFeatures::kSVE2},
1595 {"sqsubr_z_p_zz"_h, CPUFeatures::kSVE2},
1596 {"sqxtnb_z_zz"_h, CPUFeatures::kSVE2},
1597 {"sqxtnt_z_zz"_h, CPUFeatures::kSVE2},
1598 {"sqxtunb_z_zz"_h, CPUFeatures::kSVE2},
1599 {"sqxtunt_z_zz"_h, CPUFeatures::kSVE2},
1600 {"srhadd_z_p_zz"_h, CPUFeatures::kSVE2},
1601 {"sri_z_zzi"_h, CPUFeatures::kSVE2},
1602 {"srshl_z_p_zz"_h, CPUFeatures::kSVE2},
1603 {"srshlr_z_p_zz"_h, CPUFeatures::kSVE2},
1604 {"srshr_z_p_zi"_h, CPUFeatures::kSVE2},
1605 {"srsra_z_zi"_h, CPUFeatures::kSVE2},
1606 {"sshllb_z_zi"_h, CPUFeatures::kSVE2},
1607 {"sshllt_z_zi"_h, CPUFeatures::kSVE2},
1608 {"ssra_z_zi"_h, CPUFeatures::kSVE2},
1609 {"ssublb_z_zz"_h, CPUFeatures::kSVE2},
1610 {"ssublbt_z_zz"_h, CPUFeatures::kSVE2},
1611 {"ssublt_z_zz"_h, CPUFeatures::kSVE2},
1612 {"ssubltb_z_zz"_h, CPUFeatures::kSVE2},
1613 {"ssubwb_z_zz"_h, CPUFeatures::kSVE2},
1614 {"ssubwt_z_zz"_h, CPUFeatures::kSVE2},
1615 {"stnt1b_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1616 {"stnt1b_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1617 {"stnt1d_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1618 {"stnt1h_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1619 {"stnt1h_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1620 {"stnt1w_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
1621 {"stnt1w_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
1622 {"subhnb_z_zz"_h, CPUFeatures::kSVE2},
1623 {"subhnt_z_zz"_h, CPUFeatures::kSVE2},
1624 {"suqadd_z_p_zz"_h, CPUFeatures::kSVE2},
1625 {"tbl_z_zz_2"_h, CPUFeatures::kSVE2},
1626 {"tbx_z_zz"_h, CPUFeatures::kSVE2},
1627 {"uaba_z_zzz"_h, CPUFeatures::kSVE2},
1628 {"uabalb_z_zzz"_h, CPUFeatures::kSVE2},
1629 {"uabalt_z_zzz"_h, CPUFeatures::kSVE2},
1630 {"uabdlb_z_zz"_h, CPUFeatures::kSVE2},
1631 {"uabdlt_z_zz"_h, CPUFeatures::kSVE2},
1632 {"uadalp_z_p_z"_h, CPUFeatures::kSVE2},
1633 {"uaddlb_z_zz"_h, CPUFeatures::kSVE2},
1634 {"uaddlt_z_zz"_h, CPUFeatures::kSVE2},
1635 {"uaddwb_z_zz"_h, CPUFeatures::kSVE2},
1636 {"uaddwt_z_zz"_h, CPUFeatures::kSVE2},
1637 {"uhadd_z_p_zz"_h, CPUFeatures::kSVE2},
1638 {"uhsub_z_p_zz"_h, CPUFeatures::kSVE2},
1639 {"uhsubr_z_p_zz"_h, CPUFeatures::kSVE2},
1640 {"umaxp_z_p_zz"_h, CPUFeatures::kSVE2},
1641 {"uminp_z_p_zz"_h, CPUFeatures::kSVE2},
1642 {"umlalb_z_zzz"_h, CPUFeatures::kSVE2},
1643 {"umlalb_z_zzzi_d"_h, CPUFeatures::kSVE2},
1644 {"umlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1645 {"umlalt_z_zzz"_h, CPUFeatures::kSVE2},
1646 {"umlalt_z_zzzi_d"_h, CPUFeatures::kSVE2},
1647 {"umlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1648 {"umlslb_z_zzz"_h, CPUFeatures::kSVE2},
1649 {"umlslb_z_zzzi_d"_h, CPUFeatures::kSVE2},
1650 {"umlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
1651 {"umlslt_z_zzz"_h, CPUFeatures::kSVE2},
1652 {"umlslt_z_zzzi_d"_h, CPUFeatures::kSVE2},
1653 {"umlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
1654 {"umulh_z_zz"_h, CPUFeatures::kSVE2},
1655 {"umullb_z_zz"_h, CPUFeatures::kSVE2},
1656 {"umullb_z_zzi_d"_h, CPUFeatures::kSVE2},
1657 {"umullb_z_zzi_s"_h, CPUFeatures::kSVE2},
1658 {"umullt_z_zz"_h, CPUFeatures::kSVE2},
1659 {"umullt_z_zzi_d"_h, CPUFeatures::kSVE2},
1660 {"umullt_z_zzi_s"_h, CPUFeatures::kSVE2},
1661 {"uqadd_z_p_zz"_h, CPUFeatures::kSVE2},
1662 {"uqrshl_z_p_zz"_h, CPUFeatures::kSVE2},
1663 {"uqrshlr_z_p_zz"_h, CPUFeatures::kSVE2},
1664 {"uqrshrnb_z_zi"_h, CPUFeatures::kSVE2},
1665 {"uqrshrnt_z_zi"_h, CPUFeatures::kSVE2},
1666 {"uqshl_z_p_zi"_h, CPUFeatures::kSVE2},
1667 {"uqshl_z_p_zz"_h, CPUFeatures::kSVE2},
1668 {"uqshlr_z_p_zz"_h, CPUFeatures::kSVE2},
1669 {"uqshrnb_z_zi"_h, CPUFeatures::kSVE2},
1670 {"uqshrnt_z_zi"_h, CPUFeatures::kSVE2},
1671 {"uqsub_z_p_zz"_h, CPUFeatures::kSVE2},
1672 {"uqsubr_z_p_zz"_h, CPUFeatures::kSVE2},
1673 {"uqxtnb_z_zz"_h, CPUFeatures::kSVE2},
1674 {"uqxtnt_z_zz"_h, CPUFeatures::kSVE2},
1675 {"urecpe_z_p_z"_h, CPUFeatures::kSVE2},
1676 {"urhadd_z_p_zz"_h, CPUFeatures::kSVE2},
1677 {"urshl_z_p_zz"_h, CPUFeatures::kSVE2},
1678 {"urshlr_z_p_zz"_h, CPUFeatures::kSVE2},
1679 {"urshr_z_p_zi"_h, CPUFeatures::kSVE2},
1680 {"ursqrte_z_p_z"_h, CPUFeatures::kSVE2},
1681 {"ursra_z_zi"_h, CPUFeatures::kSVE2},
1682 {"ushllb_z_zi"_h, CPUFeatures::kSVE2},
1683 {"ushllt_z_zi"_h, CPUFeatures::kSVE2},
1684 {"usqadd_z_p_zz"_h, CPUFeatures::kSVE2},
1685 {"usra_z_zi"_h, CPUFeatures::kSVE2},
1686 {"usublb_z_zz"_h, CPUFeatures::kSVE2},
1687 {"usublt_z_zz"_h, CPUFeatures::kSVE2},
1688 {"usubwb_z_zz"_h, CPUFeatures::kSVE2},
1689 {"usubwt_z_zz"_h, CPUFeatures::kSVE2},
1690 {"whilege_p_p_rr"_h, CPUFeatures::kSVE2},
1691 {"whilegt_p_p_rr"_h, CPUFeatures::kSVE2},
1692 {"whilehi_p_p_rr"_h, CPUFeatures::kSVE2},
1693 {"whilehs_p_p_rr"_h, CPUFeatures::kSVE2},
1694 {"whilerw_p_rr"_h, CPUFeatures::kSVE2},
1695 {"whilewr_p_rr"_h, CPUFeatures::kSVE2},
1696 {"xar_z_zzi"_h, CPUFeatures::kSVE2},
1697 {"smmla_z_zzz"_h,
1698 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
1699 {"ummla_z_zzz"_h,
1700 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
1701 {"usmmla_z_zzz"_h,
1702 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
1703 {"fmmla_z_zzz_s"_h,
1704 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF32MM)},
1705 {"fmmla_z_zzz_d"_h,
1706 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1707 {"smmla_asimdsame2_g"_h,
1708 CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
1709 {"ummla_asimdsame2_g"_h,
1710 CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
1711 {"usmmla_asimdsame2_g"_h,
1712 CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
1713 {"ld1row_z_p_bi_u32"_h,
1714 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1715 {"ld1row_z_p_br_contiguous"_h,
1716 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1717 {"ld1rod_z_p_bi_u64"_h,
1718 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1719 {"ld1rod_z_p_br_contiguous"_h,
1720 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1721 {"ld1rob_z_p_bi_u8"_h,
1722 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1723 {"ld1rob_z_p_br_contiguous"_h,
1724 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1725 {"ld1roh_z_p_bi_u16"_h,
1726 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1727 {"ld1roh_z_p_br_contiguous"_h,
1728 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
1729 {"usdot_asimdsame2_d"_h,
1730 CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
1731 {"sudot_asimdelem_d"_h,
1732 CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
1733 {"usdot_asimdelem_d"_h,
1734 CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
1735 {"usdot_z_zzz_s"_h,
1736 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
1737 {"usdot_z_zzzi_s"_h,
1738 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
1739 {"sudot_z_zzzi_s"_h,
1740 CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
1741 {"addg_64_addsub_immtags"_h, CPUFeatures::kMTE},
1742 {"gmi_64g_dp_2src"_h, CPUFeatures::kMTE},
1743 {"irg_64i_dp_2src"_h, CPUFeatures::kMTE},
1744 {"ldg_64loffset_ldsttags"_h, CPUFeatures::kMTE},
1745 {"st2g_64soffset_ldsttags"_h, CPUFeatures::kMTE},
1746 {"st2g_64spost_ldsttags"_h, CPUFeatures::kMTE},
1747 {"st2g_64spre_ldsttags"_h, CPUFeatures::kMTE},
1748 {"stgp_64_ldstpair_off"_h, CPUFeatures::kMTE},
1749 {"stgp_64_ldstpair_post"_h, CPUFeatures::kMTE},
1750 {"stgp_64_ldstpair_pre"_h, CPUFeatures::kMTE},
1751 {"stg_64soffset_ldsttags"_h, CPUFeatures::kMTE},
1752 {"stg_64spost_ldsttags"_h, CPUFeatures::kMTE},
1753 {"stg_64spre_ldsttags"_h, CPUFeatures::kMTE},
1754 {"stz2g_64soffset_ldsttags"_h, CPUFeatures::kMTE},
1755 {"stz2g_64spost_ldsttags"_h, CPUFeatures::kMTE},
1756 {"stz2g_64spre_ldsttags"_h, CPUFeatures::kMTE},
1757 {"stzg_64soffset_ldsttags"_h, CPUFeatures::kMTE},
1758 {"stzg_64spost_ldsttags"_h, CPUFeatures::kMTE},
1759 {"stzg_64spre_ldsttags"_h, CPUFeatures::kMTE},
1760 {"subg_64_addsub_immtags"_h, CPUFeatures::kMTE},
1761 {"subps_64s_dp_2src"_h, CPUFeatures::kMTE},
1762 {"subp_64s_dp_2src"_h, CPUFeatures::kMTE},
1763 {"cpyen_cpy_memcms"_h, CPUFeatures::kMOPS},
1764 {"cpyern_cpy_memcms"_h, CPUFeatures::kMOPS},
1765 {"cpyewn_cpy_memcms"_h, CPUFeatures::kMOPS},
1766 {"cpye_cpy_memcms"_h, CPUFeatures::kMOPS},
1767 {"cpyfen_cpy_memcms"_h, CPUFeatures::kMOPS},
1768 {"cpyfern_cpy_memcms"_h, CPUFeatures::kMOPS},
1769 {"cpyfewn_cpy_memcms"_h, CPUFeatures::kMOPS},
1770 {"cpyfe_cpy_memcms"_h, CPUFeatures::kMOPS},
1771 {"cpyfmn_cpy_memcms"_h, CPUFeatures::kMOPS},
1772 {"cpyfmrn_cpy_memcms"_h, CPUFeatures::kMOPS},
1773 {"cpyfmwn_cpy_memcms"_h, CPUFeatures::kMOPS},
1774 {"cpyfm_cpy_memcms"_h, CPUFeatures::kMOPS},
1775 {"cpyfpn_cpy_memcms"_h, CPUFeatures::kMOPS},
1776 {"cpyfprn_cpy_memcms"_h, CPUFeatures::kMOPS},
1777 {"cpyfpwn_cpy_memcms"_h, CPUFeatures::kMOPS},
1778 {"cpyfp_cpy_memcms"_h, CPUFeatures::kMOPS},
1779 {"cpymn_cpy_memcms"_h, CPUFeatures::kMOPS},
1780 {"cpymrn_cpy_memcms"_h, CPUFeatures::kMOPS},
1781 {"cpymwn_cpy_memcms"_h, CPUFeatures::kMOPS},
1782 {"cpym_cpy_memcms"_h, CPUFeatures::kMOPS},
1783 {"cpypn_cpy_memcms"_h, CPUFeatures::kMOPS},
1784 {"cpyprn_cpy_memcms"_h, CPUFeatures::kMOPS},
1785 {"cpypwn_cpy_memcms"_h, CPUFeatures::kMOPS},
1786 {"cpyp_cpy_memcms"_h, CPUFeatures::kMOPS},
1787 {"seten_set_memcms"_h, CPUFeatures::kMOPS},
1788 {"sete_set_memcms"_h, CPUFeatures::kMOPS},
1789 {"setgen_set_memcms"_h,
1790 CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
1791 {"setge_set_memcms"_h,
1792 CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
1793 {"setgmn_set_memcms"_h,
1794 CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
1795 {"setgm_set_memcms"_h,
1796 CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
1797 {"setgpn_set_memcms"_h,
1798 CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
1799 {"setgp_set_memcms"_h,
1800 CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
1801 {"setmn_set_memcms"_h, CPUFeatures::kMOPS},
1802 {"setm_set_memcms"_h, CPUFeatures::kMOPS},
1803 {"setpn_set_memcms"_h, CPUFeatures::kMOPS},
1804 {"setp_set_memcms"_h, CPUFeatures::kMOPS},
1805 {"abs_32_dp_1src"_h, CPUFeatures::kCSSC},
1806 {"abs_64_dp_1src"_h, CPUFeatures::kCSSC},
1807 {"cnt_32_dp_1src"_h, CPUFeatures::kCSSC},
1808 {"cnt_64_dp_1src"_h, CPUFeatures::kCSSC},
1809 {"ctz_32_dp_1src"_h, CPUFeatures::kCSSC},
1810 {"ctz_64_dp_1src"_h, CPUFeatures::kCSSC},
1811 {"smax_32_dp_2src"_h, CPUFeatures::kCSSC},
1812 {"smax_64_dp_2src"_h, CPUFeatures::kCSSC},
1813 {"smin_32_dp_2src"_h, CPUFeatures::kCSSC},
1814 {"smin_64_dp_2src"_h, CPUFeatures::kCSSC},
1815 {"umax_32_dp_2src"_h, CPUFeatures::kCSSC},
1816 {"umax_64_dp_2src"_h, CPUFeatures::kCSSC},
1817 {"umin_32_dp_2src"_h, CPUFeatures::kCSSC},
1818 {"umin_64_dp_2src"_h, CPUFeatures::kCSSC},
1819 {"smax_32_minmax_imm"_h, CPUFeatures::kCSSC},
1820 {"smax_64_minmax_imm"_h, CPUFeatures::kCSSC},
1821 {"smin_32_minmax_imm"_h, CPUFeatures::kCSSC},
1822 {"smin_64_minmax_imm"_h, CPUFeatures::kCSSC},
1823 {"umax_32u_minmax_imm"_h, CPUFeatures::kCSSC},
1824 {"umax_64u_minmax_imm"_h, CPUFeatures::kCSSC},
1825 {"umin_32u_minmax_imm"_h, CPUFeatures::kCSSC},
1826 {"umin_64u_minmax_imm"_h, CPUFeatures::kCSSC},
1827 };
1828
1829 if (features.count(form_hash) > 0) {
1830 scope.Record(features[form_hash]);
1831 }
1832 } else {
1833 (it->second)(this, instr);
1834 }
1835 }
1836
1837 } // namespace aarch64
1838 } // namespace vixl
1839