• 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_${"pld_" if PREFETCH else ""}cortex_a75(
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 -> r2
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 -> (r7)
20//     size_t a_offset,          sp + 132 -> (r5)
21//     const float* zero,        sp + 136 -> (r7)
22//     minmax_params*params,     sp + 140 -> (r5)
23
24// inner loop registers
25
26// A0   r3  d0
27// A1  r12  d1
28// A2  r10  d2
29// A3   r0  d3
30
31// B    r9  d8,  d9, d10, d11
32// B       d12, d13, d14, d15
33
34// C0  r11 d16-d17  q8  d18-d19  q9
35// C1   r4 d20-d21 q10  d22-d23 q11
36// C2   r8 d24-d25 q12  d26-d27 q13
37// C3   r6 d28-d29 q14  d30-d31 q15
38
39// Clamp (r5) d4 d5 d6 d7
40
41BEGIN_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_${"pld_" if PREFETCH else ""}cortex_a75
42        .arm
43#ifndef __APPLE__
44        .arch armv7-a
45        .fpu neon
46#endif
47        // Push 112 bytes
48        // r2 will be reloaded in outer loop.  r3 is ks
49        PUSH   {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r14}  // +44
50        SUB    sp, sp, 4                                        // 4
51        VPUSH  {d8-d15}                                         // +64 = 112
52
53        LDR        r11, [sp, 120]    // c
54        LDR         r6, [sp, 124]    // cm_stride
55        LDR         r2, [sp, 112]    // a
56        LDR         r9, [sp, 116]    // 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        .p2align 3
710:
72        # Load initial bias from w into accumulators
73        VLDM       r9!, {d16-d19}   // Bias
74        VMOV       q10, q8
75        VMOV       q11, q9
76        VMOV       q12, q8
77        VMOV       q13, q9
78        VMOV       q14, q8
79        VMOV       q15, q9
80
81        $if PREFETCH:
82          PLD         [r9,   0]  // Prefetch B
83          PLD         [r9,  64]
84          PLD         [r9, 128]
85          PLD         [r9, 192]
86          PLD         [r9, 256]
87          PLD         [r9, 320]
88          PLD         [r9, 384]
89
901:
91        # Load next 4 A pointers
92        LDR         r3, [r2,  0]
93        LDR        r12, [r2,  4]
94        LDR        r10, [r2,  8]
95        LDR         r0, [r2, 12]
96        ADD         r2, r2, 16
97
98        // Add a_offset
99        LDR         r5, [sp, 132]    // a_offset
100        LDR         r7, [sp, 136]    // zero
101        CMP         r3,  r7          // if a0 == zero
102        ADD         r3,  r3, r5      // a0 += a_offset
103        MOVEQ       r3,  r7          //   a0 = zero, else += a0 + a_offset
104        CMP        r12,  r7          // if a1 == zero
105        ADD        r12, r12, r5      // a1 += a_offset
106        MOVEQ      r12,  r7          //   a1 = zero, else += a1 + a_offset
107        CMP        r10,  r7          // if a2 == zero
108        ADD        r10, r10, r5      // a2 += a_offset
109        MOVEQ      r10,  r7          //   a2 = zero, else += a2 + a_offset
110        CMP         r0,  r7          // if a3 == zero
111        ADD         r0,  r0, r5      // a3 += a_offset
112        LDR         r5, [sp, 68]     // kc
113        MOVEQ       r0,  r7          //   a3 = zero, else += a3 + a_offset
114
115        $if PREFETCH:
116          PLD         [r3,  0]    // Prefetch A
117          PLD         [r3, 64]
118          PLD        [r12,  0]
119          PLD        [r12, 64]
120          PLD        [r10,  0]
121          PLD        [r10, 64]
122          PLD         [r0,  0]
123          PLD         [r0, 64]
124
125        SUBS        r5, r5, 16       // kc - 16
126        BLO         5f               // less than 4 channels?
127
128        // Prologue
129        VLD1.32    {d0}, [r3]!       // A0
130        VLDM        r9!, {d8-d11}    // B0
131        VLD1.32    {d1}, [r12]!      // A1
132        VLD1.32    {d2}, [r10]!      // A2
133        VLD1.32    {d3}, [ r0]!      // A3
134
135        SUBS        r5, r5, 16
136        BLO         3f               // less than 4 channels?  skip main loop
137
138        .p2align 3
139
140        // Main loop - 4 floats of A (16 bytes)
1412:
142        VMLA.F32     q8, q4, d0[0]
143        VLDM        r9!, {d12-d15}   // B1
144        VMLA.F32    q10, q4, d1[0]
145        VMLA.F32    q12, q4, d2[0]
146        VLD1.32    {d4}, [r3]!       // A0
147        VMLA.F32    q14, q4, d3[0]
148        VMLA.F32     q9, q5, d0[0]
149        VLD1.32    {d5}, [r12]!      // A1
150        VMLA.F32    q11, q5, d1[0]
151        VMLA.F32    q13, q5, d2[0]
152        VMLA.F32    q15, q5, d3[0]
153        VLD1.32    {d6}, [r10]!      // A2
154        VMLA.F32     q8, q6, d0[1]
155        VMLA.F32    q10, q6, d1[1]
156        VLD1.32    {d7}, [ r0]!      // A3
157        VMLA.F32    q12, q6, d2[1]
158        VMLA.F32    q14, q6, d3[1]
159        VLDM        r9!, {d8-d11}    // B0
160        VMLA.F32     q9, q7, d0[1]
161        VMLA.F32    q11, q7, d1[1]
162        VMLA.F32    q13, q7, d2[1]
163        VMLA.F32    q15, q7, d3[1]
164
165        VMLA.F32     q8, q4, d4[0]
166        VLDM        r9!, {d12-d15}   // B1
167        VMLA.F32    q10, q4, d5[0]
168        $if PREFETCH:
169          PLD         [r3, 128]        // Prefetch A0
170        VMLA.F32    q12, q4, d6[0]
171        VLD1.32    {d0}, [r3]!       // A0
172        VMLA.F32    q14, q4, d7[0]
173        $if PREFETCH:
174          PLD         [r12, 128]       // Prefetch A1
175        VMLA.F32     q9, q5, d4[0]
176        VLD1.32    {d1}, [r12]!      // A1
177        VMLA.F32    q11, q5, d5[0]
178        $if PREFETCH:
179          PLD         [r10, 128]       // Prefetch A2
180        VMLA.F32    q13, q5, d6[0]
181        VLD1.32    {d2}, [r10]!      // A2
182        VMLA.F32    q15, q5, d7[0]
183        $if PREFETCH:
184          PLD         [r0, 128]        // Prefetch A3
185        VMLA.F32     q8, q6, d4[1]
186        VLD1.32    {d3}, [ r0]!      // A3
187        VMLA.F32    q10, q6, d5[1]
188        $if PREFETCH:
189          PLD         [r9, 352]        // Prefetch B
190        VMLA.F32    q12, q6, d6[1]
191        $if PREFETCH:
192          PLD         [r9, 416]        // Prefetch B
193        VMLA.F32    q14, q6, d7[1]
194        VLDM        r9!, {d8-d11}    // B0
195        VMLA.F32     q9, q7, d4[1]
196        VMLA.F32    q11, q7, d5[1]
197        SUBS         r5, r5, 16
198        VMLA.F32    q13, q7, d6[1]
199        VMLA.F32    q15, q7, d7[1]
200        BHS         2b
201
202        // Epilogue
2033:
204        VMLA.F32     q8, q4, d0[0]
205        VLDM        r9!, {d12-d15}   // B1
206        VMLA.F32    q10, q4, d1[0]
207        VMLA.F32    q12, q4, d2[0]
208        VLD1.32    {d4}, [r3]!       // A0
209        VMLA.F32    q14, q4, d3[0]
210        VMLA.F32     q9, q5, d0[0]
211        VLD1.32    {d5}, [r12]!      // A1
212        VMLA.F32    q11, q5, d1[0]
213        VMLA.F32    q13, q5, d2[0]
214        VMLA.F32    q15, q5, d3[0]
215        VLD1.32    {d6}, [r10]!      // A2
216        VMLA.F32     q8, q6, d0[1]
217        VMLA.F32    q10, q6, d1[1]
218        VLD1.32    {d7}, [ r0]!      // A3
219        VMLA.F32    q12, q6, d2[1]
220        VMLA.F32    q14, q6, d3[1]
221        VLDM        r9!, {d8-d11}    // B0
222        VMLA.F32     q9, q7, d0[1]
223        VMLA.F32    q11, q7, d1[1]
224        VMLA.F32    q13, q7, d2[1]
225        VMLA.F32    q15, q7, d3[1]
226
227        VMLA.F32     q8, q4, d4[0]
228        VLDM        r9!, {d12-d15}   // B1
229        VMLA.F32    q10, q4, d5[0]
230        VMLA.F32    q12, q4, d6[0]
231        VMLA.F32    q14, q4, d7[0]
232        VMLA.F32     q9, q5, d4[0]
233        VMLA.F32    q11, q5, d5[0]
234        VMLA.F32    q13, q5, d6[0]
235        VMLA.F32    q15, q5, d7[0]
236        VMLA.F32     q8, q6, d4[1]
237        VMLA.F32    q10, q6, d5[1]
238        VMLA.F32    q12, q6, d6[1]
239        VMLA.F32    q14, q6, d7[1]
240        VMLA.F32     q9, q7, d4[1]
241        VMLA.F32    q11, q7, d5[1]
242        VMLA.F32    q13, q7, d6[1]
243        VMLA.F32    q15, q7, d7[1]
244
245        // Is there a remainder?- 1 to 3 floats of A (4, 8 or 12 bytes)
246        TST         r5, 12
247        BNE         5f
248
249        .p2align 3
2504:
251        # ks loop
252        SUBS r14, r14, 16  // ks -= MR * sizeof(void*)
253        BHI 1b
254
255        // Load params pointer
256        LDR          r5, [sp, 140]   // params
257        LDR          r7, [sp, 128]   // cn_stride
258        LDR         r14, [sp, 72]    // p = ks
259
260        // Load min/max values
261        VLD1.32     {d4[],d5[]}, [r5]!
262        SUBS        r1, r1, 8
263        VLD1.32     {d6[],d7[]}, [r5]
264
265        // Clamp
266        VMAX.F32     q8,  q8, q2
267        VMAX.F32     q9,  q9, q2
268        VMAX.F32    q10, q10, q2
269        VMAX.F32    q11, q11, q2
270        VMAX.F32    q12, q12, q2
271        VMAX.F32    q13, q13, q2
272        VMAX.F32    q14, q14, q2
273        VMAX.F32    q15, q15, q2
274        VMIN.F32     q8,  q8, q3
275        VMIN.F32     q9,  q9, q3
276        VMIN.F32    q10, q10, q3
277        VMIN.F32    q11, q11, q3
278        VMIN.F32    q12, q12, q3
279        VMIN.F32    q13, q13, q3
280        VMIN.F32    q14, q14, q3
281        VMIN.F32    q15, q15, q3
282
283        // Store full 4 x 8
284        BLO         7f
285        VST1.32     {d28-d31},  [r6], r7
286        VST1.32     {d24-d27},  [r8], r7
287        VST1.32     {d20-d23},  [r4], r7
288        VST1.32     {d16-d19}, [r11], r7
289        SUB         r2, r2, r14    // a -= ks
290        BHI         0b
291
292        VPOP        {d8-d15}
293        ADD         sp, sp, 12  // skip pad, r2, r3
294        POP         {r4, r5, r6, r7, r8, r9, r10, r11, pc}
295
296        .p2align 3
2975:
298        // Is there a remainder?- 2 floats of A (8 bytes)
299        TST         r5, 8
300        BEQ         6f
301
302        // Remainder - 2 floats of A (8 bytes)
303        VLD1.32    {d0}, [r3]!       // A0
304        VLDM        r9!, {d8-d11}    // B0
305        VLD1.32    {d1}, [r12]!      // A1
306        VLD1.32    {d2}, [r10]!      // A2
307        VLD1.32    {d3}, [ r0]!      // A3
308
309        VMLA.F32     q8, q4, d0[0]
310        VMLA.F32     q9, q5, d0[0]
311        VMLA.F32    q10, q4, d1[0]
312        VMLA.F32    q11, q5, d1[0]
313        VLDM        r9!, {d12-d15}   // B1
314        VMLA.F32    q12, q4, d2[0]
315        VMLA.F32    q13, q5, d2[0]
316        VMLA.F32    q14, q4, d3[0]
317        VMLA.F32    q15, q5, d3[0]
318        VMLA.F32     q8, q6, d0[1]
319        VMLA.F32     q9, q7, d0[1]
320        VMLA.F32    q10, q6, d1[1]
321        VMLA.F32    q11, q7, d1[1]
322        VMLA.F32    q12, q6, d2[1]
323        VMLA.F32    q13, q7, d2[1]
324        VMLA.F32    q14, q6, d3[1]
325        VMLA.F32    q15, q7, d3[1]
326
327        // Is there a remainder?- 1 floats of A (4 bytes)
328        TST         r5, 4
329        BEQ         4b
330
3316:
332        // Remainder- 1 floats of A (4 bytes)
333        VLDM        r3!, {s0}       // A0
334        VLDM        r9!, {d8-d11}   // B0
335        VLDM       r12!, {s2}       // A1
336        VLDM       r10!, {s4}       // A2
337        VLDM        r0!, {s6}       // A3
338        VMLA.F32     q8, q4, d0[0]
339        VMLA.F32     q9, q5, d0[0]
340        VMLA.F32    q10, q4, d1[0]
341        VMLA.F32    q11, q5, d1[0]
342        VMLA.F32    q12, q4, d2[0]
343        VMLA.F32    q13, q5, d2[0]
344        VMLA.F32    q14, q4, d3[0]
345        VMLA.F32    q15, q5, d3[0]
346        B           4b
347
348        // Store odd width
3497:
350        TST         r1, 4
351        BEQ         8f
352        VST1.32    {d28-d29},  [r6]!
353        VMOV        q14, q15
354        VST1.32    {d24-d25},  [r8]!
355        VMOV        q12, q13
356        VST1.32    {d20-d21},  [r4]!
357        VMOV        q10, q11
358        VST1.32    {d16-d17}, [r11]!
359        VMOV         q8,  q9
360
3618:
362        TST        r1, 2
363        BEQ        9f
364        VST1.32    {d28},  [r6]!
365        VMOV        d28, d29
366        VST1.32    {d24},  [r8]!
367        VMOV        d24, d25
368        VST1.32    {d20},  [r4]!
369        VMOV        d20, d21
370        VST1.32    {d16}, [r11]!
371        VMOV        d16, d17
372
3739:
374        TST         r1, 1
375        BEQ         10f
376        VST1.32    {d28[0]},  [r6]!
377        VST1.32    {d24[0]},  [r8]!
378        VST1.32    {d20[0]},  [r4]!
379        VST1.32    {d16[0]}, [r11]!
380
38110:
382        VPOP        {d8-d15}
383        ADD         sp, sp, 12  // skip pad, r2, r3
384        POP         {r4, r5, r6, r7, r8, r9, r10, r11, pc}
385
386END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon_${"pld_" if PREFETCH else ""}cortex_a75
387
388#ifdef __ELF__
389.section ".note.GNU-stack","",%progbits
390#endif
391