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