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