xref: /aosp_15_r20/external/XNNPACK/src/f32-igemm/gen/4x8-minmax-aarch32-neon-prfm-cortex-a75.S (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1// Auto-generated file. Do not edit!
2//   Template: src/f32-igemm/4x8-aarch32-neon-cortex-a75.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_a75(
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 -> r2
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 -> (r7)
24//     size_t a_offset,          sp + 132 -> (r5)
25//     const float* zero,        sp + 136 -> (r7)
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// A0   r3  d0
32// A1  r12  d1
33// A2  r10  d2
34// A3   r0  d3
35
36// B    r9  d8,  d9, d10, d11
37// B       d12, d13, d14, d15
38
39// C0  r11 d16-d17  q8  d18-d19  q9
40// C1   r4 d20-d21 q10  d22-d23 q11
41// C2   r8 d24-d25 q12  d26-d27 q13
42// C3   r6 d28-d29 q14  d30-d31 q15
43
44// Clamp (r5) d4 d5 d6 d7
45
46BEGIN_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_prfm_cortex_a75
47        .arm
48#ifndef __APPLE__
49        .arch   armv7-a
50        .fpu    neon
51#endif
52        # Push 112 bytes
53        # r2 will be reloaded in outer loop.  r3 is ks
54        PUSH    {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}   // +44
55        SUB     sp, sp, 4                                        // 4
56        VPUSH   {d8-d15}                                         // +64 = 112
57
58        LDR     r11, [sp, 120]          // c
59        LDR     r6, [sp, 124]           // cm_stride
60        LDR     r2, [sp, 112]           // a
61        LDR     r9, [sp, 116]           // w
62        MOV     r14, r3                 // p = ks
63
64        # Clamp C pointers
65        CMP     r0, 2                   // if mr >= 2
66        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
67        MOVLO   r4, r11                 // c1
68                                        // if mr > 2
69        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
70        MOVLS   r8, r4                  // c2
71        CMP     r0, 4                   // if mr >=4
72        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
73        MOVLO   r6, r8                  // c3
74
75        .p2align 3
760:
77        # Load initial bias from w into accumulators
78        VLDM    r9!, {d16-d19}          // Bias
79        VMOV    q10, q8
80        VMOV    q11, q9
81        VMOV    q12, q8
82        VMOV    q13, q9
83        VMOV    q14, q8
84        VMOV    q15, q9
85
86        PLD     [r9,   0]               // Prefetch B
87        PLD     [r9,  64]
88        PLD     [r9, 128]
89        PLD     [r9, 192]
90        PLD     [r9, 256]
91        PLD     [r9, 320]
92        PLD     [r9, 384]
93
941:
95        # Load next 4 A pointers
96        LDR     r3, [r2,  0]
97        LDR     r12, [r2,  4]
98        LDR     r10, [r2,  8]
99        LDR     r0, [r2, 12]
100        ADD     r2, r2, 16
101
102        # Add a_offset
103        LDR     r5, [sp, 132]           // a_offset
104        LDR     r7, [sp, 136]           // zero
105        CMP     r3,  r7                 // if a0 == zero
106        ADD     r3,  r3, r5             // a0 += a_offset
107        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
108        CMP     r12,  r7                // if a1 == zero
109        ADD     r12, r12, r5            // a1 += a_offset
110        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
111        CMP     r10,  r7                // if a2 == zero
112        ADD     r10, r10, r5            // a2 += a_offset
113        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
114        CMP     r0,  r7                 // if a3 == zero
115        ADD     r0,  r0, r5             // a3 += a_offset
116        LDR     r5, [sp, 68]            // kc
117        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
118
119        PLD     [r3,  0]                // Prefetch A
120        PLD     [r3, 64]
121        PLD     [r12,  0]
122        PLD     [r12, 64]
123        PLD     [r10,  0]
124        PLD     [r10, 64]
125        PLD     [r0,  0]
126        PLD     [r0, 64]
127
128        SUBS    r5, r5, 16              // kc - 16
129        BLO     5f                      // less than 4 channels?
130
131        # Prologue
132        VLD1.32 {d0}, [r3]!             // A0
133        VLDM    r9!, {d8-d11}           // B0
134        VLD1.32 {d1}, [r12]!            // A1
135        VLD1.32 {d2}, [r10]!            // A2
136        VLD1.32 {d3}, [ r0]!            // A3
137
138        SUBS    r5, r5, 16
139        BLO     3f                      // less than 4 channels?  skip main loop
140
141        .p2align 3
142
143        # Main loop - 4 floats of A (16 bytes)
1442:
145        VMLA.F32 q8, q4, d0[0]
146        VLDM    r9!, {d12-d15}          // B1
147        VMLA.F32 q10, q4, d1[0]
148        VMLA.F32 q12, q4, d2[0]
149        VLD1.32 {d4}, [r3]!             // A0
150        VMLA.F32 q14, q4, d3[0]
151        VMLA.F32 q9, q5, d0[0]
152        VLD1.32 {d5}, [r12]!            // A1
153        VMLA.F32 q11, q5, d1[0]
154        VMLA.F32 q13, q5, d2[0]
155        VMLA.F32 q15, q5, d3[0]
156        VLD1.32 {d6}, [r10]!            // A2
157        VMLA.F32 q8, q6, d0[1]
158        VMLA.F32 q10, q6, d1[1]
159        VLD1.32 {d7}, [ r0]!            // A3
160        VMLA.F32 q12, q6, d2[1]
161        VMLA.F32 q14, q6, d3[1]
162        VLDM    r9!, {d8-d11}           // B0
163        VMLA.F32 q9, q7, d0[1]
164        VMLA.F32 q11, q7, d1[1]
165        VMLA.F32 q13, q7, d2[1]
166        VMLA.F32 q15, q7, d3[1]
167
168        VMLA.F32 q8, q4, d4[0]
169        VLDM    r9!, {d12-d15}          // B1
170        VMLA.F32 q10, q4, d5[0]
171        PLD     [r3, 128]               // Prefetch A0
172        VMLA.F32 q12, q4, d6[0]
173        VLD1.32 {d0}, [r3]!             // A0
174        VMLA.F32 q14, q4, d7[0]
175        PLD     [r12, 128]              // Prefetch A1
176        VMLA.F32 q9, q5, d4[0]
177        VLD1.32 {d1}, [r12]!            // A1
178        VMLA.F32 q11, q5, d5[0]
179        PLD     [r10, 128]              // Prefetch A2
180        VMLA.F32 q13, q5, d6[0]
181        VLD1.32 {d2}, [r10]!            // A2
182        VMLA.F32 q15, q5, d7[0]
183        PLD     [r0, 128]               // Prefetch A3
184        VMLA.F32 q8, q6, d4[1]
185        VLD1.32 {d3}, [ r0]!            // A3
186        VMLA.F32 q10, q6, d5[1]
187        PLD     [r9, 352]               // Prefetch B
188        VMLA.F32 q12, q6, d6[1]
189        PLD     [r9, 416]               // Prefetch B
190        VMLA.F32 q14, q6, d7[1]
191        VLDM    r9!, {d8-d11}           // B0
192        VMLA.F32 q9, q7, d4[1]
193        VMLA.F32 q11, q7, d5[1]
194        SUBS    r5, r5, 16
195        VMLA.F32 q13, q7, d6[1]
196        VMLA.F32 q15, q7, d7[1]
197        BHS     2b
198
199        # Epilogue
2003:
201        VMLA.F32 q8, q4, d0[0]
202        VLDM    r9!, {d12-d15}          // B1
203        VMLA.F32 q10, q4, d1[0]
204        VMLA.F32 q12, q4, d2[0]
205        VLD1.32 {d4}, [r3]!             // A0
206        VMLA.F32 q14, q4, d3[0]
207        VMLA.F32 q9, q5, d0[0]
208        VLD1.32 {d5}, [r12]!            // A1
209        VMLA.F32 q11, q5, d1[0]
210        VMLA.F32 q13, q5, d2[0]
211        VMLA.F32 q15, q5, d3[0]
212        VLD1.32 {d6}, [r10]!            // A2
213        VMLA.F32 q8, q6, d0[1]
214        VMLA.F32 q10, q6, d1[1]
215        VLD1.32 {d7}, [ r0]!            // A3
216        VMLA.F32 q12, q6, d2[1]
217        VMLA.F32 q14, q6, d3[1]
218        VLDM    r9!, {d8-d11}           // B0
219        VMLA.F32 q9, q7, d0[1]
220        VMLA.F32 q11, q7, d1[1]
221        VMLA.F32 q13, q7, d2[1]
222        VMLA.F32 q15, q7, d3[1]
223
224        VMLA.F32 q8, q4, d4[0]
225        VLDM    r9!, {d12-d15}          // B1
226        VMLA.F32 q10, q4, d5[0]
227        VMLA.F32 q12, q4, d6[0]
228        VMLA.F32 q14, q4, d7[0]
229        VMLA.F32 q9, q5, d4[0]
230        VMLA.F32 q11, q5, d5[0]
231        VMLA.F32 q13, q5, d6[0]
232        VMLA.F32 q15, q5, d7[0]
233        VMLA.F32 q8, q6, d4[1]
234        VMLA.F32 q10, q6, d5[1]
235        VMLA.F32 q12, q6, d6[1]
236        VMLA.F32 q14, q6, d7[1]
237        VMLA.F32 q9, q7, d4[1]
238        VMLA.F32 q11, q7, d5[1]
239        VMLA.F32 q13, q7, d6[1]
240        VMLA.F32 q15, q7, d7[1]
241
242        # Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
243        TST     r5, 12
244        BNE     5f
245
246        .p2align 3
2474:
248        # ks loop
249        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
250        BHI     1b
251
252        # Load params pointer
253        LDR     r5, [sp, 140]           // params
254        LDR     r7, [sp, 128]           // cn_stride
255        LDR     r14, [sp, 72]           // p = ks
256
257        # Load min/max values
258        VLD1.32 {d4[],d5[]}, [r5]!
259        SUBS    r1, r1, 8
260        VLD1.32 {d6[],d7[]}, [r5]
261
262        # Clamp
263        VMAX.F32 q8,  q8, q2
264        VMAX.F32 q9,  q9, q2
265        VMAX.F32 q10, q10, q2
266        VMAX.F32 q11, q11, q2
267        VMAX.F32 q12, q12, q2
268        VMAX.F32 q13, q13, q2
269        VMAX.F32 q14, q14, q2
270        VMAX.F32 q15, q15, q2
271        VMIN.F32 q8,  q8, q3
272        VMIN.F32 q9,  q9, q3
273        VMIN.F32 q10, q10, q3
274        VMIN.F32 q11, q11, q3
275        VMIN.F32 q12, q12, q3
276        VMIN.F32 q13, q13, q3
277        VMIN.F32 q14, q14, q3
278        VMIN.F32 q15, q15, q3
279
280        # Store full 4 x 8
281        BLO     7f
282        VST1.32 {d28-d31},  [r6], r7
283        VST1.32 {d24-d27},  [r8], r7
284        VST1.32 {d20-d23},  [r4], r7
285        VST1.32 {d16-d19}, [r11], r7
286        SUB     r2, r2, r14             // a -= ks
287        BHI     0b
288
289        VPOP    {d8-d15}
290        ADD     sp, sp, 12              // skip pad, r2, r3
291        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
292
293        .p2align 3
2945:
295        # Is there a remainder?- 2 floats of A (8 bytes)
296        TST     r5, 8
297        BEQ     6f
298
299        # Remainder - 2 floats of A (8 bytes)
300        VLD1.32 {d0}, [r3]!             // A0
301        VLDM    r9!, {d8-d11}           // B0
302        VLD1.32 {d1}, [r12]!            // A1
303        VLD1.32 {d2}, [r10]!            // A2
304        VLD1.32 {d3}, [ r0]!            // A3
305
306        VMLA.F32 q8, q4, d0[0]
307        VMLA.F32 q9, q5, d0[0]
308        VMLA.F32 q10, q4, d1[0]
309        VMLA.F32 q11, q5, d1[0]
310        VLDM    r9!, {d12-d15}          // B1
311        VMLA.F32 q12, q4, d2[0]
312        VMLA.F32 q13, q5, d2[0]
313        VMLA.F32 q14, q4, d3[0]
314        VMLA.F32 q15, q5, d3[0]
315        VMLA.F32 q8, q6, d0[1]
316        VMLA.F32 q9, q7, d0[1]
317        VMLA.F32 q10, q6, d1[1]
318        VMLA.F32 q11, q7, d1[1]
319        VMLA.F32 q12, q6, d2[1]
320        VMLA.F32 q13, q7, d2[1]
321        VMLA.F32 q14, q6, d3[1]
322        VMLA.F32 q15, q7, d3[1]
323
324        # Is there a remainder?- 1 float of A (4 bytes)
325        TST     r5, 4
326        BEQ     4b
327
3286:
329        # Remainder- 1 float of A (4 bytes)
330        VLDM    r3!, {s0}               // A0
331        VLDM    r9!, {d8-d11}           // B0
332        VLDM    r12!, {s2}              // A1
333        VLDM    r10!, {s4}              // A2
334        VLDM    r0!, {s6}               // A3
335        VMLA.F32 q8, q4, d0[0]
336        VMLA.F32 q9, q5, d0[0]
337        VMLA.F32 q10, q4, d1[0]
338        VMLA.F32 q11, q5, d1[0]
339        VMLA.F32 q12, q4, d2[0]
340        VMLA.F32 q13, q5, d2[0]
341        VMLA.F32 q14, q4, d3[0]
342        VMLA.F32 q15, q5, d3[0]
343        B       4b
344
345        # Store odd width
3467:
347        TST     r1, 4
348        BEQ     8f
349        VST1.32 {d28-d29},  [r6]!
350        VST1.32 {d24-d25},  [r8]!
351        VMOV    q14, q15
352        VMOV    q12, q13
353        VST1.32 {d20-d21},  [r4]!
354        VST1.32 {d16-d17}, [r11]!
355        VMOV    q10, q11
356        VMOV    q8,  q9
357
3588:
359        TST     r1, 2
360        BEQ     9f
361        VST1.32 {d28},  [r6]!
362        VST1.32 {d24},  [r8]!
363        VMOV    d28, d29
364        VMOV    d24, d25
365        VST1.32 {d20},  [r4]!
366        VST1.32 {d16}, [r11]!
367        VMOV    d20, d21
368        VMOV    d16, d17
369
3709:
371        TST     r1, 1
372        BEQ     10f
373        VST1.32 {d28[0]},  [r6]!
374        VST1.32 {d24[0]},  [r8]!
375        VST1.32 {d20[0]},  [r4]!
376        VST1.32 {d16[0]}, [r11]!
377
37810:
379        VPOP    {d8-d15}
380        ADD     sp, sp, 12              // skip pad, r2, r3
381        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
382
383END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_prfm_cortex_a75
384
385#ifdef __ELF__
386.section ".note.GNU-stack","",%progbits
387#endif
388