xref: /aosp_15_r20/external/XNNPACK/src/f32-igemm/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/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