1// Auto-generated file. Do not edit!
2//   Template: src/qs8-gemm/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_gemm_minmax_fp32_ukernel_4x8__aarch32_neonv8_mlal_lane_cortex_a53(
16//     size_t mr,                            r0
17//     size_t nc,                            r1
18//     size_t kc,                            (r2) -> sp + 56 -> r5
19//     const int8_t*restrict a,              r3
20//     size_t a_stride,           sp + 96 -> (r7)
21//     const void*restrict w,     sp + 100 -> r9
22//     int8_t*restrict c,         sp + 104 -> r11
23//     size_t cm_stride,          sp + 108 -> (r6)
24//     size_t cn_stride,          sp + 112 -> r7
25//     xnn_qs8_minmax_params params)  sp + 116 -> (r5)
26
27// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
28
29// Register usage
30// A0   r3  d0-d1 q0
31// A1  r12  d2-d3 q1
32// A2  r10  d4-d5 q2
33// A3   r0  d6-d7 q3
34
35// B    r9  d8-d9 q4 q5
36
37// C0  r11 d16-d17  q8  d18-d19  q9
38// C1   r4 d20-d21 q10  d22-d23 q11
39// C2   r8 d24-d25 q12  d26-d27 q13
40// C3   r6 d28-d29 q14  d30-d31 q15
41
42// r2,r14 A53 gpr temporary loads
43// Unused d15
44
45// params structure is 4 bytes
46//  struct {
47//    int16_t output_zero_point;  d13[2]
48//    int8_t output_min;          d13[6]
49//    int8_t output_max;          d13[7]
50//  } xnn_qs8_minmax_params.neonv8;
51
52BEGIN_FUNCTION xnn_qc8_gemm_minmax_fp32_ukernel_4x8__aarch32_neonv8_mlal_lane_cortex_a53
53        # Push 96 bytes
54        PUSH    {r2, r4, r5, r6, r7, r8, r9, r10, r11, lr}  // 40
55        SUB     sp, sp, 8                           // +8
56        VPUSH   {d8-d13}                            // +48 = 96
57
58        LDR     r7, [sp, 96]            // a_stride
59        LDR     r11, [sp, 104]          // c
60        LDR     r6, [sp, 108]           // cm_stride
61        LDR     r9, [sp, 100]           // w
62        LDR     r5, [sp, 116]           // params
63
64        # Clamp A and C pointers
65        CMP     r0, 2                   // if mr >= 2
66        ADD     r12, r3, r7             //   a1 = a0 + a_stride
67        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
68        MOVLO   r12, r3                 // a1
69        MOVLO   r4, r11                 // c1
70                                        // if mr > 2
71        ADD     r10, r12, r7            //   a2 = a1 + a_stride
72        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
73        MOVLS   r10, r12                // a2
74        MOVLS   r8, r4                  // c2
75
76        CMP     r0, 4                   // if mr >=4
77        ADD     r0, r10, r7             //   a3 = a2 + a_stride
78        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
79        MOVLO   r0, r10                 // a3
80        MOVLO   r6, r8                  // c3
81
82        # Load params values
83        VLD1.32 {d13[]}, [r5]           // QC8 neonv8 params
84        LDR     r7, [sp, 112]            // cn_stride
85
86
87        .p2align 3
880:
89        # Load initial bias from w into accumulators
90        VLDM    r9!, {d16-d19}          // Bias
91        SUBS    r5, r2, 8               // k = kc - 8
92
93        VMOV    q10, q8
94        VMOV    q11, q9
95        VMOV    q12, q8
96        VMOV    q13, q9
97        VMOV    q14, q8
98        VMOV    q15, q9
99        BLO     4f                      // less than 8 channels?
100
101        // Prologue - load 4A's and B0
102        VLD1.8  {d0},  [r3]!            // A0
103        VLD1.8  {d2}, [r12]!            // A1
104        VLD1.8  {d4}, [r10]!            // A2
105        VLD1.8  {d6},  [r0]!            // A3
106        VLD1.8  {d8},  [r9]!            // B0
107
108        SUBS    r5, r5, 8               // k = k - 8
109        BLO     2f                      // less than 8 channels?
110
111        // Main loop - 8 bytes
112        // 64 bytes for weights.
113        // 5 VMOVL = 4 A and 1 B = 5 cycles
114        // 7 blocks with VLD B, VMOVL, 8 VMLA = 10 cycles
115        // 1 blocks with VLD B, VMLA = 9 cycles
116        // total = 84 cycles
117        .p2align 3
1181:
119        // Extend - 5 cycles
120        VMOVL.S8 q0, d0
121        VMOVL.S8 q4, d8
122        VMOVL.S8 q1, d2
123        VMOVL.S8 q2, d4
124        VMOVL.S8 q3, d6
125
126        // BLOCK 0 - 10 cycles
127        VLD1.8  {d10},  [r9]!           // B1
128        VMLAL.S16 q8, d8, d0[0]
129        VMLAL.S16 q9, d9, d0[0]
130        VMLAL.S16 q10, d8, d2[0]
131        VMLAL.S16 q11, d9, d2[0]
132        VMOVL.S8 q5, d10
133        VMLAL.S16 q12, d8, d4[0]
134        VMLAL.S16 q13, d9, d4[0]
135        VMLAL.S16 q14, d8, d6[0]
136        VMLAL.S16 q15, d9, d6[0]
137
138        // BLOCK 1 - 10 cycles
139        VLD1.8  {d8},  [r9]!            // B2
140        VMLAL.S16 q8, d10, d0[1]
141        VMLAL.S16 q9, d11, d0[1]
142        VMLAL.S16 q10, d10, d2[1]
143        VMLAL.S16 q11, d11, d2[1]
144        VMOVL.S8 q4, d8
145        VMLAL.S16 q12, d10, d4[1]
146        VMLAL.S16 q13, d11, d4[1]
147        VMLAL.S16 q14, d10, d6[1]
148        VMLAL.S16 q15, d11, d6[1]
149
150        // BLOCK 2 - 10 cycles
151        VLD1.8  {d10},  [r9]!           // B3
152        VMLAL.S16 q8, d8, d0[2]
153        VMLAL.S16 q9, d9, d0[2]
154        VMLAL.S16 q10, d8, d2[2]
155        VMLAL.S16 q11, d9, d2[2]
156        VMOVL.S8 q5, d10
157        VMLAL.S16 q12, d8, d4[2]
158        VMLAL.S16 q13, d9, d4[2]
159        VMLAL.S16 q14, d8, d6[2]
160        VMLAL.S16 q15, d9, d6[2]
161
162        // BLOCK 3 - 10 cycles
163        VLD1.8  {d8},  [r9]!            // B4
164        VMLAL.S16 q8, d10, d0[3]
165        VMLAL.S16 q9, d11, d0[3]
166        VMLAL.S16 q10, d10, d2[3]
167        VMLAL.S16 q11, d11, d2[3]
168        VMOVL.S8 q4, d8
169        VMLAL.S16 q12, d10, d4[3]
170        LDR     r2, [r3]                // A0 low
171        VMLAL.S16 q13, d11, d4[3]
172        LDR     r14, [r3, 4]            // A0 high
173        VMLAL.S16 q14, d10, d6[3]
174        ADD     r3, r3, 8
175        VMLAL.S16 q15, d11, d6[3]
176
177        // BLOCK 4 - 10 cycles
178        VLD1.8  {d10},  [r9]!           // B5
179        VMOV    d0, r2, r14             // A0 VMOV
180        VMLAL.S16 q8, d8, d1[0]
181        VMLAL.S16 q9, d9, d1[0]
182        VMLAL.S16 q10, d8, d3[0]
183        VMLAL.S16 q11, d9, d3[0]
184        VMOVL.S8 q5, d10
185        VMLAL.S16 q12, d8, d5[0]
186        LDR     r2, [r12]               // A1 low
187        VMLAL.S16 q13, d9, d5[0]
188        LDR     r14, [r12, 4]           // A1 high
189        VMLAL.S16 q14, d8, d7[0]
190        ADD     r12, r12, 8
191        VMLAL.S16 q15, d9, d7[0]
192
193        // BLOCK 5 - 10 cycles
194        VLD1.8  {d8},  [r9]!            // B6
195        VMOV    d2, r2, r14             // A1 VMOV
196        VMLAL.S16 q8, d10, d1[1]
197        VMLAL.S16 q9, d11, d1[1]
198        VMLAL.S16 q10, d10, d3[1]
199        VMLAL.S16 q11, d11, d3[1]
200        VMOVL.S8 q4, d8
201        VMLAL.S16 q12, d10, d5[1]
202        LDR     r2, [r10]               // A2 low
203        VMLAL.S16 q13, d11, d5[1]
204        LDR     r14, [r10, 4]           // A2 high
205        VMLAL.S16 q14, d10, d7[1]
206        ADD     r10, r10, 8
207        VMLAL.S16 q15, d11, d7[1]
208
209        // BLOCK 6 - 10 cycles
210        VLD1.8  {d10},  [r9]!           // B7
211        VMOV    d4, r2, r14             // A2 VMOV
212        VMLAL.S16 q8, d8, d1[2]
213        VMLAL.S16 q9, d9, d1[2]
214        VMLAL.S16 q10, d8, d3[2]
215        VMLAL.S16 q11, d9, d3[2]
216        VMOVL.S8 q5, d10
217        VMLAL.S16 q12, d8, d5[2]
218        LDR     r2, [r0]                // A3 low
219        VMLAL.S16 q13, d9, d5[2]
220        LDR     r14, [r0, 4]            // A3 high
221        VMLAL.S16 q14, d8, d7[2]
222        ADD     r0, r0, 8
223        VMLAL.S16 q15, d9, d7[2]
224
225        // BLOCK 7 - 9 cycles
226        VLD1.8  {d8},  [r9]!            // B0
227        VMOV    d6, r2, r14             // A3 VMOV
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        LDR     r2, [sp, 56]            // kc
399        SUBS    r1, r1, 8
400
401        VMIN.S8 q0, q0, q13
402        VMIN.S8 q1, q1, q13
403
404        # Store full 4 x 8
405        BLO     5f
406        VST1.8  {d0}, [r11], r7
407        SUB     r3, r3, r2
408        VST1.8  {d1}, [r4], r7
409        SUB     r12, r12, r2
410        VST1.8  {d2}, [r8], r7
411        SUB     r10, r10, r2
412        VST1.8  {d3}, [r6], r7
413        SUB     r0, r0, r2
414        BHI     0b
415
416        VPOP    {d8-d13}
417        ADD     sp, sp, 12              // skip pad of 8 + r2
418        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
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, 12              // skip pad of 8 + r2
553        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
554
555
556END_FUNCTION xnn_qc8_gemm_minmax_fp32_ukernel_4x8__aarch32_neonv8_mlal_lane_cortex_a53
557
558#ifdef __ELF__
559.section ".note.GNU-stack","",%progbits
560#endif
561
562