blob: 76e073c669191a2fdbeab02b1d9bac6fbbfb1a44 [file] [log] [blame]
Zhi An Ngec17e992021-12-16 13:06:37 -08001// Copyright 2021 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
Zhi An Ngb559fe92021-12-06 09:25:38 -08006#include <xnnpack/aarch32-assembler.h>
Zhi An Ng6883abb2021-12-14 10:13:18 -08007#include <xnnpack/allocator.h>
8#include <xnnpack/common.h>
Zhi An Ngb559fe92021-12-06 09:25:38 -08009
Zhi An Ngd221c542021-12-07 15:55:22 -080010#include <ios>
11
Zhi An Ngb559fe92021-12-06 09:25:38 -080012#include <gtest/gtest.h>
13
Zhi An Ng737ad012021-12-08 16:42:44 -080014// clang-format off
15#define EXPECT_INSTR(expected, actual) \
16 EXPECT_EQ(expected, actual) << "expected = 0x" << std::hex << std::setw(8) << std::setfill('0') << expected \
17 << std::endl << " actual = 0x" << actual;
18// clang-format on
Zhi An Ng65584bd2021-12-08 09:30:10 -080019
20#define CHECK_ENCODING(expected, call) \
21 a.reset(); \
22 call; \
23 EXPECT_INSTR(expected, *a.start())
Zhi An Ngb559fe92021-12-06 09:25:38 -080024
Zhi An Ng512d44b2021-12-06 11:42:55 -080025#define EXPECT_ERROR(expected, call) \
26 a.reset(); \
27 call; \
28 EXPECT_EQ(expected, a.error());
29
Zhi An Ngb559fe92021-12-06 09:25:38 -080030namespace xnnpack {
31namespace aarch32 {
Zhi An Ng512d44b2021-12-06 11:42:55 -080032TEST(AArch32Assembler, InstructionEncoding) {
Zhi An Ng6883abb2021-12-14 10:13:18 -080033 xnn_code_buffer b;
34 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
35 Assembler a(&b);
Zhi An Ng512d44b2021-12-06 11:42:55 -080036
Zhi An Ng65584bd2021-12-08 09:30:10 -080037 CHECK_ENCODING(0xE0810002, a.add(r0, r1, r2));
Zhi An Ngf73e55b2021-12-09 10:04:38 -080038 CHECK_ENCODING(0xE28A9080, a.add(r9, r10, 128));
Zhi An Ng512d44b2021-12-06 11:42:55 -080039
Zhi An Ng10475ec2021-12-09 14:52:46 -080040 CHECK_ENCODING(0xE12FFF1E, a.bx(lr));
41
Zhi An Ng65584bd2021-12-08 09:30:10 -080042 CHECK_ENCODING(0xE3500002, a.cmp(r0, 2));
Zhi An Ng663b4fe2021-12-07 14:34:54 -080043
Zhi An Ngc9ffad72021-12-07 14:28:21 -080044 // Offset addressing mode.
Zhi An Ng65584bd2021-12-08 09:30:10 -080045 CHECK_ENCODING(0xE59D7060, a.ldr(r7, mem[sp, 96]));
Zhi An Ngc9ffad72021-12-07 14:28:21 -080046 // Post-indexed addressing mode.
Zhi An Ng65584bd2021-12-08 09:30:10 -080047 CHECK_ENCODING(0xE490B000, a.ldr(r11, mem[r0], 0));
48 CHECK_ENCODING(0xE490B060, a.ldr(r11, mem[r0], 96));
Zhi An Ngc9ffad72021-12-07 14:28:21 -080049 // Offsets out of bounds.
50 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(r7, MemOperand(sp, 4096)));
51 EXPECT_ERROR(Error::kInvalidOperand, a.ldr(r7, MemOperand(sp, -4096)));
52
Zhi An Ng65584bd2021-12-08 09:30:10 -080053 CHECK_ENCODING(0x31A0C003, a.movlo(r12, r3));
54 CHECK_ENCODING(0x91A0A00C, a.movls(r10, r12));
55 CHECK_ENCODING(0xE1A0A00C, a.mov(r10, r12));
Zhi An Ngff2e8b22021-12-07 15:18:33 -080056
Zhi An Ngbe4e6a52021-12-16 15:09:27 -080057 CHECK_ENCODING(0xE320F000, a.nop());
58
Zhi An Ng16f35482021-12-09 14:32:31 -080059 CHECK_ENCODING(0xE8BD0FF0, a.pop({r4, r5, r6, r7, r8, r9, r10, r11}));
60 EXPECT_ERROR(Error::kInvalidOperand, a.pop({}));
61 EXPECT_ERROR(Error::kInvalidOperand, a.pop({r1}));
62
Zhi An Ng65584bd2021-12-08 09:30:10 -080063 CHECK_ENCODING(0xE92D0FF0, a.push({r4, r5, r6, r7, r8, r9, r10, r11}));
Zhi An Ng512d44b2021-12-06 11:42:55 -080064 EXPECT_ERROR(Error::kInvalidOperand, a.push({}));
65 EXPECT_ERROR(Error::kInvalidOperand, a.push({r1}));
Zhi An Ng4ab7b932021-12-07 15:20:54 -080066
Zhi An Ng65584bd2021-12-08 09:30:10 -080067 CHECK_ENCODING(0xF5D3F000, a.pld(MemOperand(r3, 0)));
68 CHECK_ENCODING(0xF5D3F040, a.pld(MemOperand(r3, 64)));
Zhi An Ng591b9172021-12-07 15:38:52 -080069
Zhi An Ng65584bd2021-12-08 09:30:10 -080070 CHECK_ENCODING(0xE0487002, a.sub(r7, r8, r2));
71 CHECK_ENCODING(0xE2525010, a.subs(r5, r2, 16));
Zhi An Ng68c27d32021-12-08 10:58:34 -080072
Zhi An Ng2fce75b2021-12-09 10:40:16 -080073 CHECK_ENCODING(0xE315000F, a.tst(r5, 15));
74
Zhi An Ng4a585832021-12-14 16:46:25 -080075 CHECK_ENCODING(0xF3FF8C4F, a.vdup_8(q12, d15[7]));
76 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vdup_8(q12, d15[8]));
77 CHECK_ENCODING(0xF3FE8C4F, a.vdup_16(q12, d15[3]));
78 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vdup_16(q12, d15[4]));
79 CHECK_ENCODING(0xF3FC8C4F, a.vdup_32(q12, d15[1]));
80 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vdup_32(q12, d15[2]));
81
Zhi An Ng6fac7192021-12-14 16:48:22 -080082 CHECK_ENCODING(0xF2BE04C6, a.vext_8(q0, q15, q3, 4));
83 EXPECT_ERROR(Error::kInvalidOperand, a.vext_8(q0, q15, q3, 16));
84
Zhi An Nga38a1612021-12-14 12:07:06 -080085 CHECK_ENCODING(0xF423070F, a.vld1_8({d0}, mem[r3]));
86 CHECK_ENCODING(0xF423070D, a.vld1_8({d0}, mem[r3]++));
87
Zhi An Ngdfe89292021-12-08 16:48:48 -080088 CHECK_ENCODING(0xF42C178F, a.vld1_32({d1}, mem[r12]));
89 CHECK_ENCODING(0xF42C178D, a.vld1_32({d1}, mem[r12]++));
90
91 CHECK_ENCODING(0xF4A54CAF, a.vld1r_32({d4, d5}, mem[r5]));
92 CHECK_ENCODING(0xF4A54CAD, a.vld1r_32({d4, d5}, mem[r5]++));
93
Zhi An Ng637becf2021-12-08 13:16:59 -080094 CHECK_ENCODING(0xECF90B08, a.vldm(r9, {d16, d19}, true));
95 CHECK_ENCODING(0xEC998B08, a.vldm(r9, {d8, d11}, false));
96 CHECK_ENCODING(0xEC998B08, a.vldm(r9, {d8, d11}));
97 CHECK_ENCODING(0xECB30A01, a.vldm(r3, {s0}, true));
98 CHECK_ENCODING(0xEC930A01, a.vldm(r3, {s0}));
99
Zhi An Ng477bdbb2021-12-08 13:33:39 -0800100 CHECK_ENCODING(0xED99FB0E, a.vldr(d15, mem[r9, 56]));
Zhi An Ng737ad012021-12-08 16:42:44 -0800101 EXPECT_ERROR(Error::kInvalidOperand, a.vldr(d15, MemOperand(r9, 56, AddressingMode::kPostIndexed)));
Zhi An Ng477bdbb2021-12-08 13:33:39 -0800102 EXPECT_ERROR(Error::kInvalidOperand, a.vldr(d15, mem[r9, 256]));
103
Zhi An Ng26490142021-12-14 16:02:12 -0800104 CHECK_ENCODING(0xF20E26C6, a.vmax_s8(q1, q15, q3));
Zhi An Ngea612bc2021-12-09 10:42:50 -0800105 CHECK_ENCODING(0xF24ECFC4, a.vmax_f32(q14, q15, q2));
106
Zhi An Ng26490142021-12-14 16:02:12 -0800107 CHECK_ENCODING(0xF20E26D6, a.vmin_s8(q1, q15, q3));
Zhi An Ngea612bc2021-12-09 10:42:50 -0800108 CHECK_ENCODING(0xF220EFC6, a.vmin_f32(q7, q8, q3));
109
Zhi An Ngc9f70f72021-12-09 09:33:17 -0800110 CHECK_ENCODING(0xF3E80140, a.vmla_f32(q8, q4, d0[0]));
111 CHECK_ENCODING(0xF3EC0160, a.vmla_f32(q8, q6, d0[1]));
112 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vmla_f32(q8, q4, d0[2]));
113
Zhi An Nga38a1612021-12-14 12:07:06 -0800114 CHECK_ENCODING(0xF2D9E246, a.vmlal_s16(q15, d9, d6[0]));
115 CHECK_ENCODING(0xF2D8424A, a.vmlal_s16(q10, d8, d2[1]));
116 CHECK_ENCODING(0xF2D88264, a.vmlal_s16(q12, d8, d4[2]));
117 CHECK_ENCODING(0xF2D8626A, a.vmlal_s16(q11, d8, d2[3]));
118 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vmlal_s16(q15, d9, d6[4]));
119
Zhi An Ngf4beaf12021-12-08 13:27:29 -0800120 CHECK_ENCODING(0xEEB0EA4F, a.vmov(s28, s30));
121 CHECK_ENCODING(0xF26101B1, a.vmov(d16, d17));
122 CHECK_ENCODING(0xEC420B1F, a.vmov(d15, r0, r2));
123 CHECK_ENCODING(0xF26041F0, a.vmov(q10, q8));
124
Zhi An Nga38a1612021-12-14 12:07:06 -0800125 CHECK_ENCODING(0xF2880A10, a.vmovl_s8(q0, d0));
126
Zhi An Ng16f35482021-12-09 14:32:31 -0800127 CHECK_ENCODING(0xECBD8B10, a.vpop({d8, d15}));
128
Zhi An Ng68c27d32021-12-08 10:58:34 -0800129 CHECK_ENCODING(0xED2D4A08, a.vpush({s8, s15}));
130 CHECK_ENCODING(0xED2DAA04, a.vpush({s20, s23}));
131 CHECK_ENCODING(0xED2D8B10, a.vpush({d8, d15}));
132 CHECK_ENCODING(0xED6D4B08, a.vpush({d20, d23}));
Zhi An Ngfe4a7502021-12-09 14:21:57 -0800133
Zhi An Ng26490142021-12-14 16:02:12 -0800134 CHECK_ENCODING(0xF25E00D2, a.vqadd_s16(q8, q15, q1));
135
136 CHECK_ENCODING(0xF3A82CCE, a.vqdmulh_s32(q1, q12, d14[0]));
137 CHECK_ENCODING(0xF3A82CEE, a.vqdmulh_s32(q1, q12, d14[1]));
138 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vqdmulh_s32(q1, q12, d14[2]));
139 EXPECT_ERROR(Error::kInvalidOperand, a.vqdmulh_s32(q1, q12, d16[0]));
140
Zhi An Ng6fac7192021-12-14 16:48:22 -0800141 CHECK_ENCODING(0xF3F602A0, a.vqmovn_s32(d16, q8));
142
Zhi An Ng26490142021-12-14 16:02:12 -0800143 CHECK_ENCODING(0xF22C247E, a.vqshl_s32(q1, q15, q6));
144
145 CHECK_ENCODING(0xF264C560, a.vrshl_s32(q14, q8, q2));
146
Zhi An Ng4ef8d512021-12-14 15:47:53 -0800147 CHECK_ENCODING(0xF40B070F, a.vst1_8({d0}, mem[r11]));
148 CHECK_ENCODING(0xF40B070D, a.vst1_8({d0}, mem[r11]++));
Zhi An Ng00a929f2021-12-14 15:07:34 -0800149 CHECK_ENCODING(0xF40B0707, a.vst1_8({d0}, mem[r11], r7));
150 CHECK_ENCODING(0xF48B000F, a.vst1_8({d0[0]}, mem[r11]));
151 CHECK_ENCODING(0xF48B00EF, a.vst1_8({d0[7]}, mem[r11]));
152 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vst1_8(d0[8], mem[r11]));
153
Zhi An Ng4ef8d512021-12-14 15:47:53 -0800154 CHECK_ENCODING(0xF40B074F, a.vst1_16({d0}, mem[r11]));
155 CHECK_ENCODING(0xF40B074D, a.vst1_16({d0}, mem[r11]++));
156 CHECK_ENCODING(0xF40B0747, a.vst1_16({d0}, mem[r11], r7));
157 CHECK_ENCODING(0xF48B040F, a.vst1_16({d0[0]}, mem[r11]));
158 CHECK_ENCODING(0xF48B04CF, a.vst1_16({d0[3]}, mem[r11]));
159 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vst1_16(d0[4], mem[r11]));
160
Zhi An Ngfe4a7502021-12-09 14:21:57 -0800161 CHECK_ENCODING(0xF44B0280, a.vst1_32({d16, d19}, mem[r11], r0));
162 EXPECT_ERROR(Error::kInvalidRegisterListLength, a.vst1_32({d0, d4}, mem[r11], r0));
163 EXPECT_ERROR(Error::kInvalidOperand, a.vst1_32({d16, d19}, mem[r11], sp));
164 EXPECT_ERROR(Error::kInvalidOperand, a.vst1_32({d16, d19}, mem[r11], pc));
165 CHECK_ENCODING(0xF404168F, a.vst1_32({d1, d3}, mem[r4]));
166 CHECK_ENCODING(0xF44B0A8D, a.vst1_32({d16, d17}, mem[r11]++));
167 CHECK_ENCODING(0xF4CB080F, a.vst1_32({d16[0]}, mem[r11]));
168 // The surrounding braces are optional, but makes it look closer to native assembly.
169 CHECK_ENCODING(0xF4CB080F, a.vst1_32(d16[0], mem[r11]));
Zhi An Ng00a929f2021-12-14 15:07:34 -0800170 CHECK_ENCODING(0xF4CB088F, a.vst1_32(d16[1], mem[r11]));
Zhi An Ngfe4a7502021-12-09 14:21:57 -0800171 EXPECT_ERROR(Error::kInvalidLaneIndex, a.vst1_32(d16[2], mem[r11]));
172 CHECK_ENCODING(0xF4C6C80D, a.vst1_32({d28[0]}, mem[r6]++));
Zhi An Ng6883abb2021-12-14 10:13:18 -0800173
Zhi An Ng3bdbe9f2021-12-14 17:19:31 -0800174 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
Zhi An Ng65584bd2021-12-08 09:30:10 -0800175}
176
177TEST(AArch32Assembler, Label) {
Zhi An Ng6883abb2021-12-14 10:13:18 -0800178 xnn_code_buffer b;
179 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
180 Assembler a(&b);
Zhi An Ng65584bd2021-12-08 09:30:10 -0800181
182 Label l1;
183 a.add(r0, r0, r0);
184
185 // Branch to unbound label.
186 auto b1 = a.offset();
187 a.beq(l1);
188
189 a.add(r1, r1, r1);
190
191 auto b2 = a.offset();
192 a.bne(l1);
193
194 a.add(r2, r2, r2);
195
196 a.bind(l1);
197
198 // Check that b1 and b2 are both patched after binding l1.
199 EXPECT_INSTR(0x0A000002, *b1);
200 EXPECT_INSTR(0x1A000000, *b2);
201
202 a.add(r0, r1, r2);
203
204 // Branch to bound label.
205 auto b3 = a.offset();
206 a.bhi(l1);
207 auto b4 = a.offset();
208 a.bhs(l1);
209 auto b5 = a.offset();
210 a.blo(l1);
Zhi An Ngb63e84c2021-12-16 15:11:37 -0800211 auto b6 = a.offset();
212 a.b(l1);
Zhi An Ng65584bd2021-12-08 09:30:10 -0800213
214 EXPECT_INSTR(0x8AFFFFFD, *b3);
215 EXPECT_INSTR(0x2AFFFFFC, *b4);
216 EXPECT_INSTR(0x3AFFFFFB, *b5);
Zhi An Ngb63e84c2021-12-16 15:11:37 -0800217 EXPECT_INSTR(0xEAFFFFFA, *b6);
Zhi An Ng65584bd2021-12-08 09:30:10 -0800218
219 // Binding a bound label is an error.
220 a.bind(l1);
221 EXPECT_ERROR(Error::kLabelAlreadyBound, a.bind(l1));
222
223 // Check for bind failure due to too many users of label.
224 Label lfail;
225 a.reset();
226 // Arbitrary high number of users that we probably won't support.
227 for (int i = 0; i < 1000; i++) {
228 a.beq(lfail);
229 }
230 EXPECT_EQ(Error::kLabelHasTooManyUsers, a.error());
Zhi An Ng6883abb2021-12-14 10:13:18 -0800231
Zhi An Ng3bdbe9f2021-12-14 17:19:31 -0800232 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
Zhi An Ng512d44b2021-12-06 11:42:55 -0800233}
234
Zhi An Ngbe4e6a52021-12-16 15:09:27 -0800235TEST(AArch32Assembler, Align) {
236 xnn_code_buffer b;
237 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
238 Assembler a(&b);
239
240 a.add(r0, r1, r2);
241 a.align(4);
242 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset()) & 0x3);
243 EXPECT_EQ(4, a.code_size_in_bytes());
244
245 a.align(8);
246 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset()) & 0x7);
247 EXPECT_EQ(8, a.code_size_in_bytes());
248
249 a.add(r0, r1, r2);
250 a.align(8);
251 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset()) & 0x7);
252 EXPECT_EQ(16, a.code_size_in_bytes());
253
254 a.add(r0, r1, r2);
255 EXPECT_EQ(20, a.code_size_in_bytes());
256
257 a.align(16);
258 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset()) & 0xF);
259 EXPECT_EQ(32, a.code_size_in_bytes());
260
261 a.add(r0, r1, r2);
262 a.add(r0, r1, r2);
263 EXPECT_EQ(40, a.code_size_in_bytes());
264
265 a.align(16);
266 EXPECT_EQ(0, reinterpret_cast<uintptr_t>(a.offset()) & 0xF);
267 EXPECT_EQ(48, a.code_size_in_bytes());
268
269 // Not power-of-two.
270 EXPECT_ERROR(Error::kInvalidOperand, a.align(6));
271 // Is power-of-two but is not a multiple of instruction size.
272 EXPECT_ERROR(Error::kInvalidOperand, a.align(2));
273
274 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
275}
276
Zhi An Ng512d44b2021-12-06 11:42:55 -0800277TEST(AArch32Assembler, CoreRegisterList) {
278 EXPECT_EQ(0x3, CoreRegisterList({r0, r1}));
279 EXPECT_EQ(0xFC00, CoreRegisterList({r10, r11, r12, r13, r14, r15}));
280
281 EXPECT_FALSE(CoreRegisterList({}).has_more_than_one_register());
282 EXPECT_FALSE(CoreRegisterList({r0}).has_more_than_one_register());
283 EXPECT_FALSE(CoreRegisterList({r1}).has_more_than_one_register());
284 EXPECT_TRUE(CoreRegisterList({r0, r1}).has_more_than_one_register());
Zhi An Ngb559fe92021-12-06 09:25:38 -0800285}
Zhi An Ngc9ffad72021-12-07 14:28:21 -0800286
Zhi An Ng68c27d32021-12-08 10:58:34 -0800287TEST(AArch32Assembler, ConsecutiveRegisterList) {
288 SRegisterList s1 = SRegisterList(s0, s9);
289 EXPECT_EQ(s1.start, s0);
290 EXPECT_EQ(s1.length, 10);
291
292 DRegisterList d1 = DRegisterList(d4, d5);
293 EXPECT_EQ(d1.start, d4);
294 EXPECT_EQ(d1.length, 2);
295}
296
Zhi An Ngc9ffad72021-12-07 14:28:21 -0800297TEST(AArch32Assembler, MemOperand) {
298 EXPECT_EQ(MemOperand(r0, 4, AddressingMode::kOffset), (mem[r0, 4]));
299}
Zhi An Ngc9f70f72021-12-09 09:33:17 -0800300
301TEST(AArch32Assembler, DRegisterLane) {
302 EXPECT_EQ((DRegisterLane{2, 0}), d2[0]);
303 EXPECT_EQ((DRegisterLane{2, 1}), d2[1]);
304}
Zhi An Ng6883abb2021-12-14 10:13:18 -0800305
306TEST(AArch32Assembler, CodeBufferOverflow) {
307 xnn_code_buffer b;
308 xnn_allocate_code_memory(&b, 4);
309 Assembler a(&b);
310 a.add(r0, r0, 2);
311 EXPECT_EQ(Error::kNoError, a.error());
312
313 a.bx(lr);
314 EXPECT_EQ(Error::kOutOfMemory, a.error());
Zhi An Ng3bdbe9f2021-12-14 17:19:31 -0800315
316 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
317}
318
319TEST(AArch32Assembler, AllocateAndRelease) {
320 xnn_code_buffer b;
321 ASSERT_EQ(xnn_status_success, xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE));
322 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
Zhi An Ng6883abb2021-12-14 10:13:18 -0800323}
324
325#if XNN_ARCH_ARM
326TEST(AArch32Assembler, JitAllocCodeBuffer) {
327 typedef uint32_t (*Func)(uint32_t);
328
329 xnn_code_buffer b;
330 xnn_allocate_code_memory(&b, XNN_DEFAULT_CODE_BUFFER_SIZE);
331
332 Assembler a(&b);
333 a.add(r0, r0, 2).bx(lr);
334
335 Func fn = reinterpret_cast<Func>(a.finalize());
336
337 ASSERT_EQ(3, fn(1));
338
Zhi An Ng3bdbe9f2021-12-14 17:19:31 -0800339 ASSERT_EQ(xnn_status_success, xnn_release_code_memory(&b));
Zhi An Ng6883abb2021-12-14 10:13:18 -0800340}
341#endif
Zhi An Ngb559fe92021-12-06 09:25:38 -0800342} // namespace aarch32
343} // namespace xnnpack