blob: 9b3d55dd6427891f129c6322b35f763dcce03bb2 [file] [log] [blame]
Pierre Langloisefe0c1f2016-11-24 11:54:47 +00001// 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
Jacob Bramley2af191d2018-05-16 10:22:44 +010027#include <iostream>
28#include <set>
29#include <sstream>
30#include <vector>
31
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000032#include "test-runner.h"
33
Jacob Bramley2af191d2018-05-16 10:22:44 +010034#include "cpu-features.h"
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000035#include "utils-vixl.h"
36
Jacob Bramley2af191d2018-05-16 10:22:44 +010037#if __cplusplus >= 201103L
38#include <type_traits>
39#endif
40
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000041#define TEST(name) TEST_(API_##name)
42
43#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
44
45namespace vixl {
46
47// Describe the result of a test. Should IsUintN() and IsIntN() return true or
48// false for N and X?
49template <typename T>
50struct 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.
58TEST(IsUint_IsInt) {
59 UintIntTest<uint32_t> test_little_values_unsigned[] = {
Pierre Langlois1bce0072017-06-06 17:58:58 +010060 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000068
Pierre Langlois1bce0072017-06-06 17:58:58 +010069 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000077 };
78
79 UintIntTest<int32_t> test_little_values_signed[] = {
Pierre Langlois1bce0072017-06-06 17:58:58 +010080 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000088
Pierre Langlois1bce0072017-06-06 17:58:58 +010089 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +000097 };
98
99 UintIntTest<uint32_t> test_u16[] = {
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000100 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000108 };
109
110 UintIntTest<int32_t> test_i16[] = {
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000111 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000119 };
120
121 UintIntTest<uint64_t> test_u32[] = {
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000122 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000126 };
127
128 UintIntTest<int64_t> test_i32[] = {
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000129 {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))
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000135 };
136
137 UintIntTest<uint64_t> test_unsigned_higher_than_32[] = {
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000138 {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)},
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000142 };
143
144 UintIntTest<int64_t> test_signed_higher_than_32[] = {
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000145 {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))
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000149 };
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
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000162#define TEST_UINT(test_vector) \
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000163 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
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000171#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 } \
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000178 }
179
Pierre Langloisbde2e4b2017-01-24 17:41:26 +0000180 TEST_LIST(TEST_UINT)
181 TEST_LIST(TEST_INT)
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000182
183#undef TEST_UINT
184#undef TEST_INT
185
186#undef TEST_LIST
187}
188
Jacob Bramley2af191d2018-05-16 10:22:44 +0100189
190TEST(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
283TEST(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
335TEST(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
344static 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
357TEST(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
TatWai Chong684f5f72018-12-25 17:49:56 -0800389 "SVE, DotProduct, FPHalf, NEONHalf, RAS, DCPoP, DCCVADP, SHA3, SHA512, "
390 "SM3, SM4, "
Jacob Bramley2af191d2018-05-16 10:22:44 +0100391 // Armv8.3
Jacob Bramley4482be72018-09-14 15:57:57 +0100392 "PAuth, PAuthQARMA, PAuthGeneric, PAuthGenericQARMA, JSCVT, Fcma, RCpc, "
393 // Armv8.4
Martyn Capewellcb963f72018-10-22 15:25:28 +0100394 "RCpc (imm), FlagM, USCAT, FHM, DIT, "
395 // Armv8.5
TatWai Chong04edf682018-12-27 16:01:02 -0800396 "BTI, AXFlag, RNG",
Jacob Bramley2af191d2018-05-16 10:22:44 +0100397 CPUFeatures::All());
398}
399
400
401static void CPUFeaturesPredefinedResultCheckHelper(
402 const std::set<CPUFeatures::Feature>& unexpected,
403 const std::set<CPUFeatures::Feature>& expected) {
404 // Print a helpful diagnostic before checking the result.
405 typedef std::set<CPUFeatures::Feature>::const_iterator It;
406 if (!unexpected.empty()) {
407 std::cout << "Unexpected features:\n";
408 for (It it = unexpected.begin(); it != unexpected.end(); ++it) {
409 std::cout << " " << *it << "\n";
410 }
411 }
412 if (!expected.empty()) {
413 std::cout << "Missing features:\n";
414 for (It it = expected.begin(); it != expected.end(); ++it) {
415 std::cout << " " << *it << "\n";
416 }
417 }
418 VIXL_CHECK(unexpected.empty() && expected.empty());
419}
420
421
422TEST(CPUFeatures_predefined_legacy) {
423 CPUFeatures f = CPUFeatures::AArch64LegacyBaseline();
424 std::set<CPUFeatures::Feature> unexpected;
425 std::set<CPUFeatures::Feature> expected;
426 expected.insert(CPUFeatures::kFP);
427 expected.insert(CPUFeatures::kNEON);
428 expected.insert(CPUFeatures::kCRC32);
429
430 for (CPUFeatures::const_iterator it = f.begin(); it != f.end(); ++it) {
431 if (expected.erase(*it) == 0) unexpected.insert(*it);
432 }
433 CPUFeaturesPredefinedResultCheckHelper(unexpected, expected);
434}
435
436
437TEST(CPUFeatures_predefined_all) {
438 CPUFeatures f = CPUFeatures::All();
439 std::set<CPUFeatures::Feature> found;
440
441 for (CPUFeatures::const_iterator it = f.begin(); it != f.end(); ++it) {
442 found.insert(*it);
443 }
444 VIXL_CHECK(found.size() == CPUFeatures::kNumberOfFeatures);
445}
446
447// The CPUFeaturesScope constructor is templated, and needs an object which
448// implements `CPUFeatures* GetCPUFeatures()`. This is normally something like
449// the Assembler, but for the tests we use an architecture-independent wrapper.
450class GetCPUFeaturesWrapper {
451 public:
452 explicit GetCPUFeaturesWrapper(CPUFeatures* cpu_features)
453 : cpu_features_(cpu_features) {}
454
455 CPUFeatures* GetCPUFeatures() const { return cpu_features_; }
456
457 private:
458 CPUFeatures* cpu_features_;
459};
460
461TEST(CPUFeaturesScope) {
462 // Test that CPUFeaturesScope properly preserves state.
463
464 CPUFeatures cpu(CPUFeatures::kCRC32, CPUFeatures::kSHA1, CPUFeatures::kAES);
465 GetCPUFeaturesWrapper top_level(&cpu);
466
467 const CPUFeatures original_outer = cpu;
468
469 { // Test setting both new and existing features.
470 CPUFeaturesScope outer(&top_level, CPUFeatures::kSHA2, CPUFeatures::kAES);
471 VIXL_CHECK(outer.GetCPUFeatures() == &cpu);
472 VIXL_CHECK(cpu.Has(CPUFeatures::kCRC32,
473 CPUFeatures::kSHA1,
474 CPUFeatures::kSHA2,
475 CPUFeatures::kAES));
476
477 // Features can be added or removed directly, in the usual fashion.
478 // (The scope will restore their original status when it ends.)
479 cpu.Combine(CPUFeatures::kSHA1, CPUFeatures::kAtomics);
480 VIXL_CHECK(cpu.Has(CPUFeatures::kCRC32,
481 CPUFeatures::kSHA1,
482 CPUFeatures::kSHA2,
483 CPUFeatures::kAES));
484 VIXL_CHECK(cpu.Has(CPUFeatures::kAtomics));
485
486 cpu.Remove(CPUFeatures::kSHA2, CPUFeatures::kAES);
487 VIXL_CHECK(!cpu.Has(CPUFeatures::kSHA2, CPUFeatures::kAES));
488 VIXL_CHECK(cpu.Has(CPUFeatures::kCRC32,
489 CPUFeatures::kSHA1,
490 CPUFeatures::kAtomics));
491
492 const CPUFeatures original_inner = cpu;
493
494 // Scopes can be nested.
495 {
496 // A CPUFeaturesScope can be constructed from a CPUFeatures*, or any
497 // (non-local) object that implements `CPUFeatures* GetCPUFeatures()`.
498 // Typically, this would be an Assembler or MacroAssembler, but
499 // CPUFeatureScope itself provides this method, and allows the test to
500 // remain architecture-agnostic.
501
502 CPUFeatures auth(CPUFeatures::kPAuth,
503 CPUFeatures::kPAuthQARMA,
504 CPUFeatures::kPAuthGeneric,
505 CPUFeatures::kPAuthGenericQARMA);
506
507 CPUFeaturesScope inner(&outer, auth);
508 VIXL_CHECK(inner.GetCPUFeatures() == &cpu);
509 VIXL_CHECK(cpu.Has(auth.With(CPUFeatures::kCRC32,
510 CPUFeatures::kSHA1,
511 CPUFeatures::kAtomics)));
512 }
513 // Check for equivalence.
514 VIXL_CHECK(cpu.Has(original_inner));
515 VIXL_CHECK(original_inner.Has(cpu));
516 }
517
518 // Check for equivalence.
519 VIXL_CHECK(cpu.Has(original_outer));
520 VIXL_CHECK(original_outer.Has(cpu));
521}
522
Pierre Langloisefe0c1f2016-11-24 11:54:47 +0000523} // namespace vixl