1// Auto-generated file. Do not edit!
2//   Template: src/qs8-igemm/1x8-aarch32-neon-mlal-lane-cortex-a7.S.in
3//   Generator: tools/xngen
4//
5// Copyright 2021 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
11#include <xnnpack/assembly.h>
12
13.syntax unified
14
15// void xnn_qc8_igemm_minmax_fp32_ukernel_1x8__aarch32_neon_mlal_lane_prfm_cortex_a7
16//     size_t mr,                                     (r0)
17//     size_t nc,                                      r1
18//     size_t kc,                                     (r2) -> sp + 56 -> r5
19//     size_t ks,                                     (r3) -> sp + 60 -> r14
20//     const int8_t**restrict a,            sp + 88  -> r2
21//     const void*restrict w,              sp + 92  -> r9
22//     int8_t*restrict c,                   sp + 96  -> r11
23//     size_t cm_stride,                   sp + 100  -> r6
24//     size_t cn_stride,                   sp + 104  -> r12
25//     size_t a_offset,                    sp + 108 -> (r5)
26//     const int8_t* zero,                  sp + 112 -> r7
27//     xnn_qs8_minmax_params*params); sp + 116 -> (r5)
28
29// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
30
31// Based on cortex_a53 microkernel but with Neon loads
32
33// Register usage
34// A0   r3  d0-d1 q0
35
36// B    r9  d8-d9 q4 q5
37
38// C0  r11 d16-d17  q8  d18-d19  q9
39//         q2, q3 acc2
40
41// Unused r4, r8, r10, d15, q10-q15, q1-q3
42
43// params structure is 10 bytes
44// struct {
45//   float magic_bias;                           d12[0]
46//   int32_t magic_bias_less_output_zero_point;  d12[1]
47//   int8_t output_min;                          d13[6]
48//   int8_t output_max;                          d13[7]
49// } xnn_qs8_minmax_params.neon;
50
51BEGIN_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_1x8__aarch32_neon_mlal_lane_prfm_cortex_a7
52        # Push 88 bytes
53        # r2, r3 will be reloaded in outer loop.
54        PUSH    {r2, r3, r5, r6, r7, r9, r11, lr}     // +32
55        SUB     sp, sp, 8                           // +8
56        VPUSH   {d8-d13}                            // +48 = 88
57
58        LDR     r2,  [sp, 88]           // a
59        LDR     r9,  [sp, 92]           // w
60        LDR     r11, [sp, 96]           // c
61        LDR     r6,  [sp, 100]          // cm_stride
62        LDR     r12, [sp, 104]          // cn_stride
63        LDR     r7,  [sp, 112]          // zero
64        LDR     r5,  [sp, 116]          // params
65        MOV     r14, r3                 // p = ks
66
67        # Load params values
68        VLDM    r5!, {d12}              // QC8 neon params
69        VLD1.16 {d13[]}, [r5]
70
71        PLD     [r9,  64]               // Prefetch B
72        PLD     [r9, 112]
73        PLD     [r9, 192]
74        PLD     [r9, 256]
75        PLD     [r9, 320]
76        PLD     [r9, 384]
77
78        .p2align 3
790:
80        # Load initial bias from w into accumulators
81        VLDM    r9!, {d16-d19}          // Bias
82        VMOV.I32 q2, 0                  // second set of C for pipelining FMLA
83        VMOV.I32 q3, 0
84
85        .p2align 3
861:
87        # Load next A pointer
88        LDR     r3, [r2,  0]
89
90        # Add a_offset
91        LDR     r5, [sp, 108]           // a_offset
92        ADD     r2, r2, 4
93        CMP     r3,  r7                 // if a0 == zero
94        ADD     r3,  r3, r5             // a0 += a_offset
95        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
96
97        LDR     r5, [sp, 56]            // kc
98        SUBS    r5, r5, 8               // kc - 8
99        BLO     5f                      // less than 8 channels?
100
101        // Prologue - load A0 and B0
102        VLD1.8  {d0},  [r3]!            // A0
103        SUBS    r5, r5, 8               // k = k - 8
104        VLD1.8  {d8},  [r9]!            // B0
105        BLO     3f                      // less than 8 channels?
106
107        // Main loop - 8 bytes
108        // 64 bytes for weights.
109
110        .p2align 3
1112:
112        // Extend
113        VMOVL.S8 q0, d0
114        VMOVL.S8 q4, d8
115        PLD     [r9, 448]
116
117        // BLOCK 0
118        VLD1.8  {d10},  [r9]!           // B1
119        VMLAL.S16 q8, d8, d0[0]
120        VMLAL.S16 q9, d9, d0[0]
121        VMOVL.S8 q5, d10
122
123        // BLOCK 1
124        VLD1.8  {d8},  [r9]!            // B2
125        VMLAL.S16 q2, d10, d0[1]
126        VMLAL.S16 q3, d11, d0[1]
127        VMOVL.S8 q4, d8
128
129        // BLOCK 2
130        VLD1.8  {d10},  [r9]!           // B3
131        VMLAL.S16 q8, d8, d0[2]
132        VMLAL.S16 q9, d9, d0[2]
133        VMOVL.S8 q5, d10
134
135        // BLOCK 3
136        VLD1.8  {d8},  [r9]!            // B4
137        VMLAL.S16 q2, d10, d0[3]
138        VMLAL.S16 q3, d11, d0[3]
139        VLD1.8  {d0},  [r3]!            // A0
140        VMOVL.S8 q4, d8
141
142        // BLOCK 4
143        VLD1.8  {d10},  [r9]!           // B5
144        VMLAL.S16 q8, d8, d1[0]
145        VMLAL.S16 q9, d9, d1[0]
146        VMOVL.S8 q5, d10
147
148        // BLOCK 5
149        VLD1.8  {d8},  [r9]!            // B6
150        VMLAL.S16 q2, d10, d1[1]
151        VMLAL.S16 q3, d11, d1[1]
152        VMOVL.S8 q4, d8
153
154        // BLOCK 6
155        VLD1.8  {d10},  [r9]!           // B7
156        VMLAL.S16 q8, d8, d1[2]
157        VMLAL.S16 q9, d9, d1[2]
158        VMOVL.S8 q5, d10
159        SUBS    r5, r5, 8
160
161        // BLOCK 7
162        VLD1.8  {d8},  [r9]!            // B0
163        VMLAL.S16 q2, d10, d1[3]
164        VMLAL.S16 q3, d11, d1[3]
165        BHS     2b
166
167        // Epilogue
168
169        .p2align 3
1703:
171        // Extend
172        VMOVL.S8 q0, d0
173        VMOVL.S8 q4, d8
174        PLD     [r9, 448]
175
176        // BLOCK 0
177        VLD1.8  {d10},  [r9]!           // B1
178        VMLAL.S16 q8, d8, d0[0]
179        VMLAL.S16 q9, d9, d0[0]
180        VMOVL.S8 q5, d10
181
182        // BLOCK 1
183        VLD1.8  {d8},  [r9]!            // B2
184        VMLAL.S16 q2, d10, d0[1]
185        VMLAL.S16 q3, d11, d0[1]
186        VMOVL.S8 q4, d8
187
188        // BLOCK 2
189        VLD1.8  {d10},  [r9]!           // B3
190        VMLAL.S16 q8, d8, d0[2]
191        VMLAL.S16 q9, d9, d0[2]
192        VMOVL.S8 q5, d10
193
194        // BLOCK 3
195        VLD1.8  {d8},  [r9]!            // B4
196        VMLAL.S16 q2, d10, d0[3]
197        VMLAL.S16 q3, d11, d0[3]
198        VMOVL.S8 q4, d8
199
200        // BLOCK 4
201        VLD1.8  {d10},  [r9]!           // B5
202        VMLAL.S16 q8, d8, d1[0]
203        VMLAL.S16 q9, d9, d1[0]
204        VMOVL.S8 q5, d10
205
206        // BLOCK 5
207        VLD1.8  {d8},  [r9]!            // B6
208        VMLAL.S16 q2, d10, d1[1]
209        VMLAL.S16 q3, d11, d1[1]
210        VMOVL.S8 q4, d8
211
212        // BLOCK 6
213        VLD1.8  {d10},  [r9]!           // B7
214        VMLAL.S16 q8, d8, d1[2]
215        VMLAL.S16 q9, d9, d1[2]
216        VMOVL.S8 q5, d10
217        ADDS    r5, r5, 8
218
219        VMLAL.S16 q2, d10, d1[3]
220        VMLAL.S16 q3, d11, d1[3]
221
222        # Is there a remainder?- 1-7 bytes of A
223        BNE     6f
224
2254:
226        # ks loop
227        SUBS    r14, r14, 4             // ks -= MR * sizeof(void*)
228        BHI     1b
229
230        LDR     r14, [sp, 60]           // p = ks
231
232        VADD.S32 q8, q8, q2
233        VADD.S32 q9, q9, q3
234
235        # QC8 FP32 quantization
236        VLD1.8  {q0-q1},  [r9]!
237
238        VDUP.32 q2, d12[0]              // magic_bias
239        VDUP.32 q3, d12[1]              // magic_bias_less_output_zero_point
240
241        VCVT.F32.S32 q8,  q8
242        VCVT.F32.S32 q9,  q9
243
244        VMUL.F32 q8,  q8, q0            // multiplier
245        VMUL.F32 q9,  q9, q1
246
247        VADD.F32 q8,  q8, q2            // magic_bias
248        VADD.F32 q9,  q9, q2
249
250        VQSUB.S32 q8,  q8, q3           // magic_bias_less_output_zero_point
251        VQSUB.S32 q9,  q9, q3
252
253
254        VQMOVN.S32 d16, q8
255        VQMOVN.S32 d17, q9
256
257
258        VDUP.8  d24, d13[6]             // output_min
259
260        VQMOVN.S16 d0,  q8
261
262        VDUP.8  d25, d13[7]             // output_max
263
264        VMAX.S8 d0, d0, d24
265
266        SUBS    r1, r1, 8
267
268        VMIN.S8 d0, d0, d25
269
270        # Store full 1 x 8
271        BLO     7f
272        VST1.8  {d0}, [r11], r12
273        SUB     r2, r2, r14             // a -= ks
274        BHI     0b
275
276        VPOP    {d8-d13}
277        ADD     sp, sp, 16              // skip pad of 8, r2, r3
278        POP     {r5, r6, r7, r9, r11, pc}
279
280        # Remainder- 1 to 7 bytes of A
281        .p2align 3
2825:
283        AND     r5, r5, 7               // kc remainder 1 to 7
2846:
285        VLD1.8  {d0},  [r3]
286        VLD1.8  {d8},  [r9]!
287
288        VMOVL.S8 q0, d0
289        VMOVL.S8 q4, d8
290        VMLAL.S16 q8, d8, d0[0]
291        VMLAL.S16 q9, d9, d0[0]
292        CMP     r5, 2
293        BLO     4b
294
295        VLD1.8  {d8},  [r9]!
296        VMOVL.S8 q4, d8
297        VMLAL.S16 q8, d8, d0[1]
298        VMLAL.S16 q9, d9, d0[1]
299        BEQ     4b
300
301        VLD1.8  {d8},  [r9]!
302        VMOVL.S8 q4, d8
303        VMLAL.S16 q8, d8, d0[2]
304        VMLAL.S16 q9, d9, d0[2]
305        CMP     r5, 4
306        BLO     4b
307
308        VLD1.8  {d8},  [r9]!
309        VMOVL.S8 q4, d8
310        VMLAL.S16 q8, d8, d0[3]
311        VMLAL.S16 q9, d9, d0[3]
312        BEQ     4b
313
314        VLD1.8  {d8},  [r9]!
315        VMOVL.S8 q4, d8
316        VMLAL.S16 q8, d8, d1[0]
317        VMLAL.S16 q9, d9, d1[0]
318        CMP     r5, 6
319        BLO     4b
320
321        VLD1.8  {d8},  [r9]!
322        VMOVL.S8 q4, d8
323        VMLAL.S16 q8, d8, d1[1]
324        VMLAL.S16 q9, d9, d1[1]
325        BEQ     4b
326
327        VLD1.8  {d8},  [r9]!
328        VMOVL.S8 q4, d8
329        VMLAL.S16 q8, d8, d1[2]
330        VMLAL.S16 q9, d9, d1[2]
331        B       4b
332
333        # Store odd width
334        .p2align 3
3357:
336        TST     r1, 4
337        BEQ     8f
338        VST1.32 {d0[0]}, [r11]!
339        VEXT.8  q0, q0, q0, 4
3408:
341        TST     r1, 2
342        BEQ     9f
343        VST1.16 {d0[0]}, [r11]!
344        VEXT.8  q0, q0, q0, 2
345
3469:
347        TST     r1, 1
348        BEQ     10f
349        VST1.8  {d0[0]}, [r11]
350
35110:
352        VPOP    {d8-d13}
353        ADD     sp, sp, 16              // skip pad of 8, r2, r3
354        POP     {r5, r6, r7, r9, r11, pc}
355
356END_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_1x8__aarch32_neon_mlal_lane_prfm_cortex_a7
357
358#ifdef __ELF__
359.section ".note.GNU-stack","",%progbits
360#endif
361