1 // Copyright 2022 Google LLC
2 //
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree.
5
6 #include <xnnpack.h>
7 #include <xnnpack/aarch64-assembler.h>
8 #include <xnnpack/allocator.h>
9 #include <xnnpack/common.h>
10
11 #include "assembler-helpers.h"
12 #include <gtest/gtest.h>
13
14 namespace xnnpack {
15 namespace aarch64 {
16
TEST(AArch64Assembler,Initialization)17 TEST(AArch64Assembler, Initialization) {
18 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
19 xnn_code_buffer b;
20 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
21 Assembler a(&b);
22 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
23 }
24
TEST(AArch64Assembler,BaseInstructionEncoding)25 TEST(AArch64Assembler, BaseInstructionEncoding) {
26 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
27 xnn_code_buffer b;
28 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
29 Assembler a(&b);
30
31 CHECK_ENCODING(0x91008041, a.add(x1, x2, 32));
32 CHECK_ENCODING(0x913FFC41, a.add(x1, x2, 4095));
33 EXPECT_ERROR(Error::kInvalidOperand, a.add(x1, x2, 4096));
34
35 CHECK_ENCODING(0x8B040069, a.add(x9, x3, x4));
36
37 CHECK_ENCODING(0xF100081F, a.cmp(x0, 2));
38 EXPECT_ERROR(Error::kInvalidOperand, a.cmp(x0, 4096));
39
40 CHECK_ENCODING(0xEB0C02DF, a.cmp(x22, x12));
41
42 CHECK_ENCODING(0x9A8F322E, a.csel(x14, x17, x15, kLO));
43
44 CHECK_ENCODING(0xD4400000, a.hlt());
45
46 CHECK_ENCODING(0xA9403FEE, a.ldp(x14, x15, mem[sp]));
47 CHECK_ENCODING(0xA8C13FEE, a.ldp(x14, x15, mem[sp], 16));
48 CHECK_ENCODING(0xA9413FEE, a.ldp(x14, x15, mem[sp, 16]));
49 CHECK_ENCODING(0xA9603FEE, a.ldp(x14, x15, mem[sp, -512]));
50 CHECK_ENCODING(0xA95FBFEE, a.ldp(x14, x15, mem[sp, 504]));
51 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp], 15));
52 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp], -520));
53 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp], 512));
54 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(x14, x15, mem[sp, 16], 16));
55
56 CHECK_ENCODING(0xF9400BE8, a.ldr(x8, mem[sp, 16]));
57 CHECK_ENCODING(0xF97FFFE8, a.ldr(x8, mem[sp, 32760]));
58 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[sp, -8]));
59 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[sp, 7]));
60 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[sp, 32768]));
61 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, MemOperand(sp, 16, AddressingMode::kPostIndex)));
62
63 CHECK_ENCODING(0xF8408488, a.ldr(x8, mem[x4], 8));
64 CHECK_ENCODING(0xF84FF488, a.ldr(x8, mem[x4], 255));
65 CHECK_ENCODING(0xF8500488, a.ldr(x8, mem[x4], -256));
66 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[x4], 256));
67 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(x8, mem[x4], -257));
68
69 CHECK_ENCODING(0xAA0303E9, a.mov(x9, x3));
70
71 CHECK_ENCODING(0xD503201F, a.nop());
72
73 CHECK_ENCODING(0xF98000A0, a.prfm(kPLDL1KEEP, mem[x5]));
74 CHECK_ENCODING(0xF98020A0, a.prfm(kPLDL1KEEP, mem[x5, 64]));
75 EXPECT_ERROR(Error::kInvalidOperand, a.prfm(kPLDL1KEEP, mem[x5, -8]));
76 EXPECT_ERROR(Error::kInvalidOperand, a.prfm(kPLDL1KEEP, mem[x5, 32761]));
77
78 CHECK_ENCODING(0xD65F03C0, a.ret());
79
80 CHECK_ENCODING(0xCB020083, a.sub(x3, x4, x2));
81
82 CHECK_ENCODING(0xA90457F4, a.stp(x20, x21, mem[sp, 64]));
83 CHECK_ENCODING(0xA98457F4, a.stp(x20, x21, mem[sp, 64]++));
84 CHECK_ENCODING(0xA91FD7F4, a.stp(x20, x21, mem[sp, 504]));
85 CHECK_ENCODING(0xA92057F4, a.stp(x20, x21, mem[sp, -512]));
86 EXPECT_ERROR(Error::kInvalidOperand, a.stp(x20, x21, mem[sp, 3]));
87 EXPECT_ERROR(Error::kInvalidOperand, a.stp(x20, x21, mem[sp, 512]));
88 EXPECT_ERROR(Error::kInvalidOperand, a.stp(x20, x21, mem[sp, -520]));
89
90 CHECK_ENCODING(0xF80FFFF4, a.str(x20, mem[sp, 255]++));
91 CHECK_ENCODING(0xF81B0FF4, a.str(x20, mem[sp, -80]++));
92 CHECK_ENCODING(0xF8100FF4, a.str(x20, mem[sp, -256]++));
93 CHECK_ENCODING(0xF90003F4, a.str(x20, mem[sp, 0]));
94 CHECK_ENCODING(0xF93FFFF4, a.str(x20, mem[sp, 32760]));
95 EXPECT_ERROR(Error::kInvalidOperand, a.str(sp, mem[sp, -257]++));
96 EXPECT_ERROR(Error::kInvalidOperand, a.str(sp, mem[sp, 256]++));
97 EXPECT_ERROR(Error::kInvalidOperand, a.str(sp, mem[sp, 3]));
98 EXPECT_ERROR(Error::kInvalidOperand, a.str(sp, mem[sp, -1]));
99 EXPECT_ERROR(Error::kInvalidOperand, a.str(sp, mem[sp, 32768]));
100
101 CHECK_ENCODING(0xF1008040, a.subs(x0, x2, 32));
102 CHECK_ENCODING(0xF13FFC40, a.subs(x0, x2, 4095));
103 EXPECT_ERROR(Error::kInvalidOperand, a.subs(x0, x2, -32));
104 EXPECT_ERROR(Error::kInvalidOperand, a.subs(x0, x2, 4096));
105
106 CHECK_ENCODING(0xF240043F, a.tst(x1, 3));
107 CHECK_ENCODING(0xF2400C3F, a.tst(x1, 15));
108 CHECK_ENCODING(0xF240103F, a.tst(x1, 31));
109 EXPECT_ERROR(Error::kUnimplemented, a.tst(x1, 32));
110
111 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
112 }
113
TEST(AArch64Assembler,SIMDInstructionEncoding)114 TEST(AArch64Assembler, SIMDInstructionEncoding) {
115 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
116 xnn_code_buffer b;
117 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
118 Assembler a(&b);
119
120 CHECK_ENCODING(0x5E180610, a.dup(d16, v16.d()[1]));
121 EXPECT_ERROR(Error::kInvalidOperand, a.dup(d16, v16.d()[2]));
122 EXPECT_ERROR(Error::kInvalidOperand, a.dup(d16, v16.s()[1]));
123
124 CHECK_ENCODING(0x4EA0F8B0, a.fabs(v16.v4s(), v5.v4s()));
125 EXPECT_ERROR(Error::kInvalidOperand, a.fabs(v16.v4s(), v5.v2s()));
126
127 CHECK_ENCODING(0x4E25D690, a.fadd(v16.v4s(), v20.v4s(), v5.v4s()));
128 EXPECT_ERROR(Error::kInvalidOperand, a.fadd(v16.v4s(), v20.v4s(), v5.v2s()));
129
130 CHECK_ENCODING(0x4E30F7E3, a.fmax(v3.v4s(), v31.v4s(), v16.v4s()));
131 EXPECT_ERROR(Error::kInvalidOperand, a.fmax(v3.v8h(), v31.v4s(), v16.v4s()));
132
133 CHECK_ENCODING(0x4EB1F7C2, a.fmin(v2.v4s(), v30.v4s(), v17.v4s()));
134 EXPECT_ERROR(Error::kInvalidOperand, a.fmin(v2.v4s(), v30.v16b(), v17.v4s()));
135
136 CHECK_ENCODING(0x4F801290, a.fmla(v16.v4s(), v20.v4s(), v0.s()[0]));
137 EXPECT_ERROR(Error::kInvalidOperand, a.fmla(v16.v4s(), v20.v2s(), v0.s()[0]));
138 EXPECT_ERROR(Error::kInvalidOperand, a.fmla(v16.v2d(), v20.v2d(), v0.s()[0]));
139 EXPECT_ERROR(Error::kInvalidLaneIndex, a.fmla(v16.v4s(), v20.v4s(), v0.s()[4]));
140
141 CHECK_ENCODING(0x6E29DC61, a.fmul(v1.v4s(), v3.v4s(), v9.v4s()));
142 EXPECT_ERROR(Error::kInvalidOperand, a.fmul(v16.v4s(), v20.v4s(), v5.v2s()));
143
144 CHECK_ENCODING(0x6EA0FBC2, a.fneg(v2.v4s(), v30.v4s()));
145 EXPECT_ERROR(Error::kInvalidOperand, a.fneg(v2.v4s(), v30.v16b()));
146
147 CHECK_ENCODING(0x0CDF7060, a.ld1({v0.v8b()}, mem[x3], 8));
148 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v8b()}, mem[x3], 16));
149 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v16b()}, mem[x3], 8));
150
151 CHECK_ENCODING(0x0CDFA060, a.ld1({v0.v8b(), v1.v8b()}, mem[x3], 16));
152 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v8b(), v1.v8b()}, mem[x3], 32));
153 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v16b(), v1.v16b()}, mem[x3], 16));
154 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v0.v8b(), v2.v8b()}, mem[x3], 16));
155
156 CHECK_ENCODING(0x4CDF61F0, a.ld1({v16.v16b(), v17.v16b(), v18.v16b()}, mem[x15], 48));
157 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v8b(), v17.v16b(), v18.v16b()}, mem[x15], 48));
158 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v16b(), v17.v16b(), v18.v8b()}, mem[x15], 48));
159 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v16b(), v17.v16b(), v18.v16b()}, mem[x15], 24));
160 EXPECT_ERROR(Error::kInvalidOperand, a.ld1({v16.v8b(), v17.v8b(), v18.v8b()}, mem[x15], 48));
161
162 CHECK_ENCODING(0x6D433FEE, a.ldp(d14, d15, mem[sp, 48]));
163 CHECK_ENCODING(0x6DC33FEE, a.ldp(d14, d15, mem[sp, 48]++));
164 CHECK_ENCODING(0x6CC427E8, a.ldp(d8, d9, mem[sp], 64));
165 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(d14, d15, mem[sp, 7]));
166
167 CHECK_ENCODING(0xACC154B4, a.ldp(q20, q21, mem[x5], 32));
168 CHECK_ENCODING(0xACE054B4, a.ldp(q20, q21, mem[x5], -1024));
169 CHECK_ENCODING(0xACDFD4B4, a.ldp(q20, q21, mem[x5], 1008));
170 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(q20, q21, mem[x5], 15));
171 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(q20, q21, mem[x5], -1040));
172 EXPECT_ERROR(Error::kInvalidOperand, a.ldp(q20, q21, mem[x5], 1024));
173
174 CHECK_ENCODING(0xFC408460, a.ldr(d0, mem[x3], 8));
175 CHECK_ENCODING(0xBC404460, a.ldr(s0, mem[x3], 4));
176
177 CHECK_ENCODING(0x3CC10460, a.ldr(q0, mem[x3], 16));
178 CHECK_ENCODING(0x3CCFF460, a.ldr(q0, mem[x3], 255));
179 CHECK_ENCODING(0x3CD00460, a.ldr(q0, mem[x3], -256));
180 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(q0, mem[x3], -257));
181 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(q0, mem[x3], 256));
182 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(q0, mem[x3, 16], 16));
183
184 CHECK_ENCODING(0x4D40C904, a.ld1r({v4.v4s()}, mem[x8]));
185 EXPECT_ERROR(Error::kInvalidOperand, a.ld1r({v4.v4s(), v5.v4s()}, mem[x8]));
186 EXPECT_ERROR(Error::kInvalidOperand, a.ld1r({v4.v4s()}, mem[x8, 16]));
187
188 CHECK_ENCODING(0x4D60C902, a.ld2r({v2.v4s(), v3.v4s()}, mem[x8]));
189 EXPECT_ERROR(Error::kInvalidOperand, a.ld2r({v2.v4s(), v3.v4s()}, mem[x8, 16]));
190 EXPECT_ERROR(Error::kInvalidOperand, a.ld2r({v2.v4s(), v4.v4s()}, mem[x8]));
191 EXPECT_ERROR(Error::kInvalidOperand, a.ld2r({v2.v4s(), v3.v8b()}, mem[x8]));
192
193 CHECK_ENCODING(0x4D40E906, a.ld3r({v6.v4s(), v7.v4s(), v8.v4s()}, mem[x8]));
194 EXPECT_ERROR(Error::kInvalidOperand, a.ld3r({v6.v4s(), v7.v4s(), v8.v4s()}, mem[x8, 16]));
195 EXPECT_ERROR(Error::kInvalidOperand, a.ld3r({v6.v4s(), v7.v4s(), v9.v4s()}, mem[x8]));
196 EXPECT_ERROR(Error::kInvalidOperand, a.ld3r({v6.v4s(), v7.v2s(), v8.v4s()}, mem[x8]));
197
198 CHECK_ENCODING(0x4EB21E50, a.mov(v16.v16b(), v18.v16b()));
199 CHECK_ENCODING(0x0EB21E50, a.mov(v16.v8b(), v18.v8b()));
200 EXPECT_ERROR(Error::kInvalidOperand, a.mov(v16.v16b(), v18.v8b()));
201
202 CHECK_ENCODING(0x4F000405, a.movi(v5.v4s(), 0));
203 CHECK_ENCODING(0x4F008405, a.movi(v5.v8h(), 0));
204 CHECK_ENCODING(0x4F00E405, a.movi(v5.v16b(), 0));
205 EXPECT_ERROR(Error::kUnimplemented, a.movi(v5.v16b(), 0xFF));
206
207 CHECK_ENCODING(0x4C82746F, a.st1({v15.v8h()}, mem[x3], x2));
208
209 CHECK_ENCODING(0x4C95AA8F, a.st1({v15.v4s(), v16.v4s()}, mem[x20], x21));
210 EXPECT_ERROR(Error::kInvalidOperand, a.st1({v15.v4s(), v17.v4s()}, mem[x20], x21));
211 EXPECT_ERROR(Error::kInvalidOperand, a.st1({v15.v4s(), v16.v8h()}, mem[x20], x21));
212
213 CHECK_ENCODING(0x4C8E60D0, a.st1({v16.v16b(), v17.v16b(), v18.v16b() }, mem[x6], x14));
214 EXPECT_ERROR(Error::kInvalidOperand, a.st1({v15.v16b(), v17.v16b(), v18.v16b()}, mem[x6], x14));
215 EXPECT_ERROR(Error::kInvalidOperand, a.st1({v16.v16b(), v17.v16b(), v18.v4s()}, mem[x6], x14));
216
217 CHECK_ENCODING(0x4C812FB4, a.st1({v20.v2d(), v21.v2d(), v22.v2d(), v23.v2d()}, mem[x29], x1));
218 EXPECT_ERROR(Error::kInvalidOperand, a.st1({v20.v2d(), v21.v2d(), v22.v2d(), v23.v2s()}, mem[x29], x1));
219 EXPECT_ERROR(Error::kInvalidOperand, a.st1({v20.v2d(), v21.v2d(), v22.v2d(), v27.v2d()}, mem[x29], x1));
220
221 CHECK_ENCODING(0x6D012FEA, a.stp(d10, d11, mem[sp, 16]));
222 CHECK_ENCODING(0x6D202FEA, a.stp(d10, d11, mem[sp, -512]));
223 CHECK_ENCODING(0x6D1FAFEA, a.stp(d10, d11, mem[sp, 504]));
224 EXPECT_ERROR(Error::kInvalidOperand, a.stp(d10, d11, mem[sp, -520]));
225 EXPECT_ERROR(Error::kInvalidOperand, a.stp(d10, d11, mem[sp, 512]));
226
227 CHECK_ENCODING(0x6D812FEA, a.stp(d10, d11, mem[sp, 16]++));
228
229 CHECK_ENCODING(0xAD0075BC, a.stp(q28, q29, mem[x13]));
230 CHECK_ENCODING(0xAD80F5BC, a.stp(q28, q29, mem[x13, 16]++));
231 EXPECT_ERROR(Error::kInvalidOperand, a.stp(q28, q28, mem[x13, 7]));
232
233 CHECK_ENCODING(0xAC8144D0, a.stp(q16, q17, mem[x6], 32));
234 CHECK_ENCODING(0xAC9FC4D0, a.stp(q16, q17, mem[x6], 1008));
235 CHECK_ENCODING(0xACA044D0, a.stp(q16, q17, mem[x6], -1024));
236 EXPECT_ERROR(Error::kInvalidOperand, a.stp(q16, q17, mem[x6], 34));
237 EXPECT_ERROR(Error::kInvalidOperand, a.stp(q16, q17, mem[x6], 1024));
238 EXPECT_ERROR(Error::kInvalidOperand, a.stp(q16, q17, mem[x6], -1040));
239
240 CHECK_ENCODING(0xFC0084D0, a.str(d16, mem[x6], 8));
241 CHECK_ENCODING(0x3C8104D0, a.str(q16, mem[x6], 16));
242 CHECK_ENCODING(0x3C8FF4D0, a.str(q16, mem[x6], 255));
243 CHECK_ENCODING(0x3C9004D0, a.str(q16, mem[x6], -256));
244 EXPECT_ERROR(Error::kInvalidOperand, a.str(q16, mem[x6], 256));
245 EXPECT_ERROR(Error::kInvalidOperand, a.str(q16, mem[x6], -257));
246
247 CHECK_ENCODING(0xBD0000D0, a.str(s16, mem[x6]));
248 CHECK_ENCODING(0xBD3FFCD0, a.str(s16, mem[x6, 16380]));
249 EXPECT_ERROR(Error::kInvalidOperand, a.str(s16, mem[x6, 3]));
250 EXPECT_ERROR(Error::kInvalidOperand, a.str(s16, mem[x6, -4]));
251 EXPECT_ERROR(Error::kInvalidOperand, a.str(s16, mem[x6, 16384]));
252
253 CHECK_ENCODING(0xBC0044D0, a.str(s16, mem[x6], 4));
254 CHECK_ENCODING(0xBC0FF4D0, a.str(s16, mem[x6], 255));
255 CHECK_ENCODING(0xBC1004D0, a.str(s16, mem[x6], -256));
256 EXPECT_ERROR(Error::kInvalidOperand, a.str(s16, mem[x6], 256));
257 EXPECT_ERROR(Error::kInvalidOperand, a.str(s16, mem[x6], -257));
258
259 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
260 }
261
TEST(AArch64Assembler,Label)262 TEST(AArch64Assembler, Label) {
263 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
264 xnn_code_buffer b;
265 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
266 Assembler a(&b);
267
268 Label l1;
269 a.movi(v0.v4s(), 0);
270
271 // Branch to unbound label.
272 auto b1 = a.offset<uint32_t*>();
273 a.b_eq(l1);
274
275 a.movi(v1.v4s(), 0);
276
277 auto b2 = a.offset<uint32_t*>();
278 a.b_ne(l1);
279
280 a.movi(v2.v4s(), 0);
281
282 a.bind(l1);
283
284 // Check that b1 and b2 are both patched after binding l1.
285 EXPECT_INSTR(0x54000080, *b1);
286 EXPECT_INSTR(0x54000041, *b2);
287
288 a.movi(v3, 0);
289
290 // Branch to bound label.
291 auto b3 = a.offset<uint32_t*>();
292 a.b_hi(l1);
293 auto b4 = a.offset<uint32_t*>();
294 a.b_hs(l1);
295 auto b5 = a.offset<uint32_t*>();
296 a.b_lo(l1);
297
298 EXPECT_INSTR(0x54FFFFE8, *b3);
299 EXPECT_INSTR(0x54FFFFC2, *b4);
300 EXPECT_INSTR(0x54FFFFA3, *b5);
301
302 // Binding a bound label is an error.
303 a.bind(l1);
304 EXPECT_ERROR(Error::kLabelAlreadyBound, a.bind(l1));
305
306 // Check for bind failure due to too many users of label.
307 Label lfail;
308 a.reset();
309 // Arbitrary high number of users that we probably won't support.
310 for (int i = 0; i < 1000; i++) {
311 a.b_eq(lfail);
312 }
313 EXPECT_EQ(Error::kLabelHasTooManyUsers, a.error());
314
315 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
316 }
317
TEST(AArch64Assembler,Tbnz)318 TEST(AArch64Assembler, Tbnz) {
319 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
320 xnn_code_buffer b;
321 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
322 Assembler a(&b);
323
324 Label l1;
325 a.movi(v0.v4s(), 0);
326
327 // Branch to unbound label.
328 auto b1 = a.offset<uint32_t*>();
329 a.tbnz(x0, 4, l1);
330
331 a.movi(v1.v4s(), 0);
332 a.bind(l1);
333
334 EXPECT_INSTR(0x37200040, *b1);
335
336 a.movi(v2.v4s(), 0);
337
338 // Branch to bound label.
339 auto b2 = a.offset<uint32_t*>();
340 a.tbnz(x1, 6, l1);
341
342 EXPECT_INSTR(0x3737FFE1, *b2);
343
344 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
345 }
346
TEST(AArch64Assembler,Tbz)347 TEST(AArch64Assembler, Tbz) {
348 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
349 xnn_code_buffer b;
350 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
351 Assembler a(&b);
352
353 Label l1;
354 a.movi(v0.v4s(), 0);
355
356 // Branch to unbound label.
357 auto b1 = a.offset<uint32_t*>();
358 a.tbz(x0, 4, l1);
359
360 a.movi(v1.v4s(), 0);
361 a.bind(l1);
362
363 EXPECT_INSTR(0x36200040, *b1);
364
365 a.movi(v2.v4s(), 0);
366
367 // Branch to bound label.
368 auto b2 = a.offset<uint32_t*>();
369 a.tbz(x1, 6, l1);
370
371 EXPECT_INSTR(0x3637FFE1, *b2);
372
373 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
374 }
375
TEST(AArch64Assembler,UnconditionalBranch)376 TEST(AArch64Assembler, UnconditionalBranch) {
377 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
378 xnn_code_buffer b;
379 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
380 Assembler a(&b);
381
382 Label l1;
383 a.movi(v0.v4s(), 0);
384
385 // Branch to unbound label.
386 auto b1 = a.offset<uint32_t*>();
387 a.b(l1);
388
389 a.movi(v1.v4s(), 0);
390 a.bind(l1);
391
392 EXPECT_INSTR(0x14000002, *b1);
393
394 a.movi(v2.v4s(), 0);
395
396 // Branch to bound label.
397 auto b2 = a.offset<uint32_t*>();
398 a.b(l1);
399
400 EXPECT_INSTR(0x17FFFFFF, *b2);
401
402 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
403 }
404
TEST(AArch64Assembler,Align)405 TEST(AArch64Assembler, Align) {
406 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
407 xnn_code_buffer b;
408 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
409 Assembler a(&b);
410
411 a.add(x0, x1, x2);
412 a.align(4);
413 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset<uint32_t*>()) & 0x3);
414 EXPECT_EQ(4, a.code_size_in_bytes());
415
416 a.align(8);
417 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset<uint32_t*>()) & 0x7);
418 EXPECT_EQ(8, a.code_size_in_bytes());
419
420 a.add(x0, x1, x2);
421 a.align(8);
422 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset<uint32_t*>()) & 0x7);
423 EXPECT_EQ(16, a.code_size_in_bytes());
424
425 a.add(x0, x1, x2);
426 EXPECT_EQ(20, a.code_size_in_bytes());
427
428 a.align(16);
429 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset<uint32_t*>()) & 0xF);
430 EXPECT_EQ(32, a.code_size_in_bytes());
431
432 a.add(x0, x1, x2);
433 a.add(x0, x1, x2);
434 EXPECT_EQ(40, a.code_size_in_bytes());
435
436 a.align(16);
437 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset<uint32_t*>()) & 0xF);
438 EXPECT_EQ(48, a.code_size_in_bytes());
439
440 // Not power-of-two.
441 EXPECT_ERROR(Error::kInvalidOperand, a.align(6));
442 // Is power-of-two but is not a multiple of instruction size.
443 EXPECT_ERROR(Error::kInvalidOperand, a.align(2));
444
445 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
446 }
447
TEST(AArch64Assembler,AssembleToEndOfBuffer)448 TEST(AArch64Assembler, AssembleToEndOfBuffer) {
449 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
450 xnn_code_buffer b;
451 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
452
453 Assembler a1(&b);
454 a1.emit32(1);
455 a1.finalize();
456
457 // Different assembler, but same code buffer.
458 Assembler a2(&b);
459 a2.emit32(2);
460 a2.finalize();
461
462 // Check that we wrote to end of buffer and did not overwrite.
463 uint32_t* p = (uint32_t*) b.start;
464 ASSERT_EQ(1, *p);
465 ASSERT_EQ(2, *(p+1));
466
467 ASSERT_EQ(8, b.size);
468
469 a2.reset();
470
471 ASSERT_EQ(4, b.size);
472 ASSERT_EQ((byte*)b.start + 4, a2.offset());
473
474 a2.emit32(3);
475 ASSERT_EQ(3, *(p+1));
476
477 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
478 }
479
TEST(AArch64Assembler,FinalizeWithError)480 TEST(AArch64Assembler, FinalizeWithError) {
481 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
482 xnn_code_buffer b;
483 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
484
485 Assembler a(&b);
486 // Write a valid instruction.
487 a.add(x1, x2, 32);
488 // Then write an invalid instruction.
489 a.ldp(x14, x15, mem[sp], 15);
490 // Since we have an error, size should not be updated.
491 a.finalize();
492 ASSERT_EQ(0, b.size);
493
494 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
495 }
496
TEST(AArch64Assembler,BindOverflow)497 TEST(AArch64Assembler, BindOverflow) {
498 ASSERT_EQ(xnn_status_success, xnn_initialize(/*allocator=*/nullptr));
499 xnn_code_buffer b;
500 // Requested memory is rounded to page size.
501 xnn_allocate_code_memory(&b, 4);
502 Assembler a(&b);
503 Label l1;
504 for (int i = 0; i < b.capacity; i += 1 << kInstructionSizeInBytesLog2) {
505 a.add(x0, x0, 2);
506 }
507 EXPECT_EQ(Error::kNoError, a.error());
508
509 // This is out of bounds, not written.
510 a.tbz(x1, 1, l1);
511 EXPECT_EQ(Error::kOutOfMemory, a.error());
512
513 a.bind(l1);
514 ASSERT_EQ(false, l1.bound);
515
516 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
517 }
518
519 } // namespace aarch64
520 } // namespace xnnpack
521