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