xref: /aosp_15_r20/external/XNNPACK/src/f32-igemm/4x8-minmax-aarch32-neon-cortex-a7.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_cortex_a7(
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_cortex_a7
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        LDR     r5, [sp, 140]           // params
60        MOV     r14, r3                 // p = ks
61
62        # Clamp C pointers
63        CMP     r0, 2                   // if mr >= 2
64        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
65        MOVLO   r4, r11                 // c1
66                                        // if mr > 2
67        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
68        MOVLS   r8, r4                  // c2
69        CMP     r0, 4                   // if mr >=4
70        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
71        MOVLO   r6, r8                  // c3
72
73        # Load min/max values
74        VLD1.32 {d4[], d5[]}, [r5]!
75        VLD1.32 {d6[], d7[]}, [r5]
76
770:
78        # Load initial bias from w into accumulators
79        VLDM    r9!, {d16-d19}          // Bias
80        VMOV    q10, q8
81        VMOV    q11, q9
82        VMOV    q12, q8
83        VMOV    q13, q9
84        VMOV    q14, q8
85        VMOV    q15, q9
86
87        $if PREFETCH:
88          PLD     [r9,   0]               // Prefetch B
89          PLD     [r9,  64]
90          PLD     [r9, 128]
91          PLD     [r9, 192]
92          PLD     [r9, 256]
93          PLD     [r9, 320]
94          PLD     [r9, 384]
95          PLD     [r9, 448]
961:
97        # Load next 4 A pointers
98        LDR     r3, [r2,  0]
99        LDR     r12, [r2,  4]
100        LDR     r10, [r2,  8]
101        LDR     r0, [r2, 12]
102        ADD     r2, r2, 16
103
104        # Add a_offset
105        LDR     r5, [sp, 132]           // a_offset
106        LDR     r7, [sp, 136]           // zero
107        CMP     r3,  r7                 // if a0 == zero
108        ADD     r3,  r3, r5             // a0 += a_offset
109        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
110        CMP     r12,  r7                // if a1 == zero
111        ADD     r12, r12, r5            // a1 += a_offset
112        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
113        CMP     r10,  r7                // if a2 == zero
114        ADD     r10, r10, r5            // a2 += a_offset
115        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
116        CMP     r0,  r7                 // if a3 == zero
117        ADD     r0,  r0, r5             // a3 += a_offset
118        LDR     r5, [sp, 68]            // kc
119        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
120
121        $if PREFETCH:
122          PLD     [r3,  0]                // Prefetch A
123          PLD     [r3, 64]
124          PLD     [r12,  0]
125          PLD     [r12, 64]
126          PLD     [r10,  0]
127          PLD     [r10, 64]
128          PLD     [r0,  0]
129          PLD     [r0, 64]
130
131        SUBS    r5, r5, 8               // kc - 8
132        BLO     4f                      // less than 2 channels?
133
134        # Main loop - 2 floats of A (8 bytes)
1352:
136        VLD1.32 {d0}, [r3]!             // A0
137        VLDM    r9!, {d8-d11}           // B0
138        VLD1.32 {d1}, [r12]!            // A1
139        VLD1.32 {d2}, [r10]!            // A2
140        VLD1.32 {d3}, [ r0]!            // A3
141        VLDM    r9!, {d12-d15}          // B1
142
143        VMLA.F32 q8, q4, d0[0]
144        VMLA.F32 q9, q5, d0[0]
145        VMLA.F32 q10, q4, d1[0]
146        VMLA.F32 q11, q5, d1[0]
147        VMLA.F32 q12, q4, d2[0]
148        VMLA.F32 q13, q5, d2[0]
149        VMLA.F32 q14, q4, d3[0]
150        VMLA.F32 q15, q5, d3[0]
151        VMLA.F32 q8, q6, d0[1]
152        VMLA.F32 q9, q7, d0[1]
153        VMLA.F32 q10, q6, d1[1]
154        VMLA.F32 q11, q7, d1[1]
155        SUBS    r5, r5, 8
156        VMLA.F32 q12, q6, d2[1]
157        VMLA.F32 q13, q7, d2[1]
158        VMLA.F32 q14, q6, d3[1]
159        VMLA.F32 q15, q7, d3[1]
160        $if PREFETCH:
161          PLD     [r9, 448]               // Prefetch B
162          PLD     [r3, 128]               // Prefetch A0
163          PLD     [r12, 128]              // Prefetch A1
164          PLD     [r10, 128]              // Prefetch A2
165          PLD     [r0, 128]               // Prefetch A3
166        BHS     2b
167
168        # Is there a remainder?- 1 float of A (4 bytes)
169        TST     r5, 4
170        BNE     4f
171
1723:
173        # ks loop
174        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
175        BHI     1b
176
177        LDR     r7, [sp, 128]           // cn_stride
178        LDR     r14, [sp, 72]           // p = ks
179
180        # Clamp
181        VMAX.F32 q8,  q8, q2
182        SUBS    r1, r1, 8
183        VMAX.F32 q9,  q9, q2
184        VMAX.F32 q10, q10, q2
185        VMAX.F32 q11, q11, q2
186        VMAX.F32 q12, q12, q2
187        VMAX.F32 q13, q13, q2
188        VMAX.F32 q14, q14, q2
189        VMAX.F32 q15, q15, q2
190        VMIN.F32 q8,  q8, q3
191        VMIN.F32 q9,  q9, q3
192        VMIN.F32 q10, q10, q3
193        VMIN.F32 q11, q11, q3
194        VMIN.F32 q12, q12, q3
195        VMIN.F32 q13, q13, q3
196        VMIN.F32 q14, q14, q3
197        VMIN.F32 q15, q15, q3
198
199        # Store full 4 x 8
200        BLO     5f
201        VST1.32 {d28-d31},  [r6], r7
202        VST1.32 {d24-d27},  [r8], r7
203        VST1.32 {d20-d23},  [r4], r7
204        VST1.32 {d16-d19}, [r11], r7
205        SUB     r2, r2, r14             // a -= ks
206        BHI     0b
207
208        VPOP    {d8-d15}
209        ADD     sp, sp, 12              // skip pad, r2, r3
210        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
211
2124:
213        # Remainder- 1 float of A (4 bytes)
214        VLDM    r3!, {s0}               // A0
215        VLDM    r9!, {d8-d11}           // B0
216        VLDM    r12!, {s2}              // A1
217        VLDM    r10!, {s4}              // A2
218        VLDM    r0!, {s6}               // A3
219        VMLA.F32 q8, q4, d0[0]
220        VMLA.F32 q9, q5, d0[0]
221        VMLA.F32 q10, q4, d1[0]
222        VMLA.F32 q11, q5, d1[0]
223        VMLA.F32 q12, q4, d2[0]
224        VMLA.F32 q13, q5, d2[0]
225        VMLA.F32 q14, q4, d3[0]
226        VMLA.F32 q15, q5, d3[0]
227        B       3b
228
229        # Store odd width
2305:
231        TST     r1, 4
232        BEQ     6f
233        VST1.32 {d28-d29},  [r6]!
234        VST1.32 {d24-d25},  [r8]!
235        VMOV    q14, q15
236        VMOV    q12, q13
237        VST1.32 {d20-d21},  [r4]!
238        VST1.32 {d16-d17}, [r11]!
239        VMOV    q10, q11
240        VMOV    q8,  q9
241
2426:
243        TST     r1, 2
244        BEQ     7f
245        VST1.32 {d28},  [r6]!
246        VST1.32 {d24},  [r8]!
247        VMOV    d28, d29
248        VMOV    d24, d25
249        VST1.32 {d20},  [r4]!
250        VST1.32 {d16}, [r11]!
251        VMOV    d20, d21
252        VMOV    d16, d17
253
2547:
255        TST     r1, 1
256        BEQ     8f
257        VST1.32 {d28[0]},  [r6]!
258        VST1.32 {d24[0]},  [r8]!
259        VST1.32 {d20[0]},  [r4]!
260        VST1.32 {d16[0]}, [r11]!
261
2628:
263        VPOP    {d8-d15}
264        ADD     sp, sp, 12              // skip pad, r2, r3
265        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
266
267END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_cortex_a7
268# LINT.ThenChange(4x8-aarch32-neon-cortex-a7.cc)
269
270#ifdef __ELF__
271.section ".note.GNU-stack","",%progbits
272#endif
273