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