1 // Copyright 2022 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 <cassert>
7 #include <cstddef>
8 #include <limits>
9
10 #include <xnnpack.h>
11 #include <xnnpack/aarch64-assembler.h>
12 #include <xnnpack/allocator.h>
13 #include <xnnpack/igemm.h>
14
15 namespace xnnpack {
16 namespace aarch64 {
17 namespace {
18 class Generator : public Assembler {
19 using Assembler::Assembler;
20
21 public:
22 void generate(bool prefetch, size_t max_mr, size_t nc_mod_nr, size_t kc, size_t ks, float min, float max);
23 };
24
25 // void xnn_f32_igemm_minmax_ukernel_6x8__aarch64_neonfma_prfm_cortex_a75(
26 // size_t mr, x0
27 // size_t nc, x1
28 // size_t kc, x2 / x0
29 // size_t ks, x3 / x9
30 // const float**restrict a, x4
31 // const void*restrict w, x5
32 // uint8_t*restrict c, x6
33 // size_t cm_stride, x7
34 // size_t cn_stride, [sp] -> (x0)
35 // size_t a_offset, [sp + 8] -> x11
36 // const float* zero, [sp + 16] -> x12
37 // const xnn_f32_minmax_params params [sp + 24] -> x8
38
39 // d8-d15, x19-x30 need to be preserved if used. x18 is reserved by the OS.
40
41 // A pointers
42 // x14 a0
43 // x15 a1
44 // x20 a2
45 // x21 a3
46 // x22 a4
47 // x23 a5
48
49 // C pointers
50 // x6 c0
51 // x16 c1
52 // x17 c2
53 // x10 c3
54 // x13 c4
55 // x7 c5
56
57 // Vector register usage
58 // A0 v0 v6
59 // A1 v1 v7
60 // A2 v2 v8
61 // A3 v3 v9
62 // A4 v4 v10
63 // A5 v5 v11
64 // B v12 v13 v14 v15
65 // B v16 v17 v18 v19
66 // C v20 v21
67 // C v22 v23
68 // C v24 v25
69 // C v26 v27
70 // C v28 v29
71 // C v30 v31
72 // Clamp v6 v7
73
74 // Converted from: src/f32-igemm/gen/6x8-minmax-aarch64-neonfma-prfm-cortex-a75.S
generate(bool prefetch,size_t max_mr,size_t nc_mod_nr,size_t kc,size_t ks,float min,float max)75 void Generator::generate(bool prefetch, size_t max_mr, size_t nc_mod_nr, size_t kc, size_t ks, float min, float max)
76 {
77 assert(max_mr <= 6);
78 assert(nc_mod_nr < 8);
79 assert(kc != 0);
80 assert(kc % sizeof(float) == 0);
81 assert(ks != 0);
82
83 Label l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11;
84 const bool clamp_min = min != -std::numeric_limits<float>::infinity();
85 const bool clamp_max = max != +std::numeric_limits<float>::infinity();
86
87 // Clamp C pointers / Save d8-d15 on stack
88 stp(d8, d9, mem[sp, -96]++);
89 if (max_mr > 1) {
90 cmp(x0, 2); // if mr < 2
91 add(x16, x6, x7); // c1 = c0 + cm_stride
92 csel(x16, x6, x16, kLO); // c1 = c0
93 }
94
95 stp(d10, d11, mem[sp, 16]);
96 if (max_mr > 2) {
97 add(x17, x16, x7); // c2 = c1 + cm_stride
98 // if mr <= 2
99 csel(x17, x16, x17, kLS); // c2 = c1
100 }
101
102 stp(d12, d13, mem[sp, 32]);
103 if (max_mr > 3) {
104 cmp(x0, 4); // if mr < 4
105 add(x10, x17, x7); // c3 = c2 + cm_stride
106 csel(x10, x17, x10, kLO); // c3 = c2
107 }
108
109 stp(d14, d15, mem[sp, 48]);
110 if (max_mr > 4) {
111 add(x13, x10, x7); // c4 = c3 + cm_stride
112 // if mr <= 4
113 csel(x13, x10, x13, kLS); // c4 = c3
114 }
115
116 // Save x20,x21,x22,x23 on stack
117 stp(x20, x21, mem[sp, 64]);
118 stp(x22, x23, mem[sp, 80]);
119
120 if (max_mr > 5) {
121 cmp(x0, 6); // if mr < 6
122 add(x7, x13, x7); // c5 = c4 + cm_stride
123 csel(x7, x13, x7, kLO); // c5 = c4
124 }
125
126 // Load a_offset
127 ldr(x11, mem[sp, 104]);
128
129 // Load zero, params pointer
130 ldp(x12, x8, mem[sp, 112]);
131
132 bind(l0);
133 // Load initial bias from w into accumulators
134 ldp(q20, q21, mem[x5], 32);
135 if (max_mr > 1) {
136 mov(v22.v16b(), v20.v16b());
137 mov(v23.v16b(), v21.v16b());
138 }
139 if (prefetch) {
140 prfm(kPLDL1KEEP, mem[x5, 0]); // Prefetch B
141 }
142 if (max_mr > 2) {
143 mov(v24.v16b(), v20.v16b());
144 mov(v25.v16b(), v21.v16b());
145 }
146 if (prefetch) {
147 prfm(kPLDL1KEEP, mem[x5, 64]);
148 }
149 if (max_mr > 3) {
150 mov(v26.v16b(), v20.v16b());
151 mov(v27.v16b(), v21.v16b());
152 }
153 if (prefetch) {
154 prfm(kPLDL1KEEP, mem[x5, 128]);
155 }
156 if (max_mr > 4) {
157 mov(v28.v16b(), v20.v16b());
158 mov(v29.v16b(), v21.v16b());
159 }
160 if (prefetch) {
161 prfm(kPLDL1KEEP, mem[x5, 192]);
162 }
163 if (max_mr > 5) {
164 mov(v30.v16b(), v20.v16b());
165 mov(v31.v16b(), v21.v16b());
166 }
167 if (prefetch) {
168 prfm(kPLDL1KEEP, mem[x5, 256]);
169 prfm(kPLDL1KEEP, mem[x5, 320]);
170 }
171
172 mov(x9, x3); // p = ks
173
174 bind(l1);
175 // Load next 6 A pointers
176 switch (max_mr) {
177 case 1:
178 ldr(x14, mem[x4], 8);
179 break;
180 case 2:
181 ldp(x14, x15, mem[x4], 16);
182 break;
183 case 3:
184 ldp(x14, x15, mem[x4], 16);
185 ldr(x20, mem[x4], 8);
186 break;
187 case 4:
188 ldp(x14, x15, mem[x4], 16);
189 ldp(x20, x21, mem[x4], 16);
190 break;
191 case 5:
192 ldp(x14, x15, mem[x4], 16);
193 ldp(x20, x21, mem[x4], 16);
194 ldr(x22, mem[x4], 8);
195 break;
196 case 6:
197 ldp(x14, x15, mem[x4], 16);
198 ldp(x20, x21, mem[x4], 16);
199 ldp(x22, x23, mem[x4], 16);
200 break;
201 }
202
203 cmp(x14, x12); // if a0 == zero
204 add(x14, x14, x11); // a0 += a_offset
205 csel(x14, x12, x14, kEQ); // a0 = zero, else += a0 + a_offset
206 if (max_mr > 1) {
207 cmp(x15, x12); // if a1 == zero
208 add(x15, x15, x11); // a1 += a_offset
209 csel(x15, x12, x15, kEQ); // a1 = zero, else += a1 + a_offset
210 }
211 if (max_mr > 2) {
212 cmp(x20, x12); // if a2 == zero
213 add(x20, x20, x11); // a2 += a_offset
214 csel(x20, x12, x20, kEQ); // a2 = zero, else += a2 + a_offset
215 }
216 if (max_mr > 3) {
217 cmp(x21, x12); // if a3 == zero
218 add(x21, x21, x11); // a3 += a_offset
219 csel(x21, x12, x21, kEQ); // a3 = zero, else += a3 + a_offset
220 }
221 if (max_mr > 4) {
222 cmp(x22, x12); // if a4 == zero
223 add(x22, x22, x11); // a4 += a_offset
224 csel(x22, x12, x22, kEQ); // a4 = zero, else += a4 + a_offset
225 }
226 if (max_mr > 5) {
227 cmp(x23, x12); // if a5 == zero
228 add(x23, x23, x11); // a5 += a_offset
229 csel(x23, x12, x23, kEQ); // a5 = zero, else += a5 + a_offset
230 }
231
232 // Is there at least 8 floats (32 bytes) for prologue + epilogue?
233 subs(x0, x2, 32); // k = kc - 32
234 b_lo(l5);
235
236 // Prologue - loads for main loop of 96 FMA
237 ldr(q0, mem[x14], 16);
238 ldp(q12, q13, mem[x5], 32); // Fetch 3 B (4th deferred)
239 if (max_mr > 1) {
240 ldr(q1, mem[x15], 16);
241 }
242 if (max_mr > 2) {
243 ldr(q2, mem[x20], 16);
244 }
245 if (max_mr > 3) {
246 ldr(q3, mem[x21], 16);
247 }
248 if (max_mr > 4) {
249 ldr(q4, mem[x22], 16);
250 }
251 if (max_mr > 5) {
252 ldr(q5, mem[x23], 16);
253 }
254 ldp(q14, q15, mem[x5], 32);
255 ldp(q16, q17, mem[x5], 32);
256
257 // Is there at least 8 floats (32 bytes) for main loop?
258 subs(x0, x0, 32);
259 b_lo(l3);
260 // Main loop - 8 floats of A (32 bytes)
261 // 96 FMA + 6 LDP A + 8 LDP B
262 bind(l2);
263 // First group of 4 A. 48 FMA.
264 fmla(v20.v4s(), v12.v4s(), v0.s()[0]);
265 ldp(q18, q19, mem[x5], 32); // Load last B
266 if (max_mr > 1) {
267 fmla(v22.v4s(), v12.v4s(), v1.s()[0]);
268 }
269 if (max_mr > 2) {
270 fmla(v24.v4s(), v12.v4s(), v2.s()[0]);
271 }
272 if (max_mr > 3) {
273 fmla(v26.v4s(), v12.v4s(), v3.s()[0]);
274 }
275 if (max_mr > 4) {
276 fmla(v28.v4s(), v12.v4s(), v4.s()[0]);
277 }
278 if (max_mr > 5) {
279 fmla(v30.v4s(), v12.v4s(), v5.s()[0]);
280 }
281 if (prefetch) {
282 prfm(kPLDL1KEEP, mem[x5, 256]); // Prefetch B
283 }
284 fmla(v21.v4s(), v13.v4s(), v0.s()[0]);
285 if (max_mr > 1) {
286 fmla(v23.v4s(), v13.v4s(), v1.s()[0]);
287 }
288 if (max_mr > 2) {
289 fmla(v25.v4s(), v13.v4s(), v2.s()[0]);
290 }
291 if (prefetch) {
292 prfm(kPLDL1KEEP, mem[x5, 320]);
293 }
294 if (max_mr > 3) {
295 fmla(v27.v4s(), v13.v4s(), v3.s()[0]);
296 }
297 if (max_mr > 4) {
298 fmla(v29.v4s(), v13.v4s(), v4.s()[0]);
299 }
300 if (max_mr > 5) {
301 fmla(v31.v4s(), v13.v4s(), v5.s()[0]);
302 }
303 if (prefetch) {
304 prfm(kPLDL1KEEP, mem[x5, 384]);
305 }
306 fmla(v20.v4s(), v14.v4s(), v0.s()[1]);
307 if (max_mr > 1) {
308 fmla(v22.v4s(), v14.v4s(), v1.s()[1]);
309 }
310 if (max_mr > 2) {
311 fmla(v24.v4s(), v14.v4s(), v2.s()[1]);
312 }
313 if (prefetch) {
314 prfm(kPLDL1KEEP, mem[x5, 448]);
315 }
316 if (max_mr > 3) {
317 fmla(v26.v4s(), v14.v4s(), v3.s()[1]);
318 }
319 if (max_mr > 4) {
320 fmla(v28.v4s(), v14.v4s(), v4.s()[1]);
321 }
322 if (max_mr > 5) {
323 fmla(v30.v4s(), v14.v4s(), v5.s()[1]);
324 }
325 fmla(v21.v4s(), v15.v4s(), v0.s()[1]);
326 if (max_mr > 1) {
327 fmla(v23.v4s(), v15.v4s(), v1.s()[1]);
328 }
329 if (max_mr > 2) {
330 fmla(v25.v4s(), v15.v4s(), v2.s()[1]);
331 }
332 ldr(q6, mem[x14], 16); // Load next 6 A
333 if (max_mr > 3) {
334 fmla(v27.v4s(), v15.v4s(), v3.s()[1]);
335 }
336 if (max_mr > 4) {
337 fmla(v29.v4s(), v15.v4s(), v4.s()[1]);
338 }
339 if (max_mr > 5) {
340 fmla(v31.v4s(), v15.v4s(), v5.s()[1]);
341 }
342 if (max_mr > 1) {
343 ldr(q7, mem[x15], 16);
344 }
345
346 fmla(v20.v4s(), v16.v4s(), v0.s()[2]);
347 if (max_mr > 1) {
348 fmla(v22.v4s(), v16.v4s(), v1.s()[2]);
349 }
350 if (max_mr > 2) {
351 fmla(v24.v4s(), v16.v4s(), v2.s()[2]);
352 }
353 if (max_mr > 2) {
354 ldr(q8, mem[x20], 16);
355 }
356 if (max_mr > 3) {
357 fmla(v26.v4s(), v16.v4s(), v3.s()[2]);
358 }
359 if (max_mr > 4) {
360 fmla(v28.v4s(), v16.v4s(), v4.s()[2]);
361 }
362 if (max_mr > 5) {
363 fmla(v30.v4s(), v16.v4s(), v5.s()[2]);
364 }
365 if (max_mr > 3) {
366 ldr(q9, mem[x21], 16);
367 }
368 fmla(v21.v4s(), v17.v4s(), v0.s()[2]);
369 if (max_mr > 1) {
370 fmla(v23.v4s(), v17.v4s(), v1.s()[2]);
371 }
372 if (max_mr > 2) {
373 fmla(v25.v4s(), v17.v4s(), v2.s()[2]);
374 }
375 if (max_mr > 4) {
376 ldr(q10, mem[x22], 16);
377 }
378 if (max_mr > 3) {
379 fmla(v27.v4s(), v17.v4s(), v3.s()[2]);
380 }
381 if (max_mr > 4) {
382 fmla(v29.v4s(), v17.v4s(), v4.s()[2]);
383 }
384 if (max_mr > 5) {
385 fmla(v31.v4s(), v17.v4s(), v5.s()[2]);
386 ldr(q11, mem[x23], 16);
387 }
388
389 fmla(v20.v4s(), v18.v4s(), v0.s()[3]);
390 if (max_mr > 1) {
391 fmla(v22.v4s(), v18.v4s(), v1.s()[3]);
392 }
393 if (max_mr > 2) {
394 fmla(v24.v4s(), v18.v4s(), v2.s()[3]);
395 }
396 ldp(q12, q13, mem[x5], 32); // Load 4 B
397 if (max_mr > 3) {
398 fmla(v26.v4s(), v18.v4s(), v3.s()[3]);
399 }
400 if (max_mr > 4) {
401 fmla(v28.v4s(), v18.v4s(), v4.s()[3]);
402 }
403 if (max_mr > 5) {
404 fmla(v30.v4s(), v18.v4s(), v5.s()[3]);
405 }
406 ldp(q14, q15, mem[x5], 32);
407 fmla(v21.v4s(), v19.v4s(), v0.s()[3]);
408 if (max_mr > 1) {
409 fmla(v23.v4s(), v19.v4s(), v1.s()[3]);
410 }
411 if (max_mr > 2) {
412 fmla(v25.v4s(), v19.v4s(), v2.s()[3]);
413 }
414 ldp(q16, q17, mem[x5], 32);
415 if (max_mr > 3) {
416 fmla(v27.v4s(), v19.v4s(), v3.s()[3]);
417 }
418 if (max_mr > 4) {
419 fmla(v29.v4s(), v19.v4s(), v4.s()[3]);
420 }
421 if (max_mr > 5) {
422 fmla(v31.v4s(), v19.v4s(), v5.s()[3]);
423 }
424 ldp(q18, q19, mem[x5], 32);
425
426 // Second group of 4 A. 48 FMA.
427 fmla(v20.v4s(), v12.v4s(), v6.s()[0]);
428 if (max_mr > 1) {
429 fmla(v22.v4s(), v12.v4s(), v7.s()[0]);
430 }
431 if (max_mr > 2) {
432 fmla(v24.v4s(), v12.v4s(), v8.s()[0]);
433 }
434 ldr(q0, mem[x14], 16); // Load next 6 A
435 if (max_mr > 3) {
436 fmla(v26.v4s(), v12.v4s(), v9.s()[0]);
437 }
438 if (max_mr > 4) {
439 fmla(v28.v4s(), v12.v4s(), v10.s()[0]);
440 }
441 if (max_mr > 5) {
442 fmla(v30.v4s(), v12.v4s(), v11.s()[0]);
443 }
444 if (max_mr > 1) {
445 ldr(q1, mem[x15], 16);
446 }
447 fmla(v21.v4s(), v13.v4s(), v6.s()[0]);
448 if (max_mr > 1) {
449 fmla(v23.v4s(), v13.v4s(), v7.s()[0]);
450 }
451 if (max_mr > 2) {
452 fmla(v25.v4s(), v13.v4s(), v8.s()[0]);
453 }
454 if (max_mr > 2) {
455 ldr(q2, mem[x20], 16);
456 }
457 if (max_mr > 3) {
458 fmla(v27.v4s(), v13.v4s(), v9.s()[0]);
459 }
460 if (max_mr > 4) {
461 fmla(v29.v4s(), v13.v4s(), v10.s()[0]);
462 }
463 if (max_mr > 5) {
464 fmla(v31.v4s(), v13.v4s(), v11.s()[0]);
465 }
466 if (max_mr > 3) {
467 ldr(q3, mem[x21], 16);
468 }
469
470 fmla(v20.v4s(), v14.v4s(), v6.s()[1]);
471 if (max_mr > 1) {
472 fmla(v22.v4s(), v14.v4s(), v7.s()[1]);
473 }
474 if (max_mr > 2) {
475 fmla(v24.v4s(), v14.v4s(), v8.s()[1]);
476 }
477 if (max_mr > 4) {
478 ldr(q4, mem[x22], 16);
479 }
480 if (max_mr > 3) {
481 fmla(v26.v4s(), v14.v4s(), v9.s()[1]);
482 }
483 if (max_mr > 4) {
484 fmla(v28.v4s(), v14.v4s(), v10.s()[1]);
485 }
486 if (max_mr > 5) {
487 fmla(v30.v4s(), v14.v4s(), v11.s()[1]);
488 }
489 if (max_mr > 5) {
490 ldr(q5, mem[x23], 16);
491 }
492 fmla(v21.v4s(), v15.v4s(), v6.s()[1]);
493 if (max_mr > 1) {
494 fmla(v23.v4s(), v15.v4s(), v7.s()[1]);
495 }
496 if (max_mr > 2) {
497 fmla(v25.v4s(), v15.v4s(), v8.s()[1]);
498 }
499 ldp(q12, q13, mem[x5], 32); // Load next 3 B (not last)
500 if (max_mr > 3) {
501 fmla(v27.v4s(), v15.v4s(), v9.s()[1]);
502 }
503 if (max_mr > 4) {
504 fmla(v29.v4s(), v15.v4s(), v10.s()[1]);
505 }
506 if (max_mr > 5) {
507 fmla(v31.v4s(), v15.v4s(), v11.s()[1]);
508 }
509 ldp(q14, q15, mem[x5], 32);
510
511 fmla(v20.v4s(), v16.v4s(), v6.s()[2]);
512 if (max_mr > 1) {
513 fmla(v22.v4s(), v16.v4s(), v7.s()[2]);
514 }
515 if (max_mr > 2) {
516 fmla(v24.v4s(), v16.v4s(), v8.s()[2]);
517 }
518 if (max_mr > 3) {
519 fmla(v26.v4s(), v16.v4s(), v9.s()[2]);
520 }
521 if (max_mr > 4) {
522 fmla(v28.v4s(), v16.v4s(), v10.s()[2]);
523 }
524 if (max_mr > 5) {
525 fmla(v30.v4s(), v16.v4s(), v11.s()[2]);
526 }
527 fmla(v21.v4s(), v17.v4s(), v6.s()[2]);
528 if (max_mr > 1) {
529 fmla(v23.v4s(), v17.v4s(), v7.s()[2]);
530 }
531 if (max_mr > 2) {
532 fmla(v25.v4s(), v17.v4s(), v8.s()[2]);
533 }
534 if (max_mr > 3) {
535 fmla(v27.v4s(), v17.v4s(), v9.s()[2]);
536 }
537 if (max_mr > 4) {
538 fmla(v29.v4s(), v17.v4s(), v10.s()[2]);
539 }
540 if (max_mr > 5) {
541 fmla(v31.v4s(), v17.v4s(), v11.s()[2]);
542 }
543 ldp(q16, q17, mem[x5], 32);
544
545 fmla(v20.v4s(), v18.v4s(), v6.s()[3]);
546 if (max_mr > 1) {
547 fmla(v22.v4s(), v18.v4s(), v7.s()[3]);
548 }
549 subs(x0, x0, 32);
550 if (max_mr > 2) {
551 fmla(v24.v4s(), v18.v4s(), v8.s()[3]);
552 }
553 if (max_mr > 3) {
554 fmla(v26.v4s(), v18.v4s(), v9.s()[3]);
555 }
556 if (max_mr > 4) {
557 fmla(v28.v4s(), v18.v4s(), v10.s()[3]);
558 }
559 if (max_mr > 5) {
560 fmla(v30.v4s(), v18.v4s(), v11.s()[3]);
561 }
562 fmla(v21.v4s(), v19.v4s(), v6.s()[3]);
563 if (max_mr > 1) {
564 fmla(v23.v4s(), v19.v4s(), v7.s()[3]);
565 }
566 if (max_mr > 2) {
567 fmla(v25.v4s(), v19.v4s(), v8.s()[3]);
568 }
569 if (max_mr > 3) {
570 fmla(v27.v4s(), v19.v4s(), v9.s()[3]);
571 }
572 if (max_mr > 4) {
573 fmla(v29.v4s(), v19.v4s(), v10.s()[3]);
574 }
575 if (max_mr > 5) {
576 fmla(v31.v4s(), v19.v4s(), v11.s()[3]);
577 }
578 b_hs(l2);
579
580 // Epilogue - 8 floats of A (32 bytes)
581 // 96 FMA + 6 LDP A + 8 LDP B
582 // First block same as main loop. Second block has no preloads.
583 bind(l3);
584 // First group of 4 A. 48 FMA.
585 fmla(v20.v4s(), v12.v4s(), v0.s()[0]);
586 ldp(q18, q19, mem[x5], 32); // Load last B
587 if (max_mr > 1) {
588 fmla(v22.v4s(), v12.v4s(), v1.s()[0]);
589 }
590 if (max_mr > 2) {
591 fmla(v24.v4s(), v12.v4s(), v2.s()[0]);
592 }
593 if (max_mr > 3) {
594 fmla(v26.v4s(), v12.v4s(), v3.s()[0]);
595 }
596 if (max_mr > 4) {
597 fmla(v28.v4s(), v12.v4s(), v4.s()[0]);
598 }
599 if (max_mr > 5) {
600 fmla(v30.v4s(), v12.v4s(), v5.s()[0]);
601 }
602 fmla(v21.v4s(), v13.v4s(), v0.s()[0]);
603 if (max_mr > 1) {
604 fmla(v23.v4s(), v13.v4s(), v1.s()[0]);
605 }
606 if (max_mr > 2) {
607 fmla(v25.v4s(), v13.v4s(), v2.s()[0]);
608 }
609 if (max_mr > 3) {
610 fmla(v27.v4s(), v13.v4s(), v3.s()[0]);
611 }
612 if (max_mr > 4) {
613 fmla(v29.v4s(), v13.v4s(), v4.s()[0]);
614 }
615 if (max_mr > 5) {
616 fmla(v31.v4s(), v13.v4s(), v5.s()[0]);
617 }
618 fmla(v20.v4s(), v14.v4s(), v0.s()[1]);
619 if (prefetch) {
620 prfm(kPLDL1KEEP, mem[x5, 128]); // Prefetch B
621 }
622 if (max_mr > 1) {
623 fmla(v22.v4s(), v14.v4s(), v1.s()[1]);
624 }
625 if (max_mr > 2) {
626 fmla(v24.v4s(), v14.v4s(), v2.s()[1]);
627 }
628 if (max_mr > 3) {
629 fmla(v26.v4s(), v14.v4s(), v3.s()[1]);
630 }
631 if (max_mr > 4) {
632 fmla(v28.v4s(), v14.v4s(), v4.s()[1]);
633 }
634 if (prefetch) {
635 prfm(kPLDL1KEEP, mem[x5, 256]);
636 }
637 if (max_mr > 5) {
638 fmla(v30.v4s(), v14.v4s(), v5.s()[1]);
639 }
640 fmla(v21.v4s(), v15.v4s(), v0.s()[1]);
641 if (max_mr > 1) {
642 fmla(v23.v4s(), v15.v4s(), v1.s()[1]);
643 }
644 if (max_mr > 2) {
645 fmla(v25.v4s(), v15.v4s(), v2.s()[1]);
646 }
647 ldr(q6, mem[x14], 16); // Load next 6 A
648 if (max_mr > 3) {
649 fmla(v27.v4s(), v15.v4s(), v3.s()[1]);
650 }
651 if (max_mr > 4) {
652 fmla(v29.v4s(), v15.v4s(), v4.s()[1]);
653 }
654 if (max_mr > 5) {
655 fmla(v31.v4s(), v15.v4s(), v5.s()[1]);
656 }
657 if (max_mr > 1) {
658 ldr(q7, mem[x15], 16);
659 }
660
661 fmla(v20.v4s(), v16.v4s(), v0.s()[2]);
662 if (max_mr > 1) {
663 fmla(v22.v4s(), v16.v4s(), v1.s()[2]);
664 }
665 if (max_mr > 2) {
666 fmla(v24.v4s(), v16.v4s(), v2.s()[2]);
667 }
668 if (max_mr > 2) {
669 ldr(q8, mem[x20], 16);
670 }
671 if (max_mr > 3) {
672 fmla(v26.v4s(), v16.v4s(), v3.s()[2]);
673 }
674 if (max_mr > 4) {
675 fmla(v28.v4s(), v16.v4s(), v4.s()[2]);
676 }
677 if (max_mr > 5) {
678 fmla(v30.v4s(), v16.v4s(), v5.s()[2]);
679 }
680 if (max_mr > 3) {
681 ldr(q9, mem[x21], 16);
682 }
683 fmla(v21.v4s(), v17.v4s(), v0.s()[2]);
684 if (max_mr > 1) {
685 fmla(v23.v4s(), v17.v4s(), v1.s()[2]);
686 }
687 if (max_mr > 2) {
688 fmla(v25.v4s(), v17.v4s(), v2.s()[2]);
689 }
690 if (max_mr > 4) {
691 ldr(q10, mem[x22], 16);
692 }
693 if (max_mr > 3) {
694 fmla(v27.v4s(), v17.v4s(), v3.s()[2]);
695 }
696 if (max_mr > 4) {
697 fmla(v29.v4s(), v17.v4s(), v4.s()[2]);
698 }
699 if (max_mr > 5) {
700 fmla(v31.v4s(), v17.v4s(), v5.s()[2]);
701 }
702 if (max_mr > 5) {
703 ldr(q11, mem[x23], 16);
704 }
705
706 fmla(v20.v4s(), v18.v4s(), v0.s()[3]);
707 if (max_mr > 1) {
708 fmla(v22.v4s(), v18.v4s(), v1.s()[3]);
709 }
710 if (max_mr > 2) {
711 fmla(v24.v4s(), v18.v4s(), v2.s()[3]);
712 }
713 ldp(q12, q13, mem[x5], 32); // Load 4 B
714 if (max_mr > 3) {
715 fmla(v26.v4s(), v18.v4s(), v3.s()[3]);
716 }
717 if (max_mr > 4) {
718 fmla(v28.v4s(), v18.v4s(), v4.s()[3]);
719 }
720 if (max_mr > 5) {
721 fmla(v30.v4s(), v18.v4s(), v5.s()[3]);
722 }
723 ldp(q14, q15, mem[x5], 32);
724 fmla(v21.v4s(), v19.v4s(), v0.s()[3]);
725 if (max_mr > 1) {
726 fmla(v23.v4s(), v19.v4s(), v1.s()[3]);
727 }
728 if (max_mr > 2) {
729 fmla(v25.v4s(), v19.v4s(), v2.s()[3]);
730 }
731 ldp(q16, q17, mem[x5], 32);
732 if (max_mr > 3) {
733 fmla(v27.v4s(), v19.v4s(), v3.s()[3]);
734 }
735 if (max_mr > 4) {
736 fmla(v29.v4s(), v19.v4s(), v4.s()[3]);
737 }
738 if (max_mr > 5) {
739 fmla(v31.v4s(), v19.v4s(), v5.s()[3]);
740 }
741 ldp(q18, q19, mem[x5], 32);
742
743 // Second group of 4 A. 48 FMA.
744 fmla(v20.v4s(), v12.v4s(), v6.s()[0]);
745 if (max_mr > 1) {
746 fmla(v22.v4s(), v12.v4s(), v7.s()[0]);
747 }
748 if (max_mr > 2) {
749 fmla(v24.v4s(), v12.v4s(), v8.s()[0]);
750 }
751 if (max_mr > 3) {
752 fmla(v26.v4s(), v12.v4s(), v9.s()[0]);
753 }
754 if (max_mr > 4) {
755 fmla(v28.v4s(), v12.v4s(), v10.s()[0]);
756 }
757 if (max_mr > 5) {
758 fmla(v30.v4s(), v12.v4s(), v11.s()[0]);
759 }
760 fmla(v21.v4s(), v13.v4s(), v6.s()[0]);
761 if (max_mr > 1) {
762 fmla(v23.v4s(), v13.v4s(), v7.s()[0]);
763 }
764 if (max_mr > 2) {
765 fmla(v25.v4s(), v13.v4s(), v8.s()[0]);
766 }
767 if (max_mr > 3) {
768 fmla(v27.v4s(), v13.v4s(), v9.s()[0]);
769 }
770 if (max_mr > 4) {
771 fmla(v29.v4s(), v13.v4s(), v10.s()[0]);
772 }
773 if (max_mr > 5) {
774 fmla(v31.v4s(), v13.v4s(), v11.s()[0]);
775 }
776
777 fmla(v20.v4s(), v14.v4s(), v6.s()[1]);
778 if (max_mr > 1) {
779 fmla(v22.v4s(), v14.v4s(), v7.s()[1]);
780 }
781 if (max_mr > 2) {
782 fmla(v24.v4s(), v14.v4s(), v8.s()[1]);
783 }
784 if (max_mr > 3) {
785 fmla(v26.v4s(), v14.v4s(), v9.s()[1]);
786 }
787 if (max_mr > 4) {
788 fmla(v28.v4s(), v14.v4s(), v10.s()[1]);
789 }
790 if (max_mr > 5) {
791 fmla(v30.v4s(), v14.v4s(), v11.s()[1]);
792 }
793 fmla(v21.v4s(), v15.v4s(), v6.s()[1]);
794 if (max_mr > 1) {
795 fmla(v23.v4s(), v15.v4s(), v7.s()[1]);
796 }
797 if (max_mr > 2) {
798 fmla(v25.v4s(), v15.v4s(), v8.s()[1]);
799 }
800 if (max_mr > 3) {
801 fmla(v27.v4s(), v15.v4s(), v9.s()[1]);
802 }
803 if (max_mr > 4) {
804 fmla(v29.v4s(), v15.v4s(), v10.s()[1]);
805 }
806 if (max_mr > 5) {
807 fmla(v31.v4s(), v15.v4s(), v11.s()[1]);
808 }
809
810 fmla(v20.v4s(), v16.v4s(), v6.s()[2]);
811 if (max_mr > 1) {
812 fmla(v22.v4s(), v16.v4s(), v7.s()[2]);
813 }
814 if (max_mr > 2) {
815 fmla(v24.v4s(), v16.v4s(), v8.s()[2]);
816 }
817 if (max_mr > 3) {
818 fmla(v26.v4s(), v16.v4s(), v9.s()[2]);
819 }
820 if (max_mr > 4) {
821 fmla(v28.v4s(), v16.v4s(), v10.s()[2]);
822 }
823 if (max_mr > 5) {
824 fmla(v30.v4s(), v16.v4s(), v11.s()[2]);
825 }
826 fmla(v21.v4s(), v17.v4s(), v6.s()[2]);
827 if (max_mr > 1) {
828 fmla(v23.v4s(), v17.v4s(), v7.s()[2]);
829 }
830 if (max_mr > 2) {
831 fmla(v25.v4s(), v17.v4s(), v8.s()[2]);
832 }
833 if (max_mr > 3) {
834 fmla(v27.v4s(), v17.v4s(), v9.s()[2]);
835 }
836 if (max_mr > 4) {
837 fmla(v29.v4s(), v17.v4s(), v10.s()[2]);
838 }
839 if (max_mr > 5) {
840 fmla(v31.v4s(), v17.v4s(), v11.s()[2]);
841 }
842
843 fmla(v20.v4s(), v18.v4s(), v6.s()[3]);
844 if (max_mr > 1) {
845 fmla(v22.v4s(), v18.v4s(), v7.s()[3]);
846 }
847 if (max_mr > 2) {
848 fmla(v24.v4s(), v18.v4s(), v8.s()[3]);
849 }
850 if (max_mr > 3) {
851 fmla(v26.v4s(), v18.v4s(), v9.s()[3]);
852 }
853 if (max_mr > 4) {
854 fmla(v28.v4s(), v18.v4s(), v10.s()[3]);
855 }
856 if (max_mr > 5) {
857 fmla(v30.v4s(), v18.v4s(), v11.s()[3]);
858 }
859 // Is there a remainder?- 4 floats of A (16 bytes) or less
860 tst(x0, 31);
861 fmla(v21.v4s(), v19.v4s(), v6.s()[3]);
862 if (max_mr > 1) {
863 fmla(v23.v4s(), v19.v4s(), v7.s()[3]);
864 }
865 if (max_mr > 2) {
866 fmla(v25.v4s(), v19.v4s(), v8.s()[3]);
867 }
868 // Load min/max values
869 if (clamp_min || clamp_max) {
870 ld2r({v6.v4s(), v7.v4s()}, mem[x8]);
871 }
872 if (max_mr > 3) {
873 fmla(v27.v4s(), v19.v4s(), v9.s()[3]);
874 }
875 if (max_mr > 4) {
876 fmla(v29.v4s(), v19.v4s(), v10.s()[3]);
877 }
878 if (max_mr > 5) {
879 fmla(v31.v4s(), v19.v4s(), v11.s()[3]);
880 }
881 b_ne(l5);
882
883 bind(l4);
884 // ks loop
885 subs(x9, x9, max_mr * 8); // ks -= MR * sizeof(void*)
886 b_hi(l1);
887
888 // Load cn_stride
889 ldr(x0, mem[sp, 96]);
890 subs(x1, x1, 8);
891
892 // Clamp
893 if (clamp_min) {
894 fmax(v20.v4s(), v20.v4s(), v6.v4s());
895 fmax(v21.v4s(), v21.v4s(), v6.v4s());
896 if (max_mr > 1) {
897 fmax(v22.v4s(), v22.v4s(), v6.v4s());
898 fmax(v23.v4s(), v23.v4s(), v6.v4s());
899 }
900 if (max_mr > 2) {
901 fmax(v24.v4s(), v24.v4s(), v6.v4s());
902 fmax(v25.v4s(), v25.v4s(), v6.v4s());
903 }
904 if (max_mr > 3) {
905 fmax(v26.v4s(), v26.v4s(), v6.v4s());
906 fmax(v27.v4s(), v27.v4s(), v6.v4s());
907 }
908 if (max_mr > 4) {
909 fmax(v28.v4s(), v28.v4s(), v6.v4s());
910 fmax(v29.v4s(), v29.v4s(), v6.v4s());
911 }
912 if (max_mr > 5) {
913 fmax(v30.v4s(), v30.v4s(), v6.v4s());
914 fmax(v31.v4s(), v31.v4s(), v6.v4s());
915 }
916 }
917 if (clamp_max) {
918 fmin(v20.v4s(), v20.v4s(), v7.v4s());
919 fmin(v21.v4s(), v21.v4s(), v7.v4s());
920 if (max_mr > 1) {
921 fmin(v22.v4s(), v22.v4s(), v7.v4s());
922 fmin(v23.v4s(), v23.v4s(), v7.v4s());
923 }
924 if (max_mr > 2) {
925 fmin(v24.v4s(), v24.v4s(), v7.v4s());
926 fmin(v25.v4s(), v25.v4s(), v7.v4s());
927 }
928 if (max_mr > 3) {
929 fmin(v26.v4s(), v26.v4s(), v7.v4s());
930 fmin(v27.v4s(), v27.v4s(), v7.v4s());
931 }
932 if (max_mr > 4) {
933 fmin(v28.v4s(), v28.v4s(), v7.v4s());
934 fmin(v29.v4s(), v29.v4s(), v7.v4s());
935 }
936 if (max_mr > 5) {
937 fmin(v30.v4s(), v30.v4s(), v7.v4s());
938 fmin(v31.v4s(), v31.v4s(), v7.v4s());
939 }
940 }
941
942 // Store full 6 x 8
943 b_lo(l8);
944
945 if (max_mr > 5) {
946 stp(q30, q31, mem[x7]);
947 add(x7, x7, x0);
948 }
949 if (max_mr > 4) {
950 stp(q28, q29, mem[x13]);
951 add(x13, x13, x0);
952 }
953 if (max_mr > 3) {
954 stp(q26, q27, mem[x10]);
955 add(x10, x10, x0);
956 }
957 if (max_mr > 2) {
958 stp(q24, q25, mem[x17]);
959 add(x17, x17, x0);
960 }
961 if (max_mr > 1) {
962 stp(q22, q23, mem[x16]);
963 add(x16, x16, x0);
964 }
965 stp(q20, q21, mem[x6]);
966 add(x6, x6, x0);
967
968 sub(x4, x4, x3); // a -= ks
969
970 // nc loop
971 b_hi(l0);
972
973 // Restore x20,x21,x22,x23 from stack
974 if (max_mr > 4) {
975 ldp(x22, x23, mem[sp, 80]);
976 }
977 ldp(x20, x21, mem[sp, 64]);
978
979 // Restore d8-d15 from stack
980 ldp(d14, d15, mem[sp, 48]);
981 ldp(d12, d13, mem[sp, 32]);
982 ldp(d10, d11, mem[sp, 16]);
983 ldp(d8, d9, mem[sp], 96);
984 ret();
985
986 bind(l5);
987 // Load min/max values
988 if (clamp_min || clamp_max) {
989 ld2r({v6.v4s(), v7.v4s()}, mem[x8]);
990 }
991
992 // Is there a remainder?- 4 floats of A (16 bytes)
993 tbz(x0, 4, l6);
994
995 // Remainder- 4 floats of A (16 bytes)
996 // Load A
997 ldr(q0, mem[x14], 16);
998 if (max_mr > 1) {
999 ldr(q1, mem[x15], 16);
1000 }
1001 if (max_mr > 2) {
1002 ldr(q2, mem[x20], 16);
1003 }
1004 if (max_mr > 3) {
1005 ldr(q3, mem[x21], 16);
1006 }
1007 if (max_mr > 4) {
1008 ldr(q4, mem[x22], 16);
1009 }
1010 if (max_mr > 5) {
1011 ldr(q5, mem[x23], 16);
1012 }
1013 // Load B
1014 ldp(q12, q13, mem[x5], 32);
1015 ldp(q14, q15, mem[x5], 32);
1016 ldp(q16, q17, mem[x5], 32);
1017 ldp(q18, q19, mem[x5], 32);
1018
1019 fmla(v20.v4s(), v12.v4s(), v0.s()[0]);
1020 if (max_mr > 1) {
1021 fmla(v22.v4s(), v12.v4s(), v1.s()[0]);
1022 }
1023 if (max_mr > 2) {
1024 fmla(v24.v4s(), v12.v4s(), v2.s()[0]);
1025 }
1026 if (max_mr > 3) {
1027 fmla(v26.v4s(), v12.v4s(), v3.s()[0]);
1028 }
1029 if (max_mr > 4) {
1030 fmla(v28.v4s(), v12.v4s(), v4.s()[0]);
1031 }
1032 if (max_mr > 5) {
1033 fmla(v30.v4s(), v12.v4s(), v5.s()[0]);
1034 }
1035 fmla(v21.v4s(), v13.v4s(), v0.s()[0]);
1036 if (max_mr > 1) {
1037 fmla(v23.v4s(), v13.v4s(), v1.s()[0]);
1038 }
1039 if (max_mr > 2) {
1040 fmla(v25.v4s(), v13.v4s(), v2.s()[0]);
1041 }
1042 if (max_mr > 3) {
1043 fmla(v27.v4s(), v13.v4s(), v3.s()[0]);
1044 }
1045 if (max_mr > 4) {
1046 fmla(v29.v4s(), v13.v4s(), v4.s()[0]);
1047 }
1048 if (max_mr > 5) {
1049 fmla(v31.v4s(), v13.v4s(), v5.s()[0]);
1050 }
1051
1052 fmla(v20.v4s(), v14.v4s(), v0.s()[1]);
1053 if (max_mr > 1) {
1054 fmla(v22.v4s(), v14.v4s(), v1.s()[1]);
1055 }
1056 if (max_mr > 2) {
1057 fmla(v24.v4s(), v14.v4s(), v2.s()[1]);
1058 }
1059 if (max_mr > 3) {
1060 fmla(v26.v4s(), v14.v4s(), v3.s()[1]);
1061 }
1062 if (max_mr > 4) {
1063 fmla(v28.v4s(), v14.v4s(), v4.s()[1]);
1064 }
1065 if (max_mr > 5) {
1066 fmla(v30.v4s(), v14.v4s(), v5.s()[1]);
1067 }
1068 fmla(v21.v4s(), v15.v4s(), v0.s()[1]);
1069 if (max_mr > 1) {
1070 fmla(v23.v4s(), v15.v4s(), v1.s()[1]);
1071 }
1072 if (max_mr > 2) {
1073 fmla(v25.v4s(), v15.v4s(), v2.s()[1]);
1074 }
1075 if (max_mr > 3) {
1076 fmla(v27.v4s(), v15.v4s(), v3.s()[1]);
1077 }
1078 if (max_mr > 4) {
1079 fmla(v29.v4s(), v15.v4s(), v4.s()[1]);
1080 }
1081 if (max_mr > 5) {
1082 fmla(v31.v4s(), v15.v4s(), v5.s()[1]);
1083 }
1084
1085 fmla(v20.v4s(), v16.v4s(), v0.s()[2]);
1086 if (max_mr > 1) {
1087 fmla(v22.v4s(), v16.v4s(), v1.s()[2]);
1088 }
1089 if (max_mr > 2) {
1090 fmla(v24.v4s(), v16.v4s(), v2.s()[2]);
1091 }
1092 if (max_mr > 3) {
1093 fmla(v26.v4s(), v16.v4s(), v3.s()[2]);
1094 }
1095 if (max_mr > 4) {
1096 fmla(v28.v4s(), v16.v4s(), v4.s()[2]);
1097 }
1098 if (max_mr > 5) {
1099 fmla(v30.v4s(), v16.v4s(), v5.s()[2]);
1100 }
1101 fmla(v21.v4s(), v17.v4s(), v0.s()[2]);
1102 if (max_mr > 1) {
1103 fmla(v23.v4s(), v17.v4s(), v1.s()[2]);
1104 }
1105 if (max_mr > 2) {
1106 fmla(v25.v4s(), v17.v4s(), v2.s()[2]);
1107 }
1108 if (max_mr > 3) {
1109 fmla(v27.v4s(), v17.v4s(), v3.s()[2]);
1110 }
1111 if (max_mr > 4) {
1112 fmla(v29.v4s(), v17.v4s(), v4.s()[2]);
1113 }
1114 if (max_mr > 5) {
1115 fmla(v31.v4s(), v17.v4s(), v5.s()[2]);
1116 }
1117
1118 fmla(v20.v4s(), v18.v4s(), v0.s()[3]);
1119 if (max_mr > 1) {
1120 fmla(v22.v4s(), v18.v4s(), v1.s()[3]);
1121 }
1122 if (max_mr > 2) {
1123 fmla(v24.v4s(), v18.v4s(), v2.s()[3]);
1124 }
1125 if (max_mr > 3) {
1126 fmla(v26.v4s(), v18.v4s(), v3.s()[3]);
1127 }
1128 if (max_mr > 4) {
1129 fmla(v28.v4s(), v18.v4s(), v4.s()[3]);
1130 }
1131 if (max_mr > 5) {
1132 fmla(v30.v4s(), v18.v4s(), v5.s()[3]);
1133 }
1134 fmla(v21.v4s(), v19.v4s(), v0.s()[3]);
1135 if (max_mr > 1) {
1136 fmla(v23.v4s(), v19.v4s(), v1.s()[3]);
1137 }
1138 if (max_mr > 2) {
1139 fmla(v25.v4s(), v19.v4s(), v2.s()[3]);
1140 }
1141 if (max_mr > 3) {
1142 fmla(v27.v4s(), v19.v4s(), v3.s()[3]);
1143 }
1144 if (max_mr > 4) {
1145 fmla(v29.v4s(), v19.v4s(), v4.s()[3]);
1146 }
1147 if (max_mr > 5) {
1148 fmla(v31.v4s(), v19.v4s(), v5.s()[3]);
1149 }
1150
1151 // Is there a remainder?- 2 floats of A (8 bytes)
1152 bind(l6);
1153 tbz(x0, 3, l7);
1154
1155 // Remainder- 2 floats of A (8 bytes)
1156 // Load A
1157 ldr(d0, mem[x14], 8);
1158 if (max_mr > 1) {
1159 ldr(d1, mem[x15], 8);
1160 }
1161 if (max_mr > 2) {
1162 ldr(d2, mem[x20], 8);
1163 }
1164 if (max_mr > 3) {
1165 ldr(d3, mem[x21], 8);
1166 }
1167 if (max_mr > 4) {
1168 ldr(d4, mem[x22], 8);
1169 }
1170 if (max_mr > 5) {
1171 ldr(d5, mem[x23], 8);
1172 }
1173 // Load B
1174 ldp(q12, q13, mem[x5], 32);
1175 ldp(q14, q15, mem[x5], 32);
1176
1177 fmla(v20.v4s(), v12.v4s(), v0.s()[0]);
1178 if (max_mr > 1) {
1179 fmla(v22.v4s(), v12.v4s(), v1.s()[0]);
1180 }
1181 if (max_mr > 2) {
1182 fmla(v24.v4s(), v12.v4s(), v2.s()[0]);
1183 }
1184 if (max_mr > 3) {
1185 fmla(v26.v4s(), v12.v4s(), v3.s()[0]);
1186 }
1187 if (max_mr > 4) {
1188 fmla(v28.v4s(), v12.v4s(), v4.s()[0]);
1189 }
1190 if (max_mr > 5) {
1191 fmla(v30.v4s(), v12.v4s(), v5.s()[0]);
1192 }
1193 fmla(v21.v4s(), v13.v4s(), v0.s()[0]);
1194 if (max_mr > 1) {
1195 fmla(v23.v4s(), v13.v4s(), v1.s()[0]);
1196 }
1197 if (max_mr > 2) {
1198 fmla(v25.v4s(), v13.v4s(), v2.s()[0]);
1199 }
1200 if (max_mr > 3) {
1201 fmla(v27.v4s(), v13.v4s(), v3.s()[0]);
1202 }
1203 if (max_mr > 4) {
1204 fmla(v29.v4s(), v13.v4s(), v4.s()[0]);
1205 }
1206 if (max_mr > 5) {
1207 fmla(v31.v4s(), v13.v4s(), v5.s()[0]);
1208 }
1209
1210 fmla(v20.v4s(), v14.v4s(), v0.s()[1]);
1211 if (max_mr > 1) {
1212 fmla(v22.v4s(), v14.v4s(), v1.s()[1]);
1213 }
1214 if (max_mr > 2) {
1215 fmla(v24.v4s(), v14.v4s(), v2.s()[1]);
1216 }
1217 if (max_mr > 3) {
1218 fmla(v26.v4s(), v14.v4s(), v3.s()[1]);
1219 }
1220 if (max_mr > 4) {
1221 fmla(v28.v4s(), v14.v4s(), v4.s()[1]);
1222 }
1223 if (max_mr > 5) {
1224 fmla(v30.v4s(), v14.v4s(), v5.s()[1]);
1225 }
1226 fmla(v21.v4s(), v15.v4s(), v0.s()[1]);
1227 if (max_mr > 1) {
1228 fmla(v23.v4s(), v15.v4s(), v1.s()[1]);
1229 }
1230 if (max_mr > 2) {
1231 fmla(v25.v4s(), v15.v4s(), v2.s()[1]);
1232 }
1233 if (max_mr > 3) {
1234 fmla(v27.v4s(), v15.v4s(), v3.s()[1]);
1235 }
1236 if (max_mr > 4) {
1237 fmla(v29.v4s(), v15.v4s(), v4.s()[1]);
1238 }
1239 if (max_mr > 5) {
1240 fmla(v31.v4s(), v15.v4s(), v5.s()[1]);
1241 }
1242
1243 // Is there a remainder?- 1 float of A (4 bytes)
1244 bind(l7);
1245 tbz(x0, 2, l4);
1246
1247 // Remainder- 1 float of A (4 bytes)
1248 // Load A
1249 ldr(s0, mem[x14], 4);
1250 if (max_mr > 1) {
1251 ldr(s1, mem[x15], 4);
1252 }
1253 if (max_mr > 2) {
1254 ldr(s2, mem[x20], 4);
1255 }
1256 if (max_mr > 3) {
1257 ldr(s3, mem[x21], 4);
1258 }
1259 if (max_mr > 4) {
1260 ldr(s4, mem[x22], 4);
1261 }
1262 if (max_mr > 5) {
1263 ldr(s5, mem[x23], 4);
1264 }
1265 // Load B
1266 ldp(q12, q13, mem[x5], 32);
1267
1268 fmla(v20.v4s(), v12.v4s(), v0.s()[0]);
1269 if (max_mr > 1) {
1270 fmla(v22.v4s(), v12.v4s(), v1.s()[0]);
1271 }
1272 if (max_mr > 2) {
1273 fmla(v24.v4s(), v12.v4s(), v2.s()[0]);
1274 }
1275 if (max_mr > 3) {
1276 fmla(v26.v4s(), v12.v4s(), v3.s()[0]);
1277 }
1278 if (max_mr > 4) {
1279 fmla(v28.v4s(), v12.v4s(), v4.s()[0]);
1280 }
1281 if (max_mr > 5) {
1282 fmla(v30.v4s(), v12.v4s(), v5.s()[0]);
1283 }
1284 fmla(v21.v4s(), v13.v4s(), v0.s()[0]);
1285 if (max_mr > 1) {
1286 fmla(v23.v4s(), v13.v4s(), v1.s()[0]);
1287 }
1288 if (max_mr > 2) {
1289 fmla(v25.v4s(), v13.v4s(), v2.s()[0]);
1290 }
1291 if (max_mr > 3) {
1292 fmla(v27.v4s(), v13.v4s(), v3.s()[0]);
1293 }
1294 if (max_mr > 4) {
1295 fmla(v29.v4s(), v13.v4s(), v4.s()[0]);
1296 }
1297 if (max_mr > 5) {
1298 fmla(v31.v4s(), v13.v4s(), v5.s()[0]);
1299 }
1300 b(l4);
1301
1302 // Store odd width
1303 bind(l8);
1304 tbz(x1, 2, l9);
1305 if (max_mr > 5) {
1306 str(q30, mem[x7], 16);
1307 mov(v30.v16b(), v31.v16b());
1308 }
1309 if (max_mr > 4) {
1310 str(q28, mem[x13], 16);
1311 mov(v28.v16b(), v29.v16b());
1312 }
1313 if (max_mr > 3) {
1314 str(q26, mem[x10], 16);
1315 mov(v26.v16b(), v27.v16b());
1316 }
1317 if (max_mr > 2) {
1318 str(q24, mem[x17], 16);
1319 mov(v24.v16b(), v25.v16b());
1320 }
1321 if (max_mr > 1) {
1322 str(q22, mem[x16], 16);
1323 mov(v22.v16b(), v23.v16b());
1324 }
1325 str(q20, mem[x6], 16);
1326 mov(v20.v16b(), v21.v16b());
1327 bind(l9);
1328 tbz(x1, 1, l10);
1329 if (max_mr > 5) {
1330 str(d30, mem[x7], 8);
1331 dup(d30, v30.d()[1]);
1332 }
1333 if (max_mr > 4) {
1334 str(d28, mem[x13], 8);
1335 dup(d28, v28.d()[1]);
1336 }
1337 if (max_mr > 3) {
1338 str(d26, mem[x10], 8);
1339 dup(d26, v26.d()[1]);
1340 }
1341 if (max_mr > 2) {
1342 str(d24, mem[x17], 8);
1343 dup(d24, v24.d()[1]);
1344 }
1345 if (max_mr > 1) {
1346 str(d22, mem[x16], 8);
1347 dup(d22, v22.d()[1]);
1348 }
1349 str(d20, mem[x6], 8);
1350 dup(d20, v20.d()[1]);
1351
1352 bind(l10);
1353 tbz(x1, 0, l11);
1354 if (max_mr > 5) {
1355 str(s30, mem[x7]);
1356 }
1357 if (max_mr > 4) {
1358 str(s28, mem[x13]);
1359 }
1360 if (max_mr > 3) {
1361 str(s26, mem[x10]);
1362 }
1363 if (max_mr > 2) {
1364 str(s24, mem[x17]);
1365 }
1366 if (max_mr > 1) {
1367 str(s22, mem[x16]);
1368 }
1369 str(s20, mem[x6]);
1370 bind(l11);
1371 // Restore x20,x21,x22,x23 from stack
1372 ldp(x22, x23, mem[sp, 80]);
1373 ldp(x20, x21, mem[sp, 64]);
1374
1375 // Restore d8-d15 from stack
1376 ldp(d14, d15, mem[sp, 48]);
1377 ldp(d12, d13, mem[sp, 32]);
1378 ldp(d10, d11, mem[sp, 16]);
1379 ldp(d8, d9, mem[sp], 96);
1380 ret();
1381
1382 align(16, AlignInstruction::kHlt);
1383 }
1384 } // namespace
1385 } // namespace aarch64
1386 } // namespace xnnpack
1387
xnn_generate_f32_igemm_ukernel_upto6x8__aarch64_neonfma_cortex_a75(xnn_code_buffer * code,size_t max_mr,size_t nc_mod_nr,size_t kc,size_t ks,const void * params)1388 xnn_status_t xnn_generate_f32_igemm_ukernel_upto6x8__aarch64_neonfma_cortex_a75(xnn_code_buffer* code, size_t max_mr, size_t nc_mod_nr, size_t kc, size_t ks, const void* params) {
1389 using namespace xnnpack::aarch64;
1390 Generator g(code);
1391 assert(params != nullptr);
1392 const jit_gemm_params* gemm_params = static_cast<const jit_gemm_params*>(params);
1393 g.generate(false, max_mr, nc_mod_nr, kc, ks, gemm_params->f32_minmax.min, gemm_params->f32_minmax.max);
1394 g.finalize();
1395 if (g.error() != xnnpack::Error::kNoError) {
1396 return xnn_status_invalid_state;
1397 }
1398 return xnn_status_success;
1399
1400 }
1401
xnn_generate_f32_igemm_ukernel_upto6x8__aarch64_neonfma_prfm_cortex_a75(xnn_code_buffer * code,size_t max_mr,size_t nc_mod_nr,size_t kc,size_t ks,const void * params)1402 xnn_status_t xnn_generate_f32_igemm_ukernel_upto6x8__aarch64_neonfma_prfm_cortex_a75(xnn_code_buffer* code, size_t max_mr, size_t nc_mod_nr, size_t kc, size_t ks, const void* params) {
1403 using namespace xnnpack::aarch64;
1404 Generator g(code);
1405 assert(params != nullptr);
1406 const jit_gemm_params* gemm_params = static_cast<const jit_gemm_params*>(params);
1407 g.generate(true, max_mr, nc_mod_nr, kc, ks, gemm_params->f32_minmax.min, gemm_params->f32_minmax.max);
1408 g.finalize();
1409 if (g.error() != xnnpack::Error::kNoError) {
1410 return xnn_status_invalid_state;
1411 }
1412 return xnn_status_success;
1413 }
1414