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