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