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