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