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