• 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_ukernel_4x8__aarch32_neon_cortex_a53(
11//     size_t mr,                            r0
12//     size_t nc,                            r1
13//     size_t kc,                            r2 -> r5 -> sp + 0
14//     const uint8_t*restrict a,             r3
15//     size_t a_stride,          sp + 100 -> (r7)
16//     const void*restrict w,    sp + 104 -> r9
17//     uint8_t*restrict c,       sp + 108 -> r11
18//     size_t cm_stride,         sp + 112 -> (r6)
19//     size_t cn_stride,         sp + 116 -> (r0)
20//     const union xnn_f32_output_params params[restrict static 1])  sp + 120 -> (r5)
21
22
23// inner loop registers
24// r0, r2   scratch temporaries for loads
25// r14 (lr) unused
26
27// A0   r3  d0
28// A1  r12  d1
29// A2  r10  d2
30// A3   r7  d3
31
32// B    r9  d8,  d9, d10, d11
33// B       d12, d13, d14, d15
34
35// C0  r11 d16-d17  q8  d18-d19  q9
36// C1   r4 d20-d21 q10  d22-d23 q11
37// C2   r8 d24-d25 q12  d26-d27 q13
38// C3   r6 d28-d29 q14  d30-d31 q15
39
40// Clamp (r5) d4 d5 d6 d7
41
42BEGIN_FUNCTION xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a53
43        .arm
44#ifndef __APPLE__
45        .arch armv7-a
46//        .arch_extension mp
47        .fpu neon
48#endif
49        // Push 100 bytes
50        // r2 will be reloaded in outer loop
51        VPUSH  {d8-d15}                                // 64
52        PUSH   {r2, r4, r5, r6, r7, r8, r9, r10, r11}  // +36 = 100
53
54        LDR     r7, [sp, 100]        // a_stride
55        LDR     r9, [sp, 104]        // w
56        LDR    r11, [sp, 108]        // c
57        LDR     r6, [sp, 112]        // cm_stride
58
59        // Clamp A and C pointers
60        CMP    r0, 2                 // if mr >= 2
61        ADD    r12, r3, r7           //   a1 = a0 + a_stride
62        ADD    r4, r11, r6           //   c1 = c0 + cm_stride
63        MOVLO  r12, r3               // a1
64        MOVLO  r4, r11               // c1
65                                     // if mr > 2
66        ADD    r10, r12, r7          //   a2 = a1 + a_stride
67        ADD    r8, r4, r6            //   c2 = c1 + cm_stride
68        MOVLS  r10, r12              // a2
69        MOVLS  r8, r4                // c2
70
71        CMP    r0, 4                 // if mr >=4
72        ADD    r7, r10, r7           //   a3 = a2 + a_stride
73        ADD    r6, r8, r6            //   c3 = c2 + cm_stride
74        MOVLO  r7, r10               // a3
75        MOVLO  r6, r8                // c3
76
77        .p2align 3
781:
79        # Load initial bias from w into accumulators
80        VLDM        r9!, {d16-d19}   // Bias
81
82        SUBS        r5, r2, 16       // kc - 16
83        PLD         [r3,  0]    // Prefetch A
84        PLD         [r3, 64]
85        VMOV        q10, q8
86        PLD        [r12,  0]
87        PLD        [r12, 64]
88        VMOV        q11, q9
89        PLD        [r10,  0]
90        PLD        [r10, 64]
91        VMOV        q12, q8
92        PLD         [r7,  0]
93        PLD         [r7, 64]
94        VMOV        q13, q9
95        PLD         [r9,   0]  // Prefetch B
96        PLD         [r9,  64]
97        VMOV        q14, q8
98        PLD         [r9, 128]
99        PLD         [r9, 192]
100        VMOV        q15, q9
101        PLD         [r9, 256]
102        PLD         [r9, 320]
103
104        //  118877 us with PLDW vs 119550 us without in e2e
105        // PLDW [r11]        // Prefetch C0
106        // PLDW  [r4]        // Prefetch C1
107        // PLDW  [r8]        // Prefetch C2
108        // PLDW  [r6]        // Prefetch C3
109
110        BLO         4f               // less than 4 channels?
111
112        // Prologue
113        VLD1.32   {d0},  [r3]!       // A0
114        VLD1.32   {d1}, [r12]!       // A1
115        VLD1.32   {d2}, [r10]!       // A2
116        VLD1.32   {d3},  [r7]!       // A3
117        SUBS        r5, r5, 16
118        VLDM        r9, {d8-d11}     // B0
119        LDR         r0, [r9, 56]     // B1 low   VMOV is in BLOCK 0
120        LDR         r2, [r9, 60]     // B1 high
121        VLDR       d13, [r9, 40]     // B1
122
123        BLO         3f               // less than 4 channels?  skip main loop
124
125        # Main loop - 4 floats of A (16 bytes)
126        # 32 FMA + 8 LD64 A + 8 LDR B
127        .p2align 3
1282:
129        # First group of 16 FMA, Second group loads
130        // BLOCK 0
131        VLD1.32    {d4}, [r3]!       // A0
132        VMOV        d15, r0, r2      // b1 VMOV b from second group
133        VMLA.F32     q8, q4, d0[0]
134        LDR          r0, [r12]       // A1 low
135        VMLA.F32    q10, q4, d1[0]
136        LDR          r2, [r12, 4]    // A1 high
137        VMLA.F32    q12, q4, d2[0]
138        PLD         [r3, 128]        // Prefetch A0
139
140        // BLOCK 1
141        VLDR        d12, [r9, 32]    // B1
142        VMOV         d5, r0, r2      // a1 VMOV
143        VMLA.F32    q14, q4, d3[0]
144        LDR          r0, [r9, 72]    // B0 low
145        VMLA.F32     q9, q5, d0[0]
146        LDR          r2, [r9, 76]    // B0 high
147        VMLA.F32    q11, q5, d1[0]
148        PLD         [r12, 128]       // Prefetch A1
149
150        // BLOCK 2
151        VLD1.32    {d6}, [r10]!      // A2
152        VMOV         d9, r0, r2      // b0 VMOV
153        VMLA.F32    q13, q5, d2[0]
154        LDR          r0, [r7]        // A3 low
155        VMLA.F32    q15, q5, d3[0]
156        LDR          r2, [r7, 4]     // A3 high
157        VMLA.F32     q8, q6, d0[1]
158        PLD         [r10, 128]       // Prefetch A2
159
160        // BLOCK 3
161        VLDR        d14, [r9, 48]    // B1
162        VMOV         d7, r0, r2      // a3 VMOV
163        VMLA.F32    q10, q6, d1[1]
164        LDR          r0, [r9, 88]    // B0 low
165        VMLA.F32    q12, q6, d2[1]
166        LDR          r2, [r9, 92]    // B0 high
167        VMLA.F32    q14, q6, d3[1]
168        PLD         [r7, 128]        // Prefetch A3
169
170        // BLOCK 4
171        VLDR         d8, [r9, 64]    // B0
172        VMOV        d11, r0, r2      // B0 VMOV
173        VMLA.F32     q9, q7, d0[1]
174        LDR          r0, [r9, 104]   // B1 low   VMOV is in BLOCK 0
175        VMLA.F32    q11, q7, d1[1]
176        LDR          r2, [r9, 108]   // B1 high
177        VMLA.F32    q13, q7, d2[1]
178        PLD         [r9, 384]        // Prefetch B
179
180        // BLOCK 5
181        VLDR        d10, [r9, 80]    // B0
182        VMOV        d13, r0, r2      // b1 VMOV b from second group
183        VMLA.F32    q15, q7, d3[1]
184        LDR          r0, [r9, 120]   // B1 low   VMOV is in BLOCK 0
185        NOP
186        LDR          r2, [r9, 124]   // B1 high
187        NOP
188        PLD         [r9, 448]        // Prefetch B
189
190        # Second group of 16 FMA, First group of loads
191        // BLOCK 0
192        VLD1.32    {d0}, [r3]!       // A0
193        VMOV        d15, r0, r2      // b1 VMOV b from second group
194        VMLA.F32     q8, q4, d4[0]
195        LDR          r0, [r12, 8]    // A1 low
196        VMLA.F32    q10, q4, d5[0]
197        LDR          r2, [r12, 12]   // A1 high
198        VMLA.F32    q12, q4, d6[0]
199
200        // BLOCK 1
201        VLDR        d12, [r9, 96]    // B1
202        VMOV         d1, r0, r2      // a1 VMOV
203        VMLA.F32    q14, q4, d7[0]
204        LDR          r0, [r9, 136]   // B0 low
205        VMLA.F32     q9, q5, d4[0]
206        LDR          r2, [r9, 140]   // B0 high
207        VMLA.F32    q11, q5, d5[0]
208
209        // BLOCK 2
210        VLD1.32    {d2}, [r10]!      // A2
211        VMOV         d9, r0, r2      // b0 VMOV
212        VMLA.F32    q13, q5, d6[0]
213        LDR          r0, [r7, 8]     // A3 low
214        VMLA.F32    q15, q5, d7[0]
215        LDR          r2, [r7, 12]    // A3 high
216        VMLA.F32     q8, q6, d4[1]
217
218        // BLOCK 3
219        VLDR        d14, [r9, 112]   // B1
220        VMOV         d3, r0, r2      // a3 VMOV
221        VMLA.F32    q10, q6, d5[1]
222        LDR          r0, [r9, 152]   // B0 low
223        VMLA.F32    q12, q6, d6[1]
224        LDR          r2, [r9, 156]   // B0 high
225        VMLA.F32    q14, q6, d7[1]
226        ADD         r12, r12, 16     // A1++
227
228        // BLOCK 4
229        VLDR         d8, [r9, 128]   // B0
230        VMOV        d11, r0, r2      // B0 VMOV
231        VMLA.F32     q9, q7, d4[1]
232        LDR          r0, [r9, 168]    // B1 low
233        VMLA.F32    q11, q7, d5[1]
234        LDR          r2, [r9, 172]   // B1 high
235        VMLA.F32    q13, q7, d6[1]
236        ADD          r7, r7, 16      // A3++
237
238        // BLOCK 5
239        VLDR        d10, [r9, 144]   // B0
240        VMOV        d13, r0, r2      // b1 VMOV b
241        VMLA.F32    q15, q7, d7[1]
242        LDR          r0, [r9, 184]   // B1 low   VMOV is in BLOCK 0
243        SUBS        r5, r5, 16
244        LDR          r2, [r9, 188]   // B1 high
245        ADD         r9, r9, 128      // B++
246        BHS         2b
247
248        # Epilogue - 4 floats of A (16 bytes)
2493:
250        # First group of 16 FMA, Second group loads
251        // BLOCK 0
252        VLD1.32    {d4}, [r3]!       // A0
253        VMOV        d15, r0, r2      // b1 VMOV b from second group
254        VMLA.F32     q8, q4, d0[0]
255        LDR          r0, [r12]       // A1 low
256        VMLA.F32    q10, q4, d1[0]
257        LDR          r2, [r12, 4]    // A1 high
258        VMLA.F32    q12, q4, d2[0]
259
260        // BLOCK 1
261        VLDR        d12, [r9, 32]    // B1
262        VMOV         d5, r0, r2      // a1 VMOV
263        VMLA.F32    q14, q4, d3[0]
264        LDR          r0, [r9, 72]    // B0 low
265        VMLA.F32     q9, q5, d0[0]
266        LDR          r2, [r9, 76]    // B0 high
267        VMLA.F32    q11, q5, d1[0]
268
269        // BLOCK 2
270        VLD1.32    {d6}, [r10]!      // A2
271        VMOV         d9, r0, r2      // b0 VMOV
272        VMLA.F32    q13, q5, d2[0]
273        LDR          r0, [r7]        // A3 low
274        VMLA.F32    q15, q5, d3[0]
275        LDR          r2, [r7, 4]     // A3 high
276        VMLA.F32     q8, q6, d0[1]
277
278        // BLOCK 3
279        VLDR        d14, [r9, 48]    // B1
280        VMOV         d7, r0, r2      // a3 VMOV
281        VMLA.F32    q10, q6, d1[1]
282        LDR          r0, [r9, 88]    // B0 low
283        VMLA.F32    q12, q6, d2[1]
284        LDR          r2, [r9, 92]    // B0 high
285        VMLA.F32    q14, q6, d3[1]
286
287        // BLOCK 4
288        VLDR         d8, [r9, 64]    // B0
289        VMOV        d11, r0, r2      // B0 VMOV
290        VMLA.F32     q9, q7, d0[1]
291        LDR          r0, [r9, 104]   // B1 low
292        VMLA.F32    q11, q7, d1[1]
293        LDR          r2, [r9, 108]   // B1 high
294        VMLA.F32    q13, q7, d2[1]
295
296        // BLOCK 5
297        VLDR        d10, [r9, 80]    // B0
298        VMOV        d13, r0, r2      // b1 VMOV b
299        VMLA.F32    q15, q7, d3[1]
300        LDR          r0, [r9, 120]   // B1 low   VMOV is in BLOCK 0
301        NOP
302        LDR          r2, [r9, 124]   // B1 high
303        NOP
304        NOP
305
306        # Second group of 16 FMA, First group of loads
307        // BLOCK 0
308        VLDR        d12, [r9, 96]    // B1
309        VMOV        d15, r0, r2      // b1 VMOV b from second group
310        VMLA.F32     q8, q4, d4[0]
311        VMLA.F32    q10, q4, d5[0]
312        VMLA.F32    q12, q4, d6[0]
313
314        // BLOCK 1
315        VLDR        d14, [r9, 112]   // B1
316        VMLA.F32    q14, q4, d7[0]
317        VMLA.F32     q9, q5, d4[0]
318        VMLA.F32    q11, q5, d5[0]
319        NOP
320
321        // BLOCK 2
322        NOP                          // VDDR B1 lands here
323        NOP
324        VMLA.F32    q13, q5, d6[0]
325        VMLA.F32    q15, q5, d7[0]
326        VMLA.F32     q8, q6, d4[1]
327
328        // BLOCK 3
329        VMLA.F32    q10, q6, d5[1]
330        VMLA.F32    q12, q6, d6[1]
331        VMLA.F32    q14, q6, d7[1]
332        ADD         r12, r12, 8      // A1++
333
334        // BLOCK 4
335        VMLA.F32     q9, q7, d4[1]
336        VMLA.F32    q11, q7, d5[1]
337        VMLA.F32    q13, q7, d6[1]
338        ADD          r7, r7, 8       // A3++
339
340        // BLOCK 5
341        VMLA.F32    q15, q7, d7[1]
342        ADD          r9, r9, 128     // B++
343
3444:
345        // Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
346        TST          r5, 12
347        BNE          7f
348
349        .p2align 3
3505:
351        // Load params pointer
352        LDR          r0, [sp, 116]   // cn_stride
353        LDR          r5, [sp, 120]   // clamping_params
354        LDR          r2, [sp, 0]     // kc
355        SUBS         r1, r1, 8
356
357        // Load clamping_params values
358        VLD1.32     {d4[],d5[]}, [r5]!
359        VLD1.32     {d6[],d7[]}, [r5]
360
361        // Clamp
362        VMIN.F32     q8,  q8, q2
363        VMIN.F32     q9,  q9, q2
364        VMIN.F32    q10, q10, q2
365        VMIN.F32    q11, q11, q2
366        VMIN.F32    q12, q12, q2
367        VMIN.F32    q13, q13, q2
368        VMIN.F32    q14, q14, q2
369        VMIN.F32    q15, q15, q2
370        VMAX.F32     q8,  q8, q3
371        VMAX.F32     q9,  q9, q3
372        VMAX.F32    q10, q10, q3
373        VMAX.F32    q11, q11, q3
374        VMAX.F32    q12, q12, q3
375        VMAX.F32    q13, q13, q3
376        VMAX.F32    q14, q14, q3
377        VMAX.F32    q15, q15, q3
378
379        // Store full 4 x 8
380        BLO         10f
381        VST1.32     {d16-d19}, [r11], r0
382        SUB         r7, r7, r2
383        VST1.32     {d20-d23}, [r4], r0
384        SUB         r10, r10, r2
385        VST1.32     {d24-d27}, [r8], r0
386        SUB         r12, r12, r2
387        VST1.32     {d28-d31}, [r6], r0
388        SUB         r3, r3, r2
389        BHI         1b
390
3916:
392        ADD         sp, sp, 4
393        POP         {r4, r5, r6, r7, r8, r9, r10, r11}
394        VPOP        {d8-d15}
395        BX          lr
396
397        .p2align 3
3987:
399        // Is there a remainder?- 2 floats of A (8 bytes)
400        TST         r5, 8
401        BEQ         8f
402
403        // Remainder - 2 floats of A (8 bytes)
404        VLD1.32    {d0}, [r3]!       // A0
405        VLDM        r9!, {d8-d11}    // B0
406        VLD1.32    {d1}, [r12]!      // A1
407        VLD1.32    {d2}, [r10]!      // A2
408        VLD1.32    {d3}, [ r7]!      // A3
409
410        VMLA.F32     q8, q4, d0[0]
411        VMLA.F32     q9, q5, d0[0]
412        VMLA.F32    q10, q4, d1[0]
413        VMLA.F32    q11, q5, d1[0]
414        VLDM        r9!, {d12-d15}   // B1
415        VMLA.F32    q12, q4, d2[0]
416        VMLA.F32    q13, q5, d2[0]
417        VMLA.F32    q14, q4, d3[0]
418        VMLA.F32    q15, q5, d3[0]
419        VMLA.F32     q8, q6, d0[1]
420        VMLA.F32     q9, q7, d0[1]
421        VMLA.F32    q10, q6, d1[1]
422        VMLA.F32    q11, q7, d1[1]
423        VMLA.F32    q12, q6, d2[1]
424        VMLA.F32    q13, q7, d2[1]
425        VMLA.F32    q14, q6, d3[1]
426        VMLA.F32    q15, q7, d3[1]
4278:
428        // Is there a remainder?- 1 floats of A (4 bytes)
429        TST         r5, 4
430        BEQ         5b
431
4329:
433        // Remainder- 1 floats of A (4 bytes)
434        VLDM        r3!,  {s0}       // A0
435        VLDM        r9!, {d8-d11}    // B0
436        VLDM        r12!, {s2}       // A1
437        VLDM        r10!, {s4}       // A2
438        VLDM         r7!, {s6}       // A3
439        VMLA.F32     q8, q4, d0[0]
440        VMLA.F32     q9, q5, d0[0]
441        VMLA.F32    q10, q4, d1[0]
442        VMLA.F32    q11, q5, d1[0]
443        VMLA.F32    q12, q4, d2[0]
444        VMLA.F32    q13, q5, d2[0]
445        VMLA.F32    q14, q4, d3[0]
446        VMLA.F32    q15, q5, d3[0]
447        B           5b
448
449        // Store odd width
45010:
451        TST         r1, 4
452        BEQ         11f
453        VST1.32    {d16-d17}, [r11]!
454        VMOV         q8,  q9
455        VST1.32    {d20-d21},  [r4]!
456        VMOV        q10, q11
457        VST1.32    {d24-d25},  [r8]!
458        VMOV        q12, q13
459        VST1.32    {d28-d29},  [r6]!
460        VMOV        q14, q15
461
46211:
463        TST        r1, 2
464        BEQ        12f
465        VST1.32    {d16}, [r11]!
466        VMOV        d16, d17
467        VST1.32    {d20},  [r4]!
468        VMOV        d20, d21
469        VST1.32    {d24},  [r8]!
470        VMOV        d24, d25
471        VST1.32    {d28},  [r6]!
472        VMOV        d28, d29
473
47412:
475        TST         r1, 1
476        BEQ         13f
477        VST1.32    {d16[0]}, [r11]
478        VST1.32    {d20[0]},  [r4]
479        VST1.32    {d24[0]},  [r8]
480        VST1.32    {d28[0]},  [r6]
481
48213:
483        ADD         sp, sp, 4
484        POP         {r4, r5, r6, r7, r8, r9, r10, r11}
485        VPOP        {d8-d15}
486        BX          lr
487
488END_FUNCTION xnn_f32_gemm_ukernel_4x8__aarch32_neon_cortex_a53
489
490#ifdef __ELF__
491.section ".note.GNU-stack","",%progbits
492#endif