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_qs8_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 int8_t*restrict a,              r3
20//     size_t a_stride,           sp + 88 -> (r7)
21//     const void*restrict w,     sp + 92 -> r9
22//     int8_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 16 bytes
47//  struct {
48//    int32_t right_pre_shift;    d12[0]
49//    int32_t multiplier;         d12[1]
50//    int32_t right_post_shift;   d13[0]
51//    int16_t output_zero_point;  d13[2]
52//    int8_t output_min;          d13[6]
53//    int8_t output_max;          d13[7]
54//  } rndnu_neon;
55
56BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a7
57        # Push 88 bytes
58        PUSH    {r4, r5, r6, r7, r8, r9, r10, r11}  // 32
59        SUB     sp, sp, 8                           // +8
60        VPUSH   {d8-d13}                            // +48 = 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        VLDM    r5, {d12-d13}           // RNDNU params
88        LDR     r7, [sp, 104]            // cn_stride
89
90
91        .p2align 3
920:
93        # Load initial bias from w into accumulators
94        VLDM    r9!, {d16-d19}          // Bias
95        SUBS    r5, r2, 8               // k = kc - 8
96
97        VMOV    q10, q8
98        VMOV    q11, q9
99        VMOV    q12, q8
100        VMOV    q13, q9
101        VMOV    q14, q8
102        VMOV    q15, q9
103        BLO     4f                      // less than 8 channels?
104
105        // Prologue - load 4A's and B0
106        VLD1.8  {d0},  [r3]!            // A0
107        VLD1.8  {d2}, [r12]!            // A1
108        VLD1.8  {d4}, [r10]!            // A2
109        VLD1.8  {d6},  [r0]!            // A3
110        VLD1.8  {d8},  [r9]!            // B0
111
112        SUBS    r5, r5, 8               // k = k - 8
113        BLO     2f                      // less than 8 channels?
114
115        // Main loop - 8 bytes
116        // 64 bytes for weights.
117        // 5 VMOVL = 4 A and 1 B = 5 cycles
118        // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles
119        // 1 blocks with VLD B, VMLA = 9 cycles
120        // total = 84 cycles
121        .p2align 3
1221:
123        // Extend - 5 cycles
124        VMOVL.S8 q0, d0
125        VMOVL.S8 q4, d8
126        VMOVL.S8 q1, d2
127        VMOVL.S8 q2, d4
128        VMOVL.S8 q3, d6
129
130        // BLOCK 0 - 10 cycles
131        VLD1.8  {d10},  [r9]!           // B1
132        VMLAL.S16 q8, d8, d0[0]
133        VMLAL.S16 q9, d9, d0[0]
134        VMLAL.S16 q10, d8, d2[0]
135        VMLAL.S16 q11, d9, d2[0]
136        VMOVL.S8 q5, d10
137        VMLAL.S16 q12, d8, d4[0]
138        VMLAL.S16 q13, d9, d4[0]
139        VMLAL.S16 q14, d8, d6[0]
140        VMLAL.S16 q15, d9, d6[0]
141
142        // BLOCK 1 - 10 cycles
143        VLD1.8  {d8},  [r9]!            // B2
144        VMLAL.S16 q8, d10, d0[1]
145        VMLAL.S16 q9, d11, d0[1]
146        VMLAL.S16 q10, d10, d2[1]
147        VMLAL.S16 q11, d11, d2[1]
148        VMOVL.S8 q4, d8
149        VMLAL.S16 q12, d10, d4[1]
150        VMLAL.S16 q13, d11, d4[1]
151        VMLAL.S16 q14, d10, d6[1]
152        VMLAL.S16 q15, d11, d6[1]
153
154        // BLOCK 2 - 10 cycles
155        VLD1.8  {d10},  [r9]!           // B3
156        VMLAL.S16 q8, d8, d0[2]
157        VMLAL.S16 q9, d9, d0[2]
158        VMLAL.S16 q10, d8, d2[2]
159        VMLAL.S16 q11, d9, d2[2]
160        VMOVL.S8 q5, d10
161        VMLAL.S16 q12, d8, d4[2]
162        VMLAL.S16 q13, d9, d4[2]
163        VMLAL.S16 q14, d8, d6[2]
164        VMLAL.S16 q15, d9, d6[2]
165
166        // BLOCK 3 - 10 cycles
167        VLD1.8  {d8},  [r9]!            // B4
168        VMLAL.S16 q8, d10, d0[3]
169        VMLAL.S16 q9, d11, d0[3]
170        VMLAL.S16 q10, d10, d2[3]
171        VMLAL.S16 q11, d11, d2[3]
172        VLD1.8  {d0},  [r3]!            // A0
173        VMOVL.S8 q4, d8
174        VMLAL.S16 q12, d10, d4[3]
175        VMLAL.S16 q13, d11, d4[3]
176        VMLAL.S16 q14, d10, d6[3]
177        VMLAL.S16 q15, d11, d6[3]
178
179        // BLOCK 4 - 10 cycles
180        VLD1.8  {d10},  [r9]!           // B5
181        VMLAL.S16 q8, d8, d1[0]
182        VMLAL.S16 q9, d9, d1[0]
183        VMLAL.S16 q10, d8, d3[0]
184        VMLAL.S16 q11, d9, d3[0]
185        VLD1.8  {d2}, [r12]!            // A1
186        VMOVL.S8 q5, d10
187        VMLAL.S16 q12, d8, d5[0]
188        VMLAL.S16 q13, d9, d5[0]
189        VMLAL.S16 q14, d8, d7[0]
190        VMLAL.S16 q15, d9, d7[0]
191
192        // BLOCK 5 - 10 cycles
193        VLD1.8  {d8},  [r9]!            // B6
194        VMLAL.S16 q8, d10, d1[1]
195        VMLAL.S16 q9, d11, d1[1]
196        VMLAL.S16 q10, d10, d3[1]
197        VMLAL.S16 q11, d11, d3[1]
198        VLD1.8  {d4}, [r10]!            // A2
199        VMOVL.S8 q4, d8
200        VMLAL.S16 q12, d10, d5[1]
201        VMLAL.S16 q13, d11, d5[1]
202        VMLAL.S16 q14, d10, d7[1]
203        VMLAL.S16 q15, d11, d7[1]
204
205        // BLOCK 6 - 10 cycles
206        VLD1.8  {d10},  [r9]!           // B7
207        VMLAL.S16 q8, d8, d1[2]
208        VMLAL.S16 q9, d9, d1[2]
209        VMLAL.S16 q10, d8, d3[2]
210        VMLAL.S16 q11, d9, d3[2]
211        VLD1.8  {d6},  [r0]!            // A3
212        VMOVL.S8 q5, d10
213        VMLAL.S16 q12, d8, d5[2]
214        VMLAL.S16 q13, d9, d5[2]
215        VMLAL.S16 q14, d8, d7[2]
216        VMLAL.S16 q15, d9, d7[2]
217
218        // BLOCK 7 - 9 cycles
219        VLD1.8  {d8},  [r9]!            // B0
220        VMLAL.S16 q8, d10, d1[3]
221        VMLAL.S16 q9, d11, d1[3]
222        VMLAL.S16 q10, d10, d3[3]
223        VMLAL.S16 q11, d11, d3[3]
224        VMLAL.S16 q12, d10, d5[3]
225        VMLAL.S16 q13, d11, d5[3]
226        SUBS    r5, r5, 8
227        VMLAL.S16 q14, d10, d7[3]
228        VMLAL.S16 q15, d11, d7[3]
229        BHS     1b
230
231        // Epilogue
232
233        .p2align 3
2342:
235        VMOVL.S8 q0, d0
236        VMOVL.S8 q4, d8
237        VMOVL.S8 q1, d2
238        VMOVL.S8 q2, d4
239        VMOVL.S8 q3, d6
240
241        VLD1.8  {d10},  [r9]!           // B1
242        VMLAL.S16 q8, d8, d0[0]
243        VMLAL.S16 q9, d9, d0[0]
244        VMLAL.S16 q10, d8, d2[0]
245        VMLAL.S16 q11, d9, d2[0]
246        VMOVL.S8 q5, d10
247        VMLAL.S16 q12, d8, d4[0]
248        VMLAL.S16 q13, d9, d4[0]
249        VMLAL.S16 q14, d8, d6[0]
250        VMLAL.S16 q15, d9, d6[0]
251
252        VLD1.8  {d8},  [r9]!            // B2
253        VMLAL.S16 q8, d10, d0[1]
254        VMLAL.S16 q9, d11, d0[1]
255        VMLAL.S16 q10, d10, d2[1]
256        VMLAL.S16 q11, d11, d2[1]
257        VMOVL.S8 q4, d8
258        VMLAL.S16 q12, d10, d4[1]
259        VMLAL.S16 q13, d11, d4[1]
260        VMLAL.S16 q14, d10, d6[1]
261        VMLAL.S16 q15, d11, d6[1]
262
263        VLD1.8  {d10},  [r9]!           // B3
264        VMLAL.S16 q8, d8, d0[2]
265        VMLAL.S16 q9, d9, d0[2]
266        VMLAL.S16 q10, d8, d2[2]
267        VMLAL.S16 q11, d9, d2[2]
268        VMOVL.S8 q5, d10
269        VMLAL.S16 q12, d8, d4[2]
270        VMLAL.S16 q13, d9, d4[2]
271        VMLAL.S16 q14, d8, d6[2]
272        VMLAL.S16 q15, d9, d6[2]
273
274        VLD1.8  {d8},  [r9]!            // B4
275        VMLAL.S16 q8, d10, d0[3]
276        VMLAL.S16 q9, d11, d0[3]
277        VMLAL.S16 q10, d10, d2[3]
278        VMLAL.S16 q11, d11, d2[3]
279        VMOVL.S8 q4, d8
280        VMLAL.S16 q12, d10, d4[3]
281        VMLAL.S16 q13, d11, d4[3]
282        VMLAL.S16 q14, d10, d6[3]
283        VMLAL.S16 q15, d11, d6[3]
284
285        VLD1.8  {d10},  [r9]!           // B5
286        VMLAL.S16 q8, d8, d1[0]
287        VMLAL.S16 q9, d9, d1[0]
288        VMLAL.S16 q10, d8, d3[0]
289        VMLAL.S16 q11, d9, d3[0]
290        VMOVL.S8 q5, d10
291        VMLAL.S16 q12, d8, d5[0]
292        VMLAL.S16 q13, d9, d5[0]
293        VMLAL.S16 q14, d8, d7[0]
294        VMLAL.S16 q15, d9, d7[0]
295
296        VLD1.8  {d8},  [r9]!            // B6
297        VMLAL.S16 q8, d10, d1[1]
298        VMLAL.S16 q9, d11, d1[1]
299        VMLAL.S16 q10, d10, d3[1]
300        VMLAL.S16 q11, d11, d3[1]
301        VMOVL.S8 q4, d8
302        VMLAL.S16 q12, d10, d5[1]
303        VMLAL.S16 q13, d11, d5[1]
304        VMLAL.S16 q14, d10, d7[1]
305        VMLAL.S16 q15, d11, d7[1]
306
307        VLD1.8  {d10},  [r9]!           // B7
308        VMLAL.S16 q8, d8, d1[2]
309        VMLAL.S16 q9, d9, d1[2]
310        VMLAL.S16 q10, d8, d3[2]
311        VMLAL.S16 q11, d9, d3[2]
312        VMOVL.S8 q5, d10
313        VMLAL.S16 q12, d8, d5[2]
314        VMLAL.S16 q13, d9, d5[2]
315        VMLAL.S16 q14, d8, d7[2]
316        VMLAL.S16 q15, d9, d7[2]
317
318        VMLAL.S16 q8, d10, d1[3]
319        VMLAL.S16 q9, d11, d1[3]
320        VMLAL.S16 q10, d10, d3[3]
321        VMLAL.S16 q11, d11, d3[3]
322        VMLAL.S16 q12, d10, d5[3]
323        VMLAL.S16 q13, d11, d5[3]
324        ADDS    r5, r5, 8
325        VMLAL.S16 q14, d10, d7[3]
326        VMLAL.S16 q15, d11, d7[3]
327
328        # Is there a remainder?- 1-7 bytes of A
329        BNE     4f
330
3313:
332        # RNDNU quantization
333        VDUP.32 q0, d12[0]              // right_pre_shift
334
335        VQSHL.S32 q8,  q8, q0
336        VQSHL.S32 q9,  q9, q0
337        VQSHL.S32 q10, q10, q0
338        VQSHL.S32 q11, q11, q0
339        VQSHL.S32 q12, q12, q0
340        VQSHL.S32 q13, q13, q0
341        VQSHL.S32 q14, q14, q0
342        VQSHL.S32 q15, q15, q0
343
344        VDUP.32 q2, d13[0]              // right_post_shift
345
346        VQDMULH.S32 q8,  q8, d12[1]     // multiplier
347        VQDMULH.S32 q9,  q9, d12[1]
348        VQDMULH.S32 q10, q10, d12[1]
349        VQDMULH.S32 q11, q11, d12[1]
350        VQDMULH.S32 q12, q12, d12[1]
351        VQDMULH.S32 q13, q13, d12[1]
352        VQDMULH.S32 q14, q14, d12[1]
353        VQDMULH.S32 q15, q15, d12[1]
354
355        VRSHL.S32 q8,  q8, q2
356        VRSHL.S32 q9,  q9, q2
357        VRSHL.S32 q10, q10, q2
358        VRSHL.S32 q11, q11, q2
359        VRSHL.S32 q12, q12, q2
360        VRSHL.S32 q13, q13, q2
361        VRSHL.S32 q14, q14, q2
362        VRSHL.S32 q15, q15, q2
363
364        VDUP.16 q0, d13[2]              // output_zero_point
365
366        VQMOVN.S32 d16, q8
367        VQMOVN.S32 d17, q9
368        VQMOVN.S32 d18, q10
369        VQMOVN.S32 d19, q11
370        VQMOVN.S32 d20, q12
371        VQMOVN.S32 d21, q13
372        VQMOVN.S32 d22, q14
373        VQMOVN.S32 d23, q15
374
375        VQADD.S16 q8,  q8, q0
376        VQADD.S16 q9,  q9, q0
377        VQADD.S16 q10, q10, q0
378        VQADD.S16 q11, q11, q0
379
380        VDUP.8  q12, d13[6]             // output_min
381
382        VQMOVN.S16 d0,  q8
383        VQMOVN.S16 d1,  q9
384        VQMOVN.S16 d2, q10
385        VQMOVN.S16 d3, q11
386
387        VDUP.8  q13, d13[7]             // output_max
388
389        VMAX.S8 q0, q0, q12
390        VMAX.S8 q1, q1, q12
391
392        SUBS    r1, r1, 8
393
394        VMIN.S8 q0, q0, q13
395        VMIN.S8 q1, q1, q13
396
397        # Store full 4 x 8
398        BLO     5f
399        VST1.8  {d0}, [r11], r7
400        SUB     r3, r3, r2
401        VST1.8  {d1}, [r4], r7
402        SUB     r12, r12, r2
403        VST1.8  {d2}, [r8], r7
404        SUB     r10, r10, r2
405        VST1.8  {d3}, [r6], r7
406        SUB     r0, r0, r2
407        BHI     0b
408
409        VPOP    {d8-d13}
410        ADD     sp, sp, 8               // skip 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.S8 q0, d0
426        VMOVL.S8 q4, d8
427        VMOVL.S8 q1, d2
428        VMOVL.S8 q2, d4
429        VMOVL.S8 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        VMOVL.S8 q4, d8
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        VMOVL.S8 q4, d8
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        VMOVL.S8 q4, d8
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        VMOVL.S8 q4, d8
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        VMOVL.S8 q4, d8
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        VMOVL.S8 q4, d8
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-d13}
546        ADD     sp, sp, 8               // skip d14
547        POP     {r4, r5, r6, r7, r8, r9, r10, r11}
548        BX      lr
549
550END_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_cortex_a7
551
552#ifdef __ELF__
553.section ".note.GNU-stack","",%progbits
554#endif
555
556