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