• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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#include <xnnpack/assembly.h>
7
8.syntax unified
9
10// void xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a55(
11//     size_t mr,                            r0
12//     size_t nc,                            r1
13//     size_t kc,                            r2 -> r5
14//     const uint8_t*restrict a,             r3
15//     size_t a_stride,          sp + 96 -> (r7)
16//     const void*restrict w,    sp + 100 -> r9
17//     uint8_t*restrict c,       sp + 104 -> r11
18//     size_t cm_stride,         sp + 108 -> (r6)
19//     size_t cn_stride,         sp + 112 -> (r0)
20//     minmax_params*params,     sp + 116 -> (r5)
21
22// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
23
24// Register usage
25
26// r14 (lr) unused
27
28// A0   r3  d0
29// A1  r12  d1
30// A2  r10  d2
31// A3   r7  d3
32
33// B    r9  d8,  d9, d10, d11
34// B       d12, d13, d14, d15
35
36// C0  r11 d16-d17  q8  d18-d19  q9
37// C1   r4 d20-d21 q10  d22-d23 q11
38// C2   r8 d24-d25 q12  d26-d27 q13
39// C3   r6 d28-d29 q14  d30-d31 q15
40
41// Clamp (r5) d4 d5 d6 d7
42
43BEGIN_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a55
44        .arm
45#ifndef __APPLE__
46        .arch   armv7-a
47        .fpu    neon
48#endif
49        # Push 96 bytes
50        VPUSH   {d8-d15}                            // 64
51        PUSH    {r4, r5, r6, r7, r8, r9, r10, r11}  // +32 = 96
52
53        LDR     r7, [sp,  96]           // a_stride
54        LDR     r11, [sp, 104]          // c
55        LDR     r6, [sp, 108]           // cm_stride
56        LDR     r9, [sp, 100]           // w
57
58        # Clamp A and C pointers
59        CMP     r0, 2                   // if mr >= 2
60        ADD     r12, r3, r7             //   a1 = a0 + a_stride
61        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
62        MOVLO   r12, r3                 // a1
63        MOVLO   r4, r11                 // c1
64                                        // if mr > 2
65        ADD     r10, r12, r7            //   a2 = a1 + a_stride
66        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
67        MOVLS   r10, r12                // a2
68        MOVLS   r8, r4                  // c2
69
70        CMP     r0, 4                   // if mr >=4
71        ADD     r7, r10, r7             //   a3 = a2 + a_stride
72        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
73        MOVLO   r7, r10                 // a3
74        MOVLO   r6, r8                  // c3
75
76        .p2align 3
770:
78        # Load initial bias from w into accumulators
79        VLDM    r9!, {d16-d19}          // Bias
80
81        SUBS    r5, r2, 16              // kc - 16
82        PLD     [r3,  0]                // Prefetch A
83        PLD     [r3, 64]
84        VMOV    q10, q8
85        PLD     [r12,  0]
86        PLD     [r12, 64]
87        VMOV    q11, q9
88        PLD     [r10,  0]
89        PLD     [r10, 64]
90        VMOV    q12, q8
91        PLD     [r7,  0]
92        PLD     [r7, 64]
93        VMOV    q13, q9
94        PLD     [r9,   0]               // Prefetch B
95        PLD     [r9,  64]
96        VMOV    q14, q8
97        PLD     [r9, 128]
98        PLD     [r9, 192]
99        VMOV    q15, q9
100        PLD     [r9, 256]
101        PLD     [r9, 320]
102        BLO     4f                      // less than 4 channels?
103
104        # Prologue
105        VLD1.32 {d0},  [r3]!            // A0
106        VLD1.32 {d1}, [r12]!            // A1
107        VLD1.32 {d2}, [r10]!            // A2
108        VLD1.32 {d3},  [r7]!            // A3
109        SUBS    r5, r5, 16
110        VLDM    r9, {d8-d11}            // B0
111        VLDR    d15, [r9, 56]           // B1CK 0
112        VLDR    d13, [r9, 40]           // B1
113        BLO     2f                      // less than 4 channels?  skip main loop
114
115        # Main loop - 4 floats of A (16 bytes)
116        # 32 FMA + 8 LD64 A + 8 LDR B
117        .p2align 3
1181:
119        # First group of 16 FMA, Second group loads
120        # BLOCK 0
121        VMLA.F32 q8, q4, d0[0]
122        VLD1.32 {d4}, [r3]!             // A0
123        VMLA.F32 q10, q4, d1[0]
124        VLD1.32 {d5}, [r12]!            // A1
125        VMLA.F32 q12, q4, d2[0]
126
127        # BLOCK 1
128        VMLA.F32 q14, q4, d3[0]
129        VLDR    d12, [r9, 32]           // B1
130        VMLA.F32 q9, q5, d0[0]
131        VLDR    d9, [r9, 72]            // B0
132        VMLA.F32 q11, q5, d1[0]
133
134        # BLOCK 2
135        VMLA.F32 q13, q5, d2[0]
136        VLD1.32 {d6}, [r10]!            // A2
137        VMLA.F32 q15, q5, d3[0]
138        VLD1.32 {d7}, [r7]!             // A3
139        VMLA.F32 q8, q6, d0[1]
140
141        # BLOCK 3
142        VMLA.F32 q10, q6, d1[1]
143        VLDR    d14, [r9, 48]           // B1
144        VMLA.F32 q12, q6, d2[1]
145        VLDR    d11, [r9, 88]           // B0
146        VMLA.F32 q14, q6, d3[1]
147
148        # BLOCK 4
149        VMLA.F32 q9, q7, d0[1]
150        VLDR    d8, [r9, 64]            // B0
151        VMLA.F32 q11, q7, d1[1]
152        VLDR    d13, [r9, 104]          // B1
153        VMLA.F32 q13, q7, d2[1]
154        VLDR    d10, [r9, 80]           // B0
155
156        # BLOCK 5
157        VMLA.F32 q15, q7, d3[1]
158        VLDR    d15, [r9, 120]          // B1
159
160        # Second group of 16 FMA, First group of loads
161        # BLOCK 0
162        VMLA.F32 q8, q4, d4[0]
163        VLD1.32 {d0}, [r3]!             // A0
164        VMLA.F32 q10, q4, d5[0]
165        VLD1.32 {d1}, [r12]!            // A1
166        VMLA.F32 q12, q4, d6[0]
167
168        # BLOCK 1
169        VMLA.F32 q14, q4, d7[0]
170        VLDR    d12, [r9, 96]           // B1
171        VMLA.F32 q9, q5, d4[0]
172        VLDR    d9, [r9, 136]           // B0
173        VMLA.F32 q11, q5, d5[0]
174
175        # BLOCK 2
176        VMLA.F32 q13, q5, d6[0]
177        VLD1.32 {d2}, [r10]!            // A2
178        VMLA.F32 q15, q5, d7[0]
179        VLD1.32 {d3}, [r7]!             // A3
180        VMLA.F32 q8, q6, d4[1]
181
182        # BLOCK 3
183        VMLA.F32 q10, q6, d5[1]
184        VLDR    d14, [r9, 112]          // B1
185        VMLA.F32 q12, q6, d6[1]
186        VLDR    d11, [r9, 152]          // B0
187        VMLA.F32 q14, q6, d7[1]
188        SUBS    r5, r5, 16
189
190        # BLOCK 4
191        VMLA.F32 q9, q7, d4[1]
192        VLDR    d8, [r9, 128]           // B0
193        VMLA.F32 q11, q7, d5[1]
194        VLDR    d13, [r9, 168]          // B1
195        VMLA.F32 q13, q7, d6[1]
196        VLDR    d10, [r9, 144]          // B0
197
198        # BLOCK 5
199        VMLA.F32 q15, q7, d7[1]
200        VLDR    d15, [r9, 184]          // B1
201        ADD     r9, r9, 128             // B++
202        BHS     1b
203
204
205        # Epilogue - 4 floats of A (16 bytes)
2062:
207        # First group of 16 FMA, Second group loads
208        # BLOCK 0
209        VMLA.F32 q8, q4, d0[0]
210        VLD1.32 {d4}, [r3]!             // A0
211        VMLA.F32 q10, q4, d1[0]
212        VLD1.32 {d5}, [r12]!            // A1
213        VMLA.F32 q12, q4, d2[0]
214
215        # BLOCK 1
216        VMLA.F32 q14, q4, d3[0]
217        VLDR    d12, [r9, 32]           // B1
218        VMLA.F32 q9, q5, d0[0]
219        VLDR    d9, [r9, 72]            // B0
220        VMLA.F32 q11, q5, d1[0]
221
222        # BLOCK 2
223        VMLA.F32 q13, q5, d2[0]
224        VLD1.32 {d6}, [r10]!            // A2
225        VMLA.F32 q15, q5, d3[0]
226        VLD1.32 {d7}, [r7]!             // A3
227        VMLA.F32 q8, q6, d0[1]
228
229        # BLOCK 3
230        VMLA.F32 q10, q6, d1[1]
231        VLDR    d14, [r9, 48]           // B1
232        VMLA.F32 q12, q6, d2[1]
233        VLDR    d11, [r9, 88]           // B0
234        VMLA.F32 q14, q6, d3[1]
235
236        # BLOCK 4
237        VMLA.F32 q9, q7, d0[1]
238        VLDR    d8, [r9, 64]            // B0
239        VMLA.F32 q11, q7, d1[1]
240        VLDR    d13, [r9, 104]          // B1
241        VMLA.F32 q13, q7, d2[1]
242        VLDR    d10, [r9, 80]           // B0
243
244        # BLOCK 5
245        VMLA.F32 q15, q7, d3[1]
246        VLDR    d15, [r9, 120]          // B1
247
248        # Second group of 16 FMA, First group of loads
249        # BLOCK 0
250        VMLA.F32 q8, q4, d4[0]
251        VLDR    d12, [r9, 96]           // B1
252        VMLA.F32 q10, q4, d5[0]
253        VMLA.F32 q12, q4, d6[0]
254
255        # BLOCK 1
256        VMLA.F32 q14, q4, d7[0]
257        VLDR    d14, [r9, 112]          // B1
258        VMLA.F32 q9, q5, d4[0]
259        VMLA.F32 q11, q5, d5[0]
260
261        # BLOCK 2
262        VMLA.F32 q13, q5, d6[0]
263        VMLA.F32 q15, q5, d7[0]
264        VMLA.F32 q8, q6, d4[1]
265        ADD     r9, r9, 128             // B++
266
267        # BLOCK 3
268        VMLA.F32 q10, q6, d5[1]
269        VMLA.F32 q12, q6, d6[1]
270        VMLA.F32 q14, q6, d7[1]
271        TST     r5, 15
272
273        # BLOCK 4
274        VMLA.F32 q9, q7, d4[1]
275        VMLA.F32 q11, q7, d5[1]
276        VMLA.F32 q13, q7, d6[1]
277
278        # BLOCK 5
279        VMLA.F32 q15, q7, d7[1]
280
281        # Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
282        BNE     4f
283
284        .p2align 3
2853:
286        # Load params pointer
287        LDR     r0, [sp, 112]           // cn_stride
288        LDR     r5, [sp, 116]           // params
289        SUBS    r1, r1, 8
290
291        # Load min/max values
292        VLD1.32 {d4[],d5[]}, [r5]!
293        VLD1.32 {d6[],d7[]}, [r5]
294
295        # Clamp
296        VMAX.F32 q8,  q8, q2
297        VMAX.F32 q9,  q9, q2
298        VMAX.F32 q10, q10, q2
299        VMAX.F32 q11, q11, q2
300        VMAX.F32 q12, q12, q2
301        VMAX.F32 q13, q13, q2
302        VMAX.F32 q14, q14, q2
303        VMAX.F32 q15, q15, q2
304        VMIN.F32 q8,  q8, q3
305        VMIN.F32 q9,  q9, q3
306        VMIN.F32 q10, q10, q3
307        VMIN.F32 q11, q11, q3
308        VMIN.F32 q12, q12, q3
309        VMIN.F32 q13, q13, q3
310        VMIN.F32 q14, q14, q3
311        VMIN.F32 q15, q15, q3
312
313        # Store full 4 x 8
314        BLO     6f
315        VST1.32 {d16-d19}, [r11], r0
316        SUB     r7, r7, r2
317        VST1.32 {d20-d23}, [r4], r0
318        SUB     r10, r10, r2
319        VST1.32 {d24-d27}, [r8], r0
320        SUB     r12, r12, r2
321        VST1.32 {d28-d31}, [r6], r0
322        SUB     r3, r3, r2
323        BHI     0b
324
325        POP     {r4, r5, r6, r7, r8, r9, r10, r11}
326        VPOP    {d8-d15}
327        BX      lr
328
329        .p2align 3
3304:
331        # Is there a remainder?- 2 floats of A (8 bytes)
332        TST     r5, 8
333        BEQ     5f
334
335        # Remainder - 2 floats of A (8 bytes)
336        VLD1.32 {d0}, [r3]!             // A0
337        VLDM    r9!, {d8-d11}           // B0
338        VLD1.32 {d1}, [r12]!            // A1
339        VLD1.32 {d2}, [r10]!            // A2
340        VLD1.32 {d3}, [ r7]!            // A3
341
342        VMLA.F32 q8, q4, d0[0]
343        VMLA.F32 q9, q5, d0[0]
344        VMLA.F32 q10, q4, d1[0]
345        VMLA.F32 q11, q5, d1[0]
346        VLDM    r9!, {d12-d15}          // B1
347        VMLA.F32 q12, q4, d2[0]
348        VMLA.F32 q13, q5, d2[0]
349        VMLA.F32 q14, q4, d3[0]
350        VMLA.F32 q15, q5, d3[0]
351        VMLA.F32 q8, q6, d0[1]
352        VMLA.F32 q9, q7, d0[1]
353        VMLA.F32 q10, q6, d1[1]
354        VMLA.F32 q11, q7, d1[1]
355        VMLA.F32 q12, q6, d2[1]
356        VMLA.F32 q13, q7, d2[1]
357        VMLA.F32 q14, q6, d3[1]
358        VMLA.F32 q15, q7, d3[1]
359
360        # Is there a remainder?- 1 floats of A (4 bytes)
361        TST     r5, 4
362        BEQ     3b
363
3645:
365        # Remainder- 1 floats of A (4 bytes)
366        VLDM    r3!,  {s0}              // A0
367        VLDM    r9!, {d8-d11}           // B0
368        VLDM    r12!, {s2}              // A1
369        VLDM    r10!, {s4}              // A2
370        VLDM    r7!, {s6}               // A3
371        VMLA.F32 q8, q4, d0[0]
372        VMLA.F32 q9, q5, d0[0]
373        VMLA.F32 q10, q4, d1[0]
374        VMLA.F32 q11, q5, d1[0]
375        VMLA.F32 q12, q4, d2[0]
376        VMLA.F32 q13, q5, d2[0]
377        VMLA.F32 q14, q4, d3[0]
378        VMLA.F32 q15, q5, d3[0]
379        B       3b
380
381        # Store odd width
3826:
383        TST     r1, 4
384        BEQ     7f
385        VST1.32 {d16-d17}, [r11]!
386        VST1.32 {d20-d21},  [r4]!
387        VMOV    q8,  q9
388        VMOV    q10, q11
389        VST1.32 {d24-d25},  [r8]!
390        VST1.32 {d28-d29},  [r6]!
391        VMOV    q12, q13
392        VMOV    q14, q15
393
3947:
395        TST     r1, 2
396        BEQ     8f
397        VST1.32 {d16}, [r11]!
398        VST1.32 {d20},  [r4]!
399        VMOV    d16, d17
400        VMOV    d20, d21
401        VST1.32 {d24},  [r8]!
402        VST1.32 {d28},  [r6]!
403        VMOV    d24, d25
404        VMOV    d28, d29
405
4068:
407        TST     r1, 1
408        BEQ     9f
409        VST1.32 {d16[0]}, [r11]
410        VST1.32 {d20[0]},  [r4]
411        VST1.32 {d24[0]},  [r8]
412        VST1.32 {d28[0]},  [r6]
413
4149:
415        POP     {r4, r5, r6, r7, r8, r9, r10, r11}
416        VPOP    {d8-d15}
417        BX      lr
418
419END_FUNCTION xnn_f32_gemm_minmax_ukernel_4x8__aarch32_neon_cortex_a55
420
421#ifdef __ELF__
422.section ".note.GNU-stack","",%progbits
423#endif
424