1 // Copyright 2015, 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 "test-assembler-aarch64.h"
28
29 #include <cfloat>
30 #include <cmath>
31 #include <cstdio>
32 #include <cstdlib>
33 #include <cstring>
34 #include <sys/mman.h>
35
36 #include "test-runner.h"
37 #include "test-utils.h"
38
39 #include "aarch64/cpu-aarch64.h"
40 #include "aarch64/disasm-aarch64.h"
41 #include "aarch64/macro-assembler-aarch64.h"
42 #include "aarch64/simulator-aarch64.h"
43 #include "aarch64/test-utils-aarch64.h"
44
45 namespace vixl {
46 namespace aarch64 {
47
TEST(preshift_immediates)48 TEST(preshift_immediates) {
49 SETUP();
50
51 START();
52 // Test operations involving immediates that could be generated using a
53 // pre-shifted encodable immediate followed by a post-shift applied to
54 // the arithmetic or logical operation.
55
56 // Save sp.
57 __ Mov(x29, sp);
58
59 // Set the registers to known values.
60 __ Mov(x0, 0x1000);
61 __ Mov(sp, 0x1004);
62
63 // Arithmetic ops.
64 __ Add(x1, x0, 0x1f7de);
65 __ Add(w2, w0, 0xffffff1);
66 __ Adds(x3, x0, 0x18001);
67 __ Adds(w4, w0, 0xffffff1);
68 __ Sub(x5, x0, 0x1f7de);
69 __ Sub(w6, w0, 0xffffff1);
70 __ Subs(x7, x0, 0x18001);
71 __ Subs(w8, w0, 0xffffff1);
72
73 // Logical ops.
74 __ And(x9, x0, 0x1f7de);
75 __ Orr(w10, w0, 0xffffff1);
76 __ Eor(x11, x0, 0x18001);
77
78 // Ops using the stack pointer.
79 __ Add(sp, sp, 0x18001);
80 __ Mov(x12, sp);
81 __ Mov(sp, 0x1004);
82
83 __ Add(sp, sp, 0x1f7de);
84 __ Mov(x13, sp);
85 __ Mov(sp, 0x1004);
86
87 __ Adds(x14, sp, 0x1f7de);
88
89 __ Orr(sp, x0, 0x1f7de);
90 __ Mov(x15, sp);
91
92 // Restore sp.
93 __ Mov(sp, x29);
94 END();
95
96 if (CAN_RUN()) {
97 RUN();
98
99 ASSERT_EQUAL_64(0x1000, x0);
100 ASSERT_EQUAL_64(0x207de, x1);
101 ASSERT_EQUAL_64(0x10000ff1, x2);
102 ASSERT_EQUAL_64(0x19001, x3);
103 ASSERT_EQUAL_64(0x10000ff1, x4);
104 ASSERT_EQUAL_64(0xfffffffffffe1822, x5);
105 ASSERT_EQUAL_64(0xf000100f, x6);
106 ASSERT_EQUAL_64(0xfffffffffffe8fff, x7);
107 ASSERT_EQUAL_64(0xf000100f, x8);
108 ASSERT_EQUAL_64(0x1000, x9);
109 ASSERT_EQUAL_64(0xffffff1, x10);
110 ASSERT_EQUAL_64(0x19001, x11);
111 ASSERT_EQUAL_64(0x19005, x12);
112 ASSERT_EQUAL_64(0x207e2, x13);
113 ASSERT_EQUAL_64(0x207e2, x14);
114 ASSERT_EQUAL_64(0x1f7de, x15);
115 }
116 }
117
118
TEST(stack_ops)119 TEST(stack_ops) {
120 SETUP();
121
122 START();
123 // save sp.
124 __ Mov(x29, sp);
125
126 // Set the sp to a known value.
127 __ Mov(sp, 0x1004);
128 __ Mov(x0, sp);
129
130 // Add immediate to the sp, and move the result to a normal register.
131 __ Add(sp, sp, 0x50);
132 __ Mov(x1, sp);
133
134 // Add extended to the sp, and move the result to a normal register.
135 __ Mov(x17, 0xfff);
136 __ Add(sp, sp, Operand(x17, SXTB));
137 __ Mov(x2, sp);
138
139 // Create an sp using a logical instruction, and move to normal register.
140 __ Orr(sp, xzr, 0x1fff);
141 __ Mov(x3, sp);
142
143 // Write wsp using a logical instruction.
144 __ Orr(wsp, wzr, 0xfffffff8);
145 __ Mov(x4, sp);
146
147 // Write sp, and read back wsp.
148 __ Orr(sp, xzr, 0xfffffff8);
149 __ Mov(w5, wsp);
150
151 // Test writing into wsp in cases where the immediate isn't encodable.
152 VIXL_ASSERT(!Assembler::IsImmLogical(0x1234, kWRegSize));
153 __ Orr(wsp, w5, 0x1234);
154 __ Mov(w6, wsp);
155
156 // restore sp.
157 __ Mov(sp, x29);
158 END();
159
160 if (CAN_RUN()) {
161 RUN();
162
163 ASSERT_EQUAL_64(0x1004, x0);
164 ASSERT_EQUAL_64(0x1054, x1);
165 ASSERT_EQUAL_64(0x1053, x2);
166 ASSERT_EQUAL_64(0x1fff, x3);
167 ASSERT_EQUAL_64(0xfffffff8, x4);
168 ASSERT_EQUAL_64(0xfffffff8, x5);
169 ASSERT_EQUAL_64(0xfffffffc, x6);
170 }
171 }
172
173
TEST(mvn)174 TEST(mvn) {
175 SETUP();
176
177 START();
178 __ Mvn(w0, 0xfff);
179 __ Mvn(x1, 0xfff);
180 __ Mvn(w2, Operand(w0, LSL, 1));
181 __ Mvn(x3, Operand(x1, LSL, 2));
182 __ Mvn(w4, Operand(w0, LSR, 3));
183 __ Mvn(x5, Operand(x1, LSR, 4));
184 __ Mvn(w6, Operand(w0, ASR, 11));
185 __ Mvn(x7, Operand(x1, ASR, 12));
186 __ Mvn(w8, Operand(w0, ROR, 13));
187 __ Mvn(x9, Operand(x1, ROR, 14));
188 __ Mvn(w10, Operand(w2, UXTB));
189 __ Mvn(x11, Operand(x2, SXTB, 1));
190 __ Mvn(w12, Operand(w2, UXTH, 2));
191 __ Mvn(x13, Operand(x2, SXTH, 3));
192 __ Mvn(x14, Operand(w2, UXTW, 4));
193 __ Mvn(x15, Operand(w2, SXTW, 4));
194 END();
195
196 if (CAN_RUN()) {
197 RUN();
198
199 ASSERT_EQUAL_64(0xfffff000, x0);
200 ASSERT_EQUAL_64(0xfffffffffffff000, x1);
201 ASSERT_EQUAL_64(0x00001fff, x2);
202 ASSERT_EQUAL_64(0x0000000000003fff, x3);
203 ASSERT_EQUAL_64(0xe00001ff, x4);
204 ASSERT_EQUAL_64(0xf0000000000000ff, x5);
205 ASSERT_EQUAL_64(0x00000001, x6);
206 ASSERT_EQUAL_64(0x0000000000000000, x7);
207 ASSERT_EQUAL_64(0x7ff80000, x8);
208 ASSERT_EQUAL_64(0x3ffc000000000000, x9);
209 ASSERT_EQUAL_64(0xffffff00, x10);
210 ASSERT_EQUAL_64(0x0000000000000001, x11);
211 ASSERT_EQUAL_64(0xffff8003, x12);
212 ASSERT_EQUAL_64(0xffffffffffff0007, x13);
213 ASSERT_EQUAL_64(0xfffffffffffe000f, x14);
214 ASSERT_EQUAL_64(0xfffffffffffe000f, x15);
215 }
216 }
217
218
TEST(mov_imm_w)219 TEST(mov_imm_w) {
220 SETUP();
221
222 START();
223 __ Mov(w0, 0xffffffff);
224 __ Mov(w1, 0xffff1234);
225 __ Mov(w2, 0x1234ffff);
226 __ Mov(w3, 0x00000000);
227 __ Mov(w4, 0x00001234);
228 __ Mov(w5, 0x12340000);
229 __ Mov(w6, 0x12345678);
230 __ Mov(w7, (int32_t)0x80000000);
231 __ Mov(w8, (int32_t)0xffff0000);
232 __ Mov(w9, kWMinInt);
233 END();
234
235 if (CAN_RUN()) {
236 RUN();
237
238 ASSERT_EQUAL_64(0xffffffff, x0);
239 ASSERT_EQUAL_64(0xffff1234, x1);
240 ASSERT_EQUAL_64(0x1234ffff, x2);
241 ASSERT_EQUAL_64(0x00000000, x3);
242 ASSERT_EQUAL_64(0x00001234, x4);
243 ASSERT_EQUAL_64(0x12340000, x5);
244 ASSERT_EQUAL_64(0x12345678, x6);
245 ASSERT_EQUAL_64(0x80000000, x7);
246 ASSERT_EQUAL_64(0xffff0000, x8);
247 ASSERT_EQUAL_32(kWMinInt, w9);
248 }
249 }
250
251
TEST(mov_imm_x)252 TEST(mov_imm_x) {
253 SETUP();
254
255 START();
256 __ Mov(x0, 0xffffffffffffffff);
257 __ Mov(x1, 0xffffffffffff1234);
258 __ Mov(x2, 0xffffffff12345678);
259 __ Mov(x3, 0xffff1234ffff5678);
260 __ Mov(x4, 0x1234ffffffff5678);
261 __ Mov(x5, 0x1234ffff5678ffff);
262 __ Mov(x6, 0x12345678ffffffff);
263 __ Mov(x7, 0x1234ffffffffffff);
264 __ Mov(x8, 0x123456789abcffff);
265 __ Mov(x9, 0x12345678ffff9abc);
266 __ Mov(x10, 0x1234ffff56789abc);
267 __ Mov(x11, 0xffff123456789abc);
268 __ Mov(x12, 0x0000000000000000);
269 __ Mov(x13, 0x0000000000001234);
270 __ Mov(x14, 0x0000000012345678);
271 __ Mov(x15, 0x0000123400005678);
272 __ Mov(x18, 0x1234000000005678);
273 __ Mov(x19, 0x1234000056780000);
274 __ Mov(x20, 0x1234567800000000);
275 __ Mov(x21, 0x1234000000000000);
276 __ Mov(x22, 0x123456789abc0000);
277 __ Mov(x23, 0x1234567800009abc);
278 __ Mov(x24, 0x1234000056789abc);
279 __ Mov(x25, 0x0000123456789abc);
280 __ Mov(x26, 0x123456789abcdef0);
281 __ Mov(x27, 0xffff000000000001);
282 __ Mov(x28, 0x8000ffff00000000);
283 END();
284
285 if (CAN_RUN()) {
286 RUN();
287
288 ASSERT_EQUAL_64(0xffffffffffff1234, x1);
289 ASSERT_EQUAL_64(0xffffffff12345678, x2);
290 ASSERT_EQUAL_64(0xffff1234ffff5678, x3);
291 ASSERT_EQUAL_64(0x1234ffffffff5678, x4);
292 ASSERT_EQUAL_64(0x1234ffff5678ffff, x5);
293 ASSERT_EQUAL_64(0x12345678ffffffff, x6);
294 ASSERT_EQUAL_64(0x1234ffffffffffff, x7);
295 ASSERT_EQUAL_64(0x123456789abcffff, x8);
296 ASSERT_EQUAL_64(0x12345678ffff9abc, x9);
297 ASSERT_EQUAL_64(0x1234ffff56789abc, x10);
298 ASSERT_EQUAL_64(0xffff123456789abc, x11);
299 ASSERT_EQUAL_64(0x0000000000000000, x12);
300 ASSERT_EQUAL_64(0x0000000000001234, x13);
301 ASSERT_EQUAL_64(0x0000000012345678, x14);
302 ASSERT_EQUAL_64(0x0000123400005678, x15);
303 ASSERT_EQUAL_64(0x1234000000005678, x18);
304 ASSERT_EQUAL_64(0x1234000056780000, x19);
305 ASSERT_EQUAL_64(0x1234567800000000, x20);
306 ASSERT_EQUAL_64(0x1234000000000000, x21);
307 ASSERT_EQUAL_64(0x123456789abc0000, x22);
308 ASSERT_EQUAL_64(0x1234567800009abc, x23);
309 ASSERT_EQUAL_64(0x1234000056789abc, x24);
310 ASSERT_EQUAL_64(0x0000123456789abc, x25);
311 ASSERT_EQUAL_64(0x123456789abcdef0, x26);
312 ASSERT_EQUAL_64(0xffff000000000001, x27);
313 ASSERT_EQUAL_64(0x8000ffff00000000, x28);
314 }
315 }
316
317
TEST(mov)318 TEST(mov) {
319 SETUP();
320
321 START();
322 __ Mov(x0, 0xffffffffffffffff);
323 __ Mov(x1, 0xffffffffffffffff);
324 __ Mov(x2, 0xffffffffffffffff);
325 __ Mov(x3, 0xffffffffffffffff);
326
327 __ Mov(x0, 0x0123456789abcdef);
328
329 {
330 ExactAssemblyScope scope(&masm, 3 * kInstructionSize);
331 __ movz(x1, UINT64_C(0xabcd) << 16);
332 __ movk(x2, UINT64_C(0xabcd) << 32);
333 __ movn(x3, UINT64_C(0xabcd) << 48);
334 }
335
336 __ Mov(x4, 0x0123456789abcdef);
337 __ Mov(x5, x4);
338
339 __ Mov(w6, -1);
340
341 // Test that moves back to the same register have the desired effect. This
342 // is a no-op for X registers, and a truncation for W registers.
343 __ Mov(x7, 0x0123456789abcdef);
344 __ Mov(x7, x7);
345 __ Mov(x8, 0x0123456789abcdef);
346 __ Mov(w8, w8);
347 __ Mov(x9, 0x0123456789abcdef);
348 __ Mov(x9, Operand(x9));
349 __ Mov(x10, 0x0123456789abcdef);
350 __ Mov(w10, Operand(w10));
351
352 __ Mov(w11, 0xfff);
353 __ Mov(x12, 0xfff);
354 __ Mov(w13, Operand(w11, LSL, 1));
355 __ Mov(x14, Operand(x12, LSL, 2));
356 __ Mov(w15, Operand(w11, LSR, 3));
357 __ Mov(x18, Operand(x12, LSR, 4));
358 __ Mov(w19, Operand(w11, ASR, 11));
359 __ Mov(x20, Operand(x12, ASR, 12));
360 __ Mov(w21, Operand(w11, ROR, 13));
361 __ Mov(x22, Operand(x12, ROR, 14));
362 __ Mov(w23, Operand(w13, UXTB));
363 __ Mov(x24, Operand(x13, SXTB, 1));
364 __ Mov(w25, Operand(w13, UXTH, 2));
365 __ Mov(x26, Operand(x13, SXTH, 3));
366 __ Mov(x27, Operand(w13, UXTW, 4));
367
368 __ Mov(x28, 0x0123456789abcdef);
369 __ Mov(w28, w28, kDiscardForSameWReg);
370 END();
371
372 if (CAN_RUN()) {
373 RUN();
374
375 ASSERT_EQUAL_64(0x0123456789abcdef, x0);
376 ASSERT_EQUAL_64(0x00000000abcd0000, x1);
377 ASSERT_EQUAL_64(0xffffabcdffffffff, x2);
378 ASSERT_EQUAL_64(0x5432ffffffffffff, x3);
379 ASSERT_EQUAL_64(x4, x5);
380 ASSERT_EQUAL_32(-1, w6);
381 ASSERT_EQUAL_64(0x0123456789abcdef, x7);
382 ASSERT_EQUAL_32(0x89abcdef, w8);
383 ASSERT_EQUAL_64(0x0123456789abcdef, x9);
384 ASSERT_EQUAL_32(0x89abcdef, w10);
385 ASSERT_EQUAL_64(0x00000fff, x11);
386 ASSERT_EQUAL_64(0x0000000000000fff, x12);
387 ASSERT_EQUAL_64(0x00001ffe, x13);
388 ASSERT_EQUAL_64(0x0000000000003ffc, x14);
389 ASSERT_EQUAL_64(0x000001ff, x15);
390 ASSERT_EQUAL_64(0x00000000000000ff, x18);
391 ASSERT_EQUAL_64(0x00000001, x19);
392 ASSERT_EQUAL_64(0x0000000000000000, x20);
393 ASSERT_EQUAL_64(0x7ff80000, x21);
394 ASSERT_EQUAL_64(0x3ffc000000000000, x22);
395 ASSERT_EQUAL_64(0x000000fe, x23);
396 ASSERT_EQUAL_64(0xfffffffffffffffc, x24);
397 ASSERT_EQUAL_64(0x00007ff8, x25);
398 ASSERT_EQUAL_64(0x000000000000fff0, x26);
399 ASSERT_EQUAL_64(0x000000000001ffe0, x27);
400 ASSERT_EQUAL_64(0x0123456789abcdef, x28);
401 }
402 }
403
404
TEST(mov_negative)405 TEST(mov_negative) {
406 SETUP();
407
408 START();
409 __ Mov(w11, 0xffffffff);
410 __ Mov(x12, 0xffffffffffffffff);
411
412 __ Mov(w13, Operand(w11, LSL, 1));
413 __ Mov(w14, Operand(w11, LSR, 1));
414 __ Mov(w15, Operand(w11, ASR, 1));
415 __ Mov(w18, Operand(w11, ROR, 1));
416 __ Mov(w19, Operand(w11, UXTB, 1));
417 __ Mov(w20, Operand(w11, SXTB, 1));
418 __ Mov(w21, Operand(w11, UXTH, 1));
419 __ Mov(w22, Operand(w11, SXTH, 1));
420
421 __ Mov(x23, Operand(x12, LSL, 1));
422 __ Mov(x24, Operand(x12, LSR, 1));
423 __ Mov(x25, Operand(x12, ASR, 1));
424 __ Mov(x26, Operand(x12, ROR, 1));
425 __ Mov(x27, Operand(x12, UXTH, 1));
426 __ Mov(x28, Operand(x12, SXTH, 1));
427 __ Mov(x29, Operand(x12, UXTW, 1));
428 __ Mov(x30, Operand(x12, SXTW, 1));
429 END();
430
431 if (CAN_RUN()) {
432 RUN();
433
434 ASSERT_EQUAL_64(0xfffffffe, x13);
435 ASSERT_EQUAL_64(0x7fffffff, x14);
436 ASSERT_EQUAL_64(0xffffffff, x15);
437 ASSERT_EQUAL_64(0xffffffff, x18);
438 ASSERT_EQUAL_64(0x000001fe, x19);
439 ASSERT_EQUAL_64(0xfffffffe, x20);
440 ASSERT_EQUAL_64(0x0001fffe, x21);
441 ASSERT_EQUAL_64(0xfffffffe, x22);
442
443 ASSERT_EQUAL_64(0xfffffffffffffffe, x23);
444 ASSERT_EQUAL_64(0x7fffffffffffffff, x24);
445 ASSERT_EQUAL_64(0xffffffffffffffff, x25);
446 ASSERT_EQUAL_64(0xffffffffffffffff, x26);
447 ASSERT_EQUAL_64(0x000000000001fffe, x27);
448 ASSERT_EQUAL_64(0xfffffffffffffffe, x28);
449 ASSERT_EQUAL_64(0x00000001fffffffe, x29);
450 ASSERT_EQUAL_64(0xfffffffffffffffe, x30);
451 }
452 }
453
454
TEST(orr)455 TEST(orr) {
456 SETUP();
457
458 START();
459 __ Mov(x0, 0xf0f0);
460 __ Mov(x1, 0xf00000ff);
461
462 __ Orr(x2, x0, Operand(x1));
463 __ Orr(w3, w0, Operand(w1, LSL, 28));
464 __ Orr(x4, x0, Operand(x1, LSL, 32));
465 __ Orr(x5, x0, Operand(x1, LSR, 4));
466 __ Orr(w6, w0, Operand(w1, ASR, 4));
467 __ Orr(x7, x0, Operand(x1, ASR, 4));
468 __ Orr(w8, w0, Operand(w1, ROR, 12));
469 __ Orr(x9, x0, Operand(x1, ROR, 12));
470 __ Orr(w10, w0, 0xf);
471 __ Orr(x11, x0, 0xf0000000f0000000);
472 END();
473
474 if (CAN_RUN()) {
475 RUN();
476
477 ASSERT_EQUAL_64(0x00000000f000f0ff, x2);
478 ASSERT_EQUAL_64(0xf000f0f0, x3);
479 ASSERT_EQUAL_64(0xf00000ff0000f0f0, x4);
480 ASSERT_EQUAL_64(0x000000000f00f0ff, x5);
481 ASSERT_EQUAL_64(0xff00f0ff, x6);
482 ASSERT_EQUAL_64(0x000000000f00f0ff, x7);
483 ASSERT_EQUAL_64(0x0ffff0f0, x8);
484 ASSERT_EQUAL_64(0x0ff00000000ff0f0, x9);
485 ASSERT_EQUAL_64(0x0000f0ff, x10);
486 ASSERT_EQUAL_64(0xf0000000f000f0f0, x11);
487 }
488 }
489
490
TEST(orr_extend)491 TEST(orr_extend) {
492 SETUP();
493
494 START();
495 __ Mov(x0, 1);
496 __ Mov(x1, 0x8000000080008080);
497 __ Orr(w6, w0, Operand(w1, UXTB));
498 __ Orr(x7, x0, Operand(x1, UXTH, 1));
499 __ Orr(w8, w0, Operand(w1, UXTW, 2));
500 __ Orr(x9, x0, Operand(x1, UXTX, 3));
501 __ Orr(w10, w0, Operand(w1, SXTB));
502 __ Orr(x11, x0, Operand(x1, SXTH, 1));
503 __ Orr(x12, x0, Operand(x1, SXTW, 2));
504 __ Orr(x13, x0, Operand(x1, SXTX, 3));
505 END();
506
507 if (CAN_RUN()) {
508 RUN();
509
510 ASSERT_EQUAL_64(0x00000081, x6);
511 ASSERT_EQUAL_64(0x0000000000010101, x7);
512 ASSERT_EQUAL_64(0x00020201, x8);
513 ASSERT_EQUAL_64(0x0000000400040401, x9);
514 ASSERT_EQUAL_64(0xffffff81, x10);
515 ASSERT_EQUAL_64(0xffffffffffff0101, x11);
516 ASSERT_EQUAL_64(0xfffffffe00020201, x12);
517 ASSERT_EQUAL_64(0x0000000400040401, x13);
518 }
519 }
520
521
TEST(bitwise_wide_imm)522 TEST(bitwise_wide_imm) {
523 SETUP();
524
525 START();
526 __ Mov(x0, 0);
527 __ Mov(x1, 0xf0f0f0f0f0f0f0f0);
528
529 __ Orr(x10, x0, 0x1234567890abcdef);
530 __ Orr(w11, w1, 0x90abcdef);
531
532 __ Orr(w12, w0, kWMinInt);
533 __ Eor(w13, w0, kWMinInt);
534 END();
535
536 if (CAN_RUN()) {
537 RUN();
538
539 ASSERT_EQUAL_64(0, x0);
540 ASSERT_EQUAL_64(0xf0f0f0f0f0f0f0f0, x1);
541 ASSERT_EQUAL_64(0x1234567890abcdef, x10);
542 ASSERT_EQUAL_64(0x00000000f0fbfdff, x11);
543 ASSERT_EQUAL_32(kWMinInt, w12);
544 ASSERT_EQUAL_32(kWMinInt, w13);
545 }
546 }
547
548
TEST(orn)549 TEST(orn) {
550 SETUP();
551
552 START();
553 __ Mov(x0, 0xf0f0);
554 __ Mov(x1, 0xf00000ff);
555
556 __ Orn(x2, x0, Operand(x1));
557 __ Orn(w3, w0, Operand(w1, LSL, 4));
558 __ Orn(x4, x0, Operand(x1, LSL, 4));
559 __ Orn(x5, x0, Operand(x1, LSR, 1));
560 __ Orn(w6, w0, Operand(w1, ASR, 1));
561 __ Orn(x7, x0, Operand(x1, ASR, 1));
562 __ Orn(w8, w0, Operand(w1, ROR, 16));
563 __ Orn(x9, x0, Operand(x1, ROR, 16));
564 __ Orn(w10, w0, 0x0000ffff);
565 __ Orn(x11, x0, 0x0000ffff0000ffff);
566 END();
567
568 if (CAN_RUN()) {
569 RUN();
570
571 ASSERT_EQUAL_64(0xffffffff0ffffff0, x2);
572 ASSERT_EQUAL_64(0xfffff0ff, x3);
573 ASSERT_EQUAL_64(0xfffffff0fffff0ff, x4);
574 ASSERT_EQUAL_64(0xffffffff87fffff0, x5);
575 ASSERT_EQUAL_64(0x07fffff0, x6);
576 ASSERT_EQUAL_64(0xffffffff87fffff0, x7);
577 ASSERT_EQUAL_64(0xff00ffff, x8);
578 ASSERT_EQUAL_64(0xff00ffffffffffff, x9);
579 ASSERT_EQUAL_64(0xfffff0f0, x10);
580 ASSERT_EQUAL_64(0xffff0000fffff0f0, x11);
581 }
582 }
583
584
TEST(orn_extend)585 TEST(orn_extend) {
586 SETUP();
587
588 START();
589 __ Mov(x0, 1);
590 __ Mov(x1, 0x8000000080008081);
591 __ Orn(w6, w0, Operand(w1, UXTB));
592 __ Orn(x7, x0, Operand(x1, UXTH, 1));
593 __ Orn(w8, w0, Operand(w1, UXTW, 2));
594 __ Orn(x9, x0, Operand(x1, UXTX, 3));
595 __ Orn(w10, w0, Operand(w1, SXTB));
596 __ Orn(x11, x0, Operand(x1, SXTH, 1));
597 __ Orn(x12, x0, Operand(x1, SXTW, 2));
598 __ Orn(x13, x0, Operand(x1, SXTX, 3));
599 END();
600
601 if (CAN_RUN()) {
602 RUN();
603
604 ASSERT_EQUAL_64(0xffffff7f, x6);
605 ASSERT_EQUAL_64(0xfffffffffffefefd, x7);
606 ASSERT_EQUAL_64(0xfffdfdfb, x8);
607 ASSERT_EQUAL_64(0xfffffffbfffbfbf7, x9);
608 ASSERT_EQUAL_64(0x0000007f, x10);
609 ASSERT_EQUAL_64(0x000000000000fefd, x11);
610 ASSERT_EQUAL_64(0x00000001fffdfdfb, x12);
611 ASSERT_EQUAL_64(0xfffffffbfffbfbf7, x13);
612 }
613 }
614
615
TEST(and_)616 TEST(and_) {
617 SETUP();
618
619 START();
620 __ Mov(x0, 0xfff0);
621 __ Mov(x1, 0xf00000ff);
622
623 __ And(x2, x0, Operand(x1));
624 __ And(w3, w0, Operand(w1, LSL, 4));
625 __ And(x4, x0, Operand(x1, LSL, 4));
626 __ And(x5, x0, Operand(x1, LSR, 1));
627 __ And(w6, w0, Operand(w1, ASR, 20));
628 __ And(x7, x0, Operand(x1, ASR, 20));
629 __ And(w8, w0, Operand(w1, ROR, 28));
630 __ And(x9, x0, Operand(x1, ROR, 28));
631 __ And(w10, w0, Operand(0xff00));
632 __ And(x11, x0, Operand(0xff));
633 END();
634
635 if (CAN_RUN()) {
636 RUN();
637
638 ASSERT_EQUAL_64(0x000000f0, x2);
639 ASSERT_EQUAL_64(0x00000ff0, x3);
640 ASSERT_EQUAL_64(0x00000ff0, x4);
641 ASSERT_EQUAL_64(0x00000070, x5);
642 ASSERT_EQUAL_64(0x0000ff00, x6);
643 ASSERT_EQUAL_64(0x00000f00, x7);
644 ASSERT_EQUAL_64(0x00000ff0, x8);
645 ASSERT_EQUAL_64(0x00000000, x9);
646 ASSERT_EQUAL_64(0x0000ff00, x10);
647 ASSERT_EQUAL_64(0x000000f0, x11);
648 }
649 }
650
651
TEST(and_extend)652 TEST(and_extend) {
653 SETUP();
654
655 START();
656 __ Mov(x0, 0xffffffffffffffff);
657 __ Mov(x1, 0x8000000080008081);
658 __ And(w6, w0, Operand(w1, UXTB));
659 __ And(x7, x0, Operand(x1, UXTH, 1));
660 __ And(w8, w0, Operand(w1, UXTW, 2));
661 __ And(x9, x0, Operand(x1, UXTX, 3));
662 __ And(w10, w0, Operand(w1, SXTB));
663 __ And(x11, x0, Operand(x1, SXTH, 1));
664 __ And(x12, x0, Operand(x1, SXTW, 2));
665 __ And(x13, x0, Operand(x1, SXTX, 3));
666 END();
667
668 if (CAN_RUN()) {
669 RUN();
670
671 ASSERT_EQUAL_64(0x00000081, x6);
672 ASSERT_EQUAL_64(0x0000000000010102, x7);
673 ASSERT_EQUAL_64(0x00020204, x8);
674 ASSERT_EQUAL_64(0x0000000400040408, x9);
675 ASSERT_EQUAL_64(0xffffff81, x10);
676 ASSERT_EQUAL_64(0xffffffffffff0102, x11);
677 ASSERT_EQUAL_64(0xfffffffe00020204, x12);
678 ASSERT_EQUAL_64(0x0000000400040408, x13);
679 }
680 }
681
682
TEST(ands)683 TEST(ands) {
684 SETUP();
685
686 START();
687 __ Mov(x1, 0xf00000ff);
688 __ Ands(w0, w1, Operand(w1));
689 END();
690
691 if (CAN_RUN()) {
692 RUN();
693
694 ASSERT_EQUAL_NZCV(NFlag);
695 ASSERT_EQUAL_64(0xf00000ff, x0);
696 }
697
698 START();
699 __ Mov(x0, 0xfff0);
700 __ Mov(x1, 0xf00000ff);
701 __ Ands(w0, w0, Operand(w1, LSR, 4));
702 END();
703
704 if (CAN_RUN()) {
705 RUN();
706
707 ASSERT_EQUAL_NZCV(ZFlag);
708 ASSERT_EQUAL_64(0x00000000, x0);
709 }
710
711 START();
712 __ Mov(x0, 0x8000000000000000);
713 __ Mov(x1, 0x00000001);
714 __ Ands(x0, x0, Operand(x1, ROR, 1));
715 END();
716
717 if (CAN_RUN()) {
718 RUN();
719
720 ASSERT_EQUAL_NZCV(NFlag);
721 ASSERT_EQUAL_64(0x8000000000000000, x0);
722 }
723
724 START();
725 __ Mov(x0, 0xfff0);
726 __ Ands(w0, w0, Operand(0xf));
727 END();
728
729 if (CAN_RUN()) {
730 RUN();
731
732 ASSERT_EQUAL_NZCV(ZFlag);
733 ASSERT_EQUAL_64(0x00000000, x0);
734 }
735
736 START();
737 __ Mov(x0, 0xff000000);
738 __ Ands(w0, w0, Operand(0x80000000));
739 END();
740
741 if (CAN_RUN()) {
742 RUN();
743
744 ASSERT_EQUAL_NZCV(NFlag);
745 ASSERT_EQUAL_64(0x80000000, x0);
746 }
747 }
748
749
TEST(bic)750 TEST(bic) {
751 SETUP();
752
753 START();
754 __ Mov(x0, 0xfff0);
755 __ Mov(x1, 0xf00000ff);
756
757 __ Bic(x2, x0, Operand(x1));
758 __ Bic(w3, w0, Operand(w1, LSL, 4));
759 __ Bic(x4, x0, Operand(x1, LSL, 4));
760 __ Bic(x5, x0, Operand(x1, LSR, 1));
761 __ Bic(w6, w0, Operand(w1, ASR, 20));
762 __ Bic(x7, x0, Operand(x1, ASR, 20));
763 __ Bic(w8, w0, Operand(w1, ROR, 28));
764 __ Bic(x9, x0, Operand(x1, ROR, 24));
765 __ Bic(x10, x0, Operand(0x1f));
766 __ Bic(x11, x0, Operand(0x100));
767
768 // Test bic into sp when the constant cannot be encoded in the immediate
769 // field.
770 // Use x20 to preserve sp. We check for the result via x21 because the
771 // test infrastructure requires that sp be restored to its original value.
772 __ Mov(x20, sp);
773 __ Mov(x0, 0xffffff);
774 __ Bic(sp, x0, Operand(0xabcdef));
775 __ Mov(x21, sp);
776 __ Mov(sp, x20);
777 END();
778
779 if (CAN_RUN()) {
780 RUN();
781
782 ASSERT_EQUAL_64(0x0000ff00, x2);
783 ASSERT_EQUAL_64(0x0000f000, x3);
784 ASSERT_EQUAL_64(0x0000f000, x4);
785 ASSERT_EQUAL_64(0x0000ff80, x5);
786 ASSERT_EQUAL_64(0x000000f0, x6);
787 ASSERT_EQUAL_64(0x0000f0f0, x7);
788 ASSERT_EQUAL_64(0x0000f000, x8);
789 ASSERT_EQUAL_64(0x0000ff00, x9);
790 ASSERT_EQUAL_64(0x0000ffe0, x10);
791 ASSERT_EQUAL_64(0x0000fef0, x11);
792
793 ASSERT_EQUAL_64(0x543210, x21);
794 }
795 }
796
797
TEST(bic_extend)798 TEST(bic_extend) {
799 SETUP();
800
801 START();
802 __ Mov(x0, 0xffffffffffffffff);
803 __ Mov(x1, 0x8000000080008081);
804 __ Bic(w6, w0, Operand(w1, UXTB));
805 __ Bic(x7, x0, Operand(x1, UXTH, 1));
806 __ Bic(w8, w0, Operand(w1, UXTW, 2));
807 __ Bic(x9, x0, Operand(x1, UXTX, 3));
808 __ Bic(w10, w0, Operand(w1, SXTB));
809 __ Bic(x11, x0, Operand(x1, SXTH, 1));
810 __ Bic(x12, x0, Operand(x1, SXTW, 2));
811 __ Bic(x13, x0, Operand(x1, SXTX, 3));
812 END();
813
814 if (CAN_RUN()) {
815 RUN();
816
817 ASSERT_EQUAL_64(0xffffff7e, x6);
818 ASSERT_EQUAL_64(0xfffffffffffefefd, x7);
819 ASSERT_EQUAL_64(0xfffdfdfb, x8);
820 ASSERT_EQUAL_64(0xfffffffbfffbfbf7, x9);
821 ASSERT_EQUAL_64(0x0000007e, x10);
822 ASSERT_EQUAL_64(0x000000000000fefd, x11);
823 ASSERT_EQUAL_64(0x00000001fffdfdfb, x12);
824 ASSERT_EQUAL_64(0xfffffffbfffbfbf7, x13);
825 }
826 }
827
828
TEST(bics)829 TEST(bics) {
830 SETUP();
831
832 START();
833 __ Mov(x1, 0xffff);
834 __ Bics(w0, w1, Operand(w1));
835 END();
836
837 if (CAN_RUN()) {
838 RUN();
839
840 ASSERT_EQUAL_NZCV(ZFlag);
841 ASSERT_EQUAL_64(0x00000000, x0);
842 }
843
844 START();
845 __ Mov(x0, 0xffffffff);
846 __ Bics(w0, w0, Operand(w0, LSR, 1));
847 END();
848
849 if (CAN_RUN()) {
850 RUN();
851
852 ASSERT_EQUAL_NZCV(NFlag);
853 ASSERT_EQUAL_64(0x80000000, x0);
854 }
855
856 START();
857 __ Mov(x0, 0x8000000000000000);
858 __ Mov(x1, 0x00000001);
859 __ Bics(x0, x0, Operand(x1, ROR, 1));
860 END();
861
862 if (CAN_RUN()) {
863 RUN();
864
865 ASSERT_EQUAL_NZCV(ZFlag);
866 ASSERT_EQUAL_64(0x00000000, x0);
867 }
868
869 START();
870 __ Mov(x0, 0xffffffffffffffff);
871 __ Bics(x0, x0, 0x7fffffffffffffff);
872 END();
873
874 if (CAN_RUN()) {
875 RUN();
876
877 ASSERT_EQUAL_NZCV(NFlag);
878 ASSERT_EQUAL_64(0x8000000000000000, x0);
879 }
880
881 START();
882 __ Mov(w0, 0xffff0000);
883 __ Bics(w0, w0, 0xfffffff0);
884 END();
885
886 if (CAN_RUN()) {
887 RUN();
888
889 ASSERT_EQUAL_NZCV(ZFlag);
890 ASSERT_EQUAL_64(0x00000000, x0);
891 }
892 }
893
894
TEST(eor)895 TEST(eor) {
896 SETUP();
897
898 START();
899 __ Mov(x0, 0xfff0);
900 __ Mov(x1, 0xf00000ff);
901
902 __ Eor(x2, x0, Operand(x1));
903 __ Eor(w3, w0, Operand(w1, LSL, 4));
904 __ Eor(x4, x0, Operand(x1, LSL, 4));
905 __ Eor(x5, x0, Operand(x1, LSR, 1));
906 __ Eor(w6, w0, Operand(w1, ASR, 20));
907 __ Eor(x7, x0, Operand(x1, ASR, 20));
908 __ Eor(w8, w0, Operand(w1, ROR, 28));
909 __ Eor(x9, x0, Operand(x1, ROR, 28));
910 __ Eor(w10, w0, 0xff00ff00);
911 __ Eor(x11, x0, 0xff00ff00ff00ff00);
912 END();
913
914 if (CAN_RUN()) {
915 RUN();
916
917 ASSERT_EQUAL_64(0x00000000f000ff0f, x2);
918 ASSERT_EQUAL_64(0x0000f000, x3);
919 ASSERT_EQUAL_64(0x0000000f0000f000, x4);
920 ASSERT_EQUAL_64(0x000000007800ff8f, x5);
921 ASSERT_EQUAL_64(0xffff00f0, x6);
922 ASSERT_EQUAL_64(0x000000000000f0f0, x7);
923 ASSERT_EQUAL_64(0x0000f00f, x8);
924 ASSERT_EQUAL_64(0x00000ff00000ffff, x9);
925 ASSERT_EQUAL_64(0xff0000f0, x10);
926 ASSERT_EQUAL_64(0xff00ff00ff0000f0, x11);
927 }
928 }
929
TEST(eor_extend)930 TEST(eor_extend) {
931 SETUP();
932
933 START();
934 __ Mov(x0, 0x1111111111111111);
935 __ Mov(x1, 0x8000000080008081);
936 __ Eor(w6, w0, Operand(w1, UXTB));
937 __ Eor(x7, x0, Operand(x1, UXTH, 1));
938 __ Eor(w8, w0, Operand(w1, UXTW, 2));
939 __ Eor(x9, x0, Operand(x1, UXTX, 3));
940 __ Eor(w10, w0, Operand(w1, SXTB));
941 __ Eor(x11, x0, Operand(x1, SXTH, 1));
942 __ Eor(x12, x0, Operand(x1, SXTW, 2));
943 __ Eor(x13, x0, Operand(x1, SXTX, 3));
944 END();
945
946 if (CAN_RUN()) {
947 RUN();
948
949 ASSERT_EQUAL_64(0x11111190, x6);
950 ASSERT_EQUAL_64(0x1111111111101013, x7);
951 ASSERT_EQUAL_64(0x11131315, x8);
952 ASSERT_EQUAL_64(0x1111111511151519, x9);
953 ASSERT_EQUAL_64(0xeeeeee90, x10);
954 ASSERT_EQUAL_64(0xeeeeeeeeeeee1013, x11);
955 ASSERT_EQUAL_64(0xeeeeeeef11131315, x12);
956 ASSERT_EQUAL_64(0x1111111511151519, x13);
957 }
958 }
959
960
TEST(eon)961 TEST(eon) {
962 SETUP();
963
964 START();
965 __ Mov(x0, 0xfff0);
966 __ Mov(x1, 0xf00000ff);
967
968 __ Eon(x2, x0, Operand(x1));
969 __ Eon(w3, w0, Operand(w1, LSL, 4));
970 __ Eon(x4, x0, Operand(x1, LSL, 4));
971 __ Eon(x5, x0, Operand(x1, LSR, 1));
972 __ Eon(w6, w0, Operand(w1, ASR, 20));
973 __ Eon(x7, x0, Operand(x1, ASR, 20));
974 __ Eon(w8, w0, Operand(w1, ROR, 28));
975 __ Eon(x9, x0, Operand(x1, ROR, 28));
976 __ Eon(w10, w0, 0x03c003c0);
977 __ Eon(x11, x0, 0x0000100000001000);
978 END();
979
980 if (CAN_RUN()) {
981 RUN();
982
983 ASSERT_EQUAL_64(0xffffffff0fff00f0, x2);
984 ASSERT_EQUAL_64(0xffff0fff, x3);
985 ASSERT_EQUAL_64(0xfffffff0ffff0fff, x4);
986 ASSERT_EQUAL_64(0xffffffff87ff0070, x5);
987 ASSERT_EQUAL_64(0x0000ff0f, x6);
988 ASSERT_EQUAL_64(0xffffffffffff0f0f, x7);
989 ASSERT_EQUAL_64(0xffff0ff0, x8);
990 ASSERT_EQUAL_64(0xfffff00fffff0000, x9);
991 ASSERT_EQUAL_64(0xfc3f03cf, x10);
992 ASSERT_EQUAL_64(0xffffefffffff100f, x11);
993 }
994 }
995
996
TEST(eon_extend)997 TEST(eon_extend) {
998 SETUP();
999
1000 START();
1001 __ Mov(x0, 0x1111111111111111);
1002 __ Mov(x1, 0x8000000080008081);
1003 __ Eon(w6, w0, Operand(w1, UXTB));
1004 __ Eon(x7, x0, Operand(x1, UXTH, 1));
1005 __ Eon(w8, w0, Operand(w1, UXTW, 2));
1006 __ Eon(x9, x0, Operand(x1, UXTX, 3));
1007 __ Eon(w10, w0, Operand(w1, SXTB));
1008 __ Eon(x11, x0, Operand(x1, SXTH, 1));
1009 __ Eon(x12, x0, Operand(x1, SXTW, 2));
1010 __ Eon(x13, x0, Operand(x1, SXTX, 3));
1011 END();
1012
1013 if (CAN_RUN()) {
1014 RUN();
1015
1016 ASSERT_EQUAL_64(0xeeeeee6f, x6);
1017 ASSERT_EQUAL_64(0xeeeeeeeeeeefefec, x7);
1018 ASSERT_EQUAL_64(0xeeececea, x8);
1019 ASSERT_EQUAL_64(0xeeeeeeeaeeeaeae6, x9);
1020 ASSERT_EQUAL_64(0x1111116f, x10);
1021 ASSERT_EQUAL_64(0x111111111111efec, x11);
1022 ASSERT_EQUAL_64(0x11111110eeececea, x12);
1023 ASSERT_EQUAL_64(0xeeeeeeeaeeeaeae6, x13);
1024 }
1025 }
1026
1027
TEST(mul)1028 TEST(mul) {
1029 SETUP();
1030
1031 START();
1032 __ Mov(x25, 0);
1033 __ Mov(x26, 1);
1034 __ Mov(x18, 0xffffffff);
1035 __ Mov(x19, 0xffffffffffffffff);
1036
1037 __ Mul(w0, w25, w25);
1038 __ Mul(w1, w25, w26);
1039 __ Mul(w2, w26, w18);
1040 __ Mul(w3, w18, w19);
1041 __ Mul(x4, x25, x25);
1042 __ Mul(x5, x26, x18);
1043 __ Mul(x6, x18, x19);
1044 __ Mul(x7, x19, x19);
1045 __ Smull(x8, w26, w18);
1046 __ Smull(x9, w18, w18);
1047 __ Smull(x10, w19, w19);
1048 __ Mneg(w11, w25, w25);
1049 __ Mneg(w12, w25, w26);
1050 __ Mneg(w13, w26, w18);
1051 __ Mneg(w14, w18, w19);
1052 __ Mneg(x20, x25, x25);
1053 __ Mneg(x21, x26, x18);
1054 __ Mneg(x22, x18, x19);
1055 __ Mneg(x23, x19, x19);
1056 END();
1057
1058 if (CAN_RUN()) {
1059 RUN();
1060
1061 ASSERT_EQUAL_64(0, x0);
1062 ASSERT_EQUAL_64(0, x1);
1063 ASSERT_EQUAL_64(0xffffffff, x2);
1064 ASSERT_EQUAL_64(1, x3);
1065 ASSERT_EQUAL_64(0, x4);
1066 ASSERT_EQUAL_64(0xffffffff, x5);
1067 ASSERT_EQUAL_64(0xffffffff00000001, x6);
1068 ASSERT_EQUAL_64(1, x7);
1069 ASSERT_EQUAL_64(0xffffffffffffffff, x8);
1070 ASSERT_EQUAL_64(1, x9);
1071 ASSERT_EQUAL_64(1, x10);
1072 ASSERT_EQUAL_64(0, x11);
1073 ASSERT_EQUAL_64(0, x12);
1074 ASSERT_EQUAL_64(1, x13);
1075 ASSERT_EQUAL_64(0xffffffff, x14);
1076 ASSERT_EQUAL_64(0, x20);
1077 ASSERT_EQUAL_64(0xffffffff00000001, x21);
1078 ASSERT_EQUAL_64(0xffffffff, x22);
1079 ASSERT_EQUAL_64(0xffffffffffffffff, x23);
1080 }
1081 }
1082
1083
SmullHelper(int64_t expected,int64_t a,int64_t b)1084 static void SmullHelper(int64_t expected, int64_t a, int64_t b) {
1085 SETUP();
1086 START();
1087 __ Mov(w0, a);
1088 __ Mov(w1, b);
1089 __ Smull(x2, w0, w1);
1090 END();
1091 if (CAN_RUN()) {
1092 RUN();
1093 ASSERT_EQUAL_64(expected, x2);
1094 }
1095 }
1096
1097
TEST(smull)1098 TEST(smull) {
1099 SmullHelper(0, 0, 0);
1100 SmullHelper(1, 1, 1);
1101 SmullHelper(-1, -1, 1);
1102 SmullHelper(1, -1, -1);
1103 SmullHelper(0xffffffff80000000, 0x80000000, 1);
1104 SmullHelper(0x0000000080000000, 0x00010000, 0x00008000);
1105 }
1106
1107
TEST(madd)1108 TEST(madd) {
1109 SETUP();
1110
1111 START();
1112 __ Mov(x16, 0);
1113 __ Mov(x17, 1);
1114 __ Mov(x18, 0xffffffff);
1115 __ Mov(x19, 0xffffffffffffffff);
1116
1117 __ Madd(w0, w16, w16, w16);
1118 __ Madd(w1, w16, w16, w17);
1119 __ Madd(w2, w16, w16, w18);
1120 __ Madd(w3, w16, w16, w19);
1121 __ Madd(w4, w16, w17, w17);
1122 __ Madd(w5, w17, w17, w18);
1123 __ Madd(w6, w17, w17, w19);
1124 __ Madd(w7, w17, w18, w16);
1125 __ Madd(w8, w17, w18, w18);
1126 __ Madd(w9, w18, w18, w17);
1127 __ Madd(w10, w18, w19, w18);
1128 __ Madd(w11, w19, w19, w19);
1129
1130 __ Madd(x12, x16, x16, x16);
1131 __ Madd(x13, x16, x16, x17);
1132 __ Madd(x14, x16, x16, x18);
1133 __ Madd(x15, x16, x16, x19);
1134 __ Madd(x20, x16, x17, x17);
1135 __ Madd(x21, x17, x17, x18);
1136 __ Madd(x22, x17, x17, x19);
1137 __ Madd(x23, x17, x18, x16);
1138 __ Madd(x24, x17, x18, x18);
1139 __ Madd(x25, x18, x18, x17);
1140 __ Madd(x26, x18, x19, x18);
1141 __ Madd(x27, x19, x19, x19);
1142
1143 END();
1144
1145 if (CAN_RUN()) {
1146 RUN();
1147
1148 ASSERT_EQUAL_64(0, x0);
1149 ASSERT_EQUAL_64(1, x1);
1150 ASSERT_EQUAL_64(0xffffffff, x2);
1151 ASSERT_EQUAL_64(0xffffffff, x3);
1152 ASSERT_EQUAL_64(1, x4);
1153 ASSERT_EQUAL_64(0, x5);
1154 ASSERT_EQUAL_64(0, x6);
1155 ASSERT_EQUAL_64(0xffffffff, x7);
1156 ASSERT_EQUAL_64(0xfffffffe, x8);
1157 ASSERT_EQUAL_64(2, x9);
1158 ASSERT_EQUAL_64(0, x10);
1159 ASSERT_EQUAL_64(0, x11);
1160
1161 ASSERT_EQUAL_64(0, x12);
1162 ASSERT_EQUAL_64(1, x13);
1163 ASSERT_EQUAL_64(0x00000000ffffffff, x14);
1164 ASSERT_EQUAL_64(0xffffffffffffffff, x15);
1165 ASSERT_EQUAL_64(1, x20);
1166 ASSERT_EQUAL_64(0x0000000100000000, x21);
1167 ASSERT_EQUAL_64(0, x22);
1168 ASSERT_EQUAL_64(0x00000000ffffffff, x23);
1169 ASSERT_EQUAL_64(0x00000001fffffffe, x24);
1170 ASSERT_EQUAL_64(0xfffffffe00000002, x25);
1171 ASSERT_EQUAL_64(0, x26);
1172 ASSERT_EQUAL_64(0, x27);
1173 }
1174 }
1175
1176
TEST(msub)1177 TEST(msub) {
1178 SETUP();
1179
1180 START();
1181 __ Mov(x16, 0);
1182 __ Mov(x17, 1);
1183 __ Mov(x18, 0xffffffff);
1184 __ Mov(x19, 0xffffffffffffffff);
1185
1186 __ Msub(w0, w16, w16, w16);
1187 __ Msub(w1, w16, w16, w17);
1188 __ Msub(w2, w16, w16, w18);
1189 __ Msub(w3, w16, w16, w19);
1190 __ Msub(w4, w16, w17, w17);
1191 __ Msub(w5, w17, w17, w18);
1192 __ Msub(w6, w17, w17, w19);
1193 __ Msub(w7, w17, w18, w16);
1194 __ Msub(w8, w17, w18, w18);
1195 __ Msub(w9, w18, w18, w17);
1196 __ Msub(w10, w18, w19, w18);
1197 __ Msub(w11, w19, w19, w19);
1198
1199 __ Msub(x12, x16, x16, x16);
1200 __ Msub(x13, x16, x16, x17);
1201 __ Msub(x14, x16, x16, x18);
1202 __ Msub(x15, x16, x16, x19);
1203 __ Msub(x20, x16, x17, x17);
1204 __ Msub(x21, x17, x17, x18);
1205 __ Msub(x22, x17, x17, x19);
1206 __ Msub(x23, x17, x18, x16);
1207 __ Msub(x24, x17, x18, x18);
1208 __ Msub(x25, x18, x18, x17);
1209 __ Msub(x26, x18, x19, x18);
1210 __ Msub(x27, x19, x19, x19);
1211
1212 END();
1213
1214 if (CAN_RUN()) {
1215 RUN();
1216
1217 ASSERT_EQUAL_64(0, x0);
1218 ASSERT_EQUAL_64(1, x1);
1219 ASSERT_EQUAL_64(0xffffffff, x2);
1220 ASSERT_EQUAL_64(0xffffffff, x3);
1221 ASSERT_EQUAL_64(1, x4);
1222 ASSERT_EQUAL_64(0xfffffffe, x5);
1223 ASSERT_EQUAL_64(0xfffffffe, x6);
1224 ASSERT_EQUAL_64(1, x7);
1225 ASSERT_EQUAL_64(0, x8);
1226 ASSERT_EQUAL_64(0, x9);
1227 ASSERT_EQUAL_64(0xfffffffe, x10);
1228 ASSERT_EQUAL_64(0xfffffffe, x11);
1229
1230 ASSERT_EQUAL_64(0, x12);
1231 ASSERT_EQUAL_64(1, x13);
1232 ASSERT_EQUAL_64(0x00000000ffffffff, x14);
1233 ASSERT_EQUAL_64(0xffffffffffffffff, x15);
1234 ASSERT_EQUAL_64(1, x20);
1235 ASSERT_EQUAL_64(0x00000000fffffffe, x21);
1236 ASSERT_EQUAL_64(0xfffffffffffffffe, x22);
1237 ASSERT_EQUAL_64(0xffffffff00000001, x23);
1238 ASSERT_EQUAL_64(0, x24);
1239 ASSERT_EQUAL_64(0x0000000200000000, x25);
1240 ASSERT_EQUAL_64(0x00000001fffffffe, x26);
1241 ASSERT_EQUAL_64(0xfffffffffffffffe, x27);
1242 }
1243 }
1244
1245
TEST(smulh)1246 TEST(smulh) {
1247 SETUP();
1248
1249 START();
1250 __ Mov(x20, 0);
1251 __ Mov(x21, 1);
1252 __ Mov(x22, 0x0000000100000000);
1253 __ Mov(x23, 0x0000000012345678);
1254 __ Mov(x24, 0x0123456789abcdef);
1255 __ Mov(x25, 0x0000000200000000);
1256 __ Mov(x26, 0x8000000000000000);
1257 __ Mov(x27, 0xffffffffffffffff);
1258 __ Mov(x28, 0x5555555555555555);
1259 __ Mov(x29, 0xaaaaaaaaaaaaaaaa);
1260
1261 __ Smulh(x0, x20, x24);
1262 __ Smulh(x1, x21, x24);
1263 __ Smulh(x2, x22, x23);
1264 __ Smulh(x3, x22, x24);
1265 __ Smulh(x4, x24, x25);
1266 __ Smulh(x5, x23, x27);
1267 __ Smulh(x6, x26, x26);
1268 __ Smulh(x7, x26, x27);
1269 __ Smulh(x8, x27, x27);
1270 __ Smulh(x9, x28, x28);
1271 __ Smulh(x10, x28, x29);
1272 __ Smulh(x11, x29, x29);
1273 END();
1274
1275 if (CAN_RUN()) {
1276 RUN();
1277
1278 ASSERT_EQUAL_64(0, x0);
1279 ASSERT_EQUAL_64(0, x1);
1280 ASSERT_EQUAL_64(0, x2);
1281 ASSERT_EQUAL_64(0x0000000001234567, x3);
1282 ASSERT_EQUAL_64(0x0000000002468acf, x4);
1283 ASSERT_EQUAL_64(0xffffffffffffffff, x5);
1284 ASSERT_EQUAL_64(0x4000000000000000, x6);
1285 ASSERT_EQUAL_64(0, x7);
1286 ASSERT_EQUAL_64(0, x8);
1287 ASSERT_EQUAL_64(0x1c71c71c71c71c71, x9);
1288 ASSERT_EQUAL_64(0xe38e38e38e38e38e, x10);
1289 ASSERT_EQUAL_64(0x1c71c71c71c71c72, x11);
1290 }
1291 }
1292
1293
TEST(umulh)1294 TEST(umulh) {
1295 SETUP();
1296
1297 START();
1298 __ Mov(x20, 0);
1299 __ Mov(x21, 1);
1300 __ Mov(x22, 0x0000000100000000);
1301 __ Mov(x23, 0x0000000012345678);
1302 __ Mov(x24, 0x0123456789abcdef);
1303 __ Mov(x25, 0x0000000200000000);
1304 __ Mov(x26, 0x8000000000000000);
1305 __ Mov(x27, 0xffffffffffffffff);
1306 __ Mov(x28, 0x5555555555555555);
1307 __ Mov(x29, 0xaaaaaaaaaaaaaaaa);
1308
1309 __ Umulh(x0, x20, x24);
1310 __ Umulh(x1, x21, x24);
1311 __ Umulh(x2, x22, x23);
1312 __ Umulh(x3, x22, x24);
1313 __ Umulh(x4, x24, x25);
1314 __ Umulh(x5, x23, x27);
1315 __ Umulh(x6, x26, x26);
1316 __ Umulh(x7, x26, x27);
1317 __ Umulh(x8, x27, x27);
1318 __ Umulh(x9, x28, x28);
1319 __ Umulh(x10, x28, x29);
1320 __ Umulh(x11, x29, x29);
1321 END();
1322
1323 if (CAN_RUN()) {
1324 RUN();
1325
1326 ASSERT_EQUAL_64(0, x0);
1327 ASSERT_EQUAL_64(0, x1);
1328 ASSERT_EQUAL_64(0, x2);
1329 ASSERT_EQUAL_64(0x0000000001234567, x3);
1330 ASSERT_EQUAL_64(0x0000000002468acf, x4);
1331 ASSERT_EQUAL_64(0x0000000012345677, x5);
1332 ASSERT_EQUAL_64(0x4000000000000000, x6);
1333 ASSERT_EQUAL_64(0x7fffffffffffffff, x7);
1334 ASSERT_EQUAL_64(0xfffffffffffffffe, x8);
1335 ASSERT_EQUAL_64(0x1c71c71c71c71c71, x9);
1336 ASSERT_EQUAL_64(0x38e38e38e38e38e3, x10);
1337 ASSERT_EQUAL_64(0x71c71c71c71c71c6, x11);
1338 }
1339 }
1340
1341
TEST(smaddl_umaddl_umull)1342 TEST(smaddl_umaddl_umull) {
1343 SETUP();
1344
1345 START();
1346 __ Mov(x17, 1);
1347 __ Mov(x18, 0x00000000ffffffff);
1348 __ Mov(x19, 0xffffffffffffffff);
1349 __ Mov(x20, 4);
1350 __ Mov(x21, 0x0000000200000000);
1351
1352 __ Smaddl(x9, w17, w18, x20);
1353 __ Smaddl(x10, w18, w18, x20);
1354 __ Smaddl(x11, w19, w19, x20);
1355 __ Smaddl(x12, w19, w19, x21);
1356 __ Umaddl(x13, w17, w18, x20);
1357 __ Umaddl(x14, w18, w18, x20);
1358 __ Umaddl(x15, w19, w19, x20);
1359 __ Umaddl(x22, w19, w19, x21);
1360 __ Umull(x24, w19, w19);
1361 __ Umull(x25, w17, w18);
1362 END();
1363
1364 if (CAN_RUN()) {
1365 RUN();
1366
1367 ASSERT_EQUAL_64(3, x9);
1368 ASSERT_EQUAL_64(5, x10);
1369 ASSERT_EQUAL_64(5, x11);
1370 ASSERT_EQUAL_64(0x0000000200000001, x12);
1371 ASSERT_EQUAL_64(0x0000000100000003, x13);
1372 ASSERT_EQUAL_64(0xfffffffe00000005, x14);
1373 ASSERT_EQUAL_64(0xfffffffe00000005, x15);
1374 ASSERT_EQUAL_64(1, x22);
1375 ASSERT_EQUAL_64(0xfffffffe00000001, x24);
1376 ASSERT_EQUAL_64(0x00000000ffffffff, x25);
1377 }
1378 }
1379
1380
TEST(smsubl_umsubl)1381 TEST(smsubl_umsubl) {
1382 SETUP();
1383
1384 START();
1385 __ Mov(x17, 1);
1386 __ Mov(x18, 0x00000000ffffffff);
1387 __ Mov(x19, 0xffffffffffffffff);
1388 __ Mov(x20, 4);
1389 __ Mov(x21, 0x0000000200000000);
1390
1391 __ Smsubl(x9, w17, w18, x20);
1392 __ Smsubl(x10, w18, w18, x20);
1393 __ Smsubl(x11, w19, w19, x20);
1394 __ Smsubl(x12, w19, w19, x21);
1395 __ Umsubl(x13, w17, w18, x20);
1396 __ Umsubl(x14, w18, w18, x20);
1397 __ Umsubl(x15, w19, w19, x20);
1398 __ Umsubl(x22, w19, w19, x21);
1399 END();
1400
1401 if (CAN_RUN()) {
1402 RUN();
1403
1404 ASSERT_EQUAL_64(5, x9);
1405 ASSERT_EQUAL_64(3, x10);
1406 ASSERT_EQUAL_64(3, x11);
1407 ASSERT_EQUAL_64(0x00000001ffffffff, x12);
1408 ASSERT_EQUAL_64(0xffffffff00000005, x13);
1409 ASSERT_EQUAL_64(0x0000000200000003, x14);
1410 ASSERT_EQUAL_64(0x0000000200000003, x15);
1411 ASSERT_EQUAL_64(0x00000003ffffffff, x22);
1412 }
1413 }
1414
1415
TEST(div)1416 TEST(div) {
1417 SETUP();
1418
1419 START();
1420 __ Mov(x16, 1);
1421 __ Mov(x17, 0xffffffff);
1422 __ Mov(x18, 0xffffffffffffffff);
1423 __ Mov(x19, 0x80000000);
1424 __ Mov(x20, 0x8000000000000000);
1425 __ Mov(x21, 2);
1426
1427 __ Udiv(w0, w16, w16);
1428 __ Udiv(w1, w17, w16);
1429 __ Sdiv(w2, w16, w16);
1430 __ Sdiv(w3, w16, w17);
1431 __ Sdiv(w4, w17, w18);
1432
1433 __ Udiv(x5, x16, x16);
1434 __ Udiv(x6, x17, x18);
1435 __ Sdiv(x7, x16, x16);
1436 __ Sdiv(x8, x16, x17);
1437 __ Sdiv(x9, x17, x18);
1438
1439 __ Udiv(w10, w19, w21);
1440 __ Sdiv(w11, w19, w21);
1441 __ Udiv(x12, x19, x21);
1442 __ Sdiv(x13, x19, x21);
1443 __ Udiv(x14, x20, x21);
1444 __ Sdiv(x15, x20, x21);
1445
1446 __ Udiv(w22, w19, w17);
1447 __ Sdiv(w23, w19, w17);
1448 __ Udiv(x24, x20, x18);
1449 __ Sdiv(x25, x20, x18);
1450
1451 __ Udiv(x26, x16, x21);
1452 __ Sdiv(x27, x16, x21);
1453 __ Udiv(x28, x18, x21);
1454 __ Sdiv(x29, x18, x21);
1455
1456 __ Mov(x17, 0);
1457 __ Udiv(w18, w16, w17);
1458 __ Sdiv(w19, w16, w17);
1459 __ Udiv(x20, x16, x17);
1460 __ Sdiv(x21, x16, x17);
1461 END();
1462
1463 if (CAN_RUN()) {
1464 RUN();
1465
1466 ASSERT_EQUAL_64(1, x0);
1467 ASSERT_EQUAL_64(0xffffffff, x1);
1468 ASSERT_EQUAL_64(1, x2);
1469 ASSERT_EQUAL_64(0xffffffff, x3);
1470 ASSERT_EQUAL_64(1, x4);
1471 ASSERT_EQUAL_64(1, x5);
1472 ASSERT_EQUAL_64(0, x6);
1473 ASSERT_EQUAL_64(1, x7);
1474 ASSERT_EQUAL_64(0, x8);
1475 ASSERT_EQUAL_64(0xffffffff00000001, x9);
1476 ASSERT_EQUAL_64(0x40000000, x10);
1477 ASSERT_EQUAL_64(0xc0000000, x11);
1478 ASSERT_EQUAL_64(0x0000000040000000, x12);
1479 ASSERT_EQUAL_64(0x0000000040000000, x13);
1480 ASSERT_EQUAL_64(0x4000000000000000, x14);
1481 ASSERT_EQUAL_64(0xc000000000000000, x15);
1482 ASSERT_EQUAL_64(0, x22);
1483 ASSERT_EQUAL_64(0x80000000, x23);
1484 ASSERT_EQUAL_64(0, x24);
1485 ASSERT_EQUAL_64(0x8000000000000000, x25);
1486 ASSERT_EQUAL_64(0, x26);
1487 ASSERT_EQUAL_64(0, x27);
1488 ASSERT_EQUAL_64(0x7fffffffffffffff, x28);
1489 ASSERT_EQUAL_64(0, x29);
1490 ASSERT_EQUAL_64(0, x18);
1491 ASSERT_EQUAL_64(0, x19);
1492 ASSERT_EQUAL_64(0, x20);
1493 ASSERT_EQUAL_64(0, x21);
1494 }
1495 }
1496
1497
TEST(rbit_rev)1498 TEST(rbit_rev) {
1499 SETUP();
1500
1501 START();
1502 __ Mov(x24, 0xfedcba9876543210);
1503 __ Rbit(w0, w24);
1504 __ Rbit(x1, x24);
1505 __ Rev16(w2, w24);
1506 __ Rev16(x3, x24);
1507 __ Rev(w4, w24);
1508 __ Rev32(x5, x24);
1509 __ Rev64(x6, x24);
1510 __ Rev(x7, x24);
1511 END();
1512
1513 if (CAN_RUN()) {
1514 RUN();
1515
1516 ASSERT_EQUAL_64(0x084c2a6e, x0);
1517 ASSERT_EQUAL_64(0x084c2a6e195d3b7f, x1);
1518 ASSERT_EQUAL_64(0x54761032, x2);
1519 ASSERT_EQUAL_64(0xdcfe98ba54761032, x3);
1520 ASSERT_EQUAL_64(0x10325476, x4);
1521 ASSERT_EQUAL_64(0x98badcfe10325476, x5);
1522 ASSERT_EQUAL_64(0x1032547698badcfe, x6);
1523 ASSERT_EQUAL_64(0x1032547698badcfe, x7);
1524 }
1525 }
1526
1527 typedef void (MacroAssembler::*TestBranchSignature)(const Register& rt,
1528 unsigned bit_pos,
1529 Label* label);
1530
TbzRangePoolLimitHelper(TestBranchSignature test_branch)1531 static void TbzRangePoolLimitHelper(TestBranchSignature test_branch) {
1532 const int kTbzRange = 32768;
1533 const int kNumLdrLiteral = kTbzRange / 4;
1534 const int fuzz_range = 2;
1535 for (int n = kNumLdrLiteral - fuzz_range; n <= kNumLdrLiteral + fuzz_range;
1536 ++n) {
1537 for (int margin = -32; margin < 32; margin += 4) {
1538 SETUP();
1539
1540 START();
1541
1542 // Emit 32KB of literals (equal to the range of TBZ).
1543 for (int i = 0; i < n; ++i) {
1544 __ Ldr(w0, 0x12345678);
1545 }
1546
1547 const int kLiteralMargin = 128 * KBytes;
1548
1549 // Emit enough NOPs to be just about to emit the literal pool.
1550 ptrdiff_t end =
1551 masm.GetCursorOffset() + (kLiteralMargin - n * 4 + margin);
1552 while (masm.GetCursorOffset() < end) {
1553 __ Nop();
1554 }
1555
1556 // Add a TBZ instruction.
1557 Label label;
1558
1559 (masm.*test_branch)(x0, 2, &label);
1560
1561 // Add enough NOPs to surpass its range, to make sure we can encode the
1562 // veneer.
1563 end = masm.GetCursorOffset() + (kTbzRange - 4);
1564 {
1565 ExactAssemblyScope scope(&masm,
1566 kTbzRange,
1567 ExactAssemblyScope::kMaximumSize);
1568 while (masm.GetCursorOffset() < end) __ nop();
1569 }
1570
1571 // Finally, bind the label.
1572 __ Bind(&label);
1573
1574 END();
1575
1576 if (CAN_RUN()) {
1577 RUN();
1578 }
1579 }
1580 }
1581 }
1582
TEST(test_branch_limits_literal_pool_size_tbz)1583 TEST(test_branch_limits_literal_pool_size_tbz) {
1584 TbzRangePoolLimitHelper(&MacroAssembler::Tbz);
1585 }
1586
TEST(test_branch_limits_literal_pool_size_tbnz)1587 TEST(test_branch_limits_literal_pool_size_tbnz) {
1588 TbzRangePoolLimitHelper(&MacroAssembler::Tbnz);
1589 }
1590
TEST(clz_cls)1591 TEST(clz_cls) {
1592 SETUP();
1593
1594 START();
1595 __ Mov(x24, 0x0008000000800000);
1596 __ Mov(x25, 0xff800000fff80000);
1597 __ Mov(x26, 0);
1598 __ Clz(w0, w24);
1599 __ Clz(x1, x24);
1600 __ Clz(w2, w25);
1601 __ Clz(x3, x25);
1602 __ Clz(w4, w26);
1603 __ Clz(x5, x26);
1604 __ Cls(w6, w24);
1605 __ Cls(x7, x24);
1606 __ Cls(w8, w25);
1607 __ Cls(x9, x25);
1608 __ Cls(w10, w26);
1609 __ Cls(x11, x26);
1610 END();
1611
1612 if (CAN_RUN()) {
1613 RUN();
1614
1615 ASSERT_EQUAL_64(8, x0);
1616 ASSERT_EQUAL_64(12, x1);
1617 ASSERT_EQUAL_64(0, x2);
1618 ASSERT_EQUAL_64(0, x3);
1619 ASSERT_EQUAL_64(32, x4);
1620 ASSERT_EQUAL_64(64, x5);
1621 ASSERT_EQUAL_64(7, x6);
1622 ASSERT_EQUAL_64(11, x7);
1623 ASSERT_EQUAL_64(12, x8);
1624 ASSERT_EQUAL_64(8, x9);
1625 ASSERT_EQUAL_64(31, x10);
1626 ASSERT_EQUAL_64(63, x11);
1627 }
1628 }
1629
1630
TEST(pacia_pacib_autia_autib)1631 TEST(pacia_pacib_autia_autib) {
1632 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
1633
1634 START();
1635
1636 Register pointer = x24;
1637 Register retry_limit = x25;
1638 Register modifier = x26;
1639 Label retry;
1640
1641 // There is a small but not negligible chance (1 in 127 runs) that the PAC
1642 // codes for keys A and B will collide, so retry a few times with different
1643 // pointers.
1644 __ Mov(pointer, 0x0000000012345678);
1645 __ Mov(retry_limit, 0x0000000012345678 + 32);
1646 __ Mov(modifier, 0x477d469dec0b8760);
1647
1648 __ Bind(&retry);
1649
1650 // Generate PACs using keys A and B.
1651 __ Mov(x0, pointer);
1652 __ Pacia(x0, modifier);
1653
1654 __ Mov(x1, pointer);
1655 __ Pacib(x1, modifier);
1656
1657 // Authenticate the pointers above.
1658 __ Mov(x2, x0);
1659 __ Autia(x2, modifier);
1660
1661 __ Mov(x3, x1);
1662 __ Autib(x3, modifier);
1663
1664 // Attempt to authenticate incorrect pointers.
1665 __ Mov(x4, x1);
1666 __ Autia(x4, modifier);
1667
1668 __ Mov(x5, x0);
1669 __ Autib(x5, modifier);
1670
1671 // Retry on collisions.
1672 __ Cmp(x0, x1);
1673 __ Ccmp(pointer, x0, ZFlag, ne);
1674 __ Ccmp(pointer, x1, ZFlag, ne);
1675 __ Ccmp(pointer, x4, ZFlag, ne);
1676 __ Ccmp(pointer, x5, ZFlag, ne);
1677 __ Ccmp(pointer, retry_limit, ZFlag, eq);
1678 __ Cinc(pointer, pointer, ne);
1679 __ B(ne, &retry);
1680
1681 END();
1682
1683 if (CAN_RUN()) {
1684 RUN();
1685
1686 // Check PAC codes have been generated.
1687 ASSERT_NOT_EQUAL_64(pointer, x0);
1688 ASSERT_NOT_EQUAL_64(pointer, x1);
1689 ASSERT_NOT_EQUAL_64(x0, x1);
1690
1691 // Pointers correctly authenticated.
1692 ASSERT_EQUAL_64(pointer, x2);
1693 ASSERT_EQUAL_64(pointer, x3);
1694
1695 // Pointers corrupted after failing to authenticate.
1696 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
1697 ASSERT_EQUAL_64(0x0020000012345678, x4);
1698 ASSERT_EQUAL_64(0x0040000012345678, x5);
1699 #else
1700 ASSERT_NOT_EQUAL_64(pointer, x4);
1701 ASSERT_NOT_EQUAL_64(pointer, x5);
1702 #endif
1703 }
1704 }
1705
1706
TEST(paciza_pacizb_autiza_autizb)1707 TEST(paciza_pacizb_autiza_autizb) {
1708 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
1709
1710 START();
1711
1712 Register pointer = x24;
1713 Register retry_limit = x25;
1714 Label retry;
1715
1716 // There is a small but not negligible chance (1 in 127 runs) that the PAC
1717 // codes for keys A and B will collide, so retry a few times with different
1718 // pointers.
1719 __ Mov(pointer, 0x0000000012345678);
1720 __ Mov(retry_limit, 0x0000000012345678 + 32);
1721
1722 __ Bind(&retry);
1723
1724 // Generate PACs using keys A and B.
1725 __ Mov(x0, pointer);
1726 __ Paciza(x0);
1727
1728 __ Mov(x1, pointer);
1729 __ Pacizb(x1);
1730
1731 // Authenticate the pointers above.
1732 __ Mov(x2, x0);
1733 __ Autiza(x2);
1734
1735 __ Mov(x3, x1);
1736 __ Autizb(x3);
1737
1738 // Attempt to authenticate incorrect pointers.
1739 __ Mov(x4, x1);
1740 __ Autiza(x4);
1741
1742 __ Mov(x5, x0);
1743 __ Autizb(x5);
1744
1745 // Retry on collisions.
1746 __ Cmp(x0, x1);
1747 __ Ccmp(pointer, x0, ZFlag, ne);
1748 __ Ccmp(pointer, x1, ZFlag, ne);
1749 __ Ccmp(pointer, x4, ZFlag, ne);
1750 __ Ccmp(pointer, x5, ZFlag, ne);
1751 __ Ccmp(pointer, retry_limit, ZFlag, eq);
1752 __ Cinc(pointer, pointer, ne);
1753 __ B(ne, &retry);
1754
1755 END();
1756
1757 if (CAN_RUN()) {
1758 RUN();
1759
1760 // Check PAC codes have been generated.
1761 ASSERT_NOT_EQUAL_64(pointer, x0);
1762 ASSERT_NOT_EQUAL_64(pointer, x1);
1763 ASSERT_NOT_EQUAL_64(x0, x1);
1764
1765 // Pointers correctly authenticated.
1766 ASSERT_EQUAL_64(pointer, x2);
1767 ASSERT_EQUAL_64(pointer, x3);
1768
1769 // Pointers corrupted after failing to authenticate.
1770 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
1771 ASSERT_EQUAL_64(0x0020000012345678, x4);
1772 ASSERT_EQUAL_64(0x0040000012345678, x5);
1773 #else
1774 ASSERT_NOT_EQUAL_64(pointer, x4);
1775 ASSERT_NOT_EQUAL_64(pointer, x5);
1776 #endif
1777 }
1778 }
1779
1780
TEST(pacda_pacdb_autda_autdb)1781 TEST(pacda_pacdb_autda_autdb) {
1782 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
1783
1784 START();
1785
1786 Register pointer = x24;
1787 Register retry_limit = x25;
1788 Register modifier = x26;
1789 Label retry;
1790
1791 // There is a small but not negligible chance (1 in 127 runs) that the PAC
1792 // codes for keys A and B will collide, so retry a few times with different
1793 // pointers.
1794 __ Mov(pointer, 0x0000000012345678);
1795 __ Mov(retry_limit, 0x0000000012345678 + 32);
1796 __ Mov(modifier, 0x477d469dec0b8760);
1797
1798 __ Bind(&retry);
1799
1800 // Generate PACs using keys A and B.
1801 __ Mov(x0, pointer);
1802 __ Pacda(x0, modifier);
1803
1804 __ Mov(x1, pointer);
1805 __ Pacdb(x1, modifier);
1806
1807 // Authenticate the pointers above.
1808 __ Mov(x2, x0);
1809 __ Autda(x2, modifier);
1810
1811 __ Mov(x3, x1);
1812 __ Autdb(x3, modifier);
1813
1814 // Attempt to authenticate incorrect pointers.
1815 __ Mov(x4, x1);
1816 __ Autda(x4, modifier);
1817
1818 __ Mov(x5, x0);
1819 __ Autdb(x5, modifier);
1820
1821 // Retry on collisions.
1822 __ Cmp(x0, x1);
1823 __ Ccmp(pointer, x0, ZFlag, ne);
1824 __ Ccmp(pointer, x1, ZFlag, ne);
1825 __ Ccmp(pointer, x4, ZFlag, ne);
1826 __ Ccmp(pointer, x5, ZFlag, ne);
1827 __ Ccmp(pointer, retry_limit, ZFlag, eq);
1828 __ Cinc(pointer, pointer, ne);
1829 __ B(ne, &retry);
1830
1831 END();
1832
1833 if (CAN_RUN()) {
1834 RUN();
1835
1836 // Check PAC codes have been generated.
1837 ASSERT_NOT_EQUAL_64(pointer, x0);
1838 ASSERT_NOT_EQUAL_64(pointer, x1);
1839 ASSERT_NOT_EQUAL_64(x0, x1);
1840
1841 // Pointers correctly authenticated.
1842 ASSERT_EQUAL_64(pointer, x2);
1843 ASSERT_EQUAL_64(pointer, x3);
1844
1845 // Pointers corrupted after failing to authenticate.
1846 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
1847 ASSERT_EQUAL_64(0x0020000012345678, x4);
1848 ASSERT_EQUAL_64(0x0040000012345678, x5);
1849 #else
1850 ASSERT_NOT_EQUAL_64(pointer, x4);
1851 ASSERT_NOT_EQUAL_64(pointer, x5);
1852 #endif
1853 }
1854 }
1855
1856
TEST(pacdza_pacdzb_autdza_autdzb)1857 TEST(pacdza_pacdzb_autdza_autdzb) {
1858 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
1859
1860 START();
1861
1862 Register pointer = x24;
1863 Register retry_limit = x25;
1864 Label retry;
1865
1866 // There is a small but not negligible chance (1 in 127 runs) that the PAC
1867 // codes for keys A and B will collide, so retry a few times with different
1868 // pointers.
1869 __ Mov(pointer, 0x0000000012345678);
1870 __ Mov(retry_limit, 0x0000000012345678 + 32);
1871
1872 __ Bind(&retry);
1873
1874 // Generate PACs using keys A and B.
1875 __ Mov(x0, pointer);
1876 __ Pacdza(x0);
1877
1878 __ Mov(x1, pointer);
1879 __ Pacdzb(x1);
1880
1881 // Authenticate the pointers above.
1882 __ Mov(x2, x0);
1883 __ Autdza(x2);
1884
1885 __ Mov(x3, x1);
1886 __ Autdzb(x3);
1887
1888 // Attempt to authenticate incorrect pointers.
1889 __ Mov(x4, x1);
1890 __ Autdza(x4);
1891
1892 __ Mov(x5, x0);
1893 __ Autdzb(x5);
1894
1895 // Retry on collisions.
1896 __ Cmp(x0, x1);
1897 __ Ccmp(pointer, x0, ZFlag, ne);
1898 __ Ccmp(pointer, x1, ZFlag, ne);
1899 __ Ccmp(pointer, x4, ZFlag, ne);
1900 __ Ccmp(pointer, x5, ZFlag, ne);
1901 __ Ccmp(pointer, retry_limit, ZFlag, eq);
1902 __ Cinc(pointer, pointer, ne);
1903 __ B(ne, &retry);
1904
1905 END();
1906
1907 if (CAN_RUN()) {
1908 RUN();
1909
1910 // Check PAC codes have been generated.
1911 ASSERT_NOT_EQUAL_64(pointer, x0);
1912 ASSERT_NOT_EQUAL_64(pointer, x1);
1913 ASSERT_NOT_EQUAL_64(x0, x1);
1914
1915 // Pointers correctly authenticated.
1916 ASSERT_EQUAL_64(pointer, x2);
1917 ASSERT_EQUAL_64(pointer, x3);
1918
1919 // Pointers corrupted after failing to authenticate.
1920 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
1921 ASSERT_EQUAL_64(0x0020000012345678, x4);
1922 ASSERT_EQUAL_64(0x0040000012345678, x5);
1923 #else
1924 ASSERT_NOT_EQUAL_64(pointer, x4);
1925 ASSERT_NOT_EQUAL_64(pointer, x5);
1926 #endif
1927 }
1928 }
1929
1930
TEST(pacga_xpaci_xpacd)1931 TEST(pacga_xpaci_xpacd) {
1932 SETUP_WITH_FEATURES(CPUFeatures::kPAuth, CPUFeatures::kPAuthGeneric);
1933
1934 START();
1935
1936 Register pointer = x24;
1937 Register retry_limit = x25;
1938 Register modifier = x26;
1939 Label retry;
1940
1941 // There is a small but not negligible chance (1 in 127 runs) that the PAC
1942 // codes for keys A and B will collide, so retry a few times with different
1943 // pointers.
1944 __ Mov(pointer, 0x0000000012345678);
1945 __ Mov(retry_limit, 0x0000000012345678 + 32);
1946 __ Mov(modifier, 0x477d469dec0b8760);
1947
1948 __ Bind(&retry);
1949
1950 // Generate generic PAC.
1951 __ Pacga(x0, pointer, modifier);
1952
1953 // Generate PACs using key A.
1954 __ Mov(x1, pointer);
1955 __ Mov(x2, pointer);
1956 __ Pacia(x1, modifier);
1957 __ Pacda(x2, modifier);
1958
1959 // Strip PACs.
1960 __ Mov(x3, x1);
1961 __ Mov(x4, x2);
1962 __ Xpaci(x3);
1963 __ Xpacd(x4);
1964
1965 // Retry on collisions.
1966 __ Cmp(x1, x2);
1967 __ Ccmp(pointer, x0, ZFlag, ne);
1968 __ Ccmp(pointer, x1, ZFlag, ne);
1969 __ Ccmp(pointer, x2, ZFlag, ne);
1970 __ Ccmp(pointer, retry_limit, ZFlag, eq);
1971 __ Cinc(pointer, pointer, ne);
1972 __ B(ne, &retry);
1973
1974 END();
1975
1976 if (CAN_RUN()) {
1977 RUN();
1978
1979 // Check PAC codes have been generated.
1980 ASSERT_NOT_EQUAL_64(pointer, x0);
1981 ASSERT_NOT_EQUAL_64(pointer, x1);
1982 ASSERT_NOT_EQUAL_64(pointer, x2);
1983 ASSERT_NOT_EQUAL_64(x1, x2);
1984
1985 ASSERT_EQUAL_64(pointer, x3);
1986 ASSERT_EQUAL_64(pointer, x4);
1987 }
1988 }
1989
TEST(pac_sp_modifier)1990 TEST(pac_sp_modifier) {
1991 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
1992
1993 START();
1994
1995 __ Mov(x0, 0x0000000012345678);
1996 __ Mov(x1, x0);
1997 __ Mov(x10, sp);
1998
1999 // Generate PACs using sp and register containing a copy of sp.
2000 __ Pacia(x0, x10);
2001 __ Pacia(x1, sp);
2002
2003 // Authenticate the pointers, exchanging (equal) modifiers.
2004 __ Mov(x2, x0);
2005 __ Mov(x3, x1);
2006 __ Autia(x2, sp);
2007 __ Autia(x3, x10);
2008
2009 END();
2010
2011 if (CAN_RUN()) {
2012 RUN();
2013
2014 ASSERT_EQUAL_64(x0, x1);
2015 ASSERT_EQUAL_64(x2, x3);
2016 }
2017 }
2018
TEST(label)2019 TEST(label) {
2020 SETUP();
2021
2022 Label label_1, label_2, label_3, label_4;
2023
2024 START();
2025 __ Mov(x0, 0x1);
2026 __ Mov(x1, 0x0);
2027 __ Mov(x22, lr); // Save lr.
2028
2029 __ B(&label_1);
2030 __ B(&label_1);
2031 __ B(&label_1); // Multiple branches to the same label.
2032 __ Mov(x0, 0x0);
2033 __ Bind(&label_2);
2034 __ B(&label_3); // Forward branch.
2035 __ Mov(x0, 0x0);
2036 __ Bind(&label_1);
2037 __ B(&label_2); // Backward branch.
2038 __ Mov(x0, 0x0);
2039 __ Bind(&label_3);
2040 __ Bl(&label_4);
2041 END();
2042
2043 __ Bind(&label_4);
2044 __ Mov(x1, 0x1);
2045 __ Mov(lr, x22);
2046 END();
2047
2048 if (CAN_RUN()) {
2049 RUN();
2050
2051 ASSERT_EQUAL_64(0x1, x0);
2052 ASSERT_EQUAL_64(0x1, x1);
2053 }
2054 }
2055
2056
TEST(label_2)2057 TEST(label_2) {
2058 SETUP();
2059
2060 Label label_1, label_2, label_3;
2061 Label first_jump_to_3;
2062
2063 START();
2064 __ Mov(x0, 0x0);
2065
2066 __ B(&label_1);
2067 ptrdiff_t offset_2 = masm.GetCursorOffset();
2068 __ Orr(x0, x0, 1 << 1);
2069 __ B(&label_3);
2070 ptrdiff_t offset_1 = masm.GetCursorOffset();
2071 __ Orr(x0, x0, 1 << 0);
2072 __ B(&label_2);
2073 ptrdiff_t offset_3 = masm.GetCursorOffset();
2074 __ Tbz(x0, 2, &first_jump_to_3);
2075 __ Orr(x0, x0, 1 << 3);
2076 __ Bind(&first_jump_to_3);
2077 __ Orr(x0, x0, 1 << 2);
2078 __ Tbz(x0, 3, &label_3);
2079
2080 // Labels 1, 2, and 3 are bound before the current buffer offset. Branches to
2081 // label_1 and label_2 branch respectively forward and backward. Branches to
2082 // label 3 include both forward and backward branches.
2083 masm.BindToOffset(&label_1, offset_1);
2084 masm.BindToOffset(&label_2, offset_2);
2085 masm.BindToOffset(&label_3, offset_3);
2086
2087 END();
2088
2089 if (CAN_RUN()) {
2090 RUN();
2091
2092 ASSERT_EQUAL_64(0xf, x0);
2093 }
2094 }
2095
2096
TEST(adr)2097 TEST(adr) {
2098 SETUP();
2099
2100 Label label_1, label_2, label_3, label_4;
2101
2102 START();
2103 __ Mov(x0, 0x0); // Set to non-zero to indicate failure.
2104 __ Adr(x1, &label_3); // Set to zero to indicate success.
2105
2106 __ Adr(x2, &label_1); // Multiple forward references to the same label.
2107 __ Adr(x3, &label_1);
2108 __ Adr(x4, &label_1);
2109
2110 __ Bind(&label_2);
2111 __ Eor(x5, x2, Operand(x3)); // Ensure that x2,x3 and x4 are identical.
2112 __ Eor(x6, x2, Operand(x4));
2113 __ Orr(x0, x0, Operand(x5));
2114 __ Orr(x0, x0, Operand(x6));
2115 __ Br(x2); // label_1, label_3
2116
2117 __ Bind(&label_3);
2118 __ Adr(x2, &label_3); // Self-reference (offset 0).
2119 __ Eor(x1, x1, Operand(x2));
2120 __ Adr(x2, &label_4); // Simple forward reference.
2121 __ Br(x2); // label_4
2122
2123 __ Bind(&label_1);
2124 __ Adr(x2, &label_3); // Multiple reverse references to the same label.
2125 __ Adr(x3, &label_3);
2126 __ Adr(x4, &label_3);
2127 __ Adr(x5, &label_2); // Simple reverse reference.
2128 __ Br(x5); // label_2
2129
2130 __ Bind(&label_4);
2131 END();
2132
2133 if (CAN_RUN()) {
2134 RUN();
2135
2136 ASSERT_EQUAL_64(0x0, x0);
2137 ASSERT_EQUAL_64(0x0, x1);
2138 }
2139 }
2140
2141
2142 // Simple adrp tests: check that labels are linked and handled properly.
2143 // This is similar to the adr test, but all the adrp instructions are put on the
2144 // same page so that they return the same value.
TEST(adrp)2145 TEST(adrp) {
2146 Label start;
2147 Label label_1, label_2, label_3;
2148
2149 SETUP_CUSTOM(2 * kPageSize, PageOffsetDependentCode);
2150 START();
2151
2152 // Waste space until the start of a page.
2153 {
2154 ExactAssemblyScope scope(&masm,
2155 kPageSize,
2156 ExactAssemblyScope::kMaximumSize);
2157 const uintptr_t kPageOffsetMask = kPageSize - 1;
2158 while ((masm.GetCursorAddress<uintptr_t>() & kPageOffsetMask) != 0) {
2159 __ b(&start);
2160 }
2161 __ bind(&start);
2162 }
2163
2164 // Simple forward reference.
2165 __ Adrp(x0, &label_2);
2166
2167 __ Bind(&label_1);
2168
2169 // Multiple forward references to the same label.
2170 __ Adrp(x1, &label_3);
2171 __ Adrp(x2, &label_3);
2172 __ Adrp(x3, &label_3);
2173
2174 __ Bind(&label_2);
2175
2176 // Self-reference (offset 0).
2177 __ Adrp(x4, &label_2);
2178
2179 __ Bind(&label_3);
2180
2181 // Simple reverse reference.
2182 __ Adrp(x5, &label_1);
2183
2184 // Multiple reverse references to the same label.
2185 __ Adrp(x6, &label_2);
2186 __ Adrp(x7, &label_2);
2187 __ Adrp(x8, &label_2);
2188
2189 VIXL_ASSERT(masm.GetSizeOfCodeGeneratedSince(&start) < kPageSize);
2190 END();
2191 if (CAN_RUN()) {
2192 RUN();
2193
2194 uint64_t expected = reinterpret_cast<uint64_t>(
2195 AlignDown(masm.GetLabelAddress<uint64_t*>(&start), kPageSize));
2196 ASSERT_EQUAL_64(expected, x0);
2197 ASSERT_EQUAL_64(expected, x1);
2198 ASSERT_EQUAL_64(expected, x2);
2199 ASSERT_EQUAL_64(expected, x3);
2200 ASSERT_EQUAL_64(expected, x4);
2201 ASSERT_EQUAL_64(expected, x5);
2202 ASSERT_EQUAL_64(expected, x6);
2203 ASSERT_EQUAL_64(expected, x7);
2204 ASSERT_EQUAL_64(expected, x8);
2205 }
2206 }
2207
2208
AdrpPageBoundaryHelper(unsigned offset_into_page)2209 static void AdrpPageBoundaryHelper(unsigned offset_into_page) {
2210 VIXL_ASSERT(offset_into_page < kPageSize);
2211 VIXL_ASSERT((offset_into_page % kInstructionSize) == 0);
2212
2213 const uintptr_t kPageOffsetMask = kPageSize - 1;
2214
2215 // The test label is always bound on page 0. Adrp instructions are generated
2216 // on pages from kStartPage to kEndPage (inclusive).
2217 const int kStartPage = -16;
2218 const int kEndPage = 16;
2219 const int kMaxCodeSize = (kEndPage - kStartPage + 2) * kPageSize;
2220
2221 SETUP_CUSTOM(kMaxCodeSize, PageOffsetDependentCode);
2222 START();
2223
2224 Label test;
2225 Label start;
2226
2227 {
2228 ExactAssemblyScope scope(&masm,
2229 kMaxCodeSize,
2230 ExactAssemblyScope::kMaximumSize);
2231 // Initialize NZCV with `eq` flags.
2232 __ cmp(wzr, wzr);
2233 // Waste space until the start of a page.
2234 while ((masm.GetCursorAddress<uintptr_t>() & kPageOffsetMask) != 0) {
2235 __ b(&start);
2236 }
2237
2238 // The first page.
2239 VIXL_STATIC_ASSERT(kStartPage < 0);
2240 {
2241 ExactAssemblyScope scope_page(&masm, kPageSize);
2242 __ bind(&start);
2243 __ adrp(x0, &test);
2244 __ adrp(x1, &test);
2245 for (size_t i = 2; i < (kPageSize / kInstructionSize); i += 2) {
2246 __ ccmp(x0, x1, NoFlag, eq);
2247 __ adrp(x1, &test);
2248 }
2249 }
2250
2251 // Subsequent pages.
2252 VIXL_STATIC_ASSERT(kEndPage >= 0);
2253 for (int page = (kStartPage + 1); page <= kEndPage; page++) {
2254 ExactAssemblyScope scope_page(&masm, kPageSize);
2255 if (page == 0) {
2256 for (size_t i = 0; i < (kPageSize / kInstructionSize);) {
2257 if (i++ == (offset_into_page / kInstructionSize)) __ bind(&test);
2258 __ ccmp(x0, x1, NoFlag, eq);
2259 if (i++ == (offset_into_page / kInstructionSize)) __ bind(&test);
2260 __ adrp(x1, &test);
2261 }
2262 } else {
2263 for (size_t i = 0; i < (kPageSize / kInstructionSize); i += 2) {
2264 __ ccmp(x0, x1, NoFlag, eq);
2265 __ adrp(x1, &test);
2266 }
2267 }
2268 }
2269 }
2270
2271 // Every adrp instruction pointed to the same label (`test`), so they should
2272 // all have produced the same result.
2273
2274 END();
2275 if (CAN_RUN()) {
2276 RUN();
2277
2278 uintptr_t expected =
2279 AlignDown(masm.GetLabelAddress<uintptr_t>(&test), kPageSize);
2280 ASSERT_EQUAL_64(expected, x0);
2281 ASSERT_EQUAL_64(expected, x1);
2282 ASSERT_EQUAL_NZCV(ZCFlag);
2283 }
2284 }
2285
2286
2287 // Test that labels are correctly referenced by adrp across page boundaries.
TEST(adrp_page_boundaries)2288 TEST(adrp_page_boundaries) {
2289 VIXL_STATIC_ASSERT(kPageSize == 4096);
2290 AdrpPageBoundaryHelper(kInstructionSize * 0);
2291 AdrpPageBoundaryHelper(kInstructionSize * 1);
2292 AdrpPageBoundaryHelper(kInstructionSize * 512);
2293 AdrpPageBoundaryHelper(kInstructionSize * 1022);
2294 AdrpPageBoundaryHelper(kInstructionSize * 1023);
2295 }
2296
2297
AdrpOffsetHelper(int64_t offset)2298 static void AdrpOffsetHelper(int64_t offset) {
2299 const size_t kPageOffsetMask = kPageSize - 1;
2300 const int kMaxCodeSize = 2 * kPageSize;
2301
2302 SETUP_CUSTOM(kMaxCodeSize, PageOffsetDependentCode);
2303 START();
2304
2305 Label page;
2306
2307 {
2308 ExactAssemblyScope scope(&masm,
2309 kMaxCodeSize,
2310 ExactAssemblyScope::kMaximumSize);
2311 // Initialize NZCV with `eq` flags.
2312 __ cmp(wzr, wzr);
2313 // Waste space until the start of a page.
2314 while ((masm.GetCursorAddress<uintptr_t>() & kPageOffsetMask) != 0) {
2315 __ b(&page);
2316 }
2317 __ bind(&page);
2318
2319 {
2320 ExactAssemblyScope scope_page(&masm, kPageSize);
2321 // Every adrp instruction on this page should return the same value.
2322 __ adrp(x0, offset);
2323 __ adrp(x1, offset);
2324 for (size_t i = 2; i < kPageSize / kInstructionSize; i += 2) {
2325 __ ccmp(x0, x1, NoFlag, eq);
2326 __ adrp(x1, offset);
2327 }
2328 }
2329 }
2330
2331 END();
2332 if (CAN_RUN()) {
2333 RUN();
2334
2335 uintptr_t expected =
2336 masm.GetLabelAddress<uintptr_t>(&page) + (kPageSize * offset);
2337 ASSERT_EQUAL_64(expected, x0);
2338 ASSERT_EQUAL_64(expected, x1);
2339 ASSERT_EQUAL_NZCV(ZCFlag);
2340 }
2341 }
2342
2343
2344 // Check that adrp produces the correct result for a specific offset.
TEST(adrp_offset)2345 TEST(adrp_offset) {
2346 AdrpOffsetHelper(0);
2347 AdrpOffsetHelper(1);
2348 AdrpOffsetHelper(-1);
2349 AdrpOffsetHelper(4);
2350 AdrpOffsetHelper(-4);
2351 AdrpOffsetHelper(0x000fffff);
2352 AdrpOffsetHelper(-0x000fffff);
2353 AdrpOffsetHelper(-0x00100000);
2354 }
2355
2356
TEST(branch_cond)2357 TEST(branch_cond) {
2358 SETUP();
2359
2360 Label done, wrong;
2361
2362 START();
2363 __ Mov(x0, 0x1);
2364 __ Mov(x1, 0x1);
2365 __ Mov(x2, 0x8000000000000000);
2366
2367 // For each 'cmp' instruction below, condition codes other than the ones
2368 // following it would branch.
2369
2370 __ Cmp(x1, 0);
2371 __ B(&wrong, eq);
2372 __ B(&wrong, lo);
2373 __ B(&wrong, mi);
2374 __ B(&wrong, vs);
2375 __ B(&wrong, ls);
2376 __ B(&wrong, lt);
2377 __ B(&wrong, le);
2378 Label ok_1;
2379 __ B(&ok_1, ne);
2380 __ Mov(x0, 0x0);
2381 __ Bind(&ok_1);
2382
2383 __ Cmp(x1, 1);
2384 __ B(&wrong, ne);
2385 __ B(&wrong, lo);
2386 __ B(&wrong, mi);
2387 __ B(&wrong, vs);
2388 __ B(&wrong, hi);
2389 __ B(&wrong, lt);
2390 __ B(&wrong, gt);
2391 Label ok_2;
2392 __ B(&ok_2, pl);
2393 __ Mov(x0, 0x0);
2394 __ Bind(&ok_2);
2395
2396 __ Cmp(x1, 2);
2397 __ B(&wrong, eq);
2398 __ B(&wrong, hs);
2399 __ B(&wrong, pl);
2400 __ B(&wrong, vs);
2401 __ B(&wrong, hi);
2402 __ B(&wrong, ge);
2403 __ B(&wrong, gt);
2404 Label ok_3;
2405 __ B(&ok_3, vc);
2406 __ Mov(x0, 0x0);
2407 __ Bind(&ok_3);
2408
2409 __ Cmp(x2, 1);
2410 __ B(&wrong, eq);
2411 __ B(&wrong, lo);
2412 __ B(&wrong, mi);
2413 __ B(&wrong, vc);
2414 __ B(&wrong, ls);
2415 __ B(&wrong, ge);
2416 __ B(&wrong, gt);
2417 Label ok_4;
2418 __ B(&ok_4, le);
2419 __ Mov(x0, 0x0);
2420 __ Bind(&ok_4);
2421
2422 // The MacroAssembler does not allow al as a branch condition.
2423 Label ok_5;
2424 {
2425 ExactAssemblyScope scope(&masm, kInstructionSize);
2426 __ b(&ok_5, al);
2427 }
2428 __ Mov(x0, 0x0);
2429 __ Bind(&ok_5);
2430
2431 // The MacroAssembler does not allow nv as a branch condition.
2432 Label ok_6;
2433 {
2434 ExactAssemblyScope scope(&masm, kInstructionSize);
2435 __ b(&ok_6, nv);
2436 }
2437 __ Mov(x0, 0x0);
2438 __ Bind(&ok_6);
2439
2440 __ B(&done);
2441
2442 __ Bind(&wrong);
2443 __ Mov(x0, 0x0);
2444
2445 __ Bind(&done);
2446 END();
2447
2448 if (CAN_RUN()) {
2449 RUN();
2450
2451 ASSERT_EQUAL_64(0x1, x0);
2452 }
2453 }
2454
2455
TEST(branch_to_reg)2456 TEST(branch_to_reg) {
2457 SETUP();
2458
2459 // Test br.
2460 Label fn1, after_fn1;
2461
2462 START();
2463 __ Mov(x29, lr);
2464
2465 __ Mov(x1, 0);
2466 __ B(&after_fn1);
2467
2468 __ Bind(&fn1);
2469 __ Mov(x0, lr);
2470 __ Mov(x1, 42);
2471 __ Br(x0);
2472
2473 __ Bind(&after_fn1);
2474 __ Bl(&fn1);
2475
2476 // Test blr.
2477 Label fn2, after_fn2, after_bl2;
2478
2479 __ Mov(x2, 0);
2480 __ B(&after_fn2);
2481
2482 __ Bind(&fn2);
2483 __ Mov(x0, lr);
2484 __ Mov(x2, 84);
2485 __ Blr(x0);
2486
2487 __ Bind(&after_fn2);
2488 __ Bl(&fn2);
2489 __ Bind(&after_bl2);
2490 __ Mov(x3, lr);
2491 __ Adr(x4, &after_bl2);
2492 __ Adr(x5, &after_fn2);
2493
2494 __ Mov(lr, x29);
2495 END();
2496
2497 if (CAN_RUN()) {
2498 RUN();
2499
2500 ASSERT_EQUAL_64(x4, x0);
2501 ASSERT_EQUAL_64(x5, x3);
2502 ASSERT_EQUAL_64(42, x1);
2503 ASSERT_EQUAL_64(84, x2);
2504 }
2505 }
2506
TEST(branch_to_reg_auth_a)2507 TEST(branch_to_reg_auth_a) {
2508 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
2509
2510 START();
2511
2512 Label fn1, after_fn1;
2513
2514 __ Mov(x28, 0x477d469dec0b8760);
2515 __ Mov(x29, lr);
2516
2517 __ Mov(x1, 0);
2518 __ B(&after_fn1);
2519
2520 __ Bind(&fn1);
2521 __ Mov(x0, lr);
2522 __ Mov(x1, 42);
2523 __ Pacia(x0, x28);
2524 __ Braa(x0, x28);
2525
2526 __ Bind(&after_fn1);
2527 __ Bl(&fn1);
2528
2529 Label fn2, after_fn2, after_bl2;
2530
2531 __ Mov(x2, 0);
2532 __ B(&after_fn2);
2533
2534 __ Bind(&fn2);
2535 __ Mov(x0, lr);
2536 __ Mov(x2, 84);
2537 __ Pacia(x0, x28);
2538 __ Blraa(x0, x28);
2539
2540 __ Bind(&after_fn2);
2541 __ Bl(&fn2);
2542 __ Bind(&after_bl2);
2543 __ Mov(x3, lr);
2544 __ Adr(x4, &after_bl2);
2545 __ Adr(x5, &after_fn2);
2546
2547 __ Xpaci(x0);
2548 __ Mov(lr, x29);
2549 END();
2550
2551 if (CAN_RUN()) {
2552 RUN();
2553
2554 ASSERT_EQUAL_64(x4, x0);
2555 ASSERT_EQUAL_64(x5, x3);
2556 ASSERT_EQUAL_64(42, x1);
2557 ASSERT_EQUAL_64(84, x2);
2558 }
2559 }
2560
TEST(return_to_reg_auth)2561 TEST(return_to_reg_auth) {
2562 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
2563
2564 START();
2565
2566 Label fn1, after_fn1;
2567
2568 __ Mov(x28, sp);
2569 __ Mov(x29, lr);
2570 __ Mov(sp, 0x477d469dec0b8760);
2571
2572 __ Mov(x0, 0);
2573 __ B(&after_fn1);
2574
2575 __ Bind(&fn1);
2576 __ Mov(x0, 42);
2577 __ Paciasp();
2578 __ Retaa();
2579
2580 __ Bind(&after_fn1);
2581 __ Bl(&fn1);
2582
2583 Label fn2, after_fn2;
2584
2585 __ Mov(x1, 0);
2586 __ B(&after_fn2);
2587
2588 __ Bind(&fn2);
2589 __ Mov(x1, 84);
2590 __ Pacibsp();
2591 __ Retab();
2592
2593 __ Bind(&after_fn2);
2594 __ Bl(&fn2);
2595
2596 __ Mov(sp, x28);
2597 __ Mov(lr, x29);
2598 END();
2599
2600 if (CAN_RUN()) {
2601 RUN();
2602
2603 ASSERT_EQUAL_64(42, x0);
2604 ASSERT_EQUAL_64(84, x1);
2605 }
2606 }
2607
TEST(return_to_reg_auth_guarded)2608 TEST(return_to_reg_auth_guarded) {
2609 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
2610
2611 START();
2612
2613 Label fn1, after_fn1;
2614
2615 __ Mov(x28, sp);
2616 __ Mov(x29, lr);
2617 __ Mov(sp, 0x477d469dec0b8760);
2618
2619 __ Mov(x0, 0);
2620 __ B(&after_fn1);
2621
2622 __ Bind(&fn1, EmitPACIASP);
2623 __ Mov(x0, 42);
2624 __ Retaa();
2625
2626 __ Bind(&after_fn1);
2627 __ Adr(x2, &fn1);
2628 __ Blr(x2);
2629
2630 Label fn2, after_fn2;
2631
2632 __ Mov(x1, 0);
2633 __ B(&after_fn2);
2634
2635 __ Bind(&fn2, EmitPACIBSP);
2636 __ Mov(x1, 84);
2637 __ Retab();
2638
2639 __ Bind(&after_fn2);
2640 __ Adr(x2, &fn2);
2641 __ Blr(x2);
2642
2643 __ Mov(sp, x28);
2644 __ Mov(lr, x29);
2645 END();
2646
2647 if (CAN_RUN()) {
2648 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
2649 simulator.SetGuardedPages(true);
2650 #endif
2651 // On hardware, we'll run the test anyway, but mark it as SKIPPED until
2652 // we've implemented a mechanism for marking Guarded pages.
2653
2654 RUN();
2655
2656 ASSERT_EQUAL_64(42, x0);
2657 ASSERT_EQUAL_64(84, x1);
2658
2659 #ifndef VIXL_INCLUDE_SIMULATOR_AARCH64
2660 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
2661 #endif
2662 }
2663 }
2664
2665 #ifdef VIXL_NEGATIVE_TESTING
TEST(branch_to_reg_auth_fail)2666 TEST(branch_to_reg_auth_fail) {
2667 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
2668
2669 START();
2670
2671 Label fn1, after_fn1;
2672
2673 __ Mov(x29, lr);
2674
2675 __ B(&after_fn1);
2676
2677 __ Bind(&fn1);
2678 __ Mov(x0, lr);
2679 __ Pacizb(x0);
2680 __ Blraaz(x0);
2681
2682 __ Bind(&after_fn1);
2683 // There is a small but not negligible chance (1 in 127 runs) that the PAC
2684 // codes for keys A and B will collide and BLRAAZ won't abort. To mitigate
2685 // this, we simply repeat the test a few more times.
2686 for (unsigned i = 0; i < 32; i++) {
2687 __ Bl(&fn1);
2688 }
2689
2690 __ Mov(lr, x29);
2691 END();
2692
2693 if (CAN_RUN()) {
2694 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
2695 MUST_FAIL_WITH_MESSAGE(RUN(), "Failed to authenticate pointer.");
2696 #else
2697 printf("SKIPPED: negative PAuth tests are unimplemented on hardware.");
2698 #endif
2699 }
2700 }
2701 #endif // VIXL_NEGATIVE_TESTING
2702
2703 #ifdef VIXL_NEGATIVE_TESTING
TEST(return_to_reg_auth_fail)2704 TEST(return_to_reg_auth_fail) {
2705 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
2706
2707 START();
2708
2709 Label fn1, after_fn1;
2710
2711 __ Mov(x28, sp);
2712 __ Mov(x29, lr);
2713 __ Mov(sp, 0x477d469dec0b8760);
2714
2715 __ B(&after_fn1);
2716
2717 __ Bind(&fn1);
2718 __ Paciasp();
2719 __ Retab();
2720
2721 __ Bind(&after_fn1);
2722 // There is a small but not negligible chance (1 in 127 runs) that the PAC
2723 // codes for keys A and B will collide and RETAB won't abort. To mitigate
2724 // this, we simply repeat the test a few more times.
2725 for (unsigned i = 0; i < 32; i++) {
2726 __ Bl(&fn1);
2727 }
2728
2729 __ Mov(sp, x28);
2730 __ Mov(lr, x29);
2731 END();
2732
2733 if (CAN_RUN()) {
2734 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
2735 MUST_FAIL_WITH_MESSAGE(RUN(), "Failed to authenticate pointer.");
2736 #else
2737 printf("SKIPPED: negative PAuth tests are unimplemented on hardware.");
2738 #endif
2739 }
2740 }
2741 #endif // VIXL_NEGATIVE_TESTING
2742
TEST(branch_to_reg_auth_a_zero)2743 TEST(branch_to_reg_auth_a_zero) {
2744 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
2745
2746 START();
2747
2748 Label fn1, after_fn1;
2749
2750 __ Mov(x29, lr);
2751
2752 __ Mov(x1, 0);
2753 __ B(&after_fn1);
2754
2755 __ Bind(&fn1);
2756 __ Mov(x0, lr);
2757 __ Mov(x1, 42);
2758 __ Paciza(x0);
2759 __ Braaz(x0);
2760
2761 __ Bind(&after_fn1);
2762 __ Bl(&fn1);
2763
2764 Label fn2, after_fn2, after_bl2;
2765
2766 __ Mov(x2, 0);
2767 __ B(&after_fn2);
2768
2769 __ Bind(&fn2);
2770 __ Mov(x0, lr);
2771 __ Mov(x2, 84);
2772 __ Paciza(x0);
2773 __ Blraaz(x0);
2774
2775 __ Bind(&after_fn2);
2776 __ Bl(&fn2);
2777 __ Bind(&after_bl2);
2778 __ Mov(x3, lr);
2779 __ Adr(x4, &after_bl2);
2780 __ Adr(x5, &after_fn2);
2781
2782 __ Xpaci(x0);
2783 __ Mov(lr, x29);
2784 END();
2785
2786 if (CAN_RUN()) {
2787 RUN();
2788
2789 ASSERT_EQUAL_64(x4, x0);
2790 ASSERT_EQUAL_64(x5, x3);
2791 ASSERT_EQUAL_64(42, x1);
2792 ASSERT_EQUAL_64(84, x2);
2793 }
2794 }
2795
2796
TEST(compare_branch)2797 TEST(compare_branch) {
2798 SETUP();
2799
2800 START();
2801 __ Mov(x0, 0);
2802 __ Mov(x1, 0);
2803 __ Mov(x2, 0);
2804 __ Mov(x3, 0);
2805 __ Mov(x4, 0);
2806 __ Mov(x5, 0);
2807 __ Mov(x16, 0);
2808 __ Mov(x17, 42);
2809
2810 Label zt, zt_end;
2811 __ Cbz(w16, &zt);
2812 __ B(&zt_end);
2813 __ Bind(&zt);
2814 __ Mov(x0, 1);
2815 __ Bind(&zt_end);
2816
2817 Label zf, zf_end;
2818 __ Cbz(x17, &zf);
2819 __ B(&zf_end);
2820 __ Bind(&zf);
2821 __ Mov(x1, 1);
2822 __ Bind(&zf_end);
2823
2824 Label nzt, nzt_end;
2825 __ Cbnz(w17, &nzt);
2826 __ B(&nzt_end);
2827 __ Bind(&nzt);
2828 __ Mov(x2, 1);
2829 __ Bind(&nzt_end);
2830
2831 Label nzf, nzf_end;
2832 __ Cbnz(x16, &nzf);
2833 __ B(&nzf_end);
2834 __ Bind(&nzf);
2835 __ Mov(x3, 1);
2836 __ Bind(&nzf_end);
2837
2838 __ Mov(x18, 0xffffffff00000000);
2839
2840 Label a, a_end;
2841 __ Cbz(w18, &a);
2842 __ B(&a_end);
2843 __ Bind(&a);
2844 __ Mov(x4, 1);
2845 __ Bind(&a_end);
2846
2847 Label b, b_end;
2848 __ Cbnz(w18, &b);
2849 __ B(&b_end);
2850 __ Bind(&b);
2851 __ Mov(x5, 1);
2852 __ Bind(&b_end);
2853
2854 END();
2855
2856 if (CAN_RUN()) {
2857 RUN();
2858
2859 ASSERT_EQUAL_64(1, x0);
2860 ASSERT_EQUAL_64(0, x1);
2861 ASSERT_EQUAL_64(1, x2);
2862 ASSERT_EQUAL_64(0, x3);
2863 ASSERT_EQUAL_64(1, x4);
2864 ASSERT_EQUAL_64(0, x5);
2865 }
2866 }
2867
2868
TEST(test_branch)2869 TEST(test_branch) {
2870 SETUP();
2871
2872 START();
2873 __ Mov(x0, 0);
2874 __ Mov(x1, 0);
2875 __ Mov(x2, 0);
2876 __ Mov(x3, 0);
2877 __ Mov(x16, 0xaaaaaaaaaaaaaaaa);
2878
2879 Label bz, bz_end;
2880 __ Tbz(w16, 0, &bz);
2881 __ B(&bz_end);
2882 __ Bind(&bz);
2883 __ Mov(x0, 1);
2884 __ Bind(&bz_end);
2885
2886 Label bo, bo_end;
2887 __ Tbz(x16, 63, &bo);
2888 __ B(&bo_end);
2889 __ Bind(&bo);
2890 __ Mov(x1, 1);
2891 __ Bind(&bo_end);
2892
2893 Label nbz, nbz_end;
2894 __ Tbnz(x16, 61, &nbz);
2895 __ B(&nbz_end);
2896 __ Bind(&nbz);
2897 __ Mov(x2, 1);
2898 __ Bind(&nbz_end);
2899
2900 Label nbo, nbo_end;
2901 __ Tbnz(w16, 2, &nbo);
2902 __ B(&nbo_end);
2903 __ Bind(&nbo);
2904 __ Mov(x3, 1);
2905 __ Bind(&nbo_end);
2906 END();
2907
2908 if (CAN_RUN()) {
2909 RUN();
2910
2911 ASSERT_EQUAL_64(1, x0);
2912 ASSERT_EQUAL_64(0, x1);
2913 ASSERT_EQUAL_64(1, x2);
2914 ASSERT_EQUAL_64(0, x3);
2915 }
2916 }
2917
2918
TEST(branch_type)2919 TEST(branch_type) {
2920 SETUP();
2921
2922 Label fail, done;
2923
2924 START();
2925 __ Mov(x0, 0x0);
2926 __ Mov(x10, 0x7);
2927 __ Mov(x11, 0x0);
2928
2929 // Test non taken branches.
2930 __ Cmp(x10, 0x7);
2931 __ B(&fail, ne);
2932 __ B(&fail, never);
2933 __ B(&fail, reg_zero, x10);
2934 __ B(&fail, reg_not_zero, x11);
2935 __ B(&fail, reg_bit_clear, x10, 0);
2936 __ B(&fail, reg_bit_set, x10, 3);
2937
2938 // Test taken branches.
2939 Label l1, l2, l3, l4, l5;
2940 __ Cmp(x10, 0x7);
2941 __ B(&l1, eq);
2942 __ B(&fail);
2943 __ Bind(&l1);
2944 __ B(&l2, always);
2945 __ B(&fail);
2946 __ Bind(&l2);
2947 __ B(&l3, reg_not_zero, x10);
2948 __ B(&fail);
2949 __ Bind(&l3);
2950 __ B(&l4, reg_bit_clear, x10, 15);
2951 __ B(&fail);
2952 __ Bind(&l4);
2953 __ B(&l5, reg_bit_set, x10, 1);
2954 __ B(&fail);
2955 __ Bind(&l5);
2956
2957 __ B(&done);
2958
2959 __ Bind(&fail);
2960 __ Mov(x0, 0x1);
2961
2962 __ Bind(&done);
2963
2964 END();
2965
2966 if (CAN_RUN()) {
2967 RUN();
2968
2969 ASSERT_EQUAL_64(0x0, x0);
2970 }
2971 }
2972
2973 enum MTEStgAttribute {
2974 StgNoSideEffect = 0,
2975 StgPairTag = 1,
2976 StgZeroing = 2,
2977 StgPairReg = 4
2978 };
2979
2980 // Support st2g, stg, stz2g and stzg.
2981 template <typename Op>
MTEStoreTagHelper(Op op,AddrMode addr_mode,int attr=StgNoSideEffect)2982 static void MTEStoreTagHelper(Op op,
2983 AddrMode addr_mode,
2984 int attr = StgNoSideEffect) {
2985 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
2986 START();
2987
2988 // This method does nothing when the size is zero. i.e. stg and st2g.
2989 // Reserve x9 and x10.
2990 auto LoadDataAndSum = [&](Register reg, int off, unsigned size_in_bytes) {
2991 for (unsigned j = 0; j < size_in_bytes / kXRegSizeInBytes; j++) {
2992 __ Ldr(x9, MemOperand(reg, off));
2993 __ Add(x10, x9, x10);
2994 off += kXRegSizeInBytes;
2995 }
2996 };
2997
2998 // Initialize registers to zero.
2999 for (int i = 0; i < 29; i++) {
3000 __ Mov(XRegister(i), 0);
3001 }
3002
3003 Register base = x28;
3004 Register base_tag = x27;
3005 uint32_t* data_ptr = nullptr;
3006 const int data_size = 640;
3007 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
3008 data_ptr = reinterpret_cast<uint32_t*>(
3009 simulator.Mmap(NULL,
3010 data_size * sizeof(uint32_t),
3011 PROT_READ | PROT_WRITE | PROT_MTE,
3012 MAP_PRIVATE | MAP_ANONYMOUS,
3013 -1,
3014 0));
3015
3016 VIXL_ASSERT(data_ptr != nullptr);
3017 uint32_t* untagged_ptr = AddressUntag(data_ptr);
3018 memset(untagged_ptr, 0xae, data_size * sizeof(uint32_t));
3019 #else
3020 // TODO: Port the memory allocation to work on MTE supported platform natively.
3021 // Note that `CAN_RUN` prevents running in MTE-unsupported environments.
3022 #endif
3023
3024 __ Mov(base, reinterpret_cast<uint64_t>(&data_ptr[data_size / 2]));
3025
3026 VIXL_STATIC_ASSERT(kMTETagGranuleInBytes == 16);
3027 const int tag_granule = kMTETagGranuleInBytes;
3028 int size = ((attr & StgZeroing) != 0) ? tag_granule : 0;
3029 // lsb of MTE tag field.
3030 const int tag_lsb = 56;
3031
3032 for (int i = 1; i < 7; i++) {
3033 uint64_t tag = static_cast<uint64_t>(i) << tag_lsb;
3034 int offset = 2 * i * tag_granule;
3035 __ Mov(XRegister(i), tag);
3036 (masm.*op)(XRegister(i), MemOperand(base, offset, addr_mode));
3037
3038 // The address tag has been changed after the execution of store tag
3039 // instructions, so update the pointer tag as well.
3040 __ Bic(base_tag, base, 0x0f00000000000000);
3041 __ Orr(base_tag, base_tag, XRegister(i));
3042
3043 switch (addr_mode) {
3044 case Offset:
3045 __ Ldg(XRegister(i + 10), MemOperand(base_tag, offset));
3046 LoadDataAndSum(base_tag, offset, size);
3047 if ((attr & StgPairTag) != 0) {
3048 __ Ldg(XRegister(i + 20), MemOperand(base_tag, offset + tag_granule));
3049 LoadDataAndSum(base_tag, offset + tag_granule, size);
3050 }
3051 break;
3052
3053 case PreIndex:
3054 __ Ldg(XRegister(i + 10), MemOperand(base_tag));
3055 LoadDataAndSum(base_tag, 0, size);
3056 if ((attr & StgPairTag) != 0) {
3057 __ Ldg(XRegister(i + 20), MemOperand(base_tag, tag_granule));
3058 LoadDataAndSum(base_tag, tag_granule, size);
3059 }
3060 break;
3061
3062 case PostIndex:
3063 __ Ldg(XRegister(i + 10), MemOperand(base_tag, -offset));
3064 LoadDataAndSum(base_tag, -offset, size);
3065 if ((attr & StgPairTag) != 0) {
3066 __ Ldg(XRegister(i + 20),
3067 MemOperand(base_tag, -offset + tag_granule));
3068 LoadDataAndSum(base_tag, -offset + tag_granule, size);
3069 }
3070 break;
3071
3072 default:
3073 VIXL_UNIMPLEMENTED();
3074 break;
3075 }
3076
3077 // Switch the sign to test both positive and negative offsets.
3078 offset = -offset;
3079 }
3080
3081 int pos_offset = 304;
3082 int neg_offset = -256;
3083
3084 // Backup stack pointer and others.
3085 __ Mov(x7, sp);
3086 __ Mov(base_tag, base);
3087
3088 // Test the cases where operand is the stack pointer.
3089 __ Mov(x8, 11UL << tag_lsb);
3090 __ Mov(sp, x8);
3091 (masm.*op)(sp, MemOperand(base, neg_offset, addr_mode));
3092
3093 // Synthesise a new address with new tag and assign to the stack pointer.
3094 __ Add(sp, base_tag, 32);
3095 (masm.*op)(x8, MemOperand(sp, pos_offset, addr_mode));
3096
3097 switch (addr_mode) {
3098 case Offset:
3099 __ Ldg(x17, MemOperand(base, neg_offset));
3100 __ Ldg(x19, MemOperand(sp, pos_offset));
3101 if ((attr & StgPairTag) != 0) {
3102 __ Ldg(x18, MemOperand(base, neg_offset + tag_granule));
3103 __ Ldg(x20, MemOperand(sp, pos_offset + tag_granule));
3104 }
3105 break;
3106 case PreIndex:
3107 __ Ldg(x17, MemOperand(base));
3108 __ Ldg(x19, MemOperand(sp));
3109 if ((attr & StgPairTag) != 0) {
3110 __ Ldg(x18, MemOperand(base, tag_granule));
3111 __ Ldg(x20, MemOperand(sp, tag_granule));
3112 }
3113 break;
3114 case PostIndex:
3115 __ Ldg(x17, MemOperand(base, -neg_offset));
3116 __ Ldg(x19, MemOperand(sp, -pos_offset));
3117 if ((attr & StgPairTag) != 0) {
3118 __ Ldg(x18, MemOperand(base, -neg_offset + tag_granule));
3119 __ Ldg(x20, MemOperand(sp, -pos_offset + tag_granule));
3120 }
3121 break;
3122 default:
3123 VIXL_UNIMPLEMENTED();
3124 break;
3125 }
3126
3127 // Restore stack pointer.
3128 __ Mov(sp, x7);
3129
3130 END();
3131
3132 if (CAN_RUN()) {
3133 #ifndef VIXL_INCLUDE_SIMULATOR_AARCH64
3134 VIXL_UNIMPLEMENTED();
3135 #endif
3136 RUN();
3137
3138 ASSERT_EQUAL_64(1UL << tag_lsb, x11);
3139 ASSERT_EQUAL_64(2UL << tag_lsb, x12);
3140 ASSERT_EQUAL_64(3UL << tag_lsb, x13);
3141 ASSERT_EQUAL_64(4UL << tag_lsb, x14);
3142 ASSERT_EQUAL_64(5UL << tag_lsb, x15);
3143 ASSERT_EQUAL_64(6UL << tag_lsb, x16);
3144 ASSERT_EQUAL_64(11UL << tag_lsb, x17);
3145 ASSERT_EQUAL_64(11UL << tag_lsb, x19);
3146
3147 if ((attr & StgPairTag) != 0) {
3148 ASSERT_EQUAL_64(1UL << tag_lsb, x21);
3149 ASSERT_EQUAL_64(2UL << tag_lsb, x22);
3150 ASSERT_EQUAL_64(3UL << tag_lsb, x23);
3151 ASSERT_EQUAL_64(4UL << tag_lsb, x24);
3152 ASSERT_EQUAL_64(5UL << tag_lsb, x25);
3153 ASSERT_EQUAL_64(6UL << tag_lsb, x26);
3154 ASSERT_EQUAL_64(11UL << tag_lsb, x18);
3155 ASSERT_EQUAL_64(11UL << tag_lsb, x20);
3156 }
3157
3158 if ((attr & StgZeroing) != 0) {
3159 ASSERT_EQUAL_64(0, x10);
3160 }
3161 }
3162
3163 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
3164 simulator.Munmap(data_ptr, data_size, PROT_MTE);
3165 #endif
3166 }
3167
TEST(st2g_ldg)3168 TEST(st2g_ldg) {
3169 MTEStoreTagHelper(&MacroAssembler::St2g, Offset, StgPairTag);
3170 MTEStoreTagHelper(&MacroAssembler::St2g, PreIndex, StgPairTag);
3171 MTEStoreTagHelper(&MacroAssembler::St2g, PostIndex, StgPairTag);
3172 }
3173
TEST(stg_ldg)3174 TEST(stg_ldg) {
3175 MTEStoreTagHelper(&MacroAssembler::Stg, Offset);
3176 MTEStoreTagHelper(&MacroAssembler::Stg, PreIndex);
3177 MTEStoreTagHelper(&MacroAssembler::Stg, PostIndex);
3178 }
3179
TEST(stz2g_ldg)3180 TEST(stz2g_ldg) {
3181 MTEStoreTagHelper(&MacroAssembler::Stz2g, Offset, StgPairTag | StgZeroing);
3182 MTEStoreTagHelper(&MacroAssembler::Stz2g, PreIndex, StgPairTag | StgZeroing);
3183 MTEStoreTagHelper(&MacroAssembler::Stz2g, PostIndex, StgPairTag | StgZeroing);
3184 }
3185
TEST(stzg_ldg)3186 TEST(stzg_ldg) {
3187 MTEStoreTagHelper(&MacroAssembler::Stzg, Offset, StgZeroing);
3188 MTEStoreTagHelper(&MacroAssembler::Stzg, PreIndex, StgZeroing);
3189 MTEStoreTagHelper(&MacroAssembler::Stzg, PostIndex, StgZeroing);
3190 }
3191
TEST(stgp_ldg)3192 TEST(stgp_ldg) {
3193 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
3194 START();
3195
3196 // Initialize registers to zero.
3197 for (int i = 0; i < 29; i++) {
3198 __ Mov(XRegister(i), 0);
3199 }
3200
3201 // Reserve x14 and x15.
3202 auto LoadDataAndSum = [&](Register reg, int off) {
3203 __ Ldr(x14, MemOperand(reg, off));
3204 __ Add(x15, x14, x15);
3205 __ Ldr(x14, MemOperand(reg, off + static_cast<int>(kXRegSizeInBytes)));
3206 __ Add(x15, x14, x15);
3207 };
3208
3209 Register base = x28;
3210 uint32_t* data_ptr = nullptr;
3211 const int data_size = 640;
3212 uint64_t init_tag = 17;
3213 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
3214 data_ptr = reinterpret_cast<uint32_t*>(
3215 simulator.Mmap(NULL,
3216 data_size * sizeof(uint32_t),
3217 PROT_READ | PROT_WRITE | PROT_MTE,
3218 MAP_PRIVATE | MAP_ANONYMOUS,
3219 -1,
3220 0));
3221
3222 VIXL_ASSERT(data_ptr != nullptr);
3223 init_tag = CPU::GetPointerTag(data_ptr);
3224 uint32_t* untagged_ptr = AddressUntag(data_ptr);
3225 memset(untagged_ptr, 0xc9, data_size * sizeof(uint32_t));
3226 #else
3227 // TODO: Port the memory allocation to work on MTE supported platform natively.
3228 // Note that `CAN_RUN` prevents running in MTE-unsupported environments.
3229 #endif
3230
3231 __ Mov(base, reinterpret_cast<uint64_t>(&data_ptr[data_size / 2]));
3232
3233 // lsb of MTE tag field.
3234 const int tag_lsb = 56;
3235 for (int i = 0; i < 11; i++) {
3236 // <63..60> <59..56> <55........5> <4..0>
3237 // 0 i 0 i
3238 __ Mov(XRegister(i), i | (static_cast<uint64_t>(i) << tag_lsb));
3239 }
3240
3241 // Backup stack pointer.
3242 __ Mov(x0, sp);
3243
3244 int offset = -16;
3245 __ Addg(base, base, 0, 1);
3246 __ Stgp(x1, x2, MemOperand(base, offset, Offset));
3247 // Make sure `ldg` works well with address that isn't tag-granule aligned.
3248 __ Add(x29, base, 8);
3249 __ Ldg(x18, MemOperand(x29, offset));
3250 LoadDataAndSum(base, offset);
3251
3252 offset = -304;
3253 __ Addg(base, base, 0, 1);
3254 __ Stgp(x2, x3, MemOperand(base, offset, Offset));
3255 __ Add(x29, base, 4);
3256 __ Ldg(x19, MemOperand(x29, offset));
3257 LoadDataAndSum(base, offset);
3258
3259 offset = 128;
3260 __ Addg(base, base, 0, 1);
3261 __ Stgp(x3, x4, MemOperand(base, offset, Offset));
3262 __ Mov(sp, base);
3263 __ Ldg(x20, MemOperand(sp, offset));
3264 LoadDataAndSum(base, offset);
3265
3266 offset = -48;
3267 __ Addg(base, base, 0, 1);
3268 __ Stgp(x4, x5, MemOperand(base, offset, PreIndex));
3269 __ Add(x29, base, 8);
3270 __ Ldg(x21, MemOperand(x29));
3271 LoadDataAndSum(base, 0);
3272
3273 offset = 64;
3274 __ Addg(base, base, 0, 1);
3275 __ Stgp(x5, x6, MemOperand(base, offset, PreIndex));
3276 __ Add(x29, base, 4);
3277 __ Ldg(x22, MemOperand(x29));
3278 LoadDataAndSum(base, 0);
3279
3280 offset = -288;
3281 __ Addg(base, base, 0, 1);
3282 __ Stgp(x6, x7, MemOperand(base, offset, PreIndex));
3283 __ Mov(sp, base);
3284 __ Ldg(x23, MemOperand(sp));
3285 LoadDataAndSum(base, 0);
3286
3287 offset = -96;
3288 __ Addg(base, base, 0, 1);
3289 __ Stgp(x7, x8, MemOperand(base, offset, PostIndex));
3290 __ Add(x29, base, 8);
3291 __ Ldg(x24, MemOperand(x29, -offset));
3292 LoadDataAndSum(base, -offset);
3293
3294 offset = 80;
3295 __ Addg(base, base, 0, 1);
3296 __ Stgp(x8, x9, MemOperand(base, offset, PostIndex));
3297 __ Add(x29, base, 4);
3298 __ Ldg(x25, MemOperand(x29, -offset));
3299 LoadDataAndSum(base, -offset);
3300
3301 offset = -224;
3302 __ Addg(base, base, 0, 1);
3303 __ Stgp(x9, x10, MemOperand(base, offset, PostIndex));
3304 __ Mov(sp, base);
3305 __ Ldg(x26, MemOperand(sp, -offset));
3306 LoadDataAndSum(base, -offset);
3307
3308 __ Mov(sp, x0);
3309
3310 END();
3311
3312 if (CAN_RUN()) {
3313 #ifndef VIXL_INCLUDE_SIMULATOR_AARCH64
3314 VIXL_UNIMPLEMENTED();
3315 #endif
3316 RUN();
3317
3318 const uint64_t k = kMTETagGranuleInBytes;
3319 USE(k);
3320 ASSERT_EQUAL_64(((init_tag + 1) % k) << tag_lsb, x18);
3321 ASSERT_EQUAL_64(((init_tag + 2) % k) << tag_lsb, x19);
3322 ASSERT_EQUAL_64(((init_tag + 3) % k) << tag_lsb, x20);
3323 ASSERT_EQUAL_64(((init_tag + 4) % k) << tag_lsb, x21);
3324 ASSERT_EQUAL_64(((init_tag + 5) % k) << tag_lsb, x22);
3325 ASSERT_EQUAL_64(((init_tag + 6) % k) << tag_lsb, x23);
3326 ASSERT_EQUAL_64(((init_tag + 7) % k) << tag_lsb, x24);
3327 ASSERT_EQUAL_64(((init_tag + 8) % k) << tag_lsb, x25);
3328 ASSERT_EQUAL_64(((init_tag + 9) % k) << tag_lsb, x26);
3329
3330 // We store 1, 2, 2, 3, 3, 4, ....9, 9, 10 to memory, so the total sum of
3331 // these values is 1 + (2 * (2 + 9) * 8 / 2) + 10 = 99.
3332 ASSERT_EQUAL_64((99UL << tag_lsb | 99UL), x15);
3333 }
3334
3335 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
3336 simulator.Munmap(data_ptr, data_size, PROT_MTE);
3337 #endif
3338 }
3339
TEST(ldr_str_offset)3340 TEST(ldr_str_offset) {
3341 SETUP();
3342
3343 uint64_t src[2] = {0xfedcba9876543210, 0x0123456789abcdef};
3344 uint64_t dst[5] = {0, 0, 0, 0, 0};
3345 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3346 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3347
3348 START();
3349 __ Mov(x17, src_base);
3350 __ Mov(x18, dst_base);
3351 __ Ldr(w0, MemOperand(x17));
3352 __ Str(w0, MemOperand(x18));
3353 __ Ldr(w1, MemOperand(x17, 4));
3354 __ Str(w1, MemOperand(x18, 12));
3355 __ Ldr(x2, MemOperand(x17, 8));
3356 __ Str(x2, MemOperand(x18, 16));
3357 __ Ldrb(w3, MemOperand(x17, 1));
3358 __ Strb(w3, MemOperand(x18, 25));
3359 __ Ldrh(w4, MemOperand(x17, 2));
3360 __ Strh(w4, MemOperand(x18, 33));
3361 END();
3362
3363 if (CAN_RUN()) {
3364 RUN();
3365
3366 ASSERT_EQUAL_64(0x76543210, x0);
3367 ASSERT_EQUAL_64(0x76543210, dst[0]);
3368 ASSERT_EQUAL_64(0xfedcba98, x1);
3369 ASSERT_EQUAL_64(0xfedcba9800000000, dst[1]);
3370 ASSERT_EQUAL_64(0x0123456789abcdef, x2);
3371 ASSERT_EQUAL_64(0x0123456789abcdef, dst[2]);
3372 ASSERT_EQUAL_64(0x32, x3);
3373 ASSERT_EQUAL_64(0x3200, dst[3]);
3374 ASSERT_EQUAL_64(0x7654, x4);
3375 ASSERT_EQUAL_64(0x765400, dst[4]);
3376 ASSERT_EQUAL_64(src_base, x17);
3377 ASSERT_EQUAL_64(dst_base, x18);
3378 }
3379 }
3380
3381
TEST(ldr_str_wide)3382 TEST(ldr_str_wide) {
3383 SETUP();
3384
3385 uint32_t src[8192];
3386 uint32_t dst[8192];
3387 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3388 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3389 memset(src, 0xaa, 8192 * sizeof(src[0]));
3390 memset(dst, 0xaa, 8192 * sizeof(dst[0]));
3391 src[0] = 0;
3392 src[6144] = 6144;
3393 src[8191] = 8191;
3394
3395 START();
3396 __ Mov(x22, src_base);
3397 __ Mov(x23, dst_base);
3398 __ Mov(x24, src_base);
3399 __ Mov(x25, dst_base);
3400 __ Mov(x26, src_base);
3401 __ Mov(x27, dst_base);
3402
3403 __ Ldr(w0, MemOperand(x22, 8191 * sizeof(src[0])));
3404 __ Str(w0, MemOperand(x23, 8191 * sizeof(dst[0])));
3405 __ Ldr(w1, MemOperand(x24, 4096 * sizeof(src[0]), PostIndex));
3406 __ Str(w1, MemOperand(x25, 4096 * sizeof(dst[0]), PostIndex));
3407 __ Ldr(w2, MemOperand(x26, 6144 * sizeof(src[0]), PreIndex));
3408 __ Str(w2, MemOperand(x27, 6144 * sizeof(dst[0]), PreIndex));
3409 END();
3410
3411 if (CAN_RUN()) {
3412 RUN();
3413
3414 ASSERT_EQUAL_32(8191, w0);
3415 ASSERT_EQUAL_32(8191, dst[8191]);
3416 ASSERT_EQUAL_64(src_base, x22);
3417 ASSERT_EQUAL_64(dst_base, x23);
3418 ASSERT_EQUAL_32(0, w1);
3419 ASSERT_EQUAL_32(0, dst[0]);
3420 ASSERT_EQUAL_64(src_base + 4096 * sizeof(src[0]), x24);
3421 ASSERT_EQUAL_64(dst_base + 4096 * sizeof(dst[0]), x25);
3422 ASSERT_EQUAL_32(6144, w2);
3423 ASSERT_EQUAL_32(6144, dst[6144]);
3424 ASSERT_EQUAL_64(src_base + 6144 * sizeof(src[0]), x26);
3425 ASSERT_EQUAL_64(dst_base + 6144 * sizeof(dst[0]), x27);
3426 }
3427 }
3428
3429
TEST(ldr_str_preindex)3430 TEST(ldr_str_preindex) {
3431 SETUP();
3432
3433 uint64_t src[2] = {0xfedcba9876543210, 0x0123456789abcdef};
3434 uint64_t dst[6] = {0, 0, 0, 0, 0, 0};
3435 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3436 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3437
3438 START();
3439 __ Mov(x17, src_base);
3440 __ Mov(x18, dst_base);
3441 __ Mov(x19, src_base);
3442 __ Mov(x20, dst_base);
3443 __ Mov(x21, src_base + 16);
3444 __ Mov(x22, dst_base + 40);
3445 __ Mov(x23, src_base);
3446 __ Mov(x24, dst_base);
3447 __ Mov(x25, src_base);
3448 __ Mov(x26, dst_base);
3449 __ Ldr(w0, MemOperand(x17, 4, PreIndex));
3450 __ Str(w0, MemOperand(x18, 12, PreIndex));
3451 __ Ldr(x1, MemOperand(x19, 8, PreIndex));
3452 __ Str(x1, MemOperand(x20, 16, PreIndex));
3453 __ Ldr(w2, MemOperand(x21, -4, PreIndex));
3454 __ Str(w2, MemOperand(x22, -4, PreIndex));
3455 __ Ldrb(w3, MemOperand(x23, 1, PreIndex));
3456 __ Strb(w3, MemOperand(x24, 25, PreIndex));
3457 __ Ldrh(w4, MemOperand(x25, 3, PreIndex));
3458 __ Strh(w4, MemOperand(x26, 41, PreIndex));
3459 END();
3460
3461 if (CAN_RUN()) {
3462 RUN();
3463
3464 ASSERT_EQUAL_64(0xfedcba98, x0);
3465 ASSERT_EQUAL_64(0xfedcba9800000000, dst[1]);
3466 ASSERT_EQUAL_64(0x0123456789abcdef, x1);
3467 ASSERT_EQUAL_64(0x0123456789abcdef, dst[2]);
3468 ASSERT_EQUAL_64(0x01234567, x2);
3469 ASSERT_EQUAL_64(0x0123456700000000, dst[4]);
3470 ASSERT_EQUAL_64(0x32, x3);
3471 ASSERT_EQUAL_64(0x3200, dst[3]);
3472 ASSERT_EQUAL_64(0x9876, x4);
3473 ASSERT_EQUAL_64(0x987600, dst[5]);
3474 ASSERT_EQUAL_64(src_base + 4, x17);
3475 ASSERT_EQUAL_64(dst_base + 12, x18);
3476 ASSERT_EQUAL_64(src_base + 8, x19);
3477 ASSERT_EQUAL_64(dst_base + 16, x20);
3478 ASSERT_EQUAL_64(src_base + 12, x21);
3479 ASSERT_EQUAL_64(dst_base + 36, x22);
3480 ASSERT_EQUAL_64(src_base + 1, x23);
3481 ASSERT_EQUAL_64(dst_base + 25, x24);
3482 ASSERT_EQUAL_64(src_base + 3, x25);
3483 ASSERT_EQUAL_64(dst_base + 41, x26);
3484 }
3485 }
3486
3487
TEST(ldr_str_postindex)3488 TEST(ldr_str_postindex) {
3489 SETUP();
3490
3491 uint64_t src[2] = {0xfedcba9876543210, 0x0123456789abcdef};
3492 uint64_t dst[6] = {0, 0, 0, 0, 0, 0};
3493 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3494 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3495
3496 START();
3497 __ Mov(x17, src_base + 4);
3498 __ Mov(x18, dst_base + 12);
3499 __ Mov(x19, src_base + 8);
3500 __ Mov(x20, dst_base + 16);
3501 __ Mov(x21, src_base + 8);
3502 __ Mov(x22, dst_base + 32);
3503 __ Mov(x23, src_base + 1);
3504 __ Mov(x24, dst_base + 25);
3505 __ Mov(x25, src_base + 3);
3506 __ Mov(x26, dst_base + 41);
3507 __ Ldr(w0, MemOperand(x17, 4, PostIndex));
3508 __ Str(w0, MemOperand(x18, 12, PostIndex));
3509 __ Ldr(x1, MemOperand(x19, 8, PostIndex));
3510 __ Str(x1, MemOperand(x20, 16, PostIndex));
3511 __ Ldr(x2, MemOperand(x21, -8, PostIndex));
3512 __ Str(x2, MemOperand(x22, -32, PostIndex));
3513 __ Ldrb(w3, MemOperand(x23, 1, PostIndex));
3514 __ Strb(w3, MemOperand(x24, 5, PostIndex));
3515 __ Ldrh(w4, MemOperand(x25, -3, PostIndex));
3516 __ Strh(w4, MemOperand(x26, -41, PostIndex));
3517 END();
3518
3519 if (CAN_RUN()) {
3520 RUN();
3521
3522 ASSERT_EQUAL_64(0xfedcba98, x0);
3523 ASSERT_EQUAL_64(0xfedcba9800000000, dst[1]);
3524 ASSERT_EQUAL_64(0x0123456789abcdef, x1);
3525 ASSERT_EQUAL_64(0x0123456789abcdef, dst[2]);
3526 ASSERT_EQUAL_64(0x0123456789abcdef, x2);
3527 ASSERT_EQUAL_64(0x0123456789abcdef, dst[4]);
3528 ASSERT_EQUAL_64(0x32, x3);
3529 ASSERT_EQUAL_64(0x3200, dst[3]);
3530 ASSERT_EQUAL_64(0x9876, x4);
3531 ASSERT_EQUAL_64(0x987600, dst[5]);
3532 ASSERT_EQUAL_64(src_base + 8, x17);
3533 ASSERT_EQUAL_64(dst_base + 24, x18);
3534 ASSERT_EQUAL_64(src_base + 16, x19);
3535 ASSERT_EQUAL_64(dst_base + 32, x20);
3536 ASSERT_EQUAL_64(src_base, x21);
3537 ASSERT_EQUAL_64(dst_base, x22);
3538 ASSERT_EQUAL_64(src_base + 2, x23);
3539 ASSERT_EQUAL_64(dst_base + 30, x24);
3540 ASSERT_EQUAL_64(src_base, x25);
3541 ASSERT_EQUAL_64(dst_base, x26);
3542 }
3543 }
3544
3545
TEST(ldr_str_largeindex)3546 TEST(ldr_str_largeindex) {
3547 SETUP();
3548
3549 // This value won't fit in the immediate offset field of ldr/str instructions.
3550 int largeoffset = 0xabcdef;
3551
3552 int64_t data[3] = {0x1122334455667788, 0, 0};
3553 uint64_t base_addr = reinterpret_cast<uintptr_t>(data);
3554 uint64_t drifted_addr = base_addr - largeoffset;
3555
3556 // This test checks that we we can use large immediate offsets when
3557 // using PreIndex or PostIndex addressing mode of the MacroAssembler
3558 // Ldr/Str instructions.
3559
3560 START();
3561 __ Mov(x19, drifted_addr);
3562 __ Ldr(x0, MemOperand(x19, largeoffset, PreIndex));
3563
3564 __ Mov(x20, base_addr);
3565 __ Ldr(x1, MemOperand(x20, largeoffset, PostIndex));
3566
3567 __ Mov(x21, drifted_addr);
3568 __ Str(x0, MemOperand(x21, largeoffset + 8, PreIndex));
3569
3570 __ Mov(x22, base_addr + 16);
3571 __ Str(x0, MemOperand(x22, largeoffset, PostIndex));
3572 END();
3573
3574 if (CAN_RUN()) {
3575 RUN();
3576
3577 ASSERT_EQUAL_64(0x1122334455667788, data[0]);
3578 ASSERT_EQUAL_64(0x1122334455667788, data[1]);
3579 ASSERT_EQUAL_64(0x1122334455667788, data[2]);
3580 ASSERT_EQUAL_64(0x1122334455667788, x0);
3581 ASSERT_EQUAL_64(0x1122334455667788, x1);
3582
3583 ASSERT_EQUAL_64(base_addr, x19);
3584 ASSERT_EQUAL_64(base_addr + largeoffset, x20);
3585 ASSERT_EQUAL_64(base_addr + 8, x21);
3586 ASSERT_EQUAL_64(base_addr + 16 + largeoffset, x22);
3587 }
3588 }
3589
3590
TEST(load_signed)3591 TEST(load_signed) {
3592 SETUP();
3593
3594 uint32_t src[2] = {0x80008080, 0x7fff7f7f};
3595 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3596
3597 START();
3598 __ Mov(x24, src_base);
3599 __ Ldrsb(w0, MemOperand(x24));
3600 __ Ldrsb(w1, MemOperand(x24, 4));
3601 __ Ldrsh(w2, MemOperand(x24));
3602 __ Ldrsh(w3, MemOperand(x24, 4));
3603 __ Ldrsb(x4, MemOperand(x24));
3604 __ Ldrsb(x5, MemOperand(x24, 4));
3605 __ Ldrsh(x6, MemOperand(x24));
3606 __ Ldrsh(x7, MemOperand(x24, 4));
3607 __ Ldrsw(x8, MemOperand(x24));
3608 __ Ldrsw(x9, MemOperand(x24, 4));
3609 END();
3610
3611 if (CAN_RUN()) {
3612 RUN();
3613
3614 ASSERT_EQUAL_64(0xffffff80, x0);
3615 ASSERT_EQUAL_64(0x0000007f, x1);
3616 ASSERT_EQUAL_64(0xffff8080, x2);
3617 ASSERT_EQUAL_64(0x00007f7f, x3);
3618 ASSERT_EQUAL_64(0xffffffffffffff80, x4);
3619 ASSERT_EQUAL_64(0x000000000000007f, x5);
3620 ASSERT_EQUAL_64(0xffffffffffff8080, x6);
3621 ASSERT_EQUAL_64(0x0000000000007f7f, x7);
3622 ASSERT_EQUAL_64(0xffffffff80008080, x8);
3623 ASSERT_EQUAL_64(0x000000007fff7f7f, x9);
3624 }
3625 }
3626
3627
TEST(load_store_regoffset)3628 TEST(load_store_regoffset) {
3629 SETUP();
3630
3631 uint32_t src[3] = {1, 2, 3};
3632 uint32_t dst[4] = {0, 0, 0, 0};
3633 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3634 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3635
3636 START();
3637 __ Mov(x16, src_base);
3638 __ Mov(x17, dst_base);
3639 __ Mov(x18, src_base + 3 * sizeof(src[0]));
3640 __ Mov(x19, dst_base + 3 * sizeof(dst[0]));
3641 __ Mov(x20, dst_base + 4 * sizeof(dst[0]));
3642 __ Mov(x24, 0);
3643 __ Mov(x25, 4);
3644 __ Mov(x26, -4);
3645 __ Mov(x27, 0xfffffffc); // 32-bit -4.
3646 __ Mov(x28, 0xfffffffe); // 32-bit -2.
3647 __ Mov(x29, 0xffffffff); // 32-bit -1.
3648
3649 __ Ldr(w0, MemOperand(x16, x24));
3650 __ Ldr(x1, MemOperand(x16, x25));
3651 __ Ldr(w2, MemOperand(x18, x26));
3652 __ Ldr(w3, MemOperand(x18, x27, SXTW));
3653 __ Ldr(w4, MemOperand(x18, x28, SXTW, 2));
3654 __ Str(w0, MemOperand(x17, x24));
3655 __ Str(x1, MemOperand(x17, x25));
3656 __ Str(w2, MemOperand(x20, x29, SXTW, 2));
3657 END();
3658
3659 if (CAN_RUN()) {
3660 RUN();
3661
3662 ASSERT_EQUAL_64(1, x0);
3663 ASSERT_EQUAL_64(0x0000000300000002, x1);
3664 ASSERT_EQUAL_64(3, x2);
3665 ASSERT_EQUAL_64(3, x3);
3666 ASSERT_EQUAL_64(2, x4);
3667 ASSERT_EQUAL_32(1, dst[0]);
3668 ASSERT_EQUAL_32(2, dst[1]);
3669 ASSERT_EQUAL_32(3, dst[2]);
3670 ASSERT_EQUAL_32(3, dst[3]);
3671 }
3672 }
3673
3674
TEST(load_pauth)3675 TEST(load_pauth) {
3676 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
3677
3678 uint64_t src[4] = {1, 2, 3, 4};
3679 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3680
3681 START();
3682 __ Mov(x16, src_base);
3683 __ Mov(x17, src_base);
3684 __ Mov(x18, src_base + 4 * sizeof(src[0]));
3685 __ Mov(x19, src_base + 4 * sizeof(src[0]));
3686
3687 // Add PAC codes to addresses
3688 __ Pacdza(x16);
3689 __ Pacdzb(x17);
3690 __ Pacdza(x18);
3691 __ Pacdzb(x19);
3692
3693 __ Ldraa(x0, MemOperand(x16));
3694 __ Ldraa(x1, MemOperand(x16, sizeof(src[0])));
3695 __ Ldraa(x2, MemOperand(x16, 2 * sizeof(src[0]), PreIndex));
3696 __ Ldraa(x3, MemOperand(x18, -sizeof(src[0])));
3697 __ Ldrab(x4, MemOperand(x17));
3698 __ Ldrab(x5, MemOperand(x17, sizeof(src[0])));
3699 __ Ldrab(x6, MemOperand(x17, 2 * sizeof(src[0]), PreIndex));
3700 __ Ldrab(x7, MemOperand(x19, -sizeof(src[0])));
3701 END();
3702
3703 if (CAN_RUN()) {
3704 RUN();
3705
3706 ASSERT_EQUAL_64(1, x0);
3707 ASSERT_EQUAL_64(2, x1);
3708 ASSERT_EQUAL_64(3, x2);
3709 ASSERT_EQUAL_64(4, x3);
3710 ASSERT_EQUAL_64(1, x4);
3711 ASSERT_EQUAL_64(2, x5);
3712 ASSERT_EQUAL_64(3, x6);
3713 ASSERT_EQUAL_64(4, x7);
3714 ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x16);
3715 ASSERT_EQUAL_64(src_base + 2 * sizeof(src[0]), x17);
3716 }
3717 }
3718
3719
3720 #ifdef VIXL_NEGATIVE_TESTING
TEST(load_pauth_negative_test)3721 TEST(load_pauth_negative_test) {
3722 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
3723
3724 uint64_t src[4] = {1, 2, 3, 4};
3725 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3726
3727 START();
3728 __ Mov(x16, src_base);
3729
3730 // There is a small but not negligible chance (1 in 127 runs) that the PAC
3731 // codes for keys A and B will collide and LDRAB won't abort. To mitigate
3732 // this, we simply repeat the test a few more times.
3733 for (unsigned i = 0; i < 32; i++) {
3734 __ Add(x17, x16, i);
3735 __ Pacdza(x17);
3736 __ Ldrab(x0, MemOperand(x17));
3737 }
3738 END();
3739
3740 if (CAN_RUN()) {
3741 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
3742 MUST_FAIL_WITH_MESSAGE(RUN(), "Failed to authenticate pointer.");
3743 #else
3744 printf("SKIPPED: negative PAuth tests are unimplemented on hardware.");
3745 #endif
3746 }
3747 }
3748 #endif // VIXL_NEGATIVE_TESTING
3749
3750
TEST(ldp_stp_offset)3751 TEST(ldp_stp_offset) {
3752 SETUP();
3753
3754 uint64_t src[3] = {0x0011223344556677,
3755 0x8899aabbccddeeff,
3756 0xffeeddccbbaa9988};
3757 uint64_t dst[7] = {0, 0, 0, 0, 0, 0, 0};
3758 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3759 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3760
3761 START();
3762 __ Mov(x16, src_base);
3763 __ Mov(x17, dst_base);
3764 __ Mov(x18, src_base + 24);
3765 __ Mov(x19, dst_base + 56);
3766 __ Ldp(w0, w1, MemOperand(x16));
3767 __ Ldp(w2, w3, MemOperand(x16, 4));
3768 __ Ldp(x4, x5, MemOperand(x16, 8));
3769 __ Ldp(w6, w7, MemOperand(x18, -12));
3770 __ Ldp(x8, x9, MemOperand(x18, -16));
3771 __ Stp(w0, w1, MemOperand(x17));
3772 __ Stp(w2, w3, MemOperand(x17, 8));
3773 __ Stp(x4, x5, MemOperand(x17, 16));
3774 __ Stp(w6, w7, MemOperand(x19, -24));
3775 __ Stp(x8, x9, MemOperand(x19, -16));
3776 END();
3777
3778 if (CAN_RUN()) {
3779 RUN();
3780
3781 ASSERT_EQUAL_64(0x44556677, x0);
3782 ASSERT_EQUAL_64(0x00112233, x1);
3783 ASSERT_EQUAL_64(0x0011223344556677, dst[0]);
3784 ASSERT_EQUAL_64(0x00112233, x2);
3785 ASSERT_EQUAL_64(0xccddeeff, x3);
3786 ASSERT_EQUAL_64(0xccddeeff00112233, dst[1]);
3787 ASSERT_EQUAL_64(0x8899aabbccddeeff, x4);
3788 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[2]);
3789 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x5);
3790 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[3]);
3791 ASSERT_EQUAL_64(0x8899aabb, x6);
3792 ASSERT_EQUAL_64(0xbbaa9988, x7);
3793 ASSERT_EQUAL_64(0xbbaa99888899aabb, dst[4]);
3794 ASSERT_EQUAL_64(0x8899aabbccddeeff, x8);
3795 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[5]);
3796 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x9);
3797 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[6]);
3798 ASSERT_EQUAL_64(src_base, x16);
3799 ASSERT_EQUAL_64(dst_base, x17);
3800 ASSERT_EQUAL_64(src_base + 24, x18);
3801 ASSERT_EQUAL_64(dst_base + 56, x19);
3802 }
3803 }
3804
3805
TEST(ldp_stp_offset_wide)3806 TEST(ldp_stp_offset_wide) {
3807 SETUP();
3808
3809 uint64_t src[3] = {0x0011223344556677,
3810 0x8899aabbccddeeff,
3811 0xffeeddccbbaa9988};
3812 uint64_t dst[7] = {0, 0, 0, 0, 0, 0, 0};
3813 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3814 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3815 // Move base too far from the array to force multiple instructions
3816 // to be emitted.
3817 const int64_t base_offset = 1024;
3818
3819 START();
3820 __ Mov(x20, src_base - base_offset);
3821 __ Mov(x21, dst_base - base_offset);
3822 __ Mov(x18, src_base + base_offset + 24);
3823 __ Mov(x19, dst_base + base_offset + 56);
3824 __ Ldp(w0, w1, MemOperand(x20, base_offset));
3825 __ Ldp(w2, w3, MemOperand(x20, base_offset + 4));
3826 __ Ldp(x4, x5, MemOperand(x20, base_offset + 8));
3827 __ Ldp(w6, w7, MemOperand(x18, -12 - base_offset));
3828 __ Ldp(x8, x9, MemOperand(x18, -16 - base_offset));
3829 __ Stp(w0, w1, MemOperand(x21, base_offset));
3830 __ Stp(w2, w3, MemOperand(x21, base_offset + 8));
3831 __ Stp(x4, x5, MemOperand(x21, base_offset + 16));
3832 __ Stp(w6, w7, MemOperand(x19, -24 - base_offset));
3833 __ Stp(x8, x9, MemOperand(x19, -16 - base_offset));
3834 END();
3835
3836 if (CAN_RUN()) {
3837 RUN();
3838
3839 ASSERT_EQUAL_64(0x44556677, x0);
3840 ASSERT_EQUAL_64(0x00112233, x1);
3841 ASSERT_EQUAL_64(0x0011223344556677, dst[0]);
3842 ASSERT_EQUAL_64(0x00112233, x2);
3843 ASSERT_EQUAL_64(0xccddeeff, x3);
3844 ASSERT_EQUAL_64(0xccddeeff00112233, dst[1]);
3845 ASSERT_EQUAL_64(0x8899aabbccddeeff, x4);
3846 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[2]);
3847 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x5);
3848 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[3]);
3849 ASSERT_EQUAL_64(0x8899aabb, x6);
3850 ASSERT_EQUAL_64(0xbbaa9988, x7);
3851 ASSERT_EQUAL_64(0xbbaa99888899aabb, dst[4]);
3852 ASSERT_EQUAL_64(0x8899aabbccddeeff, x8);
3853 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[5]);
3854 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x9);
3855 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[6]);
3856 ASSERT_EQUAL_64(src_base - base_offset, x20);
3857 ASSERT_EQUAL_64(dst_base - base_offset, x21);
3858 ASSERT_EQUAL_64(src_base + base_offset + 24, x18);
3859 ASSERT_EQUAL_64(dst_base + base_offset + 56, x19);
3860 }
3861 }
3862
3863
TEST(ldnp_stnp_offset)3864 TEST(ldnp_stnp_offset) {
3865 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
3866
3867 uint64_t src[4] = {0x0011223344556677,
3868 0x8899aabbccddeeff,
3869 0xffeeddccbbaa9988,
3870 0x7766554433221100};
3871 uint64_t dst[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
3872 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3873 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3874
3875 START();
3876 __ Mov(x16, src_base);
3877 __ Mov(x17, dst_base);
3878 __ Mov(x18, src_base + 24);
3879 __ Mov(x19, dst_base + 64);
3880 __ Mov(x20, src_base + 32);
3881
3882 // Ensure address set up has happened before executing non-temporal ops.
3883 __ Dmb(InnerShareable, BarrierAll);
3884
3885 __ Ldnp(w0, w1, MemOperand(x16));
3886 __ Ldnp(w2, w3, MemOperand(x16, 4));
3887 __ Ldnp(x4, x5, MemOperand(x16, 8));
3888 __ Ldnp(w6, w7, MemOperand(x18, -12));
3889 __ Ldnp(x8, x9, MemOperand(x18, -16));
3890 __ Ldnp(q16, q17, MemOperand(x16));
3891 __ Ldnp(q19, q18, MemOperand(x20, -32));
3892 __ Stnp(w0, w1, MemOperand(x17));
3893 __ Stnp(w2, w3, MemOperand(x17, 8));
3894 __ Stnp(x4, x5, MemOperand(x17, 16));
3895 __ Stnp(w6, w7, MemOperand(x19, -32));
3896 __ Stnp(x8, x9, MemOperand(x19, -24));
3897 __ Stnp(q17, q16, MemOperand(x19));
3898 __ Stnp(q18, q19, MemOperand(x19, 32));
3899 END();
3900
3901 if (CAN_RUN()) {
3902 RUN();
3903
3904 ASSERT_EQUAL_64(0x44556677, x0);
3905 ASSERT_EQUAL_64(0x00112233, x1);
3906 ASSERT_EQUAL_64(0x0011223344556677, dst[0]);
3907 ASSERT_EQUAL_64(0x00112233, x2);
3908 ASSERT_EQUAL_64(0xccddeeff, x3);
3909 ASSERT_EQUAL_64(0xccddeeff00112233, dst[1]);
3910 ASSERT_EQUAL_64(0x8899aabbccddeeff, x4);
3911 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[2]);
3912 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x5);
3913 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[3]);
3914 ASSERT_EQUAL_64(0x8899aabb, x6);
3915 ASSERT_EQUAL_64(0xbbaa9988, x7);
3916 ASSERT_EQUAL_64(0xbbaa99888899aabb, dst[4]);
3917 ASSERT_EQUAL_64(0x8899aabbccddeeff, x8);
3918 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[5]);
3919 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x9);
3920 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[6]);
3921 ASSERT_EQUAL_128(0x8899aabbccddeeff, 0x0011223344556677, q16);
3922 ASSERT_EQUAL_128(0x7766554433221100, 0xffeeddccbbaa9988, q17);
3923 ASSERT_EQUAL_128(0x7766554433221100, 0xffeeddccbbaa9988, q18);
3924 ASSERT_EQUAL_128(0x8899aabbccddeeff, 0x0011223344556677, q19);
3925 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[8]);
3926 ASSERT_EQUAL_64(0x7766554433221100, dst[9]);
3927 ASSERT_EQUAL_64(0x0011223344556677, dst[10]);
3928 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[11]);
3929 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[12]);
3930 ASSERT_EQUAL_64(0x7766554433221100, dst[13]);
3931 ASSERT_EQUAL_64(0x0011223344556677, dst[14]);
3932 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[15]);
3933 ASSERT_EQUAL_64(src_base, x16);
3934 ASSERT_EQUAL_64(dst_base, x17);
3935 ASSERT_EQUAL_64(src_base + 24, x18);
3936 ASSERT_EQUAL_64(dst_base + 64, x19);
3937 ASSERT_EQUAL_64(src_base + 32, x20);
3938 }
3939 }
3940
TEST(ldp_stp_preindex)3941 TEST(ldp_stp_preindex) {
3942 SETUP();
3943
3944 uint64_t src[3] = {0x0011223344556677,
3945 0x8899aabbccddeeff,
3946 0xffeeddccbbaa9988};
3947 uint64_t dst[5] = {0, 0, 0, 0, 0};
3948 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
3949 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
3950
3951 START();
3952 __ Mov(x16, src_base);
3953 __ Mov(x17, dst_base);
3954 __ Mov(x18, dst_base + 16);
3955 __ Ldp(w0, w1, MemOperand(x16, 4, PreIndex));
3956 __ Mov(x19, x16);
3957 __ Ldp(w2, w3, MemOperand(x16, -4, PreIndex));
3958 __ Stp(w2, w3, MemOperand(x17, 4, PreIndex));
3959 __ Mov(x20, x17);
3960 __ Stp(w0, w1, MemOperand(x17, -4, PreIndex));
3961 __ Ldp(x4, x5, MemOperand(x16, 8, PreIndex));
3962 __ Mov(x21, x16);
3963 __ Ldp(x6, x7, MemOperand(x16, -8, PreIndex));
3964 __ Stp(x7, x6, MemOperand(x18, 8, PreIndex));
3965 __ Mov(x22, x18);
3966 __ Stp(x5, x4, MemOperand(x18, -8, PreIndex));
3967 END();
3968
3969 if (CAN_RUN()) {
3970 RUN();
3971
3972 ASSERT_EQUAL_64(0x00112233, x0);
3973 ASSERT_EQUAL_64(0xccddeeff, x1);
3974 ASSERT_EQUAL_64(0x44556677, x2);
3975 ASSERT_EQUAL_64(0x00112233, x3);
3976 ASSERT_EQUAL_64(0xccddeeff00112233, dst[0]);
3977 ASSERT_EQUAL_64(0x0000000000112233, dst[1]);
3978 ASSERT_EQUAL_64(0x8899aabbccddeeff, x4);
3979 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x5);
3980 ASSERT_EQUAL_64(0x0011223344556677, x6);
3981 ASSERT_EQUAL_64(0x8899aabbccddeeff, x7);
3982 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[2]);
3983 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[3]);
3984 ASSERT_EQUAL_64(0x0011223344556677, dst[4]);
3985 ASSERT_EQUAL_64(src_base, x16);
3986 ASSERT_EQUAL_64(dst_base, x17);
3987 ASSERT_EQUAL_64(dst_base + 16, x18);
3988 ASSERT_EQUAL_64(src_base + 4, x19);
3989 ASSERT_EQUAL_64(dst_base + 4, x20);
3990 ASSERT_EQUAL_64(src_base + 8, x21);
3991 ASSERT_EQUAL_64(dst_base + 24, x22);
3992 }
3993 }
3994
3995
TEST(ldp_stp_preindex_wide)3996 TEST(ldp_stp_preindex_wide) {
3997 SETUP();
3998
3999 uint64_t src[3] = {0x0011223344556677,
4000 0x8899aabbccddeeff,
4001 0xffeeddccbbaa9988};
4002 uint64_t dst[5] = {0, 0, 0, 0, 0};
4003 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
4004 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
4005 // Move base too far from the array to force multiple instructions
4006 // to be emitted.
4007 const int64_t base_offset = 1024;
4008
4009 START();
4010 __ Mov(x24, src_base - base_offset);
4011 __ Mov(x25, dst_base + base_offset);
4012 __ Mov(x18, dst_base + base_offset + 16);
4013 __ Ldp(w0, w1, MemOperand(x24, base_offset + 4, PreIndex));
4014 __ Mov(x19, x24);
4015 __ Mov(x24, src_base - base_offset + 4);
4016 __ Ldp(w2, w3, MemOperand(x24, base_offset - 4, PreIndex));
4017 __ Stp(w2, w3, MemOperand(x25, 4 - base_offset, PreIndex));
4018 __ Mov(x20, x25);
4019 __ Mov(x25, dst_base + base_offset + 4);
4020 __ Mov(x24, src_base - base_offset);
4021 __ Stp(w0, w1, MemOperand(x25, -4 - base_offset, PreIndex));
4022 __ Ldp(x4, x5, MemOperand(x24, base_offset + 8, PreIndex));
4023 __ Mov(x21, x24);
4024 __ Mov(x24, src_base - base_offset + 8);
4025 __ Ldp(x6, x7, MemOperand(x24, base_offset - 8, PreIndex));
4026 __ Stp(x7, x6, MemOperand(x18, 8 - base_offset, PreIndex));
4027 __ Mov(x22, x18);
4028 __ Mov(x18, dst_base + base_offset + 16 + 8);
4029 __ Stp(x5, x4, MemOperand(x18, -8 - base_offset, PreIndex));
4030 END();
4031
4032 if (CAN_RUN()) {
4033 RUN();
4034
4035 ASSERT_EQUAL_64(0x00112233, x0);
4036 ASSERT_EQUAL_64(0xccddeeff, x1);
4037 ASSERT_EQUAL_64(0x44556677, x2);
4038 ASSERT_EQUAL_64(0x00112233, x3);
4039 ASSERT_EQUAL_64(0xccddeeff00112233, dst[0]);
4040 ASSERT_EQUAL_64(0x0000000000112233, dst[1]);
4041 ASSERT_EQUAL_64(0x8899aabbccddeeff, x4);
4042 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x5);
4043 ASSERT_EQUAL_64(0x0011223344556677, x6);
4044 ASSERT_EQUAL_64(0x8899aabbccddeeff, x7);
4045 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[2]);
4046 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[3]);
4047 ASSERT_EQUAL_64(0x0011223344556677, dst[4]);
4048 ASSERT_EQUAL_64(src_base, x24);
4049 ASSERT_EQUAL_64(dst_base, x25);
4050 ASSERT_EQUAL_64(dst_base + 16, x18);
4051 ASSERT_EQUAL_64(src_base + 4, x19);
4052 ASSERT_EQUAL_64(dst_base + 4, x20);
4053 ASSERT_EQUAL_64(src_base + 8, x21);
4054 ASSERT_EQUAL_64(dst_base + 24, x22);
4055 }
4056 }
4057
4058
TEST(ldp_stp_postindex)4059 TEST(ldp_stp_postindex) {
4060 SETUP();
4061
4062 uint64_t src[4] = {0x0011223344556677,
4063 0x8899aabbccddeeff,
4064 0xffeeddccbbaa9988,
4065 0x7766554433221100};
4066 uint64_t dst[5] = {0, 0, 0, 0, 0};
4067 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
4068 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
4069
4070 START();
4071 __ Mov(x16, src_base);
4072 __ Mov(x17, dst_base);
4073 __ Mov(x18, dst_base + 16);
4074 __ Ldp(w0, w1, MemOperand(x16, 4, PostIndex));
4075 __ Mov(x19, x16);
4076 __ Ldp(w2, w3, MemOperand(x16, -4, PostIndex));
4077 __ Stp(w2, w3, MemOperand(x17, 4, PostIndex));
4078 __ Mov(x20, x17);
4079 __ Stp(w0, w1, MemOperand(x17, -4, PostIndex));
4080 __ Ldp(x4, x5, MemOperand(x16, 8, PostIndex));
4081 __ Mov(x21, x16);
4082 __ Ldp(x6, x7, MemOperand(x16, -8, PostIndex));
4083 __ Stp(x7, x6, MemOperand(x18, 8, PostIndex));
4084 __ Mov(x22, x18);
4085 __ Stp(x5, x4, MemOperand(x18, -8, PostIndex));
4086 END();
4087
4088 if (CAN_RUN()) {
4089 RUN();
4090
4091 ASSERT_EQUAL_64(0x44556677, x0);
4092 ASSERT_EQUAL_64(0x00112233, x1);
4093 ASSERT_EQUAL_64(0x00112233, x2);
4094 ASSERT_EQUAL_64(0xccddeeff, x3);
4095 ASSERT_EQUAL_64(0x4455667700112233, dst[0]);
4096 ASSERT_EQUAL_64(0x0000000000112233, dst[1]);
4097 ASSERT_EQUAL_64(0x0011223344556677, x4);
4098 ASSERT_EQUAL_64(0x8899aabbccddeeff, x5);
4099 ASSERT_EQUAL_64(0x8899aabbccddeeff, x6);
4100 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x7);
4101 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[2]);
4102 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[3]);
4103 ASSERT_EQUAL_64(0x0011223344556677, dst[4]);
4104 ASSERT_EQUAL_64(src_base, x16);
4105 ASSERT_EQUAL_64(dst_base, x17);
4106 ASSERT_EQUAL_64(dst_base + 16, x18);
4107 ASSERT_EQUAL_64(src_base + 4, x19);
4108 ASSERT_EQUAL_64(dst_base + 4, x20);
4109 ASSERT_EQUAL_64(src_base + 8, x21);
4110 ASSERT_EQUAL_64(dst_base + 24, x22);
4111 }
4112 }
4113
4114
TEST(ldp_stp_postindex_wide)4115 TEST(ldp_stp_postindex_wide) {
4116 SETUP();
4117
4118 uint64_t src[4] = {0x0011223344556677,
4119 0x8899aabbccddeeff,
4120 0xffeeddccbbaa9988,
4121 0x7766554433221100};
4122 uint64_t dst[5] = {0, 0, 0, 0, 0};
4123 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
4124 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
4125 // Move base too far from the array to force multiple instructions
4126 // to be emitted.
4127 const int64_t base_offset = 1024;
4128
4129 START();
4130 __ Mov(x24, src_base);
4131 __ Mov(x25, dst_base);
4132 __ Mov(x18, dst_base + 16);
4133 __ Ldp(w0, w1, MemOperand(x24, base_offset + 4, PostIndex));
4134 __ Mov(x19, x24);
4135 __ Sub(x24, x24, base_offset);
4136 __ Ldp(w2, w3, MemOperand(x24, base_offset - 4, PostIndex));
4137 __ Stp(w2, w3, MemOperand(x25, 4 - base_offset, PostIndex));
4138 __ Mov(x20, x25);
4139 __ Sub(x24, x24, base_offset);
4140 __ Add(x25, x25, base_offset);
4141 __ Stp(w0, w1, MemOperand(x25, -4 - base_offset, PostIndex));
4142 __ Ldp(x4, x5, MemOperand(x24, base_offset + 8, PostIndex));
4143 __ Mov(x21, x24);
4144 __ Sub(x24, x24, base_offset);
4145 __ Ldp(x6, x7, MemOperand(x24, base_offset - 8, PostIndex));
4146 __ Stp(x7, x6, MemOperand(x18, 8 - base_offset, PostIndex));
4147 __ Mov(x22, x18);
4148 __ Add(x18, x18, base_offset);
4149 __ Stp(x5, x4, MemOperand(x18, -8 - base_offset, PostIndex));
4150 END();
4151
4152 if (CAN_RUN()) {
4153 RUN();
4154
4155 ASSERT_EQUAL_64(0x44556677, x0);
4156 ASSERT_EQUAL_64(0x00112233, x1);
4157 ASSERT_EQUAL_64(0x00112233, x2);
4158 ASSERT_EQUAL_64(0xccddeeff, x3);
4159 ASSERT_EQUAL_64(0x4455667700112233, dst[0]);
4160 ASSERT_EQUAL_64(0x0000000000112233, dst[1]);
4161 ASSERT_EQUAL_64(0x0011223344556677, x4);
4162 ASSERT_EQUAL_64(0x8899aabbccddeeff, x5);
4163 ASSERT_EQUAL_64(0x8899aabbccddeeff, x6);
4164 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x7);
4165 ASSERT_EQUAL_64(0xffeeddccbbaa9988, dst[2]);
4166 ASSERT_EQUAL_64(0x8899aabbccddeeff, dst[3]);
4167 ASSERT_EQUAL_64(0x0011223344556677, dst[4]);
4168 ASSERT_EQUAL_64(src_base + base_offset, x24);
4169 ASSERT_EQUAL_64(dst_base - base_offset, x25);
4170 ASSERT_EQUAL_64(dst_base - base_offset + 16, x18);
4171 ASSERT_EQUAL_64(src_base + base_offset + 4, x19);
4172 ASSERT_EQUAL_64(dst_base - base_offset + 4, x20);
4173 ASSERT_EQUAL_64(src_base + base_offset + 8, x21);
4174 ASSERT_EQUAL_64(dst_base - base_offset + 24, x22);
4175 }
4176 }
4177
4178
TEST(ldp_sign_extend)4179 TEST(ldp_sign_extend) {
4180 SETUP();
4181
4182 uint32_t src[2] = {0x80000000, 0x7fffffff};
4183 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
4184
4185 START();
4186 __ Mov(x24, src_base);
4187 __ Ldpsw(x0, x1, MemOperand(x24));
4188 END();
4189
4190 if (CAN_RUN()) {
4191 RUN();
4192
4193 ASSERT_EQUAL_64(0xffffffff80000000, x0);
4194 ASSERT_EQUAL_64(0x000000007fffffff, x1);
4195 }
4196 }
4197
4198
TEST(ldur_stur)4199 TEST(ldur_stur) {
4200 SETUP();
4201
4202 int64_t src[2] = {0x0123456789abcdef, 0x0123456789abcdef};
4203 int64_t dst[5] = {0, 0, 0, 0, 0};
4204 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
4205 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
4206
4207 START();
4208 __ Mov(x17, src_base);
4209 __ Mov(x18, dst_base);
4210 __ Mov(x19, src_base + 16);
4211 __ Mov(x20, dst_base + 32);
4212 __ Mov(x21, dst_base + 40);
4213 __ Ldr(w0, MemOperand(x17, 1));
4214 __ Str(w0, MemOperand(x18, 2));
4215 __ Ldr(x1, MemOperand(x17, 3));
4216 __ Str(x1, MemOperand(x18, 9));
4217 __ Ldr(w2, MemOperand(x19, -9));
4218 __ Str(w2, MemOperand(x20, -5));
4219 __ Ldrb(w3, MemOperand(x19, -1));
4220 __ Strb(w3, MemOperand(x21, -1));
4221 END();
4222
4223 if (CAN_RUN()) {
4224 RUN();
4225
4226 ASSERT_EQUAL_64(0x6789abcd, x0);
4227 ASSERT_EQUAL_64(0x00006789abcd0000, dst[0]);
4228 ASSERT_EQUAL_64(0xabcdef0123456789, x1);
4229 ASSERT_EQUAL_64(0xcdef012345678900, dst[1]);
4230 ASSERT_EQUAL_64(0x000000ab, dst[2]);
4231 ASSERT_EQUAL_64(0xabcdef01, x2);
4232 ASSERT_EQUAL_64(0x00abcdef01000000, dst[3]);
4233 ASSERT_EQUAL_64(0x00000001, x3);
4234 ASSERT_EQUAL_64(0x0100000000000000, dst[4]);
4235 ASSERT_EQUAL_64(src_base, x17);
4236 ASSERT_EQUAL_64(dst_base, x18);
4237 ASSERT_EQUAL_64(src_base + 16, x19);
4238 ASSERT_EQUAL_64(dst_base + 32, x20);
4239 }
4240 }
4241
4242
TEST(ldur_stur_neon)4243 TEST(ldur_stur_neon) {
4244 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
4245
4246 int64_t src[3] = {0x0123456789abcdef, 0x0123456789abcdef, 0x0123456789abcdef};
4247 int64_t dst[5] = {0, 0, 0, 0, 0};
4248 uintptr_t src_base = reinterpret_cast<uintptr_t>(src);
4249 uintptr_t dst_base = reinterpret_cast<uintptr_t>(dst);
4250
4251 START();
4252 __ Mov(x17, src_base);
4253 __ Mov(x18, dst_base);
4254 __ Ldr(b0, MemOperand(x17));
4255 __ Str(b0, MemOperand(x18));
4256 __ Ldr(h1, MemOperand(x17, 1));
4257 __ Str(h1, MemOperand(x18, 1));
4258 __ Ldr(s2, MemOperand(x17, 2));
4259 __ Str(s2, MemOperand(x18, 3));
4260 __ Ldr(d3, MemOperand(x17, 3));
4261 __ Str(d3, MemOperand(x18, 7));
4262 __ Ldr(q4, MemOperand(x17, 4));
4263 __ Str(q4, MemOperand(x18, 15));
4264 END();
4265
4266 if (CAN_RUN()) {
4267 RUN();
4268
4269 ASSERT_EQUAL_128(0, 0xef, q0);
4270 ASSERT_EQUAL_128(0, 0xabcd, q1);
4271 ASSERT_EQUAL_128(0, 0x456789ab, q2);
4272 ASSERT_EQUAL_128(0, 0xabcdef0123456789, q3);
4273 ASSERT_EQUAL_128(0x89abcdef01234567, 0x89abcdef01234567, q4);
4274 ASSERT_EQUAL_64(0x89456789ababcdef, dst[0]);
4275 ASSERT_EQUAL_64(0x67abcdef01234567, dst[1]);
4276 ASSERT_EQUAL_64(0x6789abcdef012345, dst[2]);
4277 ASSERT_EQUAL_64(0x0089abcdef012345, dst[3]);
4278 }
4279 }
4280
4281
TEST(ldr_literal)4282 TEST(ldr_literal) {
4283 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
4284
4285 START();
4286 __ Ldr(x2, 0x1234567890abcdef);
4287 __ Ldr(w3, 0xfedcba09);
4288 __ Ldrsw(x4, 0x7fffffff);
4289 __ Ldrsw(x5, 0x80000000);
4290 __ Ldr(q11, 0x1234000056780000, 0xabcd0000ef000000);
4291 __ Ldr(d13, 1.234);
4292 __ Ldr(s25, 2.5);
4293 END();
4294
4295 if (CAN_RUN()) {
4296 RUN();
4297
4298 ASSERT_EQUAL_64(0x1234567890abcdef, x2);
4299 ASSERT_EQUAL_64(0xfedcba09, x3);
4300 ASSERT_EQUAL_64(0x7fffffff, x4);
4301 ASSERT_EQUAL_64(0xffffffff80000000, x5);
4302 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q11);
4303 ASSERT_EQUAL_FP64(1.234, d13);
4304 ASSERT_EQUAL_FP32(2.5, s25);
4305 }
4306 }
4307
4308
TEST(ldr_literal_range)4309 TEST(ldr_literal_range) {
4310 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
4311
4312 START();
4313 // Make sure the pool is empty;
4314 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
4315 ASSERT_LITERAL_POOL_SIZE(0);
4316
4317 // Create some literal pool entries.
4318 __ Ldr(x0, 0x1234567890abcdef);
4319 __ Ldr(w1, 0xfedcba09);
4320 __ Ldrsw(x2, 0x7fffffff);
4321 __ Ldrsw(x3, 0x80000000);
4322 __ Ldr(q2, 0x1234000056780000, 0xabcd0000ef000000);
4323 __ Ldr(d0, 1.234);
4324 __ Ldr(s1, 2.5);
4325 ASSERT_LITERAL_POOL_SIZE(48);
4326
4327 // Emit more code than the maximum literal load range to ensure the pool
4328 // should be emitted.
4329 const ptrdiff_t end = masm.GetCursorOffset() + 2 * kMaxLoadLiteralRange;
4330 while (masm.GetCursorOffset() < end) {
4331 __ Nop();
4332 }
4333
4334 // The pool should have been emitted.
4335 ASSERT_LITERAL_POOL_SIZE(0);
4336
4337 // These loads should be after the pool (and will require a new one).
4338 __ Ldr(x4, 0x34567890abcdef12);
4339 __ Ldr(w5, 0xdcba09fe);
4340 __ Ldrsw(x6, 0x7fffffff);
4341 __ Ldrsw(x7, 0x80000000);
4342 __ Ldr(q6, 0x1234000056780000, 0xabcd0000ef000000);
4343 __ Ldr(d4, 123.4);
4344 __ Ldr(s5, 250.0);
4345 ASSERT_LITERAL_POOL_SIZE(48);
4346 END();
4347
4348 if (CAN_RUN()) {
4349 RUN();
4350
4351 // Check that the literals loaded correctly.
4352 ASSERT_EQUAL_64(0x1234567890abcdef, x0);
4353 ASSERT_EQUAL_64(0xfedcba09, x1);
4354 ASSERT_EQUAL_64(0x7fffffff, x2);
4355 ASSERT_EQUAL_64(0xffffffff80000000, x3);
4356 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q2);
4357 ASSERT_EQUAL_FP64(1.234, d0);
4358 ASSERT_EQUAL_FP32(2.5, s1);
4359 ASSERT_EQUAL_64(0x34567890abcdef12, x4);
4360 ASSERT_EQUAL_64(0xdcba09fe, x5);
4361 ASSERT_EQUAL_64(0x7fffffff, x6);
4362 ASSERT_EQUAL_64(0xffffffff80000000, x7);
4363 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q6);
4364 ASSERT_EQUAL_FP64(123.4, d4);
4365 ASSERT_EQUAL_FP32(250.0, s5);
4366 }
4367 }
4368
4369
4370 template <typename T>
LoadIntValueHelper(T values[],int card)4371 void LoadIntValueHelper(T values[], int card) {
4372 SETUP();
4373
4374 const bool is_32bit = (sizeof(T) == 4);
4375 Register tgt1 = is_32bit ? Register(w1) : Register(x1);
4376 Register tgt2 = is_32bit ? Register(w2) : Register(x2);
4377
4378 START();
4379 __ Mov(x0, 0);
4380
4381 // If one of the values differ then x0 will be one.
4382 for (int i = 0; i < card; ++i) {
4383 __ Mov(tgt1, values[i]);
4384 __ Ldr(tgt2, values[i]);
4385 __ Cmp(tgt1, tgt2);
4386 __ Cset(x0, ne);
4387 }
4388 END();
4389
4390 if (CAN_RUN()) {
4391 RUN();
4392
4393 // If one of the values differs, the trace can be used to identify which
4394 // one.
4395 ASSERT_EQUAL_64(0, x0);
4396 }
4397 }
4398
4399
TEST(ldr_literal_values_x)4400 TEST(ldr_literal_values_x) {
4401 static const uint64_t kValues[] = {0x8000000000000000,
4402 0x7fffffffffffffff,
4403 0x0000000000000000,
4404 0xffffffffffffffff,
4405 0x00ff00ff00ff00ff,
4406 0x1234567890abcdef};
4407
4408 LoadIntValueHelper(kValues, sizeof(kValues) / sizeof(kValues[0]));
4409 }
4410
4411
TEST(ldr_literal_values_w)4412 TEST(ldr_literal_values_w) {
4413 static const uint32_t kValues[] = {0x80000000,
4414 0x7fffffff,
4415 0x00000000,
4416 0xffffffff,
4417 0x00ff00ff,
4418 0x12345678,
4419 0x90abcdef};
4420
4421 LoadIntValueHelper(kValues, sizeof(kValues) / sizeof(kValues[0]));
4422 }
4423
TEST(ldr_literal_custom)4424 TEST(ldr_literal_custom) {
4425 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
4426
4427 Label end_of_pool_before;
4428 Label end_of_pool_after;
4429
4430 const size_t kSizeOfPoolInBytes = 44;
4431
4432 Literal<uint64_t> before_x(0x1234567890abcdef);
4433 Literal<uint32_t> before_w(0xfedcba09);
4434 Literal<uint32_t> before_sx(0x80000000);
4435 Literal<uint64_t> before_q(0x1234000056780000, 0xabcd0000ef000000);
4436 Literal<double> before_d(1.234);
4437 Literal<float> before_s(2.5);
4438
4439 Literal<uint64_t> after_x(0x1234567890abcdef);
4440 Literal<uint32_t> after_w(0xfedcba09);
4441 Literal<uint32_t> after_sx(0x80000000);
4442 Literal<uint64_t> after_q(0x1234000056780000, 0xabcd0000ef000000);
4443 Literal<double> after_d(1.234);
4444 Literal<float> after_s(2.5);
4445
4446 START();
4447
4448 // Manually generate a pool.
4449 __ B(&end_of_pool_before);
4450 {
4451 ExactAssemblyScope scope(&masm, kSizeOfPoolInBytes);
4452 __ place(&before_x);
4453 __ place(&before_w);
4454 __ place(&before_sx);
4455 __ place(&before_q);
4456 __ place(&before_d);
4457 __ place(&before_s);
4458 }
4459 __ Bind(&end_of_pool_before);
4460
4461 {
4462 ExactAssemblyScope scope(&masm, 12 * kInstructionSize);
4463 __ ldr(x2, &before_x);
4464 __ ldr(w3, &before_w);
4465 __ ldrsw(x5, &before_sx);
4466 __ ldr(q11, &before_q);
4467 __ ldr(d13, &before_d);
4468 __ ldr(s25, &before_s);
4469
4470 __ ldr(x6, &after_x);
4471 __ ldr(w7, &after_w);
4472 __ ldrsw(x8, &after_sx);
4473 __ ldr(q18, &after_q);
4474 __ ldr(d14, &after_d);
4475 __ ldr(s26, &after_s);
4476 }
4477
4478 // Manually generate a pool.
4479 __ B(&end_of_pool_after);
4480 {
4481 ExactAssemblyScope scope(&masm, kSizeOfPoolInBytes);
4482 __ place(&after_x);
4483 __ place(&after_w);
4484 __ place(&after_sx);
4485 __ place(&after_q);
4486 __ place(&after_d);
4487 __ place(&after_s);
4488 }
4489 __ Bind(&end_of_pool_after);
4490
4491 END();
4492
4493 if (CAN_RUN()) {
4494 RUN();
4495
4496 ASSERT_EQUAL_64(0x1234567890abcdef, x2);
4497 ASSERT_EQUAL_64(0xfedcba09, x3);
4498 ASSERT_EQUAL_64(0xffffffff80000000, x5);
4499 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q11);
4500 ASSERT_EQUAL_FP64(1.234, d13);
4501 ASSERT_EQUAL_FP32(2.5, s25);
4502
4503 ASSERT_EQUAL_64(0x1234567890abcdef, x6);
4504 ASSERT_EQUAL_64(0xfedcba09, x7);
4505 ASSERT_EQUAL_64(0xffffffff80000000, x8);
4506 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q18);
4507 ASSERT_EQUAL_FP64(1.234, d14);
4508 ASSERT_EQUAL_FP32(2.5, s26);
4509 }
4510 }
4511
4512
TEST(ldr_literal_custom_shared)4513 TEST(ldr_literal_custom_shared) {
4514 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
4515
4516 Label end_of_pool_before;
4517 Label end_of_pool_after;
4518
4519 const size_t kSizeOfPoolInBytes = 40;
4520
4521 Literal<uint64_t> before_x(0x1234567890abcdef);
4522 Literal<uint32_t> before_w(0xfedcba09);
4523 Literal<uint64_t> before_q(0x1234000056780000, 0xabcd0000ef000000);
4524 Literal<double> before_d(1.234);
4525 Literal<float> before_s(2.5);
4526
4527 Literal<uint64_t> after_x(0x1234567890abcdef);
4528 Literal<uint32_t> after_w(0xfedcba09);
4529 Literal<uint64_t> after_q(0x1234000056780000, 0xabcd0000ef000000);
4530 Literal<double> after_d(1.234);
4531 Literal<float> after_s(2.5);
4532
4533 START();
4534
4535 // Manually generate a pool.
4536 __ B(&end_of_pool_before);
4537 {
4538 ExactAssemblyScope scope(&masm, kSizeOfPoolInBytes);
4539 __ place(&before_x);
4540 __ place(&before_w);
4541 __ place(&before_q);
4542 __ place(&before_d);
4543 __ place(&before_s);
4544 }
4545 __ Bind(&end_of_pool_before);
4546
4547 // Load the entries several times to test that literals can be shared.
4548 for (int i = 0; i < 50; i++) {
4549 ExactAssemblyScope scope(&masm, 12 * kInstructionSize);
4550 __ ldr(x2, &before_x);
4551 __ ldr(w3, &before_w);
4552 __ ldrsw(x5, &before_w); // Re-use before_w.
4553 __ ldr(q11, &before_q);
4554 __ ldr(d13, &before_d);
4555 __ ldr(s25, &before_s);
4556
4557 __ ldr(x6, &after_x);
4558 __ ldr(w7, &after_w);
4559 __ ldrsw(x8, &after_w); // Re-use after_w.
4560 __ ldr(q18, &after_q);
4561 __ ldr(d14, &after_d);
4562 __ ldr(s26, &after_s);
4563 }
4564
4565 // Manually generate a pool.
4566 __ B(&end_of_pool_after);
4567 {
4568 ExactAssemblyScope scope(&masm, kSizeOfPoolInBytes);
4569 __ place(&after_x);
4570 __ place(&after_w);
4571 __ place(&after_q);
4572 __ place(&after_d);
4573 __ place(&after_s);
4574 }
4575 __ Bind(&end_of_pool_after);
4576
4577 END();
4578
4579 if (CAN_RUN()) {
4580 RUN();
4581
4582 ASSERT_EQUAL_64(0x1234567890abcdef, x2);
4583 ASSERT_EQUAL_64(0xfedcba09, x3);
4584 ASSERT_EQUAL_64(0xfffffffffedcba09, x5);
4585 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q11);
4586 ASSERT_EQUAL_FP64(1.234, d13);
4587 ASSERT_EQUAL_FP32(2.5, s25);
4588
4589 ASSERT_EQUAL_64(0x1234567890abcdef, x6);
4590 ASSERT_EQUAL_64(0xfedcba09, x7);
4591 ASSERT_EQUAL_64(0xfffffffffedcba09, x8);
4592 ASSERT_EQUAL_128(0x1234000056780000, 0xabcd0000ef000000, q18);
4593 ASSERT_EQUAL_FP64(1.234, d14);
4594 ASSERT_EQUAL_FP32(2.5, s26);
4595 }
4596 }
4597
4598 static const PrefetchOperation kPrfmOperations[] = {PLDL1KEEP,
4599 PLDL1STRM,
4600 PLDL2KEEP,
4601 PLDL2STRM,
4602 PLDL3KEEP,
4603 PLDL3STRM,
4604
4605 PLIL1KEEP,
4606 PLIL1STRM,
4607 PLIL2KEEP,
4608 PLIL2STRM,
4609 PLIL3KEEP,
4610 PLIL3STRM,
4611
4612 PSTL1KEEP,
4613 PSTL1STRM,
4614 PSTL2KEEP,
4615 PSTL2STRM,
4616 PSTL3KEEP,
4617 PSTL3STRM};
4618
TEST(prfm_offset)4619 TEST(prfm_offset) {
4620 SETUP();
4621
4622 START();
4623 // The address used in prfm doesn't have to be valid.
4624 __ Mov(x0, 0x0123456789abcdef);
4625
4626 for (int op = 0; op < (1 << ImmPrefetchOperation_width); op++) {
4627 // Unallocated prefetch operations are ignored, so test all of them.
4628 // We have to use the Assembler directly for this.
4629 ExactAssemblyScope guard(&masm, 3 * kInstructionSize);
4630 __ prfm(op, MemOperand(x0));
4631 __ prfm(op, MemOperand(x0, 8));
4632 __ prfm(op, MemOperand(x0, 32760));
4633 }
4634
4635 for (PrefetchOperation op : kPrfmOperations) {
4636 // Also test named operations.
4637 __ Prfm(op, MemOperand(x0, 32768));
4638 __ Prfm(op, MemOperand(x0, 1));
4639 __ Prfm(op, MemOperand(x0, 9));
4640 __ Prfm(op, MemOperand(x0, 255));
4641 __ Prfm(op, MemOperand(x0, 257));
4642 __ Prfm(op, MemOperand(x0, -1));
4643 __ Prfm(op, MemOperand(x0, -9));
4644 __ Prfm(op, MemOperand(x0, -255));
4645 __ Prfm(op, MemOperand(x0, -257));
4646
4647 __ Prfm(op, MemOperand(x0, 0xfedcba9876543210));
4648 }
4649
4650 END();
4651 if (CAN_RUN()) {
4652 RUN();
4653 }
4654 }
4655
4656
TEST(prfm_regoffset)4657 TEST(prfm_regoffset) {
4658 SETUP();
4659
4660 START();
4661 // The address used in prfm doesn't have to be valid.
4662 __ Mov(x0, 0x0123456789abcdef);
4663
4664 CPURegList inputs(CPURegister::kRegister, kXRegSize, 10, 18);
4665 __ Mov(x10, 0);
4666 __ Mov(x11, 1);
4667 __ Mov(x12, 8);
4668 __ Mov(x13, 255);
4669 __ Mov(x14, -0);
4670 __ Mov(x15, -1);
4671 __ Mov(x16, -8);
4672 __ Mov(x17, -255);
4673 __ Mov(x18, 0xfedcba9876543210);
4674
4675 for (int op = 0; op < (1 << ImmPrefetchOperation_width); op++) {
4676 // Unallocated prefetch operations are ignored, so test all of them.
4677 // We have to use the Assembler directly for this.
4678
4679 // Prefetch operations of the form 0b11xxx are allocated to another
4680 // instruction.
4681 if (op >= 0b11000) continue;
4682
4683 ExactAssemblyScope guard(&masm, inputs.GetCount() * kInstructionSize);
4684 CPURegList loop = inputs;
4685 while (!loop.IsEmpty()) {
4686 __ prfm(op, MemOperand(x0, Register(loop.PopLowestIndex())));
4687 }
4688 }
4689
4690 for (PrefetchOperation op : kPrfmOperations) {
4691 // Also test named operations.
4692 CPURegList loop = inputs;
4693 while (!loop.IsEmpty()) {
4694 Register input(loop.PopLowestIndex());
4695 __ Prfm(op, MemOperand(x0, input, UXTW));
4696 __ Prfm(op, MemOperand(x0, input, UXTW, 3));
4697 __ Prfm(op, MemOperand(x0, input, LSL));
4698 __ Prfm(op, MemOperand(x0, input, LSL, 3));
4699 __ Prfm(op, MemOperand(x0, input, SXTW));
4700 __ Prfm(op, MemOperand(x0, input, SXTW, 3));
4701 __ Prfm(op, MemOperand(x0, input, SXTX));
4702 __ Prfm(op, MemOperand(x0, input, SXTX, 3));
4703 }
4704 }
4705
4706 END();
4707 if (CAN_RUN()) {
4708 RUN();
4709 }
4710 }
4711
4712
TEST(prfm_literal_imm19)4713 TEST(prfm_literal_imm19) {
4714 SETUP();
4715 START();
4716
4717 for (int op = 0; op < (1 << ImmPrefetchOperation_width); op++) {
4718 // Unallocated prefetch operations are ignored, so test all of them.
4719 // We have to use the Assembler directly for this.
4720 ExactAssemblyScope guard(&masm, 3 * kInstructionSize);
4721 __ prfm(op, INT64_C(0));
4722 __ prfm(op, 1);
4723 __ prfm(op, -1);
4724 }
4725
4726 for (PrefetchOperation op : kPrfmOperations) {
4727 // Also test named operations.
4728 ExactAssemblyScope guard(&masm, 4 * kInstructionSize);
4729 // The address used in prfm doesn't have to be valid.
4730 __ prfm(op, 1000);
4731 __ prfm(op, -1000);
4732 __ prfm(op, 0x3ffff);
4733 __ prfm(op, -0x40000);
4734 }
4735
4736 END();
4737 if (CAN_RUN()) {
4738 RUN();
4739 }
4740 }
4741
4742
TEST(prfm_literal)4743 TEST(prfm_literal) {
4744 SETUP();
4745
4746 Label end_of_pool_before;
4747 Label end_of_pool_after;
4748 Literal<uint64_t> before(0);
4749 Literal<uint64_t> after(0);
4750
4751 START();
4752
4753 // Manually generate a pool.
4754 __ B(&end_of_pool_before);
4755 {
4756 ExactAssemblyScope scope(&masm, before.GetSize());
4757 __ place(&before);
4758 }
4759 __ Bind(&end_of_pool_before);
4760
4761 for (int op = 0; op < (1 << ImmPrefetchOperation_width); op++) {
4762 // Unallocated prefetch operations are ignored, so test all of them.
4763 // We have to use the Assembler directly for this.
4764 ExactAssemblyScope guard(&masm, 2 * kInstructionSize);
4765 __ prfm(op, &before);
4766 __ prfm(op, &after);
4767 }
4768
4769 for (PrefetchOperation op : kPrfmOperations) {
4770 // Also test named operations.
4771 ExactAssemblyScope guard(&masm, 2 * kInstructionSize);
4772 __ prfm(op, &before);
4773 __ prfm(op, &after);
4774 }
4775
4776 // Manually generate a pool.
4777 __ B(&end_of_pool_after);
4778 {
4779 ExactAssemblyScope scope(&masm, after.GetSize());
4780 __ place(&after);
4781 }
4782 __ Bind(&end_of_pool_after);
4783
4784 END();
4785 if (CAN_RUN()) {
4786 RUN();
4787 }
4788 }
4789
4790
TEST(prfm_wide)4791 TEST(prfm_wide) {
4792 SETUP();
4793
4794 START();
4795 // The address used in prfm doesn't have to be valid.
4796 __ Mov(x0, 0x0123456789abcdef);
4797
4798 for (PrefetchOperation op : kPrfmOperations) {
4799 __ Prfm(op, MemOperand(x0, 0x40000));
4800 __ Prfm(op, MemOperand(x0, -0x40001));
4801 __ Prfm(op, MemOperand(x0, UINT64_C(0x5555555555555555)));
4802 __ Prfm(op, MemOperand(x0, UINT64_C(0xfedcba9876543210)));
4803 }
4804
4805 END();
4806 if (CAN_RUN()) {
4807 RUN();
4808 }
4809 }
4810
4811
TEST(load_prfm_literal)4812 TEST(load_prfm_literal) {
4813 // Test literals shared between both prfm and ldr.
4814 SETUP_WITH_FEATURES(CPUFeatures::kFP);
4815
4816 Label end_of_pool_before;
4817 Label end_of_pool_after;
4818
4819 const size_t kSizeOfPoolInBytes = 28;
4820
4821 Literal<uint64_t> before_x(0x1234567890abcdef);
4822 Literal<uint32_t> before_w(0xfedcba09);
4823 Literal<uint32_t> before_sx(0x80000000);
4824 Literal<double> before_d(1.234);
4825 Literal<float> before_s(2.5);
4826 Literal<uint64_t> after_x(0x1234567890abcdef);
4827 Literal<uint32_t> after_w(0xfedcba09);
4828 Literal<uint32_t> after_sx(0x80000000);
4829 Literal<double> after_d(1.234);
4830 Literal<float> after_s(2.5);
4831
4832 START();
4833
4834 // Manually generate a pool.
4835 __ B(&end_of_pool_before);
4836 {
4837 ExactAssemblyScope scope(&masm, kSizeOfPoolInBytes);
4838 __ place(&before_x);
4839 __ place(&before_w);
4840 __ place(&before_sx);
4841 __ place(&before_d);
4842 __ place(&before_s);
4843 }
4844 __ Bind(&end_of_pool_before);
4845
4846 for (int op = 0; op < (1 << ImmPrefetchOperation_width); op++) {
4847 // Unallocated prefetch operations are ignored, so test all of them.
4848 ExactAssemblyScope scope(&masm, 10 * kInstructionSize);
4849
4850 __ prfm(op, &before_x);
4851 __ prfm(op, &before_w);
4852 __ prfm(op, &before_sx);
4853 __ prfm(op, &before_d);
4854 __ prfm(op, &before_s);
4855
4856 __ prfm(op, &after_x);
4857 __ prfm(op, &after_w);
4858 __ prfm(op, &after_sx);
4859 __ prfm(op, &after_d);
4860 __ prfm(op, &after_s);
4861 }
4862
4863 for (PrefetchOperation op : kPrfmOperations) {
4864 // Also test named operations.
4865 ExactAssemblyScope scope(&masm, 10 * kInstructionSize);
4866
4867 __ prfm(op, &before_x);
4868 __ prfm(op, &before_w);
4869 __ prfm(op, &before_sx);
4870 __ prfm(op, &before_d);
4871 __ prfm(op, &before_s);
4872
4873 __ prfm(op, &after_x);
4874 __ prfm(op, &after_w);
4875 __ prfm(op, &after_sx);
4876 __ prfm(op, &after_d);
4877 __ prfm(op, &after_s);
4878 }
4879
4880 {
4881 ExactAssemblyScope scope(&masm, 10 * kInstructionSize);
4882 __ ldr(x2, &before_x);
4883 __ ldr(w3, &before_w);
4884 __ ldrsw(x5, &before_sx);
4885 __ ldr(d13, &before_d);
4886 __ ldr(s25, &before_s);
4887
4888 __ ldr(x6, &after_x);
4889 __ ldr(w7, &after_w);
4890 __ ldrsw(x8, &after_sx);
4891 __ ldr(d14, &after_d);
4892 __ ldr(s26, &after_s);
4893 }
4894
4895 // Manually generate a pool.
4896 __ B(&end_of_pool_after);
4897 {
4898 ExactAssemblyScope scope(&masm, kSizeOfPoolInBytes);
4899 __ place(&after_x);
4900 __ place(&after_w);
4901 __ place(&after_sx);
4902 __ place(&after_d);
4903 __ place(&after_s);
4904 }
4905 __ Bind(&end_of_pool_after);
4906
4907 END();
4908
4909 if (CAN_RUN()) {
4910 RUN();
4911
4912 ASSERT_EQUAL_64(0x1234567890abcdef, x2);
4913 ASSERT_EQUAL_64(0xfedcba09, x3);
4914 ASSERT_EQUAL_64(0xffffffff80000000, x5);
4915 ASSERT_EQUAL_FP64(1.234, d13);
4916 ASSERT_EQUAL_FP32(2.5, s25);
4917
4918 ASSERT_EQUAL_64(0x1234567890abcdef, x6);
4919 ASSERT_EQUAL_64(0xfedcba09, x7);
4920 ASSERT_EQUAL_64(0xffffffff80000000, x8);
4921 ASSERT_EQUAL_FP64(1.234, d14);
4922 ASSERT_EQUAL_FP32(2.5, s26);
4923 }
4924 }
4925
4926
TEST(add_sub_imm)4927 TEST(add_sub_imm) {
4928 SETUP();
4929
4930 START();
4931 __ Mov(x0, 0x0);
4932 __ Mov(x1, 0x1111);
4933 __ Mov(x2, 0xffffffffffffffff);
4934 __ Mov(x3, 0x8000000000000000);
4935
4936 __ Add(x10, x0, Operand(0x123));
4937 __ Add(x11, x1, Operand(0x122000));
4938 __ Add(x12, x0, Operand(0xabc << 12));
4939 __ Add(x13, x2, Operand(1));
4940
4941 __ Add(w14, w0, Operand(0x123));
4942 __ Add(w15, w1, Operand(0x122000));
4943 __ Add(w16, w0, Operand(0xabc << 12));
4944 __ Add(w17, w2, Operand(1));
4945
4946 __ Sub(x20, x0, Operand(0x1));
4947 __ Sub(x21, x1, Operand(0x111));
4948 __ Sub(x22, x1, Operand(0x1 << 12));
4949 __ Sub(x23, x3, Operand(1));
4950
4951 __ Sub(w24, w0, Operand(0x1));
4952 __ Sub(w25, w1, Operand(0x111));
4953 __ Sub(w26, w1, Operand(0x1 << 12));
4954 __ Sub(w27, w3, Operand(1));
4955 END();
4956
4957 if (CAN_RUN()) {
4958 RUN();
4959
4960 ASSERT_EQUAL_64(0x123, x10);
4961 ASSERT_EQUAL_64(0x123111, x11);
4962 ASSERT_EQUAL_64(0xabc000, x12);
4963 ASSERT_EQUAL_64(0x0, x13);
4964
4965 ASSERT_EQUAL_32(0x123, w14);
4966 ASSERT_EQUAL_32(0x123111, w15);
4967 ASSERT_EQUAL_32(0xabc000, w16);
4968 ASSERT_EQUAL_32(0x0, w17);
4969
4970 ASSERT_EQUAL_64(0xffffffffffffffff, x20);
4971 ASSERT_EQUAL_64(0x1000, x21);
4972 ASSERT_EQUAL_64(0x111, x22);
4973 ASSERT_EQUAL_64(0x7fffffffffffffff, x23);
4974
4975 ASSERT_EQUAL_32(0xffffffff, w24);
4976 ASSERT_EQUAL_32(0x1000, w25);
4977 ASSERT_EQUAL_32(0x111, w26);
4978 ASSERT_EQUAL_32(0xffffffff, w27);
4979 }
4980 }
4981
4982
TEST(add_sub_wide_imm)4983 TEST(add_sub_wide_imm) {
4984 SETUP();
4985
4986 START();
4987 __ Mov(x0, 0x0);
4988 __ Mov(x1, 0x1);
4989
4990 __ Add(x10, x0, Operand(0x1234567890abcdef));
4991 __ Add(x11, x1, Operand(0xffffffff));
4992
4993 __ Add(w12, w0, Operand(0x12345678));
4994 __ Add(w13, w1, Operand(0xffffffff));
4995
4996 __ Add(w18, w0, Operand(kWMinInt));
4997 __ Sub(w19, w0, Operand(kWMinInt));
4998
4999 __ Sub(x20, x0, Operand(0x1234567890abcdef));
5000 __ Sub(w21, w0, Operand(0x12345678));
5001
5002 END();
5003
5004 if (CAN_RUN()) {
5005 RUN();
5006
5007 ASSERT_EQUAL_64(0x1234567890abcdef, x10);
5008 ASSERT_EQUAL_64(0x100000000, x11);
5009
5010 ASSERT_EQUAL_32(0x12345678, w12);
5011 ASSERT_EQUAL_64(0x0, x13);
5012
5013 ASSERT_EQUAL_32(kWMinInt, w18);
5014 ASSERT_EQUAL_32(kWMinInt, w19);
5015
5016 ASSERT_EQUAL_64(-0x1234567890abcdef, x20);
5017 ASSERT_EQUAL_32(-0x12345678, w21);
5018 }
5019 }
5020
5021
TEST(add_sub_shifted)5022 TEST(add_sub_shifted) {
5023 SETUP();
5024
5025 START();
5026 __ Mov(x0, 0);
5027 __ Mov(x1, 0x0123456789abcdef);
5028 __ Mov(x2, 0xfedcba9876543210);
5029 __ Mov(x3, 0xffffffffffffffff);
5030
5031 __ Add(x10, x1, Operand(x2));
5032 __ Add(x11, x0, Operand(x1, LSL, 8));
5033 __ Add(x12, x0, Operand(x1, LSR, 8));
5034 __ Add(x13, x0, Operand(x1, ASR, 8));
5035 __ Add(x14, x0, Operand(x2, ASR, 8));
5036 __ Add(w15, w0, Operand(w1, ASR, 8));
5037 __ Add(w18, w3, Operand(w1, ROR, 8));
5038 __ Add(x19, x3, Operand(x1, ROR, 8));
5039
5040 __ Sub(x20, x3, Operand(x2));
5041 __ Sub(x21, x3, Operand(x1, LSL, 8));
5042 __ Sub(x22, x3, Operand(x1, LSR, 8));
5043 __ Sub(x23, x3, Operand(x1, ASR, 8));
5044 __ Sub(x24, x3, Operand(x2, ASR, 8));
5045 __ Sub(w25, w3, Operand(w1, ASR, 8));
5046 __ Sub(w26, w3, Operand(w1, ROR, 8));
5047 __ Sub(x27, x3, Operand(x1, ROR, 8));
5048 END();
5049
5050 if (CAN_RUN()) {
5051 RUN();
5052
5053 ASSERT_EQUAL_64(0xffffffffffffffff, x10);
5054 ASSERT_EQUAL_64(0x23456789abcdef00, x11);
5055 ASSERT_EQUAL_64(0x000123456789abcd, x12);
5056 ASSERT_EQUAL_64(0x000123456789abcd, x13);
5057 ASSERT_EQUAL_64(0xfffedcba98765432, x14);
5058 ASSERT_EQUAL_64(0xff89abcd, x15);
5059 ASSERT_EQUAL_64(0xef89abcc, x18);
5060 ASSERT_EQUAL_64(0xef0123456789abcc, x19);
5061
5062 ASSERT_EQUAL_64(0x0123456789abcdef, x20);
5063 ASSERT_EQUAL_64(0xdcba9876543210ff, x21);
5064 ASSERT_EQUAL_64(0xfffedcba98765432, x22);
5065 ASSERT_EQUAL_64(0xfffedcba98765432, x23);
5066 ASSERT_EQUAL_64(0x000123456789abcd, x24);
5067 ASSERT_EQUAL_64(0x00765432, x25);
5068 ASSERT_EQUAL_64(0x10765432, x26);
5069 ASSERT_EQUAL_64(0x10fedcba98765432, x27);
5070 }
5071 }
5072
5073
TEST(add_sub_extended)5074 TEST(add_sub_extended) {
5075 SETUP();
5076
5077 START();
5078 __ Mov(x0, 0);
5079 __ Mov(x1, 0x0123456789abcdef);
5080 __ Mov(x2, 0xfedcba9876543210);
5081 __ Mov(w3, 0x80);
5082
5083 __ Add(x10, x0, Operand(x1, UXTB, 0));
5084 __ Add(x11, x0, Operand(x1, UXTB, 1));
5085 __ Add(x12, x0, Operand(x1, UXTH, 2));
5086 __ Add(x13, x0, Operand(x1, UXTW, 4));
5087
5088 __ Add(x14, x0, Operand(x1, SXTB, 0));
5089 __ Add(x15, x0, Operand(x1, SXTB, 1));
5090 __ Add(x16, x0, Operand(x1, SXTH, 2));
5091 __ Add(x17, x0, Operand(x1, SXTW, 3));
5092 __ Add(x18, x0, Operand(x2, SXTB, 0));
5093 __ Add(x19, x0, Operand(x2, SXTB, 1));
5094 __ Add(x20, x0, Operand(x2, SXTH, 2));
5095 __ Add(x21, x0, Operand(x2, SXTW, 3));
5096
5097 __ Add(x22, x1, Operand(x2, SXTB, 1));
5098 __ Sub(x23, x1, Operand(x2, SXTB, 1));
5099
5100 __ Add(w24, w1, Operand(w2, UXTB, 2));
5101 __ Add(w25, w0, Operand(w1, SXTB, 0));
5102 __ Add(w26, w0, Operand(w1, SXTB, 1));
5103 __ Add(w27, w2, Operand(w1, SXTW, 3));
5104
5105 __ Add(w28, w0, Operand(w1, SXTW, 3));
5106 __ Add(x29, x0, Operand(w1, SXTW, 3));
5107
5108 __ Sub(x30, x0, Operand(w3, SXTB, 1));
5109 END();
5110
5111 if (CAN_RUN()) {
5112 RUN();
5113
5114 ASSERT_EQUAL_64(0xef, x10);
5115 ASSERT_EQUAL_64(0x1de, x11);
5116 ASSERT_EQUAL_64(0x337bc, x12);
5117 ASSERT_EQUAL_64(0x89abcdef0, x13);
5118
5119 ASSERT_EQUAL_64(0xffffffffffffffef, x14);
5120 ASSERT_EQUAL_64(0xffffffffffffffde, x15);
5121 ASSERT_EQUAL_64(0xffffffffffff37bc, x16);
5122 ASSERT_EQUAL_64(0xfffffffc4d5e6f78, x17);
5123 ASSERT_EQUAL_64(0x10, x18);
5124 ASSERT_EQUAL_64(0x20, x19);
5125 ASSERT_EQUAL_64(0xc840, x20);
5126 ASSERT_EQUAL_64(0x3b2a19080, x21);
5127
5128 ASSERT_EQUAL_64(0x0123456789abce0f, x22);
5129 ASSERT_EQUAL_64(0x0123456789abcdcf, x23);
5130
5131 ASSERT_EQUAL_32(0x89abce2f, w24);
5132 ASSERT_EQUAL_32(0xffffffef, w25);
5133 ASSERT_EQUAL_32(0xffffffde, w26);
5134 ASSERT_EQUAL_32(0xc3b2a188, w27);
5135
5136 ASSERT_EQUAL_32(0x4d5e6f78, w28);
5137 ASSERT_EQUAL_64(0xfffffffc4d5e6f78, x29);
5138
5139 ASSERT_EQUAL_64(256, x30);
5140 }
5141 }
5142
5143
TEST(add_sub_negative)5144 TEST(add_sub_negative) {
5145 SETUP();
5146
5147 START();
5148 __ Mov(x0, 0);
5149 __ Mov(x1, 4687);
5150 __ Mov(x2, 0x1122334455667788);
5151 __ Mov(w3, 0x11223344);
5152 __ Mov(w4, 400000);
5153
5154 __ Add(x10, x0, -42);
5155 __ Add(x11, x1, -687);
5156 __ Add(x12, x2, -0x88);
5157
5158 __ Sub(x13, x0, -600);
5159 __ Sub(x14, x1, -313);
5160 __ Sub(x15, x2, -0x555);
5161
5162 __ Add(w19, w3, -0x344);
5163 __ Add(w20, w4, -2000);
5164
5165 __ Sub(w21, w3, -0xbc);
5166 __ Sub(w22, w4, -2000);
5167 END();
5168
5169 if (CAN_RUN()) {
5170 RUN();
5171
5172 ASSERT_EQUAL_64(-42, x10);
5173 ASSERT_EQUAL_64(4000, x11);
5174 ASSERT_EQUAL_64(0x1122334455667700, x12);
5175
5176 ASSERT_EQUAL_64(600, x13);
5177 ASSERT_EQUAL_64(5000, x14);
5178 ASSERT_EQUAL_64(0x1122334455667cdd, x15);
5179
5180 ASSERT_EQUAL_32(0x11223000, w19);
5181 ASSERT_EQUAL_32(398000, w20);
5182
5183 ASSERT_EQUAL_32(0x11223400, w21);
5184 ASSERT_EQUAL_32(402000, w22);
5185 }
5186 }
5187
5188
TEST(add_sub_zero)5189 TEST(add_sub_zero) {
5190 SETUP();
5191
5192 START();
5193 __ Mov(x0, 0);
5194 __ Mov(x1, 0);
5195 __ Mov(x2, 0);
5196
5197 Label blob1;
5198 __ Bind(&blob1);
5199 __ Add(x0, x0, 0);
5200 __ Sub(x1, x1, 0);
5201 __ Sub(x2, x2, xzr);
5202 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&blob1) == 0);
5203
5204 Label blob2;
5205 __ Bind(&blob2);
5206 __ Add(w3, w3, 0);
5207 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&blob2) != 0);
5208
5209 Label blob3;
5210 __ Bind(&blob3);
5211 __ Sub(w3, w3, wzr);
5212 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&blob3) != 0);
5213
5214 END();
5215
5216 if (CAN_RUN()) {
5217 RUN();
5218
5219 ASSERT_EQUAL_64(0, x0);
5220 ASSERT_EQUAL_64(0, x1);
5221 ASSERT_EQUAL_64(0, x2);
5222 }
5223 }
5224
5225
TEST(claim_drop_zero)5226 TEST(claim_drop_zero) {
5227 SETUP();
5228
5229 START();
5230
5231 Label start;
5232 __ Bind(&start);
5233 __ Claim(Operand(0));
5234 __ Drop(Operand(0));
5235 __ Claim(Operand(xzr));
5236 __ Drop(Operand(xzr));
5237 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&start) == 0);
5238
5239 END();
5240
5241 if (CAN_RUN()) {
5242 RUN();
5243 }
5244 }
5245
5246
TEST(neg)5247 TEST(neg) {
5248 SETUP();
5249
5250 START();
5251 __ Mov(x0, 0xf123456789abcdef);
5252
5253 // Immediate.
5254 __ Neg(x1, 0x123);
5255 __ Neg(w2, 0x123);
5256
5257 // Shifted.
5258 __ Neg(x3, Operand(x0, LSL, 1));
5259 __ Neg(w4, Operand(w0, LSL, 2));
5260 __ Neg(x5, Operand(x0, LSR, 3));
5261 __ Neg(w6, Operand(w0, LSR, 4));
5262 __ Neg(x7, Operand(x0, ASR, 5));
5263 __ Neg(w8, Operand(w0, ASR, 6));
5264
5265 // Extended.
5266 __ Neg(w9, Operand(w0, UXTB));
5267 __ Neg(x10, Operand(x0, SXTB, 1));
5268 __ Neg(w11, Operand(w0, UXTH, 2));
5269 __ Neg(x12, Operand(x0, SXTH, 3));
5270 __ Neg(w13, Operand(w0, UXTW, 4));
5271 __ Neg(x14, Operand(x0, SXTW, 4));
5272 END();
5273
5274 if (CAN_RUN()) {
5275 RUN();
5276
5277 ASSERT_EQUAL_64(0xfffffffffffffedd, x1);
5278 ASSERT_EQUAL_64(0xfffffedd, x2);
5279 ASSERT_EQUAL_64(0x1db97530eca86422, x3);
5280 ASSERT_EQUAL_64(0xd950c844, x4);
5281 ASSERT_EQUAL_64(0xe1db97530eca8643, x5);
5282 ASSERT_EQUAL_64(0xf7654322, x6);
5283 ASSERT_EQUAL_64(0x0076e5d4c3b2a191, x7);
5284 ASSERT_EQUAL_64(0x01d950c9, x8);
5285 ASSERT_EQUAL_64(0xffffff11, x9);
5286 ASSERT_EQUAL_64(0x0000000000000022, x10);
5287 ASSERT_EQUAL_64(0xfffcc844, x11);
5288 ASSERT_EQUAL_64(0x0000000000019088, x12);
5289 ASSERT_EQUAL_64(0x65432110, x13);
5290 ASSERT_EQUAL_64(0x0000000765432110, x14);
5291 }
5292 }
5293
5294
5295 template <typename T, typename Op>
AdcsSbcsHelper(Op op,T left,T right,int carry,T expected,StatusFlags expected_flags)5296 static void AdcsSbcsHelper(
5297 Op op, T left, T right, int carry, T expected, StatusFlags expected_flags) {
5298 int reg_size = sizeof(T) * 8;
5299 Register left_reg(0, reg_size);
5300 Register right_reg(1, reg_size);
5301 Register result_reg(2, reg_size);
5302
5303 SETUP();
5304 START();
5305
5306 __ Mov(left_reg, left);
5307 __ Mov(right_reg, right);
5308 __ Mov(x10, (carry ? CFlag : NoFlag));
5309
5310 __ Msr(NZCV, x10);
5311 (masm.*op)(result_reg, left_reg, right_reg);
5312
5313 END();
5314 if (CAN_RUN()) {
5315 RUN();
5316
5317 ASSERT_EQUAL_64(left, left_reg.X());
5318 ASSERT_EQUAL_64(right, right_reg.X());
5319 ASSERT_EQUAL_64(expected, result_reg.X());
5320 ASSERT_EQUAL_NZCV(expected_flags);
5321 }
5322 }
5323
5324
TEST(adcs_sbcs_x)5325 TEST(adcs_sbcs_x) {
5326 uint64_t inputs[] = {
5327 0x0000000000000000,
5328 0x0000000000000001,
5329 0x7ffffffffffffffe,
5330 0x7fffffffffffffff,
5331 0x8000000000000000,
5332 0x8000000000000001,
5333 0xfffffffffffffffe,
5334 0xffffffffffffffff,
5335 };
5336 static const size_t input_count = sizeof(inputs) / sizeof(inputs[0]);
5337
5338 struct Expected {
5339 uint64_t carry0_result;
5340 StatusFlags carry0_flags;
5341 uint64_t carry1_result;
5342 StatusFlags carry1_flags;
5343 };
5344
5345 static const Expected expected_adcs_x[input_count][input_count] =
5346 {{{0x0000000000000000, ZFlag, 0x0000000000000001, NoFlag},
5347 {0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag},
5348 {0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag},
5349 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5350 {0x8000000000000000, NFlag, 0x8000000000000001, NFlag},
5351 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5352 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5353 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag}},
5354 {{0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag},
5355 {0x0000000000000002, NoFlag, 0x0000000000000003, NoFlag},
5356 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5357 {0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
5358 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5359 {0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
5360 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5361 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag}},
5362 {{0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag},
5363 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5364 {0xfffffffffffffffc, NVFlag, 0xfffffffffffffffd, NVFlag},
5365 {0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
5366 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5367 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5368 {0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
5369 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag}},
5370 {{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5371 {0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
5372 {0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
5373 {0xfffffffffffffffe, NVFlag, 0xffffffffffffffff, NVFlag},
5374 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5375 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5376 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5377 {0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag}},
5378 {{0x8000000000000000, NFlag, 0x8000000000000001, NFlag},
5379 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5380 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5381 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5382 {0x0000000000000000, ZCVFlag, 0x0000000000000001, CVFlag},
5383 {0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
5384 {0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
5385 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag}},
5386 {{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5387 {0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
5388 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5389 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5390 {0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
5391 {0x0000000000000002, CVFlag, 0x0000000000000003, CVFlag},
5392 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5393 {0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag}},
5394 {{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5395 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5396 {0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
5397 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5398 {0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
5399 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5400 {0xfffffffffffffffc, NCFlag, 0xfffffffffffffffd, NCFlag},
5401 {0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag}},
5402 {{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5403 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5404 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5405 {0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag},
5406 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5407 {0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag},
5408 {0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag},
5409 {0xfffffffffffffffe, NCFlag, 0xffffffffffffffff, NCFlag}}};
5410
5411 static const Expected expected_sbcs_x[input_count][input_count] =
5412 {{{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5413 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5414 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5415 {0x8000000000000000, NFlag, 0x8000000000000001, NFlag},
5416 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5417 {0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag},
5418 {0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag},
5419 {0x0000000000000000, ZFlag, 0x0000000000000001, NoFlag}},
5420 {{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5421 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5422 {0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
5423 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5424 {0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
5425 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5426 {0x0000000000000002, NoFlag, 0x0000000000000003, NoFlag},
5427 {0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag}},
5428 {{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5429 {0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
5430 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5431 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5432 {0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
5433 {0xfffffffffffffffc, NVFlag, 0xfffffffffffffffd, NVFlag},
5434 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
5435 {0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag}},
5436 {{0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag},
5437 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5438 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5439 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5440 {0xfffffffffffffffe, NVFlag, 0xffffffffffffffff, NVFlag},
5441 {0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
5442 {0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
5443 {0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag}},
5444 {{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5445 {0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
5446 {0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
5447 {0x0000000000000000, ZCVFlag, 0x0000000000000001, CVFlag},
5448 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5449 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
5450 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
5451 {0x8000000000000000, NFlag, 0x8000000000000001, NFlag}},
5452 {{0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag},
5453 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5454 {0x0000000000000002, CVFlag, 0x0000000000000003, CVFlag},
5455 {0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
5456 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5457 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5458 {0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
5459 {0x8000000000000001, NFlag, 0x8000000000000002, NFlag}},
5460 {{0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag},
5461 {0xfffffffffffffffc, NCFlag, 0xfffffffffffffffd, NCFlag},
5462 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5463 {0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
5464 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5465 {0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
5466 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
5467 {0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag}},
5468 {{0xfffffffffffffffe, NCFlag, 0xffffffffffffffff, NCFlag},
5469 {0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag},
5470 {0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag},
5471 {0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
5472 {0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag},
5473 {0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
5474 {0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
5475 {0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag}}};
5476
5477 for (size_t left = 0; left < input_count; left++) {
5478 for (size_t right = 0; right < input_count; right++) {
5479 const Expected& expected = expected_adcs_x[left][right];
5480 AdcsSbcsHelper(&MacroAssembler::Adcs,
5481 inputs[left],
5482 inputs[right],
5483 0,
5484 expected.carry0_result,
5485 expected.carry0_flags);
5486 AdcsSbcsHelper(&MacroAssembler::Adcs,
5487 inputs[left],
5488 inputs[right],
5489 1,
5490 expected.carry1_result,
5491 expected.carry1_flags);
5492 }
5493 }
5494
5495 for (size_t left = 0; left < input_count; left++) {
5496 for (size_t right = 0; right < input_count; right++) {
5497 const Expected& expected = expected_sbcs_x[left][right];
5498 AdcsSbcsHelper(&MacroAssembler::Sbcs,
5499 inputs[left],
5500 inputs[right],
5501 0,
5502 expected.carry0_result,
5503 expected.carry0_flags);
5504 AdcsSbcsHelper(&MacroAssembler::Sbcs,
5505 inputs[left],
5506 inputs[right],
5507 1,
5508 expected.carry1_result,
5509 expected.carry1_flags);
5510 }
5511 }
5512 }
5513
5514
TEST(adcs_sbcs_w)5515 TEST(adcs_sbcs_w) {
5516 uint32_t inputs[] = {
5517 0x00000000,
5518 0x00000001,
5519 0x7ffffffe,
5520 0x7fffffff,
5521 0x80000000,
5522 0x80000001,
5523 0xfffffffe,
5524 0xffffffff,
5525 };
5526 static const size_t input_count = sizeof(inputs) / sizeof(inputs[0]);
5527
5528 struct Expected {
5529 uint32_t carry0_result;
5530 StatusFlags carry0_flags;
5531 uint32_t carry1_result;
5532 StatusFlags carry1_flags;
5533 };
5534
5535 static const Expected expected_adcs_w[input_count][input_count] =
5536 {{{0x00000000, ZFlag, 0x00000001, NoFlag},
5537 {0x00000001, NoFlag, 0x00000002, NoFlag},
5538 {0x7ffffffe, NoFlag, 0x7fffffff, NoFlag},
5539 {0x7fffffff, NoFlag, 0x80000000, NVFlag},
5540 {0x80000000, NFlag, 0x80000001, NFlag},
5541 {0x80000001, NFlag, 0x80000002, NFlag},
5542 {0xfffffffe, NFlag, 0xffffffff, NFlag},
5543 {0xffffffff, NFlag, 0x00000000, ZCFlag}},
5544 {{0x00000001, NoFlag, 0x00000002, NoFlag},
5545 {0x00000002, NoFlag, 0x00000003, NoFlag},
5546 {0x7fffffff, NoFlag, 0x80000000, NVFlag},
5547 {0x80000000, NVFlag, 0x80000001, NVFlag},
5548 {0x80000001, NFlag, 0x80000002, NFlag},
5549 {0x80000002, NFlag, 0x80000003, NFlag},
5550 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5551 {0x00000000, ZCFlag, 0x00000001, CFlag}},
5552 {{0x7ffffffe, NoFlag, 0x7fffffff, NoFlag},
5553 {0x7fffffff, NoFlag, 0x80000000, NVFlag},
5554 {0xfffffffc, NVFlag, 0xfffffffd, NVFlag},
5555 {0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
5556 {0xfffffffe, NFlag, 0xffffffff, NFlag},
5557 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5558 {0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
5559 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag}},
5560 {{0x7fffffff, NoFlag, 0x80000000, NVFlag},
5561 {0x80000000, NVFlag, 0x80000001, NVFlag},
5562 {0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
5563 {0xfffffffe, NVFlag, 0xffffffff, NVFlag},
5564 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5565 {0x00000000, ZCFlag, 0x00000001, CFlag},
5566 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5567 {0x7ffffffe, CFlag, 0x7fffffff, CFlag}},
5568 {{0x80000000, NFlag, 0x80000001, NFlag},
5569 {0x80000001, NFlag, 0x80000002, NFlag},
5570 {0xfffffffe, NFlag, 0xffffffff, NFlag},
5571 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5572 {0x00000000, ZCVFlag, 0x00000001, CVFlag},
5573 {0x00000001, CVFlag, 0x00000002, CVFlag},
5574 {0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
5575 {0x7fffffff, CVFlag, 0x80000000, NCFlag}},
5576 {{0x80000001, NFlag, 0x80000002, NFlag},
5577 {0x80000002, NFlag, 0x80000003, NFlag},
5578 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5579 {0x00000000, ZCFlag, 0x00000001, CFlag},
5580 {0x00000001, CVFlag, 0x00000002, CVFlag},
5581 {0x00000002, CVFlag, 0x00000003, CVFlag},
5582 {0x7fffffff, CVFlag, 0x80000000, NCFlag},
5583 {0x80000000, NCFlag, 0x80000001, NCFlag}},
5584 {{0xfffffffe, NFlag, 0xffffffff, NFlag},
5585 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5586 {0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
5587 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5588 {0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
5589 {0x7fffffff, CVFlag, 0x80000000, NCFlag},
5590 {0xfffffffc, NCFlag, 0xfffffffd, NCFlag},
5591 {0xfffffffd, NCFlag, 0xfffffffe, NCFlag}},
5592 {{0xffffffff, NFlag, 0x00000000, ZCFlag},
5593 {0x00000000, ZCFlag, 0x00000001, CFlag},
5594 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5595 {0x7ffffffe, CFlag, 0x7fffffff, CFlag},
5596 {0x7fffffff, CVFlag, 0x80000000, NCFlag},
5597 {0x80000000, NCFlag, 0x80000001, NCFlag},
5598 {0xfffffffd, NCFlag, 0xfffffffe, NCFlag},
5599 {0xfffffffe, NCFlag, 0xffffffff, NCFlag}}};
5600
5601 static const Expected expected_sbcs_w[input_count][input_count] =
5602 {{{0xffffffff, NFlag, 0x00000000, ZCFlag},
5603 {0xfffffffe, NFlag, 0xffffffff, NFlag},
5604 {0x80000001, NFlag, 0x80000002, NFlag},
5605 {0x80000000, NFlag, 0x80000001, NFlag},
5606 {0x7fffffff, NoFlag, 0x80000000, NVFlag},
5607 {0x7ffffffe, NoFlag, 0x7fffffff, NoFlag},
5608 {0x00000001, NoFlag, 0x00000002, NoFlag},
5609 {0x00000000, ZFlag, 0x00000001, NoFlag}},
5610 {{0x00000000, ZCFlag, 0x00000001, CFlag},
5611 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5612 {0x80000002, NFlag, 0x80000003, NFlag},
5613 {0x80000001, NFlag, 0x80000002, NFlag},
5614 {0x80000000, NVFlag, 0x80000001, NVFlag},
5615 {0x7fffffff, NoFlag, 0x80000000, NVFlag},
5616 {0x00000002, NoFlag, 0x00000003, NoFlag},
5617 {0x00000001, NoFlag, 0x00000002, NoFlag}},
5618 {{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5619 {0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
5620 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5621 {0xfffffffe, NFlag, 0xffffffff, NFlag},
5622 {0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
5623 {0xfffffffc, NVFlag, 0xfffffffd, NVFlag},
5624 {0x7fffffff, NoFlag, 0x80000000, NVFlag},
5625 {0x7ffffffe, NoFlag, 0x7fffffff, NoFlag}},
5626 {{0x7ffffffe, CFlag, 0x7fffffff, CFlag},
5627 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5628 {0x00000000, ZCFlag, 0x00000001, CFlag},
5629 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5630 {0xfffffffe, NVFlag, 0xffffffff, NVFlag},
5631 {0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
5632 {0x80000000, NVFlag, 0x80000001, NVFlag},
5633 {0x7fffffff, NoFlag, 0x80000000, NVFlag}},
5634 {{0x7fffffff, CVFlag, 0x80000000, NCFlag},
5635 {0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
5636 {0x00000001, CVFlag, 0x00000002, CVFlag},
5637 {0x00000000, ZCVFlag, 0x00000001, CVFlag},
5638 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5639 {0xfffffffe, NFlag, 0xffffffff, NFlag},
5640 {0x80000001, NFlag, 0x80000002, NFlag},
5641 {0x80000000, NFlag, 0x80000001, NFlag}},
5642 {{0x80000000, NCFlag, 0x80000001, NCFlag},
5643 {0x7fffffff, CVFlag, 0x80000000, NCFlag},
5644 {0x00000002, CVFlag, 0x00000003, CVFlag},
5645 {0x00000001, CVFlag, 0x00000002, CVFlag},
5646 {0x00000000, ZCFlag, 0x00000001, CFlag},
5647 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5648 {0x80000002, NFlag, 0x80000003, NFlag},
5649 {0x80000001, NFlag, 0x80000002, NFlag}},
5650 {{0xfffffffd, NCFlag, 0xfffffffe, NCFlag},
5651 {0xfffffffc, NCFlag, 0xfffffffd, NCFlag},
5652 {0x7fffffff, CVFlag, 0x80000000, NCFlag},
5653 {0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
5654 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5655 {0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
5656 {0xffffffff, NFlag, 0x00000000, ZCFlag},
5657 {0xfffffffe, NFlag, 0xffffffff, NFlag}},
5658 {{0xfffffffe, NCFlag, 0xffffffff, NCFlag},
5659 {0xfffffffd, NCFlag, 0xfffffffe, NCFlag},
5660 {0x80000000, NCFlag, 0x80000001, NCFlag},
5661 {0x7fffffff, CVFlag, 0x80000000, NCFlag},
5662 {0x7ffffffe, CFlag, 0x7fffffff, CFlag},
5663 {0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
5664 {0x00000000, ZCFlag, 0x00000001, CFlag},
5665 {0xffffffff, NFlag, 0x00000000, ZCFlag}}};
5666
5667 for (size_t left = 0; left < input_count; left++) {
5668 for (size_t right = 0; right < input_count; right++) {
5669 const Expected& expected = expected_adcs_w[left][right];
5670 AdcsSbcsHelper(&MacroAssembler::Adcs,
5671 inputs[left],
5672 inputs[right],
5673 0,
5674 expected.carry0_result,
5675 expected.carry0_flags);
5676 AdcsSbcsHelper(&MacroAssembler::Adcs,
5677 inputs[left],
5678 inputs[right],
5679 1,
5680 expected.carry1_result,
5681 expected.carry1_flags);
5682 }
5683 }
5684
5685 for (size_t left = 0; left < input_count; left++) {
5686 for (size_t right = 0; right < input_count; right++) {
5687 const Expected& expected = expected_sbcs_w[left][right];
5688 AdcsSbcsHelper(&MacroAssembler::Sbcs,
5689 inputs[left],
5690 inputs[right],
5691 0,
5692 expected.carry0_result,
5693 expected.carry0_flags);
5694 AdcsSbcsHelper(&MacroAssembler::Sbcs,
5695 inputs[left],
5696 inputs[right],
5697 1,
5698 expected.carry1_result,
5699 expected.carry1_flags);
5700 }
5701 }
5702 }
5703
5704
TEST(adc_sbc_shift)5705 TEST(adc_sbc_shift) {
5706 SETUP();
5707
5708 START();
5709 __ Mov(x0, 0);
5710 __ Mov(x1, 1);
5711 __ Mov(x2, 0x0123456789abcdef);
5712 __ Mov(x3, 0xfedcba9876543210);
5713 __ Mov(x4, 0xffffffffffffffff);
5714
5715 // Clear the C flag.
5716 __ Adds(x0, x0, Operand(0));
5717
5718 __ Adc(x5, x2, Operand(x3));
5719 __ Adc(x6, x0, Operand(x1, LSL, 60));
5720 __ Sbc(x7, x4, Operand(x3, LSR, 4));
5721 __ Adc(x8, x2, Operand(x3, ASR, 4));
5722 __ Adc(x9, x2, Operand(x3, ROR, 8));
5723
5724 __ Adc(w10, w2, Operand(w3));
5725 __ Adc(w11, w0, Operand(w1, LSL, 30));
5726 __ Sbc(w12, w4, Operand(w3, LSR, 4));
5727 __ Adc(w13, w2, Operand(w3, ASR, 4));
5728 __ Adc(w14, w2, Operand(w3, ROR, 8));
5729
5730 // Set the C flag.
5731 __ Cmp(w0, Operand(w0));
5732
5733 __ Adc(x18, x2, Operand(x3));
5734 __ Adc(x19, x0, Operand(x1, LSL, 60));
5735 __ Sbc(x20, x4, Operand(x3, LSR, 4));
5736 __ Adc(x21, x2, Operand(x3, ASR, 4));
5737 __ Adc(x22, x2, Operand(x3, ROR, 8));
5738
5739 __ Adc(w23, w2, Operand(w3));
5740 __ Adc(w24, w0, Operand(w1, LSL, 30));
5741 __ Sbc(w25, w4, Operand(w3, LSR, 4));
5742 __ Adc(w26, w2, Operand(w3, ASR, 4));
5743 __ Adc(w27, w2, Operand(w3, ROR, 8));
5744 END();
5745
5746 if (CAN_RUN()) {
5747 RUN();
5748
5749 ASSERT_EQUAL_64(0xffffffffffffffff, x5);
5750 ASSERT_EQUAL_64(INT64_C(1) << 60, x6);
5751 ASSERT_EQUAL_64(0xf0123456789abcdd, x7);
5752 ASSERT_EQUAL_64(0x0111111111111110, x8);
5753 ASSERT_EQUAL_64(0x1222222222222221, x9);
5754
5755 ASSERT_EQUAL_32(0xffffffff, w10);
5756 ASSERT_EQUAL_32(INT32_C(1) << 30, w11);
5757 ASSERT_EQUAL_32(0xf89abcdd, w12);
5758 ASSERT_EQUAL_32(0x91111110, w13);
5759 ASSERT_EQUAL_32(0x9a222221, w14);
5760
5761 ASSERT_EQUAL_64(0xffffffffffffffff + 1, x18);
5762 ASSERT_EQUAL_64((INT64_C(1) << 60) + 1, x19);
5763 ASSERT_EQUAL_64(0xf0123456789abcdd + 1, x20);
5764 ASSERT_EQUAL_64(0x0111111111111110 + 1, x21);
5765 ASSERT_EQUAL_64(0x1222222222222221 + 1, x22);
5766
5767 ASSERT_EQUAL_32(0xffffffff + 1, w23);
5768 ASSERT_EQUAL_32((INT32_C(1) << 30) + 1, w24);
5769 ASSERT_EQUAL_32(0xf89abcdd + 1, w25);
5770 ASSERT_EQUAL_32(0x91111110 + 1, w26);
5771 ASSERT_EQUAL_32(0x9a222221 + 1, w27);
5772 }
5773 }
5774
5775
TEST(adc_sbc_extend)5776 TEST(adc_sbc_extend) {
5777 SETUP();
5778
5779 START();
5780 // Clear the C flag.
5781 __ Adds(x0, x0, Operand(0));
5782
5783 __ Mov(x0, 0);
5784 __ Mov(x1, 1);
5785 __ Mov(x2, 0x0123456789abcdef);
5786
5787 __ Adc(x10, x1, Operand(w2, UXTB, 1));
5788 __ Adc(x11, x1, Operand(x2, SXTH, 2));
5789 __ Sbc(x12, x1, Operand(w2, UXTW, 4));
5790 __ Adc(x13, x1, Operand(x2, UXTX, 4));
5791
5792 __ Adc(w14, w1, Operand(w2, UXTB, 1));
5793 __ Adc(w15, w1, Operand(w2, SXTH, 2));
5794 __ Adc(w9, w1, Operand(w2, UXTW, 4));
5795
5796 // Set the C flag.
5797 __ Cmp(w0, Operand(w0));
5798
5799 __ Adc(x20, x1, Operand(w2, UXTB, 1));
5800 __ Adc(x21, x1, Operand(x2, SXTH, 2));
5801 __ Sbc(x22, x1, Operand(w2, UXTW, 4));
5802 __ Adc(x23, x1, Operand(x2, UXTX, 4));
5803
5804 __ Adc(w24, w1, Operand(w2, UXTB, 1));
5805 __ Adc(w25, w1, Operand(w2, SXTH, 2));
5806 __ Adc(w26, w1, Operand(w2, UXTW, 4));
5807 END();
5808
5809 if (CAN_RUN()) {
5810 RUN();
5811
5812 ASSERT_EQUAL_64(0x1df, x10);
5813 ASSERT_EQUAL_64(0xffffffffffff37bd, x11);
5814 ASSERT_EQUAL_64(0xfffffff765432110, x12);
5815 ASSERT_EQUAL_64(0x123456789abcdef1, x13);
5816
5817 ASSERT_EQUAL_32(0x1df, w14);
5818 ASSERT_EQUAL_32(0xffff37bd, w15);
5819 ASSERT_EQUAL_32(0x9abcdef1, w9);
5820
5821 ASSERT_EQUAL_64(0x1df + 1, x20);
5822 ASSERT_EQUAL_64(0xffffffffffff37bd + 1, x21);
5823 ASSERT_EQUAL_64(0xfffffff765432110 + 1, x22);
5824 ASSERT_EQUAL_64(0x123456789abcdef1 + 1, x23);
5825
5826 ASSERT_EQUAL_32(0x1df + 1, w24);
5827 ASSERT_EQUAL_32(0xffff37bd + 1, w25);
5828 ASSERT_EQUAL_32(0x9abcdef1 + 1, w26);
5829 }
5830
5831 // Check that adc correctly sets the condition flags.
5832 START();
5833 __ Mov(x0, 0xff);
5834 __ Mov(x1, 0xffffffffffffffff);
5835 // Clear the C flag.
5836 __ Adds(x0, x0, Operand(0));
5837 __ Adcs(x10, x0, Operand(x1, SXTX, 1));
5838 END();
5839
5840 if (CAN_RUN()) {
5841 RUN();
5842
5843 ASSERT_EQUAL_NZCV(CFlag);
5844 }
5845
5846 START();
5847 __ Mov(x0, 0x7fffffffffffffff);
5848 __ Mov(x1, 1);
5849 // Clear the C flag.
5850 __ Adds(x0, x0, Operand(0));
5851 __ Adcs(x10, x0, Operand(x1, UXTB, 2));
5852 END();
5853
5854 if (CAN_RUN()) {
5855 RUN();
5856
5857 ASSERT_EQUAL_NZCV(NVFlag);
5858 }
5859
5860 START();
5861 __ Mov(x0, 0x7fffffffffffffff);
5862 // Clear the C flag.
5863 __ Adds(x0, x0, Operand(0));
5864 __ Adcs(x10, x0, Operand(1));
5865 END();
5866
5867 if (CAN_RUN()) {
5868 RUN();
5869
5870 ASSERT_EQUAL_NZCV(NVFlag);
5871 }
5872 }
5873
5874
TEST(adc_sbc_wide_imm)5875 TEST(adc_sbc_wide_imm) {
5876 SETUP();
5877
5878 START();
5879 __ Mov(x0, 0);
5880
5881 // Clear the C flag.
5882 __ Adds(x0, x0, Operand(0));
5883
5884 __ Adc(x7, x0, Operand(0x1234567890abcdef));
5885 __ Adc(w8, w0, Operand(0xffffffff));
5886 __ Sbc(x9, x0, Operand(0x1234567890abcdef));
5887 __ Sbc(w10, w0, Operand(0xffffffff));
5888 __ Ngc(x11, Operand(0xffffffff00000000));
5889 __ Ngc(w12, Operand(0xffff0000));
5890
5891 // Set the C flag.
5892 __ Cmp(w0, Operand(w0));
5893
5894 __ Adc(x18, x0, Operand(0x1234567890abcdef));
5895 __ Adc(w19, w0, Operand(0xffffffff));
5896 __ Sbc(x20, x0, Operand(0x1234567890abcdef));
5897 __ Sbc(w21, w0, Operand(0xffffffff));
5898 __ Ngc(x22, Operand(0xffffffff00000000));
5899 __ Ngc(w23, Operand(0xffff0000));
5900 END();
5901
5902 if (CAN_RUN()) {
5903 RUN();
5904
5905 ASSERT_EQUAL_64(0x1234567890abcdef, x7);
5906 ASSERT_EQUAL_64(0xffffffff, x8);
5907 ASSERT_EQUAL_64(0xedcba9876f543210, x9);
5908 ASSERT_EQUAL_64(0, x10);
5909 ASSERT_EQUAL_64(0xffffffff, x11);
5910 ASSERT_EQUAL_64(0xffff, x12);
5911
5912 ASSERT_EQUAL_64(0x1234567890abcdef + 1, x18);
5913 ASSERT_EQUAL_64(0, x19);
5914 ASSERT_EQUAL_64(0xedcba9876f543211, x20);
5915 ASSERT_EQUAL_64(1, x21);
5916 ASSERT_EQUAL_64(0x0000000100000000, x22);
5917 ASSERT_EQUAL_64(0x0000000000010000, x23);
5918 }
5919 }
5920
5921
TEST(rmif)5922 TEST(rmif) {
5923 SETUP_WITH_FEATURES(CPUFeatures::kFlagM);
5924
5925 START();
5926 __ Mov(x0, 0x0123456789abcdef);
5927
5928 // Clear bits of `rmif` masks leave NZCV unmodified, so we need to initialise
5929 // it to a known state to make the test reproducible.
5930 __ Msr(NZCV, x0);
5931
5932 // Set NZCV to 0b1011 (0xb)
5933 __ Rmif(x0, 0, NCVFlag);
5934 __ Mrs(x1, NZCV);
5935
5936 // Set NZCV to 0b0111 (0x7)
5937 __ Rmif(x0, 6, NZCVFlag);
5938 __ Mrs(x2, NZCV);
5939
5940 // Set Z to 0, NZCV = 0b0011 (0x3)
5941 __ Rmif(x0, 60, ZFlag);
5942 __ Mrs(x3, NZCV);
5943
5944 // Set N to 1 and C to 0, NZCV = 0b1001 (0x9)
5945 __ Rmif(x0, 62, NCFlag);
5946 __ Mrs(x4, NZCV);
5947
5948 // No change to NZCV
5949 __ Rmif(x0, 0, NoFlag);
5950 __ Mrs(x5, NZCV);
5951 END();
5952
5953 if (CAN_RUN()) {
5954 RUN();
5955 ASSERT_EQUAL_32(NCVFlag, w1);
5956 ASSERT_EQUAL_32(ZCVFlag, w2);
5957 ASSERT_EQUAL_32(CVFlag, w3);
5958 ASSERT_EQUAL_32(NVFlag, w4);
5959 ASSERT_EQUAL_32(NVFlag, w5);
5960 }
5961 }
5962
5963
TEST(setf8_setf16)5964 TEST(setf8_setf16) {
5965 SETUP_WITH_FEATURES(CPUFeatures::kFlagM);
5966
5967 START();
5968 __ Mov(x0, 0x0);
5969 __ Mov(x1, 0x1);
5970 __ Mov(x2, 0xff);
5971 __ Mov(x3, 0x100);
5972 __ Mov(x4, 0x101);
5973 __ Mov(x5, 0xffff);
5974 __ Mov(x6, 0x10000);
5975 __ Mov(x7, 0x10001);
5976 __ Mov(x8, 0xfffffffff);
5977
5978 // These instruction don't modify 'C', so give it a consistent value.
5979 __ Ands(xzr, xzr, 0);
5980
5981 __ Setf8(w0);
5982 __ Mrs(x9, NZCV);
5983 __ Setf8(w1);
5984 __ Mrs(x10, NZCV);
5985 __ Setf8(w2);
5986 __ Mrs(x11, NZCV);
5987 __ Setf8(w3);
5988 __ Mrs(x12, NZCV);
5989 __ Setf8(w4);
5990 __ Mrs(x13, NZCV);
5991 __ Setf8(w8);
5992 __ Mrs(x14, NZCV);
5993
5994 __ Setf16(w0);
5995 __ Mrs(x15, NZCV);
5996 __ Setf16(w1);
5997 __ Mrs(x16, NZCV);
5998 __ Setf16(w5);
5999 __ Mrs(x17, NZCV);
6000 __ Setf16(w6);
6001 __ Mrs(x18, NZCV);
6002 __ Setf16(w7);
6003 __ Mrs(x19, NZCV);
6004 __ Setf16(w8);
6005 __ Mrs(x20, NZCV);
6006 END();
6007
6008 if (CAN_RUN()) {
6009 RUN();
6010
6011 ASSERT_EQUAL_32(ZFlag, w9); // Zero
6012 ASSERT_EQUAL_32(NoFlag, w10); // Regular int8
6013 ASSERT_EQUAL_32(NVFlag, w11); // Negative but not sign-extended (overflow)
6014 ASSERT_EQUAL_32(ZVFlag, w12); // Overflow with zero remainder
6015 ASSERT_EQUAL_32(VFlag, w13); // Overflow with non-zero remainder
6016 ASSERT_EQUAL_32(NFlag, w14); // Negative and sign-extended
6017
6018 ASSERT_EQUAL_32(ZFlag, w15); // Zero
6019 ASSERT_EQUAL_32(NoFlag, w16); // Regular int16
6020 ASSERT_EQUAL_32(NVFlag, w17); // Negative but not sign-extended (overflow)
6021 ASSERT_EQUAL_32(ZVFlag, w18); // Overflow with zero remainder
6022 ASSERT_EQUAL_32(VFlag, w19); // Overflow with non-zero remainder
6023 ASSERT_EQUAL_32(NFlag, w20); // Negative and sign-extended
6024 }
6025 }
6026
6027
TEST(flags)6028 TEST(flags) {
6029 SETUP();
6030
6031 START();
6032 __ Mov(x0, 0);
6033 __ Mov(x1, 0x1111111111111111);
6034 __ Neg(x10, Operand(x0));
6035 __ Neg(x11, Operand(x1));
6036 __ Neg(w12, Operand(w1));
6037 // Clear the C flag.
6038 __ Adds(x0, x0, Operand(0));
6039 __ Ngc(x13, Operand(x0));
6040 // Set the C flag.
6041 __ Cmp(x0, Operand(x0));
6042 __ Ngc(w14, Operand(w0));
6043 END();
6044
6045 if (CAN_RUN()) {
6046 RUN();
6047
6048 ASSERT_EQUAL_64(0, x10);
6049 ASSERT_EQUAL_64(-0x1111111111111111, x11);
6050 ASSERT_EQUAL_32(-0x11111111, w12);
6051 ASSERT_EQUAL_64(-1, x13);
6052 ASSERT_EQUAL_32(0, w14);
6053 }
6054
6055 START();
6056 __ Mov(x0, 0);
6057 __ Cmp(x0, Operand(x0));
6058 END();
6059
6060 if (CAN_RUN()) {
6061 RUN();
6062
6063 ASSERT_EQUAL_NZCV(ZCFlag);
6064 }
6065
6066 START();
6067 __ Mov(w0, 0);
6068 __ Cmp(w0, Operand(w0));
6069 END();
6070
6071 if (CAN_RUN()) {
6072 RUN();
6073
6074 ASSERT_EQUAL_NZCV(ZCFlag);
6075 }
6076
6077 START();
6078 __ Mov(x0, 0);
6079 __ Mov(x1, 0x1111111111111111);
6080 __ Cmp(x0, Operand(x1));
6081 END();
6082
6083 if (CAN_RUN()) {
6084 RUN();
6085
6086 ASSERT_EQUAL_NZCV(NFlag);
6087 }
6088
6089 START();
6090 __ Mov(w0, 0);
6091 __ Mov(w1, 0x11111111);
6092 __ Cmp(w0, Operand(w1));
6093 END();
6094
6095 if (CAN_RUN()) {
6096 RUN();
6097
6098 ASSERT_EQUAL_NZCV(NFlag);
6099 }
6100
6101 START();
6102 __ Mov(x1, 0x1111111111111111);
6103 __ Cmp(x1, Operand(0));
6104 END();
6105
6106 if (CAN_RUN()) {
6107 RUN();
6108
6109 ASSERT_EQUAL_NZCV(CFlag);
6110 }
6111
6112 START();
6113 __ Mov(w1, 0x11111111);
6114 __ Cmp(w1, Operand(0));
6115 END();
6116
6117 if (CAN_RUN()) {
6118 RUN();
6119
6120 ASSERT_EQUAL_NZCV(CFlag);
6121 }
6122
6123 START();
6124 __ Mov(x0, 1);
6125 __ Mov(x1, 0x7fffffffffffffff);
6126 __ Cmn(x1, Operand(x0));
6127 END();
6128
6129 if (CAN_RUN()) {
6130 RUN();
6131
6132 ASSERT_EQUAL_NZCV(NVFlag);
6133 }
6134
6135 START();
6136 __ Mov(w0, 1);
6137 __ Mov(w1, 0x7fffffff);
6138 __ Cmn(w1, Operand(w0));
6139 END();
6140
6141 if (CAN_RUN()) {
6142 RUN();
6143
6144 ASSERT_EQUAL_NZCV(NVFlag);
6145 }
6146
6147 START();
6148 __ Mov(x0, 1);
6149 __ Mov(x1, 0xffffffffffffffff);
6150 __ Cmn(x1, Operand(x0));
6151 END();
6152
6153 if (CAN_RUN()) {
6154 RUN();
6155
6156 ASSERT_EQUAL_NZCV(ZCFlag);
6157 }
6158
6159 START();
6160 __ Mov(w0, 1);
6161 __ Mov(w1, 0xffffffff);
6162 __ Cmn(w1, Operand(w0));
6163 END();
6164
6165 if (CAN_RUN()) {
6166 RUN();
6167
6168 ASSERT_EQUAL_NZCV(ZCFlag);
6169 }
6170
6171 START();
6172 __ Mov(w0, 0);
6173 __ Mov(w1, 1);
6174 // Clear the C flag.
6175 __ Adds(w0, w0, Operand(0));
6176 __ Ngcs(w0, Operand(w1));
6177 END();
6178
6179 if (CAN_RUN()) {
6180 RUN();
6181
6182 ASSERT_EQUAL_NZCV(NFlag);
6183 }
6184
6185 START();
6186 __ Mov(w0, 0);
6187 __ Mov(w1, 0);
6188 // Set the C flag.
6189 __ Cmp(w0, Operand(w0));
6190 __ Ngcs(w0, Operand(w1));
6191 END();
6192
6193 if (CAN_RUN()) {
6194 RUN();
6195
6196 ASSERT_EQUAL_NZCV(ZCFlag);
6197 }
6198 }
6199
6200
TEST(cmp_shift)6201 TEST(cmp_shift) {
6202 SETUP();
6203
6204 START();
6205 __ Mov(x18, 0xf0000000);
6206 __ Mov(x19, 0xf000000010000000);
6207 __ Mov(x20, 0xf0000000f0000000);
6208 __ Mov(x21, 0x7800000078000000);
6209 __ Mov(x22, 0x3c0000003c000000);
6210 __ Mov(x23, 0x8000000780000000);
6211 __ Mov(x24, 0x0000000f00000000);
6212 __ Mov(x25, 0x00000003c0000000);
6213 __ Mov(x26, 0x8000000780000000);
6214 __ Mov(x27, 0xc0000003);
6215
6216 __ Cmp(w20, Operand(w21, LSL, 1));
6217 __ Mrs(x0, NZCV);
6218
6219 __ Cmp(x20, Operand(x22, LSL, 2));
6220 __ Mrs(x1, NZCV);
6221
6222 __ Cmp(w19, Operand(w23, LSR, 3));
6223 __ Mrs(x2, NZCV);
6224
6225 __ Cmp(x18, Operand(x24, LSR, 4));
6226 __ Mrs(x3, NZCV);
6227
6228 __ Cmp(w20, Operand(w25, ASR, 2));
6229 __ Mrs(x4, NZCV);
6230
6231 __ Cmp(x20, Operand(x26, ASR, 3));
6232 __ Mrs(x5, NZCV);
6233
6234 __ Cmp(w27, Operand(w22, ROR, 28));
6235 __ Mrs(x6, NZCV);
6236
6237 __ Cmp(x20, Operand(x21, ROR, 31));
6238 __ Mrs(x7, NZCV);
6239 END();
6240
6241 if (CAN_RUN()) {
6242 RUN();
6243
6244 ASSERT_EQUAL_32(ZCFlag, w0);
6245 ASSERT_EQUAL_32(ZCFlag, w1);
6246 ASSERT_EQUAL_32(ZCFlag, w2);
6247 ASSERT_EQUAL_32(ZCFlag, w3);
6248 ASSERT_EQUAL_32(ZCFlag, w4);
6249 ASSERT_EQUAL_32(ZCFlag, w5);
6250 ASSERT_EQUAL_32(ZCFlag, w6);
6251 ASSERT_EQUAL_32(ZCFlag, w7);
6252 }
6253 }
6254
6255
TEST(cmp_extend)6256 TEST(cmp_extend) {
6257 SETUP();
6258
6259 START();
6260 __ Mov(w20, 0x2);
6261 __ Mov(w21, 0x1);
6262 __ Mov(x22, 0xffffffffffffffff);
6263 __ Mov(x23, 0xff);
6264 __ Mov(x24, 0xfffffffffffffffe);
6265 __ Mov(x25, 0xffff);
6266 __ Mov(x26, 0xffffffff);
6267
6268 __ Cmp(w20, Operand(w21, LSL, 1));
6269 __ Mrs(x0, NZCV);
6270
6271 __ Cmp(x22, Operand(x23, SXTB, 0));
6272 __ Mrs(x1, NZCV);
6273
6274 __ Cmp(x24, Operand(x23, SXTB, 1));
6275 __ Mrs(x2, NZCV);
6276
6277 __ Cmp(x24, Operand(x23, UXTB, 1));
6278 __ Mrs(x3, NZCV);
6279
6280 __ Cmp(w22, Operand(w25, UXTH));
6281 __ Mrs(x4, NZCV);
6282
6283 __ Cmp(x22, Operand(x25, SXTH));
6284 __ Mrs(x5, NZCV);
6285
6286 __ Cmp(x22, Operand(x26, UXTW));
6287 __ Mrs(x6, NZCV);
6288
6289 __ Cmp(x24, Operand(x26, SXTW, 1));
6290 __ Mrs(x7, NZCV);
6291 END();
6292
6293 if (CAN_RUN()) {
6294 RUN();
6295
6296 ASSERT_EQUAL_32(ZCFlag, w0);
6297 ASSERT_EQUAL_32(ZCFlag, w1);
6298 ASSERT_EQUAL_32(ZCFlag, w2);
6299 ASSERT_EQUAL_32(NCFlag, w3);
6300 ASSERT_EQUAL_32(NCFlag, w4);
6301 ASSERT_EQUAL_32(ZCFlag, w5);
6302 ASSERT_EQUAL_32(NCFlag, w6);
6303 ASSERT_EQUAL_32(ZCFlag, w7);
6304 }
6305 }
6306
6307
TEST(ccmp)6308 TEST(ccmp) {
6309 SETUP();
6310
6311 START();
6312 __ Mov(w16, 0);
6313 __ Mov(w17, 1);
6314 __ Cmp(w16, w16);
6315 __ Ccmp(w16, w17, NCFlag, eq);
6316 __ Mrs(x0, NZCV);
6317
6318 __ Cmp(w16, w16);
6319 __ Ccmp(w16, w17, NCFlag, ne);
6320 __ Mrs(x1, NZCV);
6321
6322 __ Cmp(x16, x16);
6323 __ Ccmn(x16, 2, NZCVFlag, eq);
6324 __ Mrs(x2, NZCV);
6325
6326 __ Cmp(x16, x16);
6327 __ Ccmn(x16, 2, NZCVFlag, ne);
6328 __ Mrs(x3, NZCV);
6329
6330 // The MacroAssembler does not allow al as a condition.
6331 {
6332 ExactAssemblyScope scope(&masm, kInstructionSize);
6333 __ ccmp(x16, x16, NZCVFlag, al);
6334 }
6335 __ Mrs(x4, NZCV);
6336
6337 // The MacroAssembler does not allow nv as a condition.
6338 {
6339 ExactAssemblyScope scope(&masm, kInstructionSize);
6340 __ ccmp(x16, x16, NZCVFlag, nv);
6341 }
6342 __ Mrs(x5, NZCV);
6343
6344 END();
6345
6346 if (CAN_RUN()) {
6347 RUN();
6348
6349 ASSERT_EQUAL_32(NFlag, w0);
6350 ASSERT_EQUAL_32(NCFlag, w1);
6351 ASSERT_EQUAL_32(NoFlag, w2);
6352 ASSERT_EQUAL_32(NZCVFlag, w3);
6353 ASSERT_EQUAL_32(ZCFlag, w4);
6354 ASSERT_EQUAL_32(ZCFlag, w5);
6355 }
6356 }
6357
6358
TEST(ccmp_wide_imm)6359 TEST(ccmp_wide_imm) {
6360 SETUP();
6361
6362 START();
6363 __ Mov(w20, 0);
6364
6365 __ Cmp(w20, Operand(w20));
6366 __ Ccmp(w20, Operand(0x12345678), NZCVFlag, eq);
6367 __ Mrs(x0, NZCV);
6368
6369 __ Cmp(w20, Operand(w20));
6370 __ Ccmp(x20, Operand(0xffffffffffffffff), NZCVFlag, eq);
6371 __ Mrs(x1, NZCV);
6372 END();
6373
6374 if (CAN_RUN()) {
6375 RUN();
6376
6377 ASSERT_EQUAL_32(NFlag, w0);
6378 ASSERT_EQUAL_32(NoFlag, w1);
6379 }
6380 }
6381
6382
TEST(ccmp_shift_extend)6383 TEST(ccmp_shift_extend) {
6384 SETUP();
6385
6386 START();
6387 __ Mov(w20, 0x2);
6388 __ Mov(w21, 0x1);
6389 __ Mov(x22, 0xffffffffffffffff);
6390 __ Mov(x23, 0xff);
6391 __ Mov(x24, 0xfffffffffffffffe);
6392
6393 __ Cmp(w20, Operand(w20));
6394 __ Ccmp(w20, Operand(w21, LSL, 1), NZCVFlag, eq);
6395 __ Mrs(x0, NZCV);
6396
6397 __ Cmp(w20, Operand(w20));
6398 __ Ccmp(x22, Operand(x23, SXTB, 0), NZCVFlag, eq);
6399 __ Mrs(x1, NZCV);
6400
6401 __ Cmp(w20, Operand(w20));
6402 __ Ccmp(x24, Operand(x23, SXTB, 1), NZCVFlag, eq);
6403 __ Mrs(x2, NZCV);
6404
6405 __ Cmp(w20, Operand(w20));
6406 __ Ccmp(x24, Operand(x23, UXTB, 1), NZCVFlag, eq);
6407 __ Mrs(x3, NZCV);
6408
6409 __ Cmp(w20, Operand(w20));
6410 __ Ccmp(x24, Operand(x23, UXTB, 1), NZCVFlag, ne);
6411 __ Mrs(x4, NZCV);
6412 END();
6413
6414 if (CAN_RUN()) {
6415 RUN();
6416
6417 ASSERT_EQUAL_32(ZCFlag, w0);
6418 ASSERT_EQUAL_32(ZCFlag, w1);
6419 ASSERT_EQUAL_32(ZCFlag, w2);
6420 ASSERT_EQUAL_32(NCFlag, w3);
6421 ASSERT_EQUAL_32(NZCVFlag, w4);
6422 }
6423 }
6424
6425
TEST(csel_reg)6426 TEST(csel_reg) {
6427 SETUP();
6428
6429 START();
6430 __ Mov(x16, 0);
6431 __ Mov(x24, 0x0000000f0000000f);
6432 __ Mov(x25, 0x0000001f0000001f);
6433
6434 __ Cmp(w16, Operand(0));
6435 __ Csel(w0, w24, w25, eq);
6436 __ Csel(w1, w24, w25, ne);
6437 __ Csinc(w2, w24, w25, mi);
6438 __ Csinc(w3, w24, w25, pl);
6439
6440 // The MacroAssembler does not allow al or nv as a condition.
6441 {
6442 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
6443 __ csel(w13, w24, w25, al);
6444 __ csel(x14, x24, x25, nv);
6445 }
6446
6447 __ Cmp(x16, Operand(1));
6448 __ Csinv(x4, x24, x25, gt);
6449 __ Csinv(x5, x24, x25, le);
6450 __ Csneg(x6, x24, x25, hs);
6451 __ Csneg(x7, x24, x25, lo);
6452
6453 __ Cset(w8, ne);
6454 __ Csetm(w9, ne);
6455 __ Cinc(x10, x25, ne);
6456 __ Cinv(x11, x24, ne);
6457 __ Cneg(x12, x24, ne);
6458
6459 // The MacroAssembler does not allow al or nv as a condition.
6460 {
6461 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
6462 __ csel(w15, w24, w25, al);
6463 __ csel(x17, x24, x25, nv);
6464 }
6465
6466 END();
6467
6468 if (CAN_RUN()) {
6469 RUN();
6470
6471 ASSERT_EQUAL_64(0x0000000f, x0);
6472 ASSERT_EQUAL_64(0x0000001f, x1);
6473 ASSERT_EQUAL_64(0x00000020, x2);
6474 ASSERT_EQUAL_64(0x0000000f, x3);
6475 ASSERT_EQUAL_64(0xffffffe0ffffffe0, x4);
6476 ASSERT_EQUAL_64(0x0000000f0000000f, x5);
6477 ASSERT_EQUAL_64(0xffffffe0ffffffe1, x6);
6478 ASSERT_EQUAL_64(0x0000000f0000000f, x7);
6479 ASSERT_EQUAL_64(0x00000001, x8);
6480 ASSERT_EQUAL_64(0xffffffff, x9);
6481 ASSERT_EQUAL_64(0x0000001f00000020, x10);
6482 ASSERT_EQUAL_64(0xfffffff0fffffff0, x11);
6483 ASSERT_EQUAL_64(0xfffffff0fffffff1, x12);
6484 ASSERT_EQUAL_64(0x0000000f, x13);
6485 ASSERT_EQUAL_64(0x0000000f0000000f, x14);
6486 ASSERT_EQUAL_64(0x0000000f, x15);
6487 ASSERT_EQUAL_64(0x0000000f0000000f, x17);
6488 }
6489 }
6490
TEST(csel_zero)6491 TEST(csel_zero) {
6492 SETUP();
6493
6494 START();
6495
6496 __ Mov(x15, 0x0);
6497 __ Mov(x16, 0x0000001f0000002f);
6498
6499 // Check results when zero registers are used as inputs
6500 // for Csinc, Csinv and Csneg for both true and false conditions.
6501 __ Cmp(x15, 0);
6502 __ Csinc(x0, x16, xzr, eq);
6503 __ Csinc(x1, xzr, x16, eq);
6504 __ Cmp(x15, 1);
6505 __ Csinc(w2, w16, wzr, eq);
6506 __ Csinc(w3, wzr, w16, eq);
6507
6508 __ Csinc(x4, xzr, xzr, eq);
6509
6510 __ Cmp(x15, 0);
6511 __ Csinv(x5, x16, xzr, eq);
6512 __ Csinv(x6, xzr, x16, eq);
6513 __ Cmp(x15, 1);
6514 __ Csinv(w7, w16, wzr, eq);
6515 __ Csinv(w8, wzr, w16, eq);
6516
6517 __ Csinv(x9, xzr, xzr, eq);
6518
6519 __ Cmp(x15, 0);
6520 __ Csneg(x10, x16, xzr, eq);
6521 __ Csneg(x11, xzr, x16, eq);
6522 __ Cmp(x15, 1);
6523 __ Csneg(w12, w16, wzr, eq);
6524 __ Csneg(w13, wzr, w16, eq);
6525
6526 __ Csneg(x14, xzr, xzr, eq);
6527
6528 END();
6529
6530 if (CAN_RUN()) {
6531 RUN();
6532
6533 ASSERT_EQUAL_64(0x0000001f0000002f, x0);
6534 ASSERT_EQUAL_64(0x0, x1);
6535 ASSERT_EQUAL_32(0x1, w2);
6536 ASSERT_EQUAL_32(0x30, w3);
6537 ASSERT_EQUAL_64(0x1, x4);
6538 ASSERT_EQUAL_64(0x0000001f0000002f, x5);
6539 ASSERT_EQUAL_64(0x0, x6);
6540 ASSERT_EQUAL_32(0xffffffff, w7);
6541 ASSERT_EQUAL_32(0xffffffd0, w8);
6542 ASSERT_EQUAL_64(0xffffffffffffffff, x9);
6543 ASSERT_EQUAL_64(0x0000001f0000002f, x10);
6544 ASSERT_EQUAL_64(0x0, x11);
6545 ASSERT_EQUAL_32(0x0, w12);
6546 ASSERT_EQUAL_32(0xffffffd1, w13);
6547 ASSERT_EQUAL_64(0x0, x14);
6548 }
6549 }
6550
6551
TEST(csel_imm)6552 TEST(csel_imm) {
6553 SETUP();
6554
6555 int values[] = {-123, -2, -1, 0, 1, 2, 123};
6556 int n_values = sizeof(values) / sizeof(values[0]);
6557
6558 for (int i = 0; i < n_values; i++) {
6559 for (int j = 0; j < n_values; j++) {
6560 int left = values[i];
6561 int right = values[j];
6562
6563 START();
6564 __ Mov(x10, 0);
6565 __ Cmp(x10, 0);
6566 __ Csel(w0, left, right, eq);
6567 __ Csel(w1, left, right, ne);
6568 __ Csel(x2, left, right, eq);
6569 __ Csel(x3, left, right, ne);
6570
6571 END();
6572
6573 if (CAN_RUN()) {
6574 RUN();
6575
6576 ASSERT_EQUAL_32(left, w0);
6577 ASSERT_EQUAL_32(right, w1);
6578 ASSERT_EQUAL_64(left, x2);
6579 ASSERT_EQUAL_64(right, x3);
6580 }
6581 }
6582 }
6583 }
6584
6585
TEST(csel_mixed)6586 TEST(csel_mixed) {
6587 SETUP();
6588
6589 START();
6590 __ Mov(x18, 0);
6591 __ Mov(x19, 0x80000000);
6592 __ Mov(x20, 0x8000000000000000);
6593
6594 __ Cmp(x18, Operand(0));
6595 __ Csel(w0, w19, -2, ne);
6596 __ Csel(w1, w19, -1, ne);
6597 __ Csel(w2, w19, 0, ne);
6598 __ Csel(w3, w19, 1, ne);
6599 __ Csel(w4, w19, 2, ne);
6600 __ Csel(w5, w19, Operand(w19, ASR, 31), ne);
6601 __ Csel(w6, w19, Operand(w19, ROR, 1), ne);
6602 __ Csel(w7, w19, 3, eq);
6603
6604 __ Csel(x8, x20, -2, ne);
6605 __ Csel(x9, x20, -1, ne);
6606 __ Csel(x10, x20, 0, ne);
6607 __ Csel(x11, x20, 1, ne);
6608 __ Csel(x12, x20, 2, ne);
6609 __ Csel(x13, x20, Operand(x20, ASR, 63), ne);
6610 __ Csel(x14, x20, Operand(x20, ROR, 1), ne);
6611 __ Csel(x15, x20, 3, eq);
6612
6613 END();
6614
6615 if (CAN_RUN()) {
6616 RUN();
6617
6618 ASSERT_EQUAL_32(-2, w0);
6619 ASSERT_EQUAL_32(-1, w1);
6620 ASSERT_EQUAL_32(0, w2);
6621 ASSERT_EQUAL_32(1, w3);
6622 ASSERT_EQUAL_32(2, w4);
6623 ASSERT_EQUAL_32(-1, w5);
6624 ASSERT_EQUAL_32(0x40000000, w6);
6625 ASSERT_EQUAL_32(0x80000000, w7);
6626
6627 ASSERT_EQUAL_64(-2, x8);
6628 ASSERT_EQUAL_64(-1, x9);
6629 ASSERT_EQUAL_64(0, x10);
6630 ASSERT_EQUAL_64(1, x11);
6631 ASSERT_EQUAL_64(2, x12);
6632 ASSERT_EQUAL_64(-1, x13);
6633 ASSERT_EQUAL_64(0x4000000000000000, x14);
6634 ASSERT_EQUAL_64(0x8000000000000000, x15);
6635 }
6636 }
6637
6638
TEST(lslv)6639 TEST(lslv) {
6640 SETUP();
6641
6642 uint64_t value = 0x0123456789abcdef;
6643 int shift[] = {1, 3, 5, 9, 17, 33};
6644
6645 START();
6646 __ Mov(x0, value);
6647 __ Mov(w1, shift[0]);
6648 __ Mov(w2, shift[1]);
6649 __ Mov(w3, shift[2]);
6650 __ Mov(w4, shift[3]);
6651 __ Mov(w5, shift[4]);
6652 __ Mov(w6, shift[5]);
6653
6654 // The MacroAssembler does not allow zr as an argument.
6655 {
6656 ExactAssemblyScope scope(&masm, kInstructionSize);
6657 __ lslv(x0, x0, xzr);
6658 }
6659
6660 __ Lsl(x16, x0, x1);
6661 __ Lsl(x17, x0, x2);
6662 __ Lsl(x18, x0, x3);
6663 __ Lsl(x19, x0, x4);
6664 __ Lsl(x20, x0, x5);
6665 __ Lsl(x21, x0, x6);
6666
6667 __ Lsl(w22, w0, w1);
6668 __ Lsl(w23, w0, w2);
6669 __ Lsl(w24, w0, w3);
6670 __ Lsl(w25, w0, w4);
6671 __ Lsl(w26, w0, w5);
6672 __ Lsl(w27, w0, w6);
6673 END();
6674
6675 if (CAN_RUN()) {
6676 RUN();
6677
6678 ASSERT_EQUAL_64(value, x0);
6679 ASSERT_EQUAL_64(value << (shift[0] & 63), x16);
6680 ASSERT_EQUAL_64(value << (shift[1] & 63), x17);
6681 ASSERT_EQUAL_64(value << (shift[2] & 63), x18);
6682 ASSERT_EQUAL_64(value << (shift[3] & 63), x19);
6683 ASSERT_EQUAL_64(value << (shift[4] & 63), x20);
6684 ASSERT_EQUAL_64(value << (shift[5] & 63), x21);
6685 ASSERT_EQUAL_32(value << (shift[0] & 31), w22);
6686 ASSERT_EQUAL_32(value << (shift[1] & 31), w23);
6687 ASSERT_EQUAL_32(value << (shift[2] & 31), w24);
6688 ASSERT_EQUAL_32(value << (shift[3] & 31), w25);
6689 ASSERT_EQUAL_32(value << (shift[4] & 31), w26);
6690 ASSERT_EQUAL_32(value << (shift[5] & 31), w27);
6691 }
6692 }
6693
6694
TEST(lsrv)6695 TEST(lsrv) {
6696 SETUP();
6697
6698 uint64_t value = 0x0123456789abcdef;
6699 int shift[] = {1, 3, 5, 9, 17, 33};
6700
6701 START();
6702 __ Mov(x0, value);
6703 __ Mov(w1, shift[0]);
6704 __ Mov(w2, shift[1]);
6705 __ Mov(w3, shift[2]);
6706 __ Mov(w4, shift[3]);
6707 __ Mov(w5, shift[4]);
6708 __ Mov(w6, shift[5]);
6709
6710 // The MacroAssembler does not allow zr as an argument.
6711 {
6712 ExactAssemblyScope scope(&masm, kInstructionSize);
6713 __ lsrv(x0, x0, xzr);
6714 }
6715
6716 __ Lsr(x16, x0, x1);
6717 __ Lsr(x17, x0, x2);
6718 __ Lsr(x18, x0, x3);
6719 __ Lsr(x19, x0, x4);
6720 __ Lsr(x20, x0, x5);
6721 __ Lsr(x21, x0, x6);
6722
6723 __ Lsr(w22, w0, w1);
6724 __ Lsr(w23, w0, w2);
6725 __ Lsr(w24, w0, w3);
6726 __ Lsr(w25, w0, w4);
6727 __ Lsr(w26, w0, w5);
6728 __ Lsr(w27, w0, w6);
6729 END();
6730
6731 if (CAN_RUN()) {
6732 RUN();
6733
6734 ASSERT_EQUAL_64(value, x0);
6735 ASSERT_EQUAL_64(value >> (shift[0] & 63), x16);
6736 ASSERT_EQUAL_64(value >> (shift[1] & 63), x17);
6737 ASSERT_EQUAL_64(value >> (shift[2] & 63), x18);
6738 ASSERT_EQUAL_64(value >> (shift[3] & 63), x19);
6739 ASSERT_EQUAL_64(value >> (shift[4] & 63), x20);
6740 ASSERT_EQUAL_64(value >> (shift[5] & 63), x21);
6741
6742 value &= 0xffffffff;
6743 ASSERT_EQUAL_32(value >> (shift[0] & 31), w22);
6744 ASSERT_EQUAL_32(value >> (shift[1] & 31), w23);
6745 ASSERT_EQUAL_32(value >> (shift[2] & 31), w24);
6746 ASSERT_EQUAL_32(value >> (shift[3] & 31), w25);
6747 ASSERT_EQUAL_32(value >> (shift[4] & 31), w26);
6748 ASSERT_EQUAL_32(value >> (shift[5] & 31), w27);
6749 }
6750 }
6751
6752
TEST(asrv)6753 TEST(asrv) {
6754 SETUP();
6755
6756 int64_t value = 0xfedcba98fedcba98;
6757 int shift[] = {1, 3, 5, 9, 17, 33};
6758
6759 START();
6760 __ Mov(x0, value);
6761 __ Mov(w1, shift[0]);
6762 __ Mov(w2, shift[1]);
6763 __ Mov(w3, shift[2]);
6764 __ Mov(w4, shift[3]);
6765 __ Mov(w5, shift[4]);
6766 __ Mov(w6, shift[5]);
6767
6768 // The MacroAssembler does not allow zr as an argument.
6769 {
6770 ExactAssemblyScope scope(&masm, kInstructionSize);
6771 __ asrv(x0, x0, xzr);
6772 }
6773
6774 __ Asr(x16, x0, x1);
6775 __ Asr(x17, x0, x2);
6776 __ Asr(x18, x0, x3);
6777 __ Asr(x19, x0, x4);
6778 __ Asr(x20, x0, x5);
6779 __ Asr(x21, x0, x6);
6780
6781 __ Asr(w22, w0, w1);
6782 __ Asr(w23, w0, w2);
6783 __ Asr(w24, w0, w3);
6784 __ Asr(w25, w0, w4);
6785 __ Asr(w26, w0, w5);
6786 __ Asr(w27, w0, w6);
6787 END();
6788
6789 if (CAN_RUN()) {
6790 RUN();
6791
6792 ASSERT_EQUAL_64(value, x0);
6793 ASSERT_EQUAL_64(value >> (shift[0] & 63), x16);
6794 ASSERT_EQUAL_64(value >> (shift[1] & 63), x17);
6795 ASSERT_EQUAL_64(value >> (shift[2] & 63), x18);
6796 ASSERT_EQUAL_64(value >> (shift[3] & 63), x19);
6797 ASSERT_EQUAL_64(value >> (shift[4] & 63), x20);
6798 ASSERT_EQUAL_64(value >> (shift[5] & 63), x21);
6799
6800 int32_t value32 = static_cast<int32_t>(value & 0xffffffff);
6801 ASSERT_EQUAL_32(value32 >> (shift[0] & 31), w22);
6802 ASSERT_EQUAL_32(value32 >> (shift[1] & 31), w23);
6803 ASSERT_EQUAL_32(value32 >> (shift[2] & 31), w24);
6804 ASSERT_EQUAL_32(value32 >> (shift[3] & 31), w25);
6805 ASSERT_EQUAL_32(value32 >> (shift[4] & 31), w26);
6806 ASSERT_EQUAL_32(value32 >> (shift[5] & 31), w27);
6807 }
6808 }
6809
6810
TEST(rorv)6811 TEST(rorv) {
6812 SETUP();
6813
6814 uint64_t value = 0x0123456789abcdef;
6815 int shift[] = {4, 8, 12, 16, 24, 36};
6816
6817 START();
6818 __ Mov(x0, value);
6819 __ Mov(w1, shift[0]);
6820 __ Mov(w2, shift[1]);
6821 __ Mov(w3, shift[2]);
6822 __ Mov(w4, shift[3]);
6823 __ Mov(w5, shift[4]);
6824 __ Mov(w6, shift[5]);
6825
6826 // The MacroAssembler does not allow zr as an argument.
6827 {
6828 ExactAssemblyScope scope(&masm, kInstructionSize);
6829 __ rorv(x0, x0, xzr);
6830 }
6831
6832 __ Ror(x16, x0, x1);
6833 __ Ror(x17, x0, x2);
6834 __ Ror(x18, x0, x3);
6835 __ Ror(x19, x0, x4);
6836 __ Ror(x20, x0, x5);
6837 __ Ror(x21, x0, x6);
6838
6839 __ Ror(w22, w0, w1);
6840 __ Ror(w23, w0, w2);
6841 __ Ror(w24, w0, w3);
6842 __ Ror(w25, w0, w4);
6843 __ Ror(w26, w0, w5);
6844 __ Ror(w27, w0, w6);
6845 END();
6846
6847 if (CAN_RUN()) {
6848 RUN();
6849
6850 ASSERT_EQUAL_64(value, x0);
6851 ASSERT_EQUAL_64(0xf0123456789abcde, x16);
6852 ASSERT_EQUAL_64(0xef0123456789abcd, x17);
6853 ASSERT_EQUAL_64(0xdef0123456789abc, x18);
6854 ASSERT_EQUAL_64(0xcdef0123456789ab, x19);
6855 ASSERT_EQUAL_64(0xabcdef0123456789, x20);
6856 ASSERT_EQUAL_64(0x789abcdef0123456, x21);
6857 ASSERT_EQUAL_32(0xf89abcde, w22);
6858 ASSERT_EQUAL_32(0xef89abcd, w23);
6859 ASSERT_EQUAL_32(0xdef89abc, w24);
6860 ASSERT_EQUAL_32(0xcdef89ab, w25);
6861 ASSERT_EQUAL_32(0xabcdef89, w26);
6862 ASSERT_EQUAL_32(0xf89abcde, w27);
6863 }
6864 }
6865
6866
TEST(bfm)6867 TEST(bfm) {
6868 SETUP();
6869
6870 START();
6871 __ Mov(x1, 0x0123456789abcdef);
6872
6873 __ Mov(x10, 0x8888888888888888);
6874 __ Mov(x11, 0x8888888888888888);
6875 __ Mov(x12, 0x8888888888888888);
6876 __ Mov(x13, 0x8888888888888888);
6877 __ Mov(x14, 0xffffffffffffffff);
6878 __ Mov(w20, 0x88888888);
6879 __ Mov(w21, 0x88888888);
6880
6881 __ Bfm(x10, x1, 16, 31);
6882 __ Bfm(x11, x1, 32, 15);
6883
6884 __ Bfm(w20, w1, 16, 23);
6885 __ Bfm(w21, w1, 24, 15);
6886
6887 // Aliases.
6888 __ Bfi(x12, x1, 16, 8);
6889 __ Bfxil(x13, x1, 16, 8);
6890 __ Bfc(x14, 16, 8);
6891 END();
6892
6893 if (CAN_RUN()) {
6894 RUN();
6895
6896
6897 ASSERT_EQUAL_64(0x88888888888889ab, x10);
6898 ASSERT_EQUAL_64(0x8888cdef88888888, x11);
6899
6900 ASSERT_EQUAL_32(0x888888ab, w20);
6901 ASSERT_EQUAL_32(0x88cdef88, w21);
6902
6903 ASSERT_EQUAL_64(0x8888888888ef8888, x12);
6904 ASSERT_EQUAL_64(0x88888888888888ab, x13);
6905 ASSERT_EQUAL_64(0xffffffffff00ffff, x14);
6906 }
6907 }
6908
6909
TEST(sbfm)6910 TEST(sbfm) {
6911 SETUP();
6912
6913 START();
6914 __ Mov(x1, 0x0123456789abcdef);
6915 __ Mov(x2, 0xfedcba9876543210);
6916
6917 __ Sbfm(x10, x1, 16, 31);
6918 __ Sbfm(x11, x1, 32, 15);
6919 __ Sbfm(x12, x1, 32, 47);
6920 __ Sbfm(x13, x1, 48, 35);
6921
6922 __ Sbfm(w14, w1, 16, 23);
6923 __ Sbfm(w15, w1, 24, 15);
6924 __ Sbfm(w16, w2, 16, 23);
6925 __ Sbfm(w17, w2, 24, 15);
6926
6927 // Aliases.
6928 __ Asr(x18, x1, 32);
6929 __ Asr(x19, x2, 32);
6930 __ Sbfiz(x20, x1, 8, 16);
6931 __ Sbfiz(x21, x2, 8, 16);
6932 __ Sbfx(x22, x1, 8, 16);
6933 __ Sbfx(x23, x2, 8, 16);
6934 __ Sxtb(x24, w1);
6935 __ Sxtb(x25, x2);
6936 __ Sxth(x26, w1);
6937 __ Sxth(x27, x2);
6938 __ Sxtw(x28, w1);
6939 __ Sxtw(x29, x2);
6940 END();
6941
6942 if (CAN_RUN()) {
6943 RUN();
6944
6945
6946 ASSERT_EQUAL_64(0xffffffffffff89ab, x10);
6947 ASSERT_EQUAL_64(0xffffcdef00000000, x11);
6948 ASSERT_EQUAL_64(0x0000000000004567, x12);
6949 ASSERT_EQUAL_64(0x000789abcdef0000, x13);
6950
6951 ASSERT_EQUAL_32(0xffffffab, w14);
6952 ASSERT_EQUAL_32(0xffcdef00, w15);
6953 ASSERT_EQUAL_32(0x00000054, w16);
6954 ASSERT_EQUAL_32(0x00321000, w17);
6955
6956 ASSERT_EQUAL_64(0x0000000001234567, x18);
6957 ASSERT_EQUAL_64(0xfffffffffedcba98, x19);
6958 ASSERT_EQUAL_64(0xffffffffffcdef00, x20);
6959 ASSERT_EQUAL_64(0x0000000000321000, x21);
6960 ASSERT_EQUAL_64(0xffffffffffffabcd, x22);
6961 ASSERT_EQUAL_64(0x0000000000005432, x23);
6962 ASSERT_EQUAL_64(0xffffffffffffffef, x24);
6963 ASSERT_EQUAL_64(0x0000000000000010, x25);
6964 ASSERT_EQUAL_64(0xffffffffffffcdef, x26);
6965 ASSERT_EQUAL_64(0x0000000000003210, x27);
6966 ASSERT_EQUAL_64(0xffffffff89abcdef, x28);
6967 ASSERT_EQUAL_64(0x0000000076543210, x29);
6968 }
6969 }
6970
6971
TEST(ubfm)6972 TEST(ubfm) {
6973 SETUP();
6974
6975 START();
6976 __ Mov(x1, 0x0123456789abcdef);
6977 __ Mov(x2, 0xfedcba9876543210);
6978
6979 __ Mov(x10, 0x8888888888888888);
6980 __ Mov(x11, 0x8888888888888888);
6981
6982 __ Ubfm(x10, x1, 16, 31);
6983 __ Ubfm(x11, x1, 32, 15);
6984 __ Ubfm(x12, x1, 32, 47);
6985 __ Ubfm(x13, x1, 48, 35);
6986
6987 __ Ubfm(w25, w1, 16, 23);
6988 __ Ubfm(w26, w1, 24, 15);
6989 __ Ubfm(w27, w2, 16, 23);
6990 __ Ubfm(w28, w2, 24, 15);
6991
6992 // Aliases
6993 __ Lsl(x15, x1, 63);
6994 __ Lsl(x16, x1, 0);
6995 __ Lsr(x17, x1, 32);
6996 __ Ubfiz(x18, x1, 8, 16);
6997 __ Ubfx(x19, x1, 8, 16);
6998 __ Uxtb(x20, x1);
6999 __ Uxth(x21, x1);
7000 __ Uxtw(x22, x1);
7001 END();
7002
7003 if (CAN_RUN()) {
7004 RUN();
7005
7006 ASSERT_EQUAL_64(0x00000000000089ab, x10);
7007 ASSERT_EQUAL_64(0x0000cdef00000000, x11);
7008 ASSERT_EQUAL_64(0x0000000000004567, x12);
7009 ASSERT_EQUAL_64(0x000789abcdef0000, x13);
7010
7011 ASSERT_EQUAL_32(0x000000ab, w25);
7012 ASSERT_EQUAL_32(0x00cdef00, w26);
7013 ASSERT_EQUAL_32(0x00000054, w27);
7014 ASSERT_EQUAL_32(0x00321000, w28);
7015
7016 ASSERT_EQUAL_64(0x8000000000000000, x15);
7017 ASSERT_EQUAL_64(0x0123456789abcdef, x16);
7018 ASSERT_EQUAL_64(0x0000000001234567, x17);
7019 ASSERT_EQUAL_64(0x0000000000cdef00, x18);
7020 ASSERT_EQUAL_64(0x000000000000abcd, x19);
7021 ASSERT_EQUAL_64(0x00000000000000ef, x20);
7022 ASSERT_EQUAL_64(0x000000000000cdef, x21);
7023 ASSERT_EQUAL_64(0x0000000089abcdef, x22);
7024 }
7025 }
7026
7027
TEST(extr)7028 TEST(extr) {
7029 SETUP();
7030
7031 START();
7032 __ Mov(x1, 0x0123456789abcdef);
7033 __ Mov(x2, 0xfedcba9876543210);
7034
7035 __ Extr(w10, w1, w2, 0);
7036 __ Extr(w11, w1, w2, 1);
7037 __ Extr(x12, x2, x1, 2);
7038
7039 __ Ror(w13, w1, 0);
7040 __ Ror(w14, w2, 17);
7041 __ Ror(w15, w1, 31);
7042 __ Ror(x18, x2, 0);
7043 __ Ror(x19, x2, 1);
7044 __ Ror(x20, x1, 63);
7045 END();
7046
7047 if (CAN_RUN()) {
7048 RUN();
7049
7050 ASSERT_EQUAL_64(0x76543210, x10);
7051 ASSERT_EQUAL_64(0xbb2a1908, x11);
7052 ASSERT_EQUAL_64(0x0048d159e26af37b, x12);
7053 ASSERT_EQUAL_64(0x89abcdef, x13);
7054 ASSERT_EQUAL_64(0x19083b2a, x14);
7055 ASSERT_EQUAL_64(0x13579bdf, x15);
7056 ASSERT_EQUAL_64(0xfedcba9876543210, x18);
7057 ASSERT_EQUAL_64(0x7f6e5d4c3b2a1908, x19);
7058 ASSERT_EQUAL_64(0x02468acf13579bde, x20);
7059 }
7060 }
7061
7062
TEST(system_mrs)7063 TEST(system_mrs) {
7064 SETUP();
7065
7066 START();
7067 __ Mov(w0, 0);
7068 __ Mov(w1, 1);
7069 __ Mov(w2, 0x80000000);
7070
7071 // Set the Z and C flags.
7072 __ Cmp(w0, w0);
7073 __ Mrs(x3, NZCV);
7074
7075 // Set the N flag.
7076 __ Cmp(w0, w1);
7077 __ Mrs(x4, NZCV);
7078
7079 // Set the Z, C and V flags.
7080 __ Adds(w0, w2, w2);
7081 __ Mrs(x5, NZCV);
7082
7083 // Read the default FPCR.
7084 __ Mrs(x6, FPCR);
7085 END();
7086
7087 if (CAN_RUN()) {
7088 RUN();
7089
7090 // NZCV
7091 ASSERT_EQUAL_32(ZCFlag, w3);
7092 ASSERT_EQUAL_32(NFlag, w4);
7093 ASSERT_EQUAL_32(ZCVFlag, w5);
7094
7095 // FPCR
7096 // The default FPCR on Linux-based platforms is 0.
7097 ASSERT_EQUAL_32(0, w6);
7098 }
7099 }
7100
TEST(system_rng)7101 TEST(system_rng) {
7102 SETUP_WITH_FEATURES(CPUFeatures::kRNG);
7103
7104 START();
7105 // Random number.
7106 __ Mrs(x1, RNDR);
7107 // Assume that each generation is successful now.
7108 // TODO: Return failure occasionally.
7109 __ Mrs(x2, NZCV);
7110 __ Mrs(x3, RNDR);
7111 __ Mrs(x4, NZCV);
7112
7113 // Reseeded random number.
7114 __ Mrs(x5, RNDRRS);
7115 // Assume that each generation is successful now.
7116 // TODO: Return failure occasionally.
7117 __ Mrs(x6, NZCV);
7118 __ Mrs(x7, RNDRRS);
7119 __ Mrs(x8, NZCV);
7120 END();
7121
7122 if (CAN_RUN()) {
7123 RUN();
7124 // Random number generation series.
7125 // Check random numbers have been generated and aren't equal when reseed has
7126 // happened.
7127 // NOTE: With a different architectural implementation, there may be a
7128 // collison.
7129 // TODO: Return failure occasionally. Set ZFlag and return UNKNOWN value.
7130 ASSERT_NOT_EQUAL_64(x1, x3);
7131 ASSERT_EQUAL_64(NoFlag, x2);
7132 ASSERT_EQUAL_64(NoFlag, x4);
7133 ASSERT_NOT_EQUAL_64(x5, x7);
7134 ASSERT_EQUAL_64(NoFlag, x6);
7135 ASSERT_EQUAL_64(NoFlag, x8);
7136 }
7137 }
7138
TEST(cfinv)7139 TEST(cfinv) {
7140 SETUP_WITH_FEATURES(CPUFeatures::kFlagM);
7141
7142 START();
7143 __ Mov(w0, 1);
7144
7145 // Set the C flag.
7146 __ Cmp(w0, 0);
7147 __ Mrs(x1, NZCV);
7148
7149 // Invert the C flag.
7150 __ Cfinv();
7151 __ Mrs(x2, NZCV);
7152
7153 // Invert the C flag again.
7154 __ Cfinv();
7155 __ Mrs(x3, NZCV);
7156 END();
7157
7158 if (CAN_RUN()) {
7159 RUN();
7160
7161 ASSERT_EQUAL_32(CFlag, w1);
7162 ASSERT_EQUAL_32(NoFlag, w2);
7163 ASSERT_EQUAL_32(CFlag, w3);
7164 }
7165 }
7166
7167
TEST(axflag_xaflag)7168 TEST(axflag_xaflag) {
7169 // The AXFLAG and XAFLAG instructions are designed for converting the FP
7170 // conditional flags from Arm format to an alternate format efficiently.
7171 // There are only 4 cases which are relevant for this conversion but we test
7172 // the behaviour for all 16 cases anyway. The 4 important cases are labelled
7173 // below.
7174 StatusFlags expected_x[16] = {NoFlag,
7175 ZFlag,
7176 CFlag, // Greater than
7177 ZFlag, // Unordered
7178 ZFlag,
7179 ZFlag,
7180 ZCFlag, // Equal to
7181 ZFlag,
7182 NoFlag, // Less than
7183 ZFlag,
7184 CFlag,
7185 ZFlag,
7186 ZFlag,
7187 ZFlag,
7188 ZCFlag,
7189 ZFlag};
7190 StatusFlags expected_a[16] = {NFlag, // Less than
7191 NFlag,
7192 CFlag, // Greater than
7193 CFlag,
7194 CVFlag, // Unordered
7195 CVFlag,
7196 ZCFlag, // Equal to
7197 ZCFlag,
7198 NFlag,
7199 NFlag,
7200 CFlag,
7201 CFlag,
7202 CVFlag,
7203 CVFlag,
7204 ZCFlag,
7205 ZCFlag};
7206
7207 for (unsigned i = 0; i < 16; i++) {
7208 SETUP_WITH_FEATURES(CPUFeatures::kAXFlag);
7209
7210 START();
7211 __ Mov(x0, i << Flags_offset);
7212 __ Msr(NZCV, x0);
7213 __ Axflag();
7214 __ Mrs(x1, NZCV);
7215 __ Msr(NZCV, x0);
7216 __ Xaflag();
7217 __ Mrs(x2, NZCV);
7218 END();
7219
7220 if (CAN_RUN()) {
7221 RUN();
7222 ASSERT_EQUAL_32(expected_x[i], w1);
7223 ASSERT_EQUAL_32(expected_a[i], w2);
7224 }
7225 }
7226 }
7227
7228
TEST(system_msr)7229 TEST(system_msr) {
7230 // All FPCR fields that must be implemented: AHP, DN, FZ, RMode
7231 const uint64_t fpcr_core = (0b1 << 26) | // AHP
7232 (0b1 << 25) | // DN
7233 (0b1 << 24) | // FZ
7234 (0b11 << 22); // RMode
7235
7236 SETUP();
7237
7238 START();
7239 __ Mov(w0, 0);
7240 __ Mov(w1, 0x7fffffff);
7241
7242 __ Mov(x7, 0);
7243
7244 __ Mov(x10, NVFlag);
7245 __ Cmp(w0, w0); // Set Z and C.
7246 __ Msr(NZCV, x10); // Set N and V.
7247 // The Msr should have overwritten every flag set by the Cmp.
7248 __ Cinc(x7, x7, mi); // N
7249 __ Cinc(x7, x7, ne); // !Z
7250 __ Cinc(x7, x7, lo); // !C
7251 __ Cinc(x7, x7, vs); // V
7252
7253 __ Mov(x10, ZCFlag);
7254 __ Cmn(w1, w1); // Set N and V.
7255 __ Msr(NZCV, x10); // Set Z and C.
7256 // The Msr should have overwritten every flag set by the Cmn.
7257 __ Cinc(x7, x7, pl); // !N
7258 __ Cinc(x7, x7, eq); // Z
7259 __ Cinc(x7, x7, hs); // C
7260 __ Cinc(x7, x7, vc); // !V
7261
7262 Register old_fpcr = x15;
7263 __ Mrs(old_fpcr, FPCR);
7264
7265 // All core FPCR fields must be writable.
7266 __ Mov(x8, fpcr_core);
7267 __ Msr(FPCR, x8);
7268 __ Mrs(x8, FPCR);
7269
7270 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7271 // All FPCR fields that aren't `RES0`:
7272 const uint64_t fpcr_all = fpcr_core | (0b11 << 20) | // Stride
7273 (0b1 << 19) | // FZ16
7274 (0b111 << 16) | // Len
7275 (0b1 << 15) | // IDE
7276 (0b1 << 12) | // IXE
7277 (0b1 << 11) | // UFE
7278 (0b1 << 10) | // OFE
7279 (0b1 << 9) | // DZE
7280 (0b1 << 8); // IOE
7281
7282 // All FPCR fields, including optional ones. This part of the test doesn't
7283 // achieve much other than ensuring that supported fields can be cleared by
7284 // the next test.
7285 __ Mov(x9, fpcr_all);
7286 __ Msr(FPCR, x9);
7287 __ Mrs(x9, FPCR);
7288 __ And(x9, x9, fpcr_core);
7289
7290 // The undefined bits must ignore writes.
7291 // It's conceivable that a future version of the architecture could use these
7292 // fields (making this test fail), but in the meantime this is a useful test
7293 // for the simulator.
7294 __ Mov(x10, ~fpcr_all);
7295 __ Msr(FPCR, x10);
7296 __ Mrs(x10, FPCR);
7297 #endif
7298
7299 __ Msr(FPCR, old_fpcr);
7300
7301 END();
7302
7303 if (CAN_RUN()) {
7304 RUN();
7305
7306 // We should have incremented x7 (from 0) exactly 8 times.
7307 ASSERT_EQUAL_64(8, x7);
7308
7309 ASSERT_EQUAL_64(fpcr_core, x8);
7310
7311 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7312 ASSERT_EQUAL_64(fpcr_core, x9);
7313 ASSERT_EQUAL_64(0, x10);
7314 #endif
7315 }
7316 }
7317
7318
TEST(system_pauth_a)7319 TEST(system_pauth_a) {
7320 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
7321 START();
7322
7323 // Exclude x16 and x17 from the scratch register list so we can use
7324 // Pac/Autia1716 safely.
7325 UseScratchRegisterScope temps(&masm);
7326 temps.Exclude(x16, x17);
7327 temps.Include(x10, x11);
7328
7329 Register pointer = x21;
7330 Register retry_limit = x22;
7331 Label retry;
7332
7333 __ Mov(pointer, 0x0000000012345678);
7334 __ Mov(retry_limit, 0x0000000012345678 + 32);
7335
7336 // Back up stack pointer.
7337 __ Mov(x20, sp);
7338
7339 // Modifiers
7340 __ Mov(x16, 0x477d469dec0b8760);
7341 __ Mov(sp, 0x477d469dec0b8760);
7342
7343 __ Bind(&retry);
7344
7345 // Generate PACs using the 3 system instructions.
7346 __ Mov(x17, pointer);
7347 __ Pacia1716();
7348 __ Mov(x0, x17);
7349
7350 __ Mov(lr, pointer);
7351 __ Paciaz();
7352 __ Mov(x1, lr);
7353
7354 __ Mov(lr, pointer);
7355 __ Paciasp();
7356 __ Mov(x2, lr);
7357
7358 // Authenticate the pointers above.
7359 __ Mov(x17, x0);
7360 __ Autia1716();
7361 __ Mov(x3, x17);
7362
7363 __ Mov(lr, x1);
7364 __ Autiaz();
7365 __ Mov(x4, lr);
7366
7367 __ Mov(lr, x2);
7368 __ Autiasp();
7369 __ Mov(x5, lr);
7370
7371 // Attempt to authenticate incorrect pointers.
7372 __ Mov(x17, x1);
7373 __ Autia1716();
7374 __ Mov(x6, x17);
7375
7376 __ Mov(lr, x0);
7377 __ Autiaz();
7378 __ Mov(x7, lr);
7379
7380 __ Mov(lr, x1);
7381 __ Autiasp();
7382 __ Mov(x8, lr);
7383
7384 // Strip the pac code from the pointer in x0.
7385 __ Mov(lr, x0);
7386 __ Xpaclri();
7387 __ Mov(x9, lr);
7388
7389 // Retry on collisions.
7390 __ Cmp(x0, x1);
7391 __ Ccmp(pointer, x0, ZFlag, ne);
7392 __ Ccmp(pointer, x1, ZFlag, ne);
7393 __ Ccmp(pointer, x2, ZFlag, ne);
7394 __ Ccmp(pointer, x6, ZFlag, ne);
7395 __ Ccmp(pointer, x7, ZFlag, ne);
7396 __ Ccmp(pointer, x8, ZFlag, ne);
7397 __ Ccmp(pointer, retry_limit, ZFlag, eq);
7398 __ Cinc(pointer, pointer, ne);
7399 __ B(ne, &retry);
7400
7401 // Restore stack pointer.
7402 __ Mov(sp, x20);
7403
7404 END();
7405
7406 if (CAN_RUN()) {
7407 RUN();
7408
7409 // Check PAC codes have been generated.
7410 ASSERT_NOT_EQUAL_64(pointer, x0);
7411 ASSERT_NOT_EQUAL_64(pointer, x1);
7412 ASSERT_NOT_EQUAL_64(pointer, x2);
7413 ASSERT_NOT_EQUAL_64(x0, x1);
7414 ASSERT_EQUAL_64(x0, x2);
7415
7416 // Pointers correctly authenticated.
7417 ASSERT_EQUAL_64(pointer, x3);
7418 ASSERT_EQUAL_64(pointer, x4);
7419 ASSERT_EQUAL_64(pointer, x5);
7420
7421 // Pointers corrupted after failing to authenticate.
7422 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7423 ASSERT_EQUAL_64(0x0020000012345678, x6);
7424 ASSERT_EQUAL_64(0x0020000012345678, x7);
7425 ASSERT_EQUAL_64(0x0020000012345678, x8);
7426 #else
7427 ASSERT_NOT_EQUAL_64(pointer, x6);
7428 ASSERT_NOT_EQUAL_64(pointer, x7);
7429 ASSERT_NOT_EQUAL_64(pointer, x8);
7430 #endif
7431
7432 // Pointer with code stripped.
7433 ASSERT_EQUAL_64(pointer, x9);
7434 }
7435 }
7436
7437
TEST(system_pauth_b)7438 TEST(system_pauth_b) {
7439 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
7440 START();
7441
7442 // Exclude x16 and x17 from the scratch register list so we can use
7443 // Pac/Autia1716 safely.
7444 UseScratchRegisterScope temps(&masm);
7445 temps.Exclude(x16, x17);
7446 temps.Include(x10, x11);
7447
7448 Register pointer = x21;
7449 Register retry_limit = x22;
7450 Label retry;
7451
7452 __ Mov(pointer, 0x0000000012345678);
7453 __ Mov(retry_limit, 0x0000000012345678 + 32);
7454
7455 // Back up stack pointer.
7456 __ Mov(x20, sp);
7457
7458 // Modifiers
7459 __ Mov(x16, 0x477d469dec0b8760);
7460 __ Mov(sp, 0x477d469dec0b8760);
7461
7462 __ Bind(&retry);
7463
7464 // Generate PACs using the 3 system instructions.
7465 __ Mov(x17, 0x0000000012345678);
7466 __ Pacib1716();
7467 __ Mov(x0, x17);
7468
7469 __ Mov(lr, 0x0000000012345678);
7470 __ Pacibz();
7471 __ Mov(x1, lr);
7472
7473 __ Mov(lr, 0x0000000012345678);
7474 __ Pacibsp();
7475 __ Mov(x2, lr);
7476
7477 // Authenticate the pointers above.
7478 __ Mov(x17, x0);
7479 __ Autib1716();
7480 __ Mov(x3, x17);
7481
7482 __ Mov(lr, x1);
7483 __ Autibz();
7484 __ Mov(x4, lr);
7485
7486 __ Mov(lr, x2);
7487 __ Autibsp();
7488 __ Mov(x5, lr);
7489
7490 // Attempt to authenticate incorrect pointers.
7491 __ Mov(x17, x1);
7492 __ Autib1716();
7493 __ Mov(x6, x17);
7494
7495 __ Mov(lr, x0);
7496 __ Autibz();
7497 __ Mov(x7, lr);
7498
7499 __ Mov(lr, x1);
7500 __ Autibsp();
7501 __ Mov(x8, lr);
7502
7503 // Strip the pac code from the pointer in x0.
7504 __ Mov(lr, x0);
7505 __ Xpaclri();
7506 __ Mov(x9, lr);
7507
7508 // Retry on collisions.
7509 __ Cmp(x0, x1);
7510 __ Ccmp(pointer, x0, ZFlag, ne);
7511 __ Ccmp(pointer, x1, ZFlag, ne);
7512 __ Ccmp(pointer, x2, ZFlag, ne);
7513 __ Ccmp(pointer, x6, ZFlag, ne);
7514 __ Ccmp(pointer, x7, ZFlag, ne);
7515 __ Ccmp(pointer, x8, ZFlag, ne);
7516 __ Ccmp(pointer, retry_limit, ZFlag, eq);
7517 __ Cinc(pointer, pointer, ne);
7518 __ B(ne, &retry);
7519
7520 // Restore stack pointer.
7521 __ Mov(sp, x20);
7522
7523 END();
7524
7525 if (CAN_RUN()) {
7526 RUN();
7527
7528 // Check PAC codes have been generated and aren't equal.
7529 // NOTE: with a different ComputePAC implementation, there may be a
7530 // collision.
7531 ASSERT_NOT_EQUAL_64(pointer, x0);
7532 ASSERT_NOT_EQUAL_64(pointer, x1);
7533 ASSERT_NOT_EQUAL_64(pointer, x2);
7534 ASSERT_NOT_EQUAL_64(x0, x1);
7535 ASSERT_EQUAL_64(x0, x2);
7536
7537 // Pointers correctly authenticated.
7538 ASSERT_EQUAL_64(pointer, x3);
7539 ASSERT_EQUAL_64(pointer, x4);
7540 ASSERT_EQUAL_64(pointer, x5);
7541
7542 // Pointers corrupted after failing to authenticate.
7543 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7544 ASSERT_EQUAL_64(0x0040000012345678, x6);
7545 ASSERT_EQUAL_64(0x0040000012345678, x7);
7546 ASSERT_EQUAL_64(0x0040000012345678, x8);
7547 #else
7548 ASSERT_NOT_EQUAL_64(pointer, x6);
7549 ASSERT_NOT_EQUAL_64(pointer, x7);
7550 ASSERT_NOT_EQUAL_64(pointer, x8);
7551 #endif
7552
7553 // Pointer with code stripped.
7554 ASSERT_EQUAL_64(pointer, x9);
7555 }
7556 }
7557
7558 #ifdef VIXL_NEGATIVE_TESTING
TEST(system_pauth_negative_test)7559 TEST(system_pauth_negative_test) {
7560 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
7561 START();
7562
7563 // Test for an assert (independent of order).
7564 MUST_FAIL_WITH_MESSAGE(__ Pacia1716(),
7565 "Assertion failed "
7566 "(!GetScratchRegisterList()->IncludesAliasOf(");
7567
7568 // Test for x16 assert.
7569 {
7570 UseScratchRegisterScope temps(&masm);
7571 temps.Exclude(x17);
7572 temps.Include(x16);
7573 MUST_FAIL_WITH_MESSAGE(__ Pacia1716(),
7574 "Assertion failed "
7575 "(!GetScratchRegisterList()->IncludesAliasOf(x16))");
7576 }
7577
7578 // Test for x17 assert.
7579 {
7580 UseScratchRegisterScope temps(&masm);
7581 temps.Exclude(x16);
7582 temps.Include(x17);
7583 MUST_FAIL_WITH_MESSAGE(__ Pacia1716(),
7584 "Assertion failed "
7585 "(!GetScratchRegisterList()->IncludesAliasOf(x17))");
7586 }
7587
7588 // Repeat first test for other 1716 instructions.
7589 MUST_FAIL_WITH_MESSAGE(__ Pacib1716(),
7590 "Assertion failed "
7591 "(!GetScratchRegisterList()->IncludesAliasOf(");
7592 MUST_FAIL_WITH_MESSAGE(__ Autia1716(),
7593 "Assertion failed "
7594 "(!GetScratchRegisterList()->IncludesAliasOf(");
7595 MUST_FAIL_WITH_MESSAGE(__ Autib1716(),
7596 "Assertion failed "
7597 "(!GetScratchRegisterList()->IncludesAliasOf(");
7598
7599 END();
7600 }
7601 #endif // VIXL_NEGATIVE_TESTING
7602
7603
TEST(system)7604 TEST(system) {
7605 // RegisterDump::Dump uses NEON.
7606 SETUP_WITH_FEATURES(CPUFeatures::kNEON, CPUFeatures::kRAS);
7607 RegisterDump before;
7608
7609 START();
7610 before.Dump(&masm);
7611 __ Nop();
7612 __ Esb();
7613 __ Csdb();
7614 END();
7615
7616 if (CAN_RUN()) {
7617 RUN();
7618
7619 ASSERT_EQUAL_REGISTERS(before);
7620 ASSERT_EQUAL_NZCV(before.flags_nzcv());
7621 }
7622 }
7623
BtiHelper(Register ipreg)7624 static void BtiHelper(Register ipreg) {
7625 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7626
7627 Label jump_target, jump_call_target, call_target, done;
7628 START();
7629 UseScratchRegisterScope temps(&masm);
7630 temps.Exclude(ipreg);
7631 __ Adr(x0, &jump_target);
7632 __ Br(x0);
7633 __ Nop();
7634 __ Bind(&jump_target, EmitBTI_j);
7635 __ Adr(x0, &call_target);
7636 __ Blr(x0);
7637 __ Adr(ipreg, &jump_call_target);
7638 __ Blr(ipreg);
7639 __ Mov(lr, 0); // Zero lr so we branch to done.
7640 __ Br(ipreg);
7641 __ Bind(&call_target, EmitBTI_c);
7642 __ Ret();
7643 __ Bind(&jump_call_target, EmitBTI_jc);
7644 __ Cbz(lr, &done);
7645 __ Ret();
7646 __ Bind(&done);
7647 END();
7648
7649 if (CAN_RUN()) {
7650 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7651 simulator.SetGuardedPages(true);
7652 #endif
7653 // On hardware, we'll run the test anyway, but mark it as SKIPPED until
7654 // we've implemented a mechanism for marking Guarded pages.
7655
7656 RUN();
7657
7658 #ifndef VIXL_INCLUDE_SIMULATOR_AARCH64
7659 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7660 #endif
7661 }
7662 }
7663
TEST(bti)7664 TEST(bti) {
7665 BtiHelper(x16);
7666 BtiHelper(x17);
7667 }
7668
TEST(unguarded_bti_is_nop)7669 TEST(unguarded_bti_is_nop) {
7670 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7671
7672 Label start, none, c, j, jc;
7673 Label jump_to_c, call_to_j;
7674 START();
7675 __ B(&start);
7676 __ Bind(&none, EmitBTI);
7677 __ Bind(&c, EmitBTI_c);
7678 __ Bind(&j, EmitBTI_j);
7679 __ Bind(&jc, EmitBTI_jc);
7680 __ Hint(BTI);
7681 __ Hint(BTI_c);
7682 __ Hint(BTI_j);
7683 __ Hint(BTI_jc);
7684 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&none) == 8 * kInstructionSize);
7685 __ Cmp(x1, 1);
7686 __ B(lt, &jump_to_c);
7687 __ B(eq, &call_to_j);
7688 __ Ret();
7689
7690 __ Bind(&start);
7691 __ Adr(x0, &none);
7692 __ Mov(x1, 0);
7693 __ Br(x0);
7694
7695 __ Bind(&jump_to_c);
7696 __ Adr(x0, &c);
7697 __ Mov(x1, 1);
7698 __ Br(x0);
7699
7700 __ Bind(&call_to_j);
7701 __ Adr(x0, &j);
7702 __ Mov(x1, 2);
7703 __ Blr(x0);
7704 END();
7705
7706 if (CAN_RUN()) {
7707 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7708 simulator.SetGuardedPages(false);
7709 #endif
7710 RUN();
7711 }
7712 }
7713
7714 #ifdef VIXL_NEGATIVE_TESTING
TEST(bti_jump_to_ip_unidentified)7715 TEST(bti_jump_to_ip_unidentified) {
7716 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7717
7718 START();
7719 UseScratchRegisterScope temps(&masm);
7720 temps.Exclude(x17);
7721 Label l;
7722 __ Adr(x17, &l);
7723 __ Br(x17);
7724 __ Nop();
7725 __ Bind(&l);
7726 __ Nop();
7727 END();
7728
7729 if (CAN_RUN()) {
7730 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7731 simulator.SetGuardedPages(true);
7732 MUST_FAIL_WITH_MESSAGE(RUN(),
7733 "Executing non-BTI instruction with wrong "
7734 "BType.");
7735 #else
7736 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7737 #endif
7738 }
7739 }
7740
TEST(bti_jump_to_unidentified)7741 TEST(bti_jump_to_unidentified) {
7742 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7743
7744 START();
7745 Label l;
7746 __ Adr(x0, &l);
7747 __ Br(x0);
7748 __ Nop();
7749 __ Bind(&l);
7750 __ Nop();
7751 END();
7752
7753 if (CAN_RUN()) {
7754 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7755 simulator.SetGuardedPages(true);
7756 MUST_FAIL_WITH_MESSAGE(RUN(),
7757 "Executing non-BTI instruction with wrong "
7758 "BType.");
7759 #else
7760 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7761 #endif
7762 }
7763 }
7764
TEST(bti_call_to_unidentified)7765 TEST(bti_call_to_unidentified) {
7766 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7767
7768 START();
7769 Label l;
7770 __ Adr(x0, &l);
7771 __ Blr(x0);
7772 __ Nop();
7773 __ Bind(&l);
7774 __ Nop();
7775 END();
7776
7777 if (CAN_RUN()) {
7778 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7779 simulator.SetGuardedPages(true);
7780 MUST_FAIL_WITH_MESSAGE(RUN(),
7781 "Executing non-BTI instruction with wrong "
7782 "BType.");
7783 #else
7784 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7785 #endif
7786 }
7787 }
7788
TEST(bti_jump_to_c)7789 TEST(bti_jump_to_c) {
7790 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7791
7792 START();
7793 // Jumping to a "BTI c" target must fail.
7794 Label jump_target;
7795 __ Adr(x0, &jump_target);
7796 __ Br(x0);
7797 __ Nop();
7798 __ Bind(&jump_target, EmitBTI_c);
7799 __ Nop();
7800 END();
7801
7802 if (CAN_RUN()) {
7803 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7804 simulator.SetGuardedPages(true);
7805 MUST_FAIL_WITH_MESSAGE(RUN(), "Executing BTI c with wrong BType.");
7806 #else
7807 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7808 #endif
7809 }
7810 }
7811
TEST(bti_call_to_j)7812 TEST(bti_call_to_j) {
7813 SETUP_WITH_FEATURES(CPUFeatures::kBTI);
7814
7815 START();
7816 // Calling a "BTI j" target must fail.
7817 Label call_target;
7818 __ Adr(x0, &call_target);
7819 __ Blr(x0);
7820 __ Nop();
7821 __ Bind(&call_target, EmitBTI_j);
7822 __ Nop();
7823 END();
7824
7825 if (CAN_RUN()) {
7826 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7827 simulator.SetGuardedPages(true);
7828 MUST_FAIL_WITH_MESSAGE(RUN(), "Executing BTI j with wrong BType.");
7829 #else
7830 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7831 #endif
7832 }
7833 }
7834 #endif // VIXL_NEGATIVE_TESTING
7835
TEST(fall_through_bti)7836 TEST(fall_through_bti) {
7837 SETUP_WITH_FEATURES(CPUFeatures::kBTI, CPUFeatures::kPAuth);
7838
7839 START();
7840 Label target, target_j, target_c, target_jc;
7841 __ Mov(x0, 0); // 'Normal' instruction sets BTYPE to zero.
7842 __ Bind(&target, EmitBTI);
7843 __ Add(x0, x0, 1);
7844 __ Bind(&target_j, EmitBTI_j);
7845 __ Add(x0, x0, 1);
7846 __ Bind(&target_c, EmitBTI_c);
7847 __ Add(x0, x0, 1);
7848 __ Bind(&target_jc, EmitBTI_jc);
7849 __ Add(x0, x0, 1);
7850 __ Paciasp();
7851 END();
7852
7853 if (CAN_RUN()) {
7854 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
7855 simulator.SetGuardedPages(true);
7856 #endif
7857 // On hardware, we'll run the test anyway, but mark it as SKIPPED until
7858 // we've implemented a mechanism for marking Guarded pages.
7859
7860 RUN();
7861
7862 ASSERT_EQUAL_64(4, x0);
7863
7864 #ifndef VIXL_INCLUDE_SIMULATOR_AARCH64
7865 printf("SKIPPED: marking guarded pages is unimplemented on hardware");
7866 #endif
7867 }
7868 }
7869
TEST(zero_dest)7870 TEST(zero_dest) {
7871 // RegisterDump::Dump uses NEON.
7872 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
7873 RegisterDump before;
7874
7875 START();
7876 // Preserve the stack pointer, in case we clobber it.
7877 __ Mov(x30, sp);
7878 // Initialize the other registers used in this test.
7879 uint64_t literal_base = 0x0100001000100101;
7880 __ Mov(x0, 0);
7881 __ Mov(x1, literal_base);
7882 for (unsigned i = 2; i < x30.GetCode(); i++) {
7883 __ Add(XRegister(i), XRegister(i - 1), x1);
7884 }
7885 before.Dump(&masm);
7886
7887 // All of these instructions should be NOPs in these forms, but have
7888 // alternate forms which can write into the stack pointer.
7889 {
7890 ExactAssemblyScope scope(&masm, 3 * 7 * kInstructionSize);
7891 __ add(xzr, x0, x1);
7892 __ add(xzr, x1, xzr);
7893 __ add(xzr, xzr, x1);
7894
7895 __ and_(xzr, x0, x2);
7896 __ and_(xzr, x2, xzr);
7897 __ and_(xzr, xzr, x2);
7898
7899 __ bic(xzr, x0, x3);
7900 __ bic(xzr, x3, xzr);
7901 __ bic(xzr, xzr, x3);
7902
7903 __ eon(xzr, x0, x4);
7904 __ eon(xzr, x4, xzr);
7905 __ eon(xzr, xzr, x4);
7906
7907 __ eor(xzr, x0, x5);
7908 __ eor(xzr, x5, xzr);
7909 __ eor(xzr, xzr, x5);
7910
7911 __ orr(xzr, x0, x6);
7912 __ orr(xzr, x6, xzr);
7913 __ orr(xzr, xzr, x6);
7914
7915 __ sub(xzr, x0, x7);
7916 __ sub(xzr, x7, xzr);
7917 __ sub(xzr, xzr, x7);
7918 }
7919
7920 // Swap the saved stack pointer with the real one. If sp was written
7921 // during the test, it will show up in x30. This is done because the test
7922 // framework assumes that sp will be valid at the end of the test.
7923 __ Mov(x29, x30);
7924 __ Mov(x30, sp);
7925 __ Mov(sp, x29);
7926 // We used x29 as a scratch register, so reset it to make sure it doesn't
7927 // trigger a test failure.
7928 __ Add(x29, x28, x1);
7929 END();
7930
7931 if (CAN_RUN()) {
7932 RUN();
7933
7934 ASSERT_EQUAL_REGISTERS(before);
7935 ASSERT_EQUAL_NZCV(before.flags_nzcv());
7936 }
7937 }
7938
7939
TEST(zero_dest_setflags)7940 TEST(zero_dest_setflags) {
7941 // RegisterDump::Dump uses NEON.
7942 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
7943 RegisterDump before;
7944
7945 START();
7946 // Preserve the stack pointer, in case we clobber it.
7947 __ Mov(x30, sp);
7948 // Initialize the other registers used in this test.
7949 uint64_t literal_base = 0x0100001000100101;
7950 __ Mov(x0, 0);
7951 __ Mov(x1, literal_base);
7952 for (int i = 2; i < 30; i++) {
7953 __ Add(XRegister(i), XRegister(i - 1), x1);
7954 }
7955 before.Dump(&masm);
7956
7957 // All of these instructions should only write to the flags in these forms,
7958 // but have alternate forms which can write into the stack pointer.
7959 {
7960 ExactAssemblyScope scope(&masm, 6 * kInstructionSize);
7961 __ adds(xzr, x0, Operand(x1, UXTX));
7962 __ adds(xzr, x1, Operand(xzr, UXTX));
7963 __ adds(xzr, x1, 1234);
7964 __ adds(xzr, x0, x1);
7965 __ adds(xzr, x1, xzr);
7966 __ adds(xzr, xzr, x1);
7967 }
7968
7969 {
7970 ExactAssemblyScope scope(&masm, 5 * kInstructionSize);
7971 __ ands(xzr, x2, ~0xf);
7972 __ ands(xzr, xzr, ~0xf);
7973 __ ands(xzr, x0, x2);
7974 __ ands(xzr, x2, xzr);
7975 __ ands(xzr, xzr, x2);
7976 }
7977
7978 {
7979 ExactAssemblyScope scope(&masm, 5 * kInstructionSize);
7980 __ bics(xzr, x3, ~0xf);
7981 __ bics(xzr, xzr, ~0xf);
7982 __ bics(xzr, x0, x3);
7983 __ bics(xzr, x3, xzr);
7984 __ bics(xzr, xzr, x3);
7985 }
7986
7987 {
7988 ExactAssemblyScope scope(&masm, 6 * kInstructionSize);
7989 __ subs(xzr, x0, Operand(x3, UXTX));
7990 __ subs(xzr, x3, Operand(xzr, UXTX));
7991 __ subs(xzr, x3, 1234);
7992 __ subs(xzr, x0, x3);
7993 __ subs(xzr, x3, xzr);
7994 __ subs(xzr, xzr, x3);
7995 }
7996
7997 // Swap the saved stack pointer with the real one. If sp was written
7998 // during the test, it will show up in x30. This is done because the test
7999 // framework assumes that sp will be valid at the end of the test.
8000 __ Mov(x29, x30);
8001 __ Mov(x30, sp);
8002 __ Mov(sp, x29);
8003 // We used x29 as a scratch register, so reset it to make sure it doesn't
8004 // trigger a test failure.
8005 __ Add(x29, x28, x1);
8006 END();
8007
8008 if (CAN_RUN()) {
8009 RUN();
8010
8011 ASSERT_EQUAL_REGISTERS(before);
8012 }
8013 }
8014
8015
TEST(stack_pointer_override)8016 TEST(stack_pointer_override) {
8017 // This test generates some stack maintenance code, but the test only checks
8018 // the reported state.
8019 SETUP();
8020 START();
8021
8022 // The default stack pointer in VIXL is sp.
8023 VIXL_CHECK(sp.Is(__ StackPointer()));
8024 __ SetStackPointer(x0);
8025 VIXL_CHECK(x0.Is(__ StackPointer()));
8026 __ SetStackPointer(x28);
8027 VIXL_CHECK(x28.Is(__ StackPointer()));
8028 __ SetStackPointer(sp);
8029 VIXL_CHECK(sp.Is(__ StackPointer()));
8030
8031 END();
8032 if (CAN_RUN()) {
8033 RUN();
8034 }
8035 }
8036
8037
TEST(peek_poke_simple)8038 TEST(peek_poke_simple) {
8039 SETUP();
8040 START();
8041
8042 static const RegList x0_to_x3 =
8043 x0.GetBit() | x1.GetBit() | x2.GetBit() | x3.GetBit();
8044 static const RegList x10_to_x13 =
8045 x10.GetBit() | x11.GetBit() | x12.GetBit() | x13.GetBit();
8046
8047 // The literal base is chosen to have two useful properties:
8048 // * When multiplied by small values (such as a register index), this value
8049 // is clearly readable in the result.
8050 // * The value is not formed from repeating fixed-size smaller values, so it
8051 // can be used to detect endianness-related errors.
8052 uint64_t literal_base = 0x0100001000100101;
8053
8054 // Initialize the registers.
8055 __ Mov(x0, literal_base);
8056 __ Add(x1, x0, x0);
8057 __ Add(x2, x1, x0);
8058 __ Add(x3, x2, x0);
8059
8060 __ Claim(32);
8061
8062 // Simple exchange.
8063 // After this test:
8064 // x0-x3 should be unchanged.
8065 // w10-w13 should contain the lower words of x0-x3.
8066 __ Poke(x0, 0);
8067 __ Poke(x1, 8);
8068 __ Poke(x2, 16);
8069 __ Poke(x3, 24);
8070 Clobber(&masm, x0_to_x3);
8071 __ Peek(x0, 0);
8072 __ Peek(x1, 8);
8073 __ Peek(x2, 16);
8074 __ Peek(x3, 24);
8075
8076 __ Poke(w0, 0);
8077 __ Poke(w1, 4);
8078 __ Poke(w2, 8);
8079 __ Poke(w3, 12);
8080 Clobber(&masm, x10_to_x13);
8081 __ Peek(w10, 0);
8082 __ Peek(w11, 4);
8083 __ Peek(w12, 8);
8084 __ Peek(w13, 12);
8085
8086 __ Drop(32);
8087
8088 END();
8089 if (CAN_RUN()) {
8090 RUN();
8091
8092 ASSERT_EQUAL_64(literal_base * 1, x0);
8093 ASSERT_EQUAL_64(literal_base * 2, x1);
8094 ASSERT_EQUAL_64(literal_base * 3, x2);
8095 ASSERT_EQUAL_64(literal_base * 4, x3);
8096
8097 ASSERT_EQUAL_64((literal_base * 1) & 0xffffffff, x10);
8098 ASSERT_EQUAL_64((literal_base * 2) & 0xffffffff, x11);
8099 ASSERT_EQUAL_64((literal_base * 3) & 0xffffffff, x12);
8100 ASSERT_EQUAL_64((literal_base * 4) & 0xffffffff, x13);
8101 }
8102 }
8103
8104
TEST(peek_poke_unaligned)8105 TEST(peek_poke_unaligned) {
8106 SETUP();
8107 START();
8108
8109 // The literal base is chosen to have two useful properties:
8110 // * When multiplied by small values (such as a register index), this value
8111 // is clearly readable in the result.
8112 // * The value is not formed from repeating fixed-size smaller values, so it
8113 // can be used to detect endianness-related errors.
8114 uint64_t literal_base = 0x0100001000100101;
8115
8116 // Initialize the registers.
8117 __ Mov(x0, literal_base);
8118 __ Add(x1, x0, x0);
8119 __ Add(x2, x1, x0);
8120 __ Add(x3, x2, x0);
8121 __ Add(x4, x3, x0);
8122 __ Add(x5, x4, x0);
8123 __ Add(x6, x5, x0);
8124
8125 __ Claim(32);
8126
8127 // Unaligned exchanges.
8128 // After this test:
8129 // x0-x6 should be unchanged.
8130 // w10-w12 should contain the lower words of x0-x2.
8131 __ Poke(x0, 1);
8132 Clobber(&masm, x0.GetBit());
8133 __ Peek(x0, 1);
8134 __ Poke(x1, 2);
8135 Clobber(&masm, x1.GetBit());
8136 __ Peek(x1, 2);
8137 __ Poke(x2, 3);
8138 Clobber(&masm, x2.GetBit());
8139 __ Peek(x2, 3);
8140 __ Poke(x3, 4);
8141 Clobber(&masm, x3.GetBit());
8142 __ Peek(x3, 4);
8143 __ Poke(x4, 5);
8144 Clobber(&masm, x4.GetBit());
8145 __ Peek(x4, 5);
8146 __ Poke(x5, 6);
8147 Clobber(&masm, x5.GetBit());
8148 __ Peek(x5, 6);
8149 __ Poke(x6, 7);
8150 Clobber(&masm, x6.GetBit());
8151 __ Peek(x6, 7);
8152
8153 __ Poke(w0, 1);
8154 Clobber(&masm, w10.GetBit());
8155 __ Peek(w10, 1);
8156 __ Poke(w1, 2);
8157 Clobber(&masm, w11.GetBit());
8158 __ Peek(w11, 2);
8159 __ Poke(w2, 3);
8160 Clobber(&masm, w12.GetBit());
8161 __ Peek(w12, 3);
8162
8163 __ Drop(32);
8164
8165 END();
8166 if (CAN_RUN()) {
8167 RUN();
8168
8169 ASSERT_EQUAL_64(literal_base * 1, x0);
8170 ASSERT_EQUAL_64(literal_base * 2, x1);
8171 ASSERT_EQUAL_64(literal_base * 3, x2);
8172 ASSERT_EQUAL_64(literal_base * 4, x3);
8173 ASSERT_EQUAL_64(literal_base * 5, x4);
8174 ASSERT_EQUAL_64(literal_base * 6, x5);
8175 ASSERT_EQUAL_64(literal_base * 7, x6);
8176
8177 ASSERT_EQUAL_64((literal_base * 1) & 0xffffffff, x10);
8178 ASSERT_EQUAL_64((literal_base * 2) & 0xffffffff, x11);
8179 ASSERT_EQUAL_64((literal_base * 3) & 0xffffffff, x12);
8180 }
8181 }
8182
8183
TEST(peek_poke_endianness)8184 TEST(peek_poke_endianness) {
8185 SETUP();
8186 START();
8187
8188 // The literal base is chosen to have two useful properties:
8189 // * When multiplied by small values (such as a register index), this value
8190 // is clearly readable in the result.
8191 // * The value is not formed from repeating fixed-size smaller values, so it
8192 // can be used to detect endianness-related errors.
8193 uint64_t literal_base = 0x0100001000100101;
8194
8195 // Initialize the registers.
8196 __ Mov(x0, literal_base);
8197 __ Add(x1, x0, x0);
8198
8199 __ Claim(32);
8200
8201 // Endianness tests.
8202 // After this section:
8203 // x4 should match x0[31:0]:x0[63:32]
8204 // w5 should match w1[15:0]:w1[31:16]
8205 __ Poke(x0, 0);
8206 __ Poke(x0, 8);
8207 __ Peek(x4, 4);
8208
8209 __ Poke(w1, 0);
8210 __ Poke(w1, 4);
8211 __ Peek(w5, 2);
8212
8213 __ Drop(32);
8214
8215 END();
8216 if (CAN_RUN()) {
8217 RUN();
8218
8219 uint64_t x0_expected = literal_base * 1;
8220 uint64_t x1_expected = literal_base * 2;
8221 uint64_t x4_expected = (x0_expected << 32) | (x0_expected >> 32);
8222 uint64_t x5_expected =
8223 ((x1_expected << 16) & 0xffff0000) | ((x1_expected >> 16) & 0x0000ffff);
8224
8225 ASSERT_EQUAL_64(x0_expected, x0);
8226 ASSERT_EQUAL_64(x1_expected, x1);
8227 ASSERT_EQUAL_64(x4_expected, x4);
8228 ASSERT_EQUAL_64(x5_expected, x5);
8229 }
8230 }
8231
8232
TEST(peek_poke_mixed)8233 TEST(peek_poke_mixed) {
8234 SETUP();
8235 START();
8236
8237 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
8238 UseScratchRegisterScope temps(&masm);
8239 temps.ExcludeAll();
8240
8241 // The literal base is chosen to have two useful properties:
8242 // * When multiplied by small values (such as a register index), this value
8243 // is clearly readable in the result.
8244 // * The value is not formed from repeating fixed-size smaller values, so it
8245 // can be used to detect endianness-related errors.
8246 uint64_t literal_base = 0x0100001000100101;
8247
8248 // Initialize the registers.
8249 __ Mov(x0, literal_base);
8250 __ Add(x1, x0, x0);
8251 __ Add(x2, x1, x0);
8252 __ Add(x3, x2, x0);
8253
8254 __ Claim(32);
8255
8256 // Mix with other stack operations.
8257 // After this section:
8258 // x0-x3 should be unchanged.
8259 // x6 should match x1[31:0]:x0[63:32]
8260 // w7 should match x1[15:0]:x0[63:48]
8261 __ Poke(x1, 8);
8262 __ Poke(x0, 0);
8263 {
8264 VIXL_ASSERT(__ StackPointer().Is(sp));
8265 __ Mov(x4, __ StackPointer());
8266 __ SetStackPointer(x4);
8267
8268 __ Poke(wzr, 0); // Clobber the space we're about to drop.
8269 __ Drop(4);
8270 __ Peek(x6, 0);
8271 __ Claim(8);
8272 __ Peek(w7, 10);
8273 __ Poke(x3, 28);
8274 __ Poke(xzr, 0); // Clobber the space we're about to drop.
8275 __ Drop(8);
8276 __ Poke(x2, 12);
8277 __ Push(w0);
8278
8279 __ Mov(sp, __ StackPointer());
8280 __ SetStackPointer(sp);
8281 }
8282
8283 __ Pop(x0, x1, x2, x3);
8284
8285 END();
8286 if (CAN_RUN()) {
8287 RUN();
8288
8289 uint64_t x0_expected = literal_base * 1;
8290 uint64_t x1_expected = literal_base * 2;
8291 uint64_t x2_expected = literal_base * 3;
8292 uint64_t x3_expected = literal_base * 4;
8293 uint64_t x6_expected = (x1_expected << 32) | (x0_expected >> 32);
8294 uint64_t x7_expected =
8295 ((x1_expected << 16) & 0xffff0000) | ((x0_expected >> 48) & 0x0000ffff);
8296
8297 ASSERT_EQUAL_64(x0_expected, x0);
8298 ASSERT_EQUAL_64(x1_expected, x1);
8299 ASSERT_EQUAL_64(x2_expected, x2);
8300 ASSERT_EQUAL_64(x3_expected, x3);
8301 ASSERT_EQUAL_64(x6_expected, x6);
8302 ASSERT_EQUAL_64(x7_expected, x7);
8303 }
8304 }
8305
8306
TEST(peek_poke_reglist)8307 TEST(peek_poke_reglist) {
8308 SETUP_WITH_FEATURES(CPUFeatures::kFP);
8309
8310 START();
8311
8312 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
8313 UseScratchRegisterScope temps(&masm);
8314 temps.ExcludeAll();
8315
8316 // The literal base is chosen to have two useful properties:
8317 // * When multiplied by small values (such as a register index), this value
8318 // is clearly readable in the result.
8319 // * The value is not formed from repeating fixed-size smaller values, so it
8320 // can be used to detect endianness-related errors.
8321 uint64_t base = 0x0100001000100101;
8322
8323 // Initialize the registers.
8324 __ Mov(x1, base);
8325 __ Add(x2, x1, x1);
8326 __ Add(x3, x2, x1);
8327 __ Add(x4, x3, x1);
8328
8329 CPURegList list_1(x1, x2, x3, x4);
8330 CPURegList list_2(x11, x12, x13, x14);
8331 int list_1_size = list_1.GetTotalSizeInBytes();
8332
8333 __ Claim(2 * list_1_size);
8334
8335 __ PokeCPURegList(list_1, 0);
8336 __ PokeXRegList(list_1.GetList(), list_1_size);
8337 __ PeekCPURegList(list_2, 2 * kXRegSizeInBytes);
8338 __ PeekXRegList(x15.GetBit(), kWRegSizeInBytes);
8339 __ PeekWRegList(w16.GetBit() | w17.GetBit(), 3 * kXRegSizeInBytes);
8340
8341 __ Drop(2 * list_1_size);
8342
8343
8344 uint64_t base_d = 0x1010010001000010;
8345
8346 // Initialize the registers.
8347 __ Mov(x1, base_d);
8348 __ Add(x2, x1, x1);
8349 __ Add(x3, x2, x1);
8350 __ Add(x4, x3, x1);
8351 __ Fmov(d1, x1);
8352 __ Fmov(d2, x2);
8353 __ Fmov(d3, x3);
8354 __ Fmov(d4, x4);
8355
8356 CPURegList list_d_1(d1, d2, d3, d4);
8357 CPURegList list_d_2(d11, d12, d13, d14);
8358 int list_d_1_size = list_d_1.GetTotalSizeInBytes();
8359
8360 __ Claim(2 * list_d_1_size);
8361
8362 __ PokeCPURegList(list_d_1, 0);
8363 __ PokeDRegList(list_d_1.GetList(), list_d_1_size);
8364 __ PeekCPURegList(list_d_2, 2 * kDRegSizeInBytes);
8365 __ PeekDRegList(d15.GetBit(), kSRegSizeInBytes);
8366 __ PeekSRegList(s16.GetBit() | s17.GetBit(), 3 * kDRegSizeInBytes);
8367
8368 __ Drop(2 * list_d_1_size);
8369
8370
8371 END();
8372 if (CAN_RUN()) {
8373 RUN();
8374
8375 ASSERT_EQUAL_64(3 * base, x11);
8376 ASSERT_EQUAL_64(4 * base, x12);
8377 ASSERT_EQUAL_64(1 * base, x13);
8378 ASSERT_EQUAL_64(2 * base, x14);
8379 ASSERT_EQUAL_64(((1 * base) >> kWRegSize) | ((2 * base) << kWRegSize), x15);
8380 ASSERT_EQUAL_64(2 * base, x14);
8381 ASSERT_EQUAL_32((4 * base) & kWRegMask, w16);
8382 ASSERT_EQUAL_32((4 * base) >> kWRegSize, w17);
8383
8384 ASSERT_EQUAL_FP64(RawbitsToDouble(3 * base_d), d11);
8385 ASSERT_EQUAL_FP64(RawbitsToDouble(4 * base_d), d12);
8386 ASSERT_EQUAL_FP64(RawbitsToDouble(1 * base_d), d13);
8387 ASSERT_EQUAL_FP64(RawbitsToDouble(2 * base_d), d14);
8388 ASSERT_EQUAL_FP64(RawbitsToDouble((base_d >> kSRegSize) |
8389 ((2 * base_d) << kSRegSize)),
8390 d15);
8391 ASSERT_EQUAL_FP64(RawbitsToDouble(2 * base_d), d14);
8392 ASSERT_EQUAL_FP32(RawbitsToFloat((4 * base_d) & kSRegMask), s16);
8393 ASSERT_EQUAL_FP32(RawbitsToFloat((4 * base_d) >> kSRegSize), s17);
8394 }
8395 }
8396
8397
TEST(load_store_reglist)8398 TEST(load_store_reglist) {
8399 SETUP_WITH_FEATURES(CPUFeatures::kFP);
8400
8401 START();
8402
8403 // The literal base is chosen to have two useful properties:
8404 // * When multiplied by small values (such as a register index), this value
8405 // is clearly readable in the result.
8406 // * The value is not formed from repeating fixed-size smaller values, so it
8407 // can be used to detect endianness-related errors.
8408 uint64_t high_base = UINT32_C(0x01000010);
8409 uint64_t low_base = UINT32_C(0x00100101);
8410 uint64_t base = (high_base << 32) | low_base;
8411 uint64_t array[21];
8412 memset(array, 0, sizeof(array));
8413
8414 // Initialize the registers.
8415 __ Mov(x1, base);
8416 __ Add(x2, x1, x1);
8417 __ Add(x3, x2, x1);
8418 __ Add(x4, x3, x1);
8419 __ Fmov(d1, x1);
8420 __ Fmov(d2, x2);
8421 __ Fmov(d3, x3);
8422 __ Fmov(d4, x4);
8423 __ Fmov(d5, x1);
8424 __ Fmov(d6, x2);
8425 __ Fmov(d7, x3);
8426 __ Fmov(d8, x4);
8427
8428 Register reg_base = x20;
8429 Register reg_index = x21;
8430 int size_stored = 0;
8431
8432 __ Mov(reg_base, reinterpret_cast<uintptr_t>(&array));
8433
8434 // Test aligned accesses.
8435 CPURegList list_src(w1, w2, w3, w4);
8436 CPURegList list_dst(w11, w12, w13, w14);
8437 CPURegList list_fp_src_1(d1, d2, d3, d4);
8438 CPURegList list_fp_dst_1(d11, d12, d13, d14);
8439
8440 __ StoreCPURegList(list_src, MemOperand(reg_base, 0 * sizeof(uint64_t)));
8441 __ LoadCPURegList(list_dst, MemOperand(reg_base, 0 * sizeof(uint64_t)));
8442 size_stored += 4 * kWRegSizeInBytes;
8443
8444 __ Mov(reg_index, size_stored);
8445 __ StoreCPURegList(list_src, MemOperand(reg_base, reg_index));
8446 __ LoadCPURegList(list_dst, MemOperand(reg_base, reg_index));
8447 size_stored += 4 * kWRegSizeInBytes;
8448
8449 __ StoreCPURegList(list_fp_src_1, MemOperand(reg_base, size_stored));
8450 __ LoadCPURegList(list_fp_dst_1, MemOperand(reg_base, size_stored));
8451 size_stored += 4 * kDRegSizeInBytes;
8452
8453 __ Mov(reg_index, size_stored);
8454 __ StoreCPURegList(list_fp_src_1, MemOperand(reg_base, reg_index));
8455 __ LoadCPURegList(list_fp_dst_1, MemOperand(reg_base, reg_index));
8456 size_stored += 4 * kDRegSizeInBytes;
8457
8458 // Test unaligned accesses.
8459 CPURegList list_fp_src_2(d5, d6, d7, d8);
8460 CPURegList list_fp_dst_2(d15, d16, d17, d18);
8461
8462 __ Str(wzr, MemOperand(reg_base, size_stored));
8463 size_stored += 1 * kWRegSizeInBytes;
8464 __ StoreCPURegList(list_fp_src_2, MemOperand(reg_base, size_stored));
8465 __ LoadCPURegList(list_fp_dst_2, MemOperand(reg_base, size_stored));
8466 size_stored += 4 * kDRegSizeInBytes;
8467
8468 __ Mov(reg_index, size_stored);
8469 __ StoreCPURegList(list_fp_src_2, MemOperand(reg_base, reg_index));
8470 __ LoadCPURegList(list_fp_dst_2, MemOperand(reg_base, reg_index));
8471
8472 END();
8473 if (CAN_RUN()) {
8474 RUN();
8475
8476 VIXL_CHECK(array[0] == (1 * low_base) + (2 * low_base << kWRegSize));
8477 VIXL_CHECK(array[1] == (3 * low_base) + (4 * low_base << kWRegSize));
8478 VIXL_CHECK(array[2] == (1 * low_base) + (2 * low_base << kWRegSize));
8479 VIXL_CHECK(array[3] == (3 * low_base) + (4 * low_base << kWRegSize));
8480 VIXL_CHECK(array[4] == 1 * base);
8481 VIXL_CHECK(array[5] == 2 * base);
8482 VIXL_CHECK(array[6] == 3 * base);
8483 VIXL_CHECK(array[7] == 4 * base);
8484 VIXL_CHECK(array[8] == 1 * base);
8485 VIXL_CHECK(array[9] == 2 * base);
8486 VIXL_CHECK(array[10] == 3 * base);
8487 VIXL_CHECK(array[11] == 4 * base);
8488 VIXL_CHECK(array[12] == ((1 * low_base) << kSRegSize));
8489 VIXL_CHECK(array[13] == (((2 * low_base) << kSRegSize) | (1 * high_base)));
8490 VIXL_CHECK(array[14] == (((3 * low_base) << kSRegSize) | (2 * high_base)));
8491 VIXL_CHECK(array[15] == (((4 * low_base) << kSRegSize) | (3 * high_base)));
8492 VIXL_CHECK(array[16] == (((1 * low_base) << kSRegSize) | (4 * high_base)));
8493 VIXL_CHECK(array[17] == (((2 * low_base) << kSRegSize) | (1 * high_base)));
8494 VIXL_CHECK(array[18] == (((3 * low_base) << kSRegSize) | (2 * high_base)));
8495 VIXL_CHECK(array[19] == (((4 * low_base) << kSRegSize) | (3 * high_base)));
8496 VIXL_CHECK(array[20] == (4 * high_base));
8497
8498 ASSERT_EQUAL_64(1 * low_base, x11);
8499 ASSERT_EQUAL_64(2 * low_base, x12);
8500 ASSERT_EQUAL_64(3 * low_base, x13);
8501 ASSERT_EQUAL_64(4 * low_base, x14);
8502 ASSERT_EQUAL_FP64(RawbitsToDouble(1 * base), d11);
8503 ASSERT_EQUAL_FP64(RawbitsToDouble(2 * base), d12);
8504 ASSERT_EQUAL_FP64(RawbitsToDouble(3 * base), d13);
8505 ASSERT_EQUAL_FP64(RawbitsToDouble(4 * base), d14);
8506 ASSERT_EQUAL_FP64(RawbitsToDouble(1 * base), d15);
8507 ASSERT_EQUAL_FP64(RawbitsToDouble(2 * base), d16);
8508 ASSERT_EQUAL_FP64(RawbitsToDouble(3 * base), d17);
8509 ASSERT_EQUAL_FP64(RawbitsToDouble(4 * base), d18);
8510 }
8511 }
8512
8513
8514 // This enum is used only as an argument to the push-pop test helpers.
8515 enum PushPopMethod {
8516 // Push or Pop using the Push and Pop methods, with blocks of up to four
8517 // registers. (Smaller blocks will be used if necessary.)
8518 PushPopByFour,
8519
8520 // Use Push<Size>RegList and Pop<Size>RegList to transfer the registers.
8521 PushPopRegList
8522 };
8523
8524
8525 // For the PushPop* tests, use the maximum number of registers that the test
8526 // supports (where a reg_count argument would otherwise be provided).
8527 static int const kPushPopUseMaxRegCount = -1;
8528
8529 // Test a simple push-pop pattern:
8530 // * Claim <claim> bytes to set the stack alignment.
8531 // * Push <reg_count> registers with size <reg_size>.
8532 // * Clobber the register contents.
8533 // * Pop <reg_count> registers to restore the original contents.
8534 // * Drop <claim> bytes to restore the original stack pointer.
8535 //
8536 // Different push and pop methods can be specified independently to test for
8537 // proper word-endian behaviour.
PushPopSimpleHelper(int reg_count,int claim,int reg_size,PushPopMethod push_method,PushPopMethod pop_method)8538 static void PushPopSimpleHelper(int reg_count,
8539 int claim,
8540 int reg_size,
8541 PushPopMethod push_method,
8542 PushPopMethod pop_method) {
8543 SETUP();
8544
8545 START();
8546
8547 // Arbitrarily pick a register to use as a stack pointer.
8548 const Register& stack_pointer = x20;
8549 const RegList allowed = ~stack_pointer.GetBit();
8550 if (reg_count == kPushPopUseMaxRegCount) {
8551 reg_count = CountSetBits(allowed, kNumberOfRegisters);
8552 }
8553 // Work out which registers to use, based on reg_size.
8554 Register r[kNumberOfRegisters];
8555 Register x[kNumberOfRegisters];
8556 RegList list =
8557 PopulateRegisterArray(NULL, x, r, reg_size, reg_count, allowed);
8558
8559 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
8560 UseScratchRegisterScope temps(&masm);
8561 temps.ExcludeAll();
8562
8563 // The literal base is chosen to have two useful properties:
8564 // * When multiplied by small values (such as a register index), this value
8565 // is clearly readable in the result.
8566 // * The value is not formed from repeating fixed-size smaller values, so it
8567 // can be used to detect endianness-related errors.
8568 uint64_t literal_base = 0x0100001000100101;
8569
8570 {
8571 VIXL_ASSERT(__ StackPointer().Is(sp));
8572 __ Mov(stack_pointer, __ StackPointer());
8573 __ SetStackPointer(stack_pointer);
8574
8575 int i;
8576
8577 // Initialize the registers.
8578 for (i = 0; i < reg_count; i++) {
8579 // Always write into the X register, to ensure that the upper word is
8580 // properly ignored by Push when testing W registers.
8581 __ Mov(x[i], literal_base * i);
8582 }
8583
8584 // Claim memory first, as requested.
8585 __ Claim(claim);
8586
8587 switch (push_method) {
8588 case PushPopByFour:
8589 // Push high-numbered registers first (to the highest addresses).
8590 for (i = reg_count; i >= 4; i -= 4) {
8591 __ Push(r[i - 1], r[i - 2], r[i - 3], r[i - 4]);
8592 }
8593 // Finish off the leftovers.
8594 switch (i) {
8595 case 3:
8596 __ Push(r[2], r[1], r[0]);
8597 break;
8598 case 2:
8599 __ Push(r[1], r[0]);
8600 break;
8601 case 1:
8602 __ Push(r[0]);
8603 break;
8604 default:
8605 VIXL_ASSERT(i == 0);
8606 break;
8607 }
8608 break;
8609 case PushPopRegList:
8610 __ PushSizeRegList(list, reg_size);
8611 break;
8612 }
8613
8614 // Clobber all the registers, to ensure that they get repopulated by Pop.
8615 Clobber(&masm, list);
8616
8617 switch (pop_method) {
8618 case PushPopByFour:
8619 // Pop low-numbered registers first (from the lowest addresses).
8620 for (i = 0; i <= (reg_count - 4); i += 4) {
8621 __ Pop(r[i], r[i + 1], r[i + 2], r[i + 3]);
8622 }
8623 // Finish off the leftovers.
8624 switch (reg_count - i) {
8625 case 3:
8626 __ Pop(r[i], r[i + 1], r[i + 2]);
8627 break;
8628 case 2:
8629 __ Pop(r[i], r[i + 1]);
8630 break;
8631 case 1:
8632 __ Pop(r[i]);
8633 break;
8634 default:
8635 VIXL_ASSERT(i == reg_count);
8636 break;
8637 }
8638 break;
8639 case PushPopRegList:
8640 __ PopSizeRegList(list, reg_size);
8641 break;
8642 }
8643
8644 // Drop memory to restore stack_pointer.
8645 __ Drop(claim);
8646
8647 __ Mov(sp, __ StackPointer());
8648 __ SetStackPointer(sp);
8649 }
8650
8651 END();
8652
8653 if (CAN_RUN()) {
8654 RUN();
8655
8656 // Check that the register contents were preserved.
8657 // Always use ASSERT_EQUAL_64, even when testing W registers, so we can test
8658 // that the upper word was properly cleared by Pop.
8659 literal_base &= (0xffffffffffffffff >> (64 - reg_size));
8660 for (int i = 0; i < reg_count; i++) {
8661 if (x[i].Is(xzr)) {
8662 ASSERT_EQUAL_64(0, x[i]);
8663 } else {
8664 ASSERT_EQUAL_64(literal_base * i, x[i]);
8665 }
8666 }
8667 }
8668 }
8669
8670
TEST(push_pop_xreg_simple_32)8671 TEST(push_pop_xreg_simple_32) {
8672 for (int claim = 0; claim <= 8; claim++) {
8673 for (int count = 0; count <= 8; count++) {
8674 PushPopSimpleHelper(count,
8675 claim,
8676 kWRegSize,
8677 PushPopByFour,
8678 PushPopByFour);
8679 PushPopSimpleHelper(count,
8680 claim,
8681 kWRegSize,
8682 PushPopByFour,
8683 PushPopRegList);
8684 PushPopSimpleHelper(count,
8685 claim,
8686 kWRegSize,
8687 PushPopRegList,
8688 PushPopByFour);
8689 PushPopSimpleHelper(count,
8690 claim,
8691 kWRegSize,
8692 PushPopRegList,
8693 PushPopRegList);
8694 }
8695 // Test with the maximum number of registers.
8696 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8697 claim,
8698 kWRegSize,
8699 PushPopByFour,
8700 PushPopByFour);
8701 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8702 claim,
8703 kWRegSize,
8704 PushPopByFour,
8705 PushPopRegList);
8706 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8707 claim,
8708 kWRegSize,
8709 PushPopRegList,
8710 PushPopByFour);
8711 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8712 claim,
8713 kWRegSize,
8714 PushPopRegList,
8715 PushPopRegList);
8716 }
8717 }
8718
8719
TEST(push_pop_xreg_simple_64)8720 TEST(push_pop_xreg_simple_64) {
8721 for (int claim = 0; claim <= 8; claim++) {
8722 for (int count = 0; count <= 8; count++) {
8723 PushPopSimpleHelper(count,
8724 claim,
8725 kXRegSize,
8726 PushPopByFour,
8727 PushPopByFour);
8728 PushPopSimpleHelper(count,
8729 claim,
8730 kXRegSize,
8731 PushPopByFour,
8732 PushPopRegList);
8733 PushPopSimpleHelper(count,
8734 claim,
8735 kXRegSize,
8736 PushPopRegList,
8737 PushPopByFour);
8738 PushPopSimpleHelper(count,
8739 claim,
8740 kXRegSize,
8741 PushPopRegList,
8742 PushPopRegList);
8743 }
8744 // Test with the maximum number of registers.
8745 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8746 claim,
8747 kXRegSize,
8748 PushPopByFour,
8749 PushPopByFour);
8750 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8751 claim,
8752 kXRegSize,
8753 PushPopByFour,
8754 PushPopRegList);
8755 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8756 claim,
8757 kXRegSize,
8758 PushPopRegList,
8759 PushPopByFour);
8760 PushPopSimpleHelper(kPushPopUseMaxRegCount,
8761 claim,
8762 kXRegSize,
8763 PushPopRegList,
8764 PushPopRegList);
8765 }
8766 }
8767
8768 // For the PushPopFP* tests, use the maximum number of registers that the test
8769 // supports (where a reg_count argument would otherwise be provided).
8770 static int const kPushPopFPUseMaxRegCount = -1;
8771
8772 // Test a simple push-pop pattern:
8773 // * Claim <claim> bytes to set the stack alignment.
8774 // * Push <reg_count> FP registers with size <reg_size>.
8775 // * Clobber the register contents.
8776 // * Pop <reg_count> FP registers to restore the original contents.
8777 // * Drop <claim> bytes to restore the original stack pointer.
8778 //
8779 // Different push and pop methods can be specified independently to test for
8780 // proper word-endian behaviour.
PushPopFPSimpleHelper(int reg_count,int claim,int reg_size,PushPopMethod push_method,PushPopMethod pop_method)8781 static void PushPopFPSimpleHelper(int reg_count,
8782 int claim,
8783 int reg_size,
8784 PushPopMethod push_method,
8785 PushPopMethod pop_method) {
8786 SETUP_WITH_FEATURES((reg_count == 0) ? CPUFeatures::kNone : CPUFeatures::kFP);
8787
8788 START();
8789
8790 // We can use any floating-point register. None of them are reserved for
8791 // debug code, for example.
8792 static RegList const allowed = ~0;
8793 if (reg_count == kPushPopFPUseMaxRegCount) {
8794 reg_count = CountSetBits(allowed, kNumberOfVRegisters);
8795 }
8796 // Work out which registers to use, based on reg_size.
8797 VRegister v[kNumberOfRegisters];
8798 VRegister d[kNumberOfRegisters];
8799 RegList list =
8800 PopulateVRegisterArray(NULL, d, v, reg_size, reg_count, allowed);
8801
8802 // Arbitrarily pick a register to use as a stack pointer.
8803 const Register& stack_pointer = x10;
8804
8805 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
8806 UseScratchRegisterScope temps(&masm);
8807 temps.ExcludeAll();
8808
8809 // The literal base is chosen to have two useful properties:
8810 // * When multiplied (using an integer) by small values (such as a register
8811 // index), this value is clearly readable in the result.
8812 // * The value is not formed from repeating fixed-size smaller values, so it
8813 // can be used to detect endianness-related errors.
8814 // * It is never a floating-point NaN, and will therefore always compare
8815 // equal to itself.
8816 uint64_t literal_base = 0x0100001000100101;
8817
8818 {
8819 VIXL_ASSERT(__ StackPointer().Is(sp));
8820 __ Mov(stack_pointer, __ StackPointer());
8821 __ SetStackPointer(stack_pointer);
8822
8823 int i;
8824
8825 // Initialize the registers, using X registers to load the literal.
8826 __ Mov(x0, 0);
8827 __ Mov(x1, literal_base);
8828 for (i = 0; i < reg_count; i++) {
8829 // Always write into the D register, to ensure that the upper word is
8830 // properly ignored by Push when testing S registers.
8831 __ Fmov(d[i], x0);
8832 // Calculate the next literal.
8833 __ Add(x0, x0, x1);
8834 }
8835
8836 // Claim memory first, as requested.
8837 __ Claim(claim);
8838
8839 switch (push_method) {
8840 case PushPopByFour:
8841 // Push high-numbered registers first (to the highest addresses).
8842 for (i = reg_count; i >= 4; i -= 4) {
8843 __ Push(v[i - 1], v[i - 2], v[i - 3], v[i - 4]);
8844 }
8845 // Finish off the leftovers.
8846 switch (i) {
8847 case 3:
8848 __ Push(v[2], v[1], v[0]);
8849 break;
8850 case 2:
8851 __ Push(v[1], v[0]);
8852 break;
8853 case 1:
8854 __ Push(v[0]);
8855 break;
8856 default:
8857 VIXL_ASSERT(i == 0);
8858 break;
8859 }
8860 break;
8861 case PushPopRegList:
8862 __ PushSizeRegList(list, reg_size, CPURegister::kVRegister);
8863 break;
8864 }
8865
8866 // Clobber all the registers, to ensure that they get repopulated by Pop.
8867 ClobberFP(&masm, list);
8868
8869 switch (pop_method) {
8870 case PushPopByFour:
8871 // Pop low-numbered registers first (from the lowest addresses).
8872 for (i = 0; i <= (reg_count - 4); i += 4) {
8873 __ Pop(v[i], v[i + 1], v[i + 2], v[i + 3]);
8874 }
8875 // Finish off the leftovers.
8876 switch (reg_count - i) {
8877 case 3:
8878 __ Pop(v[i], v[i + 1], v[i + 2]);
8879 break;
8880 case 2:
8881 __ Pop(v[i], v[i + 1]);
8882 break;
8883 case 1:
8884 __ Pop(v[i]);
8885 break;
8886 default:
8887 VIXL_ASSERT(i == reg_count);
8888 break;
8889 }
8890 break;
8891 case PushPopRegList:
8892 __ PopSizeRegList(list, reg_size, CPURegister::kVRegister);
8893 break;
8894 }
8895
8896 // Drop memory to restore the stack pointer.
8897 __ Drop(claim);
8898
8899 __ Mov(sp, __ StackPointer());
8900 __ SetStackPointer(sp);
8901 }
8902
8903 END();
8904
8905 if (CAN_RUN()) {
8906 RUN();
8907
8908 // Check that the register contents were preserved.
8909 // Always use ASSERT_EQUAL_FP64, even when testing S registers, so we can
8910 // test that the upper word was properly cleared by Pop.
8911 literal_base &= (0xffffffffffffffff >> (64 - reg_size));
8912 for (int i = 0; i < reg_count; i++) {
8913 uint64_t literal = literal_base * i;
8914 double expected;
8915 memcpy(&expected, &literal, sizeof(expected));
8916 ASSERT_EQUAL_FP64(expected, d[i]);
8917 }
8918 }
8919 }
8920
8921
TEST(push_pop_fp_xreg_simple_32)8922 TEST(push_pop_fp_xreg_simple_32) {
8923 for (int claim = 0; claim <= 8; claim++) {
8924 for (int count = 0; count <= 8; count++) {
8925 PushPopFPSimpleHelper(count,
8926 claim,
8927 kSRegSize,
8928 PushPopByFour,
8929 PushPopByFour);
8930 PushPopFPSimpleHelper(count,
8931 claim,
8932 kSRegSize,
8933 PushPopByFour,
8934 PushPopRegList);
8935 PushPopFPSimpleHelper(count,
8936 claim,
8937 kSRegSize,
8938 PushPopRegList,
8939 PushPopByFour);
8940 PushPopFPSimpleHelper(count,
8941 claim,
8942 kSRegSize,
8943 PushPopRegList,
8944 PushPopRegList);
8945 }
8946 // Test with the maximum number of registers.
8947 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
8948 claim,
8949 kSRegSize,
8950 PushPopByFour,
8951 PushPopByFour);
8952 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
8953 claim,
8954 kSRegSize,
8955 PushPopByFour,
8956 PushPopRegList);
8957 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
8958 claim,
8959 kSRegSize,
8960 PushPopRegList,
8961 PushPopByFour);
8962 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
8963 claim,
8964 kSRegSize,
8965 PushPopRegList,
8966 PushPopRegList);
8967 }
8968 }
8969
8970
TEST(push_pop_fp_xreg_simple_64)8971 TEST(push_pop_fp_xreg_simple_64) {
8972 for (int claim = 0; claim <= 8; claim++) {
8973 for (int count = 0; count <= 8; count++) {
8974 PushPopFPSimpleHelper(count,
8975 claim,
8976 kDRegSize,
8977 PushPopByFour,
8978 PushPopByFour);
8979 PushPopFPSimpleHelper(count,
8980 claim,
8981 kDRegSize,
8982 PushPopByFour,
8983 PushPopRegList);
8984 PushPopFPSimpleHelper(count,
8985 claim,
8986 kDRegSize,
8987 PushPopRegList,
8988 PushPopByFour);
8989 PushPopFPSimpleHelper(count,
8990 claim,
8991 kDRegSize,
8992 PushPopRegList,
8993 PushPopRegList);
8994 }
8995 // Test with the maximum number of registers.
8996 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
8997 claim,
8998 kDRegSize,
8999 PushPopByFour,
9000 PushPopByFour);
9001 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
9002 claim,
9003 kDRegSize,
9004 PushPopByFour,
9005 PushPopRegList);
9006 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
9007 claim,
9008 kDRegSize,
9009 PushPopRegList,
9010 PushPopByFour);
9011 PushPopFPSimpleHelper(kPushPopFPUseMaxRegCount,
9012 claim,
9013 kDRegSize,
9014 PushPopRegList,
9015 PushPopRegList);
9016 }
9017 }
9018
9019
9020 // Push and pop data using an overlapping combination of Push/Pop and
9021 // RegList-based methods.
PushPopMixedMethodsHelper(int claim,int reg_size)9022 static void PushPopMixedMethodsHelper(int claim, int reg_size) {
9023 SETUP();
9024
9025 // Arbitrarily pick a register to use as a stack pointer.
9026 const Register& stack_pointer = x5;
9027 const RegList allowed = ~stack_pointer.GetBit();
9028 // Work out which registers to use, based on reg_size.
9029 Register r[10];
9030 Register x[10];
9031 PopulateRegisterArray(NULL, x, r, reg_size, 10, allowed);
9032
9033 // Calculate some handy register lists.
9034 RegList r0_to_r3 = 0;
9035 for (int i = 0; i <= 3; i++) {
9036 r0_to_r3 |= x[i].GetBit();
9037 }
9038 RegList r4_to_r5 = 0;
9039 for (int i = 4; i <= 5; i++) {
9040 r4_to_r5 |= x[i].GetBit();
9041 }
9042 RegList r6_to_r9 = 0;
9043 for (int i = 6; i <= 9; i++) {
9044 r6_to_r9 |= x[i].GetBit();
9045 }
9046
9047 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
9048 UseScratchRegisterScope temps(&masm);
9049 temps.ExcludeAll();
9050
9051 // The literal base is chosen to have two useful properties:
9052 // * When multiplied by small values (such as a register index), this value
9053 // is clearly readable in the result.
9054 // * The value is not formed from repeating fixed-size smaller values, so it
9055 // can be used to detect endianness-related errors.
9056 uint64_t literal_base = 0x0100001000100101;
9057
9058 START();
9059 {
9060 VIXL_ASSERT(__ StackPointer().Is(sp));
9061 __ Mov(stack_pointer, __ StackPointer());
9062 __ SetStackPointer(stack_pointer);
9063
9064 // Claim memory first, as requested.
9065 __ Claim(claim);
9066
9067 __ Mov(x[3], literal_base * 3);
9068 __ Mov(x[2], literal_base * 2);
9069 __ Mov(x[1], literal_base * 1);
9070 __ Mov(x[0], literal_base * 0);
9071
9072 __ PushSizeRegList(r0_to_r3, reg_size);
9073 __ Push(r[3], r[2]);
9074
9075 Clobber(&masm, r0_to_r3);
9076 __ PopSizeRegList(r0_to_r3, reg_size);
9077
9078 __ Push(r[2], r[1], r[3], r[0]);
9079
9080 Clobber(&masm, r4_to_r5);
9081 __ Pop(r[4], r[5]);
9082 Clobber(&masm, r6_to_r9);
9083 __ Pop(r[6], r[7], r[8], r[9]);
9084
9085 // Drop memory to restore stack_pointer.
9086 __ Drop(claim);
9087
9088 __ Mov(sp, __ StackPointer());
9089 __ SetStackPointer(sp);
9090 }
9091
9092 END();
9093
9094 if (CAN_RUN()) {
9095 RUN();
9096
9097 // Always use ASSERT_EQUAL_64, even when testing W registers, so we can test
9098 // that the upper word was properly cleared by Pop.
9099 literal_base &= (0xffffffffffffffff >> (64 - reg_size));
9100
9101 ASSERT_EQUAL_64(literal_base * 3, x[9]);
9102 ASSERT_EQUAL_64(literal_base * 2, x[8]);
9103 ASSERT_EQUAL_64(literal_base * 0, x[7]);
9104 ASSERT_EQUAL_64(literal_base * 3, x[6]);
9105 ASSERT_EQUAL_64(literal_base * 1, x[5]);
9106 ASSERT_EQUAL_64(literal_base * 2, x[4]);
9107 }
9108 }
9109
9110
TEST(push_pop_xreg_mixed_methods_64)9111 TEST(push_pop_xreg_mixed_methods_64) {
9112 for (int claim = 0; claim <= 8; claim++) {
9113 PushPopMixedMethodsHelper(claim, kXRegSize);
9114 }
9115 }
9116
9117
TEST(push_pop_xreg_mixed_methods_32)9118 TEST(push_pop_xreg_mixed_methods_32) {
9119 for (int claim = 0; claim <= 8; claim++) {
9120 PushPopMixedMethodsHelper(claim, kWRegSize);
9121 }
9122 }
9123
9124
9125 // Push and pop data using overlapping X- and W-sized quantities.
PushPopWXOverlapHelper(int reg_count,int claim)9126 static void PushPopWXOverlapHelper(int reg_count, int claim) {
9127 SETUP();
9128
9129 // Arbitrarily pick a register to use as a stack pointer.
9130 const Register& stack_pointer = x10;
9131 const RegList allowed = ~stack_pointer.GetBit();
9132 if (reg_count == kPushPopUseMaxRegCount) {
9133 reg_count = CountSetBits(allowed, kNumberOfRegisters);
9134 }
9135 // Work out which registers to use, based on reg_size.
9136 Register w[kNumberOfRegisters];
9137 Register x[kNumberOfRegisters];
9138 RegList list = PopulateRegisterArray(w, x, NULL, 0, reg_count, allowed);
9139
9140 // The number of W-sized slots we expect to pop. When we pop, we alternate
9141 // between W and X registers, so we need reg_count*1.5 W-sized slots.
9142 int const requested_w_slots = reg_count + reg_count / 2;
9143
9144 // Track what _should_ be on the stack, using W-sized slots.
9145 static int const kMaxWSlots = kNumberOfRegisters + kNumberOfRegisters / 2;
9146 uint32_t stack[kMaxWSlots];
9147 for (int i = 0; i < kMaxWSlots; i++) {
9148 stack[i] = 0xdeadbeef;
9149 }
9150
9151 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
9152 UseScratchRegisterScope temps(&masm);
9153 temps.ExcludeAll();
9154
9155 // The literal base is chosen to have two useful properties:
9156 // * When multiplied by small values (such as a register index), this value
9157 // is clearly readable in the result.
9158 // * The value is not formed from repeating fixed-size smaller values, so it
9159 // can be used to detect endianness-related errors.
9160 static uint64_t const literal_base = 0x0100001000100101;
9161 static uint64_t const literal_base_hi = literal_base >> 32;
9162 static uint64_t const literal_base_lo = literal_base & 0xffffffff;
9163 static uint64_t const literal_base_w = literal_base & 0xffffffff;
9164
9165 START();
9166 {
9167 VIXL_ASSERT(__ StackPointer().Is(sp));
9168 __ Mov(stack_pointer, __ StackPointer());
9169 __ SetStackPointer(stack_pointer);
9170
9171 // Initialize the registers.
9172 for (int i = 0; i < reg_count; i++) {
9173 // Always write into the X register, to ensure that the upper word is
9174 // properly ignored by Push when testing W registers.
9175 __ Mov(x[i], literal_base * i);
9176 }
9177
9178 // Claim memory first, as requested.
9179 __ Claim(claim);
9180
9181 // The push-pop pattern is as follows:
9182 // Push: Pop:
9183 // x[0](hi) -> w[0]
9184 // x[0](lo) -> x[1](hi)
9185 // w[1] -> x[1](lo)
9186 // w[1] -> w[2]
9187 // x[2](hi) -> x[2](hi)
9188 // x[2](lo) -> x[2](lo)
9189 // x[2](hi) -> w[3]
9190 // x[2](lo) -> x[4](hi)
9191 // x[2](hi) -> x[4](lo)
9192 // x[2](lo) -> w[5]
9193 // w[3] -> x[5](hi)
9194 // w[3] -> x[6](lo)
9195 // w[3] -> w[7]
9196 // w[3] -> x[8](hi)
9197 // x[4](hi) -> x[8](lo)
9198 // x[4](lo) -> w[9]
9199 // ... pattern continues ...
9200 //
9201 // That is, registers are pushed starting with the lower numbers,
9202 // alternating between x and w registers, and pushing i%4+1 copies of each,
9203 // where i is the register number.
9204 // Registers are popped starting with the higher numbers one-by-one,
9205 // alternating between x and w registers, but only popping one at a time.
9206 //
9207 // This pattern provides a wide variety of alignment effects and overlaps.
9208
9209 // ---- Push ----
9210
9211 int active_w_slots = 0;
9212 for (int i = 0; active_w_slots < requested_w_slots; i++) {
9213 VIXL_ASSERT(i < reg_count);
9214 // In order to test various arguments to PushMultipleTimes, and to try to
9215 // exercise different alignment and overlap effects, we push each
9216 // register a different number of times.
9217 int times = i % 4 + 1;
9218 if (i & 1) {
9219 // Push odd-numbered registers as W registers.
9220 __ PushMultipleTimes(times, w[i]);
9221 // Fill in the expected stack slots.
9222 for (int j = 0; j < times; j++) {
9223 if (w[i].Is(wzr)) {
9224 // The zero register always writes zeroes.
9225 stack[active_w_slots++] = 0;
9226 } else {
9227 stack[active_w_slots++] = literal_base_w * i;
9228 }
9229 }
9230 } else {
9231 // Push even-numbered registers as X registers.
9232 __ PushMultipleTimes(times, x[i]);
9233 // Fill in the expected stack slots.
9234 for (int j = 0; j < times; j++) {
9235 if (x[i].Is(xzr)) {
9236 // The zero register always writes zeroes.
9237 stack[active_w_slots++] = 0;
9238 stack[active_w_slots++] = 0;
9239 } else {
9240 stack[active_w_slots++] = literal_base_hi * i;
9241 stack[active_w_slots++] = literal_base_lo * i;
9242 }
9243 }
9244 }
9245 }
9246 // Because we were pushing several registers at a time, we probably pushed
9247 // more than we needed to.
9248 if (active_w_slots > requested_w_slots) {
9249 __ Drop((active_w_slots - requested_w_slots) * kWRegSizeInBytes);
9250 // Bump the number of active W-sized slots back to where it should be,
9251 // and fill the empty space with a placeholder value.
9252 do {
9253 stack[active_w_slots--] = 0xdeadbeef;
9254 } while (active_w_slots > requested_w_slots);
9255 }
9256
9257 // ---- Pop ----
9258
9259 Clobber(&masm, list);
9260
9261 // If popping an even number of registers, the first one will be X-sized.
9262 // Otherwise, the first one will be W-sized.
9263 bool next_is_64 = !(reg_count & 1);
9264 for (int i = reg_count - 1; i >= 0; i--) {
9265 if (next_is_64) {
9266 __ Pop(x[i]);
9267 active_w_slots -= 2;
9268 } else {
9269 __ Pop(w[i]);
9270 active_w_slots -= 1;
9271 }
9272 next_is_64 = !next_is_64;
9273 }
9274 VIXL_ASSERT(active_w_slots == 0);
9275
9276 // Drop memory to restore stack_pointer.
9277 __ Drop(claim);
9278
9279 __ Mov(sp, __ StackPointer());
9280 __ SetStackPointer(sp);
9281 }
9282
9283 END();
9284
9285 if (CAN_RUN()) {
9286 RUN();
9287
9288 int slot = 0;
9289 for (int i = 0; i < reg_count; i++) {
9290 // Even-numbered registers were written as W registers.
9291 // Odd-numbered registers were written as X registers.
9292 bool expect_64 = (i & 1);
9293 uint64_t expected;
9294
9295 if (expect_64) {
9296 uint64_t hi = stack[slot++];
9297 uint64_t lo = stack[slot++];
9298 expected = (hi << 32) | lo;
9299 } else {
9300 expected = stack[slot++];
9301 }
9302
9303 // Always use ASSERT_EQUAL_64, even when testing W registers, so we can
9304 // test that the upper word was properly cleared by Pop.
9305 if (x[i].Is(xzr)) {
9306 ASSERT_EQUAL_64(0, x[i]);
9307 } else {
9308 ASSERT_EQUAL_64(expected, x[i]);
9309 }
9310 }
9311 VIXL_ASSERT(slot == requested_w_slots);
9312 }
9313 }
9314
9315
TEST(push_pop_xreg_wx_overlap)9316 TEST(push_pop_xreg_wx_overlap) {
9317 for (int claim = 0; claim <= 8; claim++) {
9318 for (int count = 1; count <= 8; count++) {
9319 PushPopWXOverlapHelper(count, claim);
9320 }
9321 // Test with the maximum number of registers.
9322 PushPopWXOverlapHelper(kPushPopUseMaxRegCount, claim);
9323 }
9324 }
9325
9326
TEST(push_pop_sp)9327 TEST(push_pop_sp) {
9328 SETUP();
9329
9330 START();
9331
9332 VIXL_ASSERT(sp.Is(__ StackPointer()));
9333
9334 // Acquire all temps from the MacroAssembler. They are used arbitrarily below.
9335 UseScratchRegisterScope temps(&masm);
9336 temps.ExcludeAll();
9337
9338 __ Mov(x3, 0x3333333333333333);
9339 __ Mov(x2, 0x2222222222222222);
9340 __ Mov(x1, 0x1111111111111111);
9341 __ Mov(x0, 0x0000000000000000);
9342 __ Claim(2 * kXRegSizeInBytes);
9343 __ PushXRegList(x0.GetBit() | x1.GetBit() | x2.GetBit() | x3.GetBit());
9344 __ Push(x3, x2);
9345 __ PopXRegList(x0.GetBit() | x1.GetBit() | x2.GetBit() | x3.GetBit());
9346 __ Push(x2, x1, x3, x0);
9347 __ Pop(x4, x5);
9348 __ Pop(x6, x7, x8, x9);
9349
9350 __ Claim(2 * kXRegSizeInBytes);
9351 __ PushWRegList(w0.GetBit() | w1.GetBit() | w2.GetBit() | w3.GetBit());
9352 __ Push(w3, w1, w2, w0);
9353 __ PopWRegList(w10.GetBit() | w11.GetBit() | w12.GetBit() | w13.GetBit());
9354 __ Pop(w14, w15, w16, w17);
9355
9356 __ Claim(2 * kXRegSizeInBytes);
9357 __ Push(w2, w2, w1, w1);
9358 __ Push(x3, x3);
9359 __ Pop(w18, w19, w20, w21);
9360 __ Pop(x22, x23);
9361
9362 __ Claim(2 * kXRegSizeInBytes);
9363 __ PushXRegList(x1.GetBit() | x22.GetBit());
9364 __ PopXRegList(x24.GetBit() | x26.GetBit());
9365
9366 __ Claim(2 * kXRegSizeInBytes);
9367 __ PushWRegList(w1.GetBit() | w2.GetBit() | w4.GetBit() | w22.GetBit());
9368 __ PopWRegList(w25.GetBit() | w27.GetBit() | w28.GetBit() | w29.GetBit());
9369
9370 __ Claim(2 * kXRegSizeInBytes);
9371 __ PushXRegList(0);
9372 __ PopXRegList(0);
9373 __ PushXRegList(0xffffffff);
9374 __ PopXRegList(0xffffffff);
9375 __ Drop(12 * kXRegSizeInBytes);
9376 END();
9377
9378 if (CAN_RUN()) {
9379 RUN();
9380
9381 ASSERT_EQUAL_64(0x1111111111111111, x3);
9382 ASSERT_EQUAL_64(0x0000000000000000, x2);
9383 ASSERT_EQUAL_64(0x3333333333333333, x1);
9384 ASSERT_EQUAL_64(0x2222222222222222, x0);
9385 ASSERT_EQUAL_64(0x3333333333333333, x9);
9386 ASSERT_EQUAL_64(0x2222222222222222, x8);
9387 ASSERT_EQUAL_64(0x0000000000000000, x7);
9388 ASSERT_EQUAL_64(0x3333333333333333, x6);
9389 ASSERT_EQUAL_64(0x1111111111111111, x5);
9390 ASSERT_EQUAL_64(0x2222222222222222, x4);
9391
9392 ASSERT_EQUAL_32(0x11111111U, w13);
9393 ASSERT_EQUAL_32(0x33333333U, w12);
9394 ASSERT_EQUAL_32(0x00000000U, w11);
9395 ASSERT_EQUAL_32(0x22222222U, w10);
9396 ASSERT_EQUAL_32(0x11111111U, w17);
9397 ASSERT_EQUAL_32(0x00000000U, w16);
9398 ASSERT_EQUAL_32(0x33333333U, w15);
9399 ASSERT_EQUAL_32(0x22222222U, w14);
9400
9401 ASSERT_EQUAL_32(0x11111111U, w18);
9402 ASSERT_EQUAL_32(0x11111111U, w19);
9403 ASSERT_EQUAL_32(0x11111111U, w20);
9404 ASSERT_EQUAL_32(0x11111111U, w21);
9405 ASSERT_EQUAL_64(0x3333333333333333, x22);
9406 ASSERT_EQUAL_64(0x0000000000000000, x23);
9407
9408 ASSERT_EQUAL_64(0x3333333333333333, x24);
9409 ASSERT_EQUAL_64(0x3333333333333333, x26);
9410
9411 ASSERT_EQUAL_32(0x33333333U, w25);
9412 ASSERT_EQUAL_32(0x00000000U, w27);
9413 ASSERT_EQUAL_32(0x22222222U, w28);
9414 ASSERT_EQUAL_32(0x33333333U, w29);
9415 }
9416 }
9417
9418
TEST(printf)9419 TEST(printf) {
9420 // RegisterDump::Dump uses NEON.
9421 // Printf uses FP to cast FP arguments to doubles.
9422 SETUP_WITH_FEATURES(CPUFeatures::kNEON, CPUFeatures::kFP);
9423
9424 START();
9425
9426 char const* test_plain_string = "Printf with no arguments.\n";
9427 char const* test_substring = "'This is a substring.'";
9428 RegisterDump before;
9429
9430 // Initialize x29 to the value of the stack pointer. We will use x29 as a
9431 // temporary stack pointer later, and initializing it in this way allows the
9432 // RegisterDump check to pass.
9433 __ Mov(x29, __ StackPointer());
9434
9435 // Test simple integer arguments.
9436 __ Mov(x0, 1234);
9437 __ Mov(x1, 0x1234);
9438
9439 // Test simple floating-point arguments.
9440 __ Fmov(d0, 1.234);
9441
9442 // Test pointer (string) arguments.
9443 __ Mov(x2, reinterpret_cast<uintptr_t>(test_substring));
9444
9445 // Test the maximum number of arguments, and sign extension.
9446 __ Mov(w3, 0xffffffff);
9447 __ Mov(w4, 0xffffffff);
9448 __ Mov(x5, 0xffffffffffffffff);
9449 __ Mov(x6, 0xffffffffffffffff);
9450 __ Fmov(s1, 1.234);
9451 __ Fmov(s2, 2.345);
9452 __ Fmov(d3, 3.456);
9453 __ Fmov(d4, 4.567);
9454
9455 // Test printing callee-saved registers.
9456 __ Mov(x28, 0x123456789abcdef);
9457 __ Fmov(d10, 42.0);
9458
9459 // Test with three arguments.
9460 __ Mov(x10, 3);
9461 __ Mov(x11, 40);
9462 __ Mov(x12, 500);
9463
9464 // A single character.
9465 __ Mov(w13, 'x');
9466
9467 // Check that we don't clobber any registers.
9468 before.Dump(&masm);
9469
9470 __ Printf(test_plain_string); // NOLINT(runtime/printf)
9471 __ Printf("x0: %" PRId64 ", x1: 0x%08" PRIx64 "\n", x0, x1);
9472 __ Printf("w5: %" PRId32 ", x5: %" PRId64 "\n", w5, x5);
9473 __ Printf("d0: %f\n", d0);
9474 __ Printf("Test %%s: %s\n", x2);
9475 __ Printf("w3(uint32): %" PRIu32 "\nw4(int32): %" PRId32
9476 "\n"
9477 "x5(uint64): %" PRIu64 "\nx6(int64): %" PRId64 "\n",
9478 w3,
9479 w4,
9480 x5,
9481 x6);
9482 __ Printf("%%f: %f\n%%g: %g\n%%e: %e\n%%E: %E\n", s1, s2, d3, d4);
9483 __ Printf("0x%" PRIx32 ", 0x%" PRIx64 "\n", w28, x28);
9484 __ Printf("%g\n", d10);
9485 __ Printf("%%%%%s%%%c%%\n", x2, w13);
9486
9487 // Print the stack pointer (sp).
9488 __ Printf("StackPointer(sp): 0x%016" PRIx64 ", 0x%08" PRIx32 "\n",
9489 __ StackPointer(),
9490 __ StackPointer().W());
9491
9492 // Test with a different stack pointer.
9493 const Register old_stack_pointer = __ StackPointer();
9494 __ Mov(x29, old_stack_pointer);
9495 __ SetStackPointer(x29);
9496 // Print the stack pointer (not sp).
9497 __ Printf("StackPointer(not sp): 0x%016" PRIx64 ", 0x%08" PRIx32 "\n",
9498 __ StackPointer(),
9499 __ StackPointer().W());
9500 __ Mov(old_stack_pointer, __ StackPointer());
9501 __ SetStackPointer(old_stack_pointer);
9502
9503 // Test with three arguments.
9504 __ Printf("3=%u, 4=%u, 5=%u\n", x10, x11, x12);
9505
9506 // Mixed argument types.
9507 __ Printf("w3: %" PRIu32 ", s1: %f, x5: %" PRIu64 ", d3: %f\n",
9508 w3,
9509 s1,
9510 x5,
9511 d3);
9512 __ Printf("s1: %f, d3: %f, w3: %" PRId32 ", x5: %" PRId64 "\n",
9513 s1,
9514 d3,
9515 w3,
9516 x5);
9517
9518 END();
9519 if (CAN_RUN()) {
9520 RUN();
9521
9522 // We cannot easily test the output of the Printf sequences, and because
9523 // Printf preserves all registers by default, we can't look at the number of
9524 // bytes that were printed. However, the printf_no_preserve test should
9525 // check
9526 // that, and here we just test that we didn't clobber any registers.
9527 ASSERT_EQUAL_REGISTERS(before);
9528 }
9529 }
9530
9531
TEST(printf_no_preserve)9532 TEST(printf_no_preserve) {
9533 // PrintfNoPreserve uses FP to cast FP arguments to doubles.
9534 SETUP_WITH_FEATURES(CPUFeatures::kFP);
9535
9536 START();
9537
9538 char const* test_plain_string = "Printf with no arguments.\n";
9539 char const* test_substring = "'This is a substring.'";
9540
9541 __ PrintfNoPreserve(test_plain_string);
9542 __ Mov(x19, x0);
9543
9544 // Test simple integer arguments.
9545 __ Mov(x0, 1234);
9546 __ Mov(x1, 0x1234);
9547 __ PrintfNoPreserve("x0: %" PRId64 ", x1: 0x%08" PRIx64 "\n", x0, x1);
9548 __ Mov(x20, x0);
9549
9550 // Test simple floating-point arguments.
9551 __ Fmov(d0, 1.234);
9552 __ PrintfNoPreserve("d0: %f\n", d0);
9553 __ Mov(x21, x0);
9554
9555 // Test pointer (string) arguments.
9556 __ Mov(x2, reinterpret_cast<uintptr_t>(test_substring));
9557 __ PrintfNoPreserve("Test %%s: %s\n", x2);
9558 __ Mov(x22, x0);
9559
9560 // Test the maximum number of arguments, and sign extension.
9561 __ Mov(w3, 0xffffffff);
9562 __ Mov(w4, 0xffffffff);
9563 __ Mov(x5, 0xffffffffffffffff);
9564 __ Mov(x6, 0xffffffffffffffff);
9565 __ PrintfNoPreserve("w3(uint32): %" PRIu32 "\nw4(int32): %" PRId32
9566 "\n"
9567 "x5(uint64): %" PRIu64 "\nx6(int64): %" PRId64 "\n",
9568 w3,
9569 w4,
9570 x5,
9571 x6);
9572 __ Mov(x23, x0);
9573
9574 __ Fmov(s1, 1.234);
9575 __ Fmov(s2, 2.345);
9576 __ Fmov(d3, 3.456);
9577 __ Fmov(d4, 4.567);
9578 __ PrintfNoPreserve("%%f: %f\n%%g: %g\n%%e: %e\n%%E: %E\n", s1, s2, d3, d4);
9579 __ Mov(x24, x0);
9580
9581 // Test printing callee-saved registers.
9582 __ Mov(x28, 0x123456789abcdef);
9583 __ PrintfNoPreserve("0x%" PRIx32 ", 0x%" PRIx64 "\n", w28, x28);
9584 __ Mov(x25, x0);
9585
9586 __ Fmov(d10, 42.0);
9587 __ PrintfNoPreserve("%g\n", d10);
9588 __ Mov(x26, x0);
9589
9590 // Test with a different stack pointer.
9591 const Register old_stack_pointer = __ StackPointer();
9592 __ Mov(x29, old_stack_pointer);
9593 __ SetStackPointer(x29);
9594 // Print the stack pointer (not sp).
9595 __ PrintfNoPreserve("StackPointer(not sp): 0x%016" PRIx64 ", 0x%08" PRIx32
9596 "\n",
9597 __ StackPointer(),
9598 __ StackPointer().W());
9599 __ Mov(x27, x0);
9600 __ Mov(old_stack_pointer, __ StackPointer());
9601 __ SetStackPointer(old_stack_pointer);
9602
9603 // Test with three arguments.
9604 __ Mov(x3, 3);
9605 __ Mov(x4, 40);
9606 __ Mov(x5, 500);
9607 __ PrintfNoPreserve("3=%u, 4=%u, 5=%u\n", x3, x4, x5);
9608 __ Mov(x28, x0);
9609
9610 // Mixed argument types.
9611 __ Mov(w3, 0xffffffff);
9612 __ Fmov(s1, 1.234);
9613 __ Mov(x5, 0xffffffffffffffff);
9614 __ Fmov(d3, 3.456);
9615 __ PrintfNoPreserve("w3: %" PRIu32 ", s1: %f, x5: %" PRIu64 ", d3: %f\n",
9616 w3,
9617 s1,
9618 x5,
9619 d3);
9620 __ Mov(x29, x0);
9621
9622 END();
9623 if (CAN_RUN()) {
9624 RUN();
9625
9626 // We cannot easily test the exact output of the Printf sequences, but we
9627 // can
9628 // use the return code to check that the string length was correct.
9629
9630 // Printf with no arguments.
9631 ASSERT_EQUAL_64(strlen(test_plain_string), x19);
9632 // x0: 1234, x1: 0x00001234
9633 ASSERT_EQUAL_64(25, x20);
9634 // d0: 1.234000
9635 ASSERT_EQUAL_64(13, x21);
9636 // Test %s: 'This is a substring.'
9637 ASSERT_EQUAL_64(32, x22);
9638 // w3(uint32): 4294967295
9639 // w4(int32): -1
9640 // x5(uint64): 18446744073709551615
9641 // x6(int64): -1
9642 ASSERT_EQUAL_64(23 + 14 + 33 + 14, x23);
9643 // %f: 1.234000
9644 // %g: 2.345
9645 // %e: 3.456000e+00
9646 // %E: 4.567000E+00
9647 ASSERT_EQUAL_64(13 + 10 + 17 + 17, x24);
9648 // 0x89abcdef, 0x123456789abcdef
9649 ASSERT_EQUAL_64(30, x25);
9650 // 42
9651 ASSERT_EQUAL_64(3, x26);
9652 // StackPointer(not sp): 0x00007fb037ae2370, 0x37ae2370
9653 // Note: This is an example value, but the field width is fixed here so the
9654 // string length is still predictable.
9655 ASSERT_EQUAL_64(53, x27);
9656 // 3=3, 4=40, 5=500
9657 ASSERT_EQUAL_64(17, x28);
9658 // w3: 4294967295, s1: 1.234000, x5: 18446744073709551615, d3: 3.456000
9659 ASSERT_EQUAL_64(69, x29);
9660 }
9661 }
9662
9663
TEST(trace)9664 TEST(trace) {
9665 // The Trace helper should not generate any code unless the simulator is being
9666 // used.
9667 SETUP();
9668 START();
9669
9670 Label start;
9671 __ Bind(&start);
9672 __ Trace(LOG_ALL, TRACE_ENABLE);
9673 __ Trace(LOG_ALL, TRACE_DISABLE);
9674 if (masm.GenerateSimulatorCode()) {
9675 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&start) > 0);
9676 } else {
9677 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&start) == 0);
9678 }
9679
9680 END();
9681 }
9682
9683
TEST(log)9684 TEST(log) {
9685 // The Log helper should not generate any code unless the simulator is being
9686 // used.
9687 SETUP();
9688 START();
9689
9690 Label start;
9691 __ Bind(&start);
9692 __ Log(LOG_ALL);
9693 if (masm.GenerateSimulatorCode()) {
9694 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&start) > 0);
9695 } else {
9696 VIXL_CHECK(__ GetSizeOfCodeGeneratedSince(&start) == 0);
9697 }
9698
9699 END();
9700 }
9701
9702
TEST(blr_lr)9703 TEST(blr_lr) {
9704 // A simple test to check that the simulator correctly handle "blr lr".
9705 SETUP();
9706
9707 START();
9708 Label target;
9709 Label end;
9710
9711 __ Mov(x0, 0x0);
9712 __ Adr(lr, &target);
9713
9714 __ Blr(lr);
9715 __ Mov(x0, 0xdeadbeef);
9716 __ B(&end);
9717
9718 __ Bind(&target);
9719 __ Mov(x0, 0xc001c0de);
9720
9721 __ Bind(&end);
9722 END();
9723
9724 if (CAN_RUN()) {
9725 RUN();
9726
9727 ASSERT_EQUAL_64(0xc001c0de, x0);
9728 }
9729 }
9730
9731
TEST(barriers)9732 TEST(barriers) {
9733 // Generate all supported barriers, this is just a smoke test
9734 SETUP();
9735
9736 START();
9737
9738 // DMB
9739 __ Dmb(FullSystem, BarrierAll);
9740 __ Dmb(FullSystem, BarrierReads);
9741 __ Dmb(FullSystem, BarrierWrites);
9742 __ Dmb(FullSystem, BarrierOther);
9743
9744 __ Dmb(InnerShareable, BarrierAll);
9745 __ Dmb(InnerShareable, BarrierReads);
9746 __ Dmb(InnerShareable, BarrierWrites);
9747 __ Dmb(InnerShareable, BarrierOther);
9748
9749 __ Dmb(NonShareable, BarrierAll);
9750 __ Dmb(NonShareable, BarrierReads);
9751 __ Dmb(NonShareable, BarrierWrites);
9752 __ Dmb(NonShareable, BarrierOther);
9753
9754 __ Dmb(OuterShareable, BarrierAll);
9755 __ Dmb(OuterShareable, BarrierReads);
9756 __ Dmb(OuterShareable, BarrierWrites);
9757 __ Dmb(OuterShareable, BarrierOther);
9758
9759 // DSB
9760 __ Dsb(FullSystem, BarrierAll);
9761 __ Dsb(FullSystem, BarrierReads);
9762 __ Dsb(FullSystem, BarrierWrites);
9763 __ Dsb(FullSystem, BarrierOther);
9764
9765 __ Dsb(InnerShareable, BarrierAll);
9766 __ Dsb(InnerShareable, BarrierReads);
9767 __ Dsb(InnerShareable, BarrierWrites);
9768 __ Dsb(InnerShareable, BarrierOther);
9769
9770 __ Dsb(NonShareable, BarrierAll);
9771 __ Dsb(NonShareable, BarrierReads);
9772 __ Dsb(NonShareable, BarrierWrites);
9773 __ Dsb(NonShareable, BarrierOther);
9774
9775 __ Dsb(OuterShareable, BarrierAll);
9776 __ Dsb(OuterShareable, BarrierReads);
9777 __ Dsb(OuterShareable, BarrierWrites);
9778 __ Dsb(OuterShareable, BarrierOther);
9779
9780 // ISB
9781 __ Isb();
9782
9783 END();
9784
9785 if (CAN_RUN()) {
9786 RUN();
9787 }
9788 }
9789
9790
TEST(ldar_stlr)9791 TEST(ldar_stlr) {
9792 // The middle value is read, modified, and written. The padding exists only to
9793 // check for over-write.
9794 uint8_t b[] = {0, 0x12, 0};
9795 uint16_t h[] = {0, 0x1234, 0};
9796 uint32_t w[] = {0, 0x12345678, 0};
9797 uint64_t x[] = {0, 0x123456789abcdef0, 0};
9798
9799 SETUP();
9800 START();
9801
9802 __ Mov(x10, reinterpret_cast<uintptr_t>(&b[1]));
9803 __ Ldarb(w0, MemOperand(x10));
9804 __ Add(w0, w0, 1);
9805 __ Stlrb(w0, MemOperand(x10));
9806
9807 __ Mov(x10, reinterpret_cast<uintptr_t>(&h[1]));
9808 __ Ldarh(w0, MemOperand(x10));
9809 __ Add(w0, w0, 1);
9810 __ Stlrh(w0, MemOperand(x10));
9811
9812 __ Mov(x10, reinterpret_cast<uintptr_t>(&w[1]));
9813 __ Ldar(w0, MemOperand(x10));
9814 __ Add(w0, w0, 1);
9815 __ Stlr(w0, MemOperand(x10));
9816
9817 __ Mov(x10, reinterpret_cast<uintptr_t>(&x[1]));
9818 __ Ldar(x0, MemOperand(x10));
9819 __ Add(x0, x0, 1);
9820 __ Stlr(x0, MemOperand(x10));
9821
9822 END();
9823 if (CAN_RUN()) {
9824 RUN();
9825
9826 ASSERT_EQUAL_32(0x13, b[1]);
9827 ASSERT_EQUAL_32(0x1235, h[1]);
9828 ASSERT_EQUAL_32(0x12345679, w[1]);
9829 ASSERT_EQUAL_64(0x123456789abcdef1, x[1]);
9830
9831 // Check for over-write.
9832 ASSERT_EQUAL_32(0, b[0]);
9833 ASSERT_EQUAL_32(0, b[2]);
9834 ASSERT_EQUAL_32(0, h[0]);
9835 ASSERT_EQUAL_32(0, h[2]);
9836 ASSERT_EQUAL_32(0, w[0]);
9837 ASSERT_EQUAL_32(0, w[2]);
9838 ASSERT_EQUAL_64(0, x[0]);
9839 ASSERT_EQUAL_64(0, x[2]);
9840 }
9841 }
9842
9843
TEST(ldlar_stllr)9844 TEST(ldlar_stllr) {
9845 // The middle value is read, modified, and written. The padding exists only to
9846 // check for over-write.
9847 uint8_t b[] = {0, 0x12, 0};
9848 uint16_t h[] = {0, 0x1234, 0};
9849 uint32_t w[] = {0, 0x12345678, 0};
9850 uint64_t x[] = {0, 0x123456789abcdef0, 0};
9851
9852 SETUP_WITH_FEATURES(CPUFeatures::kLORegions);
9853
9854 START();
9855
9856 __ Mov(x10, reinterpret_cast<uintptr_t>(&b[1]));
9857 __ Ldlarb(w0, MemOperand(x10));
9858 __ Add(w0, w0, 1);
9859 __ Stllrb(w0, MemOperand(x10));
9860
9861 __ Mov(x10, reinterpret_cast<uintptr_t>(&h[1]));
9862 __ Ldlarh(w0, MemOperand(x10));
9863 __ Add(w0, w0, 1);
9864 __ Stllrh(w0, MemOperand(x10));
9865
9866 __ Mov(x10, reinterpret_cast<uintptr_t>(&w[1]));
9867 __ Ldlar(w0, MemOperand(x10));
9868 __ Add(w0, w0, 1);
9869 __ Stllr(w0, MemOperand(x10));
9870
9871 __ Mov(x10, reinterpret_cast<uintptr_t>(&x[1]));
9872 __ Ldlar(x0, MemOperand(x10));
9873 __ Add(x0, x0, 1);
9874 __ Stllr(x0, MemOperand(x10));
9875
9876 END();
9877
9878 if (CAN_RUN()) {
9879 RUN();
9880
9881 ASSERT_EQUAL_32(0x13, b[1]);
9882 ASSERT_EQUAL_32(0x1235, h[1]);
9883 ASSERT_EQUAL_32(0x12345679, w[1]);
9884 ASSERT_EQUAL_64(0x123456789abcdef1, x[1]);
9885
9886 // Check for over-write.
9887 ASSERT_EQUAL_32(0, b[0]);
9888 ASSERT_EQUAL_32(0, b[2]);
9889 ASSERT_EQUAL_32(0, h[0]);
9890 ASSERT_EQUAL_32(0, h[2]);
9891 ASSERT_EQUAL_32(0, w[0]);
9892 ASSERT_EQUAL_32(0, w[2]);
9893 ASSERT_EQUAL_64(0, x[0]);
9894 ASSERT_EQUAL_64(0, x[2]);
9895 }
9896 }
9897
9898
TEST(ldxr_stxr)9899 TEST(ldxr_stxr) {
9900 // The middle value is read, modified, and written. The padding exists only to
9901 // check for over-write.
9902 uint8_t b[] = {0, 0x12, 0};
9903 uint16_t h[] = {0, 0x1234, 0};
9904 uint32_t w[] = {0, 0x12345678, 0};
9905 uint64_t x[] = {0, 0x123456789abcdef0, 0};
9906
9907 // As above, but get suitably-aligned values for ldxp and stxp.
9908 uint32_t wp_data[] = {0, 0, 0, 0, 0};
9909 uint32_t* wp = AlignUp(wp_data + 1, kWRegSizeInBytes * 2) - 1;
9910 wp[1] = 0x12345678; // wp[1] is 64-bit-aligned.
9911 wp[2] = 0x87654321;
9912 uint64_t xp_data[] = {0, 0, 0, 0, 0};
9913 uint64_t* xp = AlignUp(xp_data + 1, kXRegSizeInBytes * 2) - 1;
9914 xp[1] = 0x123456789abcdef0; // xp[1] is 128-bit-aligned.
9915 xp[2] = 0x0fedcba987654321;
9916
9917 SETUP();
9918 START();
9919
9920 __ Mov(x10, reinterpret_cast<uintptr_t>(&b[1]));
9921 Label try_b;
9922 __ Bind(&try_b);
9923 __ Ldxrb(w0, MemOperand(x10));
9924 __ Add(w0, w0, 1);
9925 __ Stxrb(w5, w0, MemOperand(x10));
9926 __ Cbnz(w5, &try_b);
9927
9928 __ Mov(x10, reinterpret_cast<uintptr_t>(&h[1]));
9929 Label try_h;
9930 __ Bind(&try_h);
9931 __ Ldxrh(w0, MemOperand(x10));
9932 __ Add(w0, w0, 1);
9933 __ Stxrh(w5, w0, MemOperand(x10));
9934 __ Cbnz(w5, &try_h);
9935
9936 __ Mov(x10, reinterpret_cast<uintptr_t>(&w[1]));
9937 Label try_w;
9938 __ Bind(&try_w);
9939 __ Ldxr(w0, MemOperand(x10));
9940 __ Add(w0, w0, 1);
9941 __ Stxr(w5, w0, MemOperand(x10));
9942 __ Cbnz(w5, &try_w);
9943
9944 __ Mov(x10, reinterpret_cast<uintptr_t>(&x[1]));
9945 Label try_x;
9946 __ Bind(&try_x);
9947 __ Ldxr(x0, MemOperand(x10));
9948 __ Add(x0, x0, 1);
9949 __ Stxr(w5, x0, MemOperand(x10));
9950 __ Cbnz(w5, &try_x);
9951
9952 __ Mov(x10, reinterpret_cast<uintptr_t>(&wp[1]));
9953 Label try_wp;
9954 __ Bind(&try_wp);
9955 __ Ldxp(w0, w1, MemOperand(x10));
9956 __ Add(w0, w0, 1);
9957 __ Add(w1, w1, 1);
9958 __ Stxp(w5, w0, w1, MemOperand(x10));
9959 __ Cbnz(w5, &try_wp);
9960
9961 __ Mov(x10, reinterpret_cast<uintptr_t>(&xp[1]));
9962 Label try_xp;
9963 __ Bind(&try_xp);
9964 __ Ldxp(x0, x1, MemOperand(x10));
9965 __ Add(x0, x0, 1);
9966 __ Add(x1, x1, 1);
9967 __ Stxp(w5, x0, x1, MemOperand(x10));
9968 __ Cbnz(w5, &try_xp);
9969
9970 END();
9971 if (CAN_RUN()) {
9972 RUN();
9973
9974 ASSERT_EQUAL_32(0x13, b[1]);
9975 ASSERT_EQUAL_32(0x1235, h[1]);
9976 ASSERT_EQUAL_32(0x12345679, w[1]);
9977 ASSERT_EQUAL_64(0x123456789abcdef1, x[1]);
9978 ASSERT_EQUAL_32(0x12345679, wp[1]);
9979 ASSERT_EQUAL_32(0x87654322, wp[2]);
9980 ASSERT_EQUAL_64(0x123456789abcdef1, xp[1]);
9981 ASSERT_EQUAL_64(0x0fedcba987654322, xp[2]);
9982
9983 // Check for over-write.
9984 ASSERT_EQUAL_32(0, b[0]);
9985 ASSERT_EQUAL_32(0, b[2]);
9986 ASSERT_EQUAL_32(0, h[0]);
9987 ASSERT_EQUAL_32(0, h[2]);
9988 ASSERT_EQUAL_32(0, w[0]);
9989 ASSERT_EQUAL_32(0, w[2]);
9990 ASSERT_EQUAL_64(0, x[0]);
9991 ASSERT_EQUAL_64(0, x[2]);
9992 ASSERT_EQUAL_32(0, wp[0]);
9993 ASSERT_EQUAL_32(0, wp[3]);
9994 ASSERT_EQUAL_64(0, xp[0]);
9995 ASSERT_EQUAL_64(0, xp[3]);
9996 }
9997 }
9998
9999
TEST(ldaxr_stlxr)10000 TEST(ldaxr_stlxr) {
10001 // The middle value is read, modified, and written. The padding exists only to
10002 // check for over-write.
10003 uint8_t b[] = {0, 0x12, 0};
10004 uint16_t h[] = {0, 0x1234, 0};
10005 uint32_t w[] = {0, 0x12345678, 0};
10006 uint64_t x[] = {0, 0x123456789abcdef0, 0};
10007
10008 // As above, but get suitably-aligned values for ldxp and stxp.
10009 uint32_t wp_data[] = {0, 0, 0, 0, 0};
10010 uint32_t* wp = AlignUp(wp_data + 1, kWRegSizeInBytes * 2) - 1;
10011 wp[1] = 0x12345678; // wp[1] is 64-bit-aligned.
10012 wp[2] = 0x87654321;
10013 uint64_t xp_data[] = {0, 0, 0, 0, 0};
10014 uint64_t* xp = AlignUp(xp_data + 1, kXRegSizeInBytes * 2) - 1;
10015 xp[1] = 0x123456789abcdef0; // xp[1] is 128-bit-aligned.
10016 xp[2] = 0x0fedcba987654321;
10017
10018 SETUP();
10019 START();
10020
10021 __ Mov(x10, reinterpret_cast<uintptr_t>(&b[1]));
10022 Label try_b;
10023 __ Bind(&try_b);
10024 __ Ldaxrb(w0, MemOperand(x10));
10025 __ Add(w0, w0, 1);
10026 __ Stlxrb(w5, w0, MemOperand(x10));
10027 __ Cbnz(w5, &try_b);
10028
10029 __ Mov(x10, reinterpret_cast<uintptr_t>(&h[1]));
10030 Label try_h;
10031 __ Bind(&try_h);
10032 __ Ldaxrh(w0, MemOperand(x10));
10033 __ Add(w0, w0, 1);
10034 __ Stlxrh(w5, w0, MemOperand(x10));
10035 __ Cbnz(w5, &try_h);
10036
10037 __ Mov(x10, reinterpret_cast<uintptr_t>(&w[1]));
10038 Label try_w;
10039 __ Bind(&try_w);
10040 __ Ldaxr(w0, MemOperand(x10));
10041 __ Add(w0, w0, 1);
10042 __ Stlxr(w5, w0, MemOperand(x10));
10043 __ Cbnz(w5, &try_w);
10044
10045 __ Mov(x10, reinterpret_cast<uintptr_t>(&x[1]));
10046 Label try_x;
10047 __ Bind(&try_x);
10048 __ Ldaxr(x0, MemOperand(x10));
10049 __ Add(x0, x0, 1);
10050 __ Stlxr(w5, x0, MemOperand(x10));
10051 __ Cbnz(w5, &try_x);
10052
10053 __ Mov(x10, reinterpret_cast<uintptr_t>(&wp[1]));
10054 Label try_wp;
10055 __ Bind(&try_wp);
10056 __ Ldaxp(w0, w1, MemOperand(x10));
10057 __ Add(w0, w0, 1);
10058 __ Add(w1, w1, 1);
10059 __ Stlxp(w5, w0, w1, MemOperand(x10));
10060 __ Cbnz(w5, &try_wp);
10061
10062 __ Mov(x10, reinterpret_cast<uintptr_t>(&xp[1]));
10063 Label try_xp;
10064 __ Bind(&try_xp);
10065 __ Ldaxp(x0, x1, MemOperand(x10));
10066 __ Add(x0, x0, 1);
10067 __ Add(x1, x1, 1);
10068 __ Stlxp(w5, x0, x1, MemOperand(x10));
10069 __ Cbnz(w5, &try_xp);
10070
10071 END();
10072 if (CAN_RUN()) {
10073 RUN();
10074
10075 ASSERT_EQUAL_32(0x13, b[1]);
10076 ASSERT_EQUAL_32(0x1235, h[1]);
10077 ASSERT_EQUAL_32(0x12345679, w[1]);
10078 ASSERT_EQUAL_64(0x123456789abcdef1, x[1]);
10079 ASSERT_EQUAL_32(0x12345679, wp[1]);
10080 ASSERT_EQUAL_32(0x87654322, wp[2]);
10081 ASSERT_EQUAL_64(0x123456789abcdef1, xp[1]);
10082 ASSERT_EQUAL_64(0x0fedcba987654322, xp[2]);
10083
10084 // Check for over-write.
10085 ASSERT_EQUAL_32(0, b[0]);
10086 ASSERT_EQUAL_32(0, b[2]);
10087 ASSERT_EQUAL_32(0, h[0]);
10088 ASSERT_EQUAL_32(0, h[2]);
10089 ASSERT_EQUAL_32(0, w[0]);
10090 ASSERT_EQUAL_32(0, w[2]);
10091 ASSERT_EQUAL_64(0, x[0]);
10092 ASSERT_EQUAL_64(0, x[2]);
10093 ASSERT_EQUAL_32(0, wp[0]);
10094 ASSERT_EQUAL_32(0, wp[3]);
10095 ASSERT_EQUAL_64(0, xp[0]);
10096 ASSERT_EQUAL_64(0, xp[3]);
10097 }
10098 }
10099
10100
TEST(clrex)10101 TEST(clrex) {
10102 // This data should never be written.
10103 uint64_t data[] = {0, 0, 0};
10104 uint64_t* data_aligned = AlignUp(data, kXRegSizeInBytes * 2);
10105
10106 SETUP();
10107 START();
10108
10109 __ Mov(x10, reinterpret_cast<uintptr_t>(data_aligned));
10110 __ Mov(w6, 0);
10111
10112 __ Ldxrb(w0, MemOperand(x10));
10113 __ Clrex();
10114 __ Add(w0, w0, 1);
10115 __ Stxrb(w5, w0, MemOperand(x10));
10116 __ Add(w6, w6, w5);
10117
10118 __ Ldxrh(w0, MemOperand(x10));
10119 __ Clrex();
10120 __ Add(w0, w0, 1);
10121 __ Stxrh(w5, w0, MemOperand(x10));
10122 __ Add(w6, w6, w5);
10123
10124 __ Ldxr(w0, MemOperand(x10));
10125 __ Clrex();
10126 __ Add(w0, w0, 1);
10127 __ Stxr(w5, w0, MemOperand(x10));
10128 __ Add(w6, w6, w5);
10129
10130 __ Ldxr(x0, MemOperand(x10));
10131 __ Clrex();
10132 __ Add(x0, x0, 1);
10133 __ Stxr(w5, x0, MemOperand(x10));
10134 __ Add(w6, w6, w5);
10135
10136 __ Ldxp(w0, w1, MemOperand(x10));
10137 __ Clrex();
10138 __ Add(w0, w0, 1);
10139 __ Add(w1, w1, 1);
10140 __ Stxp(w5, w0, w1, MemOperand(x10));
10141 __ Add(w6, w6, w5);
10142
10143 __ Ldxp(x0, x1, MemOperand(x10));
10144 __ Clrex();
10145 __ Add(x0, x0, 1);
10146 __ Add(x1, x1, 1);
10147 __ Stxp(w5, x0, x1, MemOperand(x10));
10148 __ Add(w6, w6, w5);
10149
10150 // Acquire-release variants.
10151
10152 __ Ldaxrb(w0, MemOperand(x10));
10153 __ Clrex();
10154 __ Add(w0, w0, 1);
10155 __ Stlxrb(w5, w0, MemOperand(x10));
10156 __ Add(w6, w6, w5);
10157
10158 __ Ldaxrh(w0, MemOperand(x10));
10159 __ Clrex();
10160 __ Add(w0, w0, 1);
10161 __ Stlxrh(w5, w0, MemOperand(x10));
10162 __ Add(w6, w6, w5);
10163
10164 __ Ldaxr(w0, MemOperand(x10));
10165 __ Clrex();
10166 __ Add(w0, w0, 1);
10167 __ Stlxr(w5, w0, MemOperand(x10));
10168 __ Add(w6, w6, w5);
10169
10170 __ Ldaxr(x0, MemOperand(x10));
10171 __ Clrex();
10172 __ Add(x0, x0, 1);
10173 __ Stlxr(w5, x0, MemOperand(x10));
10174 __ Add(w6, w6, w5);
10175
10176 __ Ldaxp(w0, w1, MemOperand(x10));
10177 __ Clrex();
10178 __ Add(w0, w0, 1);
10179 __ Add(w1, w1, 1);
10180 __ Stlxp(w5, w0, w1, MemOperand(x10));
10181 __ Add(w6, w6, w5);
10182
10183 __ Ldaxp(x0, x1, MemOperand(x10));
10184 __ Clrex();
10185 __ Add(x0, x0, 1);
10186 __ Add(x1, x1, 1);
10187 __ Stlxp(w5, x0, x1, MemOperand(x10));
10188 __ Add(w6, w6, w5);
10189
10190 END();
10191 if (CAN_RUN()) {
10192 RUN();
10193
10194 // None of the 12 store-exclusives should have succeeded.
10195 ASSERT_EQUAL_32(12, w6);
10196
10197 ASSERT_EQUAL_64(0, data[0]);
10198 ASSERT_EQUAL_64(0, data[1]);
10199 ASSERT_EQUAL_64(0, data[2]);
10200 }
10201 }
10202
10203
10204 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
10205 // Check that the simulator occasionally makes store-exclusive fail.
TEST(ldxr_stxr_fail)10206 TEST(ldxr_stxr_fail) {
10207 uint64_t data[] = {0, 0, 0};
10208 uint64_t* data_aligned = AlignUp(data, kXRegSizeInBytes * 2);
10209
10210 // Impose a hard limit on the number of attempts, so the test cannot hang.
10211 static const uint64_t kWatchdog = 10000;
10212 Label done;
10213
10214 SETUP();
10215 START();
10216
10217 __ Mov(x10, reinterpret_cast<uintptr_t>(data_aligned));
10218 __ Mov(x11, kWatchdog);
10219
10220 // This loop is the opposite of what we normally do with ldxr and stxr; we
10221 // keep trying until we fail (or the watchdog counter runs out).
10222 Label try_b;
10223 __ Bind(&try_b);
10224 __ Ldxrb(w0, MemOperand(x10));
10225 __ Stxrb(w5, w0, MemOperand(x10));
10226 // Check the watchdog counter.
10227 __ Sub(x11, x11, 1);
10228 __ Cbz(x11, &done);
10229 // Check the exclusive-store result.
10230 __ Cbz(w5, &try_b);
10231
10232 Label try_h;
10233 __ Bind(&try_h);
10234 __ Ldxrh(w0, MemOperand(x10));
10235 __ Stxrh(w5, w0, MemOperand(x10));
10236 __ Sub(x11, x11, 1);
10237 __ Cbz(x11, &done);
10238 __ Cbz(w5, &try_h);
10239
10240 Label try_w;
10241 __ Bind(&try_w);
10242 __ Ldxr(w0, MemOperand(x10));
10243 __ Stxr(w5, w0, MemOperand(x10));
10244 __ Sub(x11, x11, 1);
10245 __ Cbz(x11, &done);
10246 __ Cbz(w5, &try_w);
10247
10248 Label try_x;
10249 __ Bind(&try_x);
10250 __ Ldxr(x0, MemOperand(x10));
10251 __ Stxr(w5, x0, MemOperand(x10));
10252 __ Sub(x11, x11, 1);
10253 __ Cbz(x11, &done);
10254 __ Cbz(w5, &try_x);
10255
10256 Label try_wp;
10257 __ Bind(&try_wp);
10258 __ Ldxp(w0, w1, MemOperand(x10));
10259 __ Stxp(w5, w0, w1, MemOperand(x10));
10260 __ Sub(x11, x11, 1);
10261 __ Cbz(x11, &done);
10262 __ Cbz(w5, &try_wp);
10263
10264 Label try_xp;
10265 __ Bind(&try_xp);
10266 __ Ldxp(x0, x1, MemOperand(x10));
10267 __ Stxp(w5, x0, x1, MemOperand(x10));
10268 __ Sub(x11, x11, 1);
10269 __ Cbz(x11, &done);
10270 __ Cbz(w5, &try_xp);
10271
10272 __ Bind(&done);
10273 // Trigger an error if x11 (watchdog) is zero.
10274 __ Cmp(x11, 0);
10275 __ Cset(x12, eq);
10276
10277 END();
10278 if (CAN_RUN()) {
10279 RUN();
10280
10281 // Check that the watchdog counter didn't run out.
10282 ASSERT_EQUAL_64(0, x12);
10283 }
10284 }
10285 #endif
10286
10287
10288 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
10289 // Check that the simulator occasionally makes store-exclusive fail.
TEST(ldaxr_stlxr_fail)10290 TEST(ldaxr_stlxr_fail) {
10291 uint64_t data[] = {0, 0, 0};
10292 uint64_t* data_aligned = AlignUp(data, kXRegSizeInBytes * 2);
10293
10294 // Impose a hard limit on the number of attempts, so the test cannot hang.
10295 static const uint64_t kWatchdog = 10000;
10296 Label done;
10297
10298 SETUP();
10299 START();
10300
10301 __ Mov(x10, reinterpret_cast<uintptr_t>(data_aligned));
10302 __ Mov(x11, kWatchdog);
10303
10304 // This loop is the opposite of what we normally do with ldxr and stxr; we
10305 // keep trying until we fail (or the watchdog counter runs out).
10306 Label try_b;
10307 __ Bind(&try_b);
10308 __ Ldxrb(w0, MemOperand(x10));
10309 __ Stxrb(w5, w0, MemOperand(x10));
10310 // Check the watchdog counter.
10311 __ Sub(x11, x11, 1);
10312 __ Cbz(x11, &done);
10313 // Check the exclusive-store result.
10314 __ Cbz(w5, &try_b);
10315
10316 Label try_h;
10317 __ Bind(&try_h);
10318 __ Ldaxrh(w0, MemOperand(x10));
10319 __ Stlxrh(w5, w0, MemOperand(x10));
10320 __ Sub(x11, x11, 1);
10321 __ Cbz(x11, &done);
10322 __ Cbz(w5, &try_h);
10323
10324 Label try_w;
10325 __ Bind(&try_w);
10326 __ Ldaxr(w0, MemOperand(x10));
10327 __ Stlxr(w5, w0, MemOperand(x10));
10328 __ Sub(x11, x11, 1);
10329 __ Cbz(x11, &done);
10330 __ Cbz(w5, &try_w);
10331
10332 Label try_x;
10333 __ Bind(&try_x);
10334 __ Ldaxr(x0, MemOperand(x10));
10335 __ Stlxr(w5, x0, MemOperand(x10));
10336 __ Sub(x11, x11, 1);
10337 __ Cbz(x11, &done);
10338 __ Cbz(w5, &try_x);
10339
10340 Label try_wp;
10341 __ Bind(&try_wp);
10342 __ Ldaxp(w0, w1, MemOperand(x10));
10343 __ Stlxp(w5, w0, w1, MemOperand(x10));
10344 __ Sub(x11, x11, 1);
10345 __ Cbz(x11, &done);
10346 __ Cbz(w5, &try_wp);
10347
10348 Label try_xp;
10349 __ Bind(&try_xp);
10350 __ Ldaxp(x0, x1, MemOperand(x10));
10351 __ Stlxp(w5, x0, x1, MemOperand(x10));
10352 __ Sub(x11, x11, 1);
10353 __ Cbz(x11, &done);
10354 __ Cbz(w5, &try_xp);
10355
10356 __ Bind(&done);
10357 // Trigger an error if x11 (watchdog) is zero.
10358 __ Cmp(x11, 0);
10359 __ Cset(x12, eq);
10360
10361 END();
10362 if (CAN_RUN()) {
10363 RUN();
10364
10365 // Check that the watchdog counter didn't run out.
10366 ASSERT_EQUAL_64(0, x12);
10367 }
10368 }
10369 #endif
10370
TEST(cas_casa_casl_casal_w)10371 TEST(cas_casa_casl_casal_w) {
10372 uint64_t data1 = 0x0123456789abcdef;
10373 uint64_t data2 = 0x0123456789abcdef;
10374 uint64_t data3 = 0x0123456789abcdef;
10375 uint64_t data4 = 0x0123456789abcdef;
10376 uint64_t data5 = 0x0123456789abcdef;
10377 uint64_t data6 = 0x0123456789abcdef;
10378 uint64_t data7 = 0x0123456789abcdef;
10379 uint64_t data8 = 0x0123456789abcdef;
10380
10381 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10382
10383 START();
10384
10385 __ Mov(x21, reinterpret_cast<uintptr_t>(&data1) + 0);
10386 __ Mov(x22, reinterpret_cast<uintptr_t>(&data2) + 0);
10387 __ Mov(x23, reinterpret_cast<uintptr_t>(&data3) + 4);
10388 __ Mov(x24, reinterpret_cast<uintptr_t>(&data4) + 4);
10389 __ Mov(x25, reinterpret_cast<uintptr_t>(&data5) + 0);
10390 __ Mov(x26, reinterpret_cast<uintptr_t>(&data6) + 0);
10391 __ Mov(x27, reinterpret_cast<uintptr_t>(&data7) + 4);
10392 __ Mov(x28, reinterpret_cast<uintptr_t>(&data8) + 4);
10393
10394 __ Mov(x0, 0xffffffff);
10395
10396 __ Mov(x1, 0xfedcba9876543210);
10397 __ Mov(x2, 0x0123456789abcdef);
10398 __ Mov(x3, 0xfedcba9876543210);
10399 __ Mov(x4, 0x89abcdef01234567);
10400 __ Mov(x5, 0xfedcba9876543210);
10401 __ Mov(x6, 0x0123456789abcdef);
10402 __ Mov(x7, 0xfedcba9876543210);
10403 __ Mov(x8, 0x89abcdef01234567);
10404
10405 __ Cas(w1, w0, MemOperand(x21));
10406 __ Cas(w2, w0, MemOperand(x22));
10407 __ Casa(w3, w0, MemOperand(x23));
10408 __ Casa(w4, w0, MemOperand(x24));
10409 __ Casl(w5, w0, MemOperand(x25));
10410 __ Casl(w6, w0, MemOperand(x26));
10411 __ Casal(w7, w0, MemOperand(x27));
10412 __ Casal(w8, w0, MemOperand(x28));
10413
10414 END();
10415
10416 if (CAN_RUN()) {
10417 RUN();
10418
10419 ASSERT_EQUAL_64(0x89abcdef, x1);
10420 ASSERT_EQUAL_64(0x89abcdef, x2);
10421 ASSERT_EQUAL_64(0x01234567, x3);
10422 ASSERT_EQUAL_64(0x01234567, x4);
10423 ASSERT_EQUAL_64(0x89abcdef, x5);
10424 ASSERT_EQUAL_64(0x89abcdef, x6);
10425 ASSERT_EQUAL_64(0x01234567, x7);
10426 ASSERT_EQUAL_64(0x01234567, x8);
10427
10428 ASSERT_EQUAL_64(0x0123456789abcdef, data1);
10429 ASSERT_EQUAL_64(0x01234567ffffffff, data2);
10430 ASSERT_EQUAL_64(0x0123456789abcdef, data3);
10431 ASSERT_EQUAL_64(0xffffffff89abcdef, data4);
10432 ASSERT_EQUAL_64(0x0123456789abcdef, data5);
10433 ASSERT_EQUAL_64(0x01234567ffffffff, data6);
10434 ASSERT_EQUAL_64(0x0123456789abcdef, data7);
10435 ASSERT_EQUAL_64(0xffffffff89abcdef, data8);
10436 }
10437 }
10438
TEST(cas_casa_casl_casal_x)10439 TEST(cas_casa_casl_casal_x) {
10440 uint64_t data1 = 0x0123456789abcdef;
10441 uint64_t data2 = 0x0123456789abcdef;
10442 uint64_t data3 = 0x0123456789abcdef;
10443 uint64_t data4 = 0x0123456789abcdef;
10444 uint64_t data5 = 0x0123456789abcdef;
10445 uint64_t data6 = 0x0123456789abcdef;
10446 uint64_t data7 = 0x0123456789abcdef;
10447 uint64_t data8 = 0x0123456789abcdef;
10448
10449 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10450
10451 START();
10452
10453 __ Mov(x21, reinterpret_cast<uintptr_t>(&data1));
10454 __ Mov(x22, reinterpret_cast<uintptr_t>(&data2));
10455 __ Mov(x23, reinterpret_cast<uintptr_t>(&data3));
10456 __ Mov(x24, reinterpret_cast<uintptr_t>(&data4));
10457 __ Mov(x25, reinterpret_cast<uintptr_t>(&data5));
10458 __ Mov(x26, reinterpret_cast<uintptr_t>(&data6));
10459 __ Mov(x27, reinterpret_cast<uintptr_t>(&data7));
10460 __ Mov(x28, reinterpret_cast<uintptr_t>(&data8));
10461
10462 __ Mov(x0, 0xffffffffffffffff);
10463
10464 __ Mov(x1, 0xfedcba9876543210);
10465 __ Mov(x2, 0x0123456789abcdef);
10466 __ Mov(x3, 0xfedcba9876543210);
10467 __ Mov(x4, 0x0123456789abcdef);
10468 __ Mov(x5, 0xfedcba9876543210);
10469 __ Mov(x6, 0x0123456789abcdef);
10470 __ Mov(x7, 0xfedcba9876543210);
10471 __ Mov(x8, 0x0123456789abcdef);
10472
10473 __ Cas(x1, x0, MemOperand(x21));
10474 __ Cas(x2, x0, MemOperand(x22));
10475 __ Casa(x3, x0, MemOperand(x23));
10476 __ Casa(x4, x0, MemOperand(x24));
10477 __ Casl(x5, x0, MemOperand(x25));
10478 __ Casl(x6, x0, MemOperand(x26));
10479 __ Casal(x7, x0, MemOperand(x27));
10480 __ Casal(x8, x0, MemOperand(x28));
10481
10482 END();
10483
10484 if (CAN_RUN()) {
10485 RUN();
10486
10487 ASSERT_EQUAL_64(0x0123456789abcdef, x1);
10488 ASSERT_EQUAL_64(0x0123456789abcdef, x2);
10489 ASSERT_EQUAL_64(0x0123456789abcdef, x3);
10490 ASSERT_EQUAL_64(0x0123456789abcdef, x4);
10491 ASSERT_EQUAL_64(0x0123456789abcdef, x5);
10492 ASSERT_EQUAL_64(0x0123456789abcdef, x6);
10493 ASSERT_EQUAL_64(0x0123456789abcdef, x7);
10494 ASSERT_EQUAL_64(0x0123456789abcdef, x8);
10495
10496 ASSERT_EQUAL_64(0x0123456789abcdef, data1);
10497 ASSERT_EQUAL_64(0xffffffffffffffff, data2);
10498 ASSERT_EQUAL_64(0x0123456789abcdef, data3);
10499 ASSERT_EQUAL_64(0xffffffffffffffff, data4);
10500 ASSERT_EQUAL_64(0x0123456789abcdef, data5);
10501 ASSERT_EQUAL_64(0xffffffffffffffff, data6);
10502 ASSERT_EQUAL_64(0x0123456789abcdef, data7);
10503 ASSERT_EQUAL_64(0xffffffffffffffff, data8);
10504 }
10505 }
10506
TEST(casb_casab_caslb_casalb)10507 TEST(casb_casab_caslb_casalb) {
10508 uint32_t data1 = 0x01234567;
10509 uint32_t data2 = 0x01234567;
10510 uint32_t data3 = 0x01234567;
10511 uint32_t data4 = 0x01234567;
10512 uint32_t data5 = 0x01234567;
10513 uint32_t data6 = 0x01234567;
10514 uint32_t data7 = 0x01234567;
10515 uint32_t data8 = 0x01234567;
10516
10517 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10518
10519 START();
10520
10521 __ Mov(x21, reinterpret_cast<uintptr_t>(&data1) + 0);
10522 __ Mov(x22, reinterpret_cast<uintptr_t>(&data2) + 0);
10523 __ Mov(x23, reinterpret_cast<uintptr_t>(&data3) + 1);
10524 __ Mov(x24, reinterpret_cast<uintptr_t>(&data4) + 1);
10525 __ Mov(x25, reinterpret_cast<uintptr_t>(&data5) + 2);
10526 __ Mov(x26, reinterpret_cast<uintptr_t>(&data6) + 2);
10527 __ Mov(x27, reinterpret_cast<uintptr_t>(&data7) + 3);
10528 __ Mov(x28, reinterpret_cast<uintptr_t>(&data8) + 3);
10529
10530 __ Mov(x0, 0xff);
10531
10532 __ Mov(x1, 0x76543210);
10533 __ Mov(x2, 0x01234567);
10534 __ Mov(x3, 0x76543210);
10535 __ Mov(x4, 0x67012345);
10536 __ Mov(x5, 0x76543210);
10537 __ Mov(x6, 0x45670123);
10538 __ Mov(x7, 0x76543210);
10539 __ Mov(x8, 0x23456701);
10540
10541 __ Casb(w1, w0, MemOperand(x21));
10542 __ Casb(w2, w0, MemOperand(x22));
10543 __ Casab(w3, w0, MemOperand(x23));
10544 __ Casab(w4, w0, MemOperand(x24));
10545 __ Caslb(w5, w0, MemOperand(x25));
10546 __ Caslb(w6, w0, MemOperand(x26));
10547 __ Casalb(w7, w0, MemOperand(x27));
10548 __ Casalb(w8, w0, MemOperand(x28));
10549
10550 END();
10551
10552 if (CAN_RUN()) {
10553 RUN();
10554
10555 ASSERT_EQUAL_64(0x00000067, x1);
10556 ASSERT_EQUAL_64(0x00000067, x2);
10557 ASSERT_EQUAL_64(0x00000045, x3);
10558 ASSERT_EQUAL_64(0x00000045, x4);
10559 ASSERT_EQUAL_64(0x00000023, x5);
10560 ASSERT_EQUAL_64(0x00000023, x6);
10561 ASSERT_EQUAL_64(0x00000001, x7);
10562 ASSERT_EQUAL_64(0x00000001, x8);
10563
10564 ASSERT_EQUAL_64(0x01234567, data1);
10565 ASSERT_EQUAL_64(0x012345ff, data2);
10566 ASSERT_EQUAL_64(0x01234567, data3);
10567 ASSERT_EQUAL_64(0x0123ff67, data4);
10568 ASSERT_EQUAL_64(0x01234567, data5);
10569 ASSERT_EQUAL_64(0x01ff4567, data6);
10570 ASSERT_EQUAL_64(0x01234567, data7);
10571 ASSERT_EQUAL_64(0xff234567, data8);
10572 }
10573 }
10574
TEST(cash_casah_caslh_casalh)10575 TEST(cash_casah_caslh_casalh) {
10576 uint64_t data1 = 0x0123456789abcdef;
10577 uint64_t data2 = 0x0123456789abcdef;
10578 uint64_t data3 = 0x0123456789abcdef;
10579 uint64_t data4 = 0x0123456789abcdef;
10580 uint64_t data5 = 0x0123456789abcdef;
10581 uint64_t data6 = 0x0123456789abcdef;
10582 uint64_t data7 = 0x0123456789abcdef;
10583 uint64_t data8 = 0x0123456789abcdef;
10584
10585 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10586
10587 START();
10588
10589 __ Mov(x21, reinterpret_cast<uintptr_t>(&data1) + 0);
10590 __ Mov(x22, reinterpret_cast<uintptr_t>(&data2) + 0);
10591 __ Mov(x23, reinterpret_cast<uintptr_t>(&data3) + 2);
10592 __ Mov(x24, reinterpret_cast<uintptr_t>(&data4) + 2);
10593 __ Mov(x25, reinterpret_cast<uintptr_t>(&data5) + 4);
10594 __ Mov(x26, reinterpret_cast<uintptr_t>(&data6) + 4);
10595 __ Mov(x27, reinterpret_cast<uintptr_t>(&data7) + 6);
10596 __ Mov(x28, reinterpret_cast<uintptr_t>(&data8) + 6);
10597
10598 __ Mov(x0, 0xffff);
10599
10600 __ Mov(x1, 0xfedcba9876543210);
10601 __ Mov(x2, 0x0123456789abcdef);
10602 __ Mov(x3, 0xfedcba9876543210);
10603 __ Mov(x4, 0xcdef0123456789ab);
10604 __ Mov(x5, 0xfedcba9876543210);
10605 __ Mov(x6, 0x89abcdef01234567);
10606 __ Mov(x7, 0xfedcba9876543210);
10607 __ Mov(x8, 0x456789abcdef0123);
10608
10609 __ Cash(w1, w0, MemOperand(x21));
10610 __ Cash(w2, w0, MemOperand(x22));
10611 __ Casah(w3, w0, MemOperand(x23));
10612 __ Casah(w4, w0, MemOperand(x24));
10613 __ Caslh(w5, w0, MemOperand(x25));
10614 __ Caslh(w6, w0, MemOperand(x26));
10615 __ Casalh(w7, w0, MemOperand(x27));
10616 __ Casalh(w8, w0, MemOperand(x28));
10617
10618 END();
10619
10620 if (CAN_RUN()) {
10621 RUN();
10622
10623 ASSERT_EQUAL_64(0x0000cdef, x1);
10624 ASSERT_EQUAL_64(0x0000cdef, x2);
10625 ASSERT_EQUAL_64(0x000089ab, x3);
10626 ASSERT_EQUAL_64(0x000089ab, x4);
10627 ASSERT_EQUAL_64(0x00004567, x5);
10628 ASSERT_EQUAL_64(0x00004567, x6);
10629 ASSERT_EQUAL_64(0x00000123, x7);
10630 ASSERT_EQUAL_64(0x00000123, x8);
10631
10632 ASSERT_EQUAL_64(0x0123456789abcdef, data1);
10633 ASSERT_EQUAL_64(0x0123456789abffff, data2);
10634 ASSERT_EQUAL_64(0x0123456789abcdef, data3);
10635 ASSERT_EQUAL_64(0x01234567ffffcdef, data4);
10636 ASSERT_EQUAL_64(0x0123456789abcdef, data5);
10637 ASSERT_EQUAL_64(0x0123ffff89abcdef, data6);
10638 ASSERT_EQUAL_64(0x0123456789abcdef, data7);
10639 ASSERT_EQUAL_64(0xffff456789abcdef, data8);
10640 }
10641 }
10642
TEST(casp_caspa_caspl_caspal_w)10643 TEST(casp_caspa_caspl_caspal_w) {
10644 uint64_t data1[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10645 uint64_t data2[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10646 uint64_t data3[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10647 uint64_t data4[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10648 uint64_t data5[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10649 uint64_t data6[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10650 uint64_t data7[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10651 uint64_t data8[] = {0x7766554433221100, 0xffeeddccbbaa9988};
10652
10653 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10654
10655 START();
10656
10657 __ Mov(x21, reinterpret_cast<uintptr_t>(data1) + 0);
10658 __ Mov(x22, reinterpret_cast<uintptr_t>(data2) + 0);
10659 __ Mov(x23, reinterpret_cast<uintptr_t>(data3) + 8);
10660 __ Mov(x24, reinterpret_cast<uintptr_t>(data4) + 8);
10661 __ Mov(x25, reinterpret_cast<uintptr_t>(data5) + 8);
10662 __ Mov(x26, reinterpret_cast<uintptr_t>(data6) + 8);
10663 __ Mov(x27, reinterpret_cast<uintptr_t>(data7) + 0);
10664 __ Mov(x28, reinterpret_cast<uintptr_t>(data8) + 0);
10665
10666 __ Mov(x0, 0xfff00fff);
10667 __ Mov(x1, 0xfff11fff);
10668
10669 __ Mov(x2, 0x77665544);
10670 __ Mov(x3, 0x33221100);
10671 __ Mov(x4, 0x33221100);
10672 __ Mov(x5, 0x77665544);
10673
10674 __ Mov(x6, 0xffeeddcc);
10675 __ Mov(x7, 0xbbaa9988);
10676 __ Mov(x8, 0xbbaa9988);
10677 __ Mov(x9, 0xffeeddcc);
10678
10679 __ Mov(x10, 0xffeeddcc);
10680 __ Mov(x11, 0xbbaa9988);
10681 __ Mov(x12, 0xbbaa9988);
10682 __ Mov(x13, 0xffeeddcc);
10683
10684 __ Mov(x14, 0x77665544);
10685 __ Mov(x15, 0x33221100);
10686 __ Mov(x16, 0x33221100);
10687 __ Mov(x17, 0x77665544);
10688
10689 __ Casp(w2, w3, w0, w1, MemOperand(x21));
10690 __ Casp(w4, w5, w0, w1, MemOperand(x22));
10691 __ Caspa(w6, w7, w0, w1, MemOperand(x23));
10692 __ Caspa(w8, w9, w0, w1, MemOperand(x24));
10693 __ Caspl(w10, w11, w0, w1, MemOperand(x25));
10694 __ Caspl(w12, w13, w0, w1, MemOperand(x26));
10695 __ Caspal(w14, w15, w0, w1, MemOperand(x27));
10696 __ Caspal(w16, w17, w0, w1, MemOperand(x28));
10697
10698 END();
10699
10700 if (CAN_RUN()) {
10701 RUN();
10702
10703 ASSERT_EQUAL_64(0x33221100, x2);
10704 ASSERT_EQUAL_64(0x77665544, x3);
10705 ASSERT_EQUAL_64(0x33221100, x4);
10706 ASSERT_EQUAL_64(0x77665544, x5);
10707 ASSERT_EQUAL_64(0xbbaa9988, x6);
10708 ASSERT_EQUAL_64(0xffeeddcc, x7);
10709 ASSERT_EQUAL_64(0xbbaa9988, x8);
10710 ASSERT_EQUAL_64(0xffeeddcc, x9);
10711 ASSERT_EQUAL_64(0xbbaa9988, x10);
10712 ASSERT_EQUAL_64(0xffeeddcc, x11);
10713 ASSERT_EQUAL_64(0xbbaa9988, x12);
10714 ASSERT_EQUAL_64(0xffeeddcc, x13);
10715 ASSERT_EQUAL_64(0x33221100, x14);
10716 ASSERT_EQUAL_64(0x77665544, x15);
10717 ASSERT_EQUAL_64(0x33221100, x16);
10718 ASSERT_EQUAL_64(0x77665544, x17);
10719
10720 ASSERT_EQUAL_64(0x7766554433221100, data1[0]);
10721 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data1[1]);
10722 ASSERT_EQUAL_64(0xfff11ffffff00fff, data2[0]);
10723 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data2[1]);
10724 ASSERT_EQUAL_64(0x7766554433221100, data3[0]);
10725 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data3[1]);
10726 ASSERT_EQUAL_64(0x7766554433221100, data4[0]);
10727 ASSERT_EQUAL_64(0xfff11ffffff00fff, data4[1]);
10728 ASSERT_EQUAL_64(0x7766554433221100, data5[0]);
10729 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data5[1]);
10730 ASSERT_EQUAL_64(0x7766554433221100, data6[0]);
10731 ASSERT_EQUAL_64(0xfff11ffffff00fff, data6[1]);
10732 ASSERT_EQUAL_64(0x7766554433221100, data7[0]);
10733 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data7[1]);
10734 ASSERT_EQUAL_64(0xfff11ffffff00fff, data8[0]);
10735 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data8[1]);
10736 }
10737 }
10738
TEST(casp_caspa_caspl_caspal_x)10739 TEST(casp_caspa_caspl_caspal_x) {
10740 alignas(kXRegSizeInBytes * 2) uint64_t data1[] = {0x7766554433221100,
10741 0xffeeddccbbaa9988,
10742 0xfedcba9876543210,
10743 0x0123456789abcdef};
10744 alignas(kXRegSizeInBytes * 2) uint64_t data2[] = {0x7766554433221100,
10745 0xffeeddccbbaa9988,
10746 0xfedcba9876543210,
10747 0x0123456789abcdef};
10748 alignas(kXRegSizeInBytes * 2) uint64_t data3[] = {0x7766554433221100,
10749 0xffeeddccbbaa9988,
10750 0xfedcba9876543210,
10751 0x0123456789abcdef};
10752 alignas(kXRegSizeInBytes * 2) uint64_t data4[] = {0x7766554433221100,
10753 0xffeeddccbbaa9988,
10754 0xfedcba9876543210,
10755 0x0123456789abcdef};
10756 alignas(kXRegSizeInBytes * 2) uint64_t data5[] = {0x7766554433221100,
10757 0xffeeddccbbaa9988,
10758 0xfedcba9876543210,
10759 0x0123456789abcdef};
10760 alignas(kXRegSizeInBytes * 2) uint64_t data6[] = {0x7766554433221100,
10761 0xffeeddccbbaa9988,
10762 0xfedcba9876543210,
10763 0x0123456789abcdef};
10764 alignas(kXRegSizeInBytes * 2) uint64_t data7[] = {0x7766554433221100,
10765 0xffeeddccbbaa9988,
10766 0xfedcba9876543210,
10767 0x0123456789abcdef};
10768 alignas(kXRegSizeInBytes * 2) uint64_t data8[] = {0x7766554433221100,
10769 0xffeeddccbbaa9988,
10770 0xfedcba9876543210,
10771 0x0123456789abcdef};
10772
10773 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10774
10775 START();
10776
10777 __ Mov(x21, reinterpret_cast<uintptr_t>(data1) + 0);
10778 __ Mov(x22, reinterpret_cast<uintptr_t>(data2) + 0);
10779 __ Mov(x23, reinterpret_cast<uintptr_t>(data3) + 16);
10780 __ Mov(x24, reinterpret_cast<uintptr_t>(data4) + 16);
10781 __ Mov(x25, reinterpret_cast<uintptr_t>(data5) + 16);
10782 __ Mov(x26, reinterpret_cast<uintptr_t>(data6) + 16);
10783 __ Mov(x27, reinterpret_cast<uintptr_t>(data7) + 0);
10784 __ Mov(x28, reinterpret_cast<uintptr_t>(data8) + 0);
10785
10786 __ Mov(x0, 0xfffffff00fffffff);
10787 __ Mov(x1, 0xfffffff11fffffff);
10788
10789 __ Mov(x2, 0xffeeddccbbaa9988);
10790 __ Mov(x3, 0x7766554433221100);
10791 __ Mov(x4, 0x7766554433221100);
10792 __ Mov(x5, 0xffeeddccbbaa9988);
10793
10794 __ Mov(x6, 0x0123456789abcdef);
10795 __ Mov(x7, 0xfedcba9876543210);
10796 __ Mov(x8, 0xfedcba9876543210);
10797 __ Mov(x9, 0x0123456789abcdef);
10798
10799 __ Mov(x10, 0x0123456789abcdef);
10800 __ Mov(x11, 0xfedcba9876543210);
10801 __ Mov(x12, 0xfedcba9876543210);
10802 __ Mov(x13, 0x0123456789abcdef);
10803
10804 __ Mov(x14, 0xffeeddccbbaa9988);
10805 __ Mov(x15, 0x7766554433221100);
10806 __ Mov(x16, 0x7766554433221100);
10807 __ Mov(x17, 0xffeeddccbbaa9988);
10808
10809 __ Casp(x2, x3, x0, x1, MemOperand(x21));
10810 __ Casp(x4, x5, x0, x1, MemOperand(x22));
10811 __ Caspa(x6, x7, x0, x1, MemOperand(x23));
10812 __ Caspa(x8, x9, x0, x1, MemOperand(x24));
10813 __ Caspl(x10, x11, x0, x1, MemOperand(x25));
10814 __ Caspl(x12, x13, x0, x1, MemOperand(x26));
10815 __ Caspal(x14, x15, x0, x1, MemOperand(x27));
10816 __ Caspal(x16, x17, x0, x1, MemOperand(x28));
10817
10818 END();
10819
10820 if (CAN_RUN()) {
10821 RUN();
10822
10823 ASSERT_EQUAL_64(0x7766554433221100, x2);
10824 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x3);
10825 ASSERT_EQUAL_64(0x7766554433221100, x4);
10826 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x5);
10827
10828 ASSERT_EQUAL_64(0xfedcba9876543210, x6);
10829 ASSERT_EQUAL_64(0x0123456789abcdef, x7);
10830 ASSERT_EQUAL_64(0xfedcba9876543210, x8);
10831 ASSERT_EQUAL_64(0x0123456789abcdef, x9);
10832
10833 ASSERT_EQUAL_64(0xfedcba9876543210, x10);
10834 ASSERT_EQUAL_64(0x0123456789abcdef, x11);
10835 ASSERT_EQUAL_64(0xfedcba9876543210, x12);
10836 ASSERT_EQUAL_64(0x0123456789abcdef, x13);
10837
10838 ASSERT_EQUAL_64(0x7766554433221100, x14);
10839 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x15);
10840 ASSERT_EQUAL_64(0x7766554433221100, x16);
10841 ASSERT_EQUAL_64(0xffeeddccbbaa9988, x17);
10842
10843 ASSERT_EQUAL_64(0x7766554433221100, data1[0]);
10844 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data1[1]);
10845 ASSERT_EQUAL_64(0xfedcba9876543210, data1[2]);
10846 ASSERT_EQUAL_64(0x0123456789abcdef, data1[3]);
10847
10848 ASSERT_EQUAL_64(0xfffffff00fffffff, data2[0]);
10849 ASSERT_EQUAL_64(0xfffffff11fffffff, data2[1]);
10850 ASSERT_EQUAL_64(0xfedcba9876543210, data2[2]);
10851 ASSERT_EQUAL_64(0x0123456789abcdef, data2[3]);
10852
10853 ASSERT_EQUAL_64(0x7766554433221100, data3[0]);
10854 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data3[1]);
10855 ASSERT_EQUAL_64(0xfedcba9876543210, data3[2]);
10856 ASSERT_EQUAL_64(0x0123456789abcdef, data3[3]);
10857
10858 ASSERT_EQUAL_64(0x7766554433221100, data4[0]);
10859 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data4[1]);
10860 ASSERT_EQUAL_64(0xfffffff00fffffff, data4[2]);
10861 ASSERT_EQUAL_64(0xfffffff11fffffff, data4[3]);
10862
10863 ASSERT_EQUAL_64(0x7766554433221100, data5[0]);
10864 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data5[1]);
10865 ASSERT_EQUAL_64(0xfedcba9876543210, data5[2]);
10866 ASSERT_EQUAL_64(0x0123456789abcdef, data5[3]);
10867
10868 ASSERT_EQUAL_64(0x7766554433221100, data6[0]);
10869 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data6[1]);
10870 ASSERT_EQUAL_64(0xfffffff00fffffff, data6[2]);
10871 ASSERT_EQUAL_64(0xfffffff11fffffff, data6[3]);
10872
10873 ASSERT_EQUAL_64(0x7766554433221100, data7[0]);
10874 ASSERT_EQUAL_64(0xffeeddccbbaa9988, data7[1]);
10875 ASSERT_EQUAL_64(0xfedcba9876543210, data7[2]);
10876 ASSERT_EQUAL_64(0x0123456789abcdef, data7[3]);
10877
10878 ASSERT_EQUAL_64(0xfffffff00fffffff, data8[0]);
10879 ASSERT_EQUAL_64(0xfffffff11fffffff, data8[1]);
10880 ASSERT_EQUAL_64(0xfedcba9876543210, data8[2]);
10881 ASSERT_EQUAL_64(0x0123456789abcdef, data8[3]);
10882 }
10883 }
10884
10885
10886 typedef void (MacroAssembler::*AtomicMemoryLoadSignature)(
10887 const Register& rs, const Register& rt, const MemOperand& src);
10888 typedef void (MacroAssembler::*AtomicMemoryStoreSignature)(
10889 const Register& rs, const MemOperand& src);
10890
AtomicMemoryWHelper(AtomicMemoryLoadSignature * load_funcs,AtomicMemoryStoreSignature * store_funcs,uint64_t arg1,uint64_t arg2,uint64_t expected,uint64_t result_mask)10891 void AtomicMemoryWHelper(AtomicMemoryLoadSignature* load_funcs,
10892 AtomicMemoryStoreSignature* store_funcs,
10893 uint64_t arg1,
10894 uint64_t arg2,
10895 uint64_t expected,
10896 uint64_t result_mask) {
10897 uint64_t data0[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10898 uint64_t data1[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10899 uint64_t data2[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10900 uint64_t data3[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10901 uint64_t data4[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10902 uint64_t data5[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10903
10904 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10905 START();
10906
10907 __ Mov(x20, reinterpret_cast<uintptr_t>(data0));
10908 __ Mov(x21, reinterpret_cast<uintptr_t>(data1));
10909 __ Mov(x22, reinterpret_cast<uintptr_t>(data2));
10910 __ Mov(x23, reinterpret_cast<uintptr_t>(data3));
10911
10912 __ Mov(x0, arg1);
10913 __ Mov(x1, arg1);
10914 __ Mov(x2, arg1);
10915 __ Mov(x3, arg1);
10916
10917 (masm.*(load_funcs[0]))(w0, w10, MemOperand(x20));
10918 (masm.*(load_funcs[1]))(w1, w11, MemOperand(x21));
10919 (masm.*(load_funcs[2]))(w2, w12, MemOperand(x22));
10920 (masm.*(load_funcs[3]))(w3, w13, MemOperand(x23));
10921
10922 if (store_funcs != NULL) {
10923 __ Mov(x24, reinterpret_cast<uintptr_t>(data4));
10924 __ Mov(x25, reinterpret_cast<uintptr_t>(data5));
10925 __ Mov(x4, arg1);
10926 __ Mov(x5, arg1);
10927
10928 (masm.*(store_funcs[0]))(w4, MemOperand(x24));
10929 (masm.*(store_funcs[1]))(w5, MemOperand(x25));
10930 }
10931
10932 END();
10933
10934 if (CAN_RUN()) {
10935 RUN();
10936
10937 uint64_t stored_value = arg2 & result_mask;
10938 ASSERT_EQUAL_64(stored_value, x10);
10939 ASSERT_EQUAL_64(stored_value, x11);
10940 ASSERT_EQUAL_64(stored_value, x12);
10941 ASSERT_EQUAL_64(stored_value, x13);
10942
10943 // The data fields contain arg2 already then only the bits masked by
10944 // result_mask are overwritten.
10945 uint64_t final_expected = (arg2 & ~result_mask) | (expected & result_mask);
10946 ASSERT_EQUAL_64(final_expected, data0[0]);
10947 ASSERT_EQUAL_64(final_expected, data1[0]);
10948 ASSERT_EQUAL_64(final_expected, data2[0]);
10949 ASSERT_EQUAL_64(final_expected, data3[0]);
10950
10951 if (store_funcs != NULL) {
10952 ASSERT_EQUAL_64(final_expected, data4[0]);
10953 ASSERT_EQUAL_64(final_expected, data5[0]);
10954 }
10955 }
10956 }
10957
AtomicMemoryXHelper(AtomicMemoryLoadSignature * load_funcs,AtomicMemoryStoreSignature * store_funcs,uint64_t arg1,uint64_t arg2,uint64_t expected)10958 void AtomicMemoryXHelper(AtomicMemoryLoadSignature* load_funcs,
10959 AtomicMemoryStoreSignature* store_funcs,
10960 uint64_t arg1,
10961 uint64_t arg2,
10962 uint64_t expected) {
10963 uint64_t data0[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10964 uint64_t data1[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10965 uint64_t data2[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10966 uint64_t data3[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10967 uint64_t data4[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10968 uint64_t data5[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {arg2, 0};
10969
10970 SETUP_WITH_FEATURES(CPUFeatures::kAtomics);
10971 START();
10972
10973 __ Mov(x20, reinterpret_cast<uintptr_t>(data0));
10974 __ Mov(x21, reinterpret_cast<uintptr_t>(data1));
10975 __ Mov(x22, reinterpret_cast<uintptr_t>(data2));
10976 __ Mov(x23, reinterpret_cast<uintptr_t>(data3));
10977
10978 __ Mov(x0, arg1);
10979 __ Mov(x1, arg1);
10980 __ Mov(x2, arg1);
10981 __ Mov(x3, arg1);
10982
10983 (masm.*(load_funcs[0]))(x0, x10, MemOperand(x20));
10984 (masm.*(load_funcs[1]))(x1, x11, MemOperand(x21));
10985 (masm.*(load_funcs[2]))(x2, x12, MemOperand(x22));
10986 (masm.*(load_funcs[3]))(x3, x13, MemOperand(x23));
10987
10988 if (store_funcs != NULL) {
10989 __ Mov(x24, reinterpret_cast<uintptr_t>(data4));
10990 __ Mov(x25, reinterpret_cast<uintptr_t>(data5));
10991 __ Mov(x4, arg1);
10992 __ Mov(x5, arg1);
10993
10994 (masm.*(store_funcs[0]))(x4, MemOperand(x24));
10995 (masm.*(store_funcs[1]))(x5, MemOperand(x25));
10996 }
10997
10998 END();
10999
11000 if (CAN_RUN()) {
11001 RUN();
11002
11003 ASSERT_EQUAL_64(arg2, x10);
11004 ASSERT_EQUAL_64(arg2, x11);
11005 ASSERT_EQUAL_64(arg2, x12);
11006 ASSERT_EQUAL_64(arg2, x13);
11007
11008 ASSERT_EQUAL_64(expected, data0[0]);
11009 ASSERT_EQUAL_64(expected, data1[0]);
11010 ASSERT_EQUAL_64(expected, data2[0]);
11011 ASSERT_EQUAL_64(expected, data3[0]);
11012
11013 if (store_funcs != NULL) {
11014 ASSERT_EQUAL_64(expected, data4[0]);
11015 ASSERT_EQUAL_64(expected, data5[0]);
11016 }
11017 }
11018 }
11019
11020 // clang-format off
11021 #define MAKE_LOADS(NAME) \
11022 {&MacroAssembler::Ld##NAME, \
11023 &MacroAssembler::Ld##NAME##a, \
11024 &MacroAssembler::Ld##NAME##l, \
11025 &MacroAssembler::Ld##NAME##al}
11026 #define MAKE_STORES(NAME) \
11027 {&MacroAssembler::St##NAME, &MacroAssembler::St##NAME##l}
11028
11029 #define MAKE_B_LOADS(NAME) \
11030 {&MacroAssembler::Ld##NAME##b, \
11031 &MacroAssembler::Ld##NAME##ab, \
11032 &MacroAssembler::Ld##NAME##lb, \
11033 &MacroAssembler::Ld##NAME##alb}
11034 #define MAKE_B_STORES(NAME) \
11035 {&MacroAssembler::St##NAME##b, &MacroAssembler::St##NAME##lb}
11036
11037 #define MAKE_H_LOADS(NAME) \
11038 {&MacroAssembler::Ld##NAME##h, \
11039 &MacroAssembler::Ld##NAME##ah, \
11040 &MacroAssembler::Ld##NAME##lh, \
11041 &MacroAssembler::Ld##NAME##alh}
11042 #define MAKE_H_STORES(NAME) \
11043 {&MacroAssembler::St##NAME##h, &MacroAssembler::St##NAME##lh}
11044 // clang-format on
11045
TEST(atomic_memory_add)11046 TEST(atomic_memory_add) {
11047 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(add);
11048 AtomicMemoryStoreSignature stores[] = MAKE_STORES(add);
11049 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(add);
11050 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(add);
11051 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(add);
11052 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(add);
11053
11054 // The arguments are chosen to have two useful properties:
11055 // * When multiplied by small values (such as a register index), this value
11056 // is clearly readable in the result.
11057 // * The value is not formed from repeating fixed-size smaller values, so it
11058 // can be used to detect endianness-related errors.
11059 uint64_t arg1 = 0x0100001000100101;
11060 uint64_t arg2 = 0x0200002000200202;
11061 uint64_t expected = arg1 + arg2;
11062
11063 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11064 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11065 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11066 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11067 }
11068
TEST(atomic_memory_clr)11069 TEST(atomic_memory_clr) {
11070 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(clr);
11071 AtomicMemoryStoreSignature stores[] = MAKE_STORES(clr);
11072 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(clr);
11073 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(clr);
11074 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(clr);
11075 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(clr);
11076
11077 uint64_t arg1 = 0x0300003000300303;
11078 uint64_t arg2 = 0x0500005000500505;
11079 uint64_t expected = arg2 & ~arg1;
11080
11081 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11082 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11083 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11084 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11085 }
11086
TEST(atomic_memory_eor)11087 TEST(atomic_memory_eor) {
11088 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(eor);
11089 AtomicMemoryStoreSignature stores[] = MAKE_STORES(eor);
11090 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(eor);
11091 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(eor);
11092 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(eor);
11093 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(eor);
11094
11095 uint64_t arg1 = 0x0300003000300303;
11096 uint64_t arg2 = 0x0500005000500505;
11097 uint64_t expected = arg1 ^ arg2;
11098
11099 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11100 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11101 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11102 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11103 }
11104
TEST(atomic_memory_set)11105 TEST(atomic_memory_set) {
11106 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(set);
11107 AtomicMemoryStoreSignature stores[] = MAKE_STORES(set);
11108 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(set);
11109 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(set);
11110 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(set);
11111 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(set);
11112
11113 uint64_t arg1 = 0x0300003000300303;
11114 uint64_t arg2 = 0x0500005000500505;
11115 uint64_t expected = arg1 | arg2;
11116
11117 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11118 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11119 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11120 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11121 }
11122
TEST(atomic_memory_smax)11123 TEST(atomic_memory_smax) {
11124 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(smax);
11125 AtomicMemoryStoreSignature stores[] = MAKE_STORES(smax);
11126 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(smax);
11127 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(smax);
11128 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(smax);
11129 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(smax);
11130
11131 uint64_t arg1 = 0x8100000080108181;
11132 uint64_t arg2 = 0x0100001000100101;
11133 uint64_t expected = 0x0100001000100101;
11134
11135 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11136 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11137 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11138 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11139 }
11140
TEST(atomic_memory_smin)11141 TEST(atomic_memory_smin) {
11142 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(smin);
11143 AtomicMemoryStoreSignature stores[] = MAKE_STORES(smin);
11144 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(smin);
11145 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(smin);
11146 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(smin);
11147 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(smin);
11148
11149 uint64_t arg1 = 0x8100000080108181;
11150 uint64_t arg2 = 0x0100001000100101;
11151 uint64_t expected = 0x8100000080108181;
11152
11153 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11154 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11155 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11156 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11157 }
11158
TEST(atomic_memory_umax)11159 TEST(atomic_memory_umax) {
11160 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(umax);
11161 AtomicMemoryStoreSignature stores[] = MAKE_STORES(umax);
11162 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(umax);
11163 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(umax);
11164 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(umax);
11165 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(umax);
11166
11167 uint64_t arg1 = 0x8100000080108181;
11168 uint64_t arg2 = 0x0100001000100101;
11169 uint64_t expected = 0x8100000080108181;
11170
11171 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11172 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11173 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11174 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11175 }
11176
TEST(atomic_memory_umin)11177 TEST(atomic_memory_umin) {
11178 AtomicMemoryLoadSignature loads[] = MAKE_LOADS(umin);
11179 AtomicMemoryStoreSignature stores[] = MAKE_STORES(umin);
11180 AtomicMemoryLoadSignature b_loads[] = MAKE_B_LOADS(umin);
11181 AtomicMemoryStoreSignature b_stores[] = MAKE_B_STORES(umin);
11182 AtomicMemoryLoadSignature h_loads[] = MAKE_H_LOADS(umin);
11183 AtomicMemoryStoreSignature h_stores[] = MAKE_H_STORES(umin);
11184
11185 uint64_t arg1 = 0x8100000080108181;
11186 uint64_t arg2 = 0x0100001000100101;
11187 uint64_t expected = 0x0100001000100101;
11188
11189 AtomicMemoryWHelper(b_loads, b_stores, arg1, arg2, expected, kByteMask);
11190 AtomicMemoryWHelper(h_loads, h_stores, arg1, arg2, expected, kHalfWordMask);
11191 AtomicMemoryWHelper(loads, stores, arg1, arg2, expected, kWordMask);
11192 AtomicMemoryXHelper(loads, stores, arg1, arg2, expected);
11193 }
11194
TEST(atomic_memory_swp)11195 TEST(atomic_memory_swp) {
11196 AtomicMemoryLoadSignature loads[] = {&MacroAssembler::Swp,
11197 &MacroAssembler::Swpa,
11198 &MacroAssembler::Swpl,
11199 &MacroAssembler::Swpal};
11200 AtomicMemoryLoadSignature b_loads[] = {&MacroAssembler::Swpb,
11201 &MacroAssembler::Swpab,
11202 &MacroAssembler::Swplb,
11203 &MacroAssembler::Swpalb};
11204 AtomicMemoryLoadSignature h_loads[] = {&MacroAssembler::Swph,
11205 &MacroAssembler::Swpah,
11206 &MacroAssembler::Swplh,
11207 &MacroAssembler::Swpalh};
11208
11209 uint64_t arg1 = 0x0100001000100101;
11210 uint64_t arg2 = 0x0200002000200202;
11211 uint64_t expected = 0x0100001000100101;
11212
11213 // SWP functions have equivalent signatures to the Atomic Memory LD functions
11214 // so we can use the same helper but without the ST aliases.
11215 AtomicMemoryWHelper(b_loads, NULL, arg1, arg2, expected, kByteMask);
11216 AtomicMemoryWHelper(h_loads, NULL, arg1, arg2, expected, kHalfWordMask);
11217 AtomicMemoryWHelper(loads, NULL, arg1, arg2, expected, kWordMask);
11218 AtomicMemoryXHelper(loads, NULL, arg1, arg2, expected);
11219 }
11220
11221
TEST(ldaprb_ldaprh_ldapr)11222 TEST(ldaprb_ldaprh_ldapr) {
11223 uint64_t data0[] = {0x1010101010101010, 0x1010101010101010};
11224 uint64_t data1[] = {0x1010101010101010, 0x1010101010101010};
11225 uint64_t data2[] = {0x1010101010101010, 0x1010101010101010};
11226 uint64_t data3[] = {0x1010101010101010, 0x1010101010101010};
11227
11228 uint64_t* data0_aligned = AlignUp(data0, kXRegSizeInBytes * 2);
11229 uint64_t* data1_aligned = AlignUp(data1, kXRegSizeInBytes * 2);
11230 uint64_t* data2_aligned = AlignUp(data2, kXRegSizeInBytes * 2);
11231 uint64_t* data3_aligned = AlignUp(data3, kXRegSizeInBytes * 2);
11232
11233 SETUP_WITH_FEATURES(CPUFeatures::kRCpc);
11234 START();
11235
11236 __ Mov(x20, reinterpret_cast<uintptr_t>(data0_aligned));
11237 __ Mov(x21, reinterpret_cast<uintptr_t>(data1_aligned));
11238 __ Mov(x22, reinterpret_cast<uintptr_t>(data2_aligned));
11239 __ Mov(x23, reinterpret_cast<uintptr_t>(data3_aligned));
11240
11241 __ Ldaprb(w0, MemOperand(x20));
11242 __ Ldaprh(w1, MemOperand(x21));
11243 __ Ldapr(w2, MemOperand(x22));
11244 __ Ldapr(x3, MemOperand(x23));
11245
11246 END();
11247
11248 if (CAN_RUN()) {
11249 RUN();
11250 ASSERT_EQUAL_64(0x10, x0);
11251 ASSERT_EQUAL_64(0x1010, x1);
11252 ASSERT_EQUAL_64(0x10101010, x2);
11253 ASSERT_EQUAL_64(0x1010101010101010, x3);
11254 }
11255 }
11256
11257
TEST(ldapurb_ldapurh_ldapur)11258 TEST(ldapurb_ldapurh_ldapur) {
11259 uint64_t data[]
11260 __attribute__((aligned(kXRegSizeInBytes * 2))) = {0x0123456789abcdef,
11261 0xfedcba9876543210};
11262
11263 uintptr_t data_base = reinterpret_cast<uintptr_t>(data);
11264
11265 SETUP_WITH_FEATURES(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm);
11266 START();
11267
11268 __ Mov(x20, data_base);
11269 __ Mov(x21, data_base + 2 * sizeof(data[0]));
11270
11271 __ Ldaprb(w0, MemOperand(x20));
11272 __ Ldaprh(w1, MemOperand(x20));
11273 __ Ldapr(w2, MemOperand(x20));
11274 __ Ldapr(x3, MemOperand(x20));
11275 __ Ldaprb(w4, MemOperand(x20, 12));
11276 __ Ldaprh(w5, MemOperand(x20, 8));
11277 __ Ldapr(w6, MemOperand(x20, 10));
11278 __ Ldapr(x7, MemOperand(x20, 7));
11279 __ Ldaprb(w8, MemOperand(x21, -1));
11280 __ Ldaprh(w9, MemOperand(x21, -3));
11281 __ Ldapr(w10, MemOperand(x21, -9));
11282 __ Ldapr(x11, MemOperand(x21, -12));
11283
11284 END();
11285
11286 if (CAN_RUN()) {
11287 RUN();
11288 ASSERT_EQUAL_64(0xef, x0);
11289 ASSERT_EQUAL_64(0xcdef, x1);
11290 ASSERT_EQUAL_64(0x89abcdef, x2);
11291 ASSERT_EQUAL_64(0x0123456789abcdef, x3);
11292 ASSERT_EQUAL_64(0x98, x4);
11293 ASSERT_EQUAL_64(0x3210, x5);
11294 ASSERT_EQUAL_64(0xba987654, x6);
11295 ASSERT_EQUAL_64(0xdcba987654321001, x7);
11296 ASSERT_EQUAL_64(0xfe, x8);
11297 ASSERT_EQUAL_64(0xdcba, x9);
11298 ASSERT_EQUAL_64(0x54321001, x10);
11299 ASSERT_EQUAL_64(0x7654321001234567, x11);
11300 }
11301 }
11302
11303
TEST(ldapursb_ldapursh_ldapursw)11304 TEST(ldapursb_ldapursh_ldapursw) {
11305 uint64_t data[]
11306 __attribute__((aligned(kXRegSizeInBytes * 2))) = {0x0123456789abcdef,
11307 0xfedcba9876543210};
11308
11309 uintptr_t data_base = reinterpret_cast<uintptr_t>(data);
11310
11311 SETUP_WITH_FEATURES(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm);
11312 START();
11313
11314 __ Mov(x20, data_base);
11315 __ Mov(x21, data_base + 2 * sizeof(data[0]));
11316
11317 __ Ldapursb(w0, MemOperand(x20));
11318 __ Ldapursb(x1, MemOperand(x20));
11319 __ Ldapursh(w2, MemOperand(x20));
11320 __ Ldapursh(x3, MemOperand(x20));
11321 __ Ldapursw(x4, MemOperand(x20));
11322 __ Ldapursb(w5, MemOperand(x20, 12));
11323 __ Ldapursb(x6, MemOperand(x20, 12));
11324 __ Ldapursh(w7, MemOperand(x20, 13));
11325 __ Ldapursh(x8, MemOperand(x20, 13));
11326 __ Ldapursw(x9, MemOperand(x20, 10));
11327 __ Ldapursb(w10, MemOperand(x21, -1));
11328 __ Ldapursb(x11, MemOperand(x21, -1));
11329 __ Ldapursh(w12, MemOperand(x21, -4));
11330 __ Ldapursh(x13, MemOperand(x21, -4));
11331 __ Ldapursw(x14, MemOperand(x21, -5));
11332
11333 __ Ldapursb(x15, MemOperand(x20, 8));
11334 __ Ldapursh(x16, MemOperand(x20, 8));
11335 __ Ldapursw(x17, MemOperand(x20, 8));
11336
11337 END();
11338
11339 if (CAN_RUN()) {
11340 RUN();
11341 ASSERT_EQUAL_64(0xffffffef, x0);
11342 ASSERT_EQUAL_64(0xffffffffffffffef, x1);
11343 ASSERT_EQUAL_64(0xffffcdef, x2);
11344 ASSERT_EQUAL_64(0xffffffffffffcdef, x3);
11345 ASSERT_EQUAL_64(0xffffffff89abcdef, x4);
11346 ASSERT_EQUAL_64(0xffffff98, x5);
11347 ASSERT_EQUAL_64(0xffffffffffffff98, x6);
11348 ASSERT_EQUAL_64(0xffffdcba, x7);
11349 ASSERT_EQUAL_64(0xffffffffffffdcba, x8);
11350 ASSERT_EQUAL_64(0xffffffffba987654, x9);
11351 ASSERT_EQUAL_64(0xfffffffe, x10);
11352 ASSERT_EQUAL_64(0xfffffffffffffffe, x11);
11353 ASSERT_EQUAL_64(0xffffba98, x12);
11354 ASSERT_EQUAL_64(0xffffffffffffba98, x13);
11355 ASSERT_EQUAL_64(0xffffffffdcba9876, x14);
11356
11357 ASSERT_EQUAL_64(0x0000000000000010, x15);
11358 ASSERT_EQUAL_64(0x0000000000003210, x16);
11359 ASSERT_EQUAL_64(0x0000000076543210, x17);
11360 }
11361 }
11362
11363
TEST(stlurb_stlurh_strlur)11364 TEST(stlurb_stlurh_strlur) {
11365 uint64_t data[] __attribute__((aligned(kXRegSizeInBytes * 2))) = {0x0, 0x0};
11366
11367 uintptr_t data_base = reinterpret_cast<uintptr_t>(data);
11368
11369 SETUP_WITH_FEATURES(CPUFeatures::kRCpc, CPUFeatures::kRCpcImm);
11370 START();
11371
11372 __ Mov(x0, 0x0011223344556677);
11373 __ Mov(x20, data_base);
11374 __ Mov(x21, data_base + 2 * sizeof(data[0]));
11375
11376 __ Stlrb(w0, MemOperand(x20));
11377 __ Stlrh(w0, MemOperand(x20, 1));
11378 __ Stlr(w0, MemOperand(x20, 3));
11379 __ Stlr(x0, MemOperand(x21, -8));
11380
11381 END();
11382
11383 if (CAN_RUN()) {
11384 RUN();
11385 ASSERT_EQUAL_64(0x0044556677667777, data[0]);
11386 ASSERT_EQUAL_64(0x0011223344556677, data[1]);
11387 }
11388 }
11389
11390
11391 #define SIMPLE_ATOMIC_OPS(V, DEF) \
11392 V(DEF, add) \
11393 V(DEF, clr) \
11394 V(DEF, eor) \
11395 V(DEF, set) \
11396 V(DEF, smax) \
11397 V(DEF, smin) \
11398 V(DEF, umax) \
11399 V(DEF, umin)
11400
11401 #define SIMPLE_ATOMIC_STORE_MODES(V, NAME) \
11402 V(NAME) \
11403 V(NAME##l)
11404
11405 #define SIMPLE_ATOMIC_LOAD_MODES(V, NAME) \
11406 SIMPLE_ATOMIC_STORE_MODES(V, NAME) \
11407 V(NAME##a) \
11408 V(NAME##al)
11409
11410
TEST(unaligned_single_copy_atomicity)11411 TEST(unaligned_single_copy_atomicity) {
11412 uint64_t data0[] = {0x1010101010101010, 0x1010101010101010};
11413 uint64_t dst[] = {0x0000000000000000, 0x0000000000000000};
11414
11415 uint64_t* data0_aligned = AlignUp(data0, kAtomicAccessGranule);
11416 uint64_t* dst_aligned = AlignUp(dst, kAtomicAccessGranule);
11417
11418 CPUFeatures features(CPUFeatures::kAtomics,
11419 CPUFeatures::kLORegions,
11420 CPUFeatures::kRCpc,
11421 CPUFeatures::kRCpcImm);
11422 features.Combine(CPUFeatures::kUSCAT);
11423 SETUP_WITH_FEATURES(features);
11424 START();
11425
11426 __ Mov(x0, 0x0123456789abcdef);
11427 __ Mov(x1, 0x456789abcdef0123);
11428 __ Mov(x2, 0x89abcdef01234567);
11429 __ Mov(x3, 0xcdef0123456789ab);
11430 __ Mov(x18, reinterpret_cast<uintptr_t>(data0_aligned));
11431 __ Mov(x19, reinterpret_cast<uintptr_t>(dst_aligned));
11432 __ Mov(x20, x18);
11433 __ Mov(x21, x19);
11434
11435 for (unsigned i = 0; i < kAtomicAccessGranule; i++) {
11436 __ Stxrb(w0, w1, MemOperand(x20));
11437 __ Stlxrb(w0, w1, MemOperand(x20));
11438 __ Ldxrb(w0, MemOperand(x20));
11439 __ Ldaxrb(w0, MemOperand(x20));
11440 __ Stllrb(w0, MemOperand(x20));
11441 __ Stlrb(w0, MemOperand(x20));
11442 __ Casb(w0, w1, MemOperand(x20));
11443 __ Caslb(w0, w1, MemOperand(x20));
11444 __ Ldlarb(w0, MemOperand(x20));
11445 __ Ldarb(w0, MemOperand(x20));
11446 __ Casab(w0, w1, MemOperand(x20));
11447 __ Casalb(w0, w1, MemOperand(x20));
11448
11449 __ Swpb(w0, w1, MemOperand(x20));
11450 __ Swplb(w0, w1, MemOperand(x20));
11451 __ Swpab(w0, w1, MemOperand(x20));
11452 __ Swpalb(w0, w1, MemOperand(x20));
11453 __ Ldaprb(w0, MemOperand(x20));
11454 // Use offset instead of Add to test Stlurb and Ldapurb.
11455 __ Stlrb(w0, MemOperand(x19, i));
11456 __ Ldaprb(w0, MemOperand(x19, i));
11457 __ Ldapursb(w0, MemOperand(x20));
11458 __ Ldapursb(x0, MemOperand(x20));
11459
11460 #define ATOMIC_LOAD_B(NAME) __ Ld##NAME##b(w0, w1, MemOperand(x20));
11461 #define ATOMIC_STORE_B(NAME) __ St##NAME##b(w0, MemOperand(x20));
11462 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_B)
11463 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_B)
11464 #undef ATOMIC_LOAD_B
11465 #undef ATOMIC_STORE_B
11466
11467 if (i <= (kAtomicAccessGranule - kHRegSizeInBytes)) {
11468 __ Stxrh(w0, w1, MemOperand(x20));
11469 __ Stlxrh(w0, w1, MemOperand(x20));
11470 __ Ldxrh(w0, MemOperand(x20));
11471 __ Ldaxrh(w0, MemOperand(x20));
11472 __ Stllrh(w0, MemOperand(x20));
11473 __ Stlrh(w0, MemOperand(x20));
11474 __ Cash(w0, w1, MemOperand(x20));
11475 __ Caslh(w0, w1, MemOperand(x20));
11476 __ Ldlarh(w0, MemOperand(x20));
11477 __ Ldarh(w0, MemOperand(x20));
11478 __ Casah(w0, w1, MemOperand(x20));
11479 __ Casalh(w0, w1, MemOperand(x20));
11480
11481 __ Swph(w0, w1, MemOperand(x20));
11482 __ Swplh(w0, w1, MemOperand(x20));
11483 __ Swpah(w0, w1, MemOperand(x20));
11484 __ Swpalh(w0, w1, MemOperand(x20));
11485 __ Ldaprh(w0, MemOperand(x20));
11486 // Use offset instead of Add to test Stlurh and Ldapurh.
11487 __ Stlrh(w0, MemOperand(x19, i));
11488 __ Ldaprh(w0, MemOperand(x19, i));
11489 __ Ldapursh(w0, MemOperand(x20));
11490 __ Ldapursh(x0, MemOperand(x20));
11491
11492 #define ATOMIC_LOAD_H(NAME) __ Ld##NAME##h(w0, w1, MemOperand(x20));
11493 #define ATOMIC_STORE_H(NAME) __ St##NAME##h(w0, MemOperand(x20));
11494 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_H)
11495 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_H)
11496 #undef ATOMIC_LOAD_H
11497 #undef ATOMIC_STORE_H
11498 }
11499
11500 if (i <= (kAtomicAccessGranule - kWRegSizeInBytes)) {
11501 __ Stxr(w0, w1, MemOperand(x20));
11502 __ Stlxr(w0, w1, MemOperand(x20));
11503 __ Ldxr(w0, MemOperand(x20));
11504 __ Ldaxr(w0, MemOperand(x20));
11505 __ Stllr(w0, MemOperand(x20));
11506 __ Stlr(w0, MemOperand(x20));
11507 __ Cas(w0, w1, MemOperand(x20));
11508 __ Casl(w0, w1, MemOperand(x20));
11509 __ Ldlar(w0, MemOperand(x20));
11510 __ Ldar(w0, MemOperand(x20));
11511 __ Casa(w0, w1, MemOperand(x20));
11512 __ Casal(w0, w1, MemOperand(x20));
11513
11514 __ Swp(w0, w1, MemOperand(x20));
11515 __ Swpl(w0, w1, MemOperand(x20));
11516 __ Swpa(w0, w1, MemOperand(x20));
11517 __ Swpal(w0, w1, MemOperand(x20));
11518 __ Ldapr(w0, MemOperand(x20));
11519 // Use offset instead of Add to test Stlur and Ldapur.
11520 __ Stlr(w0, MemOperand(x19, i));
11521 __ Ldapr(w0, MemOperand(x19, i));
11522 __ Ldapursw(x0, MemOperand(x20));
11523
11524 #define ATOMIC_LOAD_W(NAME) __ Ld##NAME(w0, w1, MemOperand(x20));
11525 #define ATOMIC_STORE_W(NAME) __ St##NAME(w0, MemOperand(x20));
11526 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_W)
11527 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_W)
11528 #undef ATOMIC_LOAD_W
11529 #undef ATOMIC_STORE_W
11530 }
11531
11532 if (i <= (kAtomicAccessGranule - (kWRegSizeInBytes * 2))) {
11533 __ Casp(w0, w1, w2, w3, MemOperand(x20));
11534 __ Caspl(w0, w1, w2, w3, MemOperand(x20));
11535 __ Caspa(w0, w1, w2, w3, MemOperand(x20));
11536 __ Caspal(w0, w1, w2, w3, MemOperand(x20));
11537 __ Stxp(w0, w1, w2, MemOperand(x20));
11538 __ Stlxp(w0, w1, w2, MemOperand(x20));
11539 __ Ldxp(w0, w1, MemOperand(x20));
11540 __ Ldaxp(w0, w1, MemOperand(x20));
11541 }
11542
11543 if (i <= (kAtomicAccessGranule - kXRegSizeInBytes)) {
11544 __ Stxr(x0, x1, MemOperand(x20));
11545 __ Stlxr(x0, x1, MemOperand(x20));
11546 __ Ldxr(x0, MemOperand(x20));
11547 __ Ldaxr(x0, MemOperand(x20));
11548 __ Stllr(x0, MemOperand(x20));
11549 __ Stlr(x0, MemOperand(x20));
11550 __ Cas(x0, x1, MemOperand(x20));
11551 __ Casl(x0, x1, MemOperand(x20));
11552 __ Ldlar(x0, MemOperand(x20));
11553 __ Ldar(x0, MemOperand(x20));
11554 __ Casa(x0, x1, MemOperand(x20));
11555 __ Casal(x0, x1, MemOperand(x20));
11556
11557 __ Swp(x0, x1, MemOperand(x20));
11558 __ Swpl(x0, x1, MemOperand(x20));
11559 __ Swpa(x0, x1, MemOperand(x20));
11560 __ Swpal(x0, x1, MemOperand(x20));
11561 __ Ldapr(x0, MemOperand(x20));
11562 // Use offset instead of Add to test Stlur and Ldapur.
11563 __ Stlr(x0, MemOperand(x19, i));
11564 __ Ldapr(x0, MemOperand(x19, i));
11565
11566 #define ATOMIC_LOAD_X(NAME) __ Ld##NAME(x0, x1, MemOperand(x20));
11567 #define ATOMIC_STORE_X(NAME) __ St##NAME(x0, MemOperand(x20));
11568 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_X)
11569 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_X)
11570 #undef ATOMIC_LOAD_X
11571 #undef ATOMIC_STORE_X
11572 }
11573
11574 if (i <= (kAtomicAccessGranule - (kXRegSizeInBytes * 2))) {
11575 __ Casp(x0, x1, x2, x3, MemOperand(x20));
11576 __ Caspl(x0, x1, x2, x3, MemOperand(x20));
11577 __ Caspa(x0, x1, x2, x3, MemOperand(x20));
11578 __ Caspal(x0, x1, x2, x3, MemOperand(x20));
11579 __ Stxp(x0, x1, x2, MemOperand(x20));
11580 __ Stlxp(x0, x1, x2, MemOperand(x20));
11581 __ Ldxp(x0, x1, MemOperand(x20));
11582 __ Ldaxp(x0, x1, MemOperand(x20));
11583 }
11584
11585 __ Add(x20, x20, 1);
11586 __ Add(x21, x21, 1);
11587 }
11588 END();
11589
11590 if (CAN_RUN()) {
11591 // We can't detect kUSCAT with the CPUFeaturesAuditor so it fails the seen
11592 // check.
11593 RUN_WITHOUT_SEEN_FEATURE_CHECK();
11594 }
11595 }
11596
11597
11598 #if defined(VIXL_NEGATIVE_TESTING) && defined(VIXL_INCLUDE_SIMULATOR_AARCH64)
11599
11600 #define CHECK_ALIGN_FAIL(i, expr) \
11601 { \
11602 CPUFeatures features(CPUFeatures::kAtomics, \
11603 CPUFeatures::kLORegions, \
11604 CPUFeatures::kRCpc, \
11605 CPUFeatures::kRCpcImm); \
11606 features.Combine(CPUFeatures::kUSCAT); \
11607 SETUP_WITH_FEATURES(features); \
11608 START(); \
11609 __ Mov(x0, 0x0123456789abcdef); \
11610 __ Mov(x1, 0x456789abcdef0123); \
11611 __ Mov(x2, 0x89abcdef01234567); \
11612 __ Mov(x3, 0xcdef0123456789ab); \
11613 __ Mov(x20, reinterpret_cast<uintptr_t>(data0_aligned)); \
11614 __ Mov(x21, reinterpret_cast<uintptr_t>(dst_aligned)); \
11615 __ Add(x20, x20, i); \
11616 __ Add(x21, x21, i); \
11617 expr; \
11618 END(); \
11619 if (CAN_RUN()) { \
11620 /* We can't detect kUSCAT with the CPUFeaturesAuditor so it fails the */ \
11621 /* seen check. */ \
11622 MUST_FAIL_WITH_MESSAGE(RUN_WITHOUT_SEEN_FEATURE_CHECK(), \
11623 "ALIGNMENT EXCEPTION"); \
11624 } \
11625 }
11626
TEST(unaligned_single_copy_atomicity_negative_test)11627 TEST(unaligned_single_copy_atomicity_negative_test) {
11628 uint64_t data0[] = {0x1010101010101010, 0x1010101010101010};
11629 uint64_t dst[] = {0x0000000000000000, 0x0000000000000000};
11630
11631 uint64_t* data0_aligned = AlignUp(data0, kAtomicAccessGranule);
11632 uint64_t* dst_aligned = AlignUp(dst, kAtomicAccessGranule);
11633
11634 for (unsigned i = 0; i < kAtomicAccessGranule; i++) {
11635 if (i > (kAtomicAccessGranule - kHRegSizeInBytes)) {
11636 CHECK_ALIGN_FAIL(i, __ Stxrh(w0, w1, MemOperand(x20)));
11637 CHECK_ALIGN_FAIL(i, __ Stlxrh(w0, w1, MemOperand(x20)));
11638 CHECK_ALIGN_FAIL(i, __ Ldxrh(w0, MemOperand(x20)));
11639 CHECK_ALIGN_FAIL(i, __ Ldaxrh(w0, MemOperand(x20)));
11640 CHECK_ALIGN_FAIL(i, __ Stllrh(w0, MemOperand(x20)));
11641 CHECK_ALIGN_FAIL(i, __ Stlrh(w0, MemOperand(x20)));
11642 CHECK_ALIGN_FAIL(i, __ Cash(w0, w1, MemOperand(x20)));
11643 CHECK_ALIGN_FAIL(i, __ Caslh(w0, w1, MemOperand(x20)));
11644 CHECK_ALIGN_FAIL(i, __ Ldlarh(w0, MemOperand(x20)));
11645 CHECK_ALIGN_FAIL(i, __ Ldarh(w0, MemOperand(x20)));
11646 CHECK_ALIGN_FAIL(i, __ Casah(w0, w1, MemOperand(x20)));
11647 CHECK_ALIGN_FAIL(i, __ Casalh(w0, w1, MemOperand(x20)));
11648
11649 CHECK_ALIGN_FAIL(i, __ Swph(w0, w1, MemOperand(x20)));
11650 CHECK_ALIGN_FAIL(i, __ Swplh(w0, w1, MemOperand(x20)));
11651 CHECK_ALIGN_FAIL(i, __ Swpah(w0, w1, MemOperand(x20)));
11652 CHECK_ALIGN_FAIL(i, __ Swpalh(w0, w1, MemOperand(x20)));
11653 CHECK_ALIGN_FAIL(i, __ Ldaprh(w0, MemOperand(x20)));
11654 // Use offset instead of Add to test Stlurh and Ldapurh.
11655 CHECK_ALIGN_FAIL(0, __ Stlrh(w0, MemOperand(x20, i)));
11656 CHECK_ALIGN_FAIL(0, __ Ldaprh(w0, MemOperand(x20, i)));
11657 CHECK_ALIGN_FAIL(i, __ Ldapursh(w0, MemOperand(x20)));
11658 CHECK_ALIGN_FAIL(i, __ Ldapursh(x0, MemOperand(x20)));
11659
11660 #define ATOMIC_LOAD_H(NAME) \
11661 CHECK_ALIGN_FAIL(i, __ Ld##NAME##h(w0, w1, MemOperand(x20)));
11662 #define ATOMIC_STORE_H(NAME) \
11663 CHECK_ALIGN_FAIL(i, __ St##NAME##h(w0, MemOperand(x20)));
11664 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_H)
11665 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_H)
11666 #undef ATOMIC_LOAD_H
11667 #undef ATOMIC_STORE_H
11668 }
11669
11670 if (i > (kAtomicAccessGranule - kWRegSizeInBytes)) {
11671 CHECK_ALIGN_FAIL(i, __ Stxr(w0, w1, MemOperand(x20)));
11672 CHECK_ALIGN_FAIL(i, __ Stlxr(w0, w1, MemOperand(x20)));
11673 CHECK_ALIGN_FAIL(i, __ Ldxr(w0, MemOperand(x20)));
11674 CHECK_ALIGN_FAIL(i, __ Ldaxr(w0, MemOperand(x20)));
11675 CHECK_ALIGN_FAIL(i, __ Stllr(w0, MemOperand(x20)));
11676 CHECK_ALIGN_FAIL(i, __ Stlr(w0, MemOperand(x20)));
11677 CHECK_ALIGN_FAIL(i, __ Cas(w0, w1, MemOperand(x20)));
11678 CHECK_ALIGN_FAIL(i, __ Casl(w0, w1, MemOperand(x20)));
11679 CHECK_ALIGN_FAIL(i, __ Ldlar(w0, MemOperand(x20)));
11680 CHECK_ALIGN_FAIL(i, __ Ldar(w0, MemOperand(x20)));
11681 CHECK_ALIGN_FAIL(i, __ Casa(w0, w1, MemOperand(x20)));
11682 CHECK_ALIGN_FAIL(i, __ Casal(w0, w1, MemOperand(x20)));
11683
11684 CHECK_ALIGN_FAIL(i, __ Swp(w0, w1, MemOperand(x20)));
11685 CHECK_ALIGN_FAIL(i, __ Swpl(w0, w1, MemOperand(x20)));
11686 CHECK_ALIGN_FAIL(i, __ Swpa(w0, w1, MemOperand(x20)));
11687 CHECK_ALIGN_FAIL(i, __ Swpal(w0, w1, MemOperand(x20)));
11688 CHECK_ALIGN_FAIL(i, __ Ldapr(w0, MemOperand(x20)));
11689 // Use offset instead of add to test Stlur and Ldapur.
11690 CHECK_ALIGN_FAIL(0, __ Stlr(w0, MemOperand(x20, i)));
11691 CHECK_ALIGN_FAIL(0, __ Ldapr(w0, MemOperand(x20, i)));
11692 CHECK_ALIGN_FAIL(i, __ Ldapursw(x0, MemOperand(x20)));
11693
11694 #define ATOMIC_LOAD_W(NAME) \
11695 CHECK_ALIGN_FAIL(i, __ Ld##NAME(w0, w1, MemOperand(x20)));
11696 #define ATOMIC_STORE_W(NAME) \
11697 CHECK_ALIGN_FAIL(i, __ St##NAME(w0, MemOperand(x20)));
11698 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_W)
11699 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_W)
11700 #undef ATOMIC_LOAD_W
11701 #undef ATOMIC_STORE_W
11702 }
11703
11704 if (i > (kAtomicAccessGranule - (kWRegSizeInBytes * 2))) {
11705 CHECK_ALIGN_FAIL(i, __ Casp(w0, w1, w2, w3, MemOperand(x20)));
11706 CHECK_ALIGN_FAIL(i, __ Caspl(w0, w1, w2, w3, MemOperand(x20)));
11707 CHECK_ALIGN_FAIL(i, __ Caspa(w0, w1, w2, w3, MemOperand(x20)));
11708 CHECK_ALIGN_FAIL(i, __ Caspal(w0, w1, w2, w3, MemOperand(x20)));
11709 CHECK_ALIGN_FAIL(i, __ Stxp(w0, w1, w2, MemOperand(x20)));
11710 CHECK_ALIGN_FAIL(i, __ Stlxp(w0, w1, w2, MemOperand(x20)));
11711 CHECK_ALIGN_FAIL(i, __ Ldxp(w0, w1, MemOperand(x20)));
11712 CHECK_ALIGN_FAIL(i, __ Ldaxp(w0, w1, MemOperand(x20)));
11713 }
11714
11715 if (i > (kAtomicAccessGranule - kXRegSizeInBytes)) {
11716 CHECK_ALIGN_FAIL(i, __ Stxr(x0, x1, MemOperand(x20)));
11717 CHECK_ALIGN_FAIL(i, __ Stlxr(x0, x1, MemOperand(x20)));
11718 CHECK_ALIGN_FAIL(i, __ Ldxr(x0, MemOperand(x20)));
11719 CHECK_ALIGN_FAIL(i, __ Ldaxr(x0, MemOperand(x20)));
11720 CHECK_ALIGN_FAIL(i, __ Stllr(x0, MemOperand(x20)));
11721 CHECK_ALIGN_FAIL(i, __ Stlr(x0, MemOperand(x20)));
11722 CHECK_ALIGN_FAIL(i, __ Cas(x0, x1, MemOperand(x20)));
11723 CHECK_ALIGN_FAIL(i, __ Casl(x0, x1, MemOperand(x20)));
11724 CHECK_ALIGN_FAIL(i, __ Ldlar(x0, MemOperand(x20)));
11725 CHECK_ALIGN_FAIL(i, __ Ldar(x0, MemOperand(x20)));
11726 CHECK_ALIGN_FAIL(i, __ Casa(x0, x1, MemOperand(x20)));
11727 CHECK_ALIGN_FAIL(i, __ Casal(x0, x1, MemOperand(x20)));
11728
11729 CHECK_ALIGN_FAIL(i, __ Swp(x0, x1, MemOperand(x20)));
11730 CHECK_ALIGN_FAIL(i, __ Swpl(x0, x1, MemOperand(x20)));
11731 CHECK_ALIGN_FAIL(i, __ Swpa(x0, x1, MemOperand(x20)));
11732 CHECK_ALIGN_FAIL(i, __ Swpal(x0, x1, MemOperand(x20)));
11733 CHECK_ALIGN_FAIL(i, __ Ldapr(x0, MemOperand(x20)));
11734 // Use offset instead of add to test Stlur and Ldapur.
11735 CHECK_ALIGN_FAIL(0, __ Stlr(x0, MemOperand(x20, i)));
11736 CHECK_ALIGN_FAIL(0, __ Ldapr(x0, MemOperand(x20, i)));
11737
11738 #define ATOMIC_LOAD_X(NAME) \
11739 CHECK_ALIGN_FAIL(i, __ Ld##NAME(x0, x1, MemOperand(x20)));
11740 #define ATOMIC_STORE_X(NAME) \
11741 CHECK_ALIGN_FAIL(i, __ St##NAME(x0, MemOperand(x20)));
11742 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_LOAD_MODES, ATOMIC_LOAD_X)
11743 SIMPLE_ATOMIC_OPS(SIMPLE_ATOMIC_STORE_MODES, ATOMIC_STORE_X)
11744 #undef ATOMIC_LOAD_X
11745 #undef ATOMIC_STORE_X
11746 }
11747
11748 if (i > (kAtomicAccessGranule - (kXRegSizeInBytes * 2))) {
11749 CHECK_ALIGN_FAIL(i, __ Casp(x0, x1, x2, x3, MemOperand(x20)));
11750 CHECK_ALIGN_FAIL(i, __ Caspl(x0, x1, x2, x3, MemOperand(x20)));
11751 CHECK_ALIGN_FAIL(i, __ Caspa(x0, x1, x2, x3, MemOperand(x20)));
11752 CHECK_ALIGN_FAIL(i, __ Caspal(x0, x1, x2, x3, MemOperand(x20)));
11753 CHECK_ALIGN_FAIL(i, __ Stxp(x0, x1, x2, MemOperand(x20)));
11754 CHECK_ALIGN_FAIL(i, __ Stlxp(x0, x1, x2, MemOperand(x20)));
11755 CHECK_ALIGN_FAIL(i, __ Ldxp(x0, x1, MemOperand(x20)));
11756 CHECK_ALIGN_FAIL(i, __ Ldaxp(x0, x1, MemOperand(x20)));
11757 }
11758 }
11759 }
11760
TEST(unaligned_single_copy_atomicity_negative_test_2)11761 TEST(unaligned_single_copy_atomicity_negative_test_2) {
11762 uint64_t data[] = {0x1010101010101010, 0x1010101010101010};
11763
11764 uint64_t* data_aligned = AlignUp(data, kAtomicAccessGranule);
11765
11766 // Check that the same code doesn't fail with USCAT enabled but does
11767 // fail when not enabled.
11768 {
11769 SETUP_WITH_FEATURES(CPUFeatures::kUSCAT);
11770 START();
11771 __ Mov(x0, reinterpret_cast<uintptr_t>(data_aligned));
11772 __ Add(x0, x0, 1);
11773 __ Ldxrh(w1, MemOperand(x0));
11774 END();
11775 if (CAN_RUN()) {
11776 RUN_WITHOUT_SEEN_FEATURE_CHECK();
11777 }
11778 }
11779 {
11780 SETUP();
11781 START();
11782 __ Mov(x0, reinterpret_cast<uintptr_t>(data_aligned));
11783 __ Add(x0, x0, 1);
11784 __ Ldxrh(w1, MemOperand(x0));
11785 END();
11786 if (CAN_RUN()) {
11787 MUST_FAIL_WITH_MESSAGE(RUN(), "ALIGNMENT EXCEPTION");
11788 }
11789 }
11790 }
11791 #endif // VIXL_NEGATIVE_TESTING && VIXL_INCLUDE_SIMULATOR_AARCH64
11792
11793
TEST(load_store_tagged_immediate_offset)11794 TEST(load_store_tagged_immediate_offset) {
11795 uint64_t tags[] = {0x00, 0x1, 0x55, 0xff};
11796 int tag_count = sizeof(tags) / sizeof(tags[0]);
11797
11798 const int kMaxDataLength = 160;
11799
11800 for (int i = 0; i < tag_count; i++) {
11801 unsigned char src[kMaxDataLength];
11802 uint64_t src_raw = reinterpret_cast<uint64_t>(src);
11803 uint64_t src_tag = tags[i];
11804 uint64_t src_tagged = CPU::SetPointerTag(src_raw, src_tag);
11805
11806 for (int k = 0; k < kMaxDataLength; k++) {
11807 src[k] = k + 1;
11808 }
11809
11810 for (int j = 0; j < tag_count; j++) {
11811 unsigned char dst[kMaxDataLength];
11812 uint64_t dst_raw = reinterpret_cast<uint64_t>(dst);
11813 uint64_t dst_tag = tags[j];
11814 uint64_t dst_tagged = CPU::SetPointerTag(dst_raw, dst_tag);
11815
11816 memset(dst, 0, kMaxDataLength);
11817
11818 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
11819 START();
11820
11821 __ Mov(x0, src_tagged);
11822 __ Mov(x1, dst_tagged);
11823
11824 int offset = 0;
11825
11826 // Scaled-immediate offsets.
11827 {
11828 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11829 __ ldp(q0, q1, MemOperand(x0, offset));
11830 __ stp(q0, q1, MemOperand(x1, offset));
11831 }
11832 offset += 2 * kQRegSizeInBytes;
11833
11834 {
11835 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11836 __ ldp(x2, x3, MemOperand(x0, offset));
11837 __ stp(x2, x3, MemOperand(x1, offset));
11838 }
11839 offset += 2 * kXRegSizeInBytes;
11840
11841 {
11842 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11843 __ ldpsw(x2, x3, MemOperand(x0, offset));
11844 __ stp(w2, w3, MemOperand(x1, offset));
11845 }
11846 offset += 2 * kWRegSizeInBytes;
11847
11848 {
11849 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11850 __ ldp(d0, d1, MemOperand(x0, offset));
11851 __ stp(d0, d1, MemOperand(x1, offset));
11852 }
11853 offset += 2 * kDRegSizeInBytes;
11854
11855 {
11856 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11857 __ ldp(w2, w3, MemOperand(x0, offset));
11858 __ stp(w2, w3, MemOperand(x1, offset));
11859 }
11860 offset += 2 * kWRegSizeInBytes;
11861
11862 {
11863 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11864 __ ldp(s0, s1, MemOperand(x0, offset));
11865 __ stp(s0, s1, MemOperand(x1, offset));
11866 }
11867 offset += 2 * kSRegSizeInBytes;
11868
11869 {
11870 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11871 __ ldr(x2, MemOperand(x0, offset), RequireScaledOffset);
11872 __ str(x2, MemOperand(x1, offset), RequireScaledOffset);
11873 }
11874 offset += kXRegSizeInBytes;
11875
11876 {
11877 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11878 __ ldr(d0, MemOperand(x0, offset), RequireScaledOffset);
11879 __ str(d0, MemOperand(x1, offset), RequireScaledOffset);
11880 }
11881 offset += kDRegSizeInBytes;
11882
11883 {
11884 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11885 __ ldr(w2, MemOperand(x0, offset), RequireScaledOffset);
11886 __ str(w2, MemOperand(x1, offset), RequireScaledOffset);
11887 }
11888 offset += kWRegSizeInBytes;
11889
11890 {
11891 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11892 __ ldr(s0, MemOperand(x0, offset), RequireScaledOffset);
11893 __ str(s0, MemOperand(x1, offset), RequireScaledOffset);
11894 }
11895 offset += kSRegSizeInBytes;
11896
11897 {
11898 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11899 __ ldrh(w2, MemOperand(x0, offset), RequireScaledOffset);
11900 __ strh(w2, MemOperand(x1, offset), RequireScaledOffset);
11901 }
11902 offset += 2;
11903
11904 {
11905 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11906 __ ldrsh(w2, MemOperand(x0, offset), RequireScaledOffset);
11907 __ strh(w2, MemOperand(x1, offset), RequireScaledOffset);
11908 }
11909 offset += 2;
11910
11911 {
11912 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11913 __ ldrb(w2, MemOperand(x0, offset), RequireScaledOffset);
11914 __ strb(w2, MemOperand(x1, offset), RequireScaledOffset);
11915 }
11916 offset += 1;
11917
11918 {
11919 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11920 __ ldrsb(w2, MemOperand(x0, offset), RequireScaledOffset);
11921 __ strb(w2, MemOperand(x1, offset), RequireScaledOffset);
11922 }
11923 offset += 1;
11924
11925 // Unscaled-immediate offsets.
11926
11927 {
11928 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11929 __ ldur(x2, MemOperand(x0, offset), RequireUnscaledOffset);
11930 __ stur(x2, MemOperand(x1, offset), RequireUnscaledOffset);
11931 }
11932 offset += kXRegSizeInBytes;
11933
11934 {
11935 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11936 __ ldur(d0, MemOperand(x0, offset), RequireUnscaledOffset);
11937 __ stur(d0, MemOperand(x1, offset), RequireUnscaledOffset);
11938 }
11939 offset += kDRegSizeInBytes;
11940
11941 {
11942 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11943 __ ldur(w2, MemOperand(x0, offset), RequireUnscaledOffset);
11944 __ stur(w2, MemOperand(x1, offset), RequireUnscaledOffset);
11945 }
11946 offset += kWRegSizeInBytes;
11947
11948 {
11949 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11950 __ ldur(s0, MemOperand(x0, offset), RequireUnscaledOffset);
11951 __ stur(s0, MemOperand(x1, offset), RequireUnscaledOffset);
11952 }
11953 offset += kSRegSizeInBytes;
11954
11955 {
11956 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11957 __ ldurh(w2, MemOperand(x0, offset), RequireUnscaledOffset);
11958 __ sturh(w2, MemOperand(x1, offset), RequireUnscaledOffset);
11959 }
11960 offset += 2;
11961
11962 {
11963 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11964 __ ldursh(w2, MemOperand(x0, offset), RequireUnscaledOffset);
11965 __ sturh(w2, MemOperand(x1, offset), RequireUnscaledOffset);
11966 }
11967 offset += 2;
11968
11969 {
11970 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11971 __ ldurb(w2, MemOperand(x0, offset), RequireUnscaledOffset);
11972 __ sturb(w2, MemOperand(x1, offset), RequireUnscaledOffset);
11973 }
11974 offset += 1;
11975
11976 {
11977 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
11978 __ ldursb(w2, MemOperand(x0, offset), RequireUnscaledOffset);
11979 __ sturb(w2, MemOperand(x1, offset), RequireUnscaledOffset);
11980 }
11981 offset += 1;
11982
11983 // Extract the tag (so we can test that it was preserved correctly).
11984 __ Ubfx(x0, x0, kAddressTagOffset, kAddressTagWidth);
11985 __ Ubfx(x1, x1, kAddressTagOffset, kAddressTagWidth);
11986
11987 VIXL_ASSERT(kMaxDataLength >= offset);
11988
11989 END();
11990 if (CAN_RUN()) {
11991 RUN();
11992
11993 ASSERT_EQUAL_64(src_tag, x0);
11994 ASSERT_EQUAL_64(dst_tag, x1);
11995
11996 for (int k = 0; k < offset; k++) {
11997 VIXL_CHECK(src[k] == dst[k]);
11998 }
11999 }
12000 }
12001 }
12002 }
12003
12004
TEST(load_store_tagged_immediate_preindex)12005 TEST(load_store_tagged_immediate_preindex) {
12006 uint64_t tags[] = {0x00, 0x1, 0x55, 0xff};
12007 int tag_count = sizeof(tags) / sizeof(tags[0]);
12008
12009 const int kMaxDataLength = 128;
12010
12011 for (int i = 0; i < tag_count; i++) {
12012 unsigned char src[kMaxDataLength];
12013 uint64_t src_raw = reinterpret_cast<uint64_t>(src);
12014 uint64_t src_tag = tags[i];
12015 uint64_t src_tagged = CPU::SetPointerTag(src_raw, src_tag);
12016
12017 for (int k = 0; k < kMaxDataLength; k++) {
12018 src[k] = k + 1;
12019 }
12020
12021 for (int j = 0; j < tag_count; j++) {
12022 unsigned char dst[kMaxDataLength];
12023 uint64_t dst_raw = reinterpret_cast<uint64_t>(dst);
12024 uint64_t dst_tag = tags[j];
12025 uint64_t dst_tagged = CPU::SetPointerTag(dst_raw, dst_tag);
12026
12027 for (int k = 0; k < kMaxDataLength; k++) {
12028 dst[k] = 0;
12029 }
12030
12031 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
12032 START();
12033
12034 // Each MemOperand must apply a pre-index equal to the size of the
12035 // previous access.
12036
12037 // Start with a non-zero preindex.
12038 int preindex = 62 * kXRegSizeInBytes;
12039 int data_length = 0;
12040
12041 __ Mov(x0, src_tagged - preindex);
12042 __ Mov(x1, dst_tagged - preindex);
12043
12044 {
12045 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12046 __ ldp(q0, q1, MemOperand(x0, preindex, PreIndex));
12047 __ stp(q0, q1, MemOperand(x1, preindex, PreIndex));
12048 }
12049 preindex = 2 * kQRegSizeInBytes;
12050 data_length = preindex;
12051
12052 {
12053 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12054 __ ldp(x2, x3, MemOperand(x0, preindex, PreIndex));
12055 __ stp(x2, x3, MemOperand(x1, preindex, PreIndex));
12056 }
12057 preindex = 2 * kXRegSizeInBytes;
12058 data_length += preindex;
12059
12060 {
12061 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12062 __ ldpsw(x2, x3, MemOperand(x0, preindex, PreIndex));
12063 __ stp(w2, w3, MemOperand(x1, preindex, PreIndex));
12064 }
12065 preindex = 2 * kWRegSizeInBytes;
12066 data_length += preindex;
12067
12068 {
12069 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12070 __ ldp(d0, d1, MemOperand(x0, preindex, PreIndex));
12071 __ stp(d0, d1, MemOperand(x1, preindex, PreIndex));
12072 }
12073 preindex = 2 * kDRegSizeInBytes;
12074 data_length += preindex;
12075
12076 {
12077 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12078 __ ldp(w2, w3, MemOperand(x0, preindex, PreIndex));
12079 __ stp(w2, w3, MemOperand(x1, preindex, PreIndex));
12080 }
12081 preindex = 2 * kWRegSizeInBytes;
12082 data_length += preindex;
12083
12084 {
12085 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12086 __ ldp(s0, s1, MemOperand(x0, preindex, PreIndex));
12087 __ stp(s0, s1, MemOperand(x1, preindex, PreIndex));
12088 }
12089 preindex = 2 * kSRegSizeInBytes;
12090 data_length += preindex;
12091
12092 {
12093 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12094 __ ldr(x2, MemOperand(x0, preindex, PreIndex));
12095 __ str(x2, MemOperand(x1, preindex, PreIndex));
12096 }
12097 preindex = kXRegSizeInBytes;
12098 data_length += preindex;
12099
12100 {
12101 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12102 __ ldr(d0, MemOperand(x0, preindex, PreIndex));
12103 __ str(d0, MemOperand(x1, preindex, PreIndex));
12104 }
12105 preindex = kDRegSizeInBytes;
12106 data_length += preindex;
12107
12108 {
12109 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12110 __ ldr(w2, MemOperand(x0, preindex, PreIndex));
12111 __ str(w2, MemOperand(x1, preindex, PreIndex));
12112 }
12113 preindex = kWRegSizeInBytes;
12114 data_length += preindex;
12115
12116 {
12117 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12118 __ ldr(s0, MemOperand(x0, preindex, PreIndex));
12119 __ str(s0, MemOperand(x1, preindex, PreIndex));
12120 }
12121 preindex = kSRegSizeInBytes;
12122 data_length += preindex;
12123
12124 {
12125 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12126 __ ldrh(w2, MemOperand(x0, preindex, PreIndex));
12127 __ strh(w2, MemOperand(x1, preindex, PreIndex));
12128 }
12129 preindex = 2;
12130 data_length += preindex;
12131
12132 {
12133 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12134 __ ldrsh(w2, MemOperand(x0, preindex, PreIndex));
12135 __ strh(w2, MemOperand(x1, preindex, PreIndex));
12136 }
12137 preindex = 2;
12138 data_length += preindex;
12139
12140 {
12141 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12142 __ ldrb(w2, MemOperand(x0, preindex, PreIndex));
12143 __ strb(w2, MemOperand(x1, preindex, PreIndex));
12144 }
12145 preindex = 1;
12146 data_length += preindex;
12147
12148 {
12149 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12150 __ ldrsb(w2, MemOperand(x0, preindex, PreIndex));
12151 __ strb(w2, MemOperand(x1, preindex, PreIndex));
12152 }
12153 preindex = 1;
12154 data_length += preindex;
12155
12156 VIXL_ASSERT(kMaxDataLength >= data_length);
12157
12158 END();
12159 if (CAN_RUN()) {
12160 RUN();
12161
12162 // Check that the preindex was correctly applied in each operation, and
12163 // that the tag was preserved.
12164 ASSERT_EQUAL_64(src_tagged + data_length - preindex, x0);
12165 ASSERT_EQUAL_64(dst_tagged + data_length - preindex, x1);
12166
12167 for (int k = 0; k < data_length; k++) {
12168 VIXL_CHECK(src[k] == dst[k]);
12169 }
12170 }
12171 }
12172 }
12173 }
12174
12175
TEST(load_store_tagged_immediate_postindex)12176 TEST(load_store_tagged_immediate_postindex) {
12177 uint64_t tags[] = {0x00, 0x1, 0x55, 0xff};
12178 int tag_count = sizeof(tags) / sizeof(tags[0]);
12179
12180 const int kMaxDataLength = 128;
12181
12182 for (int i = 0; i < tag_count; i++) {
12183 unsigned char src[kMaxDataLength];
12184 uint64_t src_raw = reinterpret_cast<uint64_t>(src);
12185 uint64_t src_tag = tags[i];
12186 uint64_t src_tagged = CPU::SetPointerTag(src_raw, src_tag);
12187
12188 for (int k = 0; k < kMaxDataLength; k++) {
12189 src[k] = k + 1;
12190 }
12191
12192 for (int j = 0; j < tag_count; j++) {
12193 unsigned char dst[kMaxDataLength];
12194 uint64_t dst_raw = reinterpret_cast<uint64_t>(dst);
12195 uint64_t dst_tag = tags[j];
12196 uint64_t dst_tagged = CPU::SetPointerTag(dst_raw, dst_tag);
12197
12198 for (int k = 0; k < kMaxDataLength; k++) {
12199 dst[k] = 0;
12200 }
12201
12202 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
12203 START();
12204
12205 int postindex = 2 * kXRegSizeInBytes;
12206 int data_length = 0;
12207
12208 __ Mov(x0, src_tagged);
12209 __ Mov(x1, dst_tagged);
12210
12211 {
12212 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12213 __ ldp(x2, x3, MemOperand(x0, postindex, PostIndex));
12214 __ stp(x2, x3, MemOperand(x1, postindex, PostIndex));
12215 }
12216 data_length = postindex;
12217
12218 postindex = 2 * kQRegSizeInBytes;
12219 {
12220 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12221 __ ldp(q0, q1, MemOperand(x0, postindex, PostIndex));
12222 __ stp(q0, q1, MemOperand(x1, postindex, PostIndex));
12223 }
12224 data_length += postindex;
12225
12226 postindex = 2 * kWRegSizeInBytes;
12227 {
12228 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12229 __ ldpsw(x2, x3, MemOperand(x0, postindex, PostIndex));
12230 __ stp(w2, w3, MemOperand(x1, postindex, PostIndex));
12231 }
12232 data_length += postindex;
12233
12234 postindex = 2 * kDRegSizeInBytes;
12235 {
12236 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12237 __ ldp(d0, d1, MemOperand(x0, postindex, PostIndex));
12238 __ stp(d0, d1, MemOperand(x1, postindex, PostIndex));
12239 }
12240 data_length += postindex;
12241
12242 postindex = 2 * kWRegSizeInBytes;
12243 {
12244 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12245 __ ldp(w2, w3, MemOperand(x0, postindex, PostIndex));
12246 __ stp(w2, w3, MemOperand(x1, postindex, PostIndex));
12247 }
12248 data_length += postindex;
12249
12250 postindex = 2 * kSRegSizeInBytes;
12251 {
12252 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12253 __ ldp(s0, s1, MemOperand(x0, postindex, PostIndex));
12254 __ stp(s0, s1, MemOperand(x1, postindex, PostIndex));
12255 }
12256 data_length += postindex;
12257
12258 postindex = kXRegSizeInBytes;
12259 {
12260 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12261 __ ldr(x2, MemOperand(x0, postindex, PostIndex));
12262 __ str(x2, MemOperand(x1, postindex, PostIndex));
12263 }
12264 data_length += postindex;
12265
12266 postindex = kDRegSizeInBytes;
12267 {
12268 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12269 __ ldr(d0, MemOperand(x0, postindex, PostIndex));
12270 __ str(d0, MemOperand(x1, postindex, PostIndex));
12271 }
12272 data_length += postindex;
12273
12274 postindex = kWRegSizeInBytes;
12275 {
12276 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12277 __ ldr(w2, MemOperand(x0, postindex, PostIndex));
12278 __ str(w2, MemOperand(x1, postindex, PostIndex));
12279 }
12280 data_length += postindex;
12281
12282 postindex = kSRegSizeInBytes;
12283 {
12284 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12285 __ ldr(s0, MemOperand(x0, postindex, PostIndex));
12286 __ str(s0, MemOperand(x1, postindex, PostIndex));
12287 }
12288 data_length += postindex;
12289
12290 postindex = 2;
12291 {
12292 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12293 __ ldrh(w2, MemOperand(x0, postindex, PostIndex));
12294 __ strh(w2, MemOperand(x1, postindex, PostIndex));
12295 }
12296 data_length += postindex;
12297
12298 postindex = 2;
12299 {
12300 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12301 __ ldrsh(w2, MemOperand(x0, postindex, PostIndex));
12302 __ strh(w2, MemOperand(x1, postindex, PostIndex));
12303 }
12304 data_length += postindex;
12305
12306 postindex = 1;
12307 {
12308 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12309 __ ldrb(w2, MemOperand(x0, postindex, PostIndex));
12310 __ strb(w2, MemOperand(x1, postindex, PostIndex));
12311 }
12312 data_length += postindex;
12313
12314 postindex = 1;
12315 {
12316 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12317 __ ldrsb(w2, MemOperand(x0, postindex, PostIndex));
12318 __ strb(w2, MemOperand(x1, postindex, PostIndex));
12319 }
12320 data_length += postindex;
12321
12322 VIXL_ASSERT(kMaxDataLength >= data_length);
12323
12324 END();
12325 if (CAN_RUN()) {
12326 RUN();
12327
12328 // Check that the postindex was correctly applied in each operation, and
12329 // that the tag was preserved.
12330 ASSERT_EQUAL_64(src_tagged + data_length, x0);
12331 ASSERT_EQUAL_64(dst_tagged + data_length, x1);
12332
12333 for (int k = 0; k < data_length; k++) {
12334 VIXL_CHECK(src[k] == dst[k]);
12335 }
12336 }
12337 }
12338 }
12339 }
12340
12341
TEST(load_store_tagged_register_offset)12342 TEST(load_store_tagged_register_offset) {
12343 uint64_t tags[] = {0x00, 0x1, 0x55, 0xff};
12344 int tag_count = sizeof(tags) / sizeof(tags[0]);
12345
12346 const int kMaxDataLength = 128;
12347
12348 for (int i = 0; i < tag_count; i++) {
12349 unsigned char src[kMaxDataLength];
12350 uint64_t src_raw = reinterpret_cast<uint64_t>(src);
12351 uint64_t src_tag = tags[i];
12352 uint64_t src_tagged = CPU::SetPointerTag(src_raw, src_tag);
12353
12354 for (int k = 0; k < kMaxDataLength; k++) {
12355 src[k] = k + 1;
12356 }
12357
12358 for (int j = 0; j < tag_count; j++) {
12359 unsigned char dst[kMaxDataLength];
12360 uint64_t dst_raw = reinterpret_cast<uint64_t>(dst);
12361 uint64_t dst_tag = tags[j];
12362 uint64_t dst_tagged = CPU::SetPointerTag(dst_raw, dst_tag);
12363
12364 // Also tag the offset register; the operation should still succeed.
12365 for (int o = 0; o < tag_count; o++) {
12366 uint64_t offset_base = CPU::SetPointerTag(UINT64_C(0), tags[o]);
12367 int data_length = 0;
12368
12369 for (int k = 0; k < kMaxDataLength; k++) {
12370 dst[k] = 0;
12371 }
12372
12373 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
12374 START();
12375
12376 __ Mov(x0, src_tagged);
12377 __ Mov(x1, dst_tagged);
12378
12379 __ Mov(x10, offset_base + data_length);
12380 {
12381 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12382 __ ldr(x2, MemOperand(x0, x10));
12383 __ str(x2, MemOperand(x1, x10));
12384 }
12385 data_length += kXRegSizeInBytes;
12386
12387 __ Mov(x10, offset_base + data_length);
12388 {
12389 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12390 __ ldr(d0, MemOperand(x0, x10));
12391 __ str(d0, MemOperand(x1, x10));
12392 }
12393 data_length += kDRegSizeInBytes;
12394
12395 __ Mov(x10, offset_base + data_length);
12396 {
12397 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12398 __ ldr(w2, MemOperand(x0, x10));
12399 __ str(w2, MemOperand(x1, x10));
12400 }
12401 data_length += kWRegSizeInBytes;
12402
12403 __ Mov(x10, offset_base + data_length);
12404 {
12405 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12406 __ ldr(s0, MemOperand(x0, x10));
12407 __ str(s0, MemOperand(x1, x10));
12408 }
12409 data_length += kSRegSizeInBytes;
12410
12411 __ Mov(x10, offset_base + data_length);
12412 {
12413 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12414 __ ldrh(w2, MemOperand(x0, x10));
12415 __ strh(w2, MemOperand(x1, x10));
12416 }
12417 data_length += 2;
12418
12419 __ Mov(x10, offset_base + data_length);
12420 {
12421 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12422 __ ldrsh(w2, MemOperand(x0, x10));
12423 __ strh(w2, MemOperand(x1, x10));
12424 }
12425 data_length += 2;
12426
12427 __ Mov(x10, offset_base + data_length);
12428 {
12429 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12430 __ ldrb(w2, MemOperand(x0, x10));
12431 __ strb(w2, MemOperand(x1, x10));
12432 }
12433 data_length += 1;
12434
12435 __ Mov(x10, offset_base + data_length);
12436 {
12437 ExactAssemblyScope scope(&masm, 2 * kInstructionSize);
12438 __ ldrsb(w2, MemOperand(x0, x10));
12439 __ strb(w2, MemOperand(x1, x10));
12440 }
12441 data_length += 1;
12442
12443 VIXL_ASSERT(kMaxDataLength >= data_length);
12444
12445 END();
12446 if (CAN_RUN()) {
12447 RUN();
12448
12449 // Check that the postindex was correctly applied in each operation,
12450 // and that the tag was preserved.
12451 ASSERT_EQUAL_64(src_tagged, x0);
12452 ASSERT_EQUAL_64(dst_tagged, x1);
12453 ASSERT_EQUAL_64(offset_base + data_length - 1, x10);
12454
12455 for (int k = 0; k < data_length; k++) {
12456 VIXL_CHECK(src[k] == dst[k]);
12457 }
12458 }
12459 }
12460 }
12461 }
12462 }
12463
12464
TEST(load_store_tagged_register_postindex)12465 TEST(load_store_tagged_register_postindex) {
12466 uint64_t src[] = {0x0706050403020100, 0x0f0e0d0c0b0a0908};
12467 uint64_t tags[] = {0x00, 0x1, 0x55, 0xff};
12468 int tag_count = sizeof(tags) / sizeof(tags[0]);
12469
12470 for (int j = 0; j < tag_count; j++) {
12471 for (int i = 0; i < tag_count; i++) {
12472 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
12473
12474 uint64_t src_base = reinterpret_cast<uint64_t>(src);
12475 uint64_t src_tagged = CPU::SetPointerTag(src_base, tags[i]);
12476 uint64_t offset_tagged = CPU::SetPointerTag(UINT64_C(0), tags[j]);
12477
12478 START();
12479 __ Mov(x10, src_tagged);
12480 __ Mov(x11, offset_tagged);
12481 __ Ld1(v0.V16B(), MemOperand(x10, x11, PostIndex));
12482 // TODO: add other instructions (ld2-4, st1-4) as they become available.
12483 END();
12484
12485 if (CAN_RUN()) {
12486 RUN();
12487
12488 ASSERT_EQUAL_128(0x0f0e0d0c0b0a0908, 0x0706050403020100, q0);
12489 ASSERT_EQUAL_64(src_tagged + offset_tagged, x10);
12490 }
12491 }
12492 }
12493 }
12494
12495
TEST(branch_tagged)12496 TEST(branch_tagged) {
12497 SETUP();
12498 START();
12499
12500 Label loop, loop_entry, done;
12501 __ Adr(x0, &loop);
12502 __ Mov(x1, 0);
12503 __ B(&loop_entry);
12504
12505 __ Bind(&loop);
12506 __ Add(x1, x1, 1); // Count successful jumps.
12507
12508 // Advance to the next tag, then bail out if we've come back around to tag 0.
12509 __ Add(x0, x0, UINT64_C(1) << kAddressTagOffset);
12510 __ Tst(x0, kAddressTagMask);
12511 __ B(eq, &done);
12512
12513 __ Bind(&loop_entry);
12514 __ Br(x0);
12515
12516 __ Bind(&done);
12517
12518 END();
12519 if (CAN_RUN()) {
12520 RUN();
12521
12522 ASSERT_EQUAL_64(1 << kAddressTagWidth, x1);
12523 }
12524 }
12525
12526
TEST(branch_and_link_tagged)12527 TEST(branch_and_link_tagged) {
12528 SETUP();
12529 START();
12530
12531 Label loop, loop_entry, done;
12532 __ Adr(x0, &loop);
12533 __ Mov(x1, 0);
12534 __ B(&loop_entry);
12535
12536 __ Bind(&loop);
12537
12538 // Bail out (before counting a successful jump) if lr appears to be tagged.
12539 __ Tst(lr, kAddressTagMask);
12540 __ B(ne, &done);
12541
12542 __ Add(x1, x1, 1); // Count successful jumps.
12543
12544 // Advance to the next tag, then bail out if we've come back around to tag 0.
12545 __ Add(x0, x0, UINT64_C(1) << kAddressTagOffset);
12546 __ Tst(x0, kAddressTagMask);
12547 __ B(eq, &done);
12548
12549 __ Bind(&loop_entry);
12550 __ Blr(x0);
12551
12552 __ Bind(&done);
12553
12554 END();
12555 if (CAN_RUN()) {
12556 RUN();
12557
12558 ASSERT_EQUAL_64(1 << kAddressTagWidth, x1);
12559 }
12560 }
12561
12562
TEST(branch_tagged_and_adr_adrp)12563 TEST(branch_tagged_and_adr_adrp) {
12564 SETUP_CUSTOM(kPageSize, PageOffsetDependentCode);
12565 START();
12566
12567 Label loop, loop_entry, done;
12568 __ Adr(x0, &loop);
12569 __ Mov(x1, 0);
12570 __ B(&loop_entry);
12571
12572 __ Bind(&loop);
12573
12574 // Bail out (before counting a successful jump) if `adr x10, ...` is tagged.
12575 __ Adr(x10, &done);
12576 __ Tst(x10, kAddressTagMask);
12577 __ B(ne, &done);
12578
12579 // Bail out (before counting a successful jump) if `adrp x11, ...` is tagged.
12580 __ Adrp(x11, &done);
12581 __ Tst(x11, kAddressTagMask);
12582 __ B(ne, &done);
12583
12584 __ Add(x1, x1, 1); // Count successful iterations.
12585
12586 // Advance to the next tag, then bail out if we've come back around to tag 0.
12587 __ Add(x0, x0, UINT64_C(1) << kAddressTagOffset);
12588 __ Tst(x0, kAddressTagMask);
12589 __ B(eq, &done);
12590
12591 __ Bind(&loop_entry);
12592 __ Br(x0);
12593
12594 __ Bind(&done);
12595
12596 END();
12597 if (CAN_RUN()) {
12598 RUN();
12599
12600 ASSERT_EQUAL_64(1 << kAddressTagWidth, x1);
12601 }
12602 }
12603
TEST(system_sys)12604 TEST(system_sys) {
12605 SETUP();
12606 const char* msg = "SYS test!";
12607 uintptr_t msg_addr = reinterpret_cast<uintptr_t>(msg);
12608
12609 START();
12610 __ Mov(x4, msg_addr);
12611 __ Sys(3, 0x7, 0x5, 1, x4);
12612 __ Mov(x3, x4);
12613 __ Sys(3, 0x7, 0xa, 1, x3);
12614 __ Mov(x2, x3);
12615 __ Sys(3, 0x7, 0xb, 1, x2);
12616 __ Mov(x1, x2);
12617 __ Sys(3, 0x7, 0xe, 1, x1);
12618 // TODO: Add tests to check ZVA equivalent.
12619 END();
12620
12621 if (CAN_RUN()) {
12622 RUN();
12623 }
12624 }
12625
12626
TEST(system_ic)12627 TEST(system_ic) {
12628 SETUP();
12629 const char* msg = "IC test!";
12630 uintptr_t msg_addr = reinterpret_cast<uintptr_t>(msg);
12631
12632 START();
12633 __ Mov(x11, msg_addr);
12634 __ Ic(IVAU, x11);
12635 END();
12636
12637 if (CAN_RUN()) {
12638 RUN();
12639 }
12640 }
12641
12642
TEST(system_dc)12643 TEST(system_dc) {
12644 SETUP();
12645 const char* msg = "DC test!";
12646 uintptr_t msg_addr = reinterpret_cast<uintptr_t>(msg);
12647
12648 START();
12649 __ Mov(x20, msg_addr);
12650 __ Dc(CVAC, x20);
12651 __ Mov(x21, msg_addr);
12652 __ Dc(CVAU, x21);
12653 __ Mov(x22, msg_addr);
12654 __ Dc(CIVAC, x22);
12655 // TODO: Add tests to check ZVA.
12656 END();
12657
12658 if (CAN_RUN()) {
12659 RUN();
12660 ASSERT_EQUAL_64(msg_addr, x20);
12661 ASSERT_EQUAL_64(msg_addr, x21);
12662 ASSERT_EQUAL_64(msg_addr, x22);
12663 }
12664 }
12665
12666
TEST(system_dcpop)12667 TEST(system_dcpop) {
12668 SETUP_WITH_FEATURES(CPUFeatures::kDCPoP);
12669 const char* msg = "DCPoP test!";
12670 uintptr_t msg_addr = reinterpret_cast<uintptr_t>(msg);
12671
12672 START();
12673 __ Mov(x20, msg_addr);
12674 __ Dc(CVAP, x20);
12675 END();
12676
12677 if (CAN_RUN()) {
12678 RUN();
12679 ASSERT_EQUAL_64(msg_addr, x20);
12680 }
12681 }
12682
TEST(system_dccvadp)12683 TEST(system_dccvadp) {
12684 SETUP_WITH_FEATURES(CPUFeatures::kDCCVADP);
12685 const char* msg = "DCCVADP test!";
12686 uintptr_t msg_addr = reinterpret_cast<uintptr_t>(msg);
12687
12688 START();
12689 __ Mov(x20, msg_addr);
12690 __ Dc(CVADP, x20);
12691 END();
12692
12693 if (CAN_RUN()) {
12694 RUN();
12695 ASSERT_EQUAL_64(msg_addr, x20);
12696 }
12697 }
12698
TEST(system_dc_mte)12699 TEST(system_dc_mte) {
12700 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
12701 const char* msg = "DC MTE test!";
12702 uintptr_t msg_addr = reinterpret_cast<uintptr_t>(msg);
12703
12704 START();
12705 __ Mov(x20, msg_addr);
12706 __ Dc(CGVAC, x20);
12707 __ Dc(CGDVAC, x20);
12708 __ Dc(CGVAP, x20);
12709 __ Dc(CGDVAP, x20);
12710 __ Dc(CIGVAC, x20);
12711 __ Dc(CIGDVAC, x20);
12712 END();
12713
12714 if (CAN_RUN()) {
12715 RUN();
12716 ASSERT_EQUAL_64(msg_addr, x20);
12717 }
12718 }
12719
12720 // We currently disable tests for CRC32 instructions when running natively.
12721 // Support for this family of instruction is optional, and so native platforms
12722 // may simply fail to execute the test.
TEST(crc32b)12723 TEST(crc32b) {
12724 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12725
12726 START();
12727
12728 __ Mov(w0, 0);
12729 __ Mov(w1, 0);
12730 __ Crc32b(w10, w0, w1);
12731
12732 __ Mov(w0, 0x1);
12733 __ Mov(w1, 0x138);
12734 __ Crc32b(w11, w0, w1);
12735
12736 __ Mov(w0, 0x1);
12737 __ Mov(w1, 0x38);
12738 __ Crc32b(w12, w0, w1);
12739
12740 __ Mov(w0, 0);
12741 __ Mov(w1, 128);
12742 __ Crc32b(w13, w0, w1);
12743
12744 __ Mov(w0, UINT32_MAX);
12745 __ Mov(w1, 255);
12746 __ Crc32b(w14, w0, w1);
12747
12748 __ Mov(w0, 0x00010001);
12749 __ Mov(w1, 0x10001000);
12750 __ Crc32b(w15, w0, w1);
12751
12752 END();
12753
12754 if (CAN_RUN()) {
12755 RUN();
12756
12757 ASSERT_EQUAL_64(0x0, x10);
12758 ASSERT_EQUAL_64(0x5f058808, x11);
12759 ASSERT_EQUAL_64(0x5f058808, x12);
12760 ASSERT_EQUAL_64(0xedb88320, x13);
12761 ASSERT_EQUAL_64(0x00ffffff, x14);
12762 ASSERT_EQUAL_64(0x77073196, x15);
12763 }
12764 }
12765
12766
TEST(crc32h)12767 TEST(crc32h) {
12768 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12769
12770 START();
12771
12772 __ Mov(w0, 0);
12773 __ Mov(w1, 0);
12774 __ Crc32h(w10, w0, w1);
12775
12776 __ Mov(w0, 0x1);
12777 __ Mov(w1, 0x10038);
12778 __ Crc32h(w11, w0, w1);
12779
12780 __ Mov(w0, 0x1);
12781 __ Mov(w1, 0x38);
12782 __ Crc32h(w12, w0, w1);
12783
12784 __ Mov(w0, 0);
12785 __ Mov(w1, 128);
12786 __ Crc32h(w13, w0, w1);
12787
12788 __ Mov(w0, UINT32_MAX);
12789 __ Mov(w1, 255);
12790 __ Crc32h(w14, w0, w1);
12791
12792 __ Mov(w0, 0x00010001);
12793 __ Mov(w1, 0x10001000);
12794 __ Crc32h(w15, w0, w1);
12795
12796 END();
12797
12798 if (CAN_RUN()) {
12799 RUN();
12800
12801 ASSERT_EQUAL_64(0x0, x10);
12802 ASSERT_EQUAL_64(0x0e848dba, x11);
12803 ASSERT_EQUAL_64(0x0e848dba, x12);
12804 ASSERT_EQUAL_64(0x3b83984b, x13);
12805 ASSERT_EQUAL_64(0x2d021072, x14);
12806 ASSERT_EQUAL_64(0x04ac2124, x15);
12807 }
12808 }
12809
12810
TEST(crc32w)12811 TEST(crc32w) {
12812 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12813
12814 START();
12815
12816 __ Mov(w0, 0);
12817 __ Mov(w1, 0);
12818 __ Crc32w(w10, w0, w1);
12819
12820 __ Mov(w0, 0x1);
12821 __ Mov(w1, 0x80000031);
12822 __ Crc32w(w11, w0, w1);
12823
12824 __ Mov(w0, 0);
12825 __ Mov(w1, 128);
12826 __ Crc32w(w13, w0, w1);
12827
12828 __ Mov(w0, UINT32_MAX);
12829 __ Mov(w1, 255);
12830 __ Crc32w(w14, w0, w1);
12831
12832 __ Mov(w0, 0x00010001);
12833 __ Mov(w1, 0x10001000);
12834 __ Crc32w(w15, w0, w1);
12835
12836 END();
12837
12838 if (CAN_RUN()) {
12839 RUN();
12840
12841 ASSERT_EQUAL_64(0x0, x10);
12842 ASSERT_EQUAL_64(0x1d937b81, x11);
12843 ASSERT_EQUAL_64(0xed59b63b, x13);
12844 ASSERT_EQUAL_64(0x00be2612, x14);
12845 ASSERT_EQUAL_64(0xa036e530, x15);
12846 }
12847 }
12848
12849
TEST(crc32x)12850 TEST(crc32x) {
12851 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12852
12853 START();
12854
12855 __ Mov(w0, 0);
12856 __ Mov(x1, 0);
12857 __ Crc32x(w10, w0, x1);
12858
12859 __ Mov(w0, 0x1);
12860 __ Mov(x1, UINT64_C(0x0000000800000031));
12861 __ Crc32x(w11, w0, x1);
12862
12863 __ Mov(w0, 0);
12864 __ Mov(x1, 128);
12865 __ Crc32x(w13, w0, x1);
12866
12867 __ Mov(w0, UINT32_MAX);
12868 __ Mov(x1, 255);
12869 __ Crc32x(w14, w0, x1);
12870
12871 __ Mov(w0, 0x00010001);
12872 __ Mov(x1, UINT64_C(0x1000100000000000));
12873 __ Crc32x(w15, w0, x1);
12874
12875 END();
12876
12877 if (CAN_RUN()) {
12878 RUN();
12879
12880 ASSERT_EQUAL_64(0x0, x10);
12881 ASSERT_EQUAL_64(0x40797b92, x11);
12882 ASSERT_EQUAL_64(0x533b85da, x13);
12883 ASSERT_EQUAL_64(0xbc962670, x14);
12884 ASSERT_EQUAL_64(0x0667602f, x15);
12885 }
12886 }
12887
12888
TEST(crc32cb)12889 TEST(crc32cb) {
12890 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12891
12892 START();
12893
12894 __ Mov(w0, 0);
12895 __ Mov(w1, 0);
12896 __ Crc32cb(w10, w0, w1);
12897
12898 __ Mov(w0, 0x1);
12899 __ Mov(w1, 0x138);
12900 __ Crc32cb(w11, w0, w1);
12901
12902 __ Mov(w0, 0x1);
12903 __ Mov(w1, 0x38);
12904 __ Crc32cb(w12, w0, w1);
12905
12906 __ Mov(w0, 0);
12907 __ Mov(w1, 128);
12908 __ Crc32cb(w13, w0, w1);
12909
12910 __ Mov(w0, UINT32_MAX);
12911 __ Mov(w1, 255);
12912 __ Crc32cb(w14, w0, w1);
12913
12914 __ Mov(w0, 0x00010001);
12915 __ Mov(w1, 0x10001000);
12916 __ Crc32cb(w15, w0, w1);
12917
12918 END();
12919
12920 if (CAN_RUN()) {
12921 RUN();
12922
12923 ASSERT_EQUAL_64(0x0, x10);
12924 ASSERT_EQUAL_64(0x4851927d, x11);
12925 ASSERT_EQUAL_64(0x4851927d, x12);
12926 ASSERT_EQUAL_64(0x82f63b78, x13);
12927 ASSERT_EQUAL_64(0x00ffffff, x14);
12928 ASSERT_EQUAL_64(0xf26b8203, x15);
12929 }
12930 }
12931
12932
TEST(crc32ch)12933 TEST(crc32ch) {
12934 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12935
12936 START();
12937
12938 __ Mov(w0, 0);
12939 __ Mov(w1, 0);
12940 __ Crc32ch(w10, w0, w1);
12941
12942 __ Mov(w0, 0x1);
12943 __ Mov(w1, 0x10038);
12944 __ Crc32ch(w11, w0, w1);
12945
12946 __ Mov(w0, 0x1);
12947 __ Mov(w1, 0x38);
12948 __ Crc32ch(w12, w0, w1);
12949
12950 __ Mov(w0, 0);
12951 __ Mov(w1, 128);
12952 __ Crc32ch(w13, w0, w1);
12953
12954 __ Mov(w0, UINT32_MAX);
12955 __ Mov(w1, 255);
12956 __ Crc32ch(w14, w0, w1);
12957
12958 __ Mov(w0, 0x00010001);
12959 __ Mov(w1, 0x10001000);
12960 __ Crc32ch(w15, w0, w1);
12961
12962 END();
12963
12964 if (CAN_RUN()) {
12965 RUN();
12966
12967 ASSERT_EQUAL_64(0x0, x10);
12968 ASSERT_EQUAL_64(0xcef8494c, x11);
12969 ASSERT_EQUAL_64(0xcef8494c, x12);
12970 ASSERT_EQUAL_64(0xfbc3faf9, x13);
12971 ASSERT_EQUAL_64(0xad7dacae, x14);
12972 ASSERT_EQUAL_64(0x03fc5f19, x15);
12973 }
12974 }
12975
12976
TEST(crc32cw)12977 TEST(crc32cw) {
12978 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
12979
12980 START();
12981
12982 __ Mov(w0, 0);
12983 __ Mov(w1, 0);
12984 __ Crc32cw(w10, w0, w1);
12985
12986 __ Mov(w0, 0x1);
12987 __ Mov(w1, 0x80000031);
12988 __ Crc32cw(w11, w0, w1);
12989
12990 __ Mov(w0, 0);
12991 __ Mov(w1, 128);
12992 __ Crc32cw(w13, w0, w1);
12993
12994 __ Mov(w0, UINT32_MAX);
12995 __ Mov(w1, 255);
12996 __ Crc32cw(w14, w0, w1);
12997
12998 __ Mov(w0, 0x00010001);
12999 __ Mov(w1, 0x10001000);
13000 __ Crc32cw(w15, w0, w1);
13001
13002 END();
13003
13004 if (CAN_RUN()) {
13005 RUN();
13006
13007 ASSERT_EQUAL_64(0x0, x10);
13008 ASSERT_EQUAL_64(0xbcb79ece, x11);
13009 ASSERT_EQUAL_64(0x52a0c93f, x13);
13010 ASSERT_EQUAL_64(0x9f9b5c7a, x14);
13011 ASSERT_EQUAL_64(0xae1b882a, x15);
13012 }
13013 }
13014
13015
TEST(crc32cx)13016 TEST(crc32cx) {
13017 SETUP_WITH_FEATURES(CPUFeatures::kCRC32);
13018
13019 START();
13020
13021 __ Mov(w0, 0);
13022 __ Mov(x1, 0);
13023 __ Crc32cx(w10, w0, x1);
13024
13025 __ Mov(w0, 0x1);
13026 __ Mov(x1, UINT64_C(0x0000000800000031));
13027 __ Crc32cx(w11, w0, x1);
13028
13029 __ Mov(w0, 0);
13030 __ Mov(x1, 128);
13031 __ Crc32cx(w13, w0, x1);
13032
13033 __ Mov(w0, UINT32_MAX);
13034 __ Mov(x1, 255);
13035 __ Crc32cx(w14, w0, x1);
13036
13037 __ Mov(w0, 0x00010001);
13038 __ Mov(x1, UINT64_C(0x1000100000000000));
13039 __ Crc32cx(w15, w0, x1);
13040
13041 END();
13042
13043 if (CAN_RUN()) {
13044 RUN();
13045
13046 ASSERT_EQUAL_64(0x0, x10);
13047 ASSERT_EQUAL_64(0x7f320fcb, x11);
13048 ASSERT_EQUAL_64(0x34019664, x13);
13049 ASSERT_EQUAL_64(0x6cc27dd0, x14);
13050 ASSERT_EQUAL_64(0xc6f0acdb, x15);
13051 }
13052 }
13053
TEST(regress_cmp_shift_imm)13054 TEST(regress_cmp_shift_imm) {
13055 SETUP();
13056
13057 START();
13058
13059 __ Mov(x0, 0x3d720c8d);
13060 __ Cmp(x0, Operand(0x3d720c8d));
13061
13062 END();
13063 if (CAN_RUN()) {
13064 RUN();
13065
13066 ASSERT_EQUAL_NZCV(ZCFlag);
13067 }
13068 }
13069
13070
TEST(compute_address)13071 TEST(compute_address) {
13072 SETUP();
13073
13074 START();
13075 int64_t base_address = INT64_C(0x123000000abc);
13076 int64_t reg_offset = INT64_C(0x1087654321);
13077 Register base = x0;
13078 Register offset = x1;
13079
13080 __ Mov(base, base_address);
13081 __ Mov(offset, reg_offset);
13082
13083
13084 __ ComputeAddress(x2, MemOperand(base, 0));
13085 __ ComputeAddress(x3, MemOperand(base, 8));
13086 __ ComputeAddress(x4, MemOperand(base, -100));
13087
13088 __ ComputeAddress(x5, MemOperand(base, offset));
13089 __ ComputeAddress(x6, MemOperand(base, offset, LSL, 2));
13090 __ ComputeAddress(x7, MemOperand(base, offset, LSL, 4));
13091 __ ComputeAddress(x8, MemOperand(base, offset, LSL, 8));
13092
13093 __ ComputeAddress(x9, MemOperand(base, offset, SXTW));
13094 __ ComputeAddress(x10, MemOperand(base, offset, UXTW, 1));
13095 __ ComputeAddress(x11, MemOperand(base, offset, SXTW, 2));
13096 __ ComputeAddress(x12, MemOperand(base, offset, UXTW, 3));
13097
13098 END();
13099
13100 if (CAN_RUN()) {
13101 RUN();
13102
13103 ASSERT_EQUAL_64(base_address, base);
13104
13105 ASSERT_EQUAL_64(INT64_C(0x123000000abc), x2);
13106 ASSERT_EQUAL_64(INT64_C(0x123000000ac4), x3);
13107 ASSERT_EQUAL_64(INT64_C(0x123000000a58), x4);
13108
13109 ASSERT_EQUAL_64(INT64_C(0x124087654ddd), x5);
13110 ASSERT_EQUAL_64(INT64_C(0x12721d951740), x6);
13111 ASSERT_EQUAL_64(INT64_C(0x133876543ccc), x7);
13112 ASSERT_EQUAL_64(INT64_C(0x22b765432bbc), x8);
13113
13114 ASSERT_EQUAL_64(INT64_C(0x122f87654ddd), x9);
13115 ASSERT_EQUAL_64(INT64_C(0x12310eca90fe), x10);
13116 ASSERT_EQUAL_64(INT64_C(0x122e1d951740), x11);
13117 ASSERT_EQUAL_64(INT64_C(0x12343b2a23c4), x12);
13118 }
13119 }
13120
13121
TEST(far_branch_backward)13122 TEST(far_branch_backward) {
13123 // Test that the MacroAssembler correctly resolves backward branches to labels
13124 // that are outside the immediate range of branch instructions.
13125 // Take into account that backward branches can reach one instruction further
13126 // than forward branches.
13127 const int overflow_size =
13128 kInstructionSize +
13129 std::max(Instruction::GetImmBranchForwardRange(TestBranchType),
13130 std::max(Instruction::GetImmBranchForwardRange(
13131 CompareBranchType),
13132 Instruction::GetImmBranchForwardRange(CondBranchType)));
13133
13134 SETUP();
13135 START();
13136
13137 Label done, fail;
13138 Label test_tbz, test_cbz, test_bcond;
13139 Label success_tbz, success_cbz, success_bcond;
13140
13141 __ Mov(x0, 0);
13142 __ Mov(x1, 1);
13143 __ Mov(x10, 0);
13144
13145 __ B(&test_tbz);
13146 __ Bind(&success_tbz);
13147 __ Orr(x0, x0, 1 << 0);
13148 __ B(&test_cbz);
13149 __ Bind(&success_cbz);
13150 __ Orr(x0, x0, 1 << 1);
13151 __ B(&test_bcond);
13152 __ Bind(&success_bcond);
13153 __ Orr(x0, x0, 1 << 2);
13154
13155 __ B(&done);
13156
13157 // Generate enough code to overflow the immediate range of the three types of
13158 // branches below.
13159 for (unsigned i = 0; i < overflow_size / kInstructionSize; ++i) {
13160 if (i % 100 == 0) {
13161 // If we do land in this code, we do not want to execute so many nops
13162 // before reaching the end of test (especially if tracing is activated).
13163 __ B(&fail);
13164 } else {
13165 __ Nop();
13166 }
13167 }
13168 __ B(&fail);
13169
13170 __ Bind(&test_tbz);
13171 __ Tbz(x10, 7, &success_tbz);
13172 __ Bind(&test_cbz);
13173 __ Cbz(x10, &success_cbz);
13174 __ Bind(&test_bcond);
13175 __ Cmp(x10, 0);
13176 __ B(eq, &success_bcond);
13177
13178 // For each out-of-range branch instructions, at least two instructions should
13179 // have been generated.
13180 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&test_tbz) >=
13181 7 * kInstructionSize);
13182
13183 __ Bind(&fail);
13184 __ Mov(x1, 0);
13185 __ Bind(&done);
13186
13187 END();
13188 if (CAN_RUN()) {
13189 RUN();
13190
13191 ASSERT_EQUAL_64(0x7, x0);
13192 ASSERT_EQUAL_64(0x1, x1);
13193 }
13194 }
13195
13196
TEST(single_veneer)13197 TEST(single_veneer) {
13198 SETUP();
13199 START();
13200
13201 const int max_range = Instruction::GetImmBranchForwardRange(TestBranchType);
13202
13203 Label success, fail, done;
13204
13205 __ Mov(x0, 0);
13206 __ Mov(x1, 1);
13207 __ Mov(x10, 0);
13208
13209 __ Tbz(x10, 7, &success);
13210
13211 // Generate enough code to overflow the immediate range of the `tbz`.
13212 for (unsigned i = 0; i < max_range / kInstructionSize + 1; ++i) {
13213 if (i % 100 == 0) {
13214 // If we do land in this code, we do not want to execute so many nops
13215 // before reaching the end of test (especially if tracing is activated).
13216 __ B(&fail);
13217 } else {
13218 __ Nop();
13219 }
13220 }
13221 __ B(&fail);
13222
13223 __ Bind(&success);
13224 __ Mov(x0, 1);
13225
13226 __ B(&done);
13227 __ Bind(&fail);
13228 __ Mov(x1, 0);
13229 __ Bind(&done);
13230
13231 END();
13232 if (CAN_RUN()) {
13233 RUN();
13234
13235 ASSERT_EQUAL_64(1, x0);
13236 ASSERT_EQUAL_64(1, x1);
13237 }
13238 }
13239
13240
TEST(simple_veneers)13241 TEST(simple_veneers) {
13242 // Test that the MacroAssembler correctly emits veneers for forward branches
13243 // to labels that are outside the immediate range of branch instructions.
13244 const int max_range =
13245 std::max(Instruction::GetImmBranchForwardRange(TestBranchType),
13246 std::max(Instruction::GetImmBranchForwardRange(
13247 CompareBranchType),
13248 Instruction::GetImmBranchForwardRange(CondBranchType)));
13249
13250 SETUP();
13251 START();
13252
13253 Label done, fail;
13254 Label test_tbz, test_cbz, test_bcond;
13255 Label success_tbz, success_cbz, success_bcond;
13256
13257 __ Mov(x0, 0);
13258 __ Mov(x1, 1);
13259 __ Mov(x10, 0);
13260
13261 __ Bind(&test_tbz);
13262 __ Tbz(x10, 7, &success_tbz);
13263 __ Bind(&test_cbz);
13264 __ Cbz(x10, &success_cbz);
13265 __ Bind(&test_bcond);
13266 __ Cmp(x10, 0);
13267 __ B(eq, &success_bcond);
13268
13269 // Generate enough code to overflow the immediate range of the three types of
13270 // branches below.
13271 for (unsigned i = 0; i < max_range / kInstructionSize + 1; ++i) {
13272 if (i % 100 == 0) {
13273 // If we do land in this code, we do not want to execute so many nops
13274 // before reaching the end of test (especially if tracing is activated).
13275 __ B(&fail);
13276 } else {
13277 __ Nop();
13278 }
13279 }
13280 __ B(&fail);
13281
13282 __ Bind(&success_tbz);
13283 __ Orr(x0, x0, 1 << 0);
13284 __ B(&test_cbz);
13285 __ Bind(&success_cbz);
13286 __ Orr(x0, x0, 1 << 1);
13287 __ B(&test_bcond);
13288 __ Bind(&success_bcond);
13289 __ Orr(x0, x0, 1 << 2);
13290
13291 __ B(&done);
13292 __ Bind(&fail);
13293 __ Mov(x1, 0);
13294 __ Bind(&done);
13295
13296 END();
13297 if (CAN_RUN()) {
13298 RUN();
13299
13300 ASSERT_EQUAL_64(0x7, x0);
13301 ASSERT_EQUAL_64(0x1, x1);
13302 }
13303 }
13304
13305
TEST(veneers_stress)13306 TEST(veneers_stress) {
13307 SETUP();
13308 START();
13309
13310 // This is a code generation test stressing the emission of veneers. The code
13311 // generated is not executed.
13312
13313 Label target;
13314 const unsigned max_range =
13315 Instruction::GetImmBranchForwardRange(CondBranchType);
13316 const unsigned iterations =
13317 (max_range + max_range / 4) / (4 * kInstructionSize);
13318 for (unsigned i = 0; i < iterations; i++) {
13319 __ B(&target);
13320 __ B(eq, &target);
13321 __ Cbz(x0, &target);
13322 __ Tbz(x0, 0, &target);
13323 }
13324 __ Bind(&target);
13325
13326 END();
13327 }
13328
13329
TEST(veneers_two_out_of_range)13330 TEST(veneers_two_out_of_range) {
13331 SETUP();
13332 START();
13333
13334 // This is a code generation test. The code generated is not executed.
13335 // Ensure that the MacroAssembler considers unresolved branches to chose when
13336 // a veneer pool should be emitted. We generate two branches that go out of
13337 // range at the same offset. When the MacroAssembler decides to emit the
13338 // veneer pool, the emission of a first veneer should not cause the other
13339 // branch to go out of range.
13340
13341 int range_cbz = Instruction::GetImmBranchForwardRange(CompareBranchType);
13342 int range_tbz = Instruction::GetImmBranchForwardRange(TestBranchType);
13343 int max_target = static_cast<int>(masm.GetCursorOffset()) + range_cbz;
13344
13345 Label done;
13346
13347 // We use different labels to prevent the MacroAssembler from sharing veneers.
13348 Label target_cbz, target_tbz;
13349
13350 __ Cbz(x0, &target_cbz);
13351 while (masm.GetCursorOffset() < max_target - range_tbz) {
13352 __ Nop();
13353 }
13354 __ Tbz(x0, 0, &target_tbz);
13355 while (masm.GetCursorOffset() < max_target) {
13356 __ Nop();
13357 }
13358
13359 // This additional nop makes the branches go out of range.
13360 __ Nop();
13361
13362 __ Bind(&target_cbz);
13363 __ Bind(&target_tbz);
13364
13365 END();
13366 }
13367
13368
TEST(veneers_hanging)13369 TEST(veneers_hanging) {
13370 SETUP();
13371 START();
13372
13373 // This is a code generation test. The code generated is not executed.
13374 // Ensure that the MacroAssembler considers unresolved branches to chose when
13375 // a veneer pool should be emitted. This is similar to the
13376 // 'veneers_two_out_of_range' test. We try to trigger the following situation:
13377 // b.eq label
13378 // b.eq label
13379 // ...
13380 // nop
13381 // ...
13382 // cbz x0, label
13383 // cbz x0, label
13384 // ...
13385 // tbz x0, 0 label
13386 // nop
13387 // ...
13388 // nop <- From here the `b.eq` and `cbz` instructions run out of range,
13389 // so a literal pool is required.
13390 // veneer
13391 // veneer
13392 // veneer <- The `tbz` runs out of range somewhere in the middle of the
13393 // veneer veneer pool.
13394 // veneer
13395
13396 const int range_bcond = Instruction::GetImmBranchForwardRange(CondBranchType);
13397 const int range_cbz =
13398 Instruction::GetImmBranchForwardRange(CompareBranchType);
13399 const int range_tbz = Instruction::GetImmBranchForwardRange(TestBranchType);
13400 const int max_target = static_cast<int>(masm.GetCursorOffset()) + range_bcond;
13401
13402 Label done;
13403 const int n_bcond = 100;
13404 const int n_cbz = 100;
13405 const int n_tbz = 1;
13406 const int kNTotalBranches = n_bcond + n_cbz + n_tbz;
13407
13408 // We use different labels to prevent the MacroAssembler from sharing veneers.
13409 Label labels[kNTotalBranches];
13410 for (int i = 0; i < kNTotalBranches; i++) {
13411 new (&labels[i]) Label();
13412 }
13413
13414 for (int i = 0; i < n_bcond; i++) {
13415 __ B(eq, &labels[i]);
13416 }
13417
13418 while (masm.GetCursorOffset() < max_target - range_cbz) {
13419 __ Nop();
13420 }
13421
13422 for (int i = 0; i < n_cbz; i++) {
13423 __ Cbz(x0, &labels[n_bcond + i]);
13424 }
13425
13426 // Ensure the 'tbz' will go out of range after some of the previously
13427 // generated branches.
13428 int margin = (n_bcond / 2) * kInstructionSize;
13429 while (masm.GetCursorOffset() < max_target - range_tbz + margin) {
13430 __ Nop();
13431 }
13432
13433 __ Tbz(x0, 0, &labels[n_bcond + n_cbz]);
13434
13435 while (masm.GetCursorOffset() < max_target) {
13436 __ Nop();
13437 }
13438
13439 // This additional nop makes the 'b.eq' and 'cbz' instructions go out of range
13440 // and forces the emission of a veneer pool. The 'tbz' is not yet out of
13441 // range, but will go out of range while veneers are emitted for the other
13442 // branches.
13443 // The MacroAssembler should ensure that veneers are correctly emitted for all
13444 // the branches, including the 'tbz'. Checks will fail if the target of a
13445 // branch is out of range.
13446 __ Nop();
13447
13448 for (int i = 0; i < kNTotalBranches; i++) {
13449 __ Bind(&labels[i]);
13450 }
13451
13452 END();
13453 }
13454
13455
TEST(collision_literal_veneer_pools)13456 TEST(collision_literal_veneer_pools) {
13457 SETUP_WITH_FEATURES(CPUFeatures::kFP);
13458 START();
13459
13460 // This is a code generation test. The code generated is not executed.
13461
13462 // Make sure the literal pool is empty;
13463 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13464 ASSERT_LITERAL_POOL_SIZE(0);
13465
13466 // We chose the offsets below to (try to) trigger the following situation:
13467 // buffer offset
13468 // 0: tbz x0, 0, target_tbz ----------------------------------.
13469 // 4: nop |
13470 // ... |
13471 // nop |
13472 // literal gen: ldr s0, [pc + ...] ; load from `pool start + 0` |
13473 // ldr s0, [pc + ...] ; load from `pool start + 4` |
13474 // ... |
13475 // ldr s0, [pc + ...] |
13476 // pool start: floating-point literal (0.1) |
13477 // floating-point literal (1.1) |
13478 // ... |
13479 // floating-point literal (<n>.1) <-----tbz-max-range--'
13480 // floating-point literal (<n+1>.1)
13481 // ...
13482
13483 const int range_tbz = Instruction::GetImmBranchForwardRange(TestBranchType);
13484 const int max_target = static_cast<int>(masm.GetCursorOffset()) + range_tbz;
13485
13486 const size_t target_literal_pool_size = 100 * kInstructionSize;
13487 const int offset_start_literal_gen =
13488 target_literal_pool_size + target_literal_pool_size / 2;
13489
13490
13491 Label target_tbz;
13492
13493 __ Tbz(x0, 0, &target_tbz);
13494 VIXL_CHECK(masm.GetNumberOfPotentialVeneers() == 1);
13495 while (masm.GetCursorOffset() < max_target - offset_start_literal_gen) {
13496 __ Nop();
13497 }
13498 VIXL_CHECK(masm.GetNumberOfPotentialVeneers() == 1);
13499
13500 for (int i = 0; i < 100; i++) {
13501 // Use a different value to force one literal pool entry per iteration.
13502 __ Ldr(s0, i + 0.1);
13503 }
13504 VIXL_CHECK(masm.GetLiteralPoolSize() >= target_literal_pool_size);
13505
13506 // Force emission of a literal pool.
13507 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13508 ASSERT_LITERAL_POOL_SIZE(0);
13509
13510 // The branch should not have gone out of range during the emission of the
13511 // literal pool.
13512 __ Bind(&target_tbz);
13513
13514 VIXL_CHECK(masm.GetNumberOfPotentialVeneers() == 0);
13515
13516 END();
13517 }
13518
VeneerBackwardBranchHelper(ImmBranchType type,int limit)13519 static void VeneerBackwardBranchHelper(ImmBranchType type, int limit) {
13520 SETUP();
13521 START();
13522
13523 // This is a code generation test. The code generated is not executed.
13524
13525 __ Mov(x0, 1);
13526
13527 // Non-veneer case: generate 'limit' instructions, plus the branch itself.
13528 Label start0;
13529 __ Bind(&start0);
13530 for (int i = 0; i < limit; i++) {
13531 __ Nop();
13532 }
13533 switch (type) {
13534 case CompareBranchType:
13535 __ Cbz(x0, &start0);
13536 break;
13537 case TestBranchType:
13538 __ Tbz(x0, 0, &start0);
13539 break;
13540 default:
13541 VIXL_ASSERT(type == CondBranchType);
13542 __ B(eq, &start0);
13543 }
13544 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&start0) ==
13545 ((limit + 1) * kInstructionSize));
13546
13547 // Veneer case: As above, plus one extra nop and a branch for the veneer; we
13548 // expect a total of limit + 3 instructions.
13549 //
13550 // start1:
13551 // nop x (limit + 1)
13552 // tbnz skip_veneer
13553 // b start1
13554 // skip_veneer:
13555 //
13556 Label start1;
13557 __ Bind(&start1);
13558 for (int i = 0; i < limit; i++) {
13559 __ Nop();
13560 }
13561 __ Nop(); // One extra instruction to exceed branch range.
13562 switch (type) {
13563 case CompareBranchType:
13564 __ Cbz(x0, &start0);
13565 break;
13566 case TestBranchType:
13567 __ Tbz(x0, 0, &start0);
13568 break;
13569 default:
13570 VIXL_ASSERT(type == CondBranchType);
13571 __ B(eq, &start0);
13572 }
13573 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&start1) ==
13574 ((limit + 3) * kInstructionSize));
13575
13576 END();
13577 DISASSEMBLE();
13578 }
13579
TEST(veneer_backward_tbz)13580 TEST(veneer_backward_tbz) { VeneerBackwardBranchHelper(TestBranchType, 8192); }
13581
TEST(veneer_backward_cbz)13582 TEST(veneer_backward_cbz) {
13583 VeneerBackwardBranchHelper(CompareBranchType, 262144);
13584 }
13585
TEST(veneer_backward_bcond)13586 TEST(veneer_backward_bcond) {
13587 VeneerBackwardBranchHelper(CondBranchType, 262144);
13588 }
13589
TEST(ldr_literal_explicit)13590 TEST(ldr_literal_explicit) {
13591 SETUP();
13592
13593 START();
13594 Literal<int64_t> automatically_placed_literal(1, masm.GetLiteralPool());
13595 Literal<int64_t> manually_placed_literal(2);
13596 {
13597 ExactAssemblyScope scope(&masm, kInstructionSize + sizeof(int64_t));
13598 Label over_literal;
13599 __ b(&over_literal);
13600 __ place(&manually_placed_literal);
13601 __ bind(&over_literal);
13602 }
13603 __ Ldr(x1, &manually_placed_literal);
13604 __ Ldr(x2, &automatically_placed_literal);
13605 __ Add(x0, x1, x2);
13606 END();
13607
13608 if (CAN_RUN()) {
13609 RUN();
13610
13611 ASSERT_EQUAL_64(3, x0);
13612 }
13613 }
13614
13615
TEST(ldr_literal_automatically_placed)13616 TEST(ldr_literal_automatically_placed) {
13617 SETUP_WITH_FEATURES(CPUFeatures::kFP);
13618
13619 START();
13620
13621 // We start with an empty literal pool.
13622 ASSERT_LITERAL_POOL_SIZE(0);
13623
13624 // Create a literal that should be placed by the literal pool.
13625 Literal<int64_t> explicit_literal(2, masm.GetLiteralPool());
13626 // It should not appear in the literal pool until its first use.
13627 ASSERT_LITERAL_POOL_SIZE(0);
13628
13629 // Check that using standard literals does not break the use of explicitly
13630 // created literals.
13631 __ Ldr(d1, 1.1);
13632 ASSERT_LITERAL_POOL_SIZE(8);
13633 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13634 ASSERT_LITERAL_POOL_SIZE(0);
13635
13636 __ Ldr(x2, &explicit_literal);
13637 ASSERT_LITERAL_POOL_SIZE(8);
13638 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13639 ASSERT_LITERAL_POOL_SIZE(0);
13640
13641 __ Ldr(d3, 3.3);
13642 ASSERT_LITERAL_POOL_SIZE(8);
13643 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13644 ASSERT_LITERAL_POOL_SIZE(0);
13645
13646 // Re-use our explicitly created literal. It has already been placed, so it
13647 // should not impact the literal pool.
13648 __ Ldr(x4, &explicit_literal);
13649 ASSERT_LITERAL_POOL_SIZE(0);
13650
13651 END();
13652
13653 if (CAN_RUN()) {
13654 RUN();
13655
13656 ASSERT_EQUAL_FP64(1.1, d1);
13657 ASSERT_EQUAL_64(2, x2);
13658 ASSERT_EQUAL_FP64(3.3, d3);
13659 ASSERT_EQUAL_64(2, x4);
13660 }
13661 }
13662
13663
TEST(literal_update_overwrite)13664 TEST(literal_update_overwrite) {
13665 SETUP();
13666
13667 START();
13668
13669 ASSERT_LITERAL_POOL_SIZE(0);
13670 LiteralPool* literal_pool = masm.GetLiteralPool();
13671
13672 Literal<int32_t> lit_32_update_before_pool(0xbad, literal_pool);
13673 Literal<int32_t> lit_32_update_after_pool(0xbad, literal_pool);
13674 Literal<int64_t> lit_64_update_before_pool(0xbad, literal_pool);
13675 Literal<int64_t> lit_64_update_after_pool(0xbad, literal_pool);
13676
13677 ASSERT_LITERAL_POOL_SIZE(0);
13678
13679 lit_32_update_before_pool.UpdateValue(32);
13680 lit_64_update_before_pool.UpdateValue(64);
13681
13682 __ Ldr(w1, &lit_32_update_before_pool);
13683 __ Ldr(x2, &lit_64_update_before_pool);
13684 __ Ldr(w3, &lit_32_update_after_pool);
13685 __ Ldr(x4, &lit_64_update_after_pool);
13686
13687 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13688
13689 VIXL_ASSERT(lit_32_update_after_pool.IsPlaced());
13690 VIXL_ASSERT(lit_64_update_after_pool.IsPlaced());
13691 lit_32_update_after_pool.UpdateValue(128, &masm);
13692 lit_64_update_after_pool.UpdateValue(256, &masm);
13693
13694 END();
13695
13696 if (CAN_RUN()) {
13697 RUN();
13698
13699 ASSERT_EQUAL_64(32, x1);
13700 ASSERT_EQUAL_64(64, x2);
13701 ASSERT_EQUAL_64(128, x3);
13702 ASSERT_EQUAL_64(256, x4);
13703 }
13704 }
13705
13706
TEST(literal_deletion_policies)13707 TEST(literal_deletion_policies) {
13708 SETUP();
13709
13710 START();
13711
13712 // We cannot check exactly when the deletion of the literals occur, but we
13713 // check that usage of the deletion policies is not broken.
13714
13715 ASSERT_LITERAL_POOL_SIZE(0);
13716 LiteralPool* literal_pool = masm.GetLiteralPool();
13717
13718 Literal<int32_t> lit_manual(0xbad, literal_pool);
13719 Literal<int32_t>* lit_deleted_on_placement =
13720 new Literal<int32_t>(0xbad,
13721 literal_pool,
13722 RawLiteral::kDeletedOnPlacementByPool);
13723 Literal<int32_t>* lit_deleted_on_pool_destruction =
13724 new Literal<int32_t>(0xbad,
13725 literal_pool,
13726 RawLiteral::kDeletedOnPoolDestruction);
13727
13728 ASSERT_LITERAL_POOL_SIZE(0);
13729
13730 lit_manual.UpdateValue(32);
13731 lit_deleted_on_placement->UpdateValue(64);
13732
13733 __ Ldr(w1, &lit_manual);
13734 __ Ldr(w2, lit_deleted_on_placement);
13735 __ Ldr(w3, lit_deleted_on_pool_destruction);
13736
13737 masm.EmitLiteralPool(LiteralPool::kBranchRequired);
13738
13739 VIXL_ASSERT(lit_manual.IsPlaced());
13740 VIXL_ASSERT(lit_deleted_on_pool_destruction->IsPlaced());
13741 lit_deleted_on_pool_destruction->UpdateValue(128, &masm);
13742
13743 END();
13744
13745 if (CAN_RUN()) {
13746 RUN();
13747
13748 ASSERT_EQUAL_64(32, x1);
13749 ASSERT_EQUAL_64(64, x2);
13750 ASSERT_EQUAL_64(128, x3);
13751 }
13752 }
13753
13754
TEST(generic_operand)13755 TEST(generic_operand) {
13756 SETUP_WITH_FEATURES(CPUFeatures::kFP);
13757
13758 int32_t data_32_array[5] = {0xbadbeef,
13759 0x11111111,
13760 0xbadbeef,
13761 0x33333333,
13762 0xbadbeef};
13763 int64_t data_64_array[5] = {INT64_C(0xbadbadbadbeef),
13764 INT64_C(0x1111111111111111),
13765 INT64_C(0xbadbadbadbeef),
13766 INT64_C(0x3333333333333333),
13767 INT64_C(0xbadbadbadbeef)};
13768 size_t size_32 = sizeof(data_32_array[0]);
13769 size_t size_64 = sizeof(data_64_array[0]);
13770
13771 START();
13772
13773 intptr_t data_32_address = reinterpret_cast<intptr_t>(&data_32_array[0]);
13774 intptr_t data_64_address = reinterpret_cast<intptr_t>(&data_64_array[0]);
13775 Register data_32 = x27;
13776 Register data_64 = x28;
13777 __ Mov(data_32, data_32_address);
13778 __ Mov(data_64, data_64_address);
13779
13780 __ Move(GenericOperand(w0),
13781 GenericOperand(MemOperand(data_32, 1 * size_32), size_32));
13782 __ Move(GenericOperand(s0),
13783 GenericOperand(MemOperand(data_32, 3 * size_32), size_32));
13784 __ Move(GenericOperand(x10),
13785 GenericOperand(MemOperand(data_64, 1 * size_64), size_64));
13786 __ Move(GenericOperand(d10),
13787 GenericOperand(MemOperand(data_64, 3 * size_64), size_64));
13788
13789 __ Move(GenericOperand(w1), GenericOperand(w0));
13790 __ Move(GenericOperand(s1), GenericOperand(s0));
13791 __ Move(GenericOperand(x11), GenericOperand(x10));
13792 __ Move(GenericOperand(d11), GenericOperand(d10));
13793
13794 __ Move(GenericOperand(MemOperand(data_32, 0 * size_32), size_32),
13795 GenericOperand(w1));
13796 __ Move(GenericOperand(MemOperand(data_32, 2 * size_32), size_32),
13797 GenericOperand(s1));
13798 __ Move(GenericOperand(MemOperand(data_64, 0 * size_64), size_64),
13799 GenericOperand(x11));
13800 __ Move(GenericOperand(MemOperand(data_64, 2 * size_64), size_64),
13801 GenericOperand(d11));
13802
13803 __ Move(GenericOperand(MemOperand(data_32, 4 * size_32), size_32),
13804 GenericOperand(MemOperand(data_32, 0 * size_32), size_32));
13805 __ Move(GenericOperand(MemOperand(data_64, 4 * size_64), size_64),
13806 GenericOperand(MemOperand(data_64, 0 * size_64), size_64));
13807 END();
13808
13809 if (CAN_RUN()) {
13810 RUN();
13811
13812 ASSERT_EQUAL_64(data_32_address, data_32);
13813 ASSERT_EQUAL_64(data_64_address, data_64);
13814
13815 ASSERT_EQUAL_32(0x11111111, w0);
13816 ASSERT_EQUAL_32(0x33333333, core.sreg_bits(0));
13817 ASSERT_EQUAL_64(INT64_C(0x1111111111111111), x10);
13818 ASSERT_EQUAL_64(INT64_C(0x3333333333333333), core.dreg_bits(10));
13819
13820 ASSERT_EQUAL_32(0x11111111, w1);
13821 ASSERT_EQUAL_32(0x33333333, core.sreg_bits(1));
13822 ASSERT_EQUAL_64(INT64_C(0x1111111111111111), x11);
13823 ASSERT_EQUAL_64(INT64_C(0x3333333333333333), core.dreg_bits(11));
13824
13825 VIXL_CHECK(data_32_array[0] == 0x11111111);
13826 VIXL_CHECK(data_32_array[1] == 0x11111111);
13827 VIXL_CHECK(data_32_array[2] == 0x33333333);
13828 VIXL_CHECK(data_32_array[3] == 0x33333333);
13829 VIXL_CHECK(data_32_array[4] == 0x11111111);
13830
13831 VIXL_CHECK(data_64_array[0] == INT64_C(0x1111111111111111));
13832 VIXL_CHECK(data_64_array[1] == INT64_C(0x1111111111111111));
13833 VIXL_CHECK(data_64_array[2] == INT64_C(0x3333333333333333));
13834 VIXL_CHECK(data_64_array[3] == INT64_C(0x3333333333333333));
13835 VIXL_CHECK(data_64_array[4] == INT64_C(0x1111111111111111));
13836 }
13837 }
13838
13839
13840 // Test feature detection of calls to runtime functions.
13841
13842 // C++11 should be sufficient to provide simulated runtime calls, except for a
13843 // GCC bug before 4.9.1.
13844 #if defined(VIXL_INCLUDE_SIMULATOR_AARCH64) && (__cplusplus >= 201103L) && \
13845 (defined(__clang__) || GCC_VERSION_OR_NEWER(4, 9, 1)) && \
13846 !defined(VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT)
13847 #error \
13848 "C++11 should be sufficient to provide support for simulated runtime calls."
13849 #endif // #if defined(VIXL_INCLUDE_SIMULATOR_AARCH64) && ...
13850
13851 #if (__cplusplus >= 201103L) && \
13852 !defined(VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT)
13853 #error \
13854 "C++11 should be sufficient to provide support for `MacroAssembler::CallRuntime()`."
13855 #endif // #if (__cplusplus >= 201103L) && ...
13856
13857 #ifdef VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT
runtime_call_add_one(int32_t a)13858 int32_t runtime_call_add_one(int32_t a) { return a + 1; }
13859
runtime_call_add_doubles(double a,double b,double c)13860 double runtime_call_add_doubles(double a, double b, double c) {
13861 return a + b + c;
13862 }
13863
runtime_call_one_argument_on_stack(int64_t arg1,int64_t arg2,int64_t arg3,int64_t arg4,int64_t arg5,int64_t arg6,int64_t arg7,int64_t arg8,int64_t arg9)13864 int64_t runtime_call_one_argument_on_stack(int64_t arg1 __attribute__((unused)),
13865 int64_t arg2 __attribute__((unused)),
13866 int64_t arg3 __attribute__((unused)),
13867 int64_t arg4 __attribute__((unused)),
13868 int64_t arg5 __attribute__((unused)),
13869 int64_t arg6 __attribute__((unused)),
13870 int64_t arg7 __attribute__((unused)),
13871 int64_t arg8 __attribute__((unused)),
13872 int64_t arg9) {
13873 return arg9;
13874 }
13875
runtime_call_two_arguments_on_stack(int64_t arg1,int64_t arg2,int64_t arg3,int64_t arg4,int64_t arg5,int64_t arg6,int64_t arg7,int64_t arg8,double arg9,double arg10)13876 double runtime_call_two_arguments_on_stack(int64_t arg1 __attribute__((unused)),
13877 int64_t arg2 __attribute__((unused)),
13878 int64_t arg3 __attribute__((unused)),
13879 int64_t arg4 __attribute__((unused)),
13880 int64_t arg5 __attribute__((unused)),
13881 int64_t arg6 __attribute__((unused)),
13882 int64_t arg7 __attribute__((unused)),
13883 int64_t arg8 __attribute__((unused)),
13884 double arg9,
13885 double arg10) {
13886 return arg9 - arg10;
13887 }
13888
runtime_call_store_at_address(int64_t * address)13889 void runtime_call_store_at_address(int64_t* address) { *address = 0xf00d; }
13890
runtime_call_no_args()13891 int32_t runtime_call_no_args() { return 1; }
13892
13893 enum RuntimeCallTestEnum { Enum0 };
13894
runtime_call_enum(RuntimeCallTestEnum e)13895 RuntimeCallTestEnum runtime_call_enum(RuntimeCallTestEnum e) { return e; }
13896
13897 enum class RuntimeCallTestEnumClass { Enum0 };
13898
runtime_call_enum_class(RuntimeCallTestEnumClass e)13899 RuntimeCallTestEnumClass runtime_call_enum_class(RuntimeCallTestEnumClass e) {
13900 return e;
13901 }
13902
test_int8_t(int8_t x)13903 int8_t test_int8_t(int8_t x) { return x; }
test_uint8_t(uint8_t x)13904 uint8_t test_uint8_t(uint8_t x) { return x; }
test_int16_t(int16_t x)13905 int16_t test_int16_t(int16_t x) { return x; }
test_uint16_t(uint16_t x)13906 uint16_t test_uint16_t(uint16_t x) { return x; }
13907
TEST(runtime_calls)13908 TEST(runtime_calls) {
13909 SETUP_WITH_FEATURES(CPUFeatures::kFP);
13910
13911 #ifndef VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT
13912 if (masm.GenerateSimulatorCode()) {
13913 // This configuration is unsupported and a `VIXL_UNREACHABLE()` would fire
13914 // while trying to generate `CallRuntime`. This configuration should only be
13915 // reachable with C++11 and a (buggy) version of GCC pre-4.9.1.
13916 return;
13917 }
13918 #endif
13919
13920 START();
13921
13922 // Test `CallRuntime`.
13923
13924 __ Mov(w0, 0);
13925 __ CallRuntime(runtime_call_add_one);
13926 __ Mov(w20, w0);
13927
13928 __ Fmov(d0, 0.0);
13929 __ Fmov(d1, 1.5);
13930 __ Fmov(d2, 2.5);
13931 __ CallRuntime(runtime_call_add_doubles);
13932 __ Fmov(d20, d0);
13933
13934 __ Mov(x0, 0x123);
13935 __ Push(x0, x0);
13936 __ CallRuntime(runtime_call_one_argument_on_stack);
13937 __ Mov(x21, x0);
13938 __ Pop(x0, x1);
13939
13940 __ Fmov(d0, 314.0);
13941 __ Fmov(d1, 4.0);
13942 __ Push(d1, d0);
13943 __ CallRuntime(runtime_call_two_arguments_on_stack);
13944 __ Fmov(d21, d0);
13945 __ Pop(d1, d0);
13946
13947 // Test that the template mechanisms don't break with enums.
13948 __ Mov(w0, 0);
13949 __ CallRuntime(runtime_call_enum);
13950 __ Mov(w0, 0);
13951 __ CallRuntime(runtime_call_enum_class);
13952
13953 // Test `TailCallRuntime`.
13954
13955 Label function, after_function;
13956 __ B(&after_function);
13957 __ Bind(&function);
13958 __ Mov(x22, 0);
13959 __ Mov(w0, 123);
13960 __ TailCallRuntime(runtime_call_add_one);
13961 // Control should not fall through.
13962 __ Mov(x22, 0xbad);
13963 __ Ret();
13964 __ Bind(&after_function);
13965
13966 // Call our placeholder function, taking care to preserve the link register.
13967 __ Push(ip0, lr);
13968 __ Bl(&function);
13969 __ Pop(lr, ip0);
13970 // Save the result.
13971 __ Mov(w23, w0);
13972
13973 __ Mov(x24, 0);
13974 int test_values[] = {static_cast<int8_t>(-1),
13975 static_cast<uint8_t>(-1),
13976 static_cast<int16_t>(-1),
13977 static_cast<uint16_t>(-1),
13978 -256,
13979 -1,
13980 0,
13981 1,
13982 256};
13983 for (size_t i = 0; i < sizeof(test_values) / sizeof(test_values[0]); ++i) {
13984 Label pass_int8, pass_uint8, pass_int16, pass_uint16;
13985 int x = test_values[i];
13986 __ Mov(w0, x);
13987 __ CallRuntime(test_int8_t);
13988 __ Sxtb(w0, w0);
13989 __ Cmp(w0, ExtractSignedBitfield32(7, 0, x));
13990 __ Cinc(x24, x24, ne);
13991 __ Mov(w0, x);
13992 __ CallRuntime(test_uint8_t);
13993 __ Uxtb(w0, w0);
13994 __ Cmp(w0, ExtractUnsignedBitfield32(7, 0, x));
13995 __ Cinc(x24, x24, ne);
13996 __ Mov(w0, x);
13997 __ CallRuntime(test_int16_t);
13998 __ Sxth(w0, w0);
13999 __ Cmp(w0, ExtractSignedBitfield32(15, 0, x));
14000 __ Cinc(x24, x24, ne);
14001 __ Mov(w0, x);
14002 __ CallRuntime(test_uint16_t);
14003 __ Uxth(w0, w0);
14004 __ Cmp(w0, ExtractUnsignedBitfield32(15, 0, x));
14005 __ Cinc(x24, x24, ne);
14006 }
14007
14008
14009 int64_t value = 0xbadbeef;
14010 __ Mov(x0, reinterpret_cast<uint64_t>(&value));
14011 __ CallRuntime(runtime_call_store_at_address);
14012
14013 __ Mov(w0, 0);
14014 __ CallRuntime(runtime_call_no_args);
14015 __ Mov(w25, w0);
14016
14017 END();
14018
14019 #if defined(VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT) || \
14020 !defined(VIXL_INCLUDE_SIMULATOR_AARCH64)
14021 if (CAN_RUN()) {
14022 RUN();
14023
14024 ASSERT_EQUAL_32(1, w20);
14025 ASSERT_EQUAL_FP64(4.0, d20);
14026 ASSERT_EQUAL_64(0x123, x21);
14027 ASSERT_EQUAL_FP64(310.0, d21);
14028 VIXL_CHECK(value == 0xf00d);
14029 ASSERT_EQUAL_64(0, x22);
14030 ASSERT_EQUAL_32(124, w23);
14031 ASSERT_EQUAL_64(0, x24);
14032 ASSERT_EQUAL_32(1, w25);
14033 }
14034 #endif // #if defined(VIXL_HAS_SIMULATED_RUNTIME_CALL_SUPPORT) || ...
14035 }
14036
14037 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
void_func()14038 void void_func() {}
uint32_func()14039 uint32_t uint32_func() { return 2; }
void_param_func(uint32_t x)14040 void void_param_func(uint32_t x) { USE(x); }
uint32_param_func(uint32_t x)14041 uint32_t uint32_param_func(uint32_t x) { return ++x; }
14042
void_placeholder()14043 void void_placeholder() {}
uint32_placeholder()14044 uint32_t uint32_placeholder() { return 4; }
void_param_placeholder(uint32_t x)14045 void void_param_placeholder(uint32_t x) { USE(x); }
uint32_param_placeholder(uint32_t x)14046 uint32_t uint32_param_placeholder(uint32_t x) { return ++x; }
14047
14048 #define DO_TEST_BRANCH_INTERCEPTION(func) \
14049 __ Mov(x16, reinterpret_cast<uint64_t>(func)); \
14050 __ Blr(x16);
14051
TEST(branch_interception)14052 TEST(branch_interception) {
14053 SETUP();
14054 START();
14055
14056 // Test default branch interception, i.e: do a runtime call to the function.
14057 DO_TEST_BRANCH_INTERCEPTION(void_func);
14058 DO_TEST_BRANCH_INTERCEPTION(uint32_func);
14059 __ Mov(w20, w0);
14060 DO_TEST_BRANCH_INTERCEPTION(void_param_func);
14061 __ Mov(w0, 2);
14062 DO_TEST_BRANCH_INTERCEPTION(uint32_param_func);
14063 __ Mov(w21, w0);
14064
14065 // Test interceptions with callbacks.
14066 DO_TEST_BRANCH_INTERCEPTION(void_placeholder);
14067 __ Mov(w22, w0);
14068 DO_TEST_BRANCH_INTERCEPTION(uint32_placeholder);
14069 __ Mov(w23, w0);
14070 __ Mov(w0, 4);
14071 DO_TEST_BRANCH_INTERCEPTION(uint32_placeholder);
14072 __ Mov(w24, w0);
14073 DO_TEST_BRANCH_INTERCEPTION(uint32_placeholder);
14074 __ Mov(w25, w0);
14075
14076 END();
14077
14078 simulator.RegisterBranchInterception(void_func);
14079 simulator.RegisterBranchInterception(uint32_func);
14080 simulator.RegisterBranchInterception(void_param_func);
14081 simulator.RegisterBranchInterception(uint32_param_func);
14082
14083 auto callback = [&simulator](uint64_t original_target) {
14084 USE(original_target);
14085 simulator.WriteWRegister(0, 1);
14086 };
14087
14088 simulator.RegisterBranchInterception(void_placeholder, callback);
14089 simulator.RegisterBranchInterception(uint32_placeholder, callback);
14090 simulator.RegisterBranchInterception(void_param_placeholder, callback);
14091 simulator.RegisterBranchInterception(uint32_param_placeholder, callback);
14092
14093 if (CAN_RUN()) {
14094 RUN();
14095
14096 ASSERT_EQUAL_32(2, w20);
14097 ASSERT_EQUAL_32(3, w21);
14098 ASSERT_EQUAL_32(1, w22);
14099 ASSERT_EQUAL_32(1, w23);
14100 ASSERT_EQUAL_32(1, w24);
14101 ASSERT_EQUAL_32(1, w25);
14102 }
14103 }
14104 #endif // #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
14105 #endif // #ifdef VIXL_HAS_MACROASSEMBLER_RUNTIME_CALL_SUPPORT
14106
14107
TEST(optimised_mov_register)14108 TEST(optimised_mov_register) {
14109 SETUP();
14110
14111 START();
14112 Label start;
14113 __ Bind(&start);
14114 __ Mov(x0, x0);
14115 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&start) == 0);
14116 __ Mov(w0, w0, kDiscardForSameWReg);
14117 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&start) == 0);
14118 __ Mov(w0, w0);
14119 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&start) == kInstructionSize);
14120
14121 END();
14122
14123 if (CAN_RUN()) {
14124 RUN();
14125 }
14126 }
14127
14128
TEST(nop)14129 TEST(nop) {
14130 MacroAssembler masm;
14131
14132 Label start;
14133 __ Bind(&start);
14134 __ Nop();
14135 // `MacroAssembler::Nop` must generate at least one nop.
14136 VIXL_CHECK(masm.GetSizeOfCodeGeneratedSince(&start) >= kInstructionSize);
14137
14138 masm.FinalizeCode();
14139 }
14140
14141
TEST(mte_addg_subg)14142 TEST(mte_addg_subg) {
14143 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
14144
14145 START();
14146 __ Mov(x0, 0x5555000055555555);
14147
14148 // Add/subtract an address offset, changing tag each time.
14149 __ Addg(x1, x0, 16, 2);
14150 __ Subg(x2, x1, 16, 1);
14151
14152 // Add/subtract address offsets, keep tag.
14153 __ Addg(x3, x0, 1008, 0);
14154 __ Subg(x4, x3, 1008, 0);
14155
14156 // Change tag only. Check wraparound.
14157 __ Addg(x5, x0, 0, 15);
14158 __ Subg(x6, x0, 0, 14);
14159
14160 // Do nothing.
14161 __ Addg(x7, x0, 0, 0);
14162 __ Subg(x8, x0, 0, 0);
14163
14164 // Use stack pointer as source/destination.
14165 __ Mov(x20, sp); // Store original sp.
14166
14167 __ Subg(sp, sp, 32, 0); // Claim 32 bytes.
14168 __ Sub(x9, sp, x20); // Subtract original sp and store difference.
14169
14170 __ Mov(sp, x20); // Restore original sp.
14171 __ Claim(32);
14172 __ Addg(sp, sp, 32, 0); // Drop 32 bytes.
14173 __ Sub(x10, sp, x20); // Subtract original sp and store difference.
14174
14175 __ Mov(sp, x20); // Restore sp (should be no-op)
14176 __ Addg(sp, sp, 0, 1); // Tag the sp.
14177 __ Sub(x11, sp, x20); // Subtract original sp and store for later comparison.
14178 __ Mov(sp, x20); // Restore sp.
14179
14180 END();
14181
14182 if (CAN_RUN()) {
14183 RUN();
14184
14185 ASSERT_EQUAL_64(0x5755000055555565, x1);
14186 ASSERT_EQUAL_64(0x5855000055555555, x2);
14187 ASSERT_EQUAL_64(0x5555000055555945, x3);
14188 ASSERT_EQUAL_64(0x5555000055555555, x4);
14189 ASSERT_EQUAL_64(0x5455000055555555, x5);
14190 ASSERT_EQUAL_64(0x5355000055555555, x6);
14191 ASSERT_EQUAL_64(0x5555000055555555, x7);
14192 ASSERT_EQUAL_64(0x5555000055555555, x8);
14193 ASSERT_EQUAL_64(-32, x9);
14194 ASSERT_EQUAL_64(0, x10);
14195 ASSERT_EQUAL_64(UINT64_C(1) << 56, x11);
14196 }
14197 }
14198
TEST(mte_subp)14199 TEST(mte_subp) {
14200 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
14201
14202 START();
14203 __ Mov(x0, 0x5555555555555555);
14204 __ Mov(x1, -42);
14205
14206 // Test subp with equivalent sbfx/sub(s) operations.
14207 __ Sbfx(x10, x0, 0, 56);
14208 __ Sbfx(x11, x1, 0, 56);
14209
14210 __ Subp(x4, x0, x1);
14211 __ Sub(x5, x10, x11);
14212
14213 __ Subp(x6, x1, x0);
14214 __ Sub(x7, x11, x10);
14215
14216 __ Subps(x8, x0, x1);
14217 __ Mrs(x18, NZCV);
14218 __ Subs(x9, x10, x11);
14219 __ Mrs(x19, NZCV);
14220
14221 __ Cmpp(x1, x0);
14222 __ Mrs(x20, NZCV);
14223 __ Cmp(x11, x10);
14224 __ Mrs(x21, NZCV);
14225
14226 // Test equal pointers with mismatched tags compare equal and produce a zero
14227 // difference with subps.
14228 __ Mov(x2, 0x20); // Exclude tag 5.
14229 __ Irg(x3, x0, x2);
14230 __ Subps(x22, x0, x3);
14231
14232 END();
14233
14234 if (CAN_RUN()) {
14235 RUN();
14236
14237 ASSERT_EQUAL_64(x5, x4);
14238 ASSERT_EQUAL_64(x7, x6);
14239 ASSERT_EQUAL_64(x9, x8);
14240 ASSERT_EQUAL_64(x19, x18);
14241 ASSERT_EQUAL_64(x20, x21);
14242 ASSERT_EQUAL_64(0, x22);
14243 ASSERT_EQUAL_NZCV(ZCFlag);
14244 }
14245 }
14246
TEST(mte_gmi)14247 TEST(mte_gmi) {
14248 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
14249
14250 START();
14251 __ Mov(x0, 0xaaaa);
14252 __ Mov(x20, 0x12345678);
14253
14254 __ Gmi(x0, x20, x0); // Add mask bit 0.
14255 __ Addg(x20, x20, 0, 1);
14256 __ Gmi(x1, x20, x0); // No effect.
14257 __ Addg(x20, x20, 0, 1);
14258 __ Gmi(x2, x20, x1); // Add mask bit 2.
14259 __ Addg(x20, x20, 0, 1);
14260 __ Gmi(x3, x20, x2); // No effect.
14261 __ Addg(x20, x20, 0, 1);
14262 __ Gmi(x4, x20, x3); // Add mask bit 4.
14263 __ Addg(x20, x20, 0, 1);
14264 __ Gmi(x5, x20, x4); // No effect.
14265 __ Addg(x20, x20, 0, 9);
14266 __ Gmi(x6, x20, x5); // Add mask bit 14.
14267 __ Gmi(x7, x20, xzr); // Only mask bit 14.
14268 END();
14269
14270 if (CAN_RUN()) {
14271 RUN();
14272
14273 ASSERT_EQUAL_64(0xaaab, x0);
14274 ASSERT_EQUAL_64(0xaaab, x1);
14275 ASSERT_EQUAL_64(0xaaaf, x2);
14276 ASSERT_EQUAL_64(0xaaaf, x3);
14277 ASSERT_EQUAL_64(0xaabf, x4);
14278 ASSERT_EQUAL_64(0xaabf, x5);
14279 ASSERT_EQUAL_64(0xeabf, x6);
14280 ASSERT_EQUAL_64(0x4000, x7);
14281 }
14282 }
14283
TEST(mte_irg)14284 TEST(mte_irg) {
14285 SETUP_WITH_FEATURES(CPUFeatures::kMTE);
14286
14287 START();
14288 __ Mov(x10, 8);
14289 __ Mov(x0, 0x5555555555555555);
14290 // Insert a random tag repeatedly. If the loop doesn't exit in the expected
14291 // way, it's statistically likely that a random tag was never inserted.
14292 Label loop, failed, done;
14293 __ Bind(&loop);
14294 __ Irg(x1, x0);
14295 __ Sub(x10, x10, 1);
14296 __ Cbz(x10, &failed); // Exit if loop count exceeded.
14297 __ Cmp(x1, 0x5555555555555555);
14298 __ B(eq, &loop); // Loop if the tag hasn't changed.
14299
14300 // Check non-tag bits have not changed.
14301 __ Bic(x1, x1, 0x0f00000000000000);
14302 __ Subs(x1, x1, 0x5055555555555555);
14303 __ B(&done);
14304
14305 __ Bind(&failed);
14306 __ Mov(x1, 1);
14307
14308 __ Bind(&done);
14309
14310 // Insert random tags, excluding oddly-numbered tags, and set a bit in a
14311 // result register for each tag used.
14312 // After 128 rounds, it's statistically likely that all even bits in the
14313 // least-significant half word will be set.
14314 __ Mov(x3, 0);
14315 __ Mov(x4, 1);
14316 __ Mov(x10, 128);
14317 __ Mov(x11, 0xaaaa);
14318
14319 Label loop2;
14320 __ Bind(&loop2);
14321 __ Irg(x2, x1, x11);
14322 __ Lsr(x2, x2, 56);
14323 __ Lsl(x2, x4, x2);
14324 __ Orr(x3, x3, x2);
14325 __ Subs(x10, x10, 1);
14326 __ B(ne, &loop2);
14327 __ Mov(x2, x3);
14328
14329 // Check that excluding all tags results in zero tag insertion.
14330 __ Mov(x3, 0xffffffffffffffff);
14331 __ Irg(x3, x3, x3);
14332 END();
14333
14334 if (CAN_RUN()) {
14335 RUN();
14336
14337 ASSERT_EQUAL_64(0, x1);
14338 ASSERT_EQUAL_64(0x5555, x2);
14339 ASSERT_EQUAL_64(0xf0ffffffffffffff, x3);
14340 }
14341 }
14342
TEST(mops_set)14343 TEST(mops_set) {
14344 SETUP_WITH_FEATURES(CPUFeatures::kMOPS);
14345
14346 uint8_t dst[16];
14347 memset(dst, 0x55, ArrayLength(dst));
14348 uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
14349
14350 START();
14351 __ Mov(x0, dst_addr);
14352 __ Add(x1, x0, 1);
14353 __ Mov(x2, 13);
14354 __ Mov(x3, 0x1234aa);
14355
14356 // Set 13 bytes dst[1] onwards to 0xaa.
14357 __ Setp(x1, x2, x3);
14358 __ Setm(x1, x2, x3);
14359 __ Sete(x1, x2, x3);
14360 __ Mrs(x20, NZCV);
14361
14362 // x2 is now zero, so this should do nothing.
14363 __ Setp(x1, x2, x3);
14364 __ Setm(x1, x2, x3);
14365 __ Sete(x1, x2, x3);
14366 __ Mrs(x21, NZCV);
14367
14368 // Set dst[15] to zero using the masm helper.
14369 __ Add(x1, x0, 15);
14370 __ Mov(x2, 1);
14371 __ Set(x1, x2, xzr);
14372 __ Mrs(x22, NZCV);
14373
14374 // Load dst for comparison.
14375 __ Ldp(x10, x11, MemOperand(x0));
14376 END();
14377
14378 if (CAN_RUN()) {
14379 // Permitted results:
14380 // NZCV Xd Xn
14381 // Option A: .... end of buffer 0
14382 // Option B: ..C. end of buffer 0
14383
14384 std::vector<uint64_t> allowed_flags = {NoFlag, CFlag};
14385
14386 RUN();
14387 ASSERT_EQUAL_64(allowed_flags, x20);
14388 ASSERT_EQUAL_64(allowed_flags, x21);
14389 ASSERT_EQUAL_64(allowed_flags, x22);
14390 ASSERT_EQUAL_64(dst_addr + 16, x1);
14391 ASSERT_EQUAL_64(0, x2);
14392 ASSERT_EQUAL_64(0x1234aa, x3);
14393 ASSERT_EQUAL_64(0xaaaa'aaaa'aaaa'aa55, x10);
14394 ASSERT_EQUAL_64(0x0055'aaaa'aaaa'aaaa, x11);
14395 }
14396 }
14397
TEST(mops_setn)14398 TEST(mops_setn) {
14399 SETUP_WITH_FEATURES(CPUFeatures::kMOPS);
14400
14401 // In simulation, non-temporal set is handled by the same code as normal set,
14402 // so only a basic test is required beyond that already provided above.
14403
14404 uint8_t dst[16] = {0x55};
14405 uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
14406
14407 START();
14408 __ Mov(x0, dst_addr);
14409 __ Mov(x1, x0);
14410 __ Mov(x2, 16);
14411 __ Mov(x3, 0x42);
14412 __ Setn(x1, x2, x3);
14413 __ Mrs(x20, NZCV);
14414 __ Ldp(x10, x11, MemOperand(x0));
14415 END();
14416
14417 if (CAN_RUN()) {
14418 // Permitted results:
14419 // NZCV Xd Xn
14420 // Option A: .... end of buffer 0
14421 // Option B: ..C. end of buffer 0
14422
14423 std::vector<uint64_t> allowed_flags = {NoFlag, CFlag};
14424
14425 RUN();
14426 ASSERT_EQUAL_64(allowed_flags, x20);
14427 ASSERT_EQUAL_64(dst_addr + 16, x1);
14428 ASSERT_EQUAL_64(0, x2);
14429 ASSERT_EQUAL_64(0x42, x3);
14430 ASSERT_EQUAL_64(0x4242'4242'4242'4242, x10);
14431 ASSERT_EQUAL_64(0x4242'4242'4242'4242, x11);
14432 }
14433 }
14434
TEST(mops_setg)14435 TEST(mops_setg) {
14436 SETUP_WITH_FEATURES(CPUFeatures::kMOPS, CPUFeatures::kMTE);
14437
14438 uint8_t* dst = nullptr;
14439 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
14440 const int dst_size = 32;
14441 dst = reinterpret_cast<uint8_t*>(
14442 simulator.Mmap(NULL,
14443 dst_size * sizeof(uint8_t),
14444 PROT_READ | PROT_WRITE | PROT_MTE,
14445 MAP_PRIVATE | MAP_ANONYMOUS,
14446 -1,
14447 0));
14448
14449 VIXL_ASSERT(dst != nullptr);
14450 uint8_t* untagged_ptr = AddressUntag(dst);
14451 memset(untagged_ptr, 0xc9, dst_size);
14452 #else
14453 // TODO: Port the memory allocation to work on MTE supported platform natively.
14454 // Note that `CAN_RUN` prevents running in MTE-unsupported environments.
14455 #endif
14456
14457 uintptr_t dst_addr = reinterpret_cast<uintptr_t>(dst);
14458 uint64_t tag_mask = 0xf0ff'ffff'ffff'ffff;
14459
14460 START();
14461 __ Mov(x0, dst_addr);
14462 __ Gmi(x2, x0, xzr);
14463 __ Irg(x1, x0, x2); // Choose new tag for setg destination.
14464 __ Mov(x2, 16);
14465 __ Mov(x3, 0x42);
14466 __ Setg(x1, x2, x3);
14467 __ Mrs(x20, NZCV);
14468
14469 __ Ubfx(x4, x1, 56, 4); // Extract new tag.
14470 __ Bfi(x0, x4, 56, 4); // Tag dst_addr so set region can be loaded.
14471 __ Ldp(x10, x11, MemOperand(x0));
14472
14473 __ Mov(x0, dst_addr);
14474 __ Ldp(x12, x13, MemOperand(x0, 16)); // Unset region has original tag.
14475
14476 __ And(x1, x1, tag_mask); // Strip tag for repeatable checks.
14477 END();
14478
14479 if (CAN_RUN()) {
14480 // Permitted results:
14481 // NZCV Xd Xn
14482 // Option A: .... end of buffer 0
14483 // Option B: ..C. end of buffer 0
14484
14485 std::vector<uint64_t> allowed_flags = {NoFlag, CFlag};
14486
14487 RUN();
14488 ASSERT_EQUAL_64(allowed_flags, x20);
14489 ASSERT_EQUAL_64((dst_addr & tag_mask) + 16, x1);
14490 ASSERT_EQUAL_64(0, x2);
14491 ASSERT_EQUAL_64(0x42, x3);
14492 ASSERT_EQUAL_64(0x4242'4242'4242'4242, x10);
14493 ASSERT_EQUAL_64(0x4242'4242'4242'4242, x11);
14494 ASSERT_EQUAL_64(0xc9c9'c9c9'c9c9'c9c9, x12);
14495 ASSERT_EQUAL_64(0xc9c9'c9c9'c9c9'c9c9, x13);
14496 }
14497
14498 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
14499 simulator.Munmap(dst, dst_size, PROT_MTE);
14500 #endif
14501 }
14502
TEST(mops_cpy)14503 TEST(mops_cpy) {
14504 SETUP_WITH_FEATURES(CPUFeatures::kMOPS);
14505
14506 uint8_t buf[16];
14507 uintptr_t buf_addr = reinterpret_cast<uintptr_t>(buf);
14508
14509 for (unsigned i = 0; i < ArrayLength(buf); i++) {
14510 buf[i] = i;
14511 }
14512
14513 START();
14514 __ Mov(x0, buf_addr);
14515
14516 // Copy first eight bytes into second eight.
14517 __ Mov(x1, x0); // src = &buf[0]
14518 __ Add(x2, x0, 8); // dst = &buf[8]
14519 __ Mov(x3, 8); // count = 8
14520 __ Cpyp(x2, x1, x3);
14521 __ Cpym(x2, x1, x3);
14522 __ Cpye(x2, x1, x3);
14523 __ Ldp(x10, x11, MemOperand(x0));
14524 __ Mrs(x20, NZCV);
14525
14526 // Copy first eight bytes to overlapping offset, forcing backwards copy.
14527 __ Mov(x4, x0); // src = &buf[0]
14528 __ Add(x5, x0, 4); // dst = &buf[4]
14529 __ Mov(x6, 8); // count = 8
14530 __ Cpy(x5, x4, x6);
14531 __ Ldp(x12, x13, MemOperand(x0));
14532 __ Mrs(x21, NZCV);
14533
14534 // Copy last eight bytes to overlapping offset, forcing forwards copy.
14535 __ Add(x7, x0, 8); // src = &buf[8]
14536 __ Add(x8, x0, 6); // dst = &buf[6]
14537 __ Mov(x9, 8); // count = 8
14538 __ Cpy(x8, x7, x9);
14539 __ Ldp(x14, x15, MemOperand(x0));
14540 __ Mrs(x22, NZCV);
14541 END();
14542
14543 if (CAN_RUN()) {
14544 // Permitted results:
14545 // NZCV Xs/Xd Xn
14546 // Option A (forwards) : .... ends of buffers 0
14547 // Option A (backwards): .... starts of buffers 0
14548 // Option B (forwards) : ..C. ends of buffers 0
14549 // Option B (backwards): N.C. starts of buffers 0
14550
14551 std::vector<uint64_t> allowed_backwards_flags = {NoFlag, NCFlag};
14552 std::vector<uint64_t> allowed_forwards_flags = {NoFlag, CFlag};
14553
14554 RUN();
14555 // IMPLEMENTATION DEFINED direction
14556 if (static_cast<uintptr_t>(core.xreg(2)) > buf_addr) {
14557 // Forwards
14558 ASSERT_EQUAL_64(buf_addr + 8, x1);
14559 ASSERT_EQUAL_64(buf_addr + 16, x2);
14560 ASSERT_EQUAL_64(allowed_forwards_flags, x20);
14561 } else {
14562 // Backwards
14563 ASSERT_EQUAL_64(buf_addr, x1);
14564 ASSERT_EQUAL_64(buf_addr + 8, x2);
14565 ASSERT_EQUAL_64(allowed_backwards_flags, x20);
14566 }
14567 ASSERT_EQUAL_64(0, x3); // Xn
14568 ASSERT_EQUAL_64(0x0706'0504'0302'0100, x10);
14569 ASSERT_EQUAL_64(0x0706'0504'0302'0100, x11);
14570
14571 ASSERT_EQUAL_64(buf_addr, x4); // Xs
14572 ASSERT_EQUAL_64(buf_addr + 4, x5); // Xd
14573 ASSERT_EQUAL_64(0, x6); // Xn
14574 ASSERT_EQUAL_64(0x0302'0100'0302'0100, x12);
14575 ASSERT_EQUAL_64(0x0706'0504'0706'0504, x13);
14576 ASSERT_EQUAL_64(allowed_backwards_flags, x21);
14577
14578 ASSERT_EQUAL_64(buf_addr + 16, x7); // Xs
14579 ASSERT_EQUAL_64(buf_addr + 14, x8); // Xd
14580 ASSERT_EQUAL_64(0, x9); // Xn
14581 ASSERT_EQUAL_64(0x0504'0100'0302'0100, x14);
14582 ASSERT_EQUAL_64(0x0706'0706'0504'0706, x15);
14583 ASSERT_EQUAL_64(allowed_forwards_flags, x22);
14584 }
14585 }
14586
TEST(mops_cpyn)14587 TEST(mops_cpyn) {
14588 SETUP_WITH_FEATURES(CPUFeatures::kMOPS);
14589
14590 // In simulation, non-temporal cpy is handled by the same code as normal cpy,
14591 // so only a basic test is required beyond that already provided above.
14592
14593 uint8_t buf[16];
14594 uintptr_t buf_addr = reinterpret_cast<uintptr_t>(buf);
14595
14596 for (unsigned i = 0; i < ArrayLength(buf); i++) {
14597 buf[i] = i;
14598 }
14599
14600 START();
14601 __ Mov(x0, buf_addr);
14602
14603 __ Add(x1, x0, 1); // src = &buf[1]
14604 __ Mov(x2, x0); // dst = &buf[0]
14605 __ Mov(x3, 15); // count = 15
14606 __ Cpyn(x2, x1, x3);
14607 __ Ldp(x10, x11, MemOperand(x0));
14608 __ Mrs(x20, NZCV);
14609
14610 __ Add(x4, x0, 1); // src = &buf[1]
14611 __ Mov(x5, x0); // dst = &buf[0]
14612 __ Mov(x6, 15); // count = 15
14613 __ Cpyrn(x5, x4, x6);
14614 __ Ldp(x12, x13, MemOperand(x0));
14615 __ Mrs(x21, NZCV);
14616
14617 __ Add(x7, x0, 1); // src = &buf[1]
14618 __ Mov(x8, x0); // dst = &buf[0]
14619 __ Mov(x9, 15); // count = 15
14620 __ Cpywn(x8, x7, x9);
14621 __ Ldp(x14, x15, MemOperand(x0));
14622 __ Mrs(x22, NZCV);
14623 END();
14624
14625 if (CAN_RUN()) {
14626 // Permitted results:
14627 // NZCV Xs/Xd Xn
14628 // Option A (forwards) : .... ends of buffers 0
14629 // Option A (backwards): .... starts of buffers 0
14630 // Option B (forwards) : ..C. ends of buffers 0
14631 // Option B (backwards): N.C. starts of buffers 0
14632 //
14633 // All cases overlap to force a forwards copy.
14634
14635 std::vector<uint64_t> allowed_forwards_flags = {NoFlag, CFlag};
14636
14637 RUN();
14638 ASSERT_EQUAL_64(buf_addr + 16, x1); // Xs
14639 ASSERT_EQUAL_64(buf_addr + 15, x2); // Xd
14640 ASSERT_EQUAL_64(0, x3); // Xn
14641 ASSERT_EQUAL_64(allowed_forwards_flags, x20);
14642 ASSERT_EQUAL_64(0x0807'0605'0403'0201, x10);
14643 ASSERT_EQUAL_64(0x0f0f'0e0d'0c0b'0a09, x11);
14644
14645 ASSERT_EQUAL_64(buf_addr + 16, x4); // Xs
14646 ASSERT_EQUAL_64(buf_addr + 15, x5); // Xd
14647 ASSERT_EQUAL_64(0, x6); // Xn
14648 ASSERT_EQUAL_64(allowed_forwards_flags, x21);
14649 ASSERT_EQUAL_64(0x0908'0706'0504'0302, x12);
14650 ASSERT_EQUAL_64(0x0f0f'0f0e'0d0c'0b0a, x13);
14651
14652 ASSERT_EQUAL_64(buf_addr + 16, x7); // Xs
14653 ASSERT_EQUAL_64(buf_addr + 15, x8); // Xd
14654 ASSERT_EQUAL_64(0, x9); // Xn
14655 ASSERT_EQUAL_64(allowed_forwards_flags, x22);
14656 ASSERT_EQUAL_64(0x0a09'0807'0605'0403, x14);
14657 ASSERT_EQUAL_64(0x0f0f'0f0f'0e0d'0c0b, x15);
14658 }
14659 }
14660
TEST(mops_cpyf)14661 TEST(mops_cpyf) {
14662 SETUP_WITH_FEATURES(CPUFeatures::kMOPS);
14663
14664 uint8_t buf[16];
14665 uintptr_t buf_addr = reinterpret_cast<uintptr_t>(buf);
14666
14667 for (unsigned i = 0; i < ArrayLength(buf); i++) {
14668 buf[i] = i;
14669 }
14670
14671 // As `mops_cpy`, but `cpyf` always copies forwards, so is only useful for
14672 // non-overlapping buffers, or those where the source address is greater than
14673 // the destination address.
14674
14675 START();
14676 __ Mov(x0, buf_addr);
14677
14678 // Copy first eight bytes into second eight, without overlap.
14679 __ Mov(x1, x0); // src = &buf[0]
14680 __ Add(x2, x0, 8); // dst = &buf[8]
14681 __ Mov(x3, 8); // count = 8
14682 __ Cpyfp(x2, x1, x3);
14683 __ Cpyfm(x2, x1, x3);
14684 __ Cpyfe(x2, x1, x3);
14685 __ Ldp(x10, x11, MemOperand(x0));
14686 __ Mrs(x20, NZCV);
14687
14688 // Copy last eight bytes to overlapping offset where src < dst.
14689 __ Add(x4, x0, 8); // src = &buf[8]
14690 __ Add(x5, x0, 6); // dst = &buf[6]
14691 __ Mov(x6, 8); // count = 8
14692 __ Cpyf(x5, x4, x6);
14693 __ Ldp(x12, x13, MemOperand(x0));
14694 __ Mrs(x21, NZCV);
14695
14696 // Copy first eight bytes to overlapping offset where src > dst.
14697 __ Mov(x7, x0); // src = &buf[0]
14698 __ Add(x8, x0, 4); // dst = &buf[4]
14699 __ Mov(x9, 8); // count = 8
14700 __ Cpyf(x8, x7, x9);
14701 // The only testable result is the first and last four bytes, which are not
14702 // written at all.
14703 __ Ldr(w14, MemOperand(x0));
14704 __ Ldr(w15, MemOperand(x0, 12));
14705 __ Mrs(x22, NZCV);
14706
14707 END();
14708
14709 if (CAN_RUN()) {
14710 // Permitted results:
14711 // NZCV Xs/Xd Xn
14712 // Option A: .... ends of buffers 0
14713 // Option B: ..C. ends of buffers 0
14714
14715 std::vector<uint64_t> allowed_forwards_flags = {NoFlag, CFlag};
14716
14717 RUN();
14718
14719 // No overlap.
14720 ASSERT_EQUAL_64(buf_addr + 8, x1); // Xs
14721 ASSERT_EQUAL_64(buf_addr + 16, x2); // Xd
14722 ASSERT_EQUAL_64(0, x3); // Xn
14723 ASSERT_EQUAL_64(allowed_forwards_flags, x20);
14724 ASSERT_EQUAL_64(0x0706'0504'0302'0100, x10);
14725 ASSERT_EQUAL_64(0x0706'0504'0302'0100, x11);
14726
14727 // Overlap, src > dst.
14728 ASSERT_EQUAL_64(buf_addr + 16, x4); // Xs
14729 ASSERT_EQUAL_64(buf_addr + 14, x5); // Xd
14730 ASSERT_EQUAL_64(0, x6); // Xn
14731 ASSERT_EQUAL_64(0x0100'0504'0302'0100, x12);
14732 ASSERT_EQUAL_64(0x0706'0706'0504'0302, x13);
14733 ASSERT_EQUAL_64(allowed_forwards_flags, x21);
14734
14735 // Overlap, src < dst.
14736 ASSERT_EQUAL_64(buf_addr + 8, x7); // Xs
14737 ASSERT_EQUAL_64(buf_addr + 12, x8); // Xd
14738 ASSERT_EQUAL_64(0, x9); // Xn
14739 // We can only reliably test that the operation didn't write outside the
14740 // specified region.
14741 ASSERT_EQUAL_32(0x0302'0100, w14);
14742 ASSERT_EQUAL_32(0x0706'0706, w15);
14743 ASSERT_EQUAL_64(allowed_forwards_flags, x22);
14744 }
14745 }
14746
TEST(mops_cpyfn)14747 TEST(mops_cpyfn) {
14748 SETUP_WITH_FEATURES(CPUFeatures::kMOPS);
14749
14750 // In simulation, non-temporal cpy is handled by the same code as normal cpy,
14751 // so only a basic test is required beyond that already provided above.
14752
14753 uint8_t buf[16];
14754 uintptr_t buf_addr = reinterpret_cast<uintptr_t>(buf);
14755
14756 for (unsigned i = 0; i < ArrayLength(buf); i++) {
14757 buf[i] = i;
14758 }
14759
14760 START();
14761 __ Mov(x0, buf_addr);
14762
14763 __ Add(x1, x0, 1); // src = &buf[1]
14764 __ Mov(x2, x0); // dst = &buf[0]
14765 __ Mov(x3, 15); // count = 15
14766 __ Cpyfn(x2, x1, x3);
14767 __ Ldp(x10, x11, MemOperand(x0));
14768 __ Mrs(x20, NZCV);
14769
14770 __ Add(x4, x0, 1); // src = &buf[1]
14771 __ Mov(x5, x0); // dst = &buf[0]
14772 __ Mov(x6, 15); // count = 15
14773 __ Cpyfrn(x5, x4, x6);
14774 __ Ldp(x12, x13, MemOperand(x0));
14775 __ Mrs(x21, NZCV);
14776
14777 __ Add(x7, x0, 1); // src = &buf[1]
14778 __ Mov(x8, x0); // dst = &buf[0]
14779 __ Mov(x9, 15); // count = 15
14780 __ Cpyfwn(x8, x7, x9);
14781 __ Ldp(x14, x15, MemOperand(x0));
14782 __ Mrs(x22, NZCV);
14783 END();
14784
14785 if (CAN_RUN()) {
14786 // Permitted results:
14787 // NZCV Xs/Xd Xn
14788 // Option A: .... ends of buffers 0
14789 // Option B: ..C. ends of buffers 0
14790
14791 std::vector<uint64_t> allowed_flags = {NoFlag, CFlag};
14792
14793 RUN();
14794 ASSERT_EQUAL_64(buf_addr + 16, x1); // Xs
14795 ASSERT_EQUAL_64(buf_addr + 15, x2); // Xd
14796 ASSERT_EQUAL_64(0, x3); // Xn
14797 ASSERT_EQUAL_64(allowed_flags, x20);
14798 ASSERT_EQUAL_64(0x0807'0605'0403'0201, x10);
14799 ASSERT_EQUAL_64(0x0f0f'0e0d'0c0b'0a09, x11);
14800
14801 ASSERT_EQUAL_64(buf_addr + 16, x4); // Xs
14802 ASSERT_EQUAL_64(buf_addr + 15, x5); // Xd
14803 ASSERT_EQUAL_64(0, x6); // Xn
14804 ASSERT_EQUAL_64(allowed_flags, x21);
14805 ASSERT_EQUAL_64(0x0908'0706'0504'0302, x12);
14806 ASSERT_EQUAL_64(0x0f0f'0f0e'0d0c'0b0a, x13);
14807
14808 ASSERT_EQUAL_64(buf_addr + 16, x7); // Xs
14809 ASSERT_EQUAL_64(buf_addr + 15, x8); // Xd
14810 ASSERT_EQUAL_64(0, x9); // Xn
14811 ASSERT_EQUAL_64(allowed_flags, x22);
14812 ASSERT_EQUAL_64(0x0a09'0807'0605'0403, x14);
14813 ASSERT_EQUAL_64(0x0f0f'0f0f'0e0d'0c0b, x15);
14814 }
14815 }
14816
TEST(cssc_abs)14817 TEST(cssc_abs) {
14818 SETUP_WITH_FEATURES(CPUFeatures::kCSSC);
14819
14820 START();
14821 __ Mov(x0, -1);
14822 __ Mov(x1, 1);
14823 __ Mov(x2, 0);
14824 __ Mov(x3, 0x7fff'ffff);
14825 __ Mov(x4, 0x8000'0000);
14826 __ Mov(x5, 0x8000'0001);
14827 __ Mov(x6, 0x7fff'ffff'ffff'ffff);
14828 __ Mov(x7, 0x8000'0000'0000'0000);
14829 __ Mov(x8, 0x8000'0000'0000'0001);
14830
14831 __ Abs(w10, w0);
14832 __ Abs(x11, x0);
14833 __ Abs(w12, w1);
14834 __ Abs(x13, x1);
14835 __ Abs(w14, w2);
14836 __ Abs(x15, x2);
14837
14838 __ Abs(w19, w3);
14839 __ Abs(x20, x3);
14840 __ Abs(w21, w4);
14841 __ Abs(x22, x4);
14842 __ Abs(w23, w5);
14843 __ Abs(x24, x5);
14844 __ Abs(w25, w6);
14845 __ Abs(x26, x6);
14846 __ Abs(w27, w7);
14847 __ Abs(x28, x7);
14848 __ Abs(w29, w8);
14849 __ Abs(x30, x8);
14850 END();
14851
14852 if (CAN_RUN()) {
14853 RUN();
14854
14855 ASSERT_EQUAL_64(1, x10);
14856 ASSERT_EQUAL_64(1, x11);
14857 ASSERT_EQUAL_64(1, x12);
14858 ASSERT_EQUAL_64(1, x13);
14859 ASSERT_EQUAL_64(0, x14);
14860 ASSERT_EQUAL_64(0, x15);
14861 ASSERT_EQUAL_64(0x7fff'ffff, x19);
14862 ASSERT_EQUAL_64(0x7fff'ffff, x20);
14863 ASSERT_EQUAL_64(0x8000'0000, x21);
14864 ASSERT_EQUAL_64(0x8000'0000, x22);
14865 ASSERT_EQUAL_64(0x7fff'ffff, x23);
14866 ASSERT_EQUAL_64(0x8000'0001, x24);
14867 ASSERT_EQUAL_64(1, x25);
14868 ASSERT_EQUAL_64(0x7fff'ffff'ffff'ffff, x26);
14869 ASSERT_EQUAL_64(0, x27);
14870 ASSERT_EQUAL_64(0x8000'0000'0000'0000, x28);
14871 ASSERT_EQUAL_64(1, x29);
14872 ASSERT_EQUAL_64(0x7fff'ffff'ffff'ffff, x30);
14873 }
14874 }
14875
TEST(cssc_cnt)14876 TEST(cssc_cnt) {
14877 SETUP_WITH_FEATURES(CPUFeatures::kCSSC);
14878
14879 START();
14880 __ Mov(x0, -1);
14881 __ Mov(x1, 1);
14882 __ Mov(x2, 0);
14883 __ Mov(x3, 0x7fff'ffff);
14884 __ Mov(x4, 0x8000'0000);
14885 __ Mov(x5, 0x8000'0001);
14886 __ Mov(x6, 0x7fff'ffff'ffff'ffff);
14887 __ Mov(x7, 0x4242'4242'aaaa'aaaa);
14888
14889 __ Cnt(w10, w0);
14890 __ Cnt(x11, x0);
14891 __ Cnt(w12, w1);
14892 __ Cnt(x13, x1);
14893 __ Cnt(w14, w2);
14894 __ Cnt(x15, x2);
14895 __ Cnt(w19, w3);
14896 __ Cnt(x20, x3);
14897 __ Cnt(w21, w4);
14898 __ Cnt(x22, x4);
14899 __ Cnt(w23, w5);
14900 __ Cnt(x24, x5);
14901 __ Cnt(w25, w6);
14902 __ Cnt(x26, x6);
14903 __ Cnt(w27, w7);
14904 __ Cnt(x28, x7);
14905 END();
14906
14907 if (CAN_RUN()) {
14908 RUN();
14909
14910 ASSERT_EQUAL_64(32, x10);
14911 ASSERT_EQUAL_64(64, x11);
14912 ASSERT_EQUAL_64(1, x12);
14913 ASSERT_EQUAL_64(1, x13);
14914 ASSERT_EQUAL_64(0, x14);
14915 ASSERT_EQUAL_64(0, x15);
14916 ASSERT_EQUAL_64(31, x19);
14917 ASSERT_EQUAL_64(31, x20);
14918 ASSERT_EQUAL_64(1, x21);
14919 ASSERT_EQUAL_64(1, x22);
14920 ASSERT_EQUAL_64(2, x23);
14921 ASSERT_EQUAL_64(2, x24);
14922 ASSERT_EQUAL_64(32, x25);
14923 ASSERT_EQUAL_64(63, x26);
14924 ASSERT_EQUAL_64(16, x27);
14925 ASSERT_EQUAL_64(24, x28);
14926 }
14927 }
14928
TEST(cssc_ctz)14929 TEST(cssc_ctz) {
14930 SETUP_WITH_FEATURES(CPUFeatures::kCSSC);
14931
14932 START();
14933 __ Mov(x0, -1);
14934 __ Mov(x1, 1);
14935 __ Mov(x2, 2);
14936 __ Mov(x3, 0x7fff'ff00);
14937 __ Mov(x4, 0x8000'4000);
14938 __ Mov(x5, 0x4000'0001);
14939 __ Mov(x6, 0x0000'0001'0000'0000);
14940 __ Mov(x7, 0x4200'0000'0000'0000);
14941
14942 __ Ctz(w10, w0);
14943 __ Ctz(x11, x0);
14944 __ Ctz(w12, w1);
14945 __ Ctz(x13, x1);
14946 __ Ctz(w14, w2);
14947 __ Ctz(x15, x2);
14948 __ Ctz(w19, w3);
14949 __ Ctz(x20, x3);
14950 __ Ctz(w21, w4);
14951 __ Ctz(x22, x4);
14952 __ Ctz(w23, w5);
14953 __ Ctz(x24, x5);
14954 __ Ctz(w25, w6);
14955 __ Ctz(x26, x6);
14956 __ Ctz(w27, w7);
14957 __ Ctz(x28, x7);
14958 END();
14959
14960 if (CAN_RUN()) {
14961 RUN();
14962
14963 ASSERT_EQUAL_64(0, x10);
14964 ASSERT_EQUAL_64(0, x11);
14965 ASSERT_EQUAL_64(0, x12);
14966 ASSERT_EQUAL_64(0, x13);
14967 ASSERT_EQUAL_64(1, x14);
14968 ASSERT_EQUAL_64(1, x15);
14969 ASSERT_EQUAL_64(8, x19);
14970 ASSERT_EQUAL_64(8, x20);
14971 ASSERT_EQUAL_64(14, x21);
14972 ASSERT_EQUAL_64(14, x22);
14973 ASSERT_EQUAL_64(0, x23);
14974 ASSERT_EQUAL_64(0, x24);
14975 ASSERT_EQUAL_64(32, x25);
14976 ASSERT_EQUAL_64(32, x26);
14977 ASSERT_EQUAL_64(32, x27);
14978 ASSERT_EQUAL_64(57, x28);
14979 }
14980 }
14981
14982 using MinMaxOp = void (MacroAssembler::*)(const Register&,
14983 const Register&,
14984 const Operand&);
14985
MinMaxHelper(MinMaxOp op,bool is_signed,uint64_t a,uint64_t b,uint32_t wexp,uint64_t xexp)14986 static void MinMaxHelper(MinMaxOp op,
14987 bool is_signed,
14988 uint64_t a,
14989 uint64_t b,
14990 uint32_t wexp,
14991 uint64_t xexp) {
14992 SETUP_WITH_FEATURES(CPUFeatures::kCSSC);
14993
14994 START();
14995 __ Mov(x0, a);
14996 __ Mov(x1, b);
14997 if ((is_signed && IsInt8(b)) || (!is_signed && IsUint8(b))) {
14998 (masm.*op)(w10, w0, b);
14999 (masm.*op)(x11, x0, b);
15000 } else {
15001 (masm.*op)(w10, w0, w1);
15002 (masm.*op)(x11, x0, x1);
15003 }
15004 END();
15005
15006 if (CAN_RUN()) {
15007 RUN();
15008 ASSERT_EQUAL_64(wexp, x10);
15009 ASSERT_EQUAL_64(xexp, x11);
15010 }
15011 }
15012
TEST(cssc_umin)15013 TEST(cssc_umin) {
15014 MinMaxOp op = &MacroAssembler::Umin;
15015 uint32_t s32min = 0x8000'0000;
15016 uint32_t s32max = 0x7fff'ffff;
15017 uint64_t s64min = 0x8000'0000'0000'0000;
15018 uint64_t s64max = 0x7fff'ffff'ffff'ffff;
15019
15020 MinMaxHelper(op, false, 0, 0, 0, 0);
15021 MinMaxHelper(op, false, 128, 255, 128, 128);
15022 MinMaxHelper(op, false, 0, 0xffff'ffff'ffff'ffff, 0, 0);
15023 MinMaxHelper(op, false, s32max, s32min, s32max, s32max);
15024 MinMaxHelper(op, false, s32min, s32max, s32max, s32max);
15025 MinMaxHelper(op, false, s64max, s32min, s32min, s32min);
15026 MinMaxHelper(op, false, s64min, s64max, 0, s64max);
15027 }
15028
TEST(cssc_umax)15029 TEST(cssc_umax) {
15030 MinMaxOp op = &MacroAssembler::Umax;
15031 uint32_t s32min = 0x8000'0000;
15032 uint32_t s32max = 0x7fff'ffff;
15033 uint64_t s64min = 0x8000'0000'0000'0000;
15034 uint64_t s64max = 0x7fff'ffff'ffff'ffff;
15035
15036 MinMaxHelper(op, false, 0, 0, 0, 0);
15037 MinMaxHelper(op, false, 128, 255, 255, 255);
15038 MinMaxHelper(op,
15039 false,
15040 0,
15041 0xffff'ffff'ffff'ffff,
15042 0xffff'ffff,
15043 0xffff'ffff'ffff'ffff);
15044 MinMaxHelper(op, false, s32max, s32min, s32min, s32min);
15045 MinMaxHelper(op, false, s32min, s32max, s32min, s32min);
15046 MinMaxHelper(op, false, s64max, s32min, 0xffff'ffff, s64max);
15047 MinMaxHelper(op, false, s64min, s64max, 0xffff'ffff, s64min);
15048 }
15049
TEST(cssc_smin)15050 TEST(cssc_smin) {
15051 MinMaxOp op = &MacroAssembler::Smin;
15052 uint32_t s32min = 0x8000'0000;
15053 uint32_t s32max = 0x7fff'ffff;
15054 uint64_t s64min = 0x8000'0000'0000'0000;
15055 uint64_t s64max = 0x7fff'ffff'ffff'ffff;
15056
15057 MinMaxHelper(op, true, 0, 0, 0, 0);
15058 MinMaxHelper(op, true, 128, 255, 128, 128);
15059 MinMaxHelper(op,
15060 true,
15061 0,
15062 0xffff'ffff'ffff'ffff,
15063 0xffff'ffff,
15064 0xffff'ffff'ffff'ffff);
15065 MinMaxHelper(op, true, s32max, s32min, s32min, s32max);
15066 MinMaxHelper(op, true, s32min, s32max, s32min, s32max);
15067 MinMaxHelper(op, true, s64max, s32min, s32min, s32min);
15068 MinMaxHelper(op, true, s64min, s64max, 0xffff'ffff, s64min);
15069 }
15070
TEST(cssc_smax)15071 TEST(cssc_smax) {
15072 MinMaxOp op = &MacroAssembler::Smax;
15073 uint32_t s32min = 0x8000'0000;
15074 uint32_t s32max = 0x7fff'ffff;
15075 uint64_t s64min = 0x8000'0000'0000'0000;
15076 uint64_t s64max = 0x7fff'ffff'ffff'ffff;
15077
15078 MinMaxHelper(op, true, 0, 0, 0, 0);
15079 MinMaxHelper(op, true, 128, 255, 255, 255);
15080 MinMaxHelper(op, true, 0, 0xffff'ffff'ffff'ffff, 0, 0);
15081 MinMaxHelper(op, true, s32max, s32min, s32max, s32min);
15082 MinMaxHelper(op, true, s32min, s32max, s32max, s32min);
15083 MinMaxHelper(op, true, s64max, s32min, 0xffff'ffff, s64max);
15084 MinMaxHelper(op, true, s64min, s64max, 0, s64max);
15085 }
15086
ChkfeatHelper(uint64_t initial,uint64_t chkfeat,CPUFeatures require)15087 static void ChkfeatHelper(uint64_t initial,
15088 uint64_t chkfeat,
15089 CPUFeatures require) {
15090 SETUP_WITH_FEATURES(require);
15091
15092 START();
15093 __ Mov(x16, initial);
15094 __ Chkfeat(x16);
15095 __ Mov(x0, x16);
15096
15097 __ Mov(x1, initial);
15098 __ Chkfeat(x1);
15099 END();
15100
15101 if (CAN_RUN()) {
15102 RUN_WITHOUT_SEEN_FEATURE_CHECK();
15103 ASSERT_EQUAL_64(chkfeat, x0);
15104 ASSERT_EQUAL_64(x0, x1);
15105 }
15106 }
15107
TEST(chkfeat)15108 TEST(chkfeat) { ChkfeatHelper(0x0, 0x0, CPUFeatures::None()); }
15109
TEST(chkfeat_gcs)15110 TEST(chkfeat_gcs) { ChkfeatHelper(0x1, 0x0, CPUFeatures::kGCS); }
15111
TEST(chkfeat_unused)15112 TEST(chkfeat_unused) {
15113 // Bits 1-63 are reserved. This test ensures that they are unmodified by
15114 // `chkfeat`, but it will need to be updated if these bits are assigned in the
15115 // future.
15116 ChkfeatHelper(0xffff'ffff'ffff'fffe,
15117 0xffff'ffff'ffff'fffe,
15118 CPUFeatures::None());
15119 }
15120
TEST(gcs_feature_off)15121 TEST(gcs_feature_off) {
15122 SETUP();
15123
15124 START();
15125 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
15126 simulator.DisableGCSCheck();
15127 #else
15128 // TODO: Disable GCS via operating system for this test, here and in the
15129 // gcs_off_pac_on test below.
15130 #endif
15131 __ Mov(x16, 0x0123'4567'89ab'cdef);
15132 __ Chkfeat(x16);
15133
15134 // This sequence would fail with GCS enabled.
15135 Label lab, end;
15136 __ Bl(&lab);
15137 __ B(&end);
15138
15139 __ Bind(&lab);
15140 __ Adr(lr, &end);
15141 __ Ret();
15142
15143 __ Bind(&end);
15144 END();
15145
15146 if (CAN_RUN()) {
15147 // TODO: This will currently fail on GCS-supporting hardware.
15148 RUN();
15149 ASSERT_EQUAL_64(0x0123'4567'89ab'cdef, x16);
15150 }
15151 }
15152
TEST(gcs_gcspushm)15153 TEST(gcs_gcspushm) {
15154 SETUP_WITH_FEATURES(CPUFeatures::kGCS);
15155
15156 Label ret;
15157 START();
15158 __ Adr(x0, &ret);
15159 __ Gcspushm(x0);
15160 __ Ret(x0);
15161 __ Nop();
15162 __ Bind(&ret);
15163 END();
15164
15165 if (CAN_RUN()) {
15166 RUN();
15167 }
15168 }
15169
TEST(gcs_gcspopm)15170 TEST(gcs_gcspopm) {
15171 SETUP_WITH_FEATURES(CPUFeatures::kGCS);
15172
15173 Label lab, ret;
15174 START();
15175 __ Adr(x0, &ret);
15176 __ Bl(&lab);
15177 __ Bind(&ret);
15178 __ Nop();
15179 __ Bind(&lab);
15180 __ Gcspopm(x1);
15181 END();
15182
15183 if (CAN_RUN()) {
15184 RUN();
15185 ASSERT_EQUAL_64(x0, x1);
15186 }
15187 }
15188
TEST(gcs_gcsss1)15189 TEST(gcs_gcsss1) {
15190 SETUP_WITH_FEATURES(CPUFeatures::kGCS);
15191
15192 START();
15193 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
15194 uint64_t new_gcs = simulator.GetGCSManager().AllocateStack();
15195 __ Mov(x0, new_gcs);
15196 #else
15197 // TODO: Request new GCS from the operating system.
15198 #endif
15199
15200 // Partial stack swap to check GCS has changed, and a token is at the top
15201 // of the new stack.
15202 __ Gcsss1(x0);
15203 __ Gcspopm(x1);
15204
15205 __ Bic(x0, x0, 7); // Clear LSB of new GCS.
15206 __ Bic(x2, x1, 7); // Clear LSB of old GCS.
15207 __ Cmp(x0, x2);
15208 __ Cset(x0, eq);
15209 __ And(x1, x1, 7); // In progress token.
15210 END();
15211
15212 if (CAN_RUN()) {
15213 RUN();
15214 ASSERT_EQUAL_64(0, x0); // GCS must not be equal.
15215 ASSERT_EQUAL_64(5, x1); // In progress token must be present.
15216 }
15217 }
15218
15219 // TODO: Add extra tests for combinations of PAC and GCS enabled.
TEST(gcs_stack_swap)15220 TEST(gcs_stack_swap) {
15221 SETUP_WITH_FEATURES(CPUFeatures::kGCS);
15222
15223 START();
15224 Label stack_swap, sub_fn, end;
15225 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
15226 uint64_t new_gcs = simulator.GetGCSManager().AllocateStack();
15227 __ Mov(x0, new_gcs);
15228 #else
15229 // TODO: Request new GCS from the operating system.
15230 #endif
15231 __ Bl(&stack_swap);
15232 __ B(&end);
15233
15234 __ Bind(&stack_swap);
15235 __ Gcsss1(x0); // x0 = new GCS.
15236 __ Gcsss2(x1); // x1 = old GCS.
15237 __ Mov(x29, lr);
15238 __ Bl(&sub_fn);
15239 __ Mov(lr, x29);
15240 __ Gcsss1(x1); // Restore old GCS.
15241 __ Gcsss2(x0);
15242 __ Ret();
15243
15244 __ Bind(&sub_fn);
15245 __ Mov(x2, 42);
15246 __ Ret();
15247
15248 __ Bind(&end);
15249 END();
15250
15251 if (CAN_RUN()) {
15252 RUN();
15253 ASSERT_EQUAL_64(42, x2);
15254 }
15255 }
15256
TEST(gcs_off_pac_on)15257 TEST(gcs_off_pac_on) {
15258 SETUP_WITH_FEATURES(CPUFeatures::kPAuth);
15259
15260 START();
15261 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
15262 simulator.DisableGCSCheck();
15263 #else
15264 // TODO: Disable GCS via operating system for this test, and enable for native.
15265 #endif
15266 __ Mov(x16, 1);
15267 __ Chkfeat(x16);
15268 __ Mov(x1, x16);
15269
15270 Label fn1, after_fn1;
15271
15272 __ Mov(x28, sp);
15273 __ Mov(x29, lr);
15274 __ Mov(sp, 0x477d469dec0b8760);
15275
15276 __ Mov(x0, 0);
15277 __ B(&after_fn1);
15278
15279 __ Bind(&fn1);
15280 __ Mov(x0, 42);
15281 __ Paciasp();
15282 __ Retaa();
15283
15284 __ Bind(&after_fn1);
15285 __ Bl(&fn1);
15286
15287 __ Mov(sp, x28);
15288 __ Mov(lr, x29);
15289 END();
15290
15291 if (CAN_RUN()) {
15292 RUN();
15293
15294 ASSERT_EQUAL_64(42, x0);
15295 ASSERT_EQUAL_64(1, x1);
15296 }
15297 }
15298
15299 #ifdef VIXL_NEGATIVE_TESTING
TEST(gcs_negative_test)15300 TEST(gcs_negative_test) {
15301 SETUP_WITH_FEATURES(CPUFeatures::kGCS);
15302
15303 Label fn, bad_return_addr, done;
15304 START();
15305 __ Bl(&fn);
15306 __ Nop(); // GCS enforces that fn() returns here...
15307
15308 __ Bind(&bad_return_addr);
15309 __ B(&done); // ... but this test attempts to return here.
15310
15311 __ Bind(&fn);
15312 __ Adr(lr, &bad_return_addr);
15313 __ Ret();
15314
15315 __ Bind(&done);
15316 END();
15317
15318 if (CAN_RUN()) {
15319 MUST_FAIL_WITH_MESSAGE(RUN(), "GCS failed");
15320 }
15321 }
15322 #endif // VIXL_NEGATIVE_TESTING
15323
TEST(dc_zva)15324 TEST(dc_zva) {
15325 SETUP_WITH_FEATURES(CPUFeatures::kNEON);
15326
15327 const int zva_blocksize = 64; // Assumed blocksize.
15328 uint8_t buf[2 * zva_blocksize];
15329 uintptr_t buf_addr = reinterpret_cast<uintptr_t>(buf);
15330 uintptr_t aligned_addr = AlignUp(buf_addr, zva_blocksize);
15331
15332 START();
15333 // Skip this test if the ZVA blocksize is not 64 bytes.
15334 // Set up initial register values to allow the test to pass when skipped.
15335 Label skip;
15336 __ Movi(q0.V16B(), 0);
15337 __ Movi(q1.V16B(), 0);
15338 __ Movi(q2.V16B(), 0);
15339 __ Movi(q3.V16B(), 0);
15340
15341 __ Mrs(x1, DCZID_EL0);
15342 __ Cmp(x1, 4); // 4 => DC ZVA enabled with 64-byte blocks.
15343 __ B(ne, &skip);
15344
15345 // Fill aligned region with a pattern.
15346 __ Mov(x0, aligned_addr);
15347 __ Movi(q0.V16B(), 0x55);
15348 __ Movi(q1.V16B(), 0xaa);
15349 __ Movi(q2.V16B(), 0x55);
15350 __ Movi(q3.V16B(), 0xaa);
15351 __ St4(q0.V16B(), q1.V16B(), q2.V16B(), q3.V16B(), MemOperand(x0));
15352
15353 // Misalign the address to check DC ZVA re-aligns.
15354 __ Add(x0, x0, 42);
15355
15356 // Clear the aligned region.
15357 __ Dc(ZVA, x0);
15358
15359 // Reload the aligned region to check contents.
15360 __ Mov(x0, aligned_addr);
15361 __ Ld1(q0.V16B(), q1.V16B(), q2.V16B(), q3.V16B(), MemOperand(x0));
15362
15363 __ Bind(&skip);
15364 END();
15365
15366 if (CAN_RUN()) {
15367 RUN();
15368 if (core.xreg(1) == 4) {
15369 ASSERT_EQUAL_128(0, 0, q0);
15370 ASSERT_EQUAL_128(0, 0, q1);
15371 ASSERT_EQUAL_128(0, 0, q2);
15372 ASSERT_EQUAL_128(0, 0, q3);
15373 } else {
15374 printf("SKIPPED: DC ZVA chunksize not 64-bytes");
15375 }
15376 }
15377 }
15378
15379 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
15380 // Test the pseudo-instructions that control CPUFeatures dynamically in the
15381 // Simulator. These are used by the test infrastructure itself, but in a fairly
15382 // limited way.
15383
RunHelperWithFeatureCombinations(void (* helper)(const CPUFeatures & base,const CPUFeatures & f))15384 static void RunHelperWithFeatureCombinations(
15385 void (*helper)(const CPUFeatures& base, const CPUFeatures& f)) {
15386 // Iterate, testing the first n features in this list.
15387 CPUFeatures::Feature features[] = {
15388 // Put kNone first, so that the first iteration uses an empty feature set.
15389 CPUFeatures::kNone,
15390 // The remaining features used are arbitrary.
15391 CPUFeatures::kIDRegisterEmulation,
15392 CPUFeatures::kDCPoP,
15393 CPUFeatures::kPAuth,
15394 CPUFeatures::kFcma,
15395 CPUFeatures::kAES,
15396 CPUFeatures::kNEON,
15397 CPUFeatures::kCRC32,
15398 CPUFeatures::kFP,
15399 CPUFeatures::kPmull1Q,
15400 CPUFeatures::kSM4,
15401 CPUFeatures::kSM3,
15402 CPUFeatures::kDotProduct,
15403 };
15404 VIXL_ASSERT(CPUFeatures(CPUFeatures::kNone) == CPUFeatures::None());
15405 // The features are not necessarily encoded in kInstructionSize-sized slots,
15406 // so the MacroAssembler must pad the list to align the following instruction.
15407 // Ensure that we have enough features in the list to cover all interesting
15408 // alignment cases, even if the highest common factor of kInstructionSize and
15409 // an encoded feature is one.
15410 VIXL_STATIC_ASSERT(ARRAY_SIZE(features) > kInstructionSize);
15411
15412 CPUFeatures base = CPUFeatures::None();
15413 for (size_t i = 0; i < ARRAY_SIZE(features); i++) {
15414 base.Combine(features[i]);
15415 CPUFeatures f = CPUFeatures::None();
15416 for (size_t j = 0; j < ARRAY_SIZE(features); j++) {
15417 f.Combine(features[j]);
15418 helper(base, f);
15419 }
15420 }
15421 }
15422
SetSimulatorCPUFeaturesHelper(const CPUFeatures & base,const CPUFeatures & f)15423 static void SetSimulatorCPUFeaturesHelper(const CPUFeatures& base,
15424 const CPUFeatures& f) {
15425 SETUP_WITH_FEATURES(base);
15426 START();
15427
15428 __ SetSimulatorCPUFeatures(f);
15429
15430 END();
15431 if (CAN_RUN()) {
15432 RUN_WITHOUT_SEEN_FEATURE_CHECK();
15433 VIXL_CHECK(*(simulator.GetCPUFeatures()) == f);
15434 }
15435 }
15436
TEST(configure_cpu_features_set)15437 TEST(configure_cpu_features_set) {
15438 RunHelperWithFeatureCombinations(SetSimulatorCPUFeaturesHelper);
15439 }
15440
EnableSimulatorCPUFeaturesHelper(const CPUFeatures & base,const CPUFeatures & f)15441 static void EnableSimulatorCPUFeaturesHelper(const CPUFeatures& base,
15442 const CPUFeatures& f) {
15443 SETUP_WITH_FEATURES(base);
15444 START();
15445
15446 __ EnableSimulatorCPUFeatures(f);
15447
15448 END();
15449 if (CAN_RUN()) {
15450 RUN_WITHOUT_SEEN_FEATURE_CHECK();
15451 VIXL_CHECK(*(simulator.GetCPUFeatures()) == base.With(f));
15452 }
15453 }
15454
TEST(configure_cpu_features_enable)15455 TEST(configure_cpu_features_enable) {
15456 RunHelperWithFeatureCombinations(EnableSimulatorCPUFeaturesHelper);
15457 }
15458
DisableSimulatorCPUFeaturesHelper(const CPUFeatures & base,const CPUFeatures & f)15459 static void DisableSimulatorCPUFeaturesHelper(const CPUFeatures& base,
15460 const CPUFeatures& f) {
15461 SETUP_WITH_FEATURES(base);
15462 START();
15463
15464 __ DisableSimulatorCPUFeatures(f);
15465
15466 END();
15467 if (CAN_RUN()) {
15468 RUN_WITHOUT_SEEN_FEATURE_CHECK();
15469 VIXL_CHECK(*(simulator.GetCPUFeatures()) == base.Without(f));
15470 }
15471 }
15472
TEST(configure_cpu_features_disable)15473 TEST(configure_cpu_features_disable) {
15474 RunHelperWithFeatureCombinations(DisableSimulatorCPUFeaturesHelper);
15475 }
15476
SaveRestoreSimulatorCPUFeaturesHelper(const CPUFeatures & base,const CPUFeatures & f)15477 static void SaveRestoreSimulatorCPUFeaturesHelper(const CPUFeatures& base,
15478 const CPUFeatures& f) {
15479 SETUP_WITH_FEATURES(base);
15480 START();
15481
15482 {
15483 __ SaveSimulatorCPUFeatures();
15484 __ SetSimulatorCPUFeatures(f);
15485 {
15486 __ SaveSimulatorCPUFeatures();
15487 __ SetSimulatorCPUFeatures(CPUFeatures::All());
15488 __ RestoreSimulatorCPUFeatures();
15489 }
15490 __ RestoreSimulatorCPUFeatures();
15491 }
15492
15493 END();
15494 if (CAN_RUN()) {
15495 RUN_WITHOUT_SEEN_FEATURE_CHECK();
15496 VIXL_CHECK(*(simulator.GetCPUFeatures()) == base);
15497 }
15498 }
15499
TEST(configure_cpu_features_save_restore)15500 TEST(configure_cpu_features_save_restore) {
15501 RunHelperWithFeatureCombinations(SaveRestoreSimulatorCPUFeaturesHelper);
15502 }
15503
SimulationCPUFeaturesScopeHelper(const CPUFeatures & base,const CPUFeatures & f)15504 static void SimulationCPUFeaturesScopeHelper(const CPUFeatures& base,
15505 const CPUFeatures& f) {
15506 SETUP_WITH_FEATURES(base);
15507 START();
15508
15509 {
15510 SimulationCPUFeaturesScope scope_a(&masm, f);
15511 {
15512 SimulationCPUFeaturesScope scope_b(&masm, CPUFeatures::All());
15513 {
15514 SimulationCPUFeaturesScope scope_c(&masm, CPUFeatures::None());
15515 // The scope arguments should combine with 'Enable', so we should be
15516 // able to use any CPUFeatures here.
15517 __ Fadd(v0.V4S(), v1.V4S(), v2.V4S()); // Requires {FP, NEON}.
15518 }
15519 }
15520 }
15521
15522 END();
15523 if (CAN_RUN()) {
15524 RUN_WITHOUT_SEEN_FEATURE_CHECK();
15525 VIXL_CHECK(*(simulator.GetCPUFeatures()) == base);
15526 }
15527 }
15528
TEST(configure_cpu_features_scope)15529 TEST(configure_cpu_features_scope) {
15530 RunHelperWithFeatureCombinations(SimulationCPUFeaturesScopeHelper);
15531 }
15532 #endif
15533
15534
15535 #ifdef VIXL_INCLUDE_SIMULATOR_AARCH64
TEST(large_sim_stack)15536 TEST(large_sim_stack) {
15537 SimStack builder;
15538 builder.SetUsableSize(16 * 1024); // The default is 8kB.
15539 SimStack::Allocated stack = builder.Allocate();
15540 uintptr_t base = reinterpret_cast<uintptr_t>(stack.GetBase());
15541 uintptr_t limit = reinterpret_cast<uintptr_t>(stack.GetLimit());
15542 SETUP_CUSTOM_SIM(std::move(stack));
15543 START();
15544
15545 // Check that we can access the extremes of the stack.
15546 __ Mov(x0, base);
15547 __ Mov(x1, limit);
15548 __ Mov(x2, sp);
15549 __ Add(sp, x1, 1); // Avoid accessing memory below `sp`.
15550
15551 __ Mov(x10, 42);
15552 __ Poke(x10, 0);
15553 __ Peek(x10, base - limit - kXRegSizeInBytes - 1);
15554
15555 __ Mov(sp, x2);
15556
15557 END();
15558 if (CAN_RUN()) {
15559 RUN();
15560 }
15561 }
15562
15563 #ifdef VIXL_NEGATIVE_TESTING
TEST(sim_stack_limit_guard_read)15564 TEST(sim_stack_limit_guard_read) {
15565 SimStack builder;
15566 SimStack::Allocated stack = builder.Allocate();
15567 uintptr_t limit = reinterpret_cast<uintptr_t>(stack.GetLimit());
15568 SETUP_CUSTOM_SIM(std::move(stack));
15569 START();
15570
15571 __ Mov(x1, limit);
15572 __ Mov(x2, sp);
15573 __ Add(sp, x1, 1); // Avoid accessing memory below `sp`.
15574
15575 // `sp` points to the lowest usable byte of the stack.
15576 __ Mov(w10, 42);
15577 __ Ldrb(w10, MemOperand(sp, -1));
15578
15579 __ Mov(sp, x2);
15580
15581 END();
15582 if (CAN_RUN()) {
15583 MUST_FAIL_WITH_MESSAGE(RUN(), "Attempt to read from stack guard region");
15584 }
15585 }
15586
TEST(sim_stack_limit_guard_write)15587 TEST(sim_stack_limit_guard_write) {
15588 SimStack builder;
15589 SimStack::Allocated stack = builder.Allocate();
15590 uintptr_t limit = reinterpret_cast<uintptr_t>(stack.GetLimit());
15591 SETUP_CUSTOM_SIM(std::move(stack));
15592 START();
15593
15594 __ Mov(x1, limit);
15595 __ Mov(x2, sp);
15596 __ Add(sp, x1, 1); // Avoid accessing memory below `sp`.
15597
15598 // `sp` points to the lowest usable byte of the stack.
15599 __ Mov(w10, 42);
15600 __ Strb(w10, MemOperand(sp, -1));
15601
15602 __ Mov(sp, x2);
15603
15604 END();
15605 if (CAN_RUN()) {
15606 MUST_FAIL_WITH_MESSAGE(RUN(), "Attempt to write to stack guard region");
15607 }
15608 }
15609
TEST(sim_stack_base_guard_read)15610 TEST(sim_stack_base_guard_read) {
15611 SimStack builder;
15612 SimStack::Allocated stack = builder.Allocate();
15613 uintptr_t base = reinterpret_cast<uintptr_t>(stack.GetBase());
15614 SETUP_CUSTOM_SIM(std::move(stack));
15615 START();
15616
15617 __ Mov(x0, base);
15618 // `base` (x0) is the byte after the highest usable byte of the stack.
15619 // The last byte of this access will hit the guard region.
15620 __ Mov(x10, 42);
15621 __ Ldr(x10, MemOperand(x0, -static_cast<int64_t>(kXRegSizeInBytes) + 1));
15622
15623 END();
15624 if (CAN_RUN()) {
15625 MUST_FAIL_WITH_MESSAGE(RUN(), "Attempt to read from stack guard region");
15626 }
15627 }
15628
TEST(sim_stack_base_guard_write)15629 TEST(sim_stack_base_guard_write) {
15630 SimStack builder;
15631 SimStack::Allocated stack = builder.Allocate();
15632 uintptr_t base = reinterpret_cast<uintptr_t>(stack.GetBase());
15633 SETUP_CUSTOM_SIM(std::move(stack));
15634 START();
15635
15636 __ Mov(x0, base);
15637 // `base` (x0) is the byte after the highest usable byte of the stack.
15638 // The last byte of this access will hit the guard region.
15639 __ Mov(x10, 42);
15640 __ Str(x10, MemOperand(x0, -static_cast<int64_t>(kXRegSizeInBytes) + 1));
15641
15642 END();
15643 if (CAN_RUN()) {
15644 MUST_FAIL_WITH_MESSAGE(RUN(), "Attempt to write to stack guard region");
15645 }
15646 }
15647 #endif
15648 #endif
15649
TEST(scalar_movi)15650 TEST(scalar_movi) {
15651 SETUP_WITH_FEATURES(CPUFeatures::kFP, CPUFeatures::kNEON);
15652 START();
15653
15654 // Make sure that V0 is initialized to a non-zero value.
15655 __ Movi(v0.V16B(), 0xFF);
15656 // This constant value can't be encoded in a MOVI instruction,
15657 // so the program would use a fallback path that must set the
15658 // upper 64 bits of the destination vector to 0.
15659 __ Movi(v0.V1D(), 0xDECAFC0FFEE);
15660 __ Mov(x0, v0.V2D(), 1);
15661
15662 END();
15663
15664 if (CAN_RUN()) {
15665 RUN();
15666
15667 ASSERT_EQUAL_64(0, x0);
15668 }
15669 }
15670
15671 } // namespace aarch64
15672 } // namespace vixl
15673