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