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