1// Auto-generated file. Do not edit!
2//   Template: src/qs8-igemm/4x8-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_qu8_igemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7(
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 uint8_t**restrict a,            sp + 104  -> r2
21//     const void*restrict w,              sp + 108  -> r9
22//     uint8_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 uint8_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// Unused d15
45
46// params structure is 20 bytes
47//  struct {
48//    uint8_t kernel_zero_point[4];  d14
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//    uint8_t output_min;            d13[6]
54//    uint8_t output_max;            d13[7]
55//  } rndnu_neon;
56
57BEGIN_FUNCTION xnn_qu8_igemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7
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        VPUSH   {d8-d14}                            // +56 = 104
62
63        LDR     r11, [sp, 112]          // c
64        LDR     r6, [sp, 116]           // cm_stride
65        LDR     r2, [sp, 104]           // a
66        LDR     r9, [sp, 108]           // w
67        LDR     r5, [sp, 132]           // params
68        MOV     r14, r3                 // p = ks
69
70        # Clamp C pointers
71        CMP     r0, 2                   // if mr >= 2
72        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
73        MOVLO   r4, r11                 // c1
74                                        // if mr > 2
75        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
76        MOVLS   r8, r4                  // c2
77        CMP     r0, 4                   // if mr >=4
78        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
79        MOVLO   r6, r8                  // c3
80
81        # Load params values
82        VLD1.32 {d14[]}, [r5]!          // QU8 kernel_zero_point
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
140        BLO     3f                      // less than 8 channels?
141
142        // Main loop - 8 bytes
143        // 64 bytes for weights.
144        // 5 VMOVL = 4 A and 1 B = 5 cycles
145        // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles
146        // 1 blocks with VLD B, VMLA = 9 cycles
147        // total = 84 cycles
148        .p2align 3
1492:
150        // Extend - 5 cycles
151        VMOVL.U8 q0, d0
152        VSUBL.U8 q4, d8, d14
153        PLD     [r9, 448]
154        VMOVL.U8 q1, d2
155        VMOVL.U8 q2, d4
156        VMOVL.U8 q3, d6
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        VSUBL.U8 q5, d10, d14
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        VSUBL.U8 q4, d8, d14
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        VSUBL.U8 q5, d10, d14
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        VLD1.8  {d0},  [r3]!            // A0
201        VSUBL.U8 q4, d8, d14
202        VMLAL.S16 q12, d10, d4[3]
203        VMLAL.S16 q13, d11, d4[3]
204        VMLAL.S16 q14, d10, d6[3]
205        VMLAL.S16 q15, d11, d6[3]
206
207        // BLOCK 4 - 10 cycles
208        VLD1.8  {d10},  [r9]!           // B5
209        VMLAL.S16 q8, d8, d1[0]
210        VMLAL.S16 q9, d9, d1[0]
211        VMLAL.S16 q10, d8, d3[0]
212        VMLAL.S16 q11, d9, d3[0]
213        VLD1.8  {d2}, [r12]!            // A1
214        VSUBL.U8 q5, d10, d14
215        VMLAL.S16 q12, d8, d5[0]
216        VMLAL.S16 q13, d9, d5[0]
217        VMLAL.S16 q14, d8, d7[0]
218        VMLAL.S16 q15, d9, d7[0]
219
220        // BLOCK 5 - 10 cycles
221        VLD1.8  {d8},  [r9]!            // B6
222        VMLAL.S16 q8, d10, d1[1]
223        VMLAL.S16 q9, d11, d1[1]
224        VMLAL.S16 q10, d10, d3[1]
225        VMLAL.S16 q11, d11, d3[1]
226        VLD1.8  {d4}, [r10]!            // A2
227        VSUBL.U8 q4, d8, d14
228        VMLAL.S16 q12, d10, d5[1]
229        VMLAL.S16 q13, d11, d5[1]
230        VMLAL.S16 q14, d10, d7[1]
231        VMLAL.S16 q15, d11, d7[1]
232
233        // BLOCK 6 - 10 cycles
234        VLD1.8  {d10},  [r9]!           // B7
235        VMLAL.S16 q8, d8, d1[2]
236        VMLAL.S16 q9, d9, d1[2]
237        VMLAL.S16 q10, d8, d3[2]
238        VMLAL.S16 q11, d9, d3[2]
239        VLD1.8  {d6},  [r0]!            // A3
240        VSUBL.U8 q5, d10, d14
241        VMLAL.S16 q12, d8, d5[2]
242        VMLAL.S16 q13, d9, d5[2]
243        VMLAL.S16 q14, d8, d7[2]
244        VMLAL.S16 q15, d9, d7[2]
245
246        // BLOCK 7 - 9 cycles
247        VLD1.8  {d8},  [r9]!            // B0
248        VMLAL.S16 q8, d10, d1[3]
249        VMLAL.S16 q9, d11, d1[3]
250        VMLAL.S16 q10, d10, d3[3]
251        VMLAL.S16 q11, d11, d3[3]
252        VMLAL.S16 q12, d10, d5[3]
253        VMLAL.S16 q13, d11, d5[3]
254        SUBS    r5, r5, 8
255        VMLAL.S16 q14, d10, d7[3]
256        VMLAL.S16 q15, d11, d7[3]
257        BHS     2b
258
259        // Epilogue
260
261        .p2align 3
2623:
263        VMOVL.U8 q0, d0
264        VSUBL.U8 q4, d8, d14
265        VMOVL.U8 q1, d2
266        VMOVL.U8 q2, d4
267        VMOVL.U8 q3, d6
268
269        VLD1.8  {d10},  [r9]!           // B1
270        VMLAL.S16 q8, d8, d0[0]
271        VMLAL.S16 q9, d9, d0[0]
272        VMLAL.S16 q10, d8, d2[0]
273        VMLAL.S16 q11, d9, d2[0]
274        VSUBL.U8 q5, d10, d14
275        VMLAL.S16 q12, d8, d4[0]
276        VMLAL.S16 q13, d9, d4[0]
277        VMLAL.S16 q14, d8, d6[0]
278        VMLAL.S16 q15, d9, d6[0]
279
280        VLD1.8  {d8},  [r9]!            // B2
281        VMLAL.S16 q8, d10, d0[1]
282        VMLAL.S16 q9, d11, d0[1]
283        VMLAL.S16 q10, d10, d2[1]
284        VMLAL.S16 q11, d11, d2[1]
285        VSUBL.U8 q4, d8, d14
286        VMLAL.S16 q12, d10, d4[1]
287        VMLAL.S16 q13, d11, d4[1]
288        VMLAL.S16 q14, d10, d6[1]
289        VMLAL.S16 q15, d11, d6[1]
290
291        VLD1.8  {d10},  [r9]!           // B3
292        VMLAL.S16 q8, d8, d0[2]
293        VMLAL.S16 q9, d9, d0[2]
294        VMLAL.S16 q10, d8, d2[2]
295        VMLAL.S16 q11, d9, d2[2]
296        VSUBL.U8 q5, d10, d14
297        VMLAL.S16 q12, d8, d4[2]
298        VMLAL.S16 q13, d9, d4[2]
299        VMLAL.S16 q14, d8, d6[2]
300        VMLAL.S16 q15, d9, d6[2]
301
302        VLD1.8  {d8},  [r9]!            // B4
303        VMLAL.S16 q8, d10, d0[3]
304        VMLAL.S16 q9, d11, d0[3]
305        VMLAL.S16 q10, d10, d2[3]
306        VMLAL.S16 q11, d11, d2[3]
307        VSUBL.U8 q4, d8, d14
308        VMLAL.S16 q12, d10, d4[3]
309        VMLAL.S16 q13, d11, d4[3]
310        VMLAL.S16 q14, d10, d6[3]
311        VMLAL.S16 q15, d11, d6[3]
312
313        VLD1.8  {d10},  [r9]!           // B5
314        VMLAL.S16 q8, d8, d1[0]
315        VMLAL.S16 q9, d9, d1[0]
316        VMLAL.S16 q10, d8, d3[0]
317        VMLAL.S16 q11, d9, d3[0]
318        VSUBL.U8 q5, d10, d14
319        VMLAL.S16 q12, d8, d5[0]
320        VMLAL.S16 q13, d9, d5[0]
321        VMLAL.S16 q14, d8, d7[0]
322        VMLAL.S16 q15, d9, d7[0]
323
324        VLD1.8  {d8},  [r9]!            // B6
325        VMLAL.S16 q8, d10, d1[1]
326        VMLAL.S16 q9, d11, d1[1]
327        VMLAL.S16 q10, d10, d3[1]
328        VMLAL.S16 q11, d11, d3[1]
329        VSUBL.U8 q4, d8, d14
330        VMLAL.S16 q12, d10, d5[1]
331        VMLAL.S16 q13, d11, d5[1]
332        VMLAL.S16 q14, d10, d7[1]
333        VMLAL.S16 q15, d11, d7[1]
334
335        VLD1.8  {d10},  [r9]!           // B7
336        VMLAL.S16 q8, d8, d1[2]
337        VMLAL.S16 q9, d9, d1[2]
338        VMLAL.S16 q10, d8, d3[2]
339        VMLAL.S16 q11, d9, d3[2]
340        VSUBL.U8 q5, d10, d14
341        VMLAL.S16 q12, d8, d5[2]
342        VMLAL.S16 q13, d9, d5[2]
343        VMLAL.S16 q14, d8, d7[2]
344        VMLAL.S16 q15, d9, d7[2]
345
346        VMLAL.S16 q8, d10, d1[3]
347        VMLAL.S16 q9, d11, d1[3]
348        VMLAL.S16 q10, d10, d3[3]
349        VMLAL.S16 q11, d11, d3[3]
350        VMLAL.S16 q12, d10, d5[3]
351        VMLAL.S16 q13, d11, d5[3]
352        ADDS    r5, r5, 8
353        VMLAL.S16 q14, d10, d7[3]
354        VMLAL.S16 q15, d11, d7[3]
355
356        # Is there a remainder?- 1-7 bytes of A
357        BNE     6f
358
3594:
360        # ks loop
361        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
362        BHI     1b
363
364        LDR     r7, [sp, 120]           // cn_stride
365        LDR     r14, [sp, 64]           // p = ks
366
367        # RNDNU quantization
368        VDUP.32 q0, d12[0]              // right_pre_shift
369
370        VQSHL.S32 q8,  q8, q0
371        VQSHL.S32 q9,  q9, q0
372        VQSHL.S32 q10, q10, q0
373        VQSHL.S32 q11, q11, q0
374        VQSHL.S32 q12, q12, q0
375        VQSHL.S32 q13, q13, q0
376        VQSHL.S32 q14, q14, q0
377        VQSHL.S32 q15, q15, q0
378
379        VDUP.32 q2, d13[0]              // right_post_shift
380
381        VQDMULH.S32 q8,  q8, d12[1]     // multiplier
382        VQDMULH.S32 q9,  q9, d12[1]
383        VQDMULH.S32 q10, q10, d12[1]
384        VQDMULH.S32 q11, q11, d12[1]
385        VQDMULH.S32 q12, q12, d12[1]
386        VQDMULH.S32 q13, q13, d12[1]
387        VQDMULH.S32 q14, q14, d12[1]
388        VQDMULH.S32 q15, q15, d12[1]
389
390        VRSHL.S32 q8,  q8, q2
391        VRSHL.S32 q9,  q9, q2
392        VRSHL.S32 q10, q10, q2
393        VRSHL.S32 q11, q11, q2
394        VRSHL.S32 q12, q12, q2
395        VRSHL.S32 q13, q13, q2
396        VRSHL.S32 q14, q14, q2
397        VRSHL.S32 q15, q15, q2
398
399        VDUP.16 q0, d13[2]              // output_zero_point
400
401        VQMOVN.S32 d16, q8
402        VQMOVN.S32 d17, q9
403        VQMOVN.S32 d18, q10
404        VQMOVN.S32 d19, q11
405        VQMOVN.S32 d20, q12
406        VQMOVN.S32 d21, q13
407        VQMOVN.S32 d22, q14
408        VQMOVN.S32 d23, q15
409
410        VQADD.S16 q8,  q8, q0
411        VQADD.S16 q9,  q9, q0
412        VQADD.S16 q10, q10, q0
413        VQADD.S16 q11, q11, q0
414
415        LDR     r1, [sp, 56]            // restore nc
416        VDUP.8  q12, d13[6]             // output_min
417
418        VQMOVUN.S16 d0,  q8
419        VQMOVUN.S16 d1,  q9
420        VQMOVUN.S16 d2, q10
421        VQMOVUN.S16 d3, q11
422
423        VDUP.8  q13, d13[7]             // output_max
424
425        VMAX.U8 q0, q0, q12
426        VMAX.U8 q1, q1, q12
427
428        SUBS    r1, r1, 8               // nc -= 8
429
430        VMIN.U8 q0, q0, q13
431        VMIN.U8 q1, q1, q13
432
433        # Store full 4 x 8
434        BLO     7f
435        VST1.8  {d3}, [r6], r7
436        VST1.8  {d2}, [r8], r7
437        VST1.8  {d1}, [r4], r7
438        VST1.8  {d0}, [r11], r7
439        SUB     r2, r2, r14             // a -= ks
440        BHI     0b
441
442        VPOP    {d8-d14}
443        ADD     sp, sp, 12              // skip r1, r2, r3
444        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
445
446        # Remainder- 1 to 7 bytes of A
447        .p2align 3
4485:
449        AND     r5, r5, 7               // kc remainder 1 to 7
4506:
451        VLD1.8  {d0},  [r3]
452        VLD1.8  {d8},  [r9]!
453        VLD1.8  {d2}, [r12]
454        VLD1.8  {d4}, [r10]
455        VLD1.8  {d6},  [r0]
456
457        VMOVL.U8 q0, d0
458        VSUBL.U8 q4, d8, d14
459        VMOVL.U8 q1, d2
460        VMOVL.U8 q2, d4
461        VMOVL.U8 q3, d6
462        VMLAL.S16 q8, d8, d0[0]
463        VMLAL.S16 q9, d9, d0[0]
464        VMLAL.S16 q10, d8, d2[0]
465        VMLAL.S16 q11, d9, d2[0]
466        VMLAL.S16 q12, d8, d4[0]
467        VMLAL.S16 q13, d9, d4[0]
468        VMLAL.S16 q14, d8, d6[0]
469        VMLAL.S16 q15, d9, d6[0]
470        CMP     r5, 2
471        BLO     4b
472
473        VLD1.8  {d8},  [r9]!
474        VSUBL.U8 q4, d8, d14
475        VMLAL.S16 q8, d8, d0[1]
476        VMLAL.S16 q9, d9, d0[1]
477        VMLAL.S16 q10, d8, d2[1]
478        VMLAL.S16 q11, d9, d2[1]
479        VMLAL.S16 q12, d8, d4[1]
480        VMLAL.S16 q13, d9, d4[1]
481        VMLAL.S16 q14, d8, d6[1]
482        VMLAL.S16 q15, d9, d6[1]
483        BEQ     4b
484
485        VLD1.8  {d8},  [r9]!
486        VSUBL.U8 q4, d8, d14
487        VMLAL.S16 q8, d8, d0[2]
488        VMLAL.S16 q9, d9, d0[2]
489        VMLAL.S16 q10, d8, d2[2]
490        VMLAL.S16 q11, d9, d2[2]
491        VMLAL.S16 q12, d8, d4[2]
492        VMLAL.S16 q13, d9, d4[2]
493        VMLAL.S16 q14, d8, d6[2]
494        VMLAL.S16 q15, d9, d6[2]
495        CMP     r5, 4
496        BLO     4b
497
498        VLD1.8  {d8},  [r9]!
499        VSUBL.U8 q4, d8, d14
500        VMLAL.S16 q8, d8, d0[3]
501        VMLAL.S16 q9, d9, d0[3]
502        VMLAL.S16 q10, d8, d2[3]
503        VMLAL.S16 q11, d9, d2[3]
504        VMLAL.S16 q12, d8, d4[3]
505        VMLAL.S16 q13, d9, d4[3]
506        VMLAL.S16 q14, d8, d6[3]
507        VMLAL.S16 q15, d9, d6[3]
508        BEQ     4b
509
510        VLD1.8  {d8},  [r9]!
511        VSUBL.U8 q4, d8, d14
512        VMLAL.S16 q8, d8, d1[0]
513        VMLAL.S16 q9, d9, d1[0]
514        VMLAL.S16 q10, d8, d3[0]
515        VMLAL.S16 q11, d9, d3[0]
516        VMLAL.S16 q12, d8, d5[0]
517        VMLAL.S16 q13, d9, d5[0]
518        VMLAL.S16 q14, d8, d7[0]
519        VMLAL.S16 q15, d9, d7[0]
520        CMP     r5, 6
521        BLO     4b
522
523        VLD1.8  {d8},  [r9]!
524        VSUBL.U8 q4, d8, d14
525        VMLAL.S16 q8, d8, d1[1]
526        VMLAL.S16 q9, d9, d1[1]
527        VMLAL.S16 q10, d8, d3[1]
528        VMLAL.S16 q11, d9, d3[1]
529        VMLAL.S16 q12, d8, d5[1]
530        VMLAL.S16 q13, d9, d5[1]
531        VMLAL.S16 q14, d8, d7[1]
532        VMLAL.S16 q15, d9, d7[1]
533        BEQ     4b
534
535        VLD1.8  {d8},  [r9]!
536        VSUBL.U8 q4, d8, d14
537        VMLAL.S16 q8, d8, d1[2]
538        VMLAL.S16 q9, d9, d1[2]
539        VMLAL.S16 q10, d8, d3[2]
540        VMLAL.S16 q11, d9, d3[2]
541        VMLAL.S16 q12, d8, d5[2]
542        VMLAL.S16 q13, d9, d5[2]
543        VMLAL.S16 q14, d8, d7[2]
544        VMLAL.S16 q15, d9, d7[2]
545        B       4b
546
547        # Store odd width
548        .p2align 3
5497:
550        TST     r1, 4
551        BEQ     8f
552        VST1.32 {d3[0]}, [r6]!
553        VST1.32 {d2[0]}, [r8]!
554        VST1.32 {d1[0]}, [r4]!
555        VST1.32 {d0[0]}, [r11]!
556        VEXT.8  q1, q1, q1, 4
557        VEXT.8  q0, q0, q0, 4
5588:
559        TST     r1, 2
560        BEQ     9f
561        VST1.16 {d3[0]}, [r6]!
562        VST1.16 {d2[0]}, [r8]!
563        VST1.16 {d1[0]}, [r4]!
564        VST1.16 {d0[0]}, [r11]!
565        VEXT.8  q1, q1, q1, 2
566        VEXT.8  q0, q0, q0, 2
567
5689:
569        TST     r1, 1
570        BEQ     10f
571        VST1.8  {d3[0]}, [r6]
572        VST1.8  {d2[0]}, [r8]
573        VST1.8  {d1[0]}, [r4]
574        VST1.8  {d0[0]}, [r11]
575
57610:
577        VPOP    {d8-d14}
578        ADD     sp, sp, 12              // skip r1, r2, r3
579        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
580
581END_FUNCTION xnn_qu8_igemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_cortex_a7
582
583#ifdef __ELF__
584.section ".note.GNU-stack","",%progbits
585#endif
586