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