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