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