xref: /aosp_15_r20/external/XNNPACK/src/f32-gemm/upto6x8-aarch64-neonfma-cortex-a75.cc (revision 4bdc94577ba0e567308109d787f7fec7b531ce36)
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