xref: /aosp_15_r20/external/XNNPACK/src/qc8-igemm/gen/4x8c4-minmax-fp32-aarch32-neondot-ld64.S (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
1// Auto-generated file. Do not edit!
2//   Template: src/qs8-igemm/4x8c4-aarch32-neondot-ld64.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_qc8_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_ld64(
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_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 4 bytes
47//  struct {
48//    int16_t output_zero_point;  d13[2]
49//    int8_t output_min;          d13[6]
50//    int8_t output_max;          d13[7]
51//  } xnn_qs8_minmax_params.neonv8;
52
53// iOS does not support 32 bit ARM with Neon DotProduct.
54#ifndef __APPLE__
55BEGIN_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_ld64
56        ADD     r2, r2, 3               // kc = (kc + 3) & ~3
57        BIC     r2, r2, 3
58        # Push 96 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   {d8-d13}                                         // +48 = 96
63
64        LDR     r11, [sp, 104]          // c
65        LDR     r6, [sp, 108]           // cm_stride
66        LDR     r2, [sp, 96]            // a
67        LDR     r9, [sp, 100]           // w
68        LDR     r5, [sp, 124]           // 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 {d13[]}, [r5]           // QC8 params
84
850:
86        # Load initial bias from w into accumulators
87        VLDM    r9!, {d16-d19}          // Bias
88        VMOV    q10, q8
89        VMOV    q11, q9
90        LDR     r7, [sp, 120]           // zero
91        VMOV    q12, q8
92        VMOV    q13, q9
93        VMOV    q14, q8
94        VMOV    q15, q9
95
961:
97        # Load next 4 A pointers
98        LDR     r3, [r2,  0]
99        LDR     r12, [r2,  4]
100        LDR     r10, [r2,  8]
101        LDR     r0, [r2, 12]
102        ADD     r2, r2, 16
103
104        # Add a_offset
105        LDR     r5, [sp, 116]           // a_offset
106        CMP     r3,  r7                 // if a0 == zero
107        ADD     r3,  r3, r5             // a0 += a_offset
108        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
109        CMP     r12,  r7                // if a1 == zero
110        ADD     r12, r12, r5            // a1 += a_offset
111        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
112        CMP     r10,  r7                // if a2 == zero
113        ADD     r10, r10, r5            // a2 += a_offset
114        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
115        CMP     r0,  r7                 // if a3 == zero
116        ADD     r0,  r0, r5             // a3 += a_offset
117        LDR     r5, [sp, 52]            // kc
118        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
119
120        SUBS    r5, r5, 8               // kc - 8
121        BLO     4f                      // less than 8 channels?
122
123        # Main loop - 8 bytes of A.
124        # 16 SDOT, 4 LD64 A, 4 LD128 B
125        .p2align 3
1262:
127        VLD1.8  {d0},  [r3]!            // A0
128        VLD1.8  {q2},  [r9]!            // B0
129        VLD1.8  {d1}, [r12]!            // A1
130        VLD1.8  {q3},  [r9]!            // B1
131        VLD1.8  {d2}, [r10]!            // A2
132        VLD1.8  {q4},  [r9]!            // B2
133        VLD1.8  {d3},  [r0]!            // A3
134        VLD1.8  {q5},  [r9]!            // B3
135        SUBS    r5, r5, 8
136
137        VSDOT.S8 q8, q2, d0[0]
138        VSDOT.S8 q9, q3, d0[0]
139        VSDOT.S8 q10, q2, d1[0]
140        VSDOT.S8 q11, q3, d1[0]
141        VSDOT.S8 q12, q2, d2[0]
142        VSDOT.S8 q13, q3, d2[0]
143        VSDOT.S8 q14, q2, d3[0]
144        VSDOT.S8 q15, q3, d3[0]
145
146        VSDOT.S8 q8, q4, d0[1]
147        VSDOT.S8 q9, q5, d0[1]
148        VSDOT.S8 q10, q4, d1[1]
149        VSDOT.S8 q11, q5, d1[1]
150        VSDOT.S8 q12, q4, d2[1]
151        VSDOT.S8 q13, q5, d2[1]
152        VSDOT.S8 q14, q4, d3[1]
153        VSDOT.S8 q15, q5, d3[1]
154        BHS     2b
155
156        # Is there a remainder?- 4 bytes of A
157        TST     r5, 4
158        BNE     4f
159
1603:
161        # ks loop
162        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
163        BHI     1b
164
165        LDR     r7, [sp, 112]           // cn_stride
166        LDR     r14, [sp, 56]           // p = ks
167
168        # QC8 FP32 quantization
169        VLD1.8  {q0-q1},  [r9]!
170
171        VCVT.F32.S32 q8,  q8
172        VCVT.F32.S32 q9,  q9
173        VCVT.F32.S32 q10, q10
174        VCVT.F32.S32 q11, q11
175        VCVT.F32.S32 q12, q12
176        VCVT.F32.S32 q13, q13
177        VCVT.F32.S32 q14, q14
178        VCVT.F32.S32 q15, q15
179
180        VMUL.F32 q8,  q8, q0            // multiplier
181        VMUL.F32 q9,  q9, q1
182        VMUL.F32 q10, q10, q0
183        VMUL.F32 q11, q11, q1
184        VMUL.F32 q12, q12, q0
185        VMUL.F32 q13, q13, q1
186        VMUL.F32 q14, q14, q0
187        VMUL.F32 q15, q15, q1
188
189        VCVTN.S32.F32 q8,  q8
190        VCVTN.S32.F32 q9,  q9
191        VCVTN.S32.F32 q10, q10
192        VCVTN.S32.F32 q11, q11
193        VCVTN.S32.F32 q12, q12
194        VCVTN.S32.F32 q13, q13
195        VCVTN.S32.F32 q14, q14
196        VCVTN.S32.F32 q15, q15
197        VDUP.16 q0, d13[2]              // output_zero_point
198
199        VQMOVN.S32 d16, q8
200        VQMOVN.S32 d17, q9
201        VQMOVN.S32 d18, q10
202        VQMOVN.S32 d19, q11
203        VQMOVN.S32 d20, q12
204        VQMOVN.S32 d21, q13
205        VQMOVN.S32 d22, q14
206        VQMOVN.S32 d23, q15
207
208        VQADD.S16 q8,  q8, q0
209        VQADD.S16 q9,  q9, q0
210        VQADD.S16 q10, q10, q0
211        VQADD.S16 q11, q11, q0
212
213        VDUP.8  q12, d13[6]             // output_min
214
215        VQMOVN.S16 d0,  q8
216        VQMOVN.S16 d1,  q9
217        VQMOVN.S16 d2, q10
218        VQMOVN.S16 d3, q11
219
220        VDUP.8  q13, d13[7]             // output_max
221
222        VMAX.S8 q0, q0, q12
223        VMAX.S8 q1, q1, q12
224
225        SUBS    r1, r1, 8               // nc -= 8
226
227        VMIN.S8 q0, q0, q13
228        VMIN.S8 q1, q1, q13
229
230        # Store full 4 x 8
231        BLO     5f
232        VST1.8  {d3}, [r6], r7
233        VST1.8  {d2}, [r8], r7
234        VST1.8  {d1}, [r4], r7
235        VST1.8  {d0}, [r11], r7
236        SUB     r2, r2, r14             // a -= ks
237        BHI     0b
238
239        VPOP    {d8-d13}
240        ADD     sp, sp, 12              // skip pad, r2, r3
241        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
242
2434:
244        # Remainder- 4 bytes of A
245        VLD1.32 {d0[0]},  [r3]!         // A0
246        VLD1.32 {q2},  [r9]!            // B0
247        VLD1.32 {d1[0]}, [r12]!         // A1
248        VLD1.32 {q3},  [r9]!            // B1
249        VLD1.32 {d2[0]}, [r10]!         // A2
250        VLD1.32 {d3[0]},  [r0]!         // A3
251
252        VSDOT.S8 q8, q2, d0[0]
253        VSDOT.S8 q9, q3, d0[0]
254        VSDOT.S8 q10, q2, d1[0]
255        VSDOT.S8 q11, q3, d1[0]
256        VSDOT.S8 q12, q2, d2[0]
257        VSDOT.S8 q13, q3, d2[0]
258        VSDOT.S8 q14, q2, d3[0]
259        VSDOT.S8 q15, q3, d3[0]
260        B       3b
261
262        # Store odd width
263        .p2align 3
2645:
265        TST     r1, 4
266        BEQ     6f
267        VST1.32 {d3[0]}, [r6]!
268        VST1.32 {d2[0]}, [r8]!
269        VST1.32 {d1[0]}, [r4]!
270        VST1.32 {d0[0]}, [r11]!
271        VEXT.8  q1, q1, q1, 4
272        VEXT.8  q0, q0, q0, 4
2736:
274        TST     r1, 2
275        BEQ     7f
276        VST1.16 {d3[0]}, [r6]!
277        VST1.16 {d2[0]}, [r8]!
278        VST1.16 {d1[0]}, [r4]!
279        VST1.16 {d0[0]}, [r11]!
280        VEXT.8  q1, q1, q1, 2
281        VEXT.8  q0, q0, q0, 2
282
2837:
284        TST     r1, 1
285        BEQ     8f
286        VST1.8  {d3[0]}, [r6]
287        VST1.8  {d2[0]}, [r8]
288        VST1.8  {d1[0]}, [r4]
289        VST1.8  {d0[0]}, [r11]
290
2918:
292        VPOP    {d8-d13}
293        ADD     sp, sp, 12              // skip pad, r2, r3
294        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
295
296END_FUNCTION xnn_qc8_igemm_minmax_fp32_ukernel_4x8c4__aarch32_neondot_ld64
297#endif  // __APPLE__
298
299#ifdef __ELF__
300.section ".note.GNU-stack","",%progbits
301#endif
302