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