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