xref: /aosp_15_r20/external/XNNPACK/src/qs8-igemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-cortex-a55.S (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1// Auto-generated file. Do not edit!
2//   Template: src/qs8-igemm/4x8c4-aarch32-neondot-cortex-a55.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_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55(
16//     size_t mr,                                      r0
17//     size_t nc,                                      r1
18//     size_t kc,                                      r2 -> r5 -> sp + 52
19//     size_t ks,                                      r3 -> sp + 56 -> r14
20//     const int8_t**restrict a,           sp + 96  -> r2
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//     size_t a_offset,                    sp + 116 -> (r5)
26//     const int8_t* zero,                 sp + 120 -> (r7)
27//     xnn_qs8_conv_minmax_params*params); sp + 124 -> (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
33// A1  r12  d1
34// A2  r10  d2
35// A3   r0  d3
36
37// B    r9  q2 q3 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 q7
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
56// iOS does not support 32 bit ARM with Neon DotProduct.
57#ifndef __APPLE__
58BEGIN_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55
59        ADD     r2, r2, 3               // kc = (kc + 3) & ~3
60        BIC     r2, r2, 3
61        # Push 96 bytes
62        # r2 will be reloaded in outer loop.  r3 is ks
63        PUSH    {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}   // +44
64        SUB     sp, sp, 4                                        // 4
65        VPUSH   {d8-d13}                                         // +48 = 96
66
67        LDR     r11, [sp, 104]          // c
68        LDR     r6, [sp, 108]           // cm_stride
69        LDR     r2, [sp, 96]            // a
70        LDR     r9, [sp, 100]           // w
71        LDR     r5, [sp, 124]           // params
72        MOV     r14, r3                 // p = ks
73
74        # Clamp C pointers
75        CMP     r0, 2                   // if mr >= 2
76        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
77        MOVLO   r4, r11                 // c1
78                                        // if mr > 2
79        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
80        MOVLS   r8, r4                  // c2
81        CMP     r0, 4                   // if mr >=4
82        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
83        MOVLO   r6, r8                  // c3
84
85        # Load params values
86        VLDM    r5, {d12-d13}           // RNDNU params
87
880:
89        # Load initial bias from w into accumulators
90        VLDM    r9!, {d16-d19}          // Bias
91        VMOV    q10, q8
92        VMOV    q11, q9
93        LDR     r7, [sp, 120]           // zero
94        VMOV    q12, q8
95        VMOV    q13, q9
96        VMOV    q14, q8
97        VMOV    q15, q9
98
991:
100        # Load next 4 A pointers + Add a_offset + Prologue
101        # - Load next 4 A pointers to GPR
102        # - Adjust A pointers by a_offset if not zero
103        # - Load prologue
104        # - Load k = kc from stack
105        LDR     r3, [r2,  0]            // A0
106        LDR     r5, [sp, 116]           // a_offset
107        CMP     r3,  r7                 // if a0 == zero
108        LDR     r12, [r2,  4]           // A1
109        ADD     r3,  r3, r5             // a0 += a_offset
110        LDR     r10, [r2,  8]           // A2
111        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
112        LDR     r0, [r2, 12]            // A3
113        CMP     r12,  r7                // if a1 == zero
114        VLD1.8  {d4},  [r9]!            // B0
115        ADD     r12, r12, r5            // a1 += a_offset
116        VLD1.8  {d5},  [r9]!            // B1
117        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
118        VLD1.8  {d6},  [r9]!            // B2
119        CMP     r10,  r7                // if a2 == zero
120        VLD1.8  {d7},  [r9]!            // B3
121        ADD     r10, r10, r5            // a2 += a_offset
122        VLD1.8  {d0},  [r3]!            // A0
123        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
124        VLD1.8  {d1}, [r12]!            // A1
125        CMP     r0,  r7                 // if a3 == zero
126        ADD     r0,  r0, r5             // a3 += a_offset
127        LDR     r5, [sp, 52]            // k = kc
128        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
129        SUBS    r5, r5, 8               // k = k - 8
130        ADD     r2, r2, 16
131
132        BLO     6f                      // less than 8 channels?
133
134        SUBS    r5, r5, 8               // k = k - 8
135        BLO     3f                      // less than 8 channels?
136
137        # Main loop - 8 bytes of A.
138        # 16 SDOT, 12 LD64
139        .p2align 3
1402:
141        VSDOT.S8 q8, q2, d0[0]
142        VLD1.8  {d2}, [r10]!            // A2
143        VSDOT.S8 q9, q3, d0[0]
144        VLD1.8  {d3},  [r0]!            // A3
145        VSDOT.S8 q10, q2, d1[0]
146        VLD1.8  {d8},  [r9]!            // B4
147        VSDOT.S8 q11, q3, d1[0]
148        VLD1.8  {d9},  [r9]!            // B5
149        VSDOT.S8 q12, q2, d2[0]
150        VLD1.8  {d10},  [r9]!           // B6
151        VSDOT.S8 q13, q3, d2[0]
152        VLD1.8  {d11},  [r9]!           // B7
153        VSDOT.S8 q14, q2, d3[0]
154        VSDOT.S8 q15, q3, d3[0]
155        SUBS    r5, r5, 8
156
157        VSDOT.S8 q8, q4, d0[1]
158        VLD1.8  {d4},  [r9]!            // B0
159        VSDOT.S8 q9, q5, d0[1]
160        VLD1.8  {d5},  [r9]!            // B1
161        VSDOT.S8 q10, q4, d1[1]
162        VLD1.8  {d6},  [r9]!            // B2
163        VSDOT.S8 q11, q5, d1[1]
164        VLD1.8  {d7},  [r9]!            // B3
165        VSDOT.S8 q12, q4, d2[1]
166        VLD1.8  {d0},  [r3]!            // A0
167        VSDOT.S8 q13, q5, d2[1]
168        VLD1.8  {d1}, [r12]!            // A1
169        VSDOT.S8 q14, q4, d3[1]
170        VSDOT.S8 q15, q5, d3[1]
171        BHS     2b
172
173        # Epilogue
174        .p2align 3
1753:
176        VSDOT.S8 q8, q2, d0[0]
177        VLD1.8  {d2}, [r10]!            // A2
178        VSDOT.S8 q9, q3, d0[0]
179        VLD1.8  {d3},  [r0]!            // A3
180        VSDOT.S8 q10, q2, d1[0]
181        VLD1.8  {d8},  [r9]!            // B4
182        VSDOT.S8 q11, q3, d1[0]
183        VLD1.8  {d9},  [r9]!            // B5
184        VSDOT.S8 q12, q2, d2[0]
185        VLD1.8  {d10},  [r9]!           // B6
186        VSDOT.S8 q13, q3, d2[0]
187        VLD1.8  {d11},  [r9]!           // B7
188        VSDOT.S8 q14, q2, d3[0]
189        VSDOT.S8 q15, q3, d3[0]
190        TST     r5, 5
191
192        VSDOT.S8 q8, q4, d0[1]
193        VSDOT.S8 q9, q5, d0[1]
194        VSDOT.S8 q10, q4, d1[1]
195        VSDOT.S8 q11, q5, d1[1]
196        VSDOT.S8 q12, q4, d2[1]
197        VSDOT.S8 q13, q5, d2[1]
198        VSDOT.S8 q14, q4, d3[1]
199        VSDOT.S8 q15, q5, d3[1]
200        # Is there a remainder?- 4 bytes of A
201        BNE     5f
202
2034:
204        # ks loop
205        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
206        BHI     1b
207
208        LDR     r7, [sp, 112]           // cn_stride
209        LDR     r14, [sp, 56]           // p = ks
210
211        # RNDNU quantization
212        VDUP.32 q0, d12[0]              // right_pre_shift
213
214        VQSHL.S32 q8,  q8, q0
215        VQSHL.S32 q9,  q9, q0
216        VQSHL.S32 q10, q10, q0
217        VQSHL.S32 q11, q11, q0
218        VQSHL.S32 q12, q12, q0
219        VQSHL.S32 q13, q13, q0
220        VQSHL.S32 q14, q14, q0
221        VQSHL.S32 q15, q15, q0
222
223        VDUP.32 q2, d13[0]              // right_post_shift
224
225        VQDMULH.S32 q8,  q8, d12[1]     // multiplier
226        VQDMULH.S32 q9,  q9, d12[1]
227        VQDMULH.S32 q10, q10, d12[1]
228        VQDMULH.S32 q11, q11, d12[1]
229        VQDMULH.S32 q12, q12, d12[1]
230        VQDMULH.S32 q13, q13, d12[1]
231        VQDMULH.S32 q14, q14, d12[1]
232        VQDMULH.S32 q15, q15, d12[1]
233
234        VRSHL.S32 q8,  q8, q2
235        VRSHL.S32 q9,  q9, q2
236        VRSHL.S32 q10, q10, q2
237        VRSHL.S32 q11, q11, q2
238        VRSHL.S32 q12, q12, q2
239        VRSHL.S32 q13, q13, q2
240        VRSHL.S32 q14, q14, q2
241        VRSHL.S32 q15, q15, q2
242        VDUP.16 q0, d13[2]              // output_zero_point
243
244        VQMOVN.S32 d16, q8
245        VQMOVN.S32 d17, q9
246        VQMOVN.S32 d18, q10
247        VQMOVN.S32 d19, q11
248        VQMOVN.S32 d20, q12
249        VQMOVN.S32 d21, q13
250        VQMOVN.S32 d22, q14
251        VQMOVN.S32 d23, q15
252
253        VQADD.S16 q8,  q8, q0
254        VQADD.S16 q9,  q9, q0
255        VQADD.S16 q10, q10, q0
256        VQADD.S16 q11, q11, q0
257
258        VDUP.8  q12, d13[6]             // output_min
259
260        VQMOVN.S16 d0,  q8
261        VQMOVN.S16 d1,  q9
262        VQMOVN.S16 d2, q10
263        VQMOVN.S16 d3, q11
264
265        VDUP.8  q13, d13[7]             // output_max
266
267        VMAX.S8 q0, q0, q12
268        VMAX.S8 q1, q1, q12
269
270        SUBS    r1, r1, 8               // nc -= 8
271
272        VMIN.S8 q0, q0, q13
273        VMIN.S8 q1, q1, q13
274
275        # Store full 4 x 8
276        BLO     7f
277        VST1.8  {d3}, [r6], r7
278        VST1.8  {d2}, [r8], r7
279        VST1.8  {d1}, [r4], r7
280        VST1.8  {d0}, [r11], r7
281        SUB     r2, r2, r14             // a -= ks
282        BHI     0b
283
284        VPOP    {d8-d13}
285        ADD     sp, sp, 12              // skip pad, r2, r3
286        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
287
288        # Remainder prologue
289        .p2align 3
2905:
291        VLD1.8  {d4},  [r9]!            // B0
292        VLD1.8  {d0},  [r3]!            // A0
293        VLD1.8  {d5},  [r9]!            // B1
294        VLD1.8  {d6},  [r9]!            // B2
295        VLD1.8  {d1}, [r12]!            // A1
296        VLD1.8  {d7},  [r9]!            // B3
297
298        # Remainder- 4 bytes of A
2996:
300        VSDOT.S8 q8, q2, d0[0]
301        VLD1.32 {d2[0]}, [r10]!         // A2
302        VSDOT.S8 q9, q3, d0[0]
303        VLD1.32 {d3[0]},  [r0]!         // A3
304        VSDOT.S8 q10, q2, d1[0]
305        SUB     r3, r3, 4               // Rewind A0
306        VSDOT.S8 q11, q3, d1[0]
307        SUB     r12, r12, 4             // Rewind A1
308        VSDOT.S8 q12, q2, d2[0]
309        VSDOT.S8 q13, q3, d2[0]
310        VSDOT.S8 q14, q2, d3[0]
311        VSDOT.S8 q15, q3, d3[0]
312        B       4b
313
314        # Store odd width
315        .p2align 3
3167:
317        TST     r1, 4
318        BEQ     8f
319        VST1.32 {d3[0]}, [r6]!
320        VST1.32 {d2[0]}, [r8]!
321        VST1.32 {d1[0]}, [r4]!
322        VST1.32 {d0[0]}, [r11]!
323        VEXT.8  q1, q1, q1, 4
324        VEXT.8  q0, q0, q0, 4
3258:
326        TST     r1, 2
327        BEQ     9f
328        VST1.16 {d3[0]}, [r6]!
329        VST1.16 {d2[0]}, [r8]!
330        VST1.16 {d1[0]}, [r4]!
331        VST1.16 {d0[0]}, [r11]!
332        VEXT.8  q1, q1, q1, 2
333        VEXT.8  q0, q0, q0, 2
334
3359:
336        TST     r1, 1
337        BEQ     10f
338        VST1.8  {d3[0]}, [r6]
339        VST1.8  {d2[0]}, [r8]
340        VST1.8  {d1[0]}, [r4]
341        VST1.8  {d0[0]}, [r11]
342
34310:
344        VPOP    {d8-d13}
345        ADD     sp, sp, 12              // skip pad, r2, r3
346        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
347
348END_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_cortex_a55
349#endif  // __APPLE__
350
351#ifdef __ELF__
352.section ".note.GNU-stack","",%progbits
353#endif
354