xref: /aosp_15_r20/external/vixl/src/cpu-features.h (revision f5c631da2f1efdd72b5fd1e20510e4042af13d77)
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