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
35namespace vixl {
36namespace aarch64 {
37
38const 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
68const CPUFeaturesAuditor::FormToVisitorFnMap*
69CPUFeaturesAuditor::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.
76class CPUFeaturesAuditor::RecordInstructionFeaturesScope {
77 public:
78  explicit RecordInstructionFeaturesScope(CPUFeaturesAuditor* auditor)
79      : auditor_(auditor) {
80    auditor_->last_instruction_ = CPUFeatures::None();
81  }
82  ~RecordInstructionFeaturesScope() {
83    auditor_->seen_.Combine(auditor_->last_instruction_);
84  }
85
86  void Record(const CPUFeatures& features) {
87    auditor_->last_instruction_.Combine(features);
88  }
89
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.
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
116void 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
139void 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
159void CPUFeaturesAuditor::VisitAddSubExtended(const Instruction* instr) {
160  RecordInstructionFeaturesScope scope(this);
161  USE(instr);
162}
163
164void CPUFeaturesAuditor::VisitAddSubImmediate(const Instruction* instr) {
165  RecordInstructionFeaturesScope scope(this);
166  USE(instr);
167}
168
169void CPUFeaturesAuditor::VisitAddSubShifted(const Instruction* instr) {
170  RecordInstructionFeaturesScope scope(this);
171  USE(instr);
172}
173
174void CPUFeaturesAuditor::VisitAddSubWithCarry(const Instruction* instr) {
175  RecordInstructionFeaturesScope scope(this);
176  USE(instr);
177}
178
179void 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
188void 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
198void 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
214void CPUFeaturesAuditor::VisitBitfield(const Instruction* instr) {
215  RecordInstructionFeaturesScope scope(this);
216  USE(instr);
217}
218
219void CPUFeaturesAuditor::VisitCompareBranch(const Instruction* instr) {
220  RecordInstructionFeaturesScope scope(this);
221  USE(instr);
222}
223
224void CPUFeaturesAuditor::VisitConditionalBranch(const Instruction* instr) {
225  RecordInstructionFeaturesScope scope(this);
226  USE(instr);
227}
228
229void CPUFeaturesAuditor::VisitConditionalCompareImmediate(
230    const Instruction* instr) {
231  RecordInstructionFeaturesScope scope(this);
232  USE(instr);
233}
234
235void CPUFeaturesAuditor::VisitConditionalCompareRegister(
236    const Instruction* instr) {
237  RecordInstructionFeaturesScope scope(this);
238  USE(instr);
239}
240
241void CPUFeaturesAuditor::VisitConditionalSelect(const Instruction* instr) {
242  RecordInstructionFeaturesScope scope(this);
243  USE(instr);
244}
245
246void CPUFeaturesAuditor::VisitCrypto2RegSHA(const Instruction* instr) {
247  RecordInstructionFeaturesScope scope(this);
248  USE(instr);
249}
250
251void CPUFeaturesAuditor::VisitCrypto3RegSHA(const Instruction* instr) {
252  RecordInstructionFeaturesScope scope(this);
253  USE(instr);
254}
255
256void CPUFeaturesAuditor::VisitCryptoAES(const Instruction* instr) {
257  RecordInstructionFeaturesScope scope(this);
258  USE(instr);
259}
260
261void 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
290void 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
312void 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
337void CPUFeaturesAuditor::VisitLoadStorePAC(const Instruction* instr) {
338  RecordInstructionFeaturesScope scope(this);
339  USE(instr);
340  scope.Record(CPUFeatures::kPAuth);
341}
342
343void CPUFeaturesAuditor::VisitDataProcessing3Source(const Instruction* instr) {
344  RecordInstructionFeaturesScope scope(this);
345  USE(instr);
346}
347
348void CPUFeaturesAuditor::VisitException(const Instruction* instr) {
349  RecordInstructionFeaturesScope scope(this);
350  USE(instr);
351}
352
353void CPUFeaturesAuditor::VisitExtract(const Instruction* instr) {
354  RecordInstructionFeaturesScope scope(this);
355  USE(instr);
356}
357
358void 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
375void 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
390void 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
399void 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
436void 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
459void 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
477void 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
498void 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
507void 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
559void 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
575void 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
620void CPUFeaturesAuditor::VisitLoadStorePairNonTemporal(
621    const Instruction* instr) {
622  LoadStorePairHelper(instr);
623}
624
625void CPUFeaturesAuditor::VisitLoadStorePairOffset(const Instruction* instr) {
626  LoadStorePairHelper(instr);
627}
628
629void CPUFeaturesAuditor::VisitLoadStorePairPostIndex(const Instruction* instr) {
630  LoadStorePairHelper(instr);
631}
632
633void CPUFeaturesAuditor::VisitLoadStorePairPreIndex(const Instruction* instr) {
634  LoadStorePairHelper(instr);
635}
636
637void CPUFeaturesAuditor::VisitLoadStorePostIndex(const Instruction* instr) {
638  LoadStoreHelper(instr);
639}
640
641void CPUFeaturesAuditor::VisitLoadStorePreIndex(const Instruction* instr) {
642  LoadStoreHelper(instr);
643}
644
645void CPUFeaturesAuditor::VisitLoadStoreRegisterOffset(
646    const Instruction* instr) {
647  LoadStoreHelper(instr);
648}
649
650void CPUFeaturesAuditor::VisitLoadStoreUnscaledOffset(
651    const Instruction* instr) {
652  LoadStoreHelper(instr);
653}
654
655void CPUFeaturesAuditor::VisitLoadStoreUnsignedOffset(
656    const Instruction* instr) {
657  LoadStoreHelper(instr);
658}
659
660void CPUFeaturesAuditor::VisitLogicalImmediate(const Instruction* instr) {
661  RecordInstructionFeaturesScope scope(this);
662  USE(instr);
663}
664
665void CPUFeaturesAuditor::VisitLogicalShifted(const Instruction* instr) {
666  RecordInstructionFeaturesScope scope(this);
667  USE(instr);
668}
669
670void CPUFeaturesAuditor::VisitMoveWideImmediate(const Instruction* instr) {
671  RecordInstructionFeaturesScope scope(this);
672  USE(instr);
673}
674
675void 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
726void 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
733void 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
740void 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
760void 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
785void 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
792void 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
805void 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
858void 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
865void 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
872void 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
880void 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
888void 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
896void 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
904void 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
915void 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
922void 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
956void 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
963void 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
970void 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
979void 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
986void 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
993void 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
1023void 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
1030void 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
1055void 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
1077void 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
1098void 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
1105void 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  }
1265VIXL_SIMPLE_SVE_VISITOR_LIST(VIXL_DEFINE_SIMPLE_SVE_VISITOR)
1266#undef VIXL_DEFINE_SIMPLE_SVE_VISITOR
1267#undef VIXL_SIMPLE_SVE_VISITOR_LIST
1268
1269void 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
1359void CPUFeaturesAuditor::VisitTestBranch(const Instruction* instr) {
1360  RecordInstructionFeaturesScope scope(this);
1361  USE(instr);
1362}
1363
1364void CPUFeaturesAuditor::VisitUnallocated(const Instruction* instr) {
1365  RecordInstructionFeaturesScope scope(this);
1366  USE(instr);
1367}
1368
1369void CPUFeaturesAuditor::VisitUnconditionalBranch(const Instruction* instr) {
1370  RecordInstructionFeaturesScope scope(this);
1371  USE(instr);
1372}
1373
1374void 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
1396void CPUFeaturesAuditor::VisitReserved(const Instruction* instr) {
1397  RecordInstructionFeaturesScope scope(this);
1398  USE(instr);
1399}
1400
1401void CPUFeaturesAuditor::VisitUnimplemented(const Instruction* instr) {
1402  RecordInstructionFeaturesScope scope(this);
1403  USE(instr);
1404}
1405
1406void 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