• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2022 Google LLC
2//
3// This source code is licensed under the BSD-style license found in the
4// LICENSE file in the root directory of this source tree.
5
6$assert REQUANTIZATION in ["FP32", "RNDNU"]
7$assert not CHANNELWISE or REQUANTIZATION == "FP32"
8$assert DATATYPE in ["QC8", "QS8"]
9$assert DATATYPE != "QC8" or REQUANTIZATION == "FP32"
10
11#include <xnnpack/assembly.h>
12
13.syntax unified
14
15$PARAMS_UNION = "xnn_qs8_minmax_params" if CHANNELWISE else "xnn_qs8_conv_minmax_params"
16# LINT.IfChange
17// void xnn_${DATATYPE.lower()}_igemm_minmax_${REQUANTIZATION.lower()}_ukernel_4x8c4__aarch32_neondot_ld64(
18//     size_t mr,                                      r0
19//     size_t nc,                                      r1
20//     size_t kc,                                      r2 -> r5 -> sp + 52
21//     size_t ks,                                      r3 -> sp + 56 -> r14
22//     const int8_t**restrict a,           sp + 96  -> r2
23//     const void*restrict w,              sp + 100 -> r9
24//     int8_t*restrict c,                  sp + 104 -> r11
25//     size_t cm_stride,                   sp + 108 -> (r6)
26//     size_t cn_stride,                   sp + 112 -> (r7)
27//     size_t a_offset,                    sp + 116 -> (r5)
28//     const int8_t* zero,                 sp + 120 -> (r7)
29//     ${PARAMS_UNION}*params); sp + 124 -> (r5)
30
31// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
32
33// Register usage
34// A0   r3  d0
35// A1  r12  d1
36// A2  r10  d2
37// A3   r0  d3
38
39// B    r9  q2 q3 q4 q5
40
41// C0  r11 d16-d17  q8  d18-d19  q9
42// C1   r4 d20-d21 q10  d22-d23 q11
43// C2   r8 d24-d25 q12  d26-d27 q13
44// C3   r6 d28-d29 q14  d30-d31 q15
45
46// unused q7
47
48$if REQUANTIZATION == "RNDNU":
49  // params structure is 16 bytes
50  //  struct {
51  //    int32_t right_pre_shift;    d12[0]
52  //    int32_t multiplier;         d12[1]
53  //    int32_t right_post_shift;   d13[0]
54  //    int16_t output_zero_point;  d13[2]
55  //    int8_t output_min;          d13[6]
56  //    int8_t output_max;          d13[7]
57  //  } rndnu_neon;
58$else:
59  // params structure is 4 bytes
60  //  struct {
61  //    int16_t output_zero_point;  d13[2]
62  //    int8_t output_min;          d13[6]
63  //    int8_t output_max;          d13[7]
64  //  } xnn_qs8_minmax_params.neonv8;
65
66// iOS does not support 32 bit ARM with Neon DotProduct.
67#ifndef __APPLE__
68BEGIN_FUNCTION xnn_${DATATYPE.lower()}_igemm_minmax_${REQUANTIZATION.lower()}_ukernel_4x8c4__aarch32_neondot_ld64
69        ADD     r2, r2, 3               // kc = (kc + 3) & ~3
70        BIC     r2, r2, 3
71        # Push 96 bytes
72        # r2 will be reloaded in outer loop.  r3 is ks
73        PUSH    {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}   // +44
74        SUB     sp, sp, 4                                        // 4
75        VPUSH   {d8-d13}                                         // +48 = 96
76
77        LDR     r11, [sp, 104]          // c
78        LDR     r6, [sp, 108]           // cm_stride
79        LDR     r2, [sp, 96]            // a
80        LDR     r9, [sp, 100]           // w
81        LDR     r5, [sp, 124]           // params
82        MOV     r14, r3                 // p = ks
83
84        # Clamp C pointers
85        CMP     r0, 2                   // if mr >= 2
86        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
87        MOVLO   r4, r11                 // c1
88                                        // if mr > 2
89        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
90        MOVLS   r8, r4                  // c2
91        CMP     r0, 4                   // if mr >=4
92        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
93        MOVLO   r6, r8                  // c3
94
95        # Load params values
96        $if REQUANTIZATION == "RNDNU":
97          VLDM    r5, {d12-d13}           // RNDNU params
98        $else:
99          VLD1.32 {d13[]}, [r5]           // QC8 params
100
1010:
102        # Load initial bias from w into accumulators
103        VLDM    r9!, {d16-d19}          // Bias
104        VMOV    q10, q8
105        VMOV    q11, q9
106        LDR     r7, [sp, 120]           // zero
107        VMOV    q12, q8
108        VMOV    q13, q9
109        VMOV    q14, q8
110        VMOV    q15, q9
111
1121:
113        # Load next 4 A pointers
114        LDR     r3, [r2,  0]
115        LDR     r12, [r2,  4]
116        LDR     r10, [r2,  8]
117        LDR     r0, [r2, 12]
118        ADD     r2, r2, 16
119
120        # Add a_offset
121        LDR     r5, [sp, 116]           // a_offset
122        CMP     r3,  r7                 // if a0 == zero
123        ADD     r3,  r3, r5             // a0 += a_offset
124        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
125        CMP     r12,  r7                // if a1 == zero
126        ADD     r12, r12, r5            // a1 += a_offset
127        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
128        CMP     r10,  r7                // if a2 == zero
129        ADD     r10, r10, r5            // a2 += a_offset
130        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
131        CMP     r0,  r7                 // if a3 == zero
132        ADD     r0,  r0, r5             // a3 += a_offset
133        LDR     r5, [sp, 52]            // kc
134        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
135
136        SUBS    r5, r5, 8               // kc - 8
137        BLO     4f                      // less than 8 channels?
138
139        # Main loop - 8 bytes of A.
140        # 16 SDOT, 4 LD64 A, 4 LD128 B
141        .p2align 3
1422:
143        VLD1.8  {d0},  [r3]!            // A0
144        VLD1.8  {q2},  [r9]!            // B0
145        VLD1.8  {d1}, [r12]!            // A1
146        VLD1.8  {q3},  [r9]!            // B1
147        VLD1.8  {d2}, [r10]!            // A2
148        VLD1.8  {q4},  [r9]!            // B2
149        VLD1.8  {d3},  [r0]!            // A3
150        VLD1.8  {q5},  [r9]!            // B3
151        SUBS    r5, r5, 8
152
153        VSDOT.S8 q8, q2, d0[0]
154        VSDOT.S8 q9, q3, d0[0]
155        VSDOT.S8 q10, q2, d1[0]
156        VSDOT.S8 q11, q3, d1[0]
157        VSDOT.S8 q12, q2, d2[0]
158        VSDOT.S8 q13, q3, d2[0]
159        VSDOT.S8 q14, q2, d3[0]
160        VSDOT.S8 q15, q3, d3[0]
161
162        VSDOT.S8 q8, q4, d0[1]
163        VSDOT.S8 q9, q5, d0[1]
164        VSDOT.S8 q10, q4, d1[1]
165        VSDOT.S8 q11, q5, d1[1]
166        VSDOT.S8 q12, q4, d2[1]
167        VSDOT.S8 q13, q5, d2[1]
168        VSDOT.S8 q14, q4, d3[1]
169        VSDOT.S8 q15, q5, d3[1]
170        BHS     2b
171
172        # Is there a remainder?- 4 bytes of A
173        TST     r5, 4
174        BNE     4f
175
1763:
177        # ks loop
178        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
179        BHI     1b
180
181        LDR     r7, [sp, 112]           // cn_stride
182        LDR     r14, [sp, 56]           // p = ks
183
184        $if REQUANTIZATION == "RNDNU":
185          # RNDNU quantization
186          VDUP.32 q0, d12[0]              // right_pre_shift
187
188          VQSHL.S32 q8,  q8, q0
189          VQSHL.S32 q9,  q9, q0
190          VQSHL.S32 q10, q10, q0
191          VQSHL.S32 q11, q11, q0
192          VQSHL.S32 q12, q12, q0
193          VQSHL.S32 q13, q13, q0
194          VQSHL.S32 q14, q14, q0
195          VQSHL.S32 q15, q15, q0
196
197          VDUP.32 q2, d13[0]              // right_post_shift
198
199          VQDMULH.S32 q8,  q8, d12[1]     // multiplier
200          VQDMULH.S32 q9,  q9, d12[1]
201          VQDMULH.S32 q10, q10, d12[1]
202          VQDMULH.S32 q11, q11, d12[1]
203          VQDMULH.S32 q12, q12, d12[1]
204          VQDMULH.S32 q13, q13, d12[1]
205          VQDMULH.S32 q14, q14, d12[1]
206          VQDMULH.S32 q15, q15, d12[1]
207
208          VRSHL.S32 q8,  q8, q2
209          VRSHL.S32 q9,  q9, q2
210          VRSHL.S32 q10, q10, q2
211          VRSHL.S32 q11, q11, q2
212          VRSHL.S32 q12, q12, q2
213          VRSHL.S32 q13, q13, q2
214          VRSHL.S32 q14, q14, q2
215          VRSHL.S32 q15, q15, q2
216        $else:
217          # QC8 FP32 quantization
218          VLD1.8  {q0-q1},  [r9]!
219
220          VCVT.F32.S32 q8,  q8
221          VCVT.F32.S32 q9,  q9
222          VCVT.F32.S32 q10, q10
223          VCVT.F32.S32 q11, q11
224          VCVT.F32.S32 q12, q12
225          VCVT.F32.S32 q13, q13
226          VCVT.F32.S32 q14, q14
227          VCVT.F32.S32 q15, q15
228
229          VMUL.F32 q8,  q8, q0            // multiplier
230          VMUL.F32 q9,  q9, q1
231          VMUL.F32 q10, q10, q0
232          VMUL.F32 q11, q11, q1
233          VMUL.F32 q12, q12, q0
234          VMUL.F32 q13, q13, q1
235          VMUL.F32 q14, q14, q0
236          VMUL.F32 q15, q15, q1
237
238          VCVTN.S32.F32 q8,  q8
239          VCVTN.S32.F32 q9,  q9
240          VCVTN.S32.F32 q10, q10
241          VCVTN.S32.F32 q11, q11
242          VCVTN.S32.F32 q12, q12
243          VCVTN.S32.F32 q13, q13
244          VCVTN.S32.F32 q14, q14
245          VCVTN.S32.F32 q15, q15
246        VDUP.16 q0, d13[2]              // output_zero_point
247
248        VQMOVN.S32 d16, q8
249        VQMOVN.S32 d17, q9
250        VQMOVN.S32 d18, q10
251        VQMOVN.S32 d19, q11
252        VQMOVN.S32 d20, q12
253        VQMOVN.S32 d21, q13
254        VQMOVN.S32 d22, q14
255        VQMOVN.S32 d23, q15
256
257        VQADD.S16 q8,  q8, q0
258        VQADD.S16 q9,  q9, q0
259        VQADD.S16 q10, q10, q0
260        VQADD.S16 q11, q11, q0
261
262        VDUP.8  q12, d13[6]             // output_min
263
264        VQMOVN.S16 d0,  q8
265        VQMOVN.S16 d1,  q9
266        VQMOVN.S16 d2, q10
267        VQMOVN.S16 d3, q11
268
269        VDUP.8  q13, d13[7]             // output_max
270
271        VMAX.S8 q0, q0, q12
272        VMAX.S8 q1, q1, q12
273
274        SUBS    r1, r1, 8               // nc -= 8
275
276        VMIN.S8 q0, q0, q13
277        VMIN.S8 q1, q1, q13
278
279        # Store full 4 x 8
280        BLO     5f
281        VST1.8  {d3}, [r6], r7
282        VST1.8  {d2}, [r8], r7
283        VST1.8  {d1}, [r4], r7
284        VST1.8  {d0}, [r11], r7
285        SUB     r2, r2, r14             // a -= ks
286        BHI     0b
287
288        VPOP    {d8-d13}
289        ADD     sp, sp, 12              // skip pad, r2, r3
290        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
291
2924:
293        # Remainder- 4 bytes of A
294        VLD1.32 {d0[0]},  [r3]!         // A0
295        VLD1.32 {q2},  [r9]!            // B0
296        VLD1.32 {d1[0]}, [r12]!         // A1
297        VLD1.32 {q3},  [r9]!            // B1
298        VLD1.32 {d2[0]}, [r10]!         // A2
299        VLD1.32 {d3[0]},  [r0]!         // A3
300
301        VSDOT.S8 q8, q2, d0[0]
302        VSDOT.S8 q9, q3, d0[0]
303        VSDOT.S8 q10, q2, d1[0]
304        VSDOT.S8 q11, q3, d1[0]
305        VSDOT.S8 q12, q2, d2[0]
306        VSDOT.S8 q13, q3, d2[0]
307        VSDOT.S8 q14, q2, d3[0]
308        VSDOT.S8 q15, q3, d3[0]
309        B       3b
310
311        # Store odd width
312        .p2align 3
3135:
314        TST     r1, 4
315        BEQ     6f
316        VST1.32 {d3[0]}, [r6]!
317        VST1.32 {d2[0]}, [r8]!
318        VST1.32 {d1[0]}, [r4]!
319        VST1.32 {d0[0]}, [r11]!
320        VEXT.8  q1, q1, q1, 4
321        VEXT.8  q0, q0, q0, 4
3226:
323        TST     r1, 2
324        BEQ     7f
325        VST1.16 {d3[0]}, [r6]!
326        VST1.16 {d2[0]}, [r8]!
327        VST1.16 {d1[0]}, [r4]!
328        VST1.16 {d0[0]}, [r11]!
329        VEXT.8  q1, q1, q1, 2
330        VEXT.8  q0, q0, q0, 2
331
3327:
333        TST     r1, 1
334        BEQ     8f
335        VST1.8  {d3[0]}, [r6]
336        VST1.8  {d2[0]}, [r8]
337        VST1.8  {d1[0]}, [r4]
338        VST1.8  {d0[0]}, [r11]
339
3408:
341        VPOP    {d8-d13}
342        ADD     sp, sp, 12              // skip pad, r2, r3
343        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
344
345END_FUNCTION xnn_${DATATYPE.lower()}_igemm_minmax_${REQUANTIZATION.lower()}_ukernel_4x8c4__aarch32_neondot_ld64
346# LINT.ThenChange(4x8c4-rndnu-aarch32-neondot-ld64.cc)
347#endif  // __APPLE__
348
349#ifdef __ELF__
350.section ".note.GNU-stack","",%progbits
351#endif
352