• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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