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