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