1// Auto-generated file. Do not edit!
2//   Template: src/f32-igemm/4x8-minmax-aarch32-neon-cortex-a7.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_a7(
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_a7
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        LDR         r5, [sp, 140]    // params
62        MOV        r14, r3           // p = ks
63
64        // Clamp C pointers
65        CMP         r0, 2                 // if mr >= 2
66        ADD         r4, r11, r6           //   c1 = c0 + cm_stride
67        MOVLO       r4, r11               // c1
68                                          // if mr > 2
69        ADD         r8, r4, r6            //   c2 = c1 + cm_stride
70        MOVLS       r8, r4                // c2
71        CMP         r0, 4                 // if mr >=4
72        ADD         r6, r8, r6            //   c3 = c2 + cm_stride
73        MOVLO       r6, r8                // c3
74
75        // Load min/max values
76        VLD1.32     {d4[], d5[]}, [r5]!
77        VLD1.32     {d6[], d7[]}, [r5]
78
790:
80        # Load initial bias from w into accumulators
81        VLDM       r9!, {d16-d19}   // Bias
82        VMOV       q10, q8
83        VMOV       q11, q9
84        VMOV       q12, q8
85        VMOV       q13, q9
86        VMOV       q14, q8
87        VMOV       q15, q9
88
89        PLD         [r9,   0]  // Prefetch B
90        PLD         [r9,  64]
91        PLD         [r9, 128]
92        PLD         [r9, 192]
93        PLD         [r9, 256]
94        PLD         [r9, 320]
95        PLD         [r9, 384]
96        PLD         [r9, 448]
971:
98        # Load next 4 A pointers
99        LDR         r3, [r2,  0]
100        LDR        r12, [r2,  4]
101        LDR        r10, [r2,  8]
102        LDR         r0, [r2, 12]
103        ADD         r2, r2, 16
104
105        // Add a_offset
106        LDR         r5, [sp, 132]    // a_offset
107        LDR         r7, [sp, 136]    // zero
108        CMP         r3,  r7          // if a0 == zero
109        ADD         r3,  r3, r5      // a0 += a_offset
110        MOVEQ       r3,  r7          //   a0 = zero, else += a0 + a_offset
111        CMP        r12,  r7          // if a1 == zero
112        ADD        r12, r12, r5      // a1 += a_offset
113        MOVEQ      r12,  r7          //   a1 = zero, else += a1 + a_offset
114        CMP        r10,  r7          // if a2 == zero
115        ADD        r10, r10, r5      // a2 += a_offset
116        MOVEQ      r10,  r7          //   a2 = zero, else += a2 + a_offset
117        CMP         r0,  r7          // if a3 == zero
118        ADD         r0,  r0, r5      // a3 += a_offset
119        LDR         r5, [sp, 68]     // kc
120        MOVEQ       r0,  r7          //   a3 = zero, else += a3 + a_offset
121
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        PLD         [r9, 448]        // Prefetch B
161        PLD         [r3, 128]        // Prefetch A0
162        PLD         [r12, 128]       // Prefetch A1
163        PLD         [r10, 128]       // Prefetch A2
164        PLD         [r0, 128]        // Prefetch A3
165        BHS         2b
166
167        // Is there a remainder?- 1 floats of A (4 bytes)
168        TST         r5, 4
169        BNE         4f
170
1713:
172        # ks loop
173        SUBS        r14, r14, 16  // ks -= MR * sizeof(void*)
174        BHI         1b
175
176        LDR          r7, [sp, 128]   // cn_stride
177        LDR         r14, [sp, 72]    // p = ks
178
179        // Clamp
180        VMAX.F32     q8,  q8, q2
181        SUBS         r1, r1, 8
182        VMAX.F32     q9,  q9, q2
183        VMAX.F32    q10, q10, q2
184        VMAX.F32    q11, q11, q2
185        VMAX.F32    q12, q12, q2
186        VMAX.F32    q13, q13, q2
187        VMAX.F32    q14, q14, q2
188        VMAX.F32    q15, q15, q2
189        VMIN.F32     q8,  q8, q3
190        VMIN.F32     q9,  q9, q3
191        VMIN.F32    q10, q10, q3
192        VMIN.F32    q11, q11, q3
193        VMIN.F32    q12, q12, q3
194        VMIN.F32    q13, q13, q3
195        VMIN.F32    q14, q14, q3
196        VMIN.F32    q15, q15, q3
197
198        // Store full 4 x 8
199        BLO         5f
200        VST1.32     {d28-d31},  [r6], r7
201        VST1.32     {d24-d27},  [r8], r7
202        VST1.32     {d20-d23},  [r4], r7
203        VST1.32     {d16-d19}, [r11], r7
204        SUB         r2, r2, r14    // a -= ks
205        BHI         0b
206
207        VPOP        {d8-d15}
208        ADD         sp, sp, 12  // skip pad, r2, r3
209        POP         {r4, r5, r6, r7, r8, r9, r10, r11, pc}
210
2114:
212        // Remainder- 1 floats of A (4 bytes)
213        VLDM        r3!, {s0}       // A0
214        VLDM        r9!, {d8-d11}   // B0
215        VLDM       r12!, {s2}       // A1
216        VLDM       r10!, {s4}       // A2
217        VLDM        r0!, {s6}       // A3
218        VMLA.F32     q8, q4, d0[0]
219        VMLA.F32     q9, q5, d0[0]
220        VMLA.F32    q10, q4, d1[0]
221        VMLA.F32    q11, q5, d1[0]
222        VMLA.F32    q12, q4, d2[0]
223        VMLA.F32    q13, q5, d2[0]
224        VMLA.F32    q14, q4, d3[0]
225        VMLA.F32    q15, q5, d3[0]
226        B           3b
227
228        // Store odd width
2295:
230        TST         r1, 4
231        BEQ         6f
232        VST1.32    {d28-d29},  [r6]!
233        VMOV        q14, q15
234        VST1.32    {d24-d25},  [r8]!
235        VMOV        q12, q13
236        VST1.32    {d20-d21},  [r4]!
237        VMOV        q10, q11
238        VST1.32    {d16-d17}, [r11]!
239        VMOV         q8,  q9
240
2416:
242        TST        r1, 2
243        BEQ        7f
244        VST1.32    {d28},  [r6]!
245        VMOV        d28, d29
246        VST1.32    {d24},  [r8]!
247        VMOV        d24, d25
248        VST1.32    {d20},  [r4]!
249        VMOV        d20, d21
250        VST1.32    {d16}, [r11]!
251        VMOV        d16, d17
252
2537:
254        TST         r1, 1
255        BEQ         8f
256        VST1.32    {d28[0]},  [r6]!
257        VST1.32    {d24[0]},  [r8]!
258        VST1.32    {d20[0]},  [r4]!
259        VST1.32    {d16[0]}, [r11]!
260
2618:
262        VPOP        {d8-d15}
263        ADD         sp, sp, 12  // skip pad, r2, r3
264        POP         {r4, r5, r6, r7, r8, r9, r10, r11, pc}
265
266END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_cortex_a7
267
268#ifdef __ELF__
269.section ".note.GNU-stack","",%progbits
270#endif
271