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