1// Auto-generated file. Do not edit!
2//   Template: src/qs8-igemm/4x8-aarch32-neon-mlal-lane-cortex-a53.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_4x8__aarch32_neon_mlal_lane_prfm_cortex_a53
16//     size_t mr,                                     (r0)
17//     size_t nc,                                      r1 -> sp + 56
18//     size_t kc,                                     (r2) -> r5 -> sp + 60
19//     size_t ks,                                     (r3) -> sp + 64 -> r14
20//     const int8_t**restrict a,            sp + 104  -> r2
21//     const void*restrict w,              sp + 108  -> r9
22//     int8_t*restrict c,                   sp + 112  -> r11
23//     size_t cm_stride,                   sp + 116  -> (r6)
24//     size_t cn_stride,                   sp + 120  -> (r7)
25//     size_t a_offset,                    sp + 124 -> (r5)
26//     const int8_t* zero,                  sp + 128 -> (r7)
27//     xnn_qs8_minmax_params*params); sp + 132 -> (r5)
28
29// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
30
31// Register usage
32// A0   r3  d0-d1 q0
33// A1  r12  d2-d3 q1
34// A2  r10  d4-d5 q2
35// A3   r0  d6-d7 q3
36
37// B    r9  d8-d9 q4 q5
38
39// C0  r11 d16-d17  q8  d18-d19  q9
40// C1   r4 d20-d21 q10  d22-d23 q11
41// C2   r8 d24-d25 q12  d26-d27 q13
42// C3   r6 d28-d29 q14  d30-d31 q15
43
44// r1,r7 A53 gpr temporary loads
45// Unused d15
46
47// params structure is 10 bytes
48// struct {
49//   float magic_bias;                           d12[0]
50//   int32_t magic_bias_less_output_zero_point;  d12[1]
51//   int8_t output_min;                          d13[6]
52//   int8_t output_max;                          d13[7]
53// } xnn_qs8_minmax_params.neon;
54
55BEGIN_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a53
56        # Push 104 bytes
57        # r1, r2 will be reloaded in outer loop.  r3 is ks
58        PUSH    {r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}   // +48
59        SUB     sp, sp, 8                           // +8
60        VPUSH   {d8-d13}                            // +48 = 104
61
62        LDR     r11, [sp, 112]          // c
63        LDR     r6, [sp, 116]           // cm_stride
64        LDR     r2, [sp, 104]           // a
65        LDR     r9, [sp, 108]           // w
66        LDR     r5, [sp, 132]           // params
67        MOV     r14, r3                 // p = ks
68
69        # Clamp C pointers
70        CMP     r0, 2                   // if mr >= 2
71        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
72        MOVLO   r4, r11                 // c1
73                                        // if mr > 2
74        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
75        MOVLS   r8, r4                  // c2
76        CMP     r0, 4                   // if mr >=4
77        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
78        MOVLO   r6, r8                  // c3
79
80        # Load params values
81        VLDM    r5!, {d12}              // QC8 neon params
82        VLD1.16 {d13[]}, [r5]
83
84        PLD     [r9,  64]               // Prefetch B
85        PLD     [r9, 128]
86        PLD     [r9, 192]
87        PLD     [r9, 256]
88        PLD     [r9, 320]
89        PLD     [r9, 384]
90
91        .p2align 3
920:
93        # Load initial bias from w into accumulators
94        VLDM    r9!, {d16-d19}          // Bias
95        VMOV    q10, q8
96        VMOV    q11, q9
97        STR     r1, [sp, 56]            // save nc
98        VMOV    q12, q8
99        VMOV    q13, q9
100        VMOV    q14, q8
101        VMOV    q15, q9
102
103        .p2align 3
1041:
105        # Load next 4 A pointers
106        LDR     r3, [r2,  0]
107        LDR     r12, [r2,  4]
108        LDR     r10, [r2,  8]
109        LDR     r0, [r2, 12]
110
111        # Add a_offset
112        LDR     r5, [sp, 124]           // a_offset
113        LDR     r7, [sp, 128]           // zero
114        ADD     r2, r2, 16
115        CMP     r3,  r7                 // if a0 == zero
116        ADD     r3,  r3, r5             // a0 += a_offset
117        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
118        CMP     r12,  r7                // if a1 == zero
119        ADD     r12, r12, r5            // a1 += a_offset
120        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
121        CMP     r10,  r7                // if a2 == zero
122        ADD     r10, r10, r5            // a2 += a_offset
123        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
124        CMP     r0,  r7                 // if a3 == zero
125        ADD     r0,  r0, r5             // a3 += a_offset
126        LDR     r5, [sp, 60]            // kc
127        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
128        SUBS    r5, r5, 8               // kc - 8
129        BLO     5f                      // less than 8 channels?
130
131        // Prologue - load 4A's and B0
132        VLD1.8  {d0},  [r3]!            // A0
133        VLD1.8  {d8},  [r9]!            // B0
134        SUBS    r5, r5, 8               // k = k - 8
135        VLD1.8  {d2}, [r12]!            // A1
136        VLD1.8  {d4}, [r10]!            // A2
137        VLD1.8  {d6},  [r0]!            // A3
138        BLO     3f                      // less than 8 channels?
139
140        // Main loop - 8 bytes
141        // 64 bytes for weights.
142        // 5 VMOVL = 4 A and 1 B = 5 cycles
143        // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles
144        // 1 blocks with VLD B, VMLA = 9 cycles
145        // total = 84 cycles
146        .p2align 3
1472:
148        // Extend - 5 cycles
149        VMOVL.S8 q0, d0
150        PLD     [r3, 128]
151        VMOVL.S8 q4, d8
152        PLD     [r9, 448]
153        VMOVL.S8 q1, d2
154        PLD     [r12, 128]
155        VMOVL.S8 q2, d4
156        PLD     [r0, 128]
157        VMOVL.S8 q3, d6
158        PLD     [r10, 128]
159
160        // BLOCK 0 - 10 cycles
161        VLD1.8  {d10},  [r9]!           // B1
162        VMLAL.S16 q8, d8, d0[0]
163        VMLAL.S16 q9, d9, d0[0]
164        VMLAL.S16 q10, d8, d2[0]
165        VMLAL.S16 q11, d9, d2[0]
166        VMOVL.S8 q5, d10
167        VMLAL.S16 q12, d8, d4[0]
168        VMLAL.S16 q13, d9, d4[0]
169        VMLAL.S16 q14, d8, d6[0]
170        VMLAL.S16 q15, d9, d6[0]
171
172        // BLOCK 1 - 10 cycles
173        VLD1.8  {d8},  [r9]!            // B2
174        VMLAL.S16 q8, d10, d0[1]
175        VMLAL.S16 q9, d11, d0[1]
176        VMLAL.S16 q10, d10, d2[1]
177        VMLAL.S16 q11, d11, d2[1]
178        VMOVL.S8 q4, d8
179        VMLAL.S16 q12, d10, d4[1]
180        VMLAL.S16 q13, d11, d4[1]
181        VMLAL.S16 q14, d10, d6[1]
182        VMLAL.S16 q15, d11, d6[1]
183
184        // BLOCK 2 - 10 cycles
185        VLD1.8  {d10},  [r9]!           // B3
186        VMLAL.S16 q8, d8, d0[2]
187        VMLAL.S16 q9, d9, d0[2]
188        VMLAL.S16 q10, d8, d2[2]
189        VMLAL.S16 q11, d9, d2[2]
190        VMOVL.S8 q5, d10
191        VMLAL.S16 q12, d8, d4[2]
192        VMLAL.S16 q13, d9, d4[2]
193        VMLAL.S16 q14, d8, d6[2]
194        VMLAL.S16 q15, d9, d6[2]
195
196        // BLOCK 3 - 10 cycles
197        VLD1.8  {d8},  [r9]!            // B4
198        VMLAL.S16 q8, d10, d0[3]
199        VMLAL.S16 q9, d11, d0[3]
200        VMLAL.S16 q10, d10, d2[3]
201        VMLAL.S16 q11, d11, d2[3]
202        VMOVL.S8 q4, d8
203        VMLAL.S16 q12, d10, d4[3]
204        LDR     r1, [r3]                // A0 low
205        VMLAL.S16 q13, d11, d4[3]
206        LDR     r7, [r3, 4]             // A0 high
207        VMLAL.S16 q14, d10, d6[3]
208        ADD     r3, r3, 8
209        VMLAL.S16 q15, d11, d6[3]
210
211        // BLOCK 4 - 10 cycles
212        VLD1.8  {d10},  [r9]!           // B5
213        VMOV    d0, r1, r7              // A0 VMOV
214        VMLAL.S16 q8, d8, d1[0]
215        VMLAL.S16 q9, d9, d1[0]
216        VMLAL.S16 q10, d8, d3[0]
217        VMLAL.S16 q11, d9, d3[0]
218        VMOVL.S8 q5, d10
219        VMLAL.S16 q12, d8, d5[0]
220        LDR     r1, [r12]               // A1 low
221        VMLAL.S16 q13, d9, d5[0]
222        LDR     r7, [r12, 4]            // A1 high
223        VMLAL.S16 q14, d8, d7[0]
224        ADD     r12, r12, 8
225        VMLAL.S16 q15, d9, d7[0]
226
227        // BLOCK 5 - 10 cycles
228        VLD1.8  {d8},  [r9]!            // B6
229        VMOV    d2, r1, r7              // A1 VMOV
230        VMLAL.S16 q8, d10, d1[1]
231        VMLAL.S16 q9, d11, d1[1]
232        VMLAL.S16 q10, d10, d3[1]
233        VMLAL.S16 q11, d11, d3[1]
234        VMOVL.S8 q4, d8
235        VMLAL.S16 q12, d10, d5[1]
236        LDR     r1, [r10]               // A2 low
237        VMLAL.S16 q13, d11, d5[1]
238        LDR     r7, [r10, 4]            // A2 high
239        VMLAL.S16 q14, d10, d7[1]
240        ADD     r10, r10, 8
241        VMLAL.S16 q15, d11, d7[1]
242
243        // BLOCK 6 - 10 cycles
244        VLD1.8  {d10},  [r9]!           // B7
245        VMOV    d4, r1, r7              // A2 VMOV
246        VMLAL.S16 q8, d8, d1[2]
247        VMLAL.S16 q9, d9, d1[2]
248        VMLAL.S16 q10, d8, d3[2]
249        VMLAL.S16 q11, d9, d3[2]
250        VMOVL.S8 q5, d10
251        VMLAL.S16 q12, d8, d5[2]
252        LDR     r1, [r0]                // A3 low
253        VMLAL.S16 q13, d9, d5[2]
254        LDR     r7, [r0, 4]             // A3 high
255        VMLAL.S16 q14, d8, d7[2]
256        ADD     r0, r0, 8
257        VMLAL.S16 q15, d9, d7[2]
258
259        // BLOCK 7 - 9 cycles
260        VLD1.8  {d8},  [r9]!            // B0
261        VMOV    d6, r1, r7              // A3 VMOV
262        VMLAL.S16 q8, d10, d1[3]
263        VMLAL.S16 q9, d11, d1[3]
264        VMLAL.S16 q10, d10, d3[3]
265        VMLAL.S16 q11, d11, d3[3]
266        VMLAL.S16 q12, d10, d5[3]
267        VMLAL.S16 q13, d11, d5[3]
268        SUBS    r5, r5, 8
269        VMLAL.S16 q14, d10, d7[3]
270        VMLAL.S16 q15, d11, d7[3]
271        BHS     2b
272
273        // Epilogue
274
275        .p2align 3
2763:
277        VMOVL.S8 q0, d0
278        VMOVL.S8 q4, d8
279        VMOVL.S8 q1, d2
280        VMOVL.S8 q2, d4
281        VMOVL.S8 q3, d6
282
283        VLD1.8  {d10},  [r9]!           // B1
284        VMLAL.S16 q8, d8, d0[0]
285        VMLAL.S16 q9, d9, d0[0]
286        VMLAL.S16 q10, d8, d2[0]
287        VMLAL.S16 q11, d9, d2[0]
288        VMOVL.S8 q5, d10
289        VMLAL.S16 q12, d8, d4[0]
290        VMLAL.S16 q13, d9, d4[0]
291        VMLAL.S16 q14, d8, d6[0]
292        VMLAL.S16 q15, d9, d6[0]
293
294        VLD1.8  {d8},  [r9]!            // B2
295        VMLAL.S16 q8, d10, d0[1]
296        VMLAL.S16 q9, d11, d0[1]
297        VMLAL.S16 q10, d10, d2[1]
298        VMLAL.S16 q11, d11, d2[1]
299        VMOVL.S8 q4, d8
300        VMLAL.S16 q12, d10, d4[1]
301        VMLAL.S16 q13, d11, d4[1]
302        VMLAL.S16 q14, d10, d6[1]
303        VMLAL.S16 q15, d11, d6[1]
304
305        VLD1.8  {d10},  [r9]!           // B3
306        VMLAL.S16 q8, d8, d0[2]
307        VMLAL.S16 q9, d9, d0[2]
308        VMLAL.S16 q10, d8, d2[2]
309        VMLAL.S16 q11, d9, d2[2]
310        VMOVL.S8 q5, d10
311        VMLAL.S16 q12, d8, d4[2]
312        VMLAL.S16 q13, d9, d4[2]
313        VMLAL.S16 q14, d8, d6[2]
314        VMLAL.S16 q15, d9, d6[2]
315
316        VLD1.8  {d8},  [r9]!            // B4
317        VMLAL.S16 q8, d10, d0[3]
318        VMLAL.S16 q9, d11, d0[3]
319        VMLAL.S16 q10, d10, d2[3]
320        VMLAL.S16 q11, d11, d2[3]
321        VMOVL.S8 q4, d8
322        VMLAL.S16 q12, d10, d4[3]
323        VMLAL.S16 q13, d11, d4[3]
324        VMLAL.S16 q14, d10, d6[3]
325        VMLAL.S16 q15, d11, d6[3]
326
327        VLD1.8  {d10},  [r9]!           // B5
328        VMLAL.S16 q8, d8, d1[0]
329        VMLAL.S16 q9, d9, d1[0]
330        VMLAL.S16 q10, d8, d3[0]
331        VMLAL.S16 q11, d9, d3[0]
332        VMOVL.S8 q5, d10
333        VMLAL.S16 q12, d8, d5[0]
334        VMLAL.S16 q13, d9, d5[0]
335        VMLAL.S16 q14, d8, d7[0]
336        VMLAL.S16 q15, d9, d7[0]
337
338        VLD1.8  {d8},  [r9]!            // B6
339        VMLAL.S16 q8, d10, d1[1]
340        VMLAL.S16 q9, d11, d1[1]
341        VMLAL.S16 q10, d10, d3[1]
342        VMLAL.S16 q11, d11, d3[1]
343        VMOVL.S8 q4, d8
344        VMLAL.S16 q12, d10, d5[1]
345        VMLAL.S16 q13, d11, d5[1]
346        VMLAL.S16 q14, d10, d7[1]
347        VMLAL.S16 q15, d11, d7[1]
348
349        VLD1.8  {d10},  [r9]!           // B7
350        VMLAL.S16 q8, d8, d1[2]
351        VMLAL.S16 q9, d9, d1[2]
352        VMLAL.S16 q10, d8, d3[2]
353        VMLAL.S16 q11, d9, d3[2]
354        VMOVL.S8 q5, d10
355        VMLAL.S16 q12, d8, d5[2]
356        VMLAL.S16 q13, d9, d5[2]
357        VMLAL.S16 q14, d8, d7[2]
358        VMLAL.S16 q15, d9, d7[2]
359
360        VMLAL.S16 q8, d10, d1[3]
361        VMLAL.S16 q9, d11, d1[3]
362        VMLAL.S16 q10, d10, d3[3]
363        VMLAL.S16 q11, d11, d3[3]
364        VMLAL.S16 q12, d10, d5[3]
365        VMLAL.S16 q13, d11, d5[3]
366        ADDS    r5, r5, 8
367        VMLAL.S16 q14, d10, d7[3]
368        VMLAL.S16 q15, d11, d7[3]
369
370        # Is there a remainder?- 1-7 bytes of A
371        BNE     6f
372
3734:
374        # ks loop
375        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
376        BHI     1b
377
378        LDR     r7, [sp, 120]           // cn_stride
379        LDR     r14, [sp, 64]           // p = ks
380
381        # QC8 FP32 quantization
382        VLD1.8  {q0-q1},  [r9]!
383
384        VDUP.32 q2, d12[0]              // magic_bias
385        VDUP.32 q3, d12[1]              // magic_bias_less_output_zero_point
386
387        VCVT.F32.S32 q8,  q8
388        VCVT.F32.S32 q9,  q9
389        VCVT.F32.S32 q10, q10
390        VCVT.F32.S32 q11, q11
391        VCVT.F32.S32 q12, q12
392        VCVT.F32.S32 q13, q13
393        VCVT.F32.S32 q14, q14
394        VCVT.F32.S32 q15, q15
395
396        VMUL.F32 q8,  q8, q0            // multiplier
397        VMUL.F32 q9,  q9, q1
398        VMUL.F32 q10, q10, q0
399        VMUL.F32 q11, q11, q1
400        VMUL.F32 q12, q12, q0
401        VMUL.F32 q13, q13, q1
402        VMUL.F32 q14, q14, q0
403        VMUL.F32 q15, q15, q1
404
405        VADD.F32 q8,  q8, q2            // magic_bias
406        VADD.F32 q9,  q9, q2
407        VADD.F32 q10, q10, q2
408        VADD.F32 q11, q11, q2
409        VADD.F32 q12, q12, q2
410        VADD.F32 q13, q13, q2
411        VADD.F32 q14, q14, q2
412        VADD.F32 q15, q15, q2
413
414        VQSUB.S32 q8,  q8, q3           // magic_bias_less_output_zero_point
415        VQSUB.S32 q9,  q9, q3
416        VQSUB.S32 q10, q10, q3
417        VQSUB.S32 q11, q11, q3
418        VQSUB.S32 q12, q12, q3
419        VQSUB.S32 q13, q13, q3
420        VQSUB.S32 q14, q14, q3
421        VQSUB.S32 q15, q15, q3
422
423
424        VQMOVN.S32 d16, q8
425        VQMOVN.S32 d17, q9
426        VQMOVN.S32 d18, q10
427        VQMOVN.S32 d19, q11
428        VQMOVN.S32 d20, q12
429        VQMOVN.S32 d21, q13
430        VQMOVN.S32 d22, q14
431        VQMOVN.S32 d23, q15
432
433
434        LDR     r1, [sp, 56]            // restore nc
435        VDUP.8  q12, d13[6]             // output_min
436
437        VQMOVN.S16 d0,  q8
438        VQMOVN.S16 d1,  q9
439        VQMOVN.S16 d2, q10
440        VQMOVN.S16 d3, q11
441
442        VDUP.8  q13, d13[7]             // output_max
443
444        VMAX.S8 q0, q0, q12
445        VMAX.S8 q1, q1, q12
446
447        SUBS    r1, r1, 8               // nc -= 8
448
449        VMIN.S8 q0, q0, q13
450        VMIN.S8 q1, q1, q13
451
452        # Store full 4 x 8
453        BLO     7f
454        VST1.8  {d3}, [r6], r7
455        VST1.8  {d2}, [r8], r7
456        VST1.8  {d1}, [r4], r7
457        VST1.8  {d0}, [r11], r7
458        SUB     r2, r2, r14             // a -= ks
459        BHI     0b
460
461        VPOP    {d8-d13}
462        ADD     sp, sp, 20              // skip pad of 8, r1, r2, r3
463        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
464
465        # Remainder- 1 to 7 bytes of A
466        .p2align 3
4675:
468        AND     r5, r5, 7               // kc remainder 1 to 7
4696:
470        VLD1.8  {d0},  [r3]
471        VLD1.8  {d8},  [r9]!
472        VLD1.8  {d2}, [r12]
473        VLD1.8  {d4}, [r10]
474        VLD1.8  {d6},  [r0]
475
476        VMOVL.S8 q0, d0
477        VMOVL.S8 q4, d8
478        VMOVL.S8 q1, d2
479        VMOVL.S8 q2, d4
480        VMOVL.S8 q3, d6
481        VMLAL.S16 q8, d8, d0[0]
482        VMLAL.S16 q9, d9, d0[0]
483        VMLAL.S16 q10, d8, d2[0]
484        VMLAL.S16 q11, d9, d2[0]
485        VMLAL.S16 q12, d8, d4[0]
486        VMLAL.S16 q13, d9, d4[0]
487        VMLAL.S16 q14, d8, d6[0]
488        VMLAL.S16 q15, d9, d6[0]
489        CMP     r5, 2
490        BLO     4b
491
492        VLD1.8  {d8},  [r9]!
493        VMOVL.S8 q4, d8
494        VMLAL.S16 q8, d8, d0[1]
495        VMLAL.S16 q9, d9, d0[1]
496        VMLAL.S16 q10, d8, d2[1]
497        VMLAL.S16 q11, d9, d2[1]
498        VMLAL.S16 q12, d8, d4[1]
499        VMLAL.S16 q13, d9, d4[1]
500        VMLAL.S16 q14, d8, d6[1]
501        VMLAL.S16 q15, d9, d6[1]
502        BEQ     4b
503
504        VLD1.8  {d8},  [r9]!
505        VMOVL.S8 q4, d8
506        VMLAL.S16 q8, d8, d0[2]
507        VMLAL.S16 q9, d9, d0[2]
508        VMLAL.S16 q10, d8, d2[2]
509        VMLAL.S16 q11, d9, d2[2]
510        VMLAL.S16 q12, d8, d4[2]
511        VMLAL.S16 q13, d9, d4[2]
512        VMLAL.S16 q14, d8, d6[2]
513        VMLAL.S16 q15, d9, d6[2]
514        CMP     r5, 4
515        BLO     4b
516
517        VLD1.8  {d8},  [r9]!
518        VMOVL.S8 q4, d8
519        VMLAL.S16 q8, d8, d0[3]
520        VMLAL.S16 q9, d9, d0[3]
521        VMLAL.S16 q10, d8, d2[3]
522        VMLAL.S16 q11, d9, d2[3]
523        VMLAL.S16 q12, d8, d4[3]
524        VMLAL.S16 q13, d9, d4[3]
525        VMLAL.S16 q14, d8, d6[3]
526        VMLAL.S16 q15, d9, d6[3]
527        BEQ     4b
528
529        VLD1.8  {d8},  [r9]!
530        VMOVL.S8 q4, d8
531        VMLAL.S16 q8, d8, d1[0]
532        VMLAL.S16 q9, d9, d1[0]
533        VMLAL.S16 q10, d8, d3[0]
534        VMLAL.S16 q11, d9, d3[0]
535        VMLAL.S16 q12, d8, d5[0]
536        VMLAL.S16 q13, d9, d5[0]
537        VMLAL.S16 q14, d8, d7[0]
538        VMLAL.S16 q15, d9, d7[0]
539        CMP     r5, 6
540        BLO     4b
541
542        VLD1.8  {d8},  [r9]!
543        VMOVL.S8 q4, d8
544        VMLAL.S16 q8, d8, d1[1]
545        VMLAL.S16 q9, d9, d1[1]
546        VMLAL.S16 q10, d8, d3[1]
547        VMLAL.S16 q11, d9, d3[1]
548        VMLAL.S16 q12, d8, d5[1]
549        VMLAL.S16 q13, d9, d5[1]
550        VMLAL.S16 q14, d8, d7[1]
551        VMLAL.S16 q15, d9, d7[1]
552        BEQ     4b
553
554        VLD1.8  {d8},  [r9]!
555        VMOVL.S8 q4, d8
556        VMLAL.S16 q8, d8, d1[2]
557        VMLAL.S16 q9, d9, d1[2]
558        VMLAL.S16 q10, d8, d3[2]
559        VMLAL.S16 q11, d9, d3[2]
560        VMLAL.S16 q12, d8, d5[2]
561        VMLAL.S16 q13, d9, d5[2]
562        VMLAL.S16 q14, d8, d7[2]
563        VMLAL.S16 q15, d9, d7[2]
564        B       4b
565
566        # Store odd width
567        .p2align 3
5687:
569        TST     r1, 4
570        BEQ     8f
571        VST1.32 {d3[0]}, [r6]!
572        VST1.32 {d2[0]}, [r8]!
573        VST1.32 {d1[0]}, [r4]!
574        VST1.32 {d0[0]}, [r11]!
575        VEXT.8  q1, q1, q1, 4
576        VEXT.8  q0, q0, q0, 4
5778:
578        TST     r1, 2
579        BEQ     9f
580        VST1.16 {d3[0]}, [r6]!
581        VST1.16 {d2[0]}, [r8]!
582        VST1.16 {d1[0]}, [r4]!
583        VST1.16 {d0[0]}, [r11]!
584        VEXT.8  q1, q1, q1, 2
585        VEXT.8  q0, q0, q0, 2
586
5879:
588        TST     r1, 1
589        BEQ     10f
590        VST1.8  {d3[0]}, [r6]
591        VST1.8  {d2[0]}, [r8]
592        VST1.8  {d1[0]}, [r4]
593        VST1.8  {d0[0]}, [r11]
594
59510:
596        VPOP    {d8-d13}
597        ADD     sp, sp, 20              // skip pad of 8, r1, r2, r3
598        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
599
600END_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a53
601
602#ifdef __ELF__
603.section ".note.GNU-stack","",%progbits
604#endif
605