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