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