xref: /aosp_15_r20/external/XNNPACK/src/f32-igemm/gen/4x8-minmax-aarch32-neon-prfm-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_prfm_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_prfm_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        PLD     [r9,   0]               // Prefetch B
86        VMOV    q11, q9
87        PLD     [r9,  64]
88        VMOV    q12, q8
89        PLD     [r9, 128]
90        VMOV    q13, q9
91        PLD     [r9, 192]
92        VMOV    q14, q8
93        PLD     [r9, 256]
94        VMOV    q15, q9
95        PLD     [r9, 320]
96
971:
98        # Load next 4 A pointers
99        LDR     r3, [r5,  0]
100        LDR     r12, [r5,  4]
101        LDR     r10, [r5,  8]
102        LDR     r7, [r5, 12]
103        ADD     r5, r5, 16
104        PLD     [r3,  0]                // Prefetch A
105        STR     r5, [sp, 112]           // a
106        PLD     [r3, 64]
107        LDR     r0, [sp, 136]           // zero
108        PLD     [r12,  0]
109        LDR     r5, [sp, 132]           // a_offset
110        PLD     [r12, 64]
111        LDR     r2, [sp, 68]            // kc
112        PLD     [r10,  0]
113        PLD     [r10, 64]
114        PLD     [r7,  0]
115        PLD     [r7, 64]
116
117        # Add a_offset
118        CMP     r3,  r0                 // if a0 == zero
119        ADD     r3,  r3, r5             // a0 += a_offset
120        MOVEQ   r3,  r0                 //   a0 = zero, else += a0 + a_offset
121        CMP     r12,  r0                // if a1 == zero
122        ADD     r12, r12, r5            // a1 += a_offset
123        MOVEQ   r12,  r0                //   a1 = zero, else += a1 + a_offset
124        CMP     r10,  r0                // if a2 == zero
125        ADD     r10, r10, r5            // a2 += a_offset
126        MOVEQ   r10,  r0                //   a2 = zero, else += a2 + a_offset
127        CMP     r7,  r0                 // if a3 == zero
128        ADD     r7,  r7, r5             // a3 += a_offset
129        MOVEQ   r7,  r0                 //   a3 = zero, else += a3 + a_offset
130
131        SUBS    r5, r2, 16              // kc - 16
132        BLO     5f                      // less than 4 channels?
133
134        # Prologue
135        VLD1.32 {d0},  [r3]!            // A0
136        VLD1.32 {d1}, [r12]!            // A1
137        VLD1.32 {d2}, [r10]!            // A2
138        VLD1.32 {d3},  [r7]!            // A3
139        SUBS    r5, r5, 16
140        VLDM    r9, {d8-d11}            // B0
141        LDR     r0, [r9, 56]            // B1 low   VMOV is in BLOCK 0
142        LDR     r2, [r9, 60]            // B1 high
143        VLDR    d13, [r9, 40]           // B1
144
145        BLO     3f                      // less than 4 channels?  skip main loop
146
147        # Main loop - 4 floats of A (16 bytes)
148        # 32 FMA + 8 LD64 A + 8 LDR B
149        .p2align 3
1502:
151        # First group of 16 FMA, Second group loads
152        # BLOCK 0
153        VLD1.32 {d4}, [r3]!             // A0
154        VMOV    d15, r0, r2             // b1 VMOV b from second group
155        VMLA.F32 q8, q4, d0[0]
156        LDR     r0, [r12]               // A1 low
157        VMLA.F32 q10, q4, d1[0]
158        LDR     r2, [r12, 4]            // A1 high
159        VMLA.F32 q12, q4, d2[0]
160        PLD     [r3, 128]               // Prefetch A0
161
162        # BLOCK 1
163        VLDR    d12, [r9, 32]           // B1
164        VMOV    d5, r0, r2              // a1 VMOV
165        VMLA.F32 q14, q4, d3[0]
166        LDR     r0, [r9, 72]            // B0 low
167        VMLA.F32 q9, q5, d0[0]
168        LDR     r2, [r9, 76]            // B0 high
169        VMLA.F32 q11, q5, d1[0]
170        PLD     [r12, 128]              // Prefetch A1
171
172        # BLOCK 2
173        VLD1.32 {d6}, [r10]!            // A2
174        VMOV    d9, r0, r2              // b0 VMOV
175        VMLA.F32 q13, q5, d2[0]
176        LDR     r0, [r7]                // A3 low
177        VMLA.F32 q15, q5, d3[0]
178        LDR     r2, [r7, 4]             // A3 high
179        VMLA.F32 q8, q6, d0[1]
180        PLD     [r10, 128]              // Prefetch A2
181
182        # BLOCK 3
183        VLDR    d14, [r9, 48]           // B1
184        VMOV    d7, r0, r2              // a3 VMOV
185        VMLA.F32 q10, q6, d1[1]
186        LDR     r0, [r9, 88]            // B0 low
187        VMLA.F32 q12, q6, d2[1]
188        LDR     r2, [r9, 92]            // B0 high
189        VMLA.F32 q14, q6, d3[1]
190        PLD     [r7, 128]               // Prefetch A3
191
192        # BLOCK 4
193        VLDR    d8, [r9, 64]            // B0
194        VMOV    d11, r0, r2             // B0 VMOV
195        VMLA.F32 q9, q7, d0[1]
196        LDR     r0, [r9, 104]           // B1 low   VMOV is in BLOCK 0
197        VMLA.F32 q11, q7, d1[1]
198        LDR     r2, [r9, 108]           // B1 high
199        VMLA.F32 q13, q7, d2[1]
200        PLD     [r9, 384]               // Prefetch B
201
202        # BLOCK 5
203        VLDR    d10, [r9, 80]           // B0
204        VMOV    d13, r0, r2             // b1 VMOV b from second group
205        VMLA.F32 q15, q7, d3[1]
206        LDR     r0, [r9, 120]           // B1 low   VMOV is in BLOCK 0
207        NOP
208        LDR     r2, [r9, 124]           // B1 high
209        NOP
210        PLD     [r9, 448]               // Prefetch B
211
212        # Second group of 16 FMA, First group of loads
213        # BLOCK 0
214        VLD1.32 {d0}, [r3]!             // A0
215        VMOV    d15, r0, r2             // b1 VMOV b from second group
216        VMLA.F32 q8, q4, d4[0]
217        LDR     r0, [r12, 8]            // A1 low
218        VMLA.F32 q10, q4, d5[0]
219        LDR     r2, [r12, 12]           // A1 high
220        VMLA.F32 q12, q4, d6[0]
221        # NOP
222
223        # BLOCK 1
224        VLDR    d12, [r9, 96]           // B1
225        VMOV    d1, r0, r2              // a1 VMOV
226        VMLA.F32 q14, q4, d7[0]
227        LDR     r0, [r9, 136]           // B0 low
228        VMLA.F32 q9, q5, d4[0]
229        LDR     r2, [r9, 140]           // B0 high
230        VMLA.F32 q11, q5, d5[0]
231        # NOP
232
233        # BLOCK 2
234        VLD1.32 {d2}, [r10]!            // A2
235        VMOV    d9, r0, r2              // b0 VMOV
236        VMLA.F32 q13, q5, d6[0]
237        LDR     r0, [r7, 8]             // A3 low
238        VMLA.F32 q15, q5, d7[0]
239        LDR     r2, [r7, 12]            // A3 high
240        VMLA.F32 q8, q6, d4[1]
241        # NOP
242
243        # BLOCK 3
244        VLDR    d14, [r9, 112]          // B1
245        VMOV    d3, r0, r2              // a3 VMOV
246        VMLA.F32 q10, q6, d5[1]
247        LDR     r0, [r9, 152]           // B0 low
248        VMLA.F32 q12, q6, d6[1]
249        LDR     r2, [r9, 156]           // B0 high
250        VMLA.F32 q14, q6, d7[1]
251        ADD     r12, r12, 16            // A1++
252
253        # BLOCK 4
254        VLDR    d8, [r9, 128]           // B0
255        VMOV    d11, r0, r2             // B0 VMOV
256        VMLA.F32 q9, q7, d4[1]
257        LDR     r0, [r9, 168]           // B1 low
258        VMLA.F32 q11, q7, d5[1]
259        LDR     r2, [r9, 172]           // B1 high
260        VMLA.F32 q13, q7, d6[1]
261        ADD     r7, r7, 16              // A3++
262
263        # BLOCK 5
264        VLDR    d10, [r9, 144]          // B0
265        VMOV    d13, r0, r2             // b1 VMOV b
266        VMLA.F32 q15, q7, d7[1]
267        LDR     r0, [r9, 184]           // B1 low   VMOV is in BLOCK 0
268        SUBS    r5, r5, 16
269        LDR     r2, [r9, 188]           // B1 high
270        ADD     r9, r9, 128             // B++
271        BHS     2b
272
273        # Epilogue - 4 floats of A (16 bytes)
2743:
275        # First group of 16 FMA, Second group loads
276        # BLOCK 0
277        VLD1.32 {d4}, [r3]!             // A0
278        VMOV    d15, r0, r2             // b1 VMOV b from second group
279        VMLA.F32 q8, q4, d0[0]
280        LDR     r0, [r12]               // A1 low
281        VMLA.F32 q10, q4, d1[0]
282        LDR     r2, [r12, 4]            // A1 high
283        VMLA.F32 q12, q4, d2[0]
284        # NOP
285
286        # BLOCK 1
287        VLDR    d12, [r9, 32]           // B1
288        VMOV    d5, r0, r2              // a1 VMOV
289        VMLA.F32 q14, q4, d3[0]
290        LDR     r0, [r9, 72]            // B0 low
291        VMLA.F32 q9, q5, d0[0]
292        LDR     r2, [r9, 76]            // B0 high
293        VMLA.F32 q11, q5, d1[0]
294        # NOP
295
296        # BLOCK 2
297        VLD1.32 {d6}, [r10]!            // A2
298        VMOV    d9, r0, r2              // b0 VMOV
299        VMLA.F32 q13, q5, d2[0]
300        LDR     r0, [r7]                // A3 low
301        VMLA.F32 q15, q5, d3[0]
302        LDR     r2, [r7, 4]             // A3 high
303        VMLA.F32 q8, q6, d0[1]
304        # NOP
305
306        # BLOCK 3
307        VLDR    d14, [r9, 48]           // B1
308        VMOV    d7, r0, r2              // a3 VMOV
309        VMLA.F32 q10, q6, d1[1]
310        LDR     r0, [r9, 88]            // B0 low
311        VMLA.F32 q12, q6, d2[1]
312        LDR     r2, [r9, 92]            // B0 high
313        VMLA.F32 q14, q6, d3[1]
314        # NOP
315
316        # BLOCK 4
317        VLDR    d8, [r9, 64]            // B0
318        VMOV    d11, r0, r2             // B0 VMOV
319        VMLA.F32 q9, q7, d0[1]
320        LDR     r0, [r9, 104]           // B1 low
321        VMLA.F32 q11, q7, d1[1]
322        LDR     r2, [r9, 108]           // B1 high
323        VMLA.F32 q13, q7, d2[1]
324        # NOP
325
326        # BLOCK 5
327        VLDR    d10, [r9, 80]           // B0
328        VMOV    d13, r0, r2             // b1 VMOV b
329        VMLA.F32 q15, q7, d3[1]
330        LDR     r0, [r9, 120]           // B1 low   VMOV is in BLOCK 0
331        NOP
332        LDR     r2, [r9, 124]           // B1 high
333        NOP
334        NOP
335
336        # Second group of 16 FMA, First group of loads
337        # BLOCK 0
338        VLDR    d12, [r9, 96]           // B1
339        VMOV    d15, r0, r2             // b1 VMOV b from second group
340        VMLA.F32 q8, q4, d4[0]
341        VMLA.F32 q10, q4, d5[0]
342        VMLA.F32 q12, q4, d6[0]
343
344        # BLOCK 1
345        VLDR    d14, [r9, 112]          // B1
346        VMLA.F32 q14, q4, d7[0]
347        VMLA.F32 q9, q5, d4[0]
348        VMLA.F32 q11, q5, d5[0]
349        ADD     r12, r12, 8             // A1++
350
351        # BLOCK 2
352        ADD     r7, r7, 8               // A3++ VLDR B1 lands here
353        ADD     r9, r9, 128             // B++
354        VMLA.F32 q13, q5, d6[0]
355        VMLA.F32 q15, q5, d7[0]
356        VMLA.F32 q8, q6, d4[1]
357
358        # BLOCK 3
359        VMLA.F32 q10, q6, d5[1]
360        VMLA.F32 q12, q6, d6[1]
361        VMLA.F32 q14, q6, d7[1]
362        TST     r5, 15
363
364        # BLOCK 4
365        VMLA.F32 q9, q7, d4[1]
366        VMLA.F32 q11, q7, d5[1]
367        VMLA.F32 q13, q7, d6[1]
368
369        # BLOCK 5
370        VMLA.F32 q15, q7, d7[1]
371
372        # Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
373        BNE     5f
374
375        .p2align 3
3764:
377        LDR     r5, [sp, 112]           // a
378        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
379
380        # ks loop
381        BHI     1b
382
383        # Load params pointer
384        LDR     r0, [sp, 128]           // cn_stride
385        LDR     r2, [sp, 140]           // params
386        LDR     r14, [sp, 72]           // p = ks
387        SUBS    r1, r1, 8
388
389        # Load min/max values
390        VLD1.32 {d4[],d5[]}, [r2]!
391        VLD1.32 {d6[],d7[]}, [r2]
392
393        # Clamp
394        VMAX.F32 q8,  q8, q2
395        VMAX.F32 q9,  q9, q2
396        VMAX.F32 q10, q10, q2
397        VMAX.F32 q11, q11, q2
398        VMAX.F32 q12, q12, q2
399        VMAX.F32 q13, q13, q2
400        VMAX.F32 q14, q14, q2
401        VMAX.F32 q15, q15, q2
402        VMIN.F32 q8,  q8, q3
403        VMIN.F32 q9,  q9, q3
404        VMIN.F32 q10, q10, q3
405        VMIN.F32 q11, q11, q3
406        VMIN.F32 q12, q12, q3
407        VMIN.F32 q13, q13, q3
408        VMIN.F32 q14, q14, q3
409        VMIN.F32 q15, q15, q3
410
411        # Store full 4 x 8
412        BLO     7f
413        VST1.32 {d28-d31},  [r6], r0
414        VST1.32 {d24-d27},  [r8], r0
415        VST1.32 {d20-d23},  [r4], r0
416        VST1.32 {d16-d19}, [r11], r0
417
418        SUB     r5, r5, r14             // a -= ks
419
420        BHI     0b
421
422        VPOP    {d8-d15}
423        ADD     sp, sp, 12              // skip pad, r2, r3
424        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
425
426        .p2align 3
4275:
428        # Is there a remainder?- 2 floats of A (8 bytes)
429        TST     r5, 8
430        BEQ     6f
431
432        # Remainder - 2 floats of A (8 bytes)
433        VLD1.32 {d0}, [r3]!             // A0
434        VLDM    r9!, {d8-d11}           // B0
435        VLD1.32 {d1}, [r12]!            // A1
436        VLD1.32 {d2}, [r10]!            // A2
437        VLD1.32 {d3}, [ r7]!            // A3
438
439        VMLA.F32 q8, q4, d0[0]
440        VMLA.F32 q9, q5, d0[0]
441        VMLA.F32 q10, q4, d1[0]
442        VMLA.F32 q11, q5, d1[0]
443        VLDM    r9!, {d12-d15}          // B1
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        VMLA.F32 q8, q6, d0[1]
449        VMLA.F32 q9, q7, d0[1]
450        VMLA.F32 q10, q6, d1[1]
451        VMLA.F32 q11, q7, d1[1]
452        VMLA.F32 q12, q6, d2[1]
453        VMLA.F32 q13, q7, d2[1]
454        VMLA.F32 q14, q6, d3[1]
455        VMLA.F32 q15, q7, d3[1]
456
457        # Is there a remainder?- 1 float of A (4 bytes)
458        TST     r5, 4
459        BEQ     4b
460
4616:
462        # Remainder- 1 float of A (4 bytes)
463        VLDM    r3!, {s0}               // A0
464        VLDM    r9!, {d8-d11}           // B0
465        VLDM    r12!, {s2}              // A1
466        VLDM    r10!, {s4}              // A2
467        VLDM    r7!, {s6}               // A3
468        VMLA.F32 q8, q4, d0[0]
469        VMLA.F32 q9, q5, d0[0]
470        VMLA.F32 q10, q4, d1[0]
471        VMLA.F32 q11, q5, d1[0]
472        VMLA.F32 q12, q4, d2[0]
473        VMLA.F32 q13, q5, d2[0]
474        VMLA.F32 q14, q4, d3[0]
475        VMLA.F32 q15, q5, d3[0]
476        B       4b
477
478        # Store odd width
4797:
480        TST     r1, 4
481        BEQ     8f
482        VST1.32 {d28-d29},  [r6]!
483        VST1.32 {d24-d25},  [r8]!
484        VMOV    q14, q15
485        VMOV    q12, q13
486        VST1.32 {d20-d21},  [r4]!
487        VST1.32 {d16-d17}, [r11]!
488        VMOV    q10, q11
489        VMOV    q8,  q9
490
4918:
492        TST     r1, 2
493        BEQ     9f
494        VST1.32 {d28},  [r6]!
495        VST1.32 {d24},  [r8]!
496        VMOV    d28, d29
497        VMOV    d24, d25
498        VST1.32 {d20},  [r4]!
499        VST1.32 {d16}, [r11]!
500        VMOV    d20, d21
501        VMOV    d16, d17
502
5039:
504        TST     r1, 1
505        BEQ     10f
506        VST1.32 {d28[0]},  [r6]!
507        VST1.32 {d24[0]},  [r8]!
508        VST1.32 {d20[0]},  [r4]!
509        VST1.32 {d16[0]}, [r11]!
510
51110:
512        VPOP    {d8-d15}
513        ADD     sp, sp, 12              // skip pad, r2, r3
514        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
515
516END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_prfm_cortex_a53
517
518#ifdef __ELF__
519.section ".note.GNU-stack","",%progbits
520#endif
521