blob: 77e056fa02eaea7bb3312faf067a5257b9d003a7 [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
30#include <ostream>
31
32#include "globals-vixl.h"
33
34namespace vixl {
35
36
37// clang-format off
38#define VIXL_CPU_FEATURE_LIST(V) \
39 /* If set, the OS traps and emulates MRS accesses to relevant (EL1) ID_* */ \
40 /* registers, so that the detailed feature registers can be read */ \
41 /* directly. */ \
42 V(kIDRegisterEmulation, "ID register emulation", "cpuid") \
43 \
44 V(kFP, "FP", "fp") \
45 V(kNEON, "NEON", "asimd") \
46 V(kCRC32, "CRC32", "crc32") \
47 /* Cryptographic support instructions. */ \
48 V(kAES, "AES", "aes") \
49 V(kSHA1, "SHA1", "sha1") \
50 V(kSHA2, "SHA2", "sha2") \
51 /* A form of PMULL{2} with a 128-bit (1Q) result. */ \
52 V(kPmull1Q, "Pmull1Q", "pmull") \
53 /* Atomic operations on memory: CAS, LDADD, STADD, SWP, etc. */ \
54 V(kAtomics, "Atomics", "atomics") \
55 /* Limited ordering regions: LDLAR, STLLR and their variants. */ \
56 V(kLORegions, "LORegions", NULL) \
57 /* Rounding doubling multiply add/subtract: SQRDMLAH and SQRDMLSH. */ \
58 V(kRDM, "RDM", "asimdrdm") \
Jacob Bramley4482be72018-09-14 15:57:57 +010059 /* Scalable Vector Extension. */ \
60 V(kSVE, "SVE", "sve") \
Jacob Bramley2af191d2018-05-16 10:22:44 +010061 /* SDOT and UDOT support (in NEON). */ \
62 V(kDotProduct, "DotProduct", "asimddp") \
63 /* Half-precision (FP16) support for FP and NEON, respectively. */ \
64 V(kFPHalf, "FPHalf", "fphp") \
65 V(kNEONHalf, "NEONHalf", "asimdhp") \
Jacob Bramleyca789742018-09-13 14:25:46 +010066 /* The RAS extension, including the ESB instruction. */ \
67 V(kRAS, "RAS", NULL) \
Jacob Bramley2af191d2018-05-16 10:22:44 +010068 /* Data cache clean to the point of persistence: DC CVAP. */ \
69 V(kDCPoP, "DCPoP", "dcpop") \
TatWai Chong684f5f72018-12-25 17:49:56 -080070 /* Data cache clean to the point of deep persistence: DC CVADP. */ \
71 V(kDCCVADP, "DCCVADP", NULL) \
Jacob Bramley2af191d2018-05-16 10:22:44 +010072 /* Cryptographic support instructions. */ \
73 V(kSHA3, "SHA3", "sha3") \
74 V(kSHA512, "SHA512", "sha512") \
75 V(kSM3, "SM3", "sm3") \
76 V(kSM4, "SM4", "sm4") \
77 /* Pointer authentication for addresses. */ \
78 V(kPAuth, "PAuth", NULL) \
79 /* Pointer authentication for addresses uses QARMA. */ \
80 V(kPAuthQARMA, "PAuthQARMA", NULL) \
81 /* Generic authentication (using the PACGA instruction). */ \
82 V(kPAuthGeneric, "PAuthGeneric", NULL) \
83 /* Generic authentication uses QARMA. */ \
84 V(kPAuthGenericQARMA, "PAuthGenericQARMA", NULL) \
Jacob Bramley4482be72018-09-14 15:57:57 +010085 /* JavaScript-style FP -> integer conversion instruction: FJCVTZS. */ \
Jacob Bramley2af191d2018-05-16 10:22:44 +010086 V(kJSCVT, "JSCVT", "jscvt") \
Jacob Bramley4482be72018-09-14 15:57:57 +010087 /* Complex number support for NEON: FCMLA and FCADD. */ \
88 V(kFcma, "Fcma", "fcma") \
Jacob Bramley2af191d2018-05-16 10:22:44 +010089 /* RCpc-based model (for weaker release consistency): LDAPR and variants. */ \
90 V(kRCpc, "RCpc", "lrcpc") \
Jacob Bramley4482be72018-09-14 15:57:57 +010091 V(kRCpcImm, "RCpc (imm)", "ilrcpc") \
92 /* Flag manipulation instructions: SETF{8,16}, CFINV, RMIF. */ \
93 V(kFlagM, "FlagM", "flagm") \
94 /* Unaligned single-copy atomicity. */ \
95 V(kUSCAT, "USCAT", "uscat") \
96 /* FP16 fused multiply-add or -subtract long: FMLAL{2}, FMLSL{2}. */ \
97 V(kFHM, "FHM", "asimdfhm") \
98 /* Data-independent timing (for selected instructions). */ \
Martyn Capewellcb963f72018-10-22 15:25:28 +010099 V(kDIT, "DIT", "dit") \
100 /* Branch target identification. */ \
Alexander Gilday84ee1442018-11-06 15:28:07 +0000101 V(kBTI, "BTI", NULL) \
102 /* Flag manipulation instructions: {AX,XA}FLAG */ \
TatWai Chong04edf682018-12-27 16:01:02 -0800103 V(kAXFlag, "AXFlag", NULL) \
104 /* Random number generation extension, */ \
TatWai Chong04471812019-03-19 14:29:00 -0700105 V(kRNG, "RNG", NULL) \
106 /* Floating-point round to {32,64}-bit integer. */ \
107 V(kFrintToFixedSizedInt,"Frint (bounded)", NULL)
Jacob Bramley2af191d2018-05-16 10:22:44 +0100108// clang-format on
109
110
111class CPUFeaturesConstIterator;
112
113// A representation of the set of features known to be supported by the target
114// device. Each feature is represented by a simple boolean flag.
115//
Jacob Bramley5997b462018-06-05 14:05:30 +0100116// - When the Assembler is asked to assemble an instruction, it asserts (in
117// debug mode) that the necessary features are available.
Jacob Bramley2af191d2018-05-16 10:22:44 +0100118//
Jacob Bramley2af191d2018-05-16 10:22:44 +0100119// - TODO: The MacroAssembler relies on the Assembler's assertions, but in
120// some cases it may be useful for macros to generate a fall-back sequence
121// in case features are not available.
122//
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +0100123// - The Simulator assumes by default that all features are available, but it
124// is possible to configure it to fail if the simulated code uses features
125// that are not enabled.
126//
127// The Simulator also offers pseudo-instructions to allow features to be
128// enabled and disabled dynamically. This is useful when you want to ensure
129// that some features are constrained to certain areas of code.
130//
131// - The base Disassembler knows nothing about CPU features, but the
132// PrintDisassembler can be configured to annotate its output with warnings
133// about unavailable features. The Simulator uses this feature when
134// instruction trace is enabled.
135//
136// - The Decoder-based components -- the Simulator and PrintDisassembler --
137// rely on a CPUFeaturesAuditor visitor. This visitor keeps a list of
138// features actually encountered so that a large block of code can be
139// examined (either directly or through simulation), and the required
140// features analysed later.
141//
Jacob Bramley2af191d2018-05-16 10:22:44 +0100142// Expected usage:
143//
144// // By default, VIXL uses CPUFeatures::AArch64LegacyBaseline(), for
145// // compatibility with older version of VIXL.
146// MacroAssembler masm;
147//
148// // Generate code only for the current CPU.
149// masm.SetCPUFeatures(CPUFeatures::InferFromOS());
150//
151// // Turn off feature checking entirely.
152// masm.SetCPUFeatures(CPUFeatures::All());
153//
154// Feature set manipulation:
155//
156// CPUFeatures f; // The default constructor gives an empty set.
157// // Individual features can be added (or removed).
158// f.Combine(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::AES);
159// f.Remove(CPUFeatures::kNEON);
160//
161// // Some helpers exist for extensions that provide several features.
162// f.Remove(CPUFeatures::All());
163// f.Combine(CPUFeatures::AArch64LegacyBaseline());
164//
165// // Chained construction is also possible.
166// CPUFeatures g =
167// f.With(CPUFeatures::kPmull1Q).Without(CPUFeatures::kCRC32);
168//
169// // Features can be queried. Where multiple features are given, they are
170// // combined with logical AND.
171// if (h.Has(CPUFeatures::kNEON)) { ... }
172// if (h.Has(CPUFeatures::kFP, CPUFeatures::kNEON)) { ... }
173// if (h.Has(g)) { ... }
174// // If the empty set is requested, the result is always 'true'.
175// VIXL_ASSERT(h.Has(CPUFeatures()));
176//
177// // For debug and reporting purposes, features can be enumerated (or
178// // printed directly):
179// std::cout << CPUFeatures::kNEON; // Prints something like "NEON".
180// std::cout << f; // Prints something like "FP, NEON, CRC32".
181class CPUFeatures {
182 public:
183 // clang-format off
184 // Individual features.
185 // These should be treated as opaque tokens. User code should not rely on
186 // specific numeric values or ordering.
187 enum Feature {
188 // Refer to VIXL_CPU_FEATURE_LIST (above) for the list of feature names that
189 // this class supports.
190
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100191 kNone = -1,
Jacob Bramley2af191d2018-05-16 10:22:44 +0100192#define VIXL_DECLARE_FEATURE(SYMBOL, NAME, CPUINFO) SYMBOL,
193 VIXL_CPU_FEATURE_LIST(VIXL_DECLARE_FEATURE)
194#undef VIXL_DECLARE_FEATURE
Jacob Bramleyfdf332a2018-09-17 11:17:54 +0100195 kNumberOfFeatures
Jacob Bramley2af191d2018-05-16 10:22:44 +0100196 };
197 // clang-format on
198
199 // By default, construct with no features enabled.
200 CPUFeatures() : features_(0) {}
201
202 // Construct with some features already enabled.
203 CPUFeatures(Feature feature0,
204 Feature feature1 = kNone,
205 Feature feature2 = kNone,
206 Feature feature3 = kNone);
207
208 // Construct with all features enabled. This can be used to disable feature
209 // checking: `Has(...)` returns true regardless of the argument.
210 static CPUFeatures All();
211
Jacob Bramley7b8fc822018-06-26 16:48:21 +0100212 // Construct an empty CPUFeatures. This is equivalent to the default
213 // constructor, but is provided for symmetry and convenience.
214 static CPUFeatures None() { return CPUFeatures(); }
215
Jacob Bramley2af191d2018-05-16 10:22:44 +0100216 // The presence of these features was assumed by version of VIXL before this
217 // API was added, so using this set by default ensures API compatibility.
218 static CPUFeatures AArch64LegacyBaseline() {
219 return CPUFeatures(kFP, kNEON, kCRC32);
220 }
221
Jacob Bramley48934322019-02-04 18:27:53 +0000222 // Construct a new CPUFeatures object using ID registers. This assumes that
223 // kIDRegisterEmulation is present.
224 static CPUFeatures InferFromIDRegisters();
225
226 enum QueryIDRegistersOption {
227 kDontQueryIDRegisters,
228 kQueryIDRegistersIfAvailable
229 };
230
Jacob Bramley2af191d2018-05-16 10:22:44 +0100231 // Construct a new CPUFeatures object based on what the OS reports.
Jacob Bramley48934322019-02-04 18:27:53 +0000232 static CPUFeatures InferFromOS(
233 QueryIDRegistersOption option = kQueryIDRegistersIfAvailable);
Jacob Bramley2af191d2018-05-16 10:22:44 +0100234
235 // Combine another CPUFeatures object into this one. Features that already
236 // exist in this set are left unchanged.
237 void Combine(const CPUFeatures& other);
238
239 // Combine specific features into this set. Features that already exist in
240 // this set are left unchanged.
241 void Combine(Feature feature0,
242 Feature feature1 = kNone,
243 Feature feature2 = kNone,
244 Feature feature3 = kNone);
245
246 // Remove features in another CPUFeatures object from this one.
247 void Remove(const CPUFeatures& other);
248
249 // Remove specific features from this set.
250 void Remove(Feature feature0,
251 Feature feature1 = kNone,
252 Feature feature2 = kNone,
253 Feature feature3 = kNone);
254
255 // Chaining helpers for convenient construction.
256 CPUFeatures With(const CPUFeatures& other) const;
257 CPUFeatures With(Feature feature0,
258 Feature feature1 = kNone,
259 Feature feature2 = kNone,
260 Feature feature3 = kNone) const;
261 CPUFeatures Without(const CPUFeatures& other) const;
262 CPUFeatures Without(Feature feature0,
263 Feature feature1 = kNone,
264 Feature feature2 = kNone,
265 Feature feature3 = kNone) const;
266
267 // Query features.
268 // Note that an empty query (like `Has(kNone)`) always returns true.
269 bool Has(const CPUFeatures& other) const;
270 bool Has(Feature feature0,
271 Feature feature1 = kNone,
272 Feature feature2 = kNone,
273 Feature feature3 = kNone) const;
274
Jacob Bramleyc44ce3d2018-06-12 15:39:09 +0100275 // Return the number of enabled features.
276 size_t Count() const;
277
278 // Check for equivalence.
279 bool operator==(const CPUFeatures& other) const {
280 return Has(other) && other.Has(*this);
281 }
282 bool operator!=(const CPUFeatures& other) const { return !(*this == other); }
283
Jacob Bramley2af191d2018-05-16 10:22:44 +0100284 typedef CPUFeaturesConstIterator const_iterator;
285
286 const_iterator begin() const;
287 const_iterator end() const;
288
289 private:
290 // Each bit represents a feature. This field will be replaced as needed if
291 // features are added.
292 uint64_t features_;
293
294 friend std::ostream& operator<<(std::ostream& os,
295 const vixl::CPUFeatures& features);
296};
297
298std::ostream& operator<<(std::ostream& os, vixl::CPUFeatures::Feature feature);
299std::ostream& operator<<(std::ostream& os, const vixl::CPUFeatures& features);
300
301// This is not a proper C++ iterator type, but it simulates enough of
302// ForwardIterator that simple loops can be written.
303class CPUFeaturesConstIterator {
304 public:
305 CPUFeaturesConstIterator(const CPUFeatures* cpu_features = NULL,
306 CPUFeatures::Feature start = CPUFeatures::kNone)
307 : cpu_features_(cpu_features), feature_(start) {
308 VIXL_ASSERT(IsValid());
309 }
310
311 bool operator==(const CPUFeaturesConstIterator& other) const;
312 bool operator!=(const CPUFeaturesConstIterator& other) const {
313 return !(*this == other);
314 }
315 CPUFeatures::Feature operator++();
316 CPUFeatures::Feature operator++(int);
317
318 CPUFeatures::Feature operator*() const {
319 VIXL_ASSERT(IsValid());
320 return feature_;
321 }
322
323 // For proper support of C++'s simplest "Iterator" concept, this class would
324 // have to define member types (such as CPUFeaturesIterator::pointer) to make
325 // it appear as if it iterates over Feature objects in memory. That is, we'd
326 // need CPUFeatures::iterator to behave like std::vector<Feature>::iterator.
327 // This is at least partially possible -- the std::vector<bool> specialisation
328 // does something similar -- but it doesn't seem worthwhile for a
329 // special-purpose debug helper, so they are omitted here.
330 private:
331 const CPUFeatures* cpu_features_;
332 CPUFeatures::Feature feature_;
333
334 bool IsValid() const {
335 return ((cpu_features_ == NULL) && (feature_ == CPUFeatures::kNone)) ||
336 cpu_features_->Has(feature_);
337 }
338};
339
340// A convenience scope for temporarily modifying a CPU features object. This
341// allows features to be enabled for short sequences.
342//
343// Expected usage:
344//
345// {
346// CPUFeaturesScope cpu(&masm, CPUFeatures::kCRC32);
347// // This scope can now use CRC32, as well as anything else that was enabled
348// // before the scope.
349//
350// ...
351//
352// // At the end of the scope, the original CPU features are restored.
353// }
354class CPUFeaturesScope {
355 public:
356 // Start a CPUFeaturesScope on any object that implements
357 // `CPUFeatures* GetCPUFeatures()`.
358 template <typename T>
359 explicit CPUFeaturesScope(T* cpu_features_wrapper,
360 CPUFeatures::Feature feature0 = CPUFeatures::kNone,
361 CPUFeatures::Feature feature1 = CPUFeatures::kNone,
362 CPUFeatures::Feature feature2 = CPUFeatures::kNone,
363 CPUFeatures::Feature feature3 = CPUFeatures::kNone)
364 : cpu_features_(cpu_features_wrapper->GetCPUFeatures()),
365 old_features_(*cpu_features_) {
366 cpu_features_->Combine(feature0, feature1, feature2, feature3);
367 }
368
369 template <typename T>
370 CPUFeaturesScope(T* cpu_features_wrapper, const CPUFeatures& other)
371 : cpu_features_(cpu_features_wrapper->GetCPUFeatures()),
372 old_features_(*cpu_features_) {
373 cpu_features_->Combine(other);
374 }
375
376 ~CPUFeaturesScope() { *cpu_features_ = old_features_; }
377
378 // For advanced usage, the CPUFeatures object can be accessed directly.
379 // The scope will restore the original state when it ends.
380
381 CPUFeatures* GetCPUFeatures() const { return cpu_features_; }
382
383 void SetCPUFeatures(const CPUFeatures& cpu_features) {
384 *cpu_features_ = cpu_features;
385 }
386
387 private:
388 CPUFeatures* const cpu_features_;
389 const CPUFeatures old_features_;
390};
391
392
393} // namespace vixl
394
395#endif // VIXL_CPU_FEATURES_H