• 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${"_prfm" if PREFETCH else ""}_ld64(
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// d8-d15, r4-r11,r14(lr) need to be preserved if used. r13(sp),r15(pc) are reserved.
25
26// Register usage
27// A0   r3  d0
28// A1  r12  d1
29// A2  r10  d2
30// A3   r0  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${"_prfm" if PREFETCH else ""}_ld64
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, lr}   // +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     r2, [sp, 112]           // a
57        LDR     r9, [sp, 116]           // w
58        LDR     r5, [sp, 140]           // params
59        MOV     r14, r3                 // p = ks
60
61        # Clamp C pointers
62        CMP     r0, 2                   // if mr >= 2
63        ADD     r4, r11, r6             //   c1 = c0 + cm_stride
64        MOVLO   r4, r11                 // c1
65                                        // if mr > 2
66        ADD     r8, r4, r6              //   c2 = c1 + cm_stride
67        MOVLS   r8, r4                  // c2
68        CMP     r0, 4                   // if mr >=4
69        ADD     r6, r8, r6              //   c3 = c2 + cm_stride
70        MOVLO   r6, r8                  // c3
71
72        # Load min/max values
73        VLD1.32 {d4[], d5[]}, [r5]!
74        VLD1.32 {d6[], d7[]}, [r5]
75
760:
77        # Load initial bias from w into accumulators
78        VLDM    r9!, {d16-d19}          // Bias
79        VMOV    q10, q8
80        VMOV    q11, q9
81        VMOV    q12, q8
82        VMOV    q13, q9
83        VMOV    q14, q8
84        VMOV    q15, q9
85
86        $if PREFETCH:
87          PLD     [r9,   0]               // Prefetch B
88          PLD     [r9,  64]
89          PLD     [r9, 128]
90          PLD     [r9, 192]
91          PLD     [r9, 256]
92          PLD     [r9, 320]
93          PLD     [r9, 384]
94          PLD     [r9, 448]
951:
96        # Load next 4 A pointers
97        LDR     r3, [r2,  0]
98        LDR     r12, [r2,  4]
99        LDR     r10, [r2,  8]
100        LDR     r0, [r2, 12]
101        ADD     r2, r2, 16
102
103        # Add a_offset
104        LDR     r5, [sp, 132]           // a_offset
105        LDR     r7, [sp, 136]           // zero
106        CMP     r3,  r7                 // if a0 == zero
107        ADD     r3,  r3, r5             // a0 += a_offset
108        MOVEQ   r3,  r7                 //   a0 = zero, else += a0 + a_offset
109        CMP     r12,  r7                // if a1 == zero
110        ADD     r12, r12, r5            // a1 += a_offset
111        MOVEQ   r12,  r7                //   a1 = zero, else += a1 + a_offset
112        CMP     r10,  r7                // if a2 == zero
113        ADD     r10, r10, r5            // a2 += a_offset
114        MOVEQ   r10,  r7                //   a2 = zero, else += a2 + a_offset
115        CMP     r0,  r7                 // if a3 == zero
116        ADD     r0,  r0, r5             // a3 += a_offset
117        LDR     r5, [sp, 68]            // kc
118        MOVEQ   r0,  r7                 //   a3 = zero, else += a3 + a_offset
119
120        $if PREFETCH:
121          PLD     [r3,  0]                // Prefetch A
122          PLD     [r3, 64]
123          PLD     [r12,  0]
124          PLD     [r12, 64]
125          PLD     [r10,  0]
126          PLD     [r10, 64]
127          PLD     [r0,  0]
128          PLD     [r0, 64]
129
130        SUBS    r5, r5, 8               // kc - 8
131        BLO     4f                      // less than 2 channels?
132
133        # Main loop - 2 floats of A (8 bytes)
1342:
135        VLD1.32 {d0}, [r3]!             // A0
136        VLDM    r9!, {d8-d11}           // B0
137        VLD1.32 {d1}, [r12]!            // A1
138        VLD1.32 {d2}, [r10]!            // A2
139        VLD1.32 {d3}, [ r0]!            // A3
140        VLDM    r9!, {d12-d15}          // B1
141
142        VMLA.F32 q8, q4, d0[0]
143        VMLA.F32 q9, q5, d0[0]
144        $if PREFETCH:
145          PLD     [r3, 128]               // Prefetch A0
146        VMLA.F32 q10, q4, d1[0]
147        VMLA.F32 q11, q5, d1[0]
148        $if PREFETCH:
149          PLD     [r12, 128]              // Prefetch A1
150        VMLA.F32 q12, q4, d2[0]
151        VMLA.F32 q13, q5, d2[0]
152        $if PREFETCH:
153          PLD     [r10, 128]              // Prefetch A2
154        VMLA.F32 q14, q4, d3[0]
155        VMLA.F32 q15, q5, d3[0]
156        $if PREFETCH:
157          PLD     [r0, 128]               // Prefetch A3
158        VMLA.F32 q8, q6, d0[1]
159        VMLA.F32 q9, q7, d0[1]
160        $if PREFETCH:
161          PLD     [r9, 448]               // Prefetch B
162        VMLA.F32 q10, q6, d1[1]
163        VMLA.F32 q11, q7, d1[1]
164        SUBS    r5, r5, 8
165        VMLA.F32 q12, q6, d2[1]
166        VMLA.F32 q13, q7, d2[1]
167        VMLA.F32 q14, q6, d3[1]
168        VMLA.F32 q15, q7, d3[1]
169        BHS     2b
170
171        # Is there a remainder?- 1 floats of A (4 bytes)
172        TST     r5, 4
173        BNE     4f
174
1753:
176        # ks loop
177        SUBS    r14, r14, 16            // ks -= MR * sizeof(void*)
178        BHI     1b
179
180        LDR     r7, [sp, 128]           // cn_stride
181        LDR     r14, [sp, 72]           // p = ks
182
183        # Clamp
184        VMAX.F32 q8,  q8, q2
185        SUBS    r1, r1, 8
186        VMAX.F32 q9,  q9, q2
187        VMAX.F32 q10, q10, q2
188        VMAX.F32 q11, q11, q2
189        VMAX.F32 q12, q12, q2
190        VMAX.F32 q13, q13, q2
191        VMAX.F32 q14, q14, q2
192        VMAX.F32 q15, q15, q2
193        VMIN.F32 q8,  q8, q3
194        VMIN.F32 q9,  q9, q3
195        VMIN.F32 q10, q10, q3
196        VMIN.F32 q11, q11, q3
197        VMIN.F32 q12, q12, q3
198        VMIN.F32 q13, q13, q3
199        VMIN.F32 q14, q14, q3
200        VMIN.F32 q15, q15, q3
201
202        # Store full 4 x 8
203        BLO     5f
204        VST1.32 {d28-d31},  [r6], r7
205        VST1.32 {d24-d27},  [r8], r7
206        VST1.32 {d20-d23},  [r4], r7
207        VST1.32 {d16-d19}, [r11], r7
208        SUB     r2, r2, r14             // a -= ks
209        BHI     0b
210
211        VPOP    {d8-d15}
212        ADD     sp, sp, 12              // skip pad, r2, r3
213        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
214
2154:
216        # Remainder- 1 floats of A (4 bytes)
217        VLDM    r3!, {s0}               // A0
218        VLDM    r9!, {d8-d11}           // B0
219        VLDM    r12!, {s2}              // A1
220        VLDM    r10!, {s4}              // A2
221        VLDM    r0!, {s6}               // A3
222        VMLA.F32 q8, q4, d0[0]
223        VMLA.F32 q9, q5, d0[0]
224        VMLA.F32 q10, q4, d1[0]
225        VMLA.F32 q11, q5, d1[0]
226        VMLA.F32 q12, q4, d2[0]
227        VMLA.F32 q13, q5, d2[0]
228        VMLA.F32 q14, q4, d3[0]
229        VMLA.F32 q15, q5, d3[0]
230        B       3b
231
232        # Store odd width
2335:
234        TST     r1, 4
235        BEQ     6f
236        VST1.32 {d28-d29},  [r6]!
237        VST1.32 {d24-d25},  [r8]!
238        VMOV    q14, q15
239        VMOV    q12, q13
240        VST1.32 {d20-d21},  [r4]!
241        VST1.32 {d16-d17}, [r11]!
242        VMOV    q10, q11
243        VMOV    q8,  q9
244
2456:
246        TST     r1, 2
247        BEQ     7f
248        VST1.32 {d28},  [r6]!
249        VST1.32 {d24},  [r8]!
250        VMOV    d28, d29
251        VMOV    d24, d25
252        VST1.32 {d20},  [r4]!
253        VST1.32 {d16}, [r11]!
254        VMOV    d20, d21
255        VMOV    d16, d17
256
2577:
258        TST     r1, 1
259        BEQ     8f
260        VST1.32 {d28[0]},  [r6]!
261        VST1.32 {d24[0]},  [r8]!
262        VST1.32 {d20[0]},  [r4]!
263        VST1.32 {d16[0]}, [r11]!
264
2658:
266        VPOP    {d8-d15}
267        ADD     sp, sp, 12              // skip pad, r2, r3
268        POP     {r4, r5, r6, r7, r8, r9, r10, r11, pc}
269
270END_FUNCTION xnn_f32_igemm_minmax_ukernel_4x8__aarch32_neon${"_prfm" if PREFETCH else ""}_ld64
271
272#ifdef __ELF__
273.section ".note.GNU-stack","",%progbits
274#endif
275