1// Auto-generated file. Do not edit!
2//   Template: src/qs8-igemm/4x8-aarch32-neon-mlal-lane-ld64.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_igemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64
16//     size_t mr,                                     (r0)
17//     size_t nc,                                      r1
18//     size_t kc,                                     (r2) -> r5 -> sp + 44
19//     size_t ks,                                     (r3) -> sp + 48 -> r14
20//     const int8_t**restrict a,            sp + 88  -> r2
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//     size_t a_offset,                    sp + 108 -> (r5)
26//     const int8_t* zero,                  sp + 112 -> (r7)
27//     xnn_qs8_minmax_params*params); sp + 116 -> (r5)
28
29// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
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  d10-d11 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 d13-d15
45
46// params structure is 10 bytes
47// struct {
48//   float magic_bias;                           d12[0]
49//   int32_t magic_bias_less_output_zero_point;  d12[1]
50//   int8_t output_min;                          d13[6]
51//   int8_t output_max;                          d13[7]
52// } xnn_qs8_minmax_params.neon;
53
54BEGIN_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64
55        # Push 88 bytes
56        # r2 will be reloaded in outer loop.  r3 is ks
57        PUSH    {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}   // +44
58        SUB     sp, sp, 12                          // +12
59        VPUSH   {d10-d13}                           // +32 = 88
60
61        LDR     r11, [sp, 96]           // c
62        LDR     r6, [sp, 100]           // cm_stride
63        LDR     r2, [sp, 88]            // a
64        LDR     r9, [sp, 92]            // w
65        LDR     r5, [sp, 116]           // params
66        MOV     r14, r3                 // p = ks
67
68        # Clamp C pointers
69        CMP     r0, 2                   // if mr >= 2
70        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
71        MOVLO   r4, r11                 // c1
72                                        // if mr > 2
73        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
74        MOVLS   r8, r4                  // c2
75        CMP     r0, 4                   // if mr >=4
76        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
77        MOVLO   r6, r8                  // c3
78
79        # Load params values
80        VLDM    r5!, {d12}              // QC8 neon params
81        VLD1.16 {d13[]}, [r5]
82
83        PLD     [r9,  64]               // Prefetch B
84        PLD     [r9, 128]
85        PLD     [r9, 192]
86        PLD     [r9, 256]
87        PLD     [r9, 320]
88        PLD     [r9, 384]
89
90        .p2align 3
910:
92        # Load initial bias from w into accumulators
93        VLDM    r9!, {d16-d19}          // Bias
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
101        .p2align 3
1021:
103        # Load next 4 A pointers
104        LDR     r3, [r2,  0]
105        LDR     r12, [r2,  4]
106        LDR     r10, [r2,  8]
107        LDR     r0, [r2, 12]
108        ADD     r2, r2, 16
109
110        PLD     [r3, 64]
111        PLD     [r12, 64]
112        PLD     [r10, 64]
113        PLD     [r0, 64]
114
115        # Add a_offset
116        LDR     r5, [sp, 108]           // a_offset
117        LDR     r7, [sp, 112]           // zero
118        CMP     r3,  r7                 // if a0 == zero
119        ADD     r3,  r3, r5             // a0 += a_offset
120        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
121        CMP     r12,  r7                // if a1 == zero
122        ADD     r12, r12, r5            // a1 += a_offset
123        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
124        CMP     r10,  r7                // if a2 == zero
125        ADD     r10, r10, r5            // a2 += a_offset
126        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
127        CMP     r0,  r7                 // if a3 == zero
128        ADD     r0,  r0, r5             // a3 += a_offset
129        LDR     r5, [sp, 44]            // kc
130        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
131
132        SUBS    r5, r5, 8               // kc - 8
133        BLO     4f                      // less than 8 channels?
134
135        # Main loop - 8 bytes
136        # 64 bytes for weights.
137        .p2align 3
1382:
139        VLD1.8  {d0},  [r3]!            // A0
140        VLD1.8  {d10},  [r9]!           // B
141        VLD1.8  {d2}, [r12]!            // A1
142        VLD1.8  {d4}, [r10]!            // A2
143        VLD1.8  {d6},  [r0]!            // A3
144        SUBS    r5, r5, 8
145        PLD     [r3, 128]
146        VMOVL.S8 q0, d0
147        PLD     [r12, 128]
148        VMOVL.S8 q5, d10
149        PLD     [r10, 128]
150        VMOVL.S8 q1, d2
151        PLD     [r0, 128]
152        VMOVL.S8 q2, d4
153        PLD     [r9, 448]
154        VMOVL.S8 q3, d6
155        VMLAL.S16 q8, d10, d0[0]
156        VMLAL.S16 q9, d11, d0[0]
157        VMLAL.S16 q10, d10, d2[0]
158        VMLAL.S16 q11, d11, d2[0]
159        VMLAL.S16 q12, d10, d4[0]
160        VMLAL.S16 q13, d11, d4[0]
161        VMLAL.S16 q14, d10, d6[0]
162        VMLAL.S16 q15, d11, d6[0]
163
164        VLD1.8  {d10},  [r9]!
165        VMOVL.S8 q5, d10
166        VMLAL.S16 q8, d10, d0[1]
167        VMLAL.S16 q9, d11, d0[1]
168        VMLAL.S16 q10, d10, d2[1]
169        VMLAL.S16 q11, d11, d2[1]
170        VMLAL.S16 q12, d10, d4[1]
171        VMLAL.S16 q13, d11, d4[1]
172        VMLAL.S16 q14, d10, d6[1]
173        VMLAL.S16 q15, d11, d6[1]
174
175        VLD1.8  {d10},  [r9]!
176        VMOVL.S8 q5, d10
177        VMLAL.S16 q8, d10, d0[2]
178        VMLAL.S16 q9, d11, d0[2]
179        VMLAL.S16 q10, d10, d2[2]
180        VMLAL.S16 q11, d11, d2[2]
181        VMLAL.S16 q12, d10, d4[2]
182        VMLAL.S16 q13, d11, d4[2]
183        VMLAL.S16 q14, d10, d6[2]
184        VMLAL.S16 q15, d11, d6[2]
185
186        VLD1.8  {d10},  [r9]!
187        VMOVL.S8 q5, d10
188        VMLAL.S16 q8, d10, d0[3]
189        VMLAL.S16 q9, d11, d0[3]
190        VMLAL.S16 q10, d10, d2[3]
191        VMLAL.S16 q11, d11, d2[3]
192        VMLAL.S16 q12, d10, d4[3]
193        VMLAL.S16 q13, d11, d4[3]
194        VMLAL.S16 q14, d10, d6[3]
195        VMLAL.S16 q15, d11, d6[3]
196
197        VLD1.8  {d10},  [r9]!
198        VMOVL.S8 q5, d10
199        VMLAL.S16 q8, d10, d1[0]
200        VMLAL.S16 q9, d11, d1[0]
201        VMLAL.S16 q10, d10, d3[0]
202        VMLAL.S16 q11, d11, d3[0]
203        VMLAL.S16 q12, d10, d5[0]
204        VMLAL.S16 q13, d11, d5[0]
205        VMLAL.S16 q14, d10, d7[0]
206        VMLAL.S16 q15, d11, d7[0]
207
208        VLD1.8  {d10},  [r9]!
209        VMOVL.S8 q5, d10
210        VMLAL.S16 q8, d10, d1[1]
211        VMLAL.S16 q9, d11, d1[1]
212        VMLAL.S16 q10, d10, d3[1]
213        VMLAL.S16 q11, d11, d3[1]
214        VMLAL.S16 q12, d10, d5[1]
215        VMLAL.S16 q13, d11, d5[1]
216        VMLAL.S16 q14, d10, d7[1]
217        VMLAL.S16 q15, d11, d7[1]
218
219        VLD1.8  {d10},  [r9]!
220        VMOVL.S8 q5, d10
221        VMLAL.S16 q8, d10, d1[2]
222        VMLAL.S16 q9, d11, d1[2]
223        VMLAL.S16 q10, d10, d3[2]
224        VMLAL.S16 q11, d11, d3[2]
225        VMLAL.S16 q12, d10, d5[2]
226        VMLAL.S16 q13, d11, d5[2]
227        VMLAL.S16 q14, d10, d7[2]
228        VMLAL.S16 q15, d11, d7[2]
229
230        VLD1.8  {d10},  [r9]!
231        VMOVL.S8 q5, d10
232        VMLAL.S16 q8, d10, d1[3]
233        VMLAL.S16 q9, d11, d1[3]
234        VMLAL.S16 q10, d10, d3[3]
235        VMLAL.S16 q11, d11, d3[3]
236        VMLAL.S16 q12, d10, d5[3]
237        VMLAL.S16 q13, d11, d5[3]
238        VMLAL.S16 q14, d10, d7[3]
239        VMLAL.S16 q15, d11, d7[3]
240        BHS     2b
241
242        # Is there a remainder?- 1-7 bytes of A
243        ADDS    r5, r5, 8
244        BNE     4f
245
2463:
247        # ks loop
248        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
249        BHI     1b
250
251        LDR     r7, [sp, 104]           // cn_stride
252        LDR     r14, [sp, 48]           // p = ks
253
254        # QC8 FP32 quantization
255        VLD1.8  {q0-q1},  [r9]!
256
257        VDUP.32 q2, d12[0]              // magic_bias
258        VDUP.32 q3, d12[1]              // magic_bias_less_output_zero_point
259
260        VCVT.F32.S32 q8,  q8
261        VCVT.F32.S32 q9,  q9
262        VCVT.F32.S32 q10, q10
263        VCVT.F32.S32 q11, q11
264        VCVT.F32.S32 q12, q12
265        VCVT.F32.S32 q13, q13
266        VCVT.F32.S32 q14, q14
267        VCVT.F32.S32 q15, q15
268
269        VMUL.F32 q8,  q8, q0            // multiplier
270        VMUL.F32 q9,  q9, q1
271        VMUL.F32 q10, q10, q0
272        VMUL.F32 q11, q11, q1
273        VMUL.F32 q12, q12, q0
274        VMUL.F32 q13, q13, q1
275        VMUL.F32 q14, q14, q0
276        VMUL.F32 q15, q15, q1
277
278        VADD.F32 q8,  q8, q2            // magic_bias
279        VADD.F32 q9,  q9, q2
280        VADD.F32 q10, q10, q2
281        VADD.F32 q11, q11, q2
282        VADD.F32 q12, q12, q2
283        VADD.F32 q13, q13, q2
284        VADD.F32 q14, q14, q2
285        VADD.F32 q15, q15, q2
286
287        VQSUB.S32 q8,  q8, q3           // magic_bias_less_output_zero_point
288        VQSUB.S32 q9,  q9, q3
289        VQSUB.S32 q10, q10, q3
290        VQSUB.S32 q11, q11, q3
291        VQSUB.S32 q12, q12, q3
292        VQSUB.S32 q13, q13, q3
293        VQSUB.S32 q14, q14, q3
294        VQSUB.S32 q15, q15, q3
295
296
297        VQMOVN.S32 d16, q8
298        VQMOVN.S32 d17, q9
299        VQMOVN.S32 d18, q10
300        VQMOVN.S32 d19, q11
301        VQMOVN.S32 d20, q12
302        VQMOVN.S32 d21, q13
303        VQMOVN.S32 d22, q14
304        VQMOVN.S32 d23, q15
305
306
307        VDUP.8  q12, d13[6]             // output_min
308
309        VQMOVN.S16 d0,  q8
310        VQMOVN.S16 d1,  q9
311        VQMOVN.S16 d2, q10
312        VQMOVN.S16 d3, q11
313
314        VDUP.8  q13, d13[7]             // output_max
315
316        VMAX.S8 q0, q0, q12
317        VMAX.S8 q1, q1, q12
318
319        SUBS    r1, r1, 8               // nc -= 8
320
321        VMIN.S8 q0, q0, q13
322        VMIN.S8 q1, q1, q13
323
324        # Store full 4 x 8
325        BLO     5f
326        VST1.8  {d3}, [r6], r7
327        VST1.8  {d2}, [r8], r7
328        VST1.8  {d1}, [r4], r7
329        VST1.8  {d0}, [r11], r7
330        SUB     r2, r2, r14             // a -= ks
331        BHI     0b
332
333        VPOP    {d10-d13}
334        ADD     sp, sp, 20                          // skip pad of 12, r2, r3
335        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
336
337        # Remainder- 1 to 7 bytes of A
338        .p2align 3
3394:
340        AND     r5, r5, 7               // kc remainder 1 to 7
341
342        VLD1.8  {d0},  [r3]
343        VLD1.8  {d10},  [r9]!
344        VLD1.8  {d2}, [r12]
345        VLD1.8  {d4}, [r10]
346        VLD1.8  {d6},  [r0]
347
348        VMOVL.S8 q0, d0
349        VMOVL.S8 q5, d10
350        VMOVL.S8 q1, d2
351        VMOVL.S8 q2, d4
352        VMOVL.S8 q3, d6
353        VMLAL.S16 q8, d10, d0[0]
354        VMLAL.S16 q9, d11, d0[0]
355        VMLAL.S16 q10, d10, d2[0]
356        VMLAL.S16 q11, d11, d2[0]
357        VMLAL.S16 q12, d10, d4[0]
358        VMLAL.S16 q13, d11, d4[0]
359        VMLAL.S16 q14, d10, d6[0]
360        VMLAL.S16 q15, d11, d6[0]
361        CMP     r5, 2
362        BLO     3b
363
364        VLD1.8  {d10},  [r9]!
365        VMOVL.S8 q5, d10
366        VMLAL.S16 q8, d10, d0[1]
367        VMLAL.S16 q9, d11, d0[1]
368        VMLAL.S16 q10, d10, d2[1]
369        VMLAL.S16 q11, d11, d2[1]
370        VMLAL.S16 q12, d10, d4[1]
371        VMLAL.S16 q13, d11, d4[1]
372        VMLAL.S16 q14, d10, d6[1]
373        VMLAL.S16 q15, d11, d6[1]
374        BEQ     3b
375
376        VLD1.8  {d10},  [r9]!
377        VMOVL.S8 q5, d10
378        VMLAL.S16 q8, d10, d0[2]
379        VMLAL.S16 q9, d11, d0[2]
380        VMLAL.S16 q10, d10, d2[2]
381        VMLAL.S16 q11, d11, d2[2]
382        VMLAL.S16 q12, d10, d4[2]
383        VMLAL.S16 q13, d11, d4[2]
384        VMLAL.S16 q14, d10, d6[2]
385        VMLAL.S16 q15, d11, d6[2]
386        CMP     r5, 4
387        BLO     3b
388
389        VLD1.8  {d10},  [r9]!
390        VMOVL.S8 q5, d10
391        VMLAL.S16 q8, d10, d0[3]
392        VMLAL.S16 q9, d11, d0[3]
393        VMLAL.S16 q10, d10, d2[3]
394        VMLAL.S16 q11, d11, d2[3]
395        VMLAL.S16 q12, d10, d4[3]
396        VMLAL.S16 q13, d11, d4[3]
397        VMLAL.S16 q14, d10, d6[3]
398        VMLAL.S16 q15, d11, d6[3]
399        BEQ     3b
400
401        VLD1.8  {d10},  [r9]!
402        VMOVL.S8 q5, d10
403        VMLAL.S16 q8, d10, d1[0]
404        VMLAL.S16 q9, d11, d1[0]
405        VMLAL.S16 q10, d10, d3[0]
406        VMLAL.S16 q11, d11, d3[0]
407        VMLAL.S16 q12, d10, d5[0]
408        VMLAL.S16 q13, d11, d5[0]
409        VMLAL.S16 q14, d10, d7[0]
410        VMLAL.S16 q15, d11, d7[0]
411        CMP     r5, 6
412        BLO     3b
413
414        VLD1.8  {d10},  [r9]!
415        VMOVL.S8 q5, d10
416        VMLAL.S16 q8, d10, d1[1]
417        VMLAL.S16 q9, d11, d1[1]
418        VMLAL.S16 q10, d10, d3[1]
419        VMLAL.S16 q11, d11, d3[1]
420        VMLAL.S16 q12, d10, d5[1]
421        VMLAL.S16 q13, d11, d5[1]
422        VMLAL.S16 q14, d10, d7[1]
423        VMLAL.S16 q15, d11, d7[1]
424        BEQ     3b
425
426        VLD1.8  {d10},  [r9]!
427        VMOVL.S8 q5, d10
428        VMLAL.S16 q8, d10, d1[2]
429        VMLAL.S16 q9, d11, d1[2]
430        VMLAL.S16 q10, d10, d3[2]
431        VMLAL.S16 q11, d11, d3[2]
432        VMLAL.S16 q12, d10, d5[2]
433        VMLAL.S16 q13, d11, d5[2]
434        VMLAL.S16 q14, d10, d7[2]
435        VMLAL.S16 q15, d11, d7[2]
436        B       3b
437
438        # Store odd width
439        .p2align 3
4405:
441        TST     r1, 4
442        BEQ     6f
443        VST1.32 {d3[0]}, [r6]!
444        VST1.32 {d2[0]}, [r8]!
445        VST1.32 {d1[0]}, [r4]!
446        VST1.32 {d0[0]}, [r11]!
447        VEXT.8  q1, q1, q1, 4
448        VEXT.8  q0, q0, q0, 4
4496:
450        TST     r1, 2
451        BEQ     7f
452        VST1.16 {d3[0]}, [r6]!
453        VST1.16 {d2[0]}, [r8]!
454        VST1.16 {d1[0]}, [r4]!
455        VST1.16 {d0[0]}, [r11]!
456        VEXT.8  q1, q1, q1, 2
457        VEXT.8  q0, q0, q0, 2
458
4597:
460        TST     r1, 1
461        BEQ     8f
462        VST1.8  {d3[0]}, [r6]
463        VST1.8  {d2[0]}, [r8]
464        VST1.8  {d1[0]}, [r4]
465        VST1.8  {d0[0]}, [r11]
466
4678:
468        VPOP    {d10-d13}
469        ADD     sp, sp, 20                          // skip pad of 12, r2, r3
470        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
471
472END_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64
473#ifdef __ELF__
474.section ".note.GNU-stack","",%progbits
475#endif
476