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