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