1841 lines
67 KiB
C++
1841 lines
67 KiB
C++
// 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 {
|
|
|
|
|
|
const CPUFeaturesAuditor::FormToVisitorFnMap*
|
|
CPUFeaturesAuditor::GetFormToVisitorFnMap() {
|
|
static const FormToVisitorFnMap form_to_visitor = {
|
|
DEFAULT_FORM_TO_VISITOR_MAP(CPUFeaturesAuditor),
|
|
SIM_AUD_VISITOR_MAP(CPUFeaturesAuditor),
|
|
{"fcmla_asimdelem_c_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fcmla_asimdelem_c_s"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmlal2_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmlal_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmla_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmla_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmlsl2_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmlsl_asimdelem_lh"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmls_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmls_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmulx_asimdelem_rh_h"_h,
|
|
&CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmulx_asimdelem_r_sd"_h,
|
|
&CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmul_asimdelem_rh_h"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"fmul_asimdelem_r_sd"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"sdot_asimdelem_d"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"smlal_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"smlsl_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"smull_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"sqdmlal_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"sqdmlsl_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"sqdmull_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"udot_asimdelem_d"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"umlal_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"umlsl_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
{"umull_asimdelem_l"_h, &CPUFeaturesAuditor::VisitNEONByIndexedElement},
|
|
};
|
|
return &form_to_visitor;
|
|
}
|
|
|
|
// 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);
|
|
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::kFP);
|
|
scope.Record(CPUFeatures::kFPHalf);
|
|
return;
|
|
case FMOV_dx:
|
|
scope.RecordOneOrBothOf(CPUFeatures::kFP, CPUFeatures::kNEON);
|
|
return;
|
|
case FMOV_d1_x:
|
|
case FMOV_x_d1:
|
|
scope.Record(CPUFeatures::kFP);
|
|
scope.Record(CPUFeatures::kNEON);
|
|
return;
|
|
case FJCVTZS:
|
|
scope.Record(CPUFeatures::kFP);
|
|
scope.Record(CPUFeatures::kJSCVT);
|
|
return;
|
|
default:
|
|
scope.Record(CPUFeatures::kFP);
|
|
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(SVELoadAndBroadcastQOWord_ScalarPlusImm) \
|
|
V(SVELoadAndBroadcastQOWord_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)
|
|
|
|
#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 CGVAC:
|
|
case CGDVAC:
|
|
case CGVAP:
|
|
case CGDVAP:
|
|
case CIGVAC:
|
|
case CIGDVAC:
|
|
case GVA:
|
|
case GZVA:
|
|
scope.Record(CPUFeatures::kMTE);
|
|
break;
|
|
case CVAP:
|
|
scope.Record(CPUFeatures::kDCPoP);
|
|
break;
|
|
case CVADP:
|
|
scope.Record(CPUFeatures::kDCCVADP);
|
|
break;
|
|
case IVAU:
|
|
case CVAC:
|
|
case CVAU:
|
|
case CIVAC:
|
|
case ZVA:
|
|
// 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"];
|
|
uint32_t form_hash = Hash(form.c_str());
|
|
const FormToVisitorFnMap* fv = CPUFeaturesAuditor::GetFormToVisitorFnMap();
|
|
FormToVisitorFnMap::const_iterator it = fv->find(form_hash);
|
|
if (it == fv->end()) {
|
|
RecordInstructionFeaturesScope scope(this);
|
|
std::map<uint32_t, const CPUFeatures> features = {
|
|
{"adclb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"adclt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"addhnb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"addhnt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"addp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"bcax_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"bdep_z_zz"_h,
|
|
CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)},
|
|
{"bext_z_zz"_h,
|
|
CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)},
|
|
{"bgrp_z_zz"_h,
|
|
CPUFeatures(CPUFeatures::kSVE2, CPUFeatures::kSVEBitPerm)},
|
|
{"bsl1n_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"bsl2n_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"bsl_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"cadd_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"cdot_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"cdot_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"cdot_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"cmla_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"cmla_z_zzzi_h"_h, CPUFeatures::kSVE2},
|
|
{"cmla_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"eor3_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"eorbt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"eortb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ext_z_zi_con"_h, CPUFeatures::kSVE2},
|
|
{"faddp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"fcvtlt_z_p_z_h2s"_h, CPUFeatures::kSVE2},
|
|
{"fcvtlt_z_p_z_s2d"_h, CPUFeatures::kSVE2},
|
|
{"fcvtnt_z_p_z_d2s"_h, CPUFeatures::kSVE2},
|
|
{"fcvtnt_z_p_z_s2h"_h, CPUFeatures::kSVE2},
|
|
{"fcvtx_z_p_z_d2s"_h, CPUFeatures::kSVE2},
|
|
{"fcvtxnt_z_p_z_d2s"_h, CPUFeatures::kSVE2},
|
|
{"flogb_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"fmaxnmp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"fmaxp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"fminnmp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"fminp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"fmlalb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"fmlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"fmlalt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"fmlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"fmlslb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"fmlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"fmlslt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"fmlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"histcnt_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"histseg_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1b_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1b_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1d_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1h_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1h_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1sb_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1sb_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1sh_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1sh_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1sw_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1w_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"ldnt1w_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"match_p_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"mla_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"mla_z_zzzi_h"_h, CPUFeatures::kSVE2},
|
|
{"mla_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"mls_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"mls_z_zzzi_h"_h, CPUFeatures::kSVE2},
|
|
{"mls_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"mul_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"mul_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"mul_z_zzi_h"_h, CPUFeatures::kSVE2},
|
|
{"mul_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"nbsl_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"nmatch_p_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"pmul_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"pmullb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"pmullt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"raddhnb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"raddhnt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"rshrnb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"rshrnt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"rsubhnb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"rsubhnt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"saba_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sabalb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sabalt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sabdlb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sabdlt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sadalp_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"saddlb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"saddlbt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"saddlt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"saddwb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"saddwt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sbclb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sbclt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"shadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"shrnb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"shrnt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"shsub_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"shsubr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sli_z_zzi"_h, CPUFeatures::kSVE2},
|
|
{"smaxp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sminp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"smlalb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"smlalb_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"smlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"smlalt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"smlalt_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"smlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"smlslb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"smlslb_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"smlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"smlslt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"smlslt_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"smlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"smulh_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"smullb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"smullb_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"smullb_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"smullt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"smullt_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"smullt_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"splice_z_p_zz_con"_h, CPUFeatures::kSVE2},
|
|
{"sqabs_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"sqadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqcadd_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalb_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalbt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalt_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslb_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslbt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslt_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqdmulh_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmulh_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmulh_z_zzi_h"_h, CPUFeatures::kSVE2},
|
|
{"sqdmulh_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqdmullb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmullb_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmullb_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqdmullt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqdmullt_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqdmullt_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqneg_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"sqrdcmlah_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqrdcmlah_z_zzzi_h"_h, CPUFeatures::kSVE2},
|
|
{"sqrdcmlah_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlah_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlah_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlah_z_zzzi_h"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlah_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlsh_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlsh_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlsh_z_zzzi_h"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmlsh_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmulh_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmulh_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmulh_z_zzi_h"_h, CPUFeatures::kSVE2},
|
|
{"sqrdmulh_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"sqrshl_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqrshlr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqrshrnb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqrshrnt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqrshrunb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqrshrunt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqshl_z_p_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqshl_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqshlr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqshlu_z_p_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqshrnb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqshrnt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqshrunb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqshrunt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sqsub_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqsubr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqxtnb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqxtnt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqxtunb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"sqxtunt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"srhadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"sri_z_zzi"_h, CPUFeatures::kSVE2},
|
|
{"srshl_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"srshlr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"srshr_z_p_zi"_h, CPUFeatures::kSVE2},
|
|
{"srsra_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sshllb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"sshllt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"ssra_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"ssublb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ssublbt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ssublt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ssubltb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ssubwb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"ssubwt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"stnt1b_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"stnt1b_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"stnt1d_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"stnt1h_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"stnt1h_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"stnt1w_z_p_ar_d_64_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"stnt1w_z_p_ar_s_x32_unscaled"_h, CPUFeatures::kSVE2},
|
|
{"subhnb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"subhnt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"suqadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"tbl_z_zz_2"_h, CPUFeatures::kSVE2},
|
|
{"tbx_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uaba_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"uabalb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"uabalt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"uabdlb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uabdlt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uadalp_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"uaddlb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uaddlt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uaddwb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uaddwt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uhadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uhsub_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uhsubr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"umaxp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uminp_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"umlalb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"umlalb_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"umlalb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"umlalt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"umlalt_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"umlalt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"umlslb_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"umlslb_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"umlslb_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"umlslt_z_zzz"_h, CPUFeatures::kSVE2},
|
|
{"umlslt_z_zzzi_d"_h, CPUFeatures::kSVE2},
|
|
{"umlslt_z_zzzi_s"_h, CPUFeatures::kSVE2},
|
|
{"umulh_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"umullb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"umullb_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"umullb_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"umullt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"umullt_z_zzi_d"_h, CPUFeatures::kSVE2},
|
|
{"umullt_z_zzi_s"_h, CPUFeatures::kSVE2},
|
|
{"uqadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqrshl_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqrshlr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqrshrnb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"uqrshrnt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"uqshl_z_p_zi"_h, CPUFeatures::kSVE2},
|
|
{"uqshl_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqshlr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqshrnb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"uqshrnt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"uqsub_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqsubr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqxtnb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"uqxtnt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"urecpe_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"urhadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"urshl_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"urshlr_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"urshr_z_p_zi"_h, CPUFeatures::kSVE2},
|
|
{"ursqrte_z_p_z"_h, CPUFeatures::kSVE2},
|
|
{"ursra_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"ushllb_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"ushllt_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"usqadd_z_p_zz"_h, CPUFeatures::kSVE2},
|
|
{"usra_z_zi"_h, CPUFeatures::kSVE2},
|
|
{"usublb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"usublt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"usubwb_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"usubwt_z_zz"_h, CPUFeatures::kSVE2},
|
|
{"whilege_p_p_rr"_h, CPUFeatures::kSVE2},
|
|
{"whilegt_p_p_rr"_h, CPUFeatures::kSVE2},
|
|
{"whilehi_p_p_rr"_h, CPUFeatures::kSVE2},
|
|
{"whilehs_p_p_rr"_h, CPUFeatures::kSVE2},
|
|
{"whilerw_p_rr"_h, CPUFeatures::kSVE2},
|
|
{"whilewr_p_rr"_h, CPUFeatures::kSVE2},
|
|
{"xar_z_zzi"_h, CPUFeatures::kSVE2},
|
|
{"smmla_z_zzz"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
|
|
{"ummla_z_zzz"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
|
|
{"usmmla_z_zzz"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
|
|
{"fmmla_z_zzz_s"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF32MM)},
|
|
{"fmmla_z_zzz_d"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"smmla_asimdsame2_g"_h,
|
|
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
|
|
{"ummla_asimdsame2_g"_h,
|
|
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
|
|
{"usmmla_asimdsame2_g"_h,
|
|
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
|
|
{"ld1row_z_p_bi_u32"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1row_z_p_br_contiguous"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1rod_z_p_bi_u64"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1rod_z_p_br_contiguous"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1rob_z_p_bi_u8"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1rob_z_p_br_contiguous"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1roh_z_p_bi_u16"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"ld1roh_z_p_br_contiguous"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEF64MM)},
|
|
{"usdot_asimdsame2_d"_h,
|
|
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
|
|
{"sudot_asimdelem_d"_h,
|
|
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
|
|
{"usdot_asimdelem_d"_h,
|
|
CPUFeatures(CPUFeatures::kNEON, CPUFeatures::kI8MM)},
|
|
{"usdot_z_zzz_s"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
|
|
{"usdot_z_zzzi_s"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
|
|
{"sudot_z_zzzi_s"_h,
|
|
CPUFeatures(CPUFeatures::kSVE, CPUFeatures::kSVEI8MM)},
|
|
{"addg_64_addsub_immtags"_h, CPUFeatures::kMTE},
|
|
{"gmi_64g_dp_2src"_h, CPUFeatures::kMTE},
|
|
{"irg_64i_dp_2src"_h, CPUFeatures::kMTE},
|
|
{"ldg_64loffset_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"st2g_64soffset_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"st2g_64spost_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"st2g_64spre_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stgp_64_ldstpair_off"_h, CPUFeatures::kMTE},
|
|
{"stgp_64_ldstpair_post"_h, CPUFeatures::kMTE},
|
|
{"stgp_64_ldstpair_pre"_h, CPUFeatures::kMTE},
|
|
{"stg_64soffset_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stg_64spost_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stg_64spre_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stz2g_64soffset_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stz2g_64spost_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stz2g_64spre_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stzg_64soffset_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stzg_64spost_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"stzg_64spre_ldsttags"_h, CPUFeatures::kMTE},
|
|
{"subg_64_addsub_immtags"_h, CPUFeatures::kMTE},
|
|
{"subps_64s_dp_2src"_h, CPUFeatures::kMTE},
|
|
{"subp_64s_dp_2src"_h, CPUFeatures::kMTE},
|
|
{"cpyen_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyern_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyewn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpye_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfen_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfern_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfewn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfe_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfmn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfmrn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfmwn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfm_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfpn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfprn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfpwn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyfp_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpymn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpymrn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpymwn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpym_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpypn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyprn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpypwn_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"cpyp_cpy_memcms"_h, CPUFeatures::kMOPS},
|
|
{"seten_set_memcms"_h, CPUFeatures::kMOPS},
|
|
{"sete_set_memcms"_h, CPUFeatures::kMOPS},
|
|
{"setgen_set_memcms"_h,
|
|
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
|
|
{"setge_set_memcms"_h,
|
|
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
|
|
{"setgmn_set_memcms"_h,
|
|
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
|
|
{"setgm_set_memcms"_h,
|
|
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
|
|
{"setgpn_set_memcms"_h,
|
|
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
|
|
{"setgp_set_memcms"_h,
|
|
CPUFeatures(CPUFeatures::kMOPS, CPUFeatures::kMTE)},
|
|
{"setmn_set_memcms"_h, CPUFeatures::kMOPS},
|
|
{"setm_set_memcms"_h, CPUFeatures::kMOPS},
|
|
{"setpn_set_memcms"_h, CPUFeatures::kMOPS},
|
|
{"setp_set_memcms"_h, CPUFeatures::kMOPS},
|
|
{"abs_32_dp_1src"_h, CPUFeatures::kCSSC},
|
|
{"abs_64_dp_1src"_h, CPUFeatures::kCSSC},
|
|
{"cnt_32_dp_1src"_h, CPUFeatures::kCSSC},
|
|
{"cnt_64_dp_1src"_h, CPUFeatures::kCSSC},
|
|
{"ctz_32_dp_1src"_h, CPUFeatures::kCSSC},
|
|
{"ctz_64_dp_1src"_h, CPUFeatures::kCSSC},
|
|
{"smax_32_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"smax_64_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"smin_32_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"smin_64_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"umax_32_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"umax_64_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"umin_32_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"umin_64_dp_2src"_h, CPUFeatures::kCSSC},
|
|
{"smax_32_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"smax_64_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"smin_32_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"smin_64_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"umax_32u_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"umax_64u_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"umin_32u_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
{"umin_64u_minmax_imm"_h, CPUFeatures::kCSSC},
|
|
};
|
|
|
|
if (features.count(form_hash) > 0) {
|
|
scope.Record(features[form_hash]);
|
|
}
|
|
} else {
|
|
(it->second)(this, instr);
|
|
}
|
|
}
|
|
|
|
} // namespace aarch64
|
|
} // namespace vixl
|