1 // 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 34 namespace 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") \ 59 /* SDOT and UDOT support (in NEON). */ \ 60 V(kDotProduct, "DotProduct", "asimddp") \ 61 /* Half-precision (FP16) support for FP and NEON, respectively. */ \ 62 V(kFPHalf, "FPHalf", "fphp") \ 63 V(kNEONHalf, "NEONHalf", "asimdhp") \ 64 /* The RAS extension, including the ESB instruction. */ \ 65 V(kRAS, "RAS", NULL) \ 66 /* Data cache clean to the point of persistence: DC CVAP. */ \ 67 V(kDCPoP, "DCPoP", "dcpop") \ 68 /* Cryptographic support instructions. */ \ 69 V(kSHA3, "SHA3", "sha3") \ 70 V(kSHA512, "SHA512", "sha512") \ 71 V(kSM3, "SM3", "sm3") \ 72 V(kSM4, "SM4", "sm4") \ 73 /* Pointer authentication for addresses. */ \ 74 V(kPAuth, "PAuth", NULL) \ 75 /* Pointer authentication for addresses uses QARMA. */ \ 76 V(kPAuthQARMA, "PAuthQARMA", NULL) \ 77 /* Generic authentication (using the PACGA instruction). */ \ 78 V(kPAuthGeneric, "PAuthGeneric", NULL) \ 79 /* Generic authentication uses QARMA. */ \ 80 V(kPAuthGenericQARMA, "PAuthGenericQARMA", NULL) \ 81 /* JavaScript-style FP <-> integer conversion instruction: FJCVTZS. */ \ 82 V(kJSCVT, "JSCVT", "jscvt") \ 83 /* RCpc-based model (for weaker release consistency): LDAPR and variants. */ \ 84 V(kRCpc, "RCpc", "lrcpc") \ 85 /* Complex number support for NEON: FCMLA and FCADD. */ \ 86 V(kFcma, "Fcma", "fcma") 87 // clang-format on 88 89 90 class CPUFeaturesConstIterator; 91 92 // A representation of the set of features known to be supported by the target 93 // device. Each feature is represented by a simple boolean flag. 94 // 95 // - When the Assembler is asked to assemble an instruction, it asserts (in 96 // debug mode) that the necessary features are available. 97 // 98 // - TODO: The MacroAssembler relies on the Assembler's assertions, but in 99 // some cases it may be useful for macros to generate a fall-back sequence 100 // in case features are not available. 101 // 102 // - The Simulator assumes by default that all features are available, but it 103 // is possible to configure it to fail if the simulated code uses features 104 // that are not enabled. 105 // 106 // The Simulator also offers pseudo-instructions to allow features to be 107 // enabled and disabled dynamically. This is useful when you want to ensure 108 // that some features are constrained to certain areas of code. 109 // 110 // - The base Disassembler knows nothing about CPU features, but the 111 // PrintDisassembler can be configured to annotate its output with warnings 112 // about unavailable features. The Simulator uses this feature when 113 // instruction trace is enabled. 114 // 115 // - The Decoder-based components -- the Simulator and PrintDisassembler -- 116 // rely on a CPUFeaturesAuditor visitor. This visitor keeps a list of 117 // features actually encountered so that a large block of code can be 118 // examined (either directly or through simulation), and the required 119 // features analysed later. 120 // 121 // Expected usage: 122 // 123 // // By default, VIXL uses CPUFeatures::AArch64LegacyBaseline(), for 124 // // compatibility with older version of VIXL. 125 // MacroAssembler masm; 126 // 127 // // Generate code only for the current CPU. 128 // masm.SetCPUFeatures(CPUFeatures::InferFromOS()); 129 // 130 // // Turn off feature checking entirely. 131 // masm.SetCPUFeatures(CPUFeatures::All()); 132 // 133 // Feature set manipulation: 134 // 135 // CPUFeatures f; // The default constructor gives an empty set. 136 // // Individual features can be added (or removed). 137 // f.Combine(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::AES); 138 // f.Remove(CPUFeatures::kNEON); 139 // 140 // // Some helpers exist for extensions that provide several features. 141 // f.Remove(CPUFeatures::All()); 142 // f.Combine(CPUFeatures::AArch64LegacyBaseline()); 143 // 144 // // Chained construction is also possible. 145 // CPUFeatures g = 146 // f.With(CPUFeatures::kPmull1Q).Without(CPUFeatures::kCRC32); 147 // 148 // // Features can be queried. Where multiple features are given, they are 149 // // combined with logical AND. 150 // if (h.Has(CPUFeatures::kNEON)) { ... } 151 // if (h.Has(CPUFeatures::kFP, CPUFeatures::kNEON)) { ... } 152 // if (h.Has(g)) { ... } 153 // // If the empty set is requested, the result is always 'true'. 154 // VIXL_ASSERT(h.Has(CPUFeatures())); 155 // 156 // // For debug and reporting purposes, features can be enumerated (or 157 // // printed directly): 158 // std::cout << CPUFeatures::kNEON; // Prints something like "NEON". 159 // std::cout << f; // Prints something like "FP, NEON, CRC32". 160 class CPUFeatures { 161 public: 162 // clang-format off 163 // Individual features. 164 // These should be treated as opaque tokens. User code should not rely on 165 // specific numeric values or ordering. 166 enum Feature { 167 // Refer to VIXL_CPU_FEATURE_LIST (above) for the list of feature names that 168 // this class supports. 169 170 kNone = -1, 171 #define VIXL_DECLARE_FEATURE(SYMBOL, NAME, CPUINFO) SYMBOL, 172 VIXL_CPU_FEATURE_LIST(VIXL_DECLARE_FEATURE) 173 #undef VIXL_DECLARE_FEATURE 174 kNumberOfFeatures 175 }; 176 // clang-format on 177 178 // By default, construct with no features enabled. CPUFeatures()179 CPUFeatures() : features_(0) {} 180 181 // Construct with some features already enabled. 182 CPUFeatures(Feature feature0, 183 Feature feature1 = kNone, 184 Feature feature2 = kNone, 185 Feature feature3 = kNone); 186 187 // Construct with all features enabled. This can be used to disable feature 188 // checking: `Has(...)` returns true regardless of the argument. 189 static CPUFeatures All(); 190 191 // Construct an empty CPUFeatures. This is equivalent to the default 192 // constructor, but is provided for symmetry and convenience. None()193 static CPUFeatures None() { return CPUFeatures(); } 194 195 // The presence of these features was assumed by version of VIXL before this 196 // API was added, so using this set by default ensures API compatibility. AArch64LegacyBaseline()197 static CPUFeatures AArch64LegacyBaseline() { 198 return CPUFeatures(kFP, kNEON, kCRC32); 199 } 200 201 // Construct a new CPUFeatures object based on what the OS reports. 202 static CPUFeatures InferFromOS(); 203 204 // Combine another CPUFeatures object into this one. Features that already 205 // exist in this set are left unchanged. 206 void Combine(const CPUFeatures& other); 207 208 // Combine specific features into this set. Features that already exist in 209 // this set are left unchanged. 210 void Combine(Feature feature0, 211 Feature feature1 = kNone, 212 Feature feature2 = kNone, 213 Feature feature3 = kNone); 214 215 // Remove features in another CPUFeatures object from this one. 216 void Remove(const CPUFeatures& other); 217 218 // Remove specific features from this set. 219 void Remove(Feature feature0, 220 Feature feature1 = kNone, 221 Feature feature2 = kNone, 222 Feature feature3 = kNone); 223 224 // Chaining helpers for convenient construction. 225 CPUFeatures With(const CPUFeatures& other) const; 226 CPUFeatures With(Feature feature0, 227 Feature feature1 = kNone, 228 Feature feature2 = kNone, 229 Feature feature3 = kNone) const; 230 CPUFeatures Without(const CPUFeatures& other) const; 231 CPUFeatures Without(Feature feature0, 232 Feature feature1 = kNone, 233 Feature feature2 = kNone, 234 Feature feature3 = kNone) const; 235 236 // Query features. 237 // Note that an empty query (like `Has(kNone)`) always returns true. 238 bool Has(const CPUFeatures& other) const; 239 bool Has(Feature feature0, 240 Feature feature1 = kNone, 241 Feature feature2 = kNone, 242 Feature feature3 = kNone) const; 243 244 // Return the number of enabled features. 245 size_t Count() const; 246 247 // Check for equivalence. 248 bool operator==(const CPUFeatures& other) const { 249 return Has(other) && other.Has(*this); 250 } 251 bool operator!=(const CPUFeatures& other) const { return !(*this == other); } 252 253 typedef CPUFeaturesConstIterator const_iterator; 254 255 const_iterator begin() const; 256 const_iterator end() const; 257 258 private: 259 // Each bit represents a feature. This field will be replaced as needed if 260 // features are added. 261 uint64_t features_; 262 263 friend std::ostream& operator<<(std::ostream& os, 264 const vixl::CPUFeatures& features); 265 }; 266 267 std::ostream& operator<<(std::ostream& os, vixl::CPUFeatures::Feature feature); 268 std::ostream& operator<<(std::ostream& os, const vixl::CPUFeatures& features); 269 270 // This is not a proper C++ iterator type, but it simulates enough of 271 // ForwardIterator that simple loops can be written. 272 class CPUFeaturesConstIterator { 273 public: 274 CPUFeaturesConstIterator(const CPUFeatures* cpu_features = NULL, 275 CPUFeatures::Feature start = CPUFeatures::kNone) cpu_features_(cpu_features)276 : cpu_features_(cpu_features), feature_(start) { 277 VIXL_ASSERT(IsValid()); 278 } 279 280 bool operator==(const CPUFeaturesConstIterator& other) const; 281 bool operator!=(const CPUFeaturesConstIterator& other) const { 282 return !(*this == other); 283 } 284 CPUFeatures::Feature operator++(); 285 CPUFeatures::Feature operator++(int); 286 287 CPUFeatures::Feature operator*() const { 288 VIXL_ASSERT(IsValid()); 289 return feature_; 290 } 291 292 // For proper support of C++'s simplest "Iterator" concept, this class would 293 // have to define member types (such as CPUFeaturesIterator::pointer) to make 294 // it appear as if it iterates over Feature objects in memory. That is, we'd 295 // need CPUFeatures::iterator to behave like std::vector<Feature>::iterator. 296 // This is at least partially possible -- the std::vector<bool> specialisation 297 // does something similar -- but it doesn't seem worthwhile for a 298 // special-purpose debug helper, so they are omitted here. 299 private: 300 const CPUFeatures* cpu_features_; 301 CPUFeatures::Feature feature_; 302 IsValid()303 bool IsValid() const { 304 return ((cpu_features_ == NULL) && (feature_ == CPUFeatures::kNone)) || 305 cpu_features_->Has(feature_); 306 } 307 }; 308 309 // A convenience scope for temporarily modifying a CPU features object. This 310 // allows features to be enabled for short sequences. 311 // 312 // Expected usage: 313 // 314 // { 315 // CPUFeaturesScope cpu(&masm, CPUFeatures::kCRC32); 316 // // This scope can now use CRC32, as well as anything else that was enabled 317 // // before the scope. 318 // 319 // ... 320 // 321 // // At the end of the scope, the original CPU features are restored. 322 // } 323 class CPUFeaturesScope { 324 public: 325 // Start a CPUFeaturesScope on any object that implements 326 // `CPUFeatures* GetCPUFeatures()`. 327 template <typename T> 328 explicit CPUFeaturesScope(T* cpu_features_wrapper, 329 CPUFeatures::Feature feature0 = CPUFeatures::kNone, 330 CPUFeatures::Feature feature1 = CPUFeatures::kNone, 331 CPUFeatures::Feature feature2 = CPUFeatures::kNone, 332 CPUFeatures::Feature feature3 = CPUFeatures::kNone) 333 : cpu_features_(cpu_features_wrapper->GetCPUFeatures()), 334 old_features_(*cpu_features_) { 335 cpu_features_->Combine(feature0, feature1, feature2, feature3); 336 } 337 338 template <typename T> CPUFeaturesScope(T * cpu_features_wrapper,const CPUFeatures & other)339 CPUFeaturesScope(T* cpu_features_wrapper, const CPUFeatures& other) 340 : cpu_features_(cpu_features_wrapper->GetCPUFeatures()), 341 old_features_(*cpu_features_) { 342 cpu_features_->Combine(other); 343 } 344 ~CPUFeaturesScope()345 ~CPUFeaturesScope() { *cpu_features_ = old_features_; } 346 347 // For advanced usage, the CPUFeatures object can be accessed directly. 348 // The scope will restore the original state when it ends. 349 GetCPUFeatures()350 CPUFeatures* GetCPUFeatures() const { return cpu_features_; } 351 SetCPUFeatures(const CPUFeatures & cpu_features)352 void SetCPUFeatures(const CPUFeatures& cpu_features) { 353 *cpu_features_ = cpu_features; 354 } 355 356 private: 357 CPUFeatures* const cpu_features_; 358 const CPUFeatures old_features_; 359 }; 360 361 362 } // namespace vixl 363 364 #endif // VIXL_CPU_FEATURES_H 365