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