• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 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()}_gemm_minmax_${REQUANTIZATION.lower()}_ukernel_4x8c4__aarch32_neondot_ld64(
18//     size_t mr,                            r0
19//     size_t nc,                            r1
20//     size_t kc,                            r2 -> r5
21//     const uint8_t*restrict a,             r3
22//     size_t a_stride,           sp + 80 -> (r7)
23//     const void*restrict w,     sp + 84 -> r9
24//     uint8_t*restrict c,        sp + 88 -> r11
25//     size_t cm_stride,          sp + 92 -> (r6)
26//     size_t cn_stride,          sp + 96 -> r7
27//     ${PARAMS_UNION} params)  sp + 100 -> (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$if REQUANTIZATION == "RNDNU":
47  // params structure is 16 bytes
48  //  struct {
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  //    int8_t output_min;          d13[6]
54  //    int8_t output_max;          d13[7]
55  //  } rndnu_neon;
56$else:
57  // params structure is 4 bytes
58  //  struct {
59  //    int16_t output_zero_point;  d13[2]
60  //    int8_t output_min;          d13[6]
61  //    int8_t output_max;          d13[7]
62  //  } xnn_qs8_minmax_params.neonv8;
63
64// iOS does not support 32 bit ARM with Neon DotProduct.
65#ifndef __APPLE__
66BEGIN_FUNCTION xnn_${DATATYPE.lower()}_gemm_minmax_${REQUANTIZATION.lower()}_ukernel_4x8c4__aarch32_neondot_ld64
67        # Push 80 bytes
68        PUSH    {r4, r5, r6, r7, r8, r9, r10, r11}  // 32
69        VPUSH   {d8-d13}                            // +48 = 80
70
71        LDR     r7, [sp, 80]            // a_stride
72        ADD     r2, r2, 3               // kc = (kc + 3) & ~3
73        LDR     r11, [sp, 88]           // c
74        LDR     r6, [sp, 92]            // cm_stride
75        LDR     r9, [sp, 84]            // w
76        BIC     r2, r2, 3
77        LDR     r5, [sp, 100]           // params
78
79        # Clamp A and C pointers
80        CMP     r0, 2                   // if mr >= 2
81        ADD     r12, r3, r7             //   a1 = a0 + a_stride
82        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
83        MOVLO   r12, r3                 // a1
84        MOVLO   r4, r11                 // c1
85                                        // if mr > 2
86        ADD     r10, r12, r7            //   a2 = a1 + a_stride
87        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
88        MOVLS   r10, r12                // a2
89        MOVLS   r8, r4                  // c2
90
91        CMP     r0, 4                   // if mr >=4
92        ADD     r0, r10, r7             //   a3 = a2 + a_stride
93        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
94        MOVLO   r0, r10                 // a3
95        MOVLO   r6, r8                  // c3
96
97        # Load params values
98        $if REQUANTIZATION == "RNDNU":
99          VLDM    r5, {d12-d13}           // RNDNU params
100        $else:
101          VLD1.32 {d13[]}, [r5]           // QC8 params
102        LDR     r7, [sp, 96]            // cn_stride
103
104        .p2align 3
1050:
106        # Load initial bias from w into accumulators
107        VLDM    r9!, {d16-d19}          // Bias
108        SUBS    r5, r2, 8               // k = kc - 8
109        VMOV    q10, q8
110        VMOV    q11, q9
111        VMOV    q12, q8
112        VMOV    q13, q9
113        VMOV    q14, q8
114        VMOV    q15, q9
115        BLO     3f                      // less than 8 channels?
116
117        # Main loop - 8 bytes of A.
118        # 16 SDOT, 4 LD64 A, 4 LD128 B
119        .p2align 3
1201:
121        VLD1.8  {d0},  [r3]!            // A0
122        VLD1.8  {q2},  [r9]!            // B0
123        VLD1.8  {d1}, [r12]!            // A1
124        VLD1.8  {q3},  [r9]!            // B1
125        VLD1.8  {d2}, [r10]!            // A2
126        VLD1.8  {q4},  [r9]!            // B2
127        VLD1.8  {d3},  [r0]!            // A3
128        VLD1.8  {q5},  [r9]!            // B3
129        SUBS    r5, r5, 8
130
131        VSDOT.S8 q8, q2, d0[0]
132        VSDOT.S8 q9, q3, d0[0]
133        VSDOT.S8 q10, q2, d1[0]
134        VSDOT.S8 q11, q3, d1[0]
135        VSDOT.S8 q12, q2, d2[0]
136        VSDOT.S8 q13, q3, d2[0]
137        VSDOT.S8 q14, q2, d3[0]
138        VSDOT.S8 q15, q3, d3[0]
139
140        VSDOT.S8 q8, q4, d0[1]
141        VSDOT.S8 q9, q5, d0[1]
142        VSDOT.S8 q10, q4, d1[1]
143        VSDOT.S8 q11, q5, d1[1]
144        VSDOT.S8 q12, q4, d2[1]
145        VSDOT.S8 q13, q5, d2[1]
146        VSDOT.S8 q14, q4, d3[1]
147        VSDOT.S8 q15, q5, d3[1]
148        BHS     1b
149
150        # Is there a remainder?- 4 bytes of A
151        ADDS    r5, r5, 8
152        BNE     3f
153
1542:
155        $if REQUANTIZATION == "RNDNU":
156          # RNDNU quantization
157          VDUP.32 q0, d12[0]              // right_pre_shift
158
159          VQSHL.S32 q8,  q8, q0
160          VQSHL.S32 q9,  q9, q0
161          VQSHL.S32 q10, q10, q0
162          VQSHL.S32 q11, q11, q0
163          VQSHL.S32 q12, q12, q0
164          VQSHL.S32 q13, q13, q0
165          VQSHL.S32 q14, q14, q0
166          VQSHL.S32 q15, q15, q0
167
168          VDUP.32 q2, d13[0]              // right_post_shift
169
170          VQDMULH.S32 q8,  q8, d12[1]     // multiplier
171          VQDMULH.S32 q9,  q9, d12[1]
172          VQDMULH.S32 q10, q10, d12[1]
173          VQDMULH.S32 q11, q11, d12[1]
174          VQDMULH.S32 q12, q12, d12[1]
175          VQDMULH.S32 q13, q13, d12[1]
176          VQDMULH.S32 q14, q14, d12[1]
177          VQDMULH.S32 q15, q15, d12[1]
178
179          VRSHL.S32 q8,  q8, q2
180          VRSHL.S32 q9,  q9, q2
181          VRSHL.S32 q10, q10, q2
182          VRSHL.S32 q11, q11, q2
183          VRSHL.S32 q12, q12, q2
184          VRSHL.S32 q13, q13, q2
185          VRSHL.S32 q14, q14, q2
186          VRSHL.S32 q15, q15, q2
187        $else:
188          # QC8 FP32 quantization
189          VLD1.8  {q0-q1},  [r9]!
190
191          VCVT.F32.S32 q8,  q8
192          VCVT.F32.S32 q9,  q9
193          VCVT.F32.S32 q10, q10
194          VCVT.F32.S32 q11, q11
195          VCVT.F32.S32 q12, q12
196          VCVT.F32.S32 q13, q13
197          VCVT.F32.S32 q14, q14
198          VCVT.F32.S32 q15, q15
199
200          VMUL.F32 q8,  q8, q0            // multiplier
201          VMUL.F32 q9,  q9, q1
202          VMUL.F32 q10, q10, q0
203          VMUL.F32 q11, q11, q1
204          VMUL.F32 q12, q12, q0
205          VMUL.F32 q13, q13, q1
206          VMUL.F32 q14, q14, q0
207          VMUL.F32 q15, q15, q1
208
209          VCVTN.S32.F32 q8,  q8
210          VCVTN.S32.F32 q9,  q9
211          VCVTN.S32.F32 q10, q10
212          VCVTN.S32.F32 q11, q11
213          VCVTN.S32.F32 q12, q12
214          VCVTN.S32.F32 q13, q13
215          VCVTN.S32.F32 q14, q14
216          VCVTN.S32.F32 q15, q15
217
218        VDUP.16 q0, d13[2]              // output_zero_point
219
220        VQMOVN.S32 d16, q8
221        VQMOVN.S32 d17, q9
222        VQMOVN.S32 d18, q10
223        VQMOVN.S32 d19, q11
224        VQMOVN.S32 d20, q12
225        VQMOVN.S32 d21, q13
226        VQMOVN.S32 d22, q14
227        VQMOVN.S32 d23, q15
228
229        VQADD.S16 q8,  q8, q0
230        VQADD.S16 q9,  q9, q0
231        VQADD.S16 q10, q10, q0
232        VQADD.S16 q11, q11, q0
233
234        VDUP.8  q12, d13[6]             // output_min
235
236        VQMOVN.S16 d0,  q8
237        VQMOVN.S16 d1,  q9
238        VQMOVN.S16 d2, q10
239        VQMOVN.S16 d3, q11
240
241        VDUP.8  q13, d13[7]             // output_max
242
243        VMAX.S8 q0, q0, q12
244        VMAX.S8 q1, q1, q12
245
246        SUBS    r1, r1, 8
247
248        VMIN.S8 q0, q0, q13
249        VMIN.S8 q1, q1, q13
250
251        # Store full 4 x 8
252        BLO     4f
253        VST1.8  {d0}, [r11], r7
254        SUB     r3, r3, r2
255        VST1.8  {d1}, [r4], r7
256        SUB     r12, r12, r2
257        VST1.8  {d2}, [r8], r7
258        SUB     r10, r10, r2
259        VST1.8  {d3}, [r6], r7
260        SUB     r0, r0, r2
261        BHI     0b
262
263        VPOP    {d8-d13}
264        POP     {r4, r5, r6, r7, r8, r9, r10, r11}
265        BX      lr
266
267        # Remainder- 4 bytes of A
268        .p2align 3
2693:
270        VLD1.32 {d0[0]},  [r3]!         // A0
271        VLD1.32 {q2},  [r9]!            // B0
272        VLD1.32 {d1[0]}, [r12]!         // A1
273        VLD1.32 {q3},  [r9]!            // B1
274        VLD1.32 {d2[0]}, [r10]!         // A2
275        VLD1.32 {d3[0]},  [r0]!         // A3
276
277        VSDOT.S8 q8, q2, d0[0]
278        VSDOT.S8 q9, q3, d0[0]
279        VSDOT.S8 q10, q2, d1[0]
280        VSDOT.S8 q11, q3, d1[0]
281        VSDOT.S8 q12, q2, d2[0]
282        VSDOT.S8 q13, q3, d2[0]
283        VSDOT.S8 q14, q2, d3[0]
284        VSDOT.S8 q15, q3, d3[0]
285        B       2b
286
287        # Store odd width
288        .p2align 3
2894:
290        TST     r1, 4
291        BEQ     5f
292        VST1.32 {d0[0]}, [r11]!
293        VST1.32 {d1[0]}, [r4]!
294        VST1.32 {d2[0]}, [r8]!
295        VST1.32 {d3[0]}, [r6]!
296        VEXT.8  q0, q0, q0, 4
297        VEXT.8  q1, q1, q1, 4
2985:
299        TST     r1, 2
300        BEQ     6f
301        VST1.16 {d0[0]}, [r11]!
302        VST1.16 {d1[0]}, [r4]!
303        VST1.16 {d2[0]}, [r8]!
304        VST1.16 {d3[0]}, [r6]!
305        VEXT.8  q0, q0, q0, 2
306        VEXT.8  q1, q1, q1, 2
307
3086:
309        TST     r1, 1
310        BEQ     7f
311        VST1.8  {d0[0]}, [r11]
312        VST1.8  {d1[0]}, [r4]
313        VST1.8  {d2[0]}, [r8]
314        VST1.8  {d3[0]}, [r6]
315
3167:
317        VPOP    {d8-d13}
318        POP     {r4, r5, r6, r7, r8, r9, r10, r11}
319        BX      lr
320
321END_FUNCTION xnn_${DATATYPE.lower()}_gemm_minmax_${REQUANTIZATION.lower()}_ukernel_4x8c4__aarch32_neondot_ld64
322# LINT.ThenChange(4x8c4-rndnu-aarch32-neondot-ld64.cc)
323#endif  // __APPLE__
324
325#ifdef __ELF__
326.section ".note.GNU-stack","",%progbits
327#endif
328
329