blob: 27fcb306fb363e7634683628b4ebd77e15f65abd [file] [log] [blame]
Frank Barchardc87a8fd2020-02-12 13:02:52 -08001// Copyright 2019 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/assembly.h>
7
8.syntax unified
9
10// void xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a53(
11// size_t mr, r0
12// size_t nc, r1
13// size_t kc, r2 -> r5 -> sp + 68
14// size_t ks, r3 -> sp + 72 -> r14
15// const float**restrict a, sp + 112 -> (r5)
16// const void*restrict w, sp + 116 -> r9
17// uint8_t*restrict c, sp + 120 -> r11
18// size_t cm_stride, sp + 124 -> (r6)
19// size_t cn_stride, sp + 128 -> (r0)
20// size_t a_offset, sp + 132 -> (r5)
21// const float* zero, sp + 136 -> (r0)
Marat Dukhaneb09a6b2020-04-08 17:34:32 -070022// minmax_params*params, sp + 140 -> (r5)
Frank Barchardc87a8fd2020-02-12 13:02:52 -080023
24// inner loop registers
25// r0, r2 scratch temporaries for loads
26
27// A0 r3 d0
28// A1 r12 d1
29// A2 r10 d2
30// A3 r7 d3
31
32// B r9 d8, d9, d10, d11
33// B d12, d13, d14, d15
34
35// C0 r11 d16-d17 q8 d18-d19 q9
36// C1 r4 d20-d21 q10 d22-d23 q11
37// C2 r8 d24-d25 q12 d26-d27 q13
38// C3 r6 d28-d29 q14 d30-d31 q15
39
40// Clamp (r5) d4 d5 d6 d7
41
42BEGIN_FUNCTION xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a53
43 .arm
44#ifndef __APPLE__
45 .arch armv7-a
46 .fpu neon
47#endif
48 // Push 112 bytes
49 // r2 will be reloaded in outer loop. r3 is ks
50 PUSH {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r14} // +44
51 SUB sp, sp, 4 // 4
52 VPUSH {d8-d15} // +64 = 112
53
54 LDR r11, [sp, 120] // c
55 LDR r6, [sp, 124] // cm_stride
56 LDR r5, [sp, 112] // a
57 LDR r9, [sp, 116] // w
58 MOV r14, r3 // p = ks
59
60 // Clamp C pointers
61 CMP r0, 2 // if mr >= 2
62 ADD r4, r11, r6 // c1 = c0 + cm_stride
63 MOVLO r4, r11 // c1
64 // if mr > 2
65 ADD r8, r4, r6 // c2 = c1 + cm_stride
66 MOVLS r8, r4 // c2
67 CMP r0, 4 // if mr >=4
68 ADD r6, r8, r6 // c3 = c2 + cm_stride
69 MOVLO r6, r8 // c3
70
71
72 .p2align 3
730:
74 # Load initial bias from w into accumulators
75 VLDM r9!, {d16-d19} // Bias
76
77 VMOV q10, q8
78 VMOV q11, q9
79 VMOV q12, q8
80 VMOV q13, q9
81 PLD [r9, 0] // Prefetch B
82 PLD [r9, 64]
83 VMOV q14, q8
84 PLD [r9, 128]
85 PLD [r9, 192]
86 VMOV q15, q9
87 PLD [r9, 256]
88 PLD [r9, 320]
89
901:
91 # Load next 4 A pointers
92 LDR r3, [r5, 0]
93 LDR r12, [r5, 4]
94 LDR r10, [r5, 8]
95 LDR r7, [r5, 12]
96 ADD r5, r5, 16
97 PLD [r3, 0] // Prefetch A
98 STR r5, [sp, 112] // a
99 PLD [r3, 64]
100 LDR r0, [sp, 136] // zero
101 PLD [r12, 0]
102 LDR r5, [sp, 132] // a_offset
103 PLD [r12, 64]
104 LDR r2, [sp, 68] // kc
105 PLD [r10, 0]
106 PLD [r10, 64]
107 PLD [r7, 0]
108 PLD [r7, 64]
109
110 // Add a_offset
111 CMP r3, r0 // if a0 == zero
112 ADD r3, r3, r5 // a0 += a_offset
113 MOVEQ r3, r0 // a0 = zero, else += a0 + a_offset
114 CMP r12, r0 // if a1 == zero
115 ADD r12, r12, r5 // a1 += a_offset
116 MOVEQ r12, r0 // a1 = zero, else += a1 + a_offset
117 CMP r10, r0 // if a2 == zero
118 ADD r10, r10, r5 // a2 += a_offset
119 MOVEQ r10, r0 // a2 = zero, else += a2 + a_offset
120 CMP r7, r0 // if a3 == zero
121 ADD r7, r7, r5 // a3 += a_offset
122 MOVEQ r7, r0 // a3 = zero, else += a3 + a_offset
123
124 SUBS r5, r2, 16 // kc - 16
125 BLO 5f // less than 4 channels?
126
127 // Prologue
128 VLD1.32 {d0}, [r3]! // A0
129 VLD1.32 {d1}, [r12]! // A1
130 VLD1.32 {d2}, [r10]! // A2
131 VLD1.32 {d3}, [r7]! // A3
132 SUBS r5, r5, 16
133 VLDM r9, {d8-d11} // B0
134 LDR r0, [r9, 56] // B1 low VMOV is in BLOCK 0
135 LDR r2, [r9, 60] // B1 high
136 VLDR d13, [r9, 40] // B1
137
138 BLO 3f // less than 4 channels? skip main loop
139
140 # Main loop - 4 floats of A (16 bytes)
141 # 32 FMA + 8 LD64 A + 8 LDR B
142 .p2align 3
1432:
144 # First group of 16 FMA, Second group loads
145 // BLOCK 0
146 VLD1.32 {d4}, [r3]! // A0
147 VMOV d15, r0, r2 // b1 VMOV b from second group
148 VMLA.F32 q8, q4, d0[0]
149 LDR r0, [r12] // A1 low
150 VMLA.F32 q10, q4, d1[0]
151 LDR r2, [r12, 4] // A1 high
152 VMLA.F32 q12, q4, d2[0]
153 PLD [r3, 128] // Prefetch A0
154
155 // BLOCK 1
156 VLDR d12, [r9, 32] // B1
157 VMOV d5, r0, r2 // a1 VMOV
158 VMLA.F32 q14, q4, d3[0]
159 LDR r0, [r9, 72] // B0 low
160 VMLA.F32 q9, q5, d0[0]
161 LDR r2, [r9, 76] // B0 high
162 VMLA.F32 q11, q5, d1[0]
163 PLD [r12, 128] // Prefetch A1
164
165 // BLOCK 2
166 VLD1.32 {d6}, [r10]! // A2
167 VMOV d9, r0, r2 // b0 VMOV
168 VMLA.F32 q13, q5, d2[0]
169 LDR r0, [r7] // A3 low
170 VMLA.F32 q15, q5, d3[0]
171 LDR r2, [r7, 4] // A3 high
172 VMLA.F32 q8, q6, d0[1]
173 PLD [r10, 128] // Prefetch A2
174
175 // BLOCK 3
176 VLDR d14, [r9, 48] // B1
177 VMOV d7, r0, r2 // a3 VMOV
178 VMLA.F32 q10, q6, d1[1]
179 LDR r0, [r9, 88] // B0 low
180 VMLA.F32 q12, q6, d2[1]
181 LDR r2, [r9, 92] // B0 high
182 VMLA.F32 q14, q6, d3[1]
183 PLD [r7, 128] // Prefetch A3
184
185 // BLOCK 4
186 VLDR d8, [r9, 64] // B0
187 VMOV d11, r0, r2 // B0 VMOV
188 VMLA.F32 q9, q7, d0[1]
189 LDR r0, [r9, 104] // B1 low VMOV is in BLOCK 0
190 VMLA.F32 q11, q7, d1[1]
191 LDR r2, [r9, 108] // B1 high
192 VMLA.F32 q13, q7, d2[1]
193 PLD [r9, 384] // Prefetch B
194
195 // BLOCK 5
196 VLDR d10, [r9, 80] // B0
197 VMOV d13, r0, r2 // b1 VMOV b from second group
198 VMLA.F32 q15, q7, d3[1]
199 LDR r0, [r9, 120] // B1 low VMOV is in BLOCK 0
200 NOP
201 LDR r2, [r9, 124] // B1 high
202 NOP
203 PLD [r9, 448] // Prefetch B
204
205 # Second group of 16 FMA, First group of loads
206 // BLOCK 0
207 VLD1.32 {d0}, [r3]! // A0
208 VMOV d15, r0, r2 // b1 VMOV b from second group
209 VMLA.F32 q8, q4, d4[0]
210 LDR r0, [r12, 8] // A1 low
211 VMLA.F32 q10, q4, d5[0]
212 LDR r2, [r12, 12] // A1 high
213 VMLA.F32 q12, q4, d6[0]
214 // NOP
215
216 // BLOCK 1
217 VLDR d12, [r9, 96] // B1
218 VMOV d1, r0, r2 // a1 VMOV
219 VMLA.F32 q14, q4, d7[0]
220 LDR r0, [r9, 136] // B0 low
221 VMLA.F32 q9, q5, d4[0]
222 LDR r2, [r9, 140] // B0 high
223 VMLA.F32 q11, q5, d5[0]
224 // NOP
225
226 // BLOCK 2
227 VLD1.32 {d2}, [r10]! // A2
228 VMOV d9, r0, r2 // b0 VMOV
229 VMLA.F32 q13, q5, d6[0]
230 LDR r0, [r7, 8] // A3 low
231 VMLA.F32 q15, q5, d7[0]
232 LDR r2, [r7, 12] // A3 high
233 VMLA.F32 q8, q6, d4[1]
234 // NOP
235
236 // BLOCK 3
237 VLDR d14, [r9, 112] // B1
238 VMOV d3, r0, r2 // a3 VMOV
239 VMLA.F32 q10, q6, d5[1]
240 LDR r0, [r9, 152] // B0 low
241 VMLA.F32 q12, q6, d6[1]
242 LDR r2, [r9, 156] // B0 high
243 VMLA.F32 q14, q6, d7[1]
244 ADD r12, r12, 16 // A1++
245
246 // BLOCK 4
247 VLDR d8, [r9, 128] // B0
248 VMOV d11, r0, r2 // B0 VMOV
249 VMLA.F32 q9, q7, d4[1]
250 LDR r0, [r9, 168] // B1 low
251 VMLA.F32 q11, q7, d5[1]
252 LDR r2, [r9, 172] // B1 high
253 VMLA.F32 q13, q7, d6[1]
254 ADD r7, r7, 16 // A3++
255
256 // BLOCK 5
257 VLDR d10, [r9, 144] // B0
258 VMOV d13, r0, r2 // b1 VMOV b
259 VMLA.F32 q15, q7, d7[1]
260 LDR r0, [r9, 184] // B1 low VMOV is in BLOCK 0
261 SUBS r5, r5, 16
262 LDR r2, [r9, 188] // B1 high
263 ADD r9, r9, 128 // B++
264 BHS 2b
265
266 # Epilogue - 4 floats of A (16 bytes)
2673:
268 # First group of 16 FMA, Second group loads
269 // BLOCK 0
270 VLD1.32 {d4}, [r3]! // A0
271 VMOV d15, r0, r2 // b1 VMOV b from second group
272 VMLA.F32 q8, q4, d0[0]
273 LDR r0, [r12] // A1 low
274 VMLA.F32 q10, q4, d1[0]
275 LDR r2, [r12, 4] // A1 high
276 VMLA.F32 q12, q4, d2[0]
277 // NOP
278
279 // BLOCK 1
280 VLDR d12, [r9, 32] // B1
281 VMOV d5, r0, r2 // a1 VMOV
282 VMLA.F32 q14, q4, d3[0]
283 LDR r0, [r9, 72] // B0 low
284 VMLA.F32 q9, q5, d0[0]
285 LDR r2, [r9, 76] // B0 high
286 VMLA.F32 q11, q5, d1[0]
287 // NOP
288
289 // BLOCK 2
290 VLD1.32 {d6}, [r10]! // A2
291 VMOV d9, r0, r2 // b0 VMOV
292 VMLA.F32 q13, q5, d2[0]
293 LDR r0, [r7] // A3 low
294 VMLA.F32 q15, q5, d3[0]
295 LDR r2, [r7, 4] // A3 high
296 VMLA.F32 q8, q6, d0[1]
297 // NOP
298
299 // BLOCK 3
300 VLDR d14, [r9, 48] // B1
301 VMOV d7, r0, r2 // a3 VMOV
302 VMLA.F32 q10, q6, d1[1]
303 LDR r0, [r9, 88] // B0 low
304 VMLA.F32 q12, q6, d2[1]
305 LDR r2, [r9, 92] // B0 high
306 VMLA.F32 q14, q6, d3[1]
307 // NOP
308
309 // BLOCK 4
310 VLDR d8, [r9, 64] // B0
311 VMOV d11, r0, r2 // B0 VMOV
312 VMLA.F32 q9, q7, d0[1]
313 LDR r0, [r9, 104] // B1 low
314 VMLA.F32 q11, q7, d1[1]
315 LDR r2, [r9, 108] // B1 high
316 VMLA.F32 q13, q7, d2[1]
317 // NOP
318
319 // BLOCK 5
320 VLDR d10, [r9, 80] // B0
321 VMOV d13, r0, r2 // b1 VMOV b
322 VMLA.F32 q15, q7, d3[1]
323 LDR r0, [r9, 120] // B1 low VMOV is in BLOCK 0
324 NOP
325 LDR r2, [r9, 124] // B1 high
326 NOP
327 NOP
328
329 # Second group of 16 FMA, First group of loads
330 // BLOCK 0
331 VLDR d12, [r9, 96] // B1
332 VMOV d15, r0, r2 // b1 VMOV b from second group
333 VMLA.F32 q8, q4, d4[0]
334 VMLA.F32 q10, q4, d5[0]
335 VMLA.F32 q12, q4, d6[0]
336
337 // BLOCK 1
338 VLDR d14, [r9, 112] // B1
339 VMLA.F32 q14, q4, d7[0]
340 VMLA.F32 q9, q5, d4[0]
341 VMLA.F32 q11, q5, d5[0]
342 ADD r12, r12, 8 // A1++
343
344 // BLOCK 2
345 ADD r7, r7, 8 // A3++ VLDR B1 lands here
346 ADD r9, r9, 128 // B++
347 VMLA.F32 q13, q5, d6[0]
348 VMLA.F32 q15, q5, d7[0]
349 VMLA.F32 q8, q6, d4[1]
350
351 // BLOCK 3
352 VMLA.F32 q10, q6, d5[1]
353 VMLA.F32 q12, q6, d6[1]
354 VMLA.F32 q14, q6, d7[1]
355 TST r5, 15
356
357 // BLOCK 4
358 VMLA.F32 q9, q7, d4[1]
359 VMLA.F32 q11, q7, d5[1]
360 VMLA.F32 q13, q7, d6[1]
361
362 // BLOCK 5
363 VMLA.F32 q15, q7, d7[1]
364
365 // Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
366 BNE 5f
367
368 .p2align 3
3694:
370 LDR r5, [sp, 112] // a
371 SUBS r14, r14, 16 // ks -= MR * sizeof(void*)
372
373 # ks loop
Frank Barchard16d72722020-02-12 15:46:20 -0800374 BHI 1b
Frank Barchardc87a8fd2020-02-12 13:02:52 -0800375
376 // Load params pointer
377 LDR r0, [sp, 128] // cn_stride
Marat Dukhaneb09a6b2020-04-08 17:34:32 -0700378 LDR r2, [sp, 140] // params
Frank Barchardc87a8fd2020-02-12 13:02:52 -0800379 LDR r14, [sp, 72] // p = ks
380 SUBS r1, r1, 8
381
Marat Dukhaneb09a6b2020-04-08 17:34:32 -0700382 // Load min/max values
Frank Barchardc87a8fd2020-02-12 13:02:52 -0800383 VLD1.32 {d4[],d5[]}, [r2]!
384 VLD1.32 {d6[],d7[]}, [r2]
385
386 // Clamp
Marat Dukhana51cf482020-04-08 16:16:19 -0700387 VMAX.F32 q8, q8, q2
388 VMAX.F32 q9, q9, q2
389 VMAX.F32 q10, q10, q2
390 VMAX.F32 q11, q11, q2
391 VMAX.F32 q12, q12, q2
392 VMAX.F32 q13, q13, q2
393 VMAX.F32 q14, q14, q2
394 VMAX.F32 q15, q15, q2
395 VMIN.F32 q8, q8, q3
396 VMIN.F32 q9, q9, q3
397 VMIN.F32 q10, q10, q3
398 VMIN.F32 q11, q11, q3
399 VMIN.F32 q12, q12, q3
400 VMIN.F32 q13, q13, q3
401 VMIN.F32 q14, q14, q3
402 VMIN.F32 q15, q15, q3
Frank Barchardc87a8fd2020-02-12 13:02:52 -0800403
404 // Store full 4 x 8
405 BLO 10f
406 VST1.32 {d28-d31}, [r6], r0
407 VST1.32 {d24-d27}, [r8], r0
408 VST1.32 {d20-d23}, [r4], r0
409 VST1.32 {d16-d19}, [r11], r0
410
411 SUB r5, r5, r14 // a -= ks
412
413 BHI 0b
414
415 VPOP {d8-d15}
416 ADD sp, sp, 12 // skip pad, r2, r3
417 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}
418
419 .p2align 3
4205:
421 // Is there a remainder?- 2 floats of A (8 bytes)
422 TST r5, 8
423 BEQ 6f
424
425 // Remainder - 2 floats of A (8 bytes)
426 VLD1.32 {d0}, [r3]! // A0
427 VLDM r9!, {d8-d11} // B0
428 VLD1.32 {d1}, [r12]! // A1
429 VLD1.32 {d2}, [r10]! // A2
430 VLD1.32 {d3}, [ r7]! // A3
431
432 VMLA.F32 q8, q4, d0[0]
433 VMLA.F32 q9, q5, d0[0]
434 VMLA.F32 q10, q4, d1[0]
435 VMLA.F32 q11, q5, d1[0]
436 VLDM r9!, {d12-d15} // B1
437 VMLA.F32 q12, q4, d2[0]
438 VMLA.F32 q13, q5, d2[0]
439 VMLA.F32 q14, q4, d3[0]
440 VMLA.F32 q15, q5, d3[0]
441 VMLA.F32 q8, q6, d0[1]
442 VMLA.F32 q9, q7, d0[1]
443 VMLA.F32 q10, q6, d1[1]
444 VMLA.F32 q11, q7, d1[1]
445 VMLA.F32 q12, q6, d2[1]
446 VMLA.F32 q13, q7, d2[1]
447 VMLA.F32 q14, q6, d3[1]
448 VMLA.F32 q15, q7, d3[1]
449
450 // Is there a remainder?- 1 floats of A (4 bytes)
451 TST r5, 4
452 BEQ 4b
453
4546:
455 // Remainder- 1 floats of A (4 bytes)
456 VLDM r3!, {s0} // A0
457 VLDM r9!, {d8-d11} // B0
458 VLDM r12!, {s2} // A1
459 VLDM r10!, {s4} // A2
460 VLDM r7!, {s6} // A3
461 VMLA.F32 q8, q4, d0[0]
462 VMLA.F32 q9, q5, d0[0]
463 VMLA.F32 q10, q4, d1[0]
464 VMLA.F32 q11, q5, d1[0]
465 VMLA.F32 q12, q4, d2[0]
466 VMLA.F32 q13, q5, d2[0]
467 VMLA.F32 q14, q4, d3[0]
468 VMLA.F32 q15, q5, d3[0]
469 B 4b
470
471 // Store odd width
47210:
473 TST r1, 4
474 BEQ 11f
475 VST1.32 {d28-d29}, [r6]!
476 VMOV q14, q15
477 VST1.32 {d24-d25}, [r8]!
478 VMOV q12, q13
479 VST1.32 {d20-d21}, [r4]!
480 VMOV q10, q11
481 VST1.32 {d16-d17}, [r11]!
482 VMOV q8, q9
483
48411:
485 TST r1, 2
486 BEQ 12f
487 VST1.32 {d28}, [r6]!
488 VMOV d28, d29
489 VST1.32 {d24}, [r8]!
490 VMOV d24, d25
491 VST1.32 {d20}, [r4]!
492 VMOV d20, d21
493 VST1.32 {d16}, [r11]!
494 VMOV d16, d17
495
49612:
497 TST r1, 1
498 BEQ 13f
499 VST1.32 {d28[0]}, [r6]!
500 VST1.32 {d24[0]}, [r8]!
501 VST1.32 {d20[0]}, [r4]!
502 VST1.32 {d16[0]}, [r11]!
503
50413:
505 VPOP {d8-d15}
506 ADD sp, sp, 12 // skip pad, r2, r3
507 POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}
508
509END_FUNCTION xnn_f32_igemm_ukernel_4x8__aarch32_neon_cortex_a53
510
511#ifdef __ELF__
512.section ".note.GNU-stack","",%progbits
513#endif