1*f5c631daSSadaf Ebrahimi // Copyright 2018, VIXL authors 2*f5c631daSSadaf Ebrahimi // All rights reserved. 3*f5c631daSSadaf Ebrahimi // 4*f5c631daSSadaf Ebrahimi // Redistribution and use in source and binary forms, with or without 5*f5c631daSSadaf Ebrahimi // modification, are permitted provided that the following conditions are met: 6*f5c631daSSadaf Ebrahimi // 7*f5c631daSSadaf Ebrahimi // * Redistributions of source code must retain the above copyright notice, 8*f5c631daSSadaf Ebrahimi // this list of conditions and the following disclaimer. 9*f5c631daSSadaf Ebrahimi // * Redistributions in binary form must reproduce the above copyright notice, 10*f5c631daSSadaf Ebrahimi // this list of conditions and the following disclaimer in the documentation 11*f5c631daSSadaf Ebrahimi // and/or other materials provided with the distribution. 12*f5c631daSSadaf Ebrahimi // * Neither the name of ARM Limited nor the names of its contributors may be 13*f5c631daSSadaf Ebrahimi // used to endorse or promote products derived from this software without 14*f5c631daSSadaf Ebrahimi // specific prior written permission. 15*f5c631daSSadaf Ebrahimi // 16*f5c631daSSadaf Ebrahimi // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17*f5c631daSSadaf Ebrahimi // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18*f5c631daSSadaf Ebrahimi // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19*f5c631daSSadaf Ebrahimi // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20*f5c631daSSadaf Ebrahimi // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*f5c631daSSadaf Ebrahimi // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22*f5c631daSSadaf Ebrahimi // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23*f5c631daSSadaf Ebrahimi // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24*f5c631daSSadaf Ebrahimi // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25*f5c631daSSadaf Ebrahimi // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26*f5c631daSSadaf Ebrahimi 27*f5c631daSSadaf Ebrahimi #ifndef VIXL_CPU_FEATURES_H 28*f5c631daSSadaf Ebrahimi #define VIXL_CPU_FEATURES_H 29*f5c631daSSadaf Ebrahimi 30*f5c631daSSadaf Ebrahimi #include <bitset> 31*f5c631daSSadaf Ebrahimi #include <ostream> 32*f5c631daSSadaf Ebrahimi 33*f5c631daSSadaf Ebrahimi #include "globals-vixl.h" 34*f5c631daSSadaf Ebrahimi 35*f5c631daSSadaf Ebrahimi namespace vixl { 36*f5c631daSSadaf Ebrahimi 37*f5c631daSSadaf Ebrahimi 38*f5c631daSSadaf Ebrahimi // VIXL aims to handle and detect all architectural features that are likely to 39*f5c631daSSadaf Ebrahimi // influence code-generation decisions at EL0 (user-space). 40*f5c631daSSadaf Ebrahimi // 41*f5c631daSSadaf Ebrahimi // - There may be multiple VIXL feature flags for a given architectural 42*f5c631daSSadaf Ebrahimi // extension. This occurs where the extension allow components to be 43*f5c631daSSadaf Ebrahimi // implemented independently, or where kernel support is needed, and is likely 44*f5c631daSSadaf Ebrahimi // to be fragmented. 45*f5c631daSSadaf Ebrahimi // 46*f5c631daSSadaf Ebrahimi // For example, Pointer Authentication (kPAuth*) has a separate feature flag 47*f5c631daSSadaf Ebrahimi // for access to PACGA, and to indicate that the QARMA algorithm is 48*f5c631daSSadaf Ebrahimi // implemented. 49*f5c631daSSadaf Ebrahimi // 50*f5c631daSSadaf Ebrahimi // - Conversely, some extensions have configuration options that do not affect 51*f5c631daSSadaf Ebrahimi // EL0, so these are presented as a single VIXL feature. 52*f5c631daSSadaf Ebrahimi // 53*f5c631daSSadaf Ebrahimi // For example, the RAS extension (kRAS) has several variants, but the only 54*f5c631daSSadaf Ebrahimi // feature relevant to VIXL is the addition of the ESB instruction so we only 55*f5c631daSSadaf Ebrahimi // need a single flag. 56*f5c631daSSadaf Ebrahimi // 57*f5c631daSSadaf Ebrahimi // - VIXL offers separate flags for separate features even if they're 58*f5c631daSSadaf Ebrahimi // architecturally linked. 59*f5c631daSSadaf Ebrahimi // 60*f5c631daSSadaf Ebrahimi // For example, the architecture requires kFPHalf and kNEONHalf to be equal, 61*f5c631daSSadaf Ebrahimi // but they have separate hardware ID register fields so VIXL presents them as 62*f5c631daSSadaf Ebrahimi // separate features. 63*f5c631daSSadaf Ebrahimi // 64*f5c631daSSadaf Ebrahimi // - VIXL can detect every feature for which it can generate code. 65*f5c631daSSadaf Ebrahimi // 66*f5c631daSSadaf Ebrahimi // - VIXL can detect some features for which it cannot generate code. 67*f5c631daSSadaf Ebrahimi // 68*f5c631daSSadaf Ebrahimi // The CPUFeatures::Feature enum — derived from the macro list below — is 69*f5c631daSSadaf Ebrahimi // frequently extended. New features may be added to the list at any point, and 70*f5c631daSSadaf Ebrahimi // no assumptions should be made about the numerical values assigned to each 71*f5c631daSSadaf Ebrahimi // enum constant. The symbolic names can be considered to be stable. 72*f5c631daSSadaf Ebrahimi // 73*f5c631daSSadaf Ebrahimi // The debug descriptions are used only for debug output. The 'cpuinfo' strings 74*f5c631daSSadaf Ebrahimi // are informative; VIXL does not use /proc/cpuinfo for feature detection. 75*f5c631daSSadaf Ebrahimi 76*f5c631daSSadaf Ebrahimi // clang-format off 77*f5c631daSSadaf Ebrahimi #define VIXL_CPU_FEATURE_LIST(V) \ 78*f5c631daSSadaf Ebrahimi /* If set, the OS traps and emulates MRS accesses to relevant (EL1) ID_* */ \ 79*f5c631daSSadaf Ebrahimi /* registers, so that the detailed feature registers can be read */ \ 80*f5c631daSSadaf Ebrahimi /* directly. */ \ 81*f5c631daSSadaf Ebrahimi \ 82*f5c631daSSadaf Ebrahimi /* Constant name Debug description Linux 'cpuinfo' string. */ \ 83*f5c631daSSadaf Ebrahimi V(kIDRegisterEmulation, "ID register emulation", "cpuid") \ 84*f5c631daSSadaf Ebrahimi \ 85*f5c631daSSadaf Ebrahimi V(kFP, "FP", "fp") \ 86*f5c631daSSadaf Ebrahimi V(kNEON, "NEON", "asimd") \ 87*f5c631daSSadaf Ebrahimi V(kCRC32, "CRC32", "crc32") \ 88*f5c631daSSadaf Ebrahimi V(kDGH, "DGH", "dgh") \ 89*f5c631daSSadaf Ebrahimi /* Speculation control features. */ \ 90*f5c631daSSadaf Ebrahimi V(kCSV2, "CSV2", NULL) \ 91*f5c631daSSadaf Ebrahimi V(kSCXTNUM, "SCXTNUM", NULL) \ 92*f5c631daSSadaf Ebrahimi V(kCSV3, "CSV3", NULL) \ 93*f5c631daSSadaf Ebrahimi V(kSB, "SB", "sb") \ 94*f5c631daSSadaf Ebrahimi V(kSPECRES, "SPECRES", NULL) \ 95*f5c631daSSadaf Ebrahimi V(kSSBS, "SSBS", NULL) \ 96*f5c631daSSadaf Ebrahimi V(kSSBSControl, "SSBS (PSTATE control)", "ssbs") \ 97*f5c631daSSadaf Ebrahimi /* Cryptographic support instructions. */ \ 98*f5c631daSSadaf Ebrahimi V(kAES, "AES", "aes") \ 99*f5c631daSSadaf Ebrahimi V(kSHA1, "SHA1", "sha1") \ 100*f5c631daSSadaf Ebrahimi V(kSHA2, "SHA2", "sha2") \ 101*f5c631daSSadaf Ebrahimi /* A form of PMULL{2} with a 128-bit (1Q) result. */ \ 102*f5c631daSSadaf Ebrahimi V(kPmull1Q, "Pmull1Q", "pmull") \ 103*f5c631daSSadaf Ebrahimi /* Atomic operations on memory: CAS, LDADD, STADD, SWP, etc. */ \ 104*f5c631daSSadaf Ebrahimi V(kAtomics, "Atomics", "atomics") \ 105*f5c631daSSadaf Ebrahimi /* Limited ordering regions: LDLAR, STLLR and their variants. */ \ 106*f5c631daSSadaf Ebrahimi V(kLORegions, "LORegions", NULL) \ 107*f5c631daSSadaf Ebrahimi /* Rounding doubling multiply add/subtract: SQRDMLAH and SQRDMLSH. */ \ 108*f5c631daSSadaf Ebrahimi V(kRDM, "RDM", "asimdrdm") \ 109*f5c631daSSadaf Ebrahimi /* Scalable Vector Extension. */ \ 110*f5c631daSSadaf Ebrahimi V(kSVE, "SVE", "sve") \ 111*f5c631daSSadaf Ebrahimi V(kSVEF64MM, "SVE F64MM", "svef64mm") \ 112*f5c631daSSadaf Ebrahimi V(kSVEF32MM, "SVE F32MM", "svef32mm") \ 113*f5c631daSSadaf Ebrahimi V(kSVEI8MM, "SVE I8MM", "svei8imm") \ 114*f5c631daSSadaf Ebrahimi V(kSVEBF16, "SVE BFloat16", "svebf16") \ 115*f5c631daSSadaf Ebrahimi /* SDOT and UDOT support (in NEON). */ \ 116*f5c631daSSadaf Ebrahimi V(kDotProduct, "DotProduct", "asimddp") \ 117*f5c631daSSadaf Ebrahimi /* Int8 matrix multiplication (in NEON). */ \ 118*f5c631daSSadaf Ebrahimi V(kI8MM, "NEON I8MM", "i8mm") \ 119*f5c631daSSadaf Ebrahimi /* Half-precision (FP16) support for FP and NEON, respectively. */ \ 120*f5c631daSSadaf Ebrahimi V(kFPHalf, "FPHalf", "fphp") \ 121*f5c631daSSadaf Ebrahimi V(kNEONHalf, "NEONHalf", "asimdhp") \ 122*f5c631daSSadaf Ebrahimi /* BFloat16 support (in both FP and NEON.) */ \ 123*f5c631daSSadaf Ebrahimi V(kBF16, "FP/NEON BFloat 16", "bf16") \ 124*f5c631daSSadaf Ebrahimi /* The RAS extension, including the ESB instruction. */ \ 125*f5c631daSSadaf Ebrahimi V(kRAS, "RAS", NULL) \ 126*f5c631daSSadaf Ebrahimi /* Data cache clean to the point of persistence: DC CVAP. */ \ 127*f5c631daSSadaf Ebrahimi V(kDCPoP, "DCPoP", "dcpop") \ 128*f5c631daSSadaf Ebrahimi /* Data cache clean to the point of deep persistence: DC CVADP. */ \ 129*f5c631daSSadaf Ebrahimi V(kDCCVADP, "DCCVADP", "dcpodp") \ 130*f5c631daSSadaf Ebrahimi /* Cryptographic support instructions. */ \ 131*f5c631daSSadaf Ebrahimi V(kSHA3, "SHA3", "sha3") \ 132*f5c631daSSadaf Ebrahimi V(kSHA512, "SHA512", "sha512") \ 133*f5c631daSSadaf Ebrahimi V(kSM3, "SM3", "sm3") \ 134*f5c631daSSadaf Ebrahimi V(kSM4, "SM4", "sm4") \ 135*f5c631daSSadaf Ebrahimi /* Pointer authentication for addresses. */ \ 136*f5c631daSSadaf Ebrahimi V(kPAuth, "PAuth", "paca") \ 137*f5c631daSSadaf Ebrahimi /* Pointer authentication for addresses uses QARMA. */ \ 138*f5c631daSSadaf Ebrahimi V(kPAuthQARMA, "PAuthQARMA", NULL) \ 139*f5c631daSSadaf Ebrahimi /* Generic authentication (using the PACGA instruction). */ \ 140*f5c631daSSadaf Ebrahimi V(kPAuthGeneric, "PAuthGeneric", "pacg") \ 141*f5c631daSSadaf Ebrahimi /* Generic authentication uses QARMA. */ \ 142*f5c631daSSadaf Ebrahimi V(kPAuthGenericQARMA, "PAuthGenericQARMA", NULL) \ 143*f5c631daSSadaf Ebrahimi /* JavaScript-style FP -> integer conversion instruction: FJCVTZS. */ \ 144*f5c631daSSadaf Ebrahimi V(kJSCVT, "JSCVT", "jscvt") \ 145*f5c631daSSadaf Ebrahimi /* Complex number support for NEON: FCMLA and FCADD. */ \ 146*f5c631daSSadaf Ebrahimi V(kFcma, "Fcma", "fcma") \ 147*f5c631daSSadaf Ebrahimi /* RCpc-based model (for weaker release consistency): LDAPR and variants. */ \ 148*f5c631daSSadaf Ebrahimi V(kRCpc, "RCpc", "lrcpc") \ 149*f5c631daSSadaf Ebrahimi V(kRCpcImm, "RCpc (imm)", "ilrcpc") \ 150*f5c631daSSadaf Ebrahimi /* Flag manipulation instructions: SETF{8,16}, CFINV, RMIF. */ \ 151*f5c631daSSadaf Ebrahimi V(kFlagM, "FlagM", "flagm") \ 152*f5c631daSSadaf Ebrahimi /* Unaligned single-copy atomicity. */ \ 153*f5c631daSSadaf Ebrahimi V(kUSCAT, "USCAT", "uscat") \ 154*f5c631daSSadaf Ebrahimi /* FP16 fused multiply-add or -subtract long: FMLAL{2}, FMLSL{2}. */ \ 155*f5c631daSSadaf Ebrahimi V(kFHM, "FHM", "asimdfhm") \ 156*f5c631daSSadaf Ebrahimi /* Data-independent timing (for selected instructions). */ \ 157*f5c631daSSadaf Ebrahimi V(kDIT, "DIT", "dit") \ 158*f5c631daSSadaf Ebrahimi /* Branch target identification. */ \ 159*f5c631daSSadaf Ebrahimi V(kBTI, "BTI", "bti") \ 160*f5c631daSSadaf Ebrahimi /* Flag manipulation instructions: {AX,XA}FLAG */ \ 161*f5c631daSSadaf Ebrahimi V(kAXFlag, "AXFlag", "flagm2") \ 162*f5c631daSSadaf Ebrahimi /* Random number generation extension, */ \ 163*f5c631daSSadaf Ebrahimi V(kRNG, "RNG", "rng") \ 164*f5c631daSSadaf Ebrahimi /* Floating-point round to {32,64}-bit integer. */ \ 165*f5c631daSSadaf Ebrahimi V(kFrintToFixedSizedInt,"Frint (bounded)", "frint") \ 166*f5c631daSSadaf Ebrahimi /* Memory Tagging Extension. */ \ 167*f5c631daSSadaf Ebrahimi V(kMTEInstructions, "MTE (EL0 instructions)", NULL) \ 168*f5c631daSSadaf Ebrahimi V(kMTE, "MTE", NULL) \ 169*f5c631daSSadaf Ebrahimi /* PAuth extensions. */ \ 170*f5c631daSSadaf Ebrahimi V(kPAuthEnhancedPAC, "PAuth EnhancedPAC", NULL) \ 171*f5c631daSSadaf Ebrahimi V(kPAuthEnhancedPAC2, "PAuth EnhancedPAC2", NULL) \ 172*f5c631daSSadaf Ebrahimi V(kPAuthFPAC, "PAuth FPAC", NULL) \ 173*f5c631daSSadaf Ebrahimi V(kPAuthFPACCombined, "PAuth FPACCombined", NULL) \ 174*f5c631daSSadaf Ebrahimi /* Scalable Vector Extension 2. */ \ 175*f5c631daSSadaf Ebrahimi V(kSVE2, "SVE2", "sve2") \ 176*f5c631daSSadaf Ebrahimi V(kSVESM4, "SVE SM4", "svesm4") \ 177*f5c631daSSadaf Ebrahimi V(kSVESHA3, "SVE SHA3", "svesha3") \ 178*f5c631daSSadaf Ebrahimi V(kSVEBitPerm, "SVE BitPerm", "svebitperm") \ 179*f5c631daSSadaf Ebrahimi V(kSVEAES, "SVE AES", "sveaes") \ 180*f5c631daSSadaf Ebrahimi V(kSVEPmull128, "SVE Pmull128", "svepmull") \ 181*f5c631daSSadaf Ebrahimi /* Alternate floating-point behavior */ \ 182*f5c631daSSadaf Ebrahimi V(kAFP, "AFP", "afp") \ 183*f5c631daSSadaf Ebrahimi /* Enhanced Counter Virtualization */ \ 184*f5c631daSSadaf Ebrahimi V(kECV, "ECV", "ecv") \ 185*f5c631daSSadaf Ebrahimi /* Increased precision of Reciprocal Estimate and Square Root Estimate */ \ 186*f5c631daSSadaf Ebrahimi V(kRPRES, "RPRES", "rpres") 187*f5c631daSSadaf Ebrahimi // clang-format on 188*f5c631daSSadaf Ebrahimi 189*f5c631daSSadaf Ebrahimi 190*f5c631daSSadaf Ebrahimi class CPUFeaturesConstIterator; 191*f5c631daSSadaf Ebrahimi 192*f5c631daSSadaf Ebrahimi // A representation of the set of features known to be supported by the target 193*f5c631daSSadaf Ebrahimi // device. Each feature is represented by a simple boolean flag. 194*f5c631daSSadaf Ebrahimi // 195*f5c631daSSadaf Ebrahimi // - When the Assembler is asked to assemble an instruction, it asserts (in 196*f5c631daSSadaf Ebrahimi // debug mode) that the necessary features are available. 197*f5c631daSSadaf Ebrahimi // 198*f5c631daSSadaf Ebrahimi // - TODO: The MacroAssembler relies on the Assembler's assertions, but in 199*f5c631daSSadaf Ebrahimi // some cases it may be useful for macros to generate a fall-back sequence 200*f5c631daSSadaf Ebrahimi // in case features are not available. 201*f5c631daSSadaf Ebrahimi // 202*f5c631daSSadaf Ebrahimi // - The Simulator assumes by default that all features are available, but it 203*f5c631daSSadaf Ebrahimi // is possible to configure it to fail if the simulated code uses features 204*f5c631daSSadaf Ebrahimi // that are not enabled. 205*f5c631daSSadaf Ebrahimi // 206*f5c631daSSadaf Ebrahimi // The Simulator also offers pseudo-instructions to allow features to be 207*f5c631daSSadaf Ebrahimi // enabled and disabled dynamically. This is useful when you want to ensure 208*f5c631daSSadaf Ebrahimi // that some features are constrained to certain areas of code. 209*f5c631daSSadaf Ebrahimi // 210*f5c631daSSadaf Ebrahimi // - The base Disassembler knows nothing about CPU features, but the 211*f5c631daSSadaf Ebrahimi // PrintDisassembler can be configured to annotate its output with warnings 212*f5c631daSSadaf Ebrahimi // about unavailable features. The Simulator uses this feature when 213*f5c631daSSadaf Ebrahimi // instruction trace is enabled. 214*f5c631daSSadaf Ebrahimi // 215*f5c631daSSadaf Ebrahimi // - The Decoder-based components -- the Simulator and PrintDisassembler -- 216*f5c631daSSadaf Ebrahimi // rely on a CPUFeaturesAuditor visitor. This visitor keeps a list of 217*f5c631daSSadaf Ebrahimi // features actually encountered so that a large block of code can be 218*f5c631daSSadaf Ebrahimi // examined (either directly or through simulation), and the required 219*f5c631daSSadaf Ebrahimi // features analysed later. 220*f5c631daSSadaf Ebrahimi // 221*f5c631daSSadaf Ebrahimi // Expected usage: 222*f5c631daSSadaf Ebrahimi // 223*f5c631daSSadaf Ebrahimi // // By default, VIXL uses CPUFeatures::AArch64LegacyBaseline(), for 224*f5c631daSSadaf Ebrahimi // // compatibility with older version of VIXL. 225*f5c631daSSadaf Ebrahimi // MacroAssembler masm; 226*f5c631daSSadaf Ebrahimi // 227*f5c631daSSadaf Ebrahimi // // Generate code only for the current CPU. 228*f5c631daSSadaf Ebrahimi // masm.SetCPUFeatures(CPUFeatures::InferFromOS()); 229*f5c631daSSadaf Ebrahimi // 230*f5c631daSSadaf Ebrahimi // // Turn off feature checking entirely. 231*f5c631daSSadaf Ebrahimi // masm.SetCPUFeatures(CPUFeatures::All()); 232*f5c631daSSadaf Ebrahimi // 233*f5c631daSSadaf Ebrahimi // Feature set manipulation: 234*f5c631daSSadaf Ebrahimi // 235*f5c631daSSadaf Ebrahimi // CPUFeatures f; // The default constructor gives an empty set. 236*f5c631daSSadaf Ebrahimi // // Individual features can be added (or removed). 237*f5c631daSSadaf Ebrahimi // f.Combine(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::AES); 238*f5c631daSSadaf Ebrahimi // f.Remove(CPUFeatures::kNEON); 239*f5c631daSSadaf Ebrahimi // 240*f5c631daSSadaf Ebrahimi // // Some helpers exist for extensions that provide several features. 241*f5c631daSSadaf Ebrahimi // f.Remove(CPUFeatures::All()); 242*f5c631daSSadaf Ebrahimi // f.Combine(CPUFeatures::AArch64LegacyBaseline()); 243*f5c631daSSadaf Ebrahimi // 244*f5c631daSSadaf Ebrahimi // // Chained construction is also possible. 245*f5c631daSSadaf Ebrahimi // CPUFeatures g = 246*f5c631daSSadaf Ebrahimi // f.With(CPUFeatures::kPmull1Q).Without(CPUFeatures::kCRC32); 247*f5c631daSSadaf Ebrahimi // 248*f5c631daSSadaf Ebrahimi // // Features can be queried. Where multiple features are given, they are 249*f5c631daSSadaf Ebrahimi // // combined with logical AND. 250*f5c631daSSadaf Ebrahimi // if (h.Has(CPUFeatures::kNEON)) { ... } 251*f5c631daSSadaf Ebrahimi // if (h.Has(CPUFeatures::kFP, CPUFeatures::kNEON)) { ... } 252*f5c631daSSadaf Ebrahimi // if (h.Has(g)) { ... } 253*f5c631daSSadaf Ebrahimi // // If the empty set is requested, the result is always 'true'. 254*f5c631daSSadaf Ebrahimi // VIXL_ASSERT(h.Has(CPUFeatures())); 255*f5c631daSSadaf Ebrahimi // 256*f5c631daSSadaf Ebrahimi // // For debug and reporting purposes, features can be enumerated (or 257*f5c631daSSadaf Ebrahimi // // printed directly): 258*f5c631daSSadaf Ebrahimi // std::cout << CPUFeatures::kNEON; // Prints something like "NEON". 259*f5c631daSSadaf Ebrahimi // std::cout << f; // Prints something like "FP, NEON, CRC32". 260*f5c631daSSadaf Ebrahimi class CPUFeatures { 261*f5c631daSSadaf Ebrahimi public: 262*f5c631daSSadaf Ebrahimi // clang-format off 263*f5c631daSSadaf Ebrahimi // Individual features. 264*f5c631daSSadaf Ebrahimi // These should be treated as opaque tokens. User code should not rely on 265*f5c631daSSadaf Ebrahimi // specific numeric values or ordering. 266*f5c631daSSadaf Ebrahimi enum Feature { 267*f5c631daSSadaf Ebrahimi // Refer to VIXL_CPU_FEATURE_LIST (above) for the list of feature names that 268*f5c631daSSadaf Ebrahimi // this class supports. 269*f5c631daSSadaf Ebrahimi 270*f5c631daSSadaf Ebrahimi kNone = -1, 271*f5c631daSSadaf Ebrahimi #define VIXL_DECLARE_FEATURE(SYMBOL, NAME, CPUINFO) SYMBOL, 272*f5c631daSSadaf Ebrahimi VIXL_CPU_FEATURE_LIST(VIXL_DECLARE_FEATURE) 273*f5c631daSSadaf Ebrahimi #undef VIXL_DECLARE_FEATURE 274*f5c631daSSadaf Ebrahimi kNumberOfFeatures 275*f5c631daSSadaf Ebrahimi }; 276*f5c631daSSadaf Ebrahimi // clang-format on 277*f5c631daSSadaf Ebrahimi 278*f5c631daSSadaf Ebrahimi // By default, construct with no features enabled. CPUFeatures()279*f5c631daSSadaf Ebrahimi CPUFeatures() : features_{} {} 280*f5c631daSSadaf Ebrahimi 281*f5c631daSSadaf Ebrahimi // Construct with some features already enabled. 282*f5c631daSSadaf Ebrahimi template <typename T, typename... U> CPUFeatures(T first,U...others)283*f5c631daSSadaf Ebrahimi CPUFeatures(T first, U... others) : features_{} { 284*f5c631daSSadaf Ebrahimi Combine(first, others...); 285*f5c631daSSadaf Ebrahimi } 286*f5c631daSSadaf Ebrahimi 287*f5c631daSSadaf Ebrahimi // Construct with all features enabled. This can be used to disable feature 288*f5c631daSSadaf Ebrahimi // checking: `Has(...)` returns true regardless of the argument. 289*f5c631daSSadaf Ebrahimi static CPUFeatures All(); 290*f5c631daSSadaf Ebrahimi 291*f5c631daSSadaf Ebrahimi // Construct an empty CPUFeatures. This is equivalent to the default 292*f5c631daSSadaf Ebrahimi // constructor, but is provided for symmetry and convenience. None()293*f5c631daSSadaf Ebrahimi static CPUFeatures None() { return CPUFeatures(); } 294*f5c631daSSadaf Ebrahimi 295*f5c631daSSadaf Ebrahimi // The presence of these features was assumed by version of VIXL before this 296*f5c631daSSadaf Ebrahimi // API was added, so using this set by default ensures API compatibility. AArch64LegacyBaseline()297*f5c631daSSadaf Ebrahimi static CPUFeatures AArch64LegacyBaseline() { 298*f5c631daSSadaf Ebrahimi return CPUFeatures(kFP, kNEON, kCRC32); 299*f5c631daSSadaf Ebrahimi } 300*f5c631daSSadaf Ebrahimi 301*f5c631daSSadaf Ebrahimi // Construct a new CPUFeatures object using ID registers. This assumes that 302*f5c631daSSadaf Ebrahimi // kIDRegisterEmulation is present. 303*f5c631daSSadaf Ebrahimi static CPUFeatures InferFromIDRegisters(); 304*f5c631daSSadaf Ebrahimi 305*f5c631daSSadaf Ebrahimi enum QueryIDRegistersOption { 306*f5c631daSSadaf Ebrahimi kDontQueryIDRegisters, 307*f5c631daSSadaf Ebrahimi kQueryIDRegistersIfAvailable 308*f5c631daSSadaf Ebrahimi }; 309*f5c631daSSadaf Ebrahimi 310*f5c631daSSadaf Ebrahimi // Construct a new CPUFeatures object based on what the OS reports. 311*f5c631daSSadaf Ebrahimi static CPUFeatures InferFromOS( 312*f5c631daSSadaf Ebrahimi QueryIDRegistersOption option = kQueryIDRegistersIfAvailable); 313*f5c631daSSadaf Ebrahimi 314*f5c631daSSadaf Ebrahimi // Combine another CPUFeatures object into this one. Features that already 315*f5c631daSSadaf Ebrahimi // exist in this set are left unchanged. 316*f5c631daSSadaf Ebrahimi void Combine(const CPUFeatures& other); 317*f5c631daSSadaf Ebrahimi 318*f5c631daSSadaf Ebrahimi // Combine a specific feature into this set. If it already exists in the set, 319*f5c631daSSadaf Ebrahimi // the set is left unchanged. 320*f5c631daSSadaf Ebrahimi void Combine(Feature feature); 321*f5c631daSSadaf Ebrahimi 322*f5c631daSSadaf Ebrahimi // Combine multiple features (or feature sets) into this set. 323*f5c631daSSadaf Ebrahimi template <typename T, typename... U> Combine(T first,U...others)324*f5c631daSSadaf Ebrahimi void Combine(T first, U... others) { 325*f5c631daSSadaf Ebrahimi Combine(first); 326*f5c631daSSadaf Ebrahimi Combine(others...); 327*f5c631daSSadaf Ebrahimi } 328*f5c631daSSadaf Ebrahimi 329*f5c631daSSadaf Ebrahimi // Remove features in another CPUFeatures object from this one. 330*f5c631daSSadaf Ebrahimi void Remove(const CPUFeatures& other); 331*f5c631daSSadaf Ebrahimi 332*f5c631daSSadaf Ebrahimi // Remove a specific feature from this set. This has no effect if the feature 333*f5c631daSSadaf Ebrahimi // doesn't exist in the set. 334*f5c631daSSadaf Ebrahimi void Remove(Feature feature0); 335*f5c631daSSadaf Ebrahimi 336*f5c631daSSadaf Ebrahimi // Remove multiple features (or feature sets) from this set. 337*f5c631daSSadaf Ebrahimi template <typename T, typename... U> Remove(T first,U...others)338*f5c631daSSadaf Ebrahimi void Remove(T first, U... others) { 339*f5c631daSSadaf Ebrahimi Remove(first); 340*f5c631daSSadaf Ebrahimi Remove(others...); 341*f5c631daSSadaf Ebrahimi } 342*f5c631daSSadaf Ebrahimi 343*f5c631daSSadaf Ebrahimi // Chaining helpers for convenient construction by combining other CPUFeatures 344*f5c631daSSadaf Ebrahimi // or individual Features. 345*f5c631daSSadaf Ebrahimi template <typename... T> With(T...others)346*f5c631daSSadaf Ebrahimi CPUFeatures With(T... others) const { 347*f5c631daSSadaf Ebrahimi CPUFeatures f(*this); 348*f5c631daSSadaf Ebrahimi f.Combine(others...); 349*f5c631daSSadaf Ebrahimi return f; 350*f5c631daSSadaf Ebrahimi } 351*f5c631daSSadaf Ebrahimi 352*f5c631daSSadaf Ebrahimi template <typename... T> Without(T...others)353*f5c631daSSadaf Ebrahimi CPUFeatures Without(T... others) const { 354*f5c631daSSadaf Ebrahimi CPUFeatures f(*this); 355*f5c631daSSadaf Ebrahimi f.Remove(others...); 356*f5c631daSSadaf Ebrahimi return f; 357*f5c631daSSadaf Ebrahimi } 358*f5c631daSSadaf Ebrahimi 359*f5c631daSSadaf Ebrahimi // Test whether the `other` feature set is equal to or a subset of this one. 360*f5c631daSSadaf Ebrahimi bool Has(const CPUFeatures& other) const; 361*f5c631daSSadaf Ebrahimi 362*f5c631daSSadaf Ebrahimi // Test whether a single feature exists in this set. 363*f5c631daSSadaf Ebrahimi // Note that `Has(kNone)` always returns true. 364*f5c631daSSadaf Ebrahimi bool Has(Feature feature) const; 365*f5c631daSSadaf Ebrahimi 366*f5c631daSSadaf Ebrahimi // Test whether all of the specified features exist in this set. 367*f5c631daSSadaf Ebrahimi template <typename T, typename... U> Has(T first,U...others)368*f5c631daSSadaf Ebrahimi bool Has(T first, U... others) const { 369*f5c631daSSadaf Ebrahimi return Has(first) && Has(others...); 370*f5c631daSSadaf Ebrahimi } 371*f5c631daSSadaf Ebrahimi 372*f5c631daSSadaf Ebrahimi // Return the number of enabled features. 373*f5c631daSSadaf Ebrahimi size_t Count() const; HasNoFeatures()374*f5c631daSSadaf Ebrahimi bool HasNoFeatures() const { return Count() == 0; } 375*f5c631daSSadaf Ebrahimi 376*f5c631daSSadaf Ebrahimi // Check for equivalence. 377*f5c631daSSadaf Ebrahimi bool operator==(const CPUFeatures& other) const { 378*f5c631daSSadaf Ebrahimi return Has(other) && other.Has(*this); 379*f5c631daSSadaf Ebrahimi } 380*f5c631daSSadaf Ebrahimi bool operator!=(const CPUFeatures& other) const { return !(*this == other); } 381*f5c631daSSadaf Ebrahimi 382*f5c631daSSadaf Ebrahimi typedef CPUFeaturesConstIterator const_iterator; 383*f5c631daSSadaf Ebrahimi 384*f5c631daSSadaf Ebrahimi const_iterator begin() const; 385*f5c631daSSadaf Ebrahimi const_iterator end() const; 386*f5c631daSSadaf Ebrahimi 387*f5c631daSSadaf Ebrahimi private: 388*f5c631daSSadaf Ebrahimi // Each bit represents a feature. This set will be extended as needed. 389*f5c631daSSadaf Ebrahimi std::bitset<kNumberOfFeatures> features_; 390*f5c631daSSadaf Ebrahimi 391*f5c631daSSadaf Ebrahimi friend std::ostream& operator<<(std::ostream& os, 392*f5c631daSSadaf Ebrahimi const vixl::CPUFeatures& features); 393*f5c631daSSadaf Ebrahimi }; 394*f5c631daSSadaf Ebrahimi 395*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, vixl::CPUFeatures::Feature feature); 396*f5c631daSSadaf Ebrahimi std::ostream& operator<<(std::ostream& os, const vixl::CPUFeatures& features); 397*f5c631daSSadaf Ebrahimi 398*f5c631daSSadaf Ebrahimi // This is not a proper C++ iterator type, but it simulates enough of 399*f5c631daSSadaf Ebrahimi // ForwardIterator that simple loops can be written. 400*f5c631daSSadaf Ebrahimi class CPUFeaturesConstIterator { 401*f5c631daSSadaf Ebrahimi public: 402*f5c631daSSadaf Ebrahimi CPUFeaturesConstIterator(const CPUFeatures* cpu_features = NULL, 403*f5c631daSSadaf Ebrahimi CPUFeatures::Feature start = CPUFeatures::kNone) cpu_features_(cpu_features)404*f5c631daSSadaf Ebrahimi : cpu_features_(cpu_features), feature_(start) { 405*f5c631daSSadaf Ebrahimi VIXL_ASSERT(IsValid()); 406*f5c631daSSadaf Ebrahimi } 407*f5c631daSSadaf Ebrahimi 408*f5c631daSSadaf Ebrahimi bool operator==(const CPUFeaturesConstIterator& other) const; 409*f5c631daSSadaf Ebrahimi bool operator!=(const CPUFeaturesConstIterator& other) const { 410*f5c631daSSadaf Ebrahimi return !(*this == other); 411*f5c631daSSadaf Ebrahimi } 412*f5c631daSSadaf Ebrahimi CPUFeaturesConstIterator& operator++(); 413*f5c631daSSadaf Ebrahimi CPUFeaturesConstIterator operator++(int); 414*f5c631daSSadaf Ebrahimi 415*f5c631daSSadaf Ebrahimi CPUFeatures::Feature operator*() const { 416*f5c631daSSadaf Ebrahimi VIXL_ASSERT(IsValid()); 417*f5c631daSSadaf Ebrahimi return feature_; 418*f5c631daSSadaf Ebrahimi } 419*f5c631daSSadaf Ebrahimi 420*f5c631daSSadaf Ebrahimi // For proper support of C++'s simplest "Iterator" concept, this class would 421*f5c631daSSadaf Ebrahimi // have to define member types (such as CPUFeaturesIterator::pointer) to make 422*f5c631daSSadaf Ebrahimi // it appear as if it iterates over Feature objects in memory. That is, we'd 423*f5c631daSSadaf Ebrahimi // need CPUFeatures::iterator to behave like std::vector<Feature>::iterator. 424*f5c631daSSadaf Ebrahimi // This is at least partially possible -- the std::vector<bool> specialisation 425*f5c631daSSadaf Ebrahimi // does something similar -- but it doesn't seem worthwhile for a 426*f5c631daSSadaf Ebrahimi // special-purpose debug helper, so they are omitted here. 427*f5c631daSSadaf Ebrahimi private: 428*f5c631daSSadaf Ebrahimi const CPUFeatures* cpu_features_; 429*f5c631daSSadaf Ebrahimi CPUFeatures::Feature feature_; 430*f5c631daSSadaf Ebrahimi IsValid()431*f5c631daSSadaf Ebrahimi bool IsValid() const { 432*f5c631daSSadaf Ebrahimi if (cpu_features_ == NULL) { 433*f5c631daSSadaf Ebrahimi return feature_ == CPUFeatures::kNone; 434*f5c631daSSadaf Ebrahimi } 435*f5c631daSSadaf Ebrahimi return cpu_features_->Has(feature_); 436*f5c631daSSadaf Ebrahimi } 437*f5c631daSSadaf Ebrahimi }; 438*f5c631daSSadaf Ebrahimi 439*f5c631daSSadaf Ebrahimi // A convenience scope for temporarily modifying a CPU features object. This 440*f5c631daSSadaf Ebrahimi // allows features to be enabled for short sequences. 441*f5c631daSSadaf Ebrahimi // 442*f5c631daSSadaf Ebrahimi // Expected usage: 443*f5c631daSSadaf Ebrahimi // 444*f5c631daSSadaf Ebrahimi // { 445*f5c631daSSadaf Ebrahimi // CPUFeaturesScope cpu(&masm, CPUFeatures::kCRC32); 446*f5c631daSSadaf Ebrahimi // // This scope can now use CRC32, as well as anything else that was enabled 447*f5c631daSSadaf Ebrahimi // // before the scope. 448*f5c631daSSadaf Ebrahimi // 449*f5c631daSSadaf Ebrahimi // ... 450*f5c631daSSadaf Ebrahimi // 451*f5c631daSSadaf Ebrahimi // // At the end of the scope, the original CPU features are restored. 452*f5c631daSSadaf Ebrahimi // } 453*f5c631daSSadaf Ebrahimi class CPUFeaturesScope { 454*f5c631daSSadaf Ebrahimi public: 455*f5c631daSSadaf Ebrahimi // Start a CPUFeaturesScope on any object that implements 456*f5c631daSSadaf Ebrahimi // `CPUFeatures* GetCPUFeatures()`. 457*f5c631daSSadaf Ebrahimi template <typename T> CPUFeaturesScope(T * cpu_features_wrapper)458*f5c631daSSadaf Ebrahimi explicit CPUFeaturesScope(T* cpu_features_wrapper) 459*f5c631daSSadaf Ebrahimi : cpu_features_(cpu_features_wrapper->GetCPUFeatures()), 460*f5c631daSSadaf Ebrahimi old_features_(*cpu_features_) {} 461*f5c631daSSadaf Ebrahimi 462*f5c631daSSadaf Ebrahimi // Start a CPUFeaturesScope on any object that implements 463*f5c631daSSadaf Ebrahimi // `CPUFeatures* GetCPUFeatures()`, with the specified features enabled. 464*f5c631daSSadaf Ebrahimi template <typename T, typename U, typename... V> CPUFeaturesScope(T * cpu_features_wrapper,U first,V...features)465*f5c631daSSadaf Ebrahimi CPUFeaturesScope(T* cpu_features_wrapper, U first, V... features) 466*f5c631daSSadaf Ebrahimi : cpu_features_(cpu_features_wrapper->GetCPUFeatures()), 467*f5c631daSSadaf Ebrahimi old_features_(*cpu_features_) { 468*f5c631daSSadaf Ebrahimi cpu_features_->Combine(first, features...); 469*f5c631daSSadaf Ebrahimi } 470*f5c631daSSadaf Ebrahimi ~CPUFeaturesScope()471*f5c631daSSadaf Ebrahimi ~CPUFeaturesScope() { *cpu_features_ = old_features_; } 472*f5c631daSSadaf Ebrahimi 473*f5c631daSSadaf Ebrahimi // For advanced usage, the CPUFeatures object can be accessed directly. 474*f5c631daSSadaf Ebrahimi // The scope will restore the original state when it ends. 475*f5c631daSSadaf Ebrahimi GetCPUFeatures()476*f5c631daSSadaf Ebrahimi CPUFeatures* GetCPUFeatures() const { return cpu_features_; } 477*f5c631daSSadaf Ebrahimi SetCPUFeatures(const CPUFeatures & cpu_features)478*f5c631daSSadaf Ebrahimi void SetCPUFeatures(const CPUFeatures& cpu_features) { 479*f5c631daSSadaf Ebrahimi *cpu_features_ = cpu_features; 480*f5c631daSSadaf Ebrahimi } 481*f5c631daSSadaf Ebrahimi 482*f5c631daSSadaf Ebrahimi private: 483*f5c631daSSadaf Ebrahimi CPUFeatures* const cpu_features_; 484*f5c631daSSadaf Ebrahimi const CPUFeatures old_features_; 485*f5c631daSSadaf Ebrahimi }; 486*f5c631daSSadaf Ebrahimi 487*f5c631daSSadaf Ebrahimi 488*f5c631daSSadaf Ebrahimi } // namespace vixl 489*f5c631daSSadaf Ebrahimi 490*f5c631daSSadaf Ebrahimi #endif // VIXL_CPU_FEATURES_H 491