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_pld_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_pld_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        PLD         [r9,   0]  // Prefetch B
86        PLD         [r9,  64]
87        PLD         [r9, 128]
88        PLD         [r9, 192]
89        PLD         [r9, 256]
90        PLD         [r9, 320]
91        PLD         [r9, 384]
92
931:
94        # Load next 4 A pointers
95        LDR         r3, [r2,  0]
96        LDR        r12, [r2,  4]
97        LDR        r10, [r2,  8]
98        LDR         r0, [r2, 12]
99        ADD         r2, r2, 16
100
101        // Add a_offset
102        LDR         r5, [sp, 132]    // a_offset
103        LDR         r7, [sp, 136]    // zero
104        CMP         r3,  r7          // if a0 == zero
105        ADD         r3,  r3, r5      // a0 += a_offset
106        MOVEQ       r3,  r7          //   a0 = zero, else += a0 + a_offset
107        CMP        r12,  r7          // if a1 == zero
108        ADD        r12, r12, r5      // a1 += a_offset
109        MOVEQ      r12,  r7          //   a1 = zero, else += a1 + a_offset
110        CMP        r10,  r7          // if a2 == zero
111        ADD        r10, r10, r5      // a2 += a_offset
112        MOVEQ      r10,  r7          //   a2 = zero, else += a2 + a_offset
113        CMP         r0,  r7          // if a3 == zero
114        ADD         r0,  r0, r5      // a3 += a_offset
115        LDR         r5, [sp, 68]     // kc
116        MOVEQ       r0,  r7          //   a3 = zero, else += a3 + a_offset
117
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        PLD         [r3, 128]        // Prefetch A0
171        VMLA.F32    q12, q4, d6[0]
172        VLD1.32    {d0}, [r3]!       // A0
173        VMLA.F32    q14, q4, d7[0]
174        PLD         [r12, 128]       // Prefetch A1
175        VMLA.F32     q9, q5, d4[0]
176        VLD1.32    {d1}, [r12]!      // A1
177        VMLA.F32    q11, q5, d5[0]
178        PLD         [r10, 128]       // Prefetch A2
179        VMLA.F32    q13, q5, d6[0]
180        VLD1.32    {d2}, [r10]!      // A2
181        VMLA.F32    q15, q5, d7[0]
182        PLD         [r0, 128]        // Prefetch A3
183        VMLA.F32     q8, q6, d4[1]
184        VLD1.32    {d3}, [ r0]!      // A3
185        VMLA.F32    q10, q6, d5[1]
186        PLD         [r9, 352]        // Prefetch B
187        VMLA.F32    q12, q6, d6[1]
188        PLD         [r9, 416]        // Prefetch B
189        VMLA.F32    q14, q6, d7[1]
190        VLDM        r9!, {d8-d11}    // B0
191        VMLA.F32     q9, q7, d4[1]
192        VMLA.F32    q11, q7, d5[1]
193        SUBS         r5, r5, 16
194        VMLA.F32    q13, q7, d6[1]
195        VMLA.F32    q15, q7, d7[1]
196        BHS         2b
197
198        // Epilogue
1993:
200        VMLA.F32     q8, q4, d0[0]
201        VLDM        r9!, {d12-d15}   // B1
202        VMLA.F32    q10, q4, d1[0]
203        VMLA.F32    q12, q4, d2[0]
204        VLD1.32    {d4}, [r3]!       // A0
205        VMLA.F32    q14, q4, d3[0]
206        VMLA.F32     q9, q5, d0[0]
207        VLD1.32    {d5}, [r12]!      // A1
208        VMLA.F32    q11, q5, d1[0]
209        VMLA.F32    q13, q5, d2[0]
210        VMLA.F32    q15, q5, d3[0]
211        VLD1.32    {d6}, [r10]!      // A2
212        VMLA.F32     q8, q6, d0[1]
213        VMLA.F32    q10, q6, d1[1]
214        VLD1.32    {d7}, [ r0]!      // A3
215        VMLA.F32    q12, q6, d2[1]
216        VMLA.F32    q14, q6, d3[1]
217        VLDM        r9!, {d8-d11}    // B0
218        VMLA.F32     q9, q7, d0[1]
219        VMLA.F32    q11, q7, d1[1]
220        VMLA.F32    q13, q7, d2[1]
221        VMLA.F32    q15, q7, d3[1]
222
223        VMLA.F32     q8, q4, d4[0]
224        VLDM        r9!, {d12-d15}   // B1
225        VMLA.F32    q10, q4, d5[0]
226        VMLA.F32    q12, q4, d6[0]
227        VMLA.F32    q14, q4, d7[0]
228        VMLA.F32     q9, q5, d4[0]
229        VMLA.F32    q11, q5, d5[0]
230        VMLA.F32    q13, q5, d6[0]
231        VMLA.F32    q15, q5, d7[0]
232        VMLA.F32     q8, q6, d4[1]
233        VMLA.F32    q10, q6, d5[1]
234        VMLA.F32    q12, q6, d6[1]
235        VMLA.F32    q14, q6, d7[1]
236        VMLA.F32     q9, q7, d4[1]
237        VMLA.F32    q11, q7, d5[1]
238        VMLA.F32    q13, q7, d6[1]
239        VMLA.F32    q15, q7, d7[1]
240
241        // Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
242        TST         r5, 12
243        BNE         5f
244
245        .p2align 3
2464:
247        # ks loop
248        SUBS r14, r14, 16  // ks -= MR * sizeof(void*)
249        BHI 1b
250
251        // Load params pointer
252        LDR          r5, [sp, 140]   // params
253        LDR          r7, [sp, 128]   // cn_stride
254        LDR         r14, [sp, 72]    // p = ks
255
256        // Load min/max values
257        VLD1.32     {d4[],d5[]}, [r5]!
258        SUBS        r1, r1, 8
259        VLD1.32     {d6[],d7[]}, [r5]
260
261        // Clamp
262        VMAX.F32     q8,  q8, q2
263        VMAX.F32     q9,  q9, q2
264        VMAX.F32    q10, q10, q2
265        VMAX.F32    q11, q11, q2
266        VMAX.F32    q12, q12, q2
267        VMAX.F32    q13, q13, q2
268        VMAX.F32    q14, q14, q2
269        VMAX.F32    q15, q15, q2
270        VMIN.F32     q8,  q8, q3
271        VMIN.F32     q9,  q9, q3
272        VMIN.F32    q10, q10, q3
273        VMIN.F32    q11, q11, q3
274        VMIN.F32    q12, q12, q3
275        VMIN.F32    q13, q13, q3
276        VMIN.F32    q14, q14, q3
277        VMIN.F32    q15, q15, q3
278
279        // Store full 4 x 8
280        BLO         7f
281        VST1.32     {d28-d31},  [r6], r7
282        VST1.32     {d24-d27},  [r8], r7
283        VST1.32     {d20-d23},  [r4], r7
284        VST1.32     {d16-d19}, [r11], r7
285        SUB         r2, r2, r14    // a -= ks
286        BHI         0b
287
288        VPOP        {d8-d15}
289        ADD         sp, sp, 12  // skip pad, r2, r3
290        POP         {r4, r5, r6, r7, r8, r9, r10, r11, pc}
291
292        .p2align 3
2935:
294        // Is there a remainder?- 2 floats of A (8 bytes)
295        TST         r5, 8
296        BEQ         6f
297
298        // Remainder - 2 floats of A (8 bytes)
299        VLD1.32    {d0}, [r3]!       // A0
300        VLDM        r9!, {d8-d11}    // B0
301        VLD1.32    {d1}, [r12]!      // A1
302        VLD1.32    {d2}, [r10]!      // A2
303        VLD1.32    {d3}, [ r0]!      // A3
304
305        VMLA.F32     q8, q4, d0[0]
306        VMLA.F32     q9, q5, d0[0]
307        VMLA.F32    q10, q4, d1[0]
308        VMLA.F32    q11, q5, d1[0]
309        VLDM        r9!, {d12-d15}   // B1
310        VMLA.F32    q12, q4, d2[0]
311        VMLA.F32    q13, q5, d2[0]
312        VMLA.F32    q14, q4, d3[0]
313        VMLA.F32    q15, q5, d3[0]
314        VMLA.F32     q8, q6, d0[1]
315        VMLA.F32     q9, q7, d0[1]
316        VMLA.F32    q10, q6, d1[1]
317        VMLA.F32    q11, q7, d1[1]
318        VMLA.F32    q12, q6, d2[1]
319        VMLA.F32    q13, q7, d2[1]
320        VMLA.F32    q14, q6, d3[1]
321        VMLA.F32    q15, q7, d3[1]
322
323        // Is there a remainder?- 1 floats of A (4 bytes)
324        TST         r5, 4
325        BEQ         4b
326
3276:
328        // Remainder- 1 floats of A (4 bytes)
329        VLDM        r3!, {s0}       // A0
330        VLDM        r9!, {d8-d11}   // B0
331        VLDM       r12!, {s2}       // A1
332        VLDM       r10!, {s4}       // A2
333        VLDM        r0!, {s6}       // A3
334        VMLA.F32     q8, q4, d0[0]
335        VMLA.F32     q9, q5, d0[0]
336        VMLA.F32    q10, q4, d1[0]
337        VMLA.F32    q11, q5, d1[0]
338        VMLA.F32    q12, q4, d2[0]
339        VMLA.F32    q13, q5, d2[0]
340        VMLA.F32    q14, q4, d3[0]
341        VMLA.F32    q15, q5, d3[0]
342        B           4b
343
344        // Store odd width
3457:
346        TST         r1, 4
347        BEQ         8f
348        VST1.32    {d28-d29},  [r6]!
349        VMOV        q14, q15
350        VST1.32    {d24-d25},  [r8]!
351        VMOV        q12, q13
352        VST1.32    {d20-d21},  [r4]!
353        VMOV        q10, q11
354        VST1.32    {d16-d17}, [r11]!
355        VMOV         q8,  q9
356
3578:
358        TST        r1, 2
359        BEQ        9f
360        VST1.32    {d28},  [r6]!
361        VMOV        d28, d29
362        VST1.32    {d24},  [r8]!
363        VMOV        d24, d25
364        VST1.32    {d20},  [r4]!
365        VMOV        d20, d21
366        VST1.32    {d16}, [r11]!
367        VMOV        d16, d17
368
3699:
370        TST         r1, 1
371        BEQ         10f
372        VST1.32    {d28[0]},  [r6]!
373        VST1.32    {d24[0]},  [r8]!
374        VST1.32    {d20[0]},  [r4]!
375        VST1.32    {d16[0]}, [r11]!
376
37710:
378        VPOP        {d8-d15}
379        ADD         sp, sp, 12  // skip pad, r2, r3
380        POP         {r4, r5, r6, r7, r8, r9, r10, r11, pc}
381
382END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_pld_cortex_a75
383
384#ifdef __ELF__
385.section ".note.GNU-stack","",%progbits
386#endif
387