| // Copyright 2018, VIXL authors |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // |
| // * Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimer in the documentation |
| // and/or other materials provided with the distribution. |
| // * Neither the name of Arm Limited nor the names of its contributors may be |
| // used to endorse or promote products derived from this software without |
| // specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
| // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "cpu-features.h" |
| #include "globals-vixl.h" |
| #include "utils-vixl.h" |
| #include "decoder-aarch64.h" |
| |
| #include "cpu-features-auditor-aarch64.h" |
| |
| namespace vixl { |
| namespace aarch64 { |
| |
| CPUFeaturesAuditor::FormToVisitorFnMap CPUFeaturesAuditor::form_to_visitor_ = { |
| DEFAULT_FORM_TO_VISITOR_MAP(CPUFeaturesAuditor)}; |
| |
| // Every instruction must update last_instruction_, even if only to clear it, |
| // and every instruction must also update seen_ once it has been fully handled. |
| // This scope makes that simple, and allows early returns in the decode logic. |
| class CPUFeaturesAuditor::RecordInstructionFeaturesScope { |
| public: |
| explicit RecordInstructionFeaturesScope(CPUFeaturesAuditor* auditor) |
| : auditor_(auditor) { |
| auditor_->last_instruction_ = CPUFeatures::None(); |
| } |
| ~RecordInstructionFeaturesScope() { |
| auditor_->seen_.Combine(auditor_->last_instruction_); |
| } |
| |
| void Record(const CPUFeatures& features) { |
| auditor_->last_instruction_.Combine(features); |
| } |
| |
| void Record(CPUFeatures::Feature feature0, |
| CPUFeatures::Feature feature1 = CPUFeatures::kNone, |
| CPUFeatures::Feature feature2 = CPUFeatures::kNone, |
| CPUFeatures::Feature feature3 = CPUFeatures::kNone) { |
| auditor_->last_instruction_.Combine(feature0, feature1, feature2, feature3); |
| } |
| |
| // If exactly one of a or b is known to be available, record it. Otherwise, |
| // record both. This is intended for encodings that can be provided by two |
| // different features. |
| void RecordOneOrBothOf(CPUFeatures::Feature a, CPUFeatures::Feature b) { |
| bool hint_a = auditor_->available_.Has(a); |
| bool hint_b = auditor_->available_.Has(b); |
| if (hint_a && !hint_b) { |
| Record(a); |
| } else if (hint_b && !hint_a) { |
| Record(b); |
| } else { |
| Record(a, b); |
| } |
| } |
| |
| private: |
| CPUFeaturesAuditor* auditor_; |
| }; |
| |
| void CPUFeaturesAuditor::LoadStoreHelper(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(LoadStoreMask)) { |
| case LDR_b: |
| case LDR_q: |
| case STR_b: |
| case STR_q: |
| scope.Record(CPUFeatures::kNEON); |
| return; |
| case LDR_h: |
| case LDR_s: |
| case LDR_d: |
| case STR_h: |
| case STR_s: |
| case STR_d: |
| scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::LoadStorePairHelper(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(LoadStorePairMask)) { |
| case LDP_q: |
| case STP_q: |
| scope.Record(CPUFeatures::kNEON); |
| return; |
| case LDP_s: |
| case LDP_d: |
| case STP_s: |
| case STP_d: { |
| scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON); |
| return; |
| } |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitAddSubExtended(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitAddSubImmediate(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitAddSubShifted(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitAddSubWithCarry(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitRotateRightIntoFlags(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(RotateRightIntoFlagsMask)) { |
| case RMIF: |
| scope.Record(CPUFeatures::kFlagM); |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitEvaluateIntoFlags(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(EvaluateIntoFlagsMask)) { |
| case SETF8: |
| case SETF16: |
| scope.Record(CPUFeatures::kFlagM); |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitAtomicMemory(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(AtomicMemoryMask)) { |
| case LDAPRB: |
| case LDAPRH: |
| case LDAPR_w: |
| case LDAPR_x: |
| scope.Record(CPUFeatures::kRCpc); |
| return; |
| default: |
| // Everything else belongs to the Atomics extension. |
| scope.Record(CPUFeatures::kAtomics); |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitBitfield(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitCompareBranch(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitConditionalBranch(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitConditionalCompareImmediate( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitConditionalCompareRegister( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitConditionalSelect(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitCrypto2RegSHA(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitCrypto3RegSHA(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitCryptoAES(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitDataProcessing1Source(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(DataProcessing1SourceMask)) { |
| case PACIA: |
| case PACIB: |
| case PACDA: |
| case PACDB: |
| case AUTIA: |
| case AUTIB: |
| case AUTDA: |
| case AUTDB: |
| case PACIZA: |
| case PACIZB: |
| case PACDZA: |
| case PACDZB: |
| case AUTIZA: |
| case AUTIZB: |
| case AUTDZA: |
| case AUTDZB: |
| case XPACI: |
| case XPACD: |
| scope.Record(CPUFeatures::kPAuth); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitDataProcessing2Source(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(DataProcessing2SourceMask)) { |
| case CRC32B: |
| case CRC32H: |
| case CRC32W: |
| case CRC32X: |
| case CRC32CB: |
| case CRC32CH: |
| case CRC32CW: |
| case CRC32CX: |
| scope.Record(CPUFeatures::kCRC32); |
| return; |
| case PACGA: |
| scope.Record(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStoreRCpcUnscaledOffset( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(LoadStoreRCpcUnscaledOffsetMask)) { |
| case LDAPURB: |
| case LDAPURSB_w: |
| case LDAPURSB_x: |
| case LDAPURH: |
| case LDAPURSH_w: |
| case LDAPURSH_x: |
| case LDAPUR_w: |
| case LDAPURSW: |
| case LDAPUR_x: |
| |
| // These stores don't actually have RCpc semantics but they're included with |
| // the RCpc extensions. |
| case STLURB: |
| case STLURH: |
| case STLUR_w: |
| case STLUR_x: |
| scope.Record(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm); |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePAC(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| scope.Record(CPUFeatures::kPAuth); |
| } |
| |
| void CPUFeaturesAuditor::VisitDataProcessing3Source(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitException(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitExtract(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitFPCompare(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPCompareMask)) { |
| case FCMP_h: |
| case FCMP_h_zero: |
| case FCMPE_h: |
| case FCMPE_h_zero: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPConditionalCompare(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPConditionalCompareMask)) { |
| case FCCMP_h: |
| case FCCMPE_h: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPConditionalSelect(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| if (instr->Mask(FPConditionalSelectMask) == FCSEL_h) { |
| scope.Record(CPUFeatures::kFPHalf); |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPDataProcessing1Source( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPDataProcessing1SourceMask)) { |
| case FMOV_h: |
| case FABS_h: |
| case FNEG_h: |
| case FSQRT_h: |
| case FRINTN_h: |
| case FRINTP_h: |
| case FRINTM_h: |
| case FRINTZ_h: |
| case FRINTA_h: |
| case FRINTX_h: |
| case FRINTI_h: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| case FRINT32X_s: |
| case FRINT32X_d: |
| case FRINT32Z_s: |
| case FRINT32Z_d: |
| case FRINT64X_s: |
| case FRINT64X_d: |
| case FRINT64Z_s: |
| case FRINT64Z_d: |
| scope.Record(CPUFeatures::kFrintToFixedSizedInt); |
| return; |
| default: |
| // No special CPU features. |
| // This category includes some half-precision FCVT instructions that do |
| // not require FPHalf. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPDataProcessing2Source( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPDataProcessing2SourceMask)) { |
| case FMUL_h: |
| case FDIV_h: |
| case FADD_h: |
| case FSUB_h: |
| case FMAX_h: |
| case FMIN_h: |
| case FMAXNM_h: |
| case FMINNM_h: |
| case FNMUL_h: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPDataProcessing3Source( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPDataProcessing3SourceMask)) { |
| case FMADD_h: |
| case FMSUB_h: |
| case FNMADD_h: |
| case FNMSUB_h: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPFixedPointConvert(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPFixedPointConvertMask)) { |
| case FCVTZS_wh_fixed: |
| case FCVTZS_xh_fixed: |
| case FCVTZU_wh_fixed: |
| case FCVTZU_xh_fixed: |
| case SCVTF_hw_fixed: |
| case SCVTF_hx_fixed: |
| case UCVTF_hw_fixed: |
| case UCVTF_hx_fixed: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPImmediate(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| if (instr->Mask(FPImmediateMask) == FMOV_h_imm) { |
| scope.Record(CPUFeatures::kFPHalf); |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitFPIntegerConvert(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require FP. |
| scope.Record(CPUFeatures::kFP); |
| switch (instr->Mask(FPIntegerConvertMask)) { |
| case FCVTAS_wh: |
| case FCVTAS_xh: |
| case FCVTAU_wh: |
| case FCVTAU_xh: |
| case FCVTMS_wh: |
| case FCVTMS_xh: |
| case FCVTMU_wh: |
| case FCVTMU_xh: |
| case FCVTNS_wh: |
| case FCVTNS_xh: |
| case FCVTNU_wh: |
| case FCVTNU_xh: |
| case FCVTPS_wh: |
| case FCVTPS_xh: |
| case FCVTPU_wh: |
| case FCVTPU_xh: |
| case FCVTZS_wh: |
| case FCVTZS_xh: |
| case FCVTZU_wh: |
| case FCVTZU_xh: |
| case FMOV_hw: |
| case FMOV_hx: |
| case FMOV_wh: |
| case FMOV_xh: |
| case SCVTF_hw: |
| case SCVTF_hx: |
| case UCVTF_hw: |
| case UCVTF_hx: |
| scope.Record(CPUFeatures::kFPHalf); |
| return; |
| case FMOV_d1_x: |
| case FMOV_x_d1: |
| scope.Record(CPUFeatures::kNEON); |
| return; |
| case FJCVTZS: |
| scope.Record(CPUFeatures::kJSCVT); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadLiteral(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(LoadLiteralMask)) { |
| case LDR_s_lit: |
| case LDR_d_lit: |
| scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON); |
| return; |
| case LDR_q_lit: |
| scope.Record(CPUFeatures::kNEON); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStoreExclusive(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(LoadStoreExclusiveMask)) { |
| case CAS_w: |
| case CASA_w: |
| case CASL_w: |
| case CASAL_w: |
| case CAS_x: |
| case CASA_x: |
| case CASL_x: |
| case CASAL_x: |
| case CASB: |
| case CASAB: |
| case CASLB: |
| case CASALB: |
| case CASH: |
| case CASAH: |
| case CASLH: |
| case CASALH: |
| case CASP_w: |
| case CASPA_w: |
| case CASPL_w: |
| case CASPAL_w: |
| case CASP_x: |
| case CASPA_x: |
| case CASPL_x: |
| case CASPAL_x: |
| scope.Record(CPUFeatures::kAtomics); |
| return; |
| case STLLRB: |
| case LDLARB: |
| case STLLRH: |
| case LDLARH: |
| case STLLR_w: |
| case LDLAR_w: |
| case STLLR_x: |
| case LDLAR_x: |
| scope.Record(CPUFeatures::kLORegions); |
| return; |
| default: |
| // No special CPU features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePairNonTemporal( |
| const Instruction* instr) { |
| LoadStorePairHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePairOffset(const Instruction* instr) { |
| LoadStorePairHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePairPostIndex(const Instruction* instr) { |
| LoadStorePairHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePairPreIndex(const Instruction* instr) { |
| LoadStorePairHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePostIndex(const Instruction* instr) { |
| LoadStoreHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStorePreIndex(const Instruction* instr) { |
| LoadStoreHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStoreRegisterOffset( |
| const Instruction* instr) { |
| LoadStoreHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStoreUnscaledOffset( |
| const Instruction* instr) { |
| LoadStoreHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLoadStoreUnsignedOffset( |
| const Instruction* instr) { |
| LoadStoreHelper(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLogicalImmediate(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitLogicalShifted(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitMoveWideImmediate(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEON2RegMisc(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEON2RegMiscFPMask)) { |
| case NEON_FABS: |
| case NEON_FNEG: |
| case NEON_FSQRT: |
| case NEON_FCVTL: |
| case NEON_FCVTN: |
| case NEON_FCVTXN: |
| case NEON_FRINTI: |
| case NEON_FRINTX: |
| case NEON_FRINTA: |
| case NEON_FRINTM: |
| case NEON_FRINTN: |
| case NEON_FRINTP: |
| case NEON_FRINTZ: |
| case NEON_FCVTNS: |
| case NEON_FCVTNU: |
| case NEON_FCVTPS: |
| case NEON_FCVTPU: |
| case NEON_FCVTMS: |
| case NEON_FCVTMU: |
| case NEON_FCVTZS: |
| case NEON_FCVTZU: |
| case NEON_FCVTAS: |
| case NEON_FCVTAU: |
| case NEON_SCVTF: |
| case NEON_UCVTF: |
| case NEON_FRSQRTE: |
| case NEON_FRECPE: |
| case NEON_FCMGT_zero: |
| case NEON_FCMGE_zero: |
| case NEON_FCMEQ_zero: |
| case NEON_FCMLE_zero: |
| case NEON_FCMLT_zero: |
| scope.Record(CPUFeatures::kFP); |
| return; |
| case NEON_FRINT32X: |
| case NEON_FRINT32Z: |
| case NEON_FRINT64X: |
| case NEON_FRINT64Z: |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kFrintToFixedSizedInt); |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEON2RegMiscFP16(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEONHalf. |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEON3Different(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEON3Same(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) { |
| scope.Record(CPUFeatures::kFP); |
| } |
| switch (instr->Mask(NEON3SameFHMMask)) { |
| case NEON_FMLAL: |
| case NEON_FMLAL2: |
| case NEON_FMLSL: |
| case NEON_FMLSL2: |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf, CPUFeatures::kFHM); |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEON3SameExtra(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| if ((instr->Mask(NEON3SameExtraFCMLAMask) == NEON_FCMLA) || |
| (instr->Mask(NEON3SameExtraFCADDMask) == NEON_FCADD)) { |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma); |
| if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf); |
| } else { |
| switch (instr->Mask(NEON3SameExtraMask)) { |
| case NEON_SDOT: |
| case NEON_UDOT: |
| scope.Record(CPUFeatures::kDotProduct); |
| return; |
| case NEON_SQRDMLAH: |
| case NEON_SQRDMLSH: |
| scope.Record(CPUFeatures::kRDM); |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEON3SameFP16(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON FP16 support. |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONAcrossLanes(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| if (instr->Mask(NEONAcrossLanesFP16FMask) == NEONAcrossLanesFP16Fixed) { |
| // FMAXV_H, FMINV_H, FMAXNMV_H, FMINNMV_H |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf); |
| } else if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) { |
| // FMAXV, FMINV, FMAXNMV, FMINNMV |
| scope.Record(CPUFeatures::kFP); |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONByIndexedElement(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEONByIndexedElementMask)) { |
| case NEON_SDOT_byelement: |
| case NEON_UDOT_byelement: |
| scope.Record(CPUFeatures::kDotProduct); |
| return; |
| case NEON_SQRDMLAH_byelement: |
| case NEON_SQRDMLSH_byelement: |
| scope.Record(CPUFeatures::kRDM); |
| return; |
| default: |
| // Fall through to check other instructions. |
| break; |
| } |
| switch (instr->Mask(NEONByIndexedElementFPLongMask)) { |
| case NEON_FMLAL_H_byelement: |
| case NEON_FMLAL2_H_byelement: |
| case NEON_FMLSL_H_byelement: |
| case NEON_FMLSL2_H_byelement: |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEONHalf, CPUFeatures::kFHM); |
| return; |
| default: |
| // Fall through to check other instructions. |
| break; |
| } |
| switch (instr->Mask(NEONByIndexedElementFPMask)) { |
| case NEON_FMLA_H_byelement: |
| case NEON_FMLS_H_byelement: |
| case NEON_FMUL_H_byelement: |
| case NEON_FMULX_H_byelement: |
| scope.Record(CPUFeatures::kNEONHalf); |
| VIXL_FALLTHROUGH(); |
| case NEON_FMLA_byelement: |
| case NEON_FMLS_byelement: |
| case NEON_FMUL_byelement: |
| case NEON_FMULX_byelement: |
| scope.Record(CPUFeatures::kFP); |
| return; |
| default: |
| switch (instr->Mask(NEONByIndexedElementFPComplexMask)) { |
| case NEON_FCMLA_byelement: |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kFcma); |
| if (instr->GetNEONSize() == 1) scope.Record(CPUFeatures::kNEONHalf); |
| return; |
| } |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONCopy(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONExtract(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStruct( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONLoadStoreMultiStructPostIndex( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStruct( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONLoadStoreSingleStructPostIndex( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONModifiedImmediate(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| if (instr->GetNEONCmode() == 0xf) { |
| // FMOV (vector, immediate), double-, single- or half-precision. |
| scope.Record(CPUFeatures::kFP); |
| if (instr->ExtractBit(11)) scope.Record(CPUFeatures::kNEONHalf); |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONPerm(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalar2RegMisc(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEONScalar2RegMiscFPMask)) { |
| case NEON_FRECPE_scalar: |
| case NEON_FRECPX_scalar: |
| case NEON_FRSQRTE_scalar: |
| case NEON_FCMGT_zero_scalar: |
| case NEON_FCMGE_zero_scalar: |
| case NEON_FCMEQ_zero_scalar: |
| case NEON_FCMLE_zero_scalar: |
| case NEON_FCMLT_zero_scalar: |
| case NEON_SCVTF_scalar: |
| case NEON_UCVTF_scalar: |
| case NEON_FCVTNS_scalar: |
| case NEON_FCVTNU_scalar: |
| case NEON_FCVTPS_scalar: |
| case NEON_FCVTPU_scalar: |
| case NEON_FCVTMS_scalar: |
| case NEON_FCVTMU_scalar: |
| case NEON_FCVTZS_scalar: |
| case NEON_FCVTZU_scalar: |
| case NEON_FCVTAS_scalar: |
| case NEON_FCVTAU_scalar: |
| case NEON_FCVTXN_scalar: |
| scope.Record(CPUFeatures::kFP); |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalar2RegMiscFP16(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEONHalf. |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalar3Diff(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalar3Same(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) { |
| scope.Record(CPUFeatures::kFP); |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalar3SameExtra(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON and RDM. |
| scope.Record(CPUFeatures::kNEON, CPUFeatures::kRDM); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalar3SameFP16(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEONHalf. |
| scope.Record(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kNEONHalf); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalarByIndexedElement( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEONScalarByIndexedElementMask)) { |
| case NEON_SQRDMLAH_byelement_scalar: |
| case NEON_SQRDMLSH_byelement_scalar: |
| scope.Record(CPUFeatures::kRDM); |
| return; |
| default: |
| switch (instr->Mask(NEONScalarByIndexedElementFPMask)) { |
| case NEON_FMLA_H_byelement_scalar: |
| case NEON_FMLS_H_byelement_scalar: |
| case NEON_FMUL_H_byelement_scalar: |
| case NEON_FMULX_H_byelement_scalar: |
| scope.Record(CPUFeatures::kNEONHalf); |
| VIXL_FALLTHROUGH(); |
| case NEON_FMLA_byelement_scalar: |
| case NEON_FMLS_byelement_scalar: |
| case NEON_FMUL_byelement_scalar: |
| case NEON_FMULX_byelement_scalar: |
| scope.Record(CPUFeatures::kFP); |
| return; |
| } |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalarCopy(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalarPairwise(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEONScalarPairwiseMask)) { |
| case NEON_FMAXNMP_h_scalar: |
| case NEON_FADDP_h_scalar: |
| case NEON_FMAXP_h_scalar: |
| case NEON_FMINNMP_h_scalar: |
| case NEON_FMINP_h_scalar: |
| scope.Record(CPUFeatures::kNEONHalf); |
| VIXL_FALLTHROUGH(); |
| case NEON_FADDP_scalar: |
| case NEON_FMAXP_scalar: |
| case NEON_FMAXNMP_scalar: |
| case NEON_FMINP_scalar: |
| case NEON_FMINNMP_scalar: |
| scope.Record(CPUFeatures::kFP); |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONScalarShiftImmediate( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEONScalarShiftImmediateMask)) { |
| case NEON_FCVTZS_imm_scalar: |
| case NEON_FCVTZU_imm_scalar: |
| case NEON_SCVTF_imm_scalar: |
| case NEON_UCVTF_imm_scalar: |
| scope.Record(CPUFeatures::kFP); |
| // If immh is 0b001x then the data type is FP16, and requires kNEONHalf. |
| if ((instr->GetImmNEONImmh() & 0xe) == 0x2) { |
| scope.Record(CPUFeatures::kNEONHalf); |
| } |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONShiftImmediate(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| switch (instr->Mask(NEONShiftImmediateMask)) { |
| case NEON_SCVTF_imm: |
| case NEON_UCVTF_imm: |
| case NEON_FCVTZS_imm: |
| case NEON_FCVTZU_imm: |
| scope.Record(CPUFeatures::kFP); |
| // If immh is 0b001x then the data type is FP16, and requires kNEONHalf. |
| if ((instr->GetImmNEONImmh() & 0xe) == 0x2) { |
| scope.Record(CPUFeatures::kNEONHalf); |
| } |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitNEONTable(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| // All of these instructions require NEON. |
| scope.Record(CPUFeatures::kNEON); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitPCRelAddressing(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| // Most SVE visitors require only SVE. |
| #define VIXL_SIMPLE_SVE_VISITOR_LIST(V) \ |
| V(SVE32BitGatherLoad_ScalarPlus32BitUnscaledOffsets) \ |
| V(SVE32BitGatherLoad_VectorPlusImm) \ |
| V(SVE32BitGatherLoadHalfwords_ScalarPlus32BitScaledOffsets) \ |
| V(SVE32BitGatherLoadWords_ScalarPlus32BitScaledOffsets) \ |
| V(SVE32BitGatherPrefetch_ScalarPlus32BitScaledOffsets) \ |
| V(SVE32BitGatherPrefetch_VectorPlusImm) \ |
| V(SVE32BitScatterStore_ScalarPlus32BitScaledOffsets) \ |
| V(SVE32BitScatterStore_ScalarPlus32BitUnscaledOffsets) \ |
| V(SVE32BitScatterStore_VectorPlusImm) \ |
| V(SVE64BitGatherLoad_ScalarPlus32BitUnpackedScaledOffsets) \ |
| V(SVE64BitGatherLoad_ScalarPlus64BitScaledOffsets) \ |
| V(SVE64BitGatherLoad_ScalarPlus64BitUnscaledOffsets) \ |
| V(SVE64BitGatherLoad_ScalarPlusUnpacked32BitUnscaledOffsets) \ |
| V(SVE64BitGatherLoad_VectorPlusImm) \ |
| V(SVE64BitGatherPrefetch_ScalarPlus64BitScaledOffsets) \ |
| V(SVE64BitGatherPrefetch_ScalarPlusUnpacked32BitScaledOffsets) \ |
| V(SVE64BitGatherPrefetch_VectorPlusImm) \ |
| V(SVE64BitScatterStore_ScalarPlus64BitScaledOffsets) \ |
| V(SVE64BitScatterStore_ScalarPlus64BitUnscaledOffsets) \ |
| V(SVE64BitScatterStore_ScalarPlusUnpacked32BitScaledOffsets) \ |
| V(SVE64BitScatterStore_ScalarPlusUnpacked32BitUnscaledOffsets) \ |
| V(SVE64BitScatterStore_VectorPlusImm) \ |
| V(SVEAddressGeneration) \ |
| V(SVEBitwiseLogicalUnpredicated) \ |
| V(SVEBitwiseShiftUnpredicated) \ |
| V(SVEFFRInitialise) \ |
| V(SVEFFRWriteFromPredicate) \ |
| V(SVEFPAccumulatingReduction) \ |
| V(SVEFPArithmeticUnpredicated) \ |
| V(SVEFPCompareVectors) \ |
| V(SVEFPCompareWithZero) \ |
| V(SVEFPComplexAddition) \ |
| V(SVEFPComplexMulAdd) \ |
| V(SVEFPComplexMulAddIndex) \ |
| V(SVEFPFastReduction) \ |
| V(SVEFPMulIndex) \ |
| V(SVEFPMulAdd) \ |
| V(SVEFPMulAddIndex) \ |
| V(SVEFPUnaryOpUnpredicated) \ |
| V(SVEIncDecByPredicateCount) \ |
| V(SVEIndexGeneration) \ |
| V(SVEIntArithmeticUnpredicated) \ |
| V(SVEIntCompareSignedImm) \ |
| V(SVEIntCompareUnsignedImm) \ |
| V(SVEIntCompareVectors) \ |
| V(SVEIntMulAddPredicated) \ |
| V(SVEIntMulAddUnpredicated) \ |
| V(SVEIntReduction) \ |
| V(SVEIntUnaryArithmeticPredicated) \ |
| V(SVEMovprfx) \ |
| V(SVEMulIndex) \ |
| V(SVEPermuteVectorExtract) \ |
| V(SVEPermuteVectorInterleaving) \ |
| V(SVEPredicateCount) \ |
| V(SVEPredicateLogical) \ |
| V(SVEPropagateBreak) \ |
| V(SVEStackFrameAdjustment) \ |
| V(SVEStackFrameSize) \ |
| V(SVEVectorSelect) \ |
| V(SVEBitwiseLogical_Predicated) \ |
| V(SVEBitwiseLogicalWithImm_Unpredicated) \ |
| V(SVEBitwiseShiftByImm_Predicated) \ |
| V(SVEBitwiseShiftByVector_Predicated) \ |
| V(SVEBitwiseShiftByWideElements_Predicated) \ |
| V(SVEBroadcastBitmaskImm) \ |
| V(SVEBroadcastFPImm_Unpredicated) \ |
| V(SVEBroadcastGeneralRegister) \ |
| V(SVEBroadcastIndexElement) \ |
| V(SVEBroadcastIntImm_Unpredicated) \ |
| V(SVECompressActiveElements) \ |
| V(SVEConditionallyBroadcastElementToVector) \ |
| V(SVEConditionallyExtractElementToSIMDFPScalar) \ |
| V(SVEConditionallyExtractElementToGeneralRegister) \ |
| V(SVEConditionallyTerminateScalars) \ |
| V(SVEConstructivePrefix_Unpredicated) \ |
| V(SVEContiguousFirstFaultLoad_ScalarPlusScalar) \ |
| V(SVEContiguousLoad_ScalarPlusImm) \ |
| V(SVEContiguousLoad_ScalarPlusScalar) \ |
| V(SVEContiguousNonFaultLoad_ScalarPlusImm) \ |
| V(SVEContiguousNonTemporalLoad_ScalarPlusImm) \ |
| V(SVEContiguousNonTemporalLoad_ScalarPlusScalar) \ |
| V(SVEContiguousNonTemporalStore_ScalarPlusImm) \ |
| V(SVEContiguousNonTemporalStore_ScalarPlusScalar) \ |
| V(SVEContiguousPrefetch_ScalarPlusImm) \ |
| V(SVEContiguousPrefetch_ScalarPlusScalar) \ |
| V(SVEContiguousStore_ScalarPlusImm) \ |
| V(SVEContiguousStore_ScalarPlusScalar) \ |
| V(SVECopySIMDFPScalarRegisterToVector_Predicated) \ |
| V(SVECopyFPImm_Predicated) \ |
| V(SVECopyGeneralRegisterToVector_Predicated) \ |
| V(SVECopyIntImm_Predicated) \ |
| V(SVEElementCount) \ |
| V(SVEExtractElementToSIMDFPScalarRegister) \ |
| V(SVEExtractElementToGeneralRegister) \ |
| V(SVEFPArithmetic_Predicated) \ |
| V(SVEFPArithmeticWithImm_Predicated) \ |
| V(SVEFPConvertPrecision) \ |
| V(SVEFPConvertToInt) \ |
| V(SVEFPExponentialAccelerator) \ |
| V(SVEFPRoundToIntegralValue) \ |
| V(SVEFPTrigMulAddCoefficient) \ |
| V(SVEFPTrigSelectCoefficient) \ |
| V(SVEFPUnaryOp) \ |
| V(SVEIncDecRegisterByElementCount) \ |
| V(SVEIncDecVectorByElementCount) \ |
| V(SVEInsertSIMDFPScalarRegister) \ |
| V(SVEInsertGeneralRegister) \ |
| V(SVEIntAddSubtractImm_Unpredicated) \ |
| V(SVEIntAddSubtractVectors_Predicated) \ |
| V(SVEIntCompareScalarCountAndLimit) \ |
| V(SVEIntConvertToFP) \ |
| V(SVEIntDivideVectors_Predicated) \ |
| V(SVEIntMinMaxImm_Unpredicated) \ |
| V(SVEIntMinMaxDifference_Predicated) \ |
| V(SVEIntMulImm_Unpredicated) \ |
| V(SVEIntMulVectors_Predicated) \ |
| V(SVELoadAndBroadcastElement) \ |
| V(SVELoadAndBroadcastQuadword_ScalarPlusImm) \ |
| V(SVELoadAndBroadcastQuadword_ScalarPlusScalar) \ |
| V(SVELoadMultipleStructures_ScalarPlusImm) \ |
| V(SVELoadMultipleStructures_ScalarPlusScalar) \ |
| V(SVELoadPredicateRegister) \ |
| V(SVELoadVectorRegister) \ |
| V(SVEPartitionBreakCondition) \ |
| V(SVEPermutePredicateElements) \ |
| V(SVEPredicateFirstActive) \ |
| V(SVEPredicateInitialize) \ |
| V(SVEPredicateNextActive) \ |
| V(SVEPredicateReadFromFFR_Predicated) \ |
| V(SVEPredicateReadFromFFR_Unpredicated) \ |
| V(SVEPredicateTest) \ |
| V(SVEPredicateZero) \ |
| V(SVEPropagateBreakToNextPartition) \ |
| V(SVEReversePredicateElements) \ |
| V(SVEReverseVectorElements) \ |
| V(SVEReverseWithinElements) \ |
| V(SVESaturatingIncDecRegisterByElementCount) \ |
| V(SVESaturatingIncDecVectorByElementCount) \ |
| V(SVEStoreMultipleStructures_ScalarPlusImm) \ |
| V(SVEStoreMultipleStructures_ScalarPlusScalar) \ |
| V(SVEStorePredicateRegister) \ |
| V(SVEStoreVectorRegister) \ |
| V(SVETableLookup) \ |
| V(SVEUnpackPredicateElements) \ |
| V(SVEUnpackVectorElements) \ |
| V(SVEVectorSplice_Destructive) |
| |
| #define VIXL_DEFINE_SIMPLE_SVE_VISITOR(NAME) \ |
| void CPUFeaturesAuditor::Visit##NAME(const Instruction* instr) { \ |
| RecordInstructionFeaturesScope scope(this); \ |
| scope.Record(CPUFeatures::kSVE); \ |
| USE(instr); \ |
| } |
| VIXL_SIMPLE_SVE_VISITOR_LIST(VIXL_DEFINE_SIMPLE_SVE_VISITOR) |
| #undef VIXL_DEFINE_SIMPLE_SVE_VISITOR |
| #undef VIXL_SIMPLE_SVE_VISITOR_LIST |
| |
| void CPUFeaturesAuditor::VisitSystem(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| if (instr->Mask(SystemHintFMask) == SystemHintFixed) { |
| CPUFeatures required; |
| switch (instr->GetInstructionBits()) { |
| case PACIA1716: |
| case PACIB1716: |
| case AUTIA1716: |
| case AUTIB1716: |
| case PACIAZ: |
| case PACIASP: |
| case PACIBZ: |
| case PACIBSP: |
| case AUTIAZ: |
| case AUTIASP: |
| case AUTIBZ: |
| case AUTIBSP: |
| case XPACLRI: |
| required.Combine(CPUFeatures::kPAuth); |
| break; |
| default: |
| switch (instr->GetImmHint()) { |
| case ESB: |
| required.Combine(CPUFeatures::kRAS); |
| break; |
| case BTI: |
| case BTI_j: |
| case BTI_c: |
| case BTI_jc: |
| required.Combine(CPUFeatures::kBTI); |
| break; |
| default: |
| break; |
| } |
| break; |
| } |
| |
| // These are all HINT instructions, and behave as NOPs if the corresponding |
| // features are not implemented, so we record the corresponding features |
| // only if they are available. |
| if (available_.Has(required)) scope.Record(required); |
| } else if (instr->Mask(SystemSysMask) == SYS) { |
| switch (instr->GetSysOp()) { |
| // DC instruction variants. |
| case CVAP: |
| scope.Record(CPUFeatures::kDCPoP); |
| break; |
| case CVADP: |
| scope.Record(CPUFeatures::kDCCVADP); |
| break; |
| case IVAU: |
| case CVAC: |
| case CVAU: |
| case CIVAC: |
| // No special CPU features. |
| break; |
| } |
| } else if (instr->Mask(SystemPStateFMask) == SystemPStateFixed) { |
| switch (instr->Mask(SystemPStateMask)) { |
| case CFINV: |
| scope.Record(CPUFeatures::kFlagM); |
| break; |
| case AXFLAG: |
| case XAFLAG: |
| scope.Record(CPUFeatures::kAXFlag); |
| break; |
| } |
| } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) { |
| if (instr->Mask(SystemSysRegMask) == MRS) { |
| switch (instr->GetImmSystemRegister()) { |
| case RNDR: |
| case RNDRRS: |
| scope.Record(CPUFeatures::kRNG); |
| break; |
| } |
| } |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitTestBranch(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitUnallocated(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitUnconditionalBranch(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitUnconditionalBranchToRegister( |
| const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| switch (instr->Mask(UnconditionalBranchToRegisterMask)) { |
| case BRAAZ: |
| case BRABZ: |
| case BLRAAZ: |
| case BLRABZ: |
| case RETAA: |
| case RETAB: |
| case BRAA: |
| case BRAB: |
| case BLRAA: |
| case BLRAB: |
| scope.Record(CPUFeatures::kPAuth); |
| return; |
| default: |
| // No additional features. |
| return; |
| } |
| } |
| |
| void CPUFeaturesAuditor::VisitReserved(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::VisitUnimplemented(const Instruction* instr) { |
| RecordInstructionFeaturesScope scope(this); |
| USE(instr); |
| } |
| |
| void CPUFeaturesAuditor::Visit(Metadata* metadata, const Instruction* instr) { |
| VIXL_ASSERT(metadata->count("form") > 0); |
| const std::string& form = (*metadata)["form"]; |
| if ((form_to_visitor_.count(form) > 0) && form_to_visitor_[form]) { |
| form_to_visitor_[form](this, instr); |
| } else { |
| RecordInstructionFeaturesScope scope(this); |
| std::map<const std::string, const CPUFeatures> features = { |
| {"adclb_z_zzz", CPUFeatures::kSVE2}, |
| {"adclt_z_zzz", CPUFeatures::kSVE2}, |
| {"addhnb_z_zz", CPUFeatures::kSVE2}, |
| {"addhnt_z_zz", CPUFeatures::kSVE2}, |
| {"addp_z_p_zz", CPUFeatures::kSVE2}, |
| {"bcax_z_zzz", CPUFeatures::kSVE2}, |
| {"bdep_z_zz", CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)}, |
| {"bext_z_zz", CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)}, |
| {"bgrp_z_zz", CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)}, |
| {"bsl1n_z_zzz", CPUFeatures::kSVE2}, |
| {"bsl2n_z_zzz", CPUFeatures::kSVE2}, |
| {"bsl_z_zzz", CPUFeatures::kSVE2}, |
| {"cadd_z_zz", CPUFeatures::kSVE2}, |
| {"cdot_z_zzz", CPUFeatures::kSVE2}, |
| {"cdot_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"cdot_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"cmla_z_zzz", CPUFeatures::kSVE2}, |
| {"cmla_z_zzzi_h", CPUFeatures::kSVE2}, |
| {"cmla_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"eor3_z_zzz", CPUFeatures::kSVE2}, |
| {"eorbt_z_zz", CPUFeatures::kSVE2}, |
| {"eortb_z_zz", CPUFeatures::kSVE2}, |
| {"ext_z_zi_con", CPUFeatures::kSVE2}, |
| {"faddp_z_p_zz", CPUFeatures::kSVE2}, |
| {"fcvtlt_z_p_z_h2s", CPUFeatures::kSVE2}, |
| {"fcvtlt_z_p_z_s2d", CPUFeatures::kSVE2}, |
| {"fcvtnt_z_p_z_d2s", CPUFeatures::kSVE2}, |
| {"fcvtnt_z_p_z_s2h", CPUFeatures::kSVE2}, |
| {"fcvtx_z_p_z_d2s", CPUFeatures::kSVE2}, |
| {"fcvtxnt_z_p_z_d2s", CPUFeatures::kSVE2}, |
| {"flogb_z_p_z", CPUFeatures::kSVE2}, |
| {"fmaxnmp_z_p_zz", CPUFeatures::kSVE2}, |
| {"fmaxp_z_p_zz", CPUFeatures::kSVE2}, |
| {"fminnmp_z_p_zz", CPUFeatures::kSVE2}, |
| {"fminp_z_p_zz", CPUFeatures::kSVE2}, |
| {"fmlalb_z_zzz", CPUFeatures::kSVE2}, |
| {"fmlalb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"fmlalt_z_zzz", CPUFeatures::kSVE2}, |
| {"fmlalt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"fmlslb_z_zzz", CPUFeatures::kSVE2}, |
| {"fmlslb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"fmlslt_z_zzz", CPUFeatures::kSVE2}, |
| {"fmlslt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"histcnt_z_p_zz", CPUFeatures::kSVE2}, |
| {"histseg_z_zz", CPUFeatures::kSVE2}, |
| {"ldnt1b_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1b_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1d_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1h_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1h_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1sb_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1sb_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1sh_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1sh_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1sw_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1w_z_p_ar_d_64_unscaled", |
| CPUFeatures::kSVE2}, |
| {"ldnt1w_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"match_p_p_zz", CPUFeatures::kSVE2}, |
| {"mla_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"mla_z_zzzi_h", CPUFeatures::kSVE2}, |
| {"mla_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"mls_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"mls_z_zzzi_h", CPUFeatures::kSVE2}, |
| {"mls_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"mul_z_zz", CPUFeatures::kSVE2}, |
| {"mul_z_zzi_d", CPUFeatures::kSVE2}, |
| {"mul_z_zzi_h", CPUFeatures::kSVE2}, |
| {"mul_z_zzi_s", CPUFeatures::kSVE2}, |
| {"nbsl_z_zzz", CPUFeatures::kSVE2}, |
| {"nmatch_p_p_zz", CPUFeatures::kSVE2}, |
| {"pmul_z_zz", CPUFeatures::kSVE2}, |
| {"pmullb_z_zz", CPUFeatures::kSVE2}, |
| {"pmullt_z_zz", CPUFeatures::kSVE2}, |
| {"raddhnb_z_zz", CPUFeatures::kSVE2}, |
| {"raddhnt_z_zz", CPUFeatures::kSVE2}, |
| {"rshrnb_z_zi", CPUFeatures::kSVE2}, |
| {"rshrnt_z_zi", CPUFeatures::kSVE2}, |
| {"rsubhnb_z_zz", CPUFeatures::kSVE2}, |
| {"rsubhnt_z_zz", CPUFeatures::kSVE2}, |
| {"saba_z_zzz", CPUFeatures::kSVE2}, |
| {"sabalb_z_zzz", CPUFeatures::kSVE2}, |
| {"sabalt_z_zzz", CPUFeatures::kSVE2}, |
| {"sabdlb_z_zz", CPUFeatures::kSVE2}, |
| {"sabdlt_z_zz", CPUFeatures::kSVE2}, |
| {"sadalp_z_p_z", CPUFeatures::kSVE2}, |
| {"saddlb_z_zz", CPUFeatures::kSVE2}, |
| {"saddlbt_z_zz", CPUFeatures::kSVE2}, |
| {"saddlt_z_zz", CPUFeatures::kSVE2}, |
| {"saddwb_z_zz", CPUFeatures::kSVE2}, |
| {"saddwt_z_zz", CPUFeatures::kSVE2}, |
| {"sbclb_z_zzz", CPUFeatures::kSVE2}, |
| {"sbclt_z_zzz", CPUFeatures::kSVE2}, |
| {"shadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"shrnb_z_zi", CPUFeatures::kSVE2}, |
| {"shrnt_z_zi", CPUFeatures::kSVE2}, |
| {"shsub_z_p_zz", CPUFeatures::kSVE2}, |
| {"shsubr_z_p_zz", CPUFeatures::kSVE2}, |
| {"sli_z_zzi", CPUFeatures::kSVE2}, |
| {"smaxp_z_p_zz", CPUFeatures::kSVE2}, |
| {"sminp_z_p_zz", CPUFeatures::kSVE2}, |
| {"smlalb_z_zzz", CPUFeatures::kSVE2}, |
| {"smlalb_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"smlalb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"smlalt_z_zzz", CPUFeatures::kSVE2}, |
| {"smlalt_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"smlalt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"smlslb_z_zzz", CPUFeatures::kSVE2}, |
| {"smlslb_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"smlslb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"smlslt_z_zzz", CPUFeatures::kSVE2}, |
| {"smlslt_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"smlslt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"smulh_z_zz", CPUFeatures::kSVE2}, |
| {"smullb_z_zz", CPUFeatures::kSVE2}, |
| {"smullb_z_zzi_d", CPUFeatures::kSVE2}, |
| {"smullb_z_zzi_s", CPUFeatures::kSVE2}, |
| {"smullt_z_zz", CPUFeatures::kSVE2}, |
| {"smullt_z_zzi_d", CPUFeatures::kSVE2}, |
| {"smullt_z_zzi_s", CPUFeatures::kSVE2}, |
| {"splice_z_p_zz_con", CPUFeatures::kSVE2}, |
| {"sqabs_z_p_z", CPUFeatures::kSVE2}, |
| {"sqadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqcadd_z_zz", CPUFeatures::kSVE2}, |
| {"sqdmlalb_z_zzz", CPUFeatures::kSVE2}, |
| {"sqdmlalb_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"sqdmlalb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqdmlalbt_z_zzz", CPUFeatures::kSVE2}, |
| {"sqdmlalt_z_zzz", CPUFeatures::kSVE2}, |
| {"sqdmlalt_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"sqdmlalt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqdmlslb_z_zzz", CPUFeatures::kSVE2}, |
| {"sqdmlslb_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"sqdmlslb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqdmlslbt_z_zzz", CPUFeatures::kSVE2}, |
| {"sqdmlslt_z_zzz", CPUFeatures::kSVE2}, |
| {"sqdmlslt_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"sqdmlslt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqdmulh_z_zz", CPUFeatures::kSVE2}, |
| {"sqdmulh_z_zzi_d", CPUFeatures::kSVE2}, |
| {"sqdmulh_z_zzi_h", CPUFeatures::kSVE2}, |
| {"sqdmulh_z_zzi_s", CPUFeatures::kSVE2}, |
| {"sqdmullb_z_zz", CPUFeatures::kSVE2}, |
| {"sqdmullb_z_zzi_d", CPUFeatures::kSVE2}, |
| {"sqdmullb_z_zzi_s", CPUFeatures::kSVE2}, |
| {"sqdmullt_z_zz", CPUFeatures::kSVE2}, |
| {"sqdmullt_z_zzi_d", CPUFeatures::kSVE2}, |
| {"sqdmullt_z_zzi_s", CPUFeatures::kSVE2}, |
| {"sqneg_z_p_z", CPUFeatures::kSVE2}, |
| {"sqrdcmlah_z_zzz", CPUFeatures::kSVE2}, |
| {"sqrdcmlah_z_zzzi_h", CPUFeatures::kSVE2}, |
| {"sqrdcmlah_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqrdmlah_z_zzz", CPUFeatures::kSVE2}, |
| {"sqrdmlah_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"sqrdmlah_z_zzzi_h", CPUFeatures::kSVE2}, |
| {"sqrdmlah_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqrdmlsh_z_zzz", CPUFeatures::kSVE2}, |
| {"sqrdmlsh_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"sqrdmlsh_z_zzzi_h", CPUFeatures::kSVE2}, |
| {"sqrdmlsh_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"sqrdmulh_z_zz", CPUFeatures::kSVE2}, |
| {"sqrdmulh_z_zzi_d", CPUFeatures::kSVE2}, |
| {"sqrdmulh_z_zzi_h", CPUFeatures::kSVE2}, |
| {"sqrdmulh_z_zzi_s", CPUFeatures::kSVE2}, |
| {"sqrshl_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqrshlr_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqrshrnb_z_zi", CPUFeatures::kSVE2}, |
| {"sqrshrnt_z_zi", CPUFeatures::kSVE2}, |
| {"sqrshrunb_z_zi", CPUFeatures::kSVE2}, |
| {"sqrshrunt_z_zi", CPUFeatures::kSVE2}, |
| {"sqshl_z_p_zi", CPUFeatures::kSVE2}, |
| {"sqshl_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqshlr_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqshlu_z_p_zi", CPUFeatures::kSVE2}, |
| {"sqshrnb_z_zi", CPUFeatures::kSVE2}, |
| {"sqshrnt_z_zi", CPUFeatures::kSVE2}, |
| {"sqshrunb_z_zi", CPUFeatures::kSVE2}, |
| {"sqshrunt_z_zi", CPUFeatures::kSVE2}, |
| {"sqsub_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqsubr_z_p_zz", CPUFeatures::kSVE2}, |
| {"sqxtnb_z_zz", CPUFeatures::kSVE2}, |
| {"sqxtnt_z_zz", CPUFeatures::kSVE2}, |
| {"sqxtunb_z_zz", CPUFeatures::kSVE2}, |
| {"sqxtunt_z_zz", CPUFeatures::kSVE2}, |
| {"srhadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"sri_z_zzi", CPUFeatures::kSVE2}, |
| {"srshl_z_p_zz", CPUFeatures::kSVE2}, |
| {"srshlr_z_p_zz", CPUFeatures::kSVE2}, |
| {"srshr_z_p_zi", CPUFeatures::kSVE2}, |
| {"srsra_z_zi", CPUFeatures::kSVE2}, |
| {"sshllb_z_zi", CPUFeatures::kSVE2}, |
| {"sshllt_z_zi", CPUFeatures::kSVE2}, |
| {"ssra_z_zi", CPUFeatures::kSVE2}, |
| {"ssublb_z_zz", CPUFeatures::kSVE2}, |
| {"ssublbt_z_zz", CPUFeatures::kSVE2}, |
| {"ssublt_z_zz", CPUFeatures::kSVE2}, |
| {"ssubltb_z_zz", CPUFeatures::kSVE2}, |
| {"ssubwb_z_zz", CPUFeatures::kSVE2}, |
| {"ssubwt_z_zz", CPUFeatures::kSVE2}, |
| {"stnt1b_z_p_ar_d_64_unscaled", CPUFeatures::kSVE2}, |
| {"stnt1b_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"stnt1d_z_p_ar_d_64_unscaled", CPUFeatures::kSVE2}, |
| {"stnt1h_z_p_ar_d_64_unscaled", CPUFeatures::kSVE2}, |
| {"stnt1h_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"stnt1w_z_p_ar_d_64_unscaled", CPUFeatures::kSVE2}, |
| {"stnt1w_z_p_ar_s_x32_unscaled", |
| CPUFeatures::kSVE2}, |
| {"subhnb_z_zz", CPUFeatures::kSVE2}, |
| {"subhnt_z_zz", CPUFeatures::kSVE2}, |
| {"suqadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"tbl_z_zz_2", CPUFeatures::kSVE2}, |
| {"tbx_z_zz", CPUFeatures::kSVE2}, |
| {"uaba_z_zzz", CPUFeatures::kSVE2}, |
| {"uabalb_z_zzz", CPUFeatures::kSVE2}, |
| {"uabalt_z_zzz", CPUFeatures::kSVE2}, |
| {"uabdlb_z_zz", CPUFeatures::kSVE2}, |
| {"uabdlt_z_zz", CPUFeatures::kSVE2}, |
| {"uadalp_z_p_z", CPUFeatures::kSVE2}, |
| {"uaddlb_z_zz", CPUFeatures::kSVE2}, |
| {"uaddlt_z_zz", CPUFeatures::kSVE2}, |
| {"uaddwb_z_zz", CPUFeatures::kSVE2}, |
| {"uaddwt_z_zz", CPUFeatures::kSVE2}, |
| {"uhadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"uhsub_z_p_zz", CPUFeatures::kSVE2}, |
| {"uhsubr_z_p_zz", CPUFeatures::kSVE2}, |
| {"umaxp_z_p_zz", CPUFeatures::kSVE2}, |
| {"uminp_z_p_zz", CPUFeatures::kSVE2}, |
| {"umlalb_z_zzz", CPUFeatures::kSVE2}, |
| {"umlalb_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"umlalb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"umlalt_z_zzz", CPUFeatures::kSVE2}, |
| {"umlalt_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"umlalt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"umlslb_z_zzz", CPUFeatures::kSVE2}, |
| {"umlslb_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"umlslb_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"umlslt_z_zzz", CPUFeatures::kSVE2}, |
| {"umlslt_z_zzzi_d", CPUFeatures::kSVE2}, |
| {"umlslt_z_zzzi_s", CPUFeatures::kSVE2}, |
| {"umulh_z_zz", CPUFeatures::kSVE2}, |
| {"umullb_z_zz", CPUFeatures::kSVE2}, |
| {"umullb_z_zzi_d", CPUFeatures::kSVE2}, |
| {"umullb_z_zzi_s", CPUFeatures::kSVE2}, |
| {"umullt_z_zz", CPUFeatures::kSVE2}, |
| {"umullt_z_zzi_d", CPUFeatures::kSVE2}, |
| {"umullt_z_zzi_s", CPUFeatures::kSVE2}, |
| {"uqadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqrshl_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqrshlr_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqrshrnb_z_zi", CPUFeatures::kSVE2}, |
| {"uqrshrnt_z_zi", CPUFeatures::kSVE2}, |
| {"uqshl_z_p_zi", CPUFeatures::kSVE2}, |
| {"uqshl_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqshlr_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqshrnb_z_zi", CPUFeatures::kSVE2}, |
| {"uqshrnt_z_zi", CPUFeatures::kSVE2}, |
| {"uqsub_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqsubr_z_p_zz", CPUFeatures::kSVE2}, |
| {"uqxtnb_z_zz", CPUFeatures::kSVE2}, |
| {"uqxtnt_z_zz", CPUFeatures::kSVE2}, |
| {"urecpe_z_p_z", CPUFeatures::kSVE2}, |
| {"urhadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"urshl_z_p_zz", CPUFeatures::kSVE2}, |
| {"urshlr_z_p_zz", CPUFeatures::kSVE2}, |
| {"urshr_z_p_zi", CPUFeatures::kSVE2}, |
| {"ursqrte_z_p_z", CPUFeatures::kSVE2}, |
| {"ursra_z_zi", CPUFeatures::kSVE2}, |
| {"ushllb_z_zi", CPUFeatures::kSVE2}, |
| {"ushllt_z_zi", CPUFeatures::kSVE2}, |
| {"usqadd_z_p_zz", CPUFeatures::kSVE2}, |
| {"usra_z_zi", CPUFeatures::kSVE2}, |
| {"usublb_z_zz", CPUFeatures::kSVE2}, |
| {"usublt_z_zz", CPUFeatures::kSVE2}, |
| {"usubwb_z_zz", CPUFeatures::kSVE2}, |
| {"usubwt_z_zz", CPUFeatures::kSVE2}, |
| {"whilege_p_p_rr", CPUFeatures::kSVE2}, |
| {"whilegt_p_p_rr", CPUFeatures::kSVE2}, |
| {"whilehi_p_p_rr", CPUFeatures::kSVE2}, |
| {"whilehs_p_p_rr", CPUFeatures::kSVE2}, |
| {"whilerw_p_rr", CPUFeatures::kSVE2}, |
| {"whilewr_p_rr", CPUFeatures::kSVE2}, |
| {"xar_z_zzi", CPUFeatures::kSVE2}, |
| }; |
| |
| if (features.count(form) > 0) { |
| scope.Record(features[form]); |
| } |
| } |
| } |
| |
| } // namespace aarch64 |
| } // namespace vixl |