1 // Copyright 2016, 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 #include <iostream> 28 #include <set> 29 #include <sstream> 30 #include <vector> 31 32 #include "test-runner.h" 33 34 #include "cpu-features.h" 35 #include "utils-vixl.h" 36 37 #if __cplusplus >= 201103L 38 #include <type_traits> 39 #endif 40 41 #define TEST(name) TEST_(API_##name) 42 43 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 44 45 namespace vixl { 46 47 // Describe the result of a test. Should IsUintN() and IsIntN() return true or 48 // false for N and X? 49 template <typename T> 50 struct UintIntTest { 51 bool is_uintn; 52 bool is_intn; 53 unsigned n; 54 T x; 55 }; 56 57 // Test IsUintN() and IsIntN() against various values and integral types. 58 TEST(IsUint_IsInt) { 59 UintIntTest<uint32_t> test_little_values_unsigned[] = { 60 {true, true, 1, UINT32_C(0x0)}, {true, false, 1, UINT32_C(0x1)}, 61 {false, false, 1, UINT32_C(0x2)}, {false, false, 1, UINT32_C(0x3)}, 62 {false, false, 1, UINT32_C(0x4)}, {false, false, 1, UINT32_C(0x5)}, 63 {false, false, 1, UINT32_C(0x6)}, {false, false, 1, UINT32_C(0x7)}, 64 {false, false, 1, UINT32_C(0x8)}, {false, false, 1, UINT32_C(0x9)}, 65 {false, false, 1, UINT32_C(0xa)}, {false, false, 1, UINT32_C(0xb)}, 66 {false, false, 1, UINT32_C(0xc)}, {false, false, 1, UINT32_C(0xd)}, 67 {false, false, 1, UINT32_C(0xe)}, {false, false, 1, UINT32_C(0xf)}, 68 69 {true, true, 2, UINT32_C(0x0)}, {true, true, 2, UINT32_C(0x1)}, 70 {true, false, 2, UINT32_C(0x2)}, {true, false, 2, UINT32_C(0x3)}, 71 {false, false, 2, UINT32_C(0x4)}, {false, false, 2, UINT32_C(0x5)}, 72 {false, false, 2, UINT32_C(0x6)}, {false, false, 2, UINT32_C(0x7)}, 73 {false, false, 2, UINT32_C(0x8)}, {false, false, 2, UINT32_C(0x9)}, 74 {false, false, 2, UINT32_C(0xa)}, {false, false, 2, UINT32_C(0xb)}, 75 {false, false, 2, UINT32_C(0xc)}, {false, false, 2, UINT32_C(0xd)}, 76 {false, false, 2, UINT32_C(0xe)}, {false, false, 2, UINT32_C(0xf)}, 77 }; 78 79 UintIntTest<int32_t> test_little_values_signed[] = { 80 {true, true, 1, INT32_C(0)}, {true, false, 1, INT32_C(1)}, 81 {false, false, 1, INT32_C(2)}, {false, false, 1, INT32_C(3)}, 82 {false, false, 1, INT32_C(4)}, {false, false, 1, INT32_C(5)}, 83 {false, false, 1, INT32_C(6)}, {false, false, 1, INT32_C(7)}, 84 {false, true, 1, INT32_C(-1)}, {false, false, 1, INT32_C(-2)}, 85 {false, false, 1, INT32_C(-3)}, {false, false, 1, INT32_C(-4)}, 86 {false, false, 1, INT32_C(-5)}, {false, false, 1, INT32_C(-6)}, 87 {false, false, 1, INT32_C(-7)}, {false, false, 1, INT32_C(-8)}, 88 89 {true, true, 2, INT32_C(0)}, {true, true, 2, INT32_C(1)}, 90 {true, false, 2, INT32_C(2)}, {true, false, 2, INT32_C(3)}, 91 {false, false, 2, INT32_C(4)}, {false, false, 2, INT32_C(5)}, 92 {false, false, 2, INT32_C(6)}, {false, false, 2, INT32_C(7)}, 93 {false, true, 2, INT32_C(-1)}, {false, true, 2, INT32_C(-2)}, 94 {false, false, 2, INT32_C(-3)}, {false, false, 2, INT32_C(-4)}, 95 {false, false, 2, INT32_C(-5)}, {false, false, 2, INT32_C(-6)}, 96 {false, false, 2, INT32_C(-7)}, {false, false, 2, INT32_C(-8)}, 97 }; 98 99 UintIntTest<uint32_t> test_u16[] = { 100 {true, true, 16, UINT32_C(0x0)}, 101 {true, false, 16, UINT32_C(0xabcd)}, 102 {true, false, 16, UINT32_C(0x8000)}, 103 {true, false, 16, UINT32_C(0xffff)}, 104 {false, false, 16, UINT32_C(0x10000)}, 105 {false, false, 16, UINT32_C(0xffff0000)}, 106 {false, false, 16, UINT32_C(0xffff8000)}, 107 {false, false, 16, UINT32_C(0xffffffff)}, 108 }; 109 110 UintIntTest<int32_t> test_i16[] = { 111 {true, true, 16, INT32_C(0x0)}, 112 {true, false, 16, INT32_C(0xabcd)}, 113 {true, false, 16, INT32_C(0x8000)}, 114 {true, false, 16, INT32_C(0xffff)}, 115 {false, false, 16, INT32_C(0x10000)}, 116 {true, true, 16, INT32_C(42)}, 117 {false, true, 16, INT32_C(-42)}, 118 {false, true, 16, INT32_C(-1)}, 119 }; 120 121 UintIntTest<uint64_t> test_u32[] = { 122 {true, true, 32, UINT64_C(0x0)}, 123 {true, false, 32, UINT64_C(0xabcdabcd)}, 124 {true, false, 32, UINT64_C(0x80000000)}, 125 {true, false, 32, UINT64_C(0xffffffff)}, 126 }; 127 128 UintIntTest<int64_t> test_i32[] = { 129 {true, true, 32, INT64_C(0)}, 130 {true, true, 32, INT64_C(42)}, 131 {false, true, 32, INT64_C(-42)}, 132 {false, true, 32, INT64_C(-1)}, 133 {true, true, 32, INT64_C(2147483647)}, // (1 << (32 - 1)) - 1 134 {false, true, 32, INT64_C(-2147483648)}, // -(1 << (32 - 1)) 135 }; 136 137 UintIntTest<uint64_t> test_unsigned_higher_than_32[] = { 138 {false, false, 54, UINT64_C(0xabcdef9012345678)}, 139 {true, false, 33, UINT64_C(0x100000000)}, 140 {true, false, 62, UINT64_C(0x3fffffffffffffff)}, 141 {true, false, 63, UINT64_C(0x7fffffffffffffff)}, 142 }; 143 144 UintIntTest<int64_t> test_signed_higher_than_32[] = { 145 {true, true, 54, INT64_C(9007199254740991)}, // (1 << (54 - 1)) - 1 146 {true, false, 54, INT64_C(9007199254740992)}, // 1 << (54 - 1) 147 {true, true, 33, INT64_C(4294967295)}, // (1 << (33 - 1) - 1) 148 {false, true, 33, INT64_C(-4294967296)}, // -(1 << (33 - 1)) 149 }; 150 151 #define TEST_LIST(M) \ 152 M(test_little_values_unsigned) \ 153 M(test_little_values_signed) \ 154 M(test_u16) \ 155 M(test_i16) \ 156 M(test_u32) \ 157 M(test_i32) \ 158 M(test_unsigned_higher_than_32) \ 159 M(test_signed_higher_than_32) 160 161 162 #define TEST_UINT(test_vector) \ 163 for (unsigned i = 0; i < ARRAY_SIZE(test_vector); i++) { \ 164 if (test_vector[i].is_uintn) { \ 165 VIXL_CHECK(IsUintN(test_vector[i].n, test_vector[i].x)); \ 166 } else { \ 167 VIXL_CHECK(!IsUintN(test_vector[i].n, test_vector[i].x)); \ 168 } \ 169 } 170 171 #define TEST_INT(test_vector) \ 172 for (unsigned i = 0; i < ARRAY_SIZE(test_vector); i++) { \ 173 if (test_vector[i].is_intn) { \ 174 VIXL_CHECK(IsIntN(test_vector[i].n, test_vector[i].x)); \ 175 } else { \ 176 VIXL_CHECK(!IsIntN(test_vector[i].n, test_vector[i].x)); \ 177 } \ 178 } 179 180 TEST_LIST(TEST_UINT) 181 TEST_LIST(TEST_INT) 182 183 #undef TEST_UINT 184 #undef TEST_INT 185 186 #undef TEST_LIST 187 } 188 189 190 TEST(CPUFeatures_iterator_api) { 191 // CPUFeaturesIterator does not fully satisfy the requirements of C++'s 192 // iterator concepts, but it should implement enough for some basic usage. 193 194 // Arbitrary feature lists. 195 CPUFeatures f1(CPUFeatures::kFP, CPUFeatures::kNEON); 196 CPUFeatures f2(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kCRC32); 197 CPUFeatures f3; 198 199 typedef CPUFeatures::const_iterator It; 200 201 It it0; 202 It it1_neon(&f1, CPUFeatures::kNEON); 203 It it2_neon(&f2, CPUFeatures::kNEON); 204 It it2_crc32(&f2, CPUFeatures::kCRC32); 205 It it3(&f3); 206 207 // Equality 208 VIXL_CHECK(it0 == it0); 209 VIXL_CHECK(it1_neon == it1_neon); 210 VIXL_CHECK(it2_neon == it2_neon); 211 VIXL_CHECK(it2_crc32 == it2_crc32); 212 VIXL_CHECK(it3 == it3); 213 VIXL_CHECK(!(it0 == it1_neon)); 214 VIXL_CHECK(!(it0 == it3)); 215 VIXL_CHECK(!(it1_neon == it2_neon)); 216 VIXL_CHECK(!(it1_neon == it2_crc32)); 217 VIXL_CHECK(!(it1_neon == it3)); 218 VIXL_CHECK(!(it2_neon == it2_crc32)); 219 VIXL_CHECK(!(it3 == it0)); 220 VIXL_CHECK(!(it3 == it1_neon)); 221 222 // Inequality 223 // (a == b) <-> !(a != b) 224 VIXL_CHECK(!(it0 != it0)); 225 VIXL_CHECK(!(it1_neon != it1_neon)); 226 VIXL_CHECK(!(it2_neon != it2_neon)); 227 VIXL_CHECK(!(it2_crc32 != it2_crc32)); 228 VIXL_CHECK(!(it3 != it3)); 229 // !(a == b) <-> (a != b) 230 VIXL_CHECK(it0 != it1_neon); 231 VIXL_CHECK(it0 != it3); 232 VIXL_CHECK(it1_neon != it2_neon); 233 VIXL_CHECK(it1_neon != it2_crc32); 234 VIXL_CHECK(it1_neon != it3); 235 VIXL_CHECK(it2_neon != it2_crc32); 236 VIXL_CHECK(it3 != it0); 237 VIXL_CHECK(it3 != it1_neon); 238 239 // Dereferenceable 240 VIXL_CHECK(*it0 == CPUFeatures::kNone); 241 VIXL_CHECK(*it1_neon == CPUFeatures::kNEON); 242 VIXL_CHECK(*it2_neon == CPUFeatures::kNEON); 243 VIXL_CHECK(*it2_crc32 == CPUFeatures::kCRC32); 244 VIXL_CHECK(*it3 == CPUFeatures::kNone); 245 246 #if __cplusplus >= 201103L 247 VIXL_STATIC_ASSERT(std::is_copy_constructible<It>::value); 248 VIXL_STATIC_ASSERT(std::is_copy_assignable<It>::value); 249 VIXL_STATIC_ASSERT(std::is_destructible<It>::value); 250 #endif 251 // Copy constructable 252 It test0 = it0; 253 It test1 = it1_neon; 254 It test2(it2_neon); 255 VIXL_CHECK(test0 == It(NULL, CPUFeatures::kNone)); 256 VIXL_CHECK(test1 == It(&f1, CPUFeatures::kNEON)); 257 VIXL_CHECK(test2 == It(&f2, CPUFeatures::kNEON)); 258 259 // Copy assignable 260 test2 = it2_crc32; 261 VIXL_CHECK(test2 == It(&f2, CPUFeatures::kCRC32)); 262 263 // Incrementable 264 // - Incrementing has no effect on an empty CPUFeatures. 265 VIXL_CHECK(it3++ == CPUFeatures::kNone); 266 VIXL_CHECK(++it3 == CPUFeatures::kNone); 267 VIXL_CHECK(it3 == It(&f3, CPUFeatures::kNone)); 268 // - Incrementing moves to the next feature, wrapping around (through kNone). 269 // This test will need to be updated if the Feature enum is reordered. 270 VIXL_CHECK(it2_neon++ == CPUFeatures::kNEON); 271 VIXL_CHECK(it2_neon++ == CPUFeatures::kCRC32); 272 VIXL_CHECK(it2_neon++ == CPUFeatures::kNone); 273 VIXL_CHECK(it2_neon++ == CPUFeatures::kFP); 274 VIXL_CHECK(it2_neon == It(&f2, CPUFeatures::kNEON)); 275 VIXL_CHECK(++it2_crc32 == CPUFeatures::kNone); 276 VIXL_CHECK(++it2_crc32 == CPUFeatures::kFP); 277 VIXL_CHECK(++it2_crc32 == CPUFeatures::kNEON); 278 VIXL_CHECK(++it2_crc32 == CPUFeatures::kCRC32); 279 VIXL_CHECK(it2_crc32 == It(&f2, CPUFeatures::kCRC32)); 280 } 281 282 283 TEST(CPUFeatures_iterator_loops) { 284 // Check that CPUFeaturesIterator can be used for some simple loops. 285 286 // Arbitrary feature lists. 287 CPUFeatures f1(CPUFeatures::kFP, CPUFeatures::kNEON); 288 CPUFeatures f2(CPUFeatures::kFP, CPUFeatures::kNEON, CPUFeatures::kCRC32); 289 CPUFeatures f3; 290 291 // This test will need to be updated if the Feature enum is reordered. 292 293 std::vector<CPUFeatures::Feature> f1_list; 294 for (CPUFeatures::const_iterator it = f1.begin(); it != f1.end(); ++it) { 295 f1_list.push_back(*it); 296 } 297 VIXL_CHECK(f1_list.size() == 2); 298 VIXL_CHECK(f1_list[0] == CPUFeatures::kFP); 299 VIXL_CHECK(f1_list[1] == CPUFeatures::kNEON); 300 301 std::vector<CPUFeatures::Feature> f2_list; 302 for (CPUFeatures::const_iterator it = f2.begin(); it != f2.end(); ++it) { 303 f2_list.push_back(*it); 304 } 305 VIXL_CHECK(f2_list.size() == 3); 306 VIXL_CHECK(f2_list[0] == CPUFeatures::kFP); 307 VIXL_CHECK(f2_list[1] == CPUFeatures::kNEON); 308 VIXL_CHECK(f2_list[2] == CPUFeatures::kCRC32); 309 310 std::vector<CPUFeatures::Feature> f3_list; 311 for (CPUFeatures::const_iterator it = f3.begin(); it != f3.end(); ++it) { 312 f3_list.push_back(*it); 313 } 314 VIXL_CHECK(f3_list.size() == 0); 315 316 #if __cplusplus >= 201103L 317 std::vector<CPUFeatures::Feature> f2_list_cxx11; 318 for (auto&& feature : f2) { 319 f2_list_cxx11.push_back(feature); 320 } 321 VIXL_CHECK(f2_list_cxx11.size() == 3); 322 VIXL_CHECK(f2_list_cxx11[0] == CPUFeatures::kFP); 323 VIXL_CHECK(f2_list_cxx11[1] == CPUFeatures::kNEON); 324 VIXL_CHECK(f2_list_cxx11[2] == CPUFeatures::kCRC32); 325 326 std::vector<CPUFeatures::Feature> f3_list_cxx11; 327 for (auto&& feature : f3) { 328 f3_list_cxx11.push_back(feature); 329 } 330 VIXL_CHECK(f3_list_cxx11.size() == 0); 331 #endif 332 } 333 334 335 TEST(CPUFeatures_empty) { 336 // A default-constructed CPUFeatures has no features enabled. 337 CPUFeatures f; 338 for (CPUFeatures::const_iterator it = f.begin(); it != f.end(); ++it) { 339 VIXL_ABORT(); 340 } 341 } 342 343 344 static void CPUFeaturesFormatHelper(const char* expected, 345 const CPUFeatures& features) { 346 std::stringstream os; 347 os << features; 348 std::string os_str = os.str(); 349 if (os_str != expected) { 350 std::cout << "Found: " << os_str << "\n"; 351 std::cout << "Expected: " << expected << "\n"; 352 VIXL_ABORT(); 353 } 354 } 355 356 357 TEST(CPUFeatures_format) { 358 // Check that the debug output is complete and accurate. 359 360 // Individual features. 361 CPUFeaturesFormatHelper("", CPUFeatures(CPUFeatures::kNone)); 362 CPUFeaturesFormatHelper("FP", CPUFeatures(CPUFeatures::kFP)); 363 CPUFeaturesFormatHelper("NEON", CPUFeatures(CPUFeatures::kNEON)); 364 CPUFeaturesFormatHelper("AES", CPUFeatures(CPUFeatures::kAES)); 365 CPUFeaturesFormatHelper("Pmull1Q", CPUFeatures(CPUFeatures::kPmull1Q)); 366 CPUFeaturesFormatHelper("SHA1", CPUFeatures(CPUFeatures::kSHA1)); 367 CPUFeaturesFormatHelper("SHA2", CPUFeatures(CPUFeatures::kSHA2)); 368 CPUFeaturesFormatHelper("CRC32", CPUFeatures(CPUFeatures::kCRC32)); 369 370 // Combinations of (arbitrary) features. 371 // This test will need to be updated if the Feature enum is reordered. 372 CPUFeatures f(CPUFeatures::kFP, CPUFeatures::kNEON); 373 CPUFeaturesFormatHelper("FP, NEON", f); 374 f.Combine(CPUFeatures::kCRC32); 375 CPUFeaturesFormatHelper("FP, NEON, CRC32", f); 376 f.Combine(CPUFeatures::kFcma); 377 CPUFeaturesFormatHelper("FP, NEON, CRC32, Fcma", f); 378 f.Combine(CPUFeatures::kSHA1); 379 CPUFeaturesFormatHelper("FP, NEON, CRC32, SHA1, Fcma", f); 380 381 CPUFeaturesFormatHelper( 382 "ID register emulation, " 383 // Armv8.0 384 "FP, NEON, CRC32, " 385 "AES, SHA1, SHA2, Pmull1Q, " 386 // Armv8.1 387 "Atomics, LORegions, RDM, " 388 // Armv8.2 389 "DotProduct, FPHalf, NEONHalf, RAS, DCPoP, SHA3, SHA512, SM3, SM4, " 390 // Armv8.3 391 "PAuth, PAuthQARMA, PAuthGeneric, PAuthGenericQARMA, JSCVT, RCpc, Fcma", 392 CPUFeatures::All()); 393 } 394 395 396 static void CPUFeaturesPredefinedResultCheckHelper( 397 const std::set<CPUFeatures::Feature>& unexpected, 398 const std::set<CPUFeatures::Feature>& expected) { 399 // Print a helpful diagnostic before checking the result. 400 typedef std::set<CPUFeatures::Feature>::const_iterator It; 401 if (!unexpected.empty()) { 402 std::cout << "Unexpected features:\n"; 403 for (It it = unexpected.begin(); it != unexpected.end(); ++it) { 404 std::cout << " " << *it << "\n"; 405 } 406 } 407 if (!expected.empty()) { 408 std::cout << "Missing features:\n"; 409 for (It it = expected.begin(); it != expected.end(); ++it) { 410 std::cout << " " << *it << "\n"; 411 } 412 } 413 VIXL_CHECK(unexpected.empty() && expected.empty()); 414 } 415 416 417 TEST(CPUFeatures_predefined_legacy) { 418 CPUFeatures f = CPUFeatures::AArch64LegacyBaseline(); 419 std::set<CPUFeatures::Feature> unexpected; 420 std::set<CPUFeatures::Feature> expected; 421 expected.insert(CPUFeatures::kFP); 422 expected.insert(CPUFeatures::kNEON); 423 expected.insert(CPUFeatures::kCRC32); 424 425 for (CPUFeatures::const_iterator it = f.begin(); it != f.end(); ++it) { 426 if (expected.erase(*it) == 0) unexpected.insert(*it); 427 } 428 CPUFeaturesPredefinedResultCheckHelper(unexpected, expected); 429 } 430 431 432 TEST(CPUFeatures_predefined_all) { 433 CPUFeatures f = CPUFeatures::All(); 434 std::set<CPUFeatures::Feature> found; 435 436 for (CPUFeatures::const_iterator it = f.begin(); it != f.end(); ++it) { 437 found.insert(*it); 438 } 439 VIXL_CHECK(found.size() == CPUFeatures::kNumberOfFeatures); 440 } 441 442 // The CPUFeaturesScope constructor is templated, and needs an object which 443 // implements `CPUFeatures* GetCPUFeatures()`. This is normally something like 444 // the Assembler, but for the tests we use an architecture-independent wrapper. 445 class GetCPUFeaturesWrapper { 446 public: 447 explicit GetCPUFeaturesWrapper(CPUFeatures* cpu_features) 448 : cpu_features_(cpu_features) {} 449 450 CPUFeatures* GetCPUFeatures() const { return cpu_features_; } 451 452 private: 453 CPUFeatures* cpu_features_; 454 }; 455 456 TEST(CPUFeaturesScope) { 457 // Test that CPUFeaturesScope properly preserves state. 458 459 CPUFeatures cpu(CPUFeatures::kCRC32, CPUFeatures::kSHA1, CPUFeatures::kAES); 460 GetCPUFeaturesWrapper top_level(&cpu); 461 462 const CPUFeatures original_outer = cpu; 463 464 { // Test setting both new and existing features. 465 CPUFeaturesScope outer(&top_level, CPUFeatures::kSHA2, CPUFeatures::kAES); 466 VIXL_CHECK(outer.GetCPUFeatures() == &cpu); 467 VIXL_CHECK(cpu.Has(CPUFeatures::kCRC32, 468 CPUFeatures::kSHA1, 469 CPUFeatures::kSHA2, 470 CPUFeatures::kAES)); 471 472 // Features can be added or removed directly, in the usual fashion. 473 // (The scope will restore their original status when it ends.) 474 cpu.Combine(CPUFeatures::kSHA1, CPUFeatures::kAtomics); 475 VIXL_CHECK(cpu.Has(CPUFeatures::kCRC32, 476 CPUFeatures::kSHA1, 477 CPUFeatures::kSHA2, 478 CPUFeatures::kAES)); 479 VIXL_CHECK(cpu.Has(CPUFeatures::kAtomics)); 480 481 cpu.Remove(CPUFeatures::kSHA2, CPUFeatures::kAES); 482 VIXL_CHECK(!cpu.Has(CPUFeatures::kSHA2, CPUFeatures::kAES)); 483 VIXL_CHECK(cpu.Has(CPUFeatures::kCRC32, 484 CPUFeatures::kSHA1, 485 CPUFeatures::kAtomics)); 486 487 const CPUFeatures original_inner = cpu; 488 489 // Scopes can be nested. 490 { 491 // A CPUFeaturesScope can be constructed from a CPUFeatures*, or any 492 // (non-local) object that implements `CPUFeatures* GetCPUFeatures()`. 493 // Typically, this would be an Assembler or MacroAssembler, but 494 // CPUFeatureScope itself provides this method, and allows the test to 495 // remain architecture-agnostic. 496 497 CPUFeatures auth(CPUFeatures::kPAuth, 498 CPUFeatures::kPAuthQARMA, 499 CPUFeatures::kPAuthGeneric, 500 CPUFeatures::kPAuthGenericQARMA); 501 502 CPUFeaturesScope inner(&outer, auth); 503 VIXL_CHECK(inner.GetCPUFeatures() == &cpu); 504 VIXL_CHECK(cpu.Has(auth.With(CPUFeatures::kCRC32, 505 CPUFeatures::kSHA1, 506 CPUFeatures::kAtomics))); 507 } 508 // Check for equivalence. 509 VIXL_CHECK(cpu.Has(original_inner)); 510 VIXL_CHECK(original_inner.Has(cpu)); 511 } 512 513 // Check for equivalence. 514 VIXL_CHECK(cpu.Has(original_outer)); 515 VIXL_CHECK(original_outer.Has(cpu)); 516 } 517 518 } // namespace vixl 519