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