duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

cpu-features-auditor-aarch64.cc (68668B)


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