1 // Copyright 2016 The Gemmlowp Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GEMMLOWP_META_TRANSFORM_KERNELS_ARM_32_H_
16 #define GEMMLOWP_META_TRANSFORM_KERNELS_ARM_32_H_
17 
18 #ifdef GEMMLOWP_NEON_32
19 
20 #include <cassert>
21 #include <cstdint>
22 
23 namespace gemmlowp {
24 namespace meta {
25 
26 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)27 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 0>::Transform(
28     const int32_t* input, const Requantize& params, uint8_t* output) {
29 #ifdef DEBUG
30 #ifdef DEBUG_METAGEMM_VERBOSE
31   std::cout << __FILE__ << "(" << __LINE__
32             << ") Requantize<int32_t, uint8_t, Requantize, 16, 0>::Transform()"
33             << std::endl
34             << std::flush;
35 #endif
36 #endif
37   int params_count_copy = params.count;
38   asm volatile(
39 
40       // Requantize::Prepare
41       "vdup.32 q4, %[input_range_min]\n"
42       "vdup.32 q5, %[output_range_min]\n"
43       "vdup.32 q6, %[input_range_offset]\n"
44       "vdup.32 q7, %[input_range_scale]\n"
45       "vdup.32 q8, %[one_over_output_range_scale]\n"
46       "vsub.f32 q4, q4, q5\n"
47 
48       "1:"
49       "subs %[count], %[count], #16\n"
50 
51       // Requantize::Transform
52       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
53       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
54       "pld [%[input], #64]\n"
55       "vcvt.f32.s32 q0, q0\n"
56       "vcvt.f32.s32 q1, q1\n"
57       "vcvt.f32.s32 q2, q2\n"
58       "vcvt.f32.s32 q3, q3\n"
59       "vsub.f32 q0, q0, q6\n"
60       "vsub.f32 q1, q1, q6\n"
61       "vsub.f32 q2, q2, q6\n"
62       "vsub.f32 q3, q3, q6\n"
63       "vmul.f32 q0, q0, q7\n"
64       "vmul.f32 q1, q1, q7\n"
65       "vmul.f32 q2, q2, q7\n"
66       "vmul.f32 q3, q3, q7\n"
67       "vadd.f32 q0, q0, q4\n"
68       "vadd.f32 q1, q1, q4\n"
69       "vadd.f32 q2, q2, q4\n"
70       "vadd.f32 q3, q3, q4\n"
71       "vmul.f32 q0, q0, q8\n"
72       "vmul.f32 q1, q1, q8\n"
73       "vmul.f32 q2, q2, q8\n"
74       "vmul.f32 q3, q3, q8\n"
75       "vcvt.s32.f32 q0, q0\n"
76       "vcvt.s32.f32 q1, q1\n"
77       "vcvt.s32.f32 q2, q2\n"
78       "vcvt.s32.f32 q3, q3\n"
79       "vqmovn.s32 d0, q0\n"
80       "vqmovn.s32 d1, q1\n"
81       "vqmovn.s32 d4, q2\n"
82       "vqmovn.s32 d5, q3\n"
83       "vqmovun.s16 d0, q0\n"
84       "vqmovun.s16 d1, q2\n"
85 
86       "vst1.32 {d0, d1}, [%[output]]!\n"
87       "pld [%[output]]\n"
88 
89       "bne 1b\n"
90       : [count] "+r"(params_count_copy), [input] "+r"(input),
91         [output] "+r"(output)
92       : [input_range_min] "r"(params.input_range_min),
93         [output_range_min] "r"(params.output_range_min),
94         [input_range_offset] "r"(params.input_range_offset),
95         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
96         [input_range_scale] "r"(params.input_range_scale)
97       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
98         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
99 }
100 
101 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)102 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 1>::Transform(
103     const int32_t* input, const Requantize& params, uint8_t* output) {
104 #ifdef DEBUG
105 #ifdef DEBUG_METAGEMM_VERBOSE
106   std::cout << __FILE__ << "(" << __LINE__
107             << ") Requantize<int32_t, uint8_t, Requantize, 16, 1>::Transform()"
108             << std::endl
109             << std::flush;
110 #endif
111 #endif
112   int params_count_copy = params.count;
113   asm volatile(
114 
115       // Requantize::Prepare
116       "vdup.32 q4, %[input_range_min]\n"
117       "vdup.32 q5, %[output_range_min]\n"
118       "vdup.32 q6, %[input_range_offset]\n"
119       "vdup.32 q7, %[input_range_scale]\n"
120       "vdup.32 q8, %[one_over_output_range_scale]\n"
121       "vsub.f32 q4, q4, q5\n"
122 
123       // Reduce count by leftovers.
124       "subs %[count], %[count], #1\n"
125       "beq 2f\n"
126 
127       "1:"
128       "subs %[count], %[count], #16\n"
129 
130       // Requantize::Transform
131       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
132       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
133       "pld [%[input], #64]\n"
134       "vcvt.f32.s32 q0, q0\n"
135       "vcvt.f32.s32 q1, q1\n"
136       "vcvt.f32.s32 q2, q2\n"
137       "vcvt.f32.s32 q3, q3\n"
138       "vsub.f32 q0, q0, q6\n"
139       "vsub.f32 q1, q1, q6\n"
140       "vsub.f32 q2, q2, q6\n"
141       "vsub.f32 q3, q3, q6\n"
142       "vmul.f32 q0, q0, q7\n"
143       "vmul.f32 q1, q1, q7\n"
144       "vmul.f32 q2, q2, q7\n"
145       "vmul.f32 q3, q3, q7\n"
146       "vadd.f32 q0, q0, q4\n"
147       "vadd.f32 q1, q1, q4\n"
148       "vadd.f32 q2, q2, q4\n"
149       "vadd.f32 q3, q3, q4\n"
150       "vmul.f32 q0, q0, q8\n"
151       "vmul.f32 q1, q1, q8\n"
152       "vmul.f32 q2, q2, q8\n"
153       "vmul.f32 q3, q3, q8\n"
154       "vcvt.s32.f32 q0, q0\n"
155       "vcvt.s32.f32 q1, q1\n"
156       "vcvt.s32.f32 q2, q2\n"
157       "vcvt.s32.f32 q3, q3\n"
158       "vqmovn.s32 d0, q0\n"
159       "vqmovn.s32 d1, q1\n"
160       "vqmovn.s32 d4, q2\n"
161       "vqmovn.s32 d5, q3\n"
162       "vqmovun.s16 d0, q0\n"
163       "vqmovun.s16 d1, q2\n"
164 
165       "vst1.32 {d0, d1}, [%[output]]!\n"
166       "pld [%[output]]\n"
167 
168       "bne 1b\n"
169       "2:"
170 
171       // Handle leftovers.
172 
173       // Requantize::Transform
174       "vld1.32 {d0[0]}, [%[input]]!\n"
175       "pld [%[input], #64]\n"
176       "vcvt.f32.s32 q0, q0\n"
177       "vsub.f32 q0, q0, q6\n"
178       "vmul.f32 q0, q0, q7\n"
179       "vadd.f32 q0, q0, q4\n"
180       "vmul.f32 q0, q0, q8\n"
181       "vcvt.s32.f32 q0, q0\n"
182       "vqmovn.s32 d0, q0\n"
183       "vqmovun.s16 d0, q0\n"
184 
185       "vst1.8 {d0[0]}, [%[output]]!\n"
186       "pld [%[output]]\n"
187       : [count] "+r"(params_count_copy), [input] "+r"(input),
188         [output] "+r"(output)
189       : [input_range_min] "r"(params.input_range_min),
190         [output_range_min] "r"(params.output_range_min),
191         [input_range_offset] "r"(params.input_range_offset),
192         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
193         [input_range_scale] "r"(params.input_range_scale)
194       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
195         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
196 }
197 
198 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)199 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 2>::Transform(
200     const int32_t* input, const Requantize& params, uint8_t* output) {
201 #ifdef DEBUG
202 #ifdef DEBUG_METAGEMM_VERBOSE
203   std::cout << __FILE__ << "(" << __LINE__
204             << ") Requantize<int32_t, uint8_t, Requantize, 16, 2>::Transform()"
205             << std::endl
206             << std::flush;
207 #endif
208 #endif
209   int params_count_copy = params.count;
210   asm volatile(
211 
212       // Requantize::Prepare
213       "vdup.32 q4, %[input_range_min]\n"
214       "vdup.32 q5, %[output_range_min]\n"
215       "vdup.32 q6, %[input_range_offset]\n"
216       "vdup.32 q7, %[input_range_scale]\n"
217       "vdup.32 q8, %[one_over_output_range_scale]\n"
218       "vsub.f32 q4, q4, q5\n"
219 
220       // Reduce count by leftovers.
221       "subs %[count], %[count], #2\n"
222       "beq 2f\n"
223 
224       "1:"
225       "subs %[count], %[count], #16\n"
226 
227       // Requantize::Transform
228       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
229       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
230       "pld [%[input], #64]\n"
231       "vcvt.f32.s32 q0, q0\n"
232       "vcvt.f32.s32 q1, q1\n"
233       "vcvt.f32.s32 q2, q2\n"
234       "vcvt.f32.s32 q3, q3\n"
235       "vsub.f32 q0, q0, q6\n"
236       "vsub.f32 q1, q1, q6\n"
237       "vsub.f32 q2, q2, q6\n"
238       "vsub.f32 q3, q3, q6\n"
239       "vmul.f32 q0, q0, q7\n"
240       "vmul.f32 q1, q1, q7\n"
241       "vmul.f32 q2, q2, q7\n"
242       "vmul.f32 q3, q3, q7\n"
243       "vadd.f32 q0, q0, q4\n"
244       "vadd.f32 q1, q1, q4\n"
245       "vadd.f32 q2, q2, q4\n"
246       "vadd.f32 q3, q3, q4\n"
247       "vmul.f32 q0, q0, q8\n"
248       "vmul.f32 q1, q1, q8\n"
249       "vmul.f32 q2, q2, q8\n"
250       "vmul.f32 q3, q3, q8\n"
251       "vcvt.s32.f32 q0, q0\n"
252       "vcvt.s32.f32 q1, q1\n"
253       "vcvt.s32.f32 q2, q2\n"
254       "vcvt.s32.f32 q3, q3\n"
255       "vqmovn.s32 d0, q0\n"
256       "vqmovn.s32 d1, q1\n"
257       "vqmovn.s32 d4, q2\n"
258       "vqmovn.s32 d5, q3\n"
259       "vqmovun.s16 d0, q0\n"
260       "vqmovun.s16 d1, q2\n"
261 
262       "vst1.32 {d0, d1}, [%[output]]!\n"
263       "pld [%[output]]\n"
264 
265       "bne 1b\n"
266       "2:"
267 
268       // Handle leftovers.
269 
270       // Requantize::Transform
271       "vld1.32 {d0}, [%[input]]!\n"
272       "pld [%[input], #64]\n"
273       "vcvt.f32.s32 q0, q0\n"
274       "vsub.f32 q0, q0, q6\n"
275       "vmul.f32 q0, q0, q7\n"
276       "vadd.f32 q0, q0, q4\n"
277       "vmul.f32 q0, q0, q8\n"
278       "vcvt.s32.f32 q0, q0\n"
279       "vqmovn.s32 d0, q0\n"
280       "vqmovun.s16 d0, q0\n"
281 
282       "vst1.16 {d0[0]}, [%[output]]!\n"
283       "pld [%[output]]\n"
284       : [count] "+r"(params_count_copy), [input] "+r"(input),
285         [output] "+r"(output)
286       : [input_range_min] "r"(params.input_range_min),
287         [output_range_min] "r"(params.output_range_min),
288         [input_range_offset] "r"(params.input_range_offset),
289         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
290         [input_range_scale] "r"(params.input_range_scale)
291       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
292         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
293 }
294 
295 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)296 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 3>::Transform(
297     const int32_t* input, const Requantize& params, uint8_t* output) {
298 #ifdef DEBUG
299 #ifdef DEBUG_METAGEMM_VERBOSE
300   std::cout << __FILE__ << "(" << __LINE__
301             << ") Requantize<int32_t, uint8_t, Requantize, 16, 3>::Transform()"
302             << std::endl
303             << std::flush;
304 #endif
305 #endif
306   int params_count_copy = params.count;
307   asm volatile(
308 
309       // Requantize::Prepare
310       "vdup.32 q4, %[input_range_min]\n"
311       "vdup.32 q5, %[output_range_min]\n"
312       "vdup.32 q6, %[input_range_offset]\n"
313       "vdup.32 q7, %[input_range_scale]\n"
314       "vdup.32 q8, %[one_over_output_range_scale]\n"
315       "vsub.f32 q4, q4, q5\n"
316 
317       // Reduce count by leftovers.
318       "subs %[count], %[count], #3\n"
319       "beq 2f\n"
320 
321       "1:"
322       "subs %[count], %[count], #16\n"
323 
324       // Requantize::Transform
325       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
326       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
327       "pld [%[input], #64]\n"
328       "vcvt.f32.s32 q0, q0\n"
329       "vcvt.f32.s32 q1, q1\n"
330       "vcvt.f32.s32 q2, q2\n"
331       "vcvt.f32.s32 q3, q3\n"
332       "vsub.f32 q0, q0, q6\n"
333       "vsub.f32 q1, q1, q6\n"
334       "vsub.f32 q2, q2, q6\n"
335       "vsub.f32 q3, q3, q6\n"
336       "vmul.f32 q0, q0, q7\n"
337       "vmul.f32 q1, q1, q7\n"
338       "vmul.f32 q2, q2, q7\n"
339       "vmul.f32 q3, q3, q7\n"
340       "vadd.f32 q0, q0, q4\n"
341       "vadd.f32 q1, q1, q4\n"
342       "vadd.f32 q2, q2, q4\n"
343       "vadd.f32 q3, q3, q4\n"
344       "vmul.f32 q0, q0, q8\n"
345       "vmul.f32 q1, q1, q8\n"
346       "vmul.f32 q2, q2, q8\n"
347       "vmul.f32 q3, q3, q8\n"
348       "vcvt.s32.f32 q0, q0\n"
349       "vcvt.s32.f32 q1, q1\n"
350       "vcvt.s32.f32 q2, q2\n"
351       "vcvt.s32.f32 q3, q3\n"
352       "vqmovn.s32 d0, q0\n"
353       "vqmovn.s32 d1, q1\n"
354       "vqmovn.s32 d4, q2\n"
355       "vqmovn.s32 d5, q3\n"
356       "vqmovun.s16 d0, q0\n"
357       "vqmovun.s16 d1, q2\n"
358 
359       "vst1.32 {d0, d1}, [%[output]]!\n"
360       "pld [%[output]]\n"
361 
362       "bne 1b\n"
363       "2:"
364 
365       // Handle leftovers.
366 
367       // Requantize::Transform
368       "vld1.32 {d0}, [%[input]]!\n"
369       "vld1.32 {d1[0]}, [%[input]]!\n"
370       "pld [%[input], #64]\n"
371       "vcvt.f32.s32 q0, q0\n"
372       "vsub.f32 q0, q0, q6\n"
373       "vmul.f32 q0, q0, q7\n"
374       "vadd.f32 q0, q0, q4\n"
375       "vmul.f32 q0, q0, q8\n"
376       "vcvt.s32.f32 q0, q0\n"
377       "vqmovn.s32 d0, q0\n"
378       "vqmovun.s16 d0, q0\n"
379 
380       "vst1.16 {d0[0]}, [%[output]]!\n"
381       "vst1.8 {d0[2]}, [%[output]]!\n"
382       "pld [%[output]]\n"
383       : [count] "+r"(params_count_copy), [input] "+r"(input),
384         [output] "+r"(output)
385       : [input_range_min] "r"(params.input_range_min),
386         [output_range_min] "r"(params.output_range_min),
387         [input_range_offset] "r"(params.input_range_offset),
388         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
389         [input_range_scale] "r"(params.input_range_scale)
390       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
391         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
392 }
393 
394 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)395 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 4>::Transform(
396     const int32_t* input, const Requantize& params, uint8_t* output) {
397 #ifdef DEBUG
398 #ifdef DEBUG_METAGEMM_VERBOSE
399   std::cout << __FILE__ << "(" << __LINE__
400             << ") Requantize<int32_t, uint8_t, Requantize, 16, 4>::Transform()"
401             << std::endl
402             << std::flush;
403 #endif
404 #endif
405   int params_count_copy = params.count;
406   asm volatile(
407 
408       // Requantize::Prepare
409       "vdup.32 q4, %[input_range_min]\n"
410       "vdup.32 q5, %[output_range_min]\n"
411       "vdup.32 q6, %[input_range_offset]\n"
412       "vdup.32 q7, %[input_range_scale]\n"
413       "vdup.32 q8, %[one_over_output_range_scale]\n"
414       "vsub.f32 q4, q4, q5\n"
415 
416       // Reduce count by leftovers.
417       "subs %[count], %[count], #4\n"
418       "beq 2f\n"
419 
420       "1:"
421       "subs %[count], %[count], #16\n"
422 
423       // Requantize::Transform
424       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
425       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
426       "pld [%[input], #64]\n"
427       "vcvt.f32.s32 q0, q0\n"
428       "vcvt.f32.s32 q1, q1\n"
429       "vcvt.f32.s32 q2, q2\n"
430       "vcvt.f32.s32 q3, q3\n"
431       "vsub.f32 q0, q0, q6\n"
432       "vsub.f32 q1, q1, q6\n"
433       "vsub.f32 q2, q2, q6\n"
434       "vsub.f32 q3, q3, q6\n"
435       "vmul.f32 q0, q0, q7\n"
436       "vmul.f32 q1, q1, q7\n"
437       "vmul.f32 q2, q2, q7\n"
438       "vmul.f32 q3, q3, q7\n"
439       "vadd.f32 q0, q0, q4\n"
440       "vadd.f32 q1, q1, q4\n"
441       "vadd.f32 q2, q2, q4\n"
442       "vadd.f32 q3, q3, q4\n"
443       "vmul.f32 q0, q0, q8\n"
444       "vmul.f32 q1, q1, q8\n"
445       "vmul.f32 q2, q2, q8\n"
446       "vmul.f32 q3, q3, q8\n"
447       "vcvt.s32.f32 q0, q0\n"
448       "vcvt.s32.f32 q1, q1\n"
449       "vcvt.s32.f32 q2, q2\n"
450       "vcvt.s32.f32 q3, q3\n"
451       "vqmovn.s32 d0, q0\n"
452       "vqmovn.s32 d1, q1\n"
453       "vqmovn.s32 d4, q2\n"
454       "vqmovn.s32 d5, q3\n"
455       "vqmovun.s16 d0, q0\n"
456       "vqmovun.s16 d1, q2\n"
457 
458       "vst1.32 {d0, d1}, [%[output]]!\n"
459       "pld [%[output]]\n"
460 
461       "bne 1b\n"
462       "2:"
463 
464       // Handle leftovers.
465 
466       // Requantize::Transform
467       "vld1.32 {d0, d1}, [%[input]]!\n"
468       "pld [%[input], #64]\n"
469       "vcvt.f32.s32 q0, q0\n"
470       "vsub.f32 q0, q0, q6\n"
471       "vmul.f32 q0, q0, q7\n"
472       "vadd.f32 q0, q0, q4\n"
473       "vmul.f32 q0, q0, q8\n"
474       "vcvt.s32.f32 q0, q0\n"
475       "vqmovn.s32 d0, q0\n"
476       "vqmovun.s16 d0, q0\n"
477 
478       "vst1.32 {d0[0]}, [%[output]]!\n"
479       "pld [%[output]]\n"
480       : [count] "+r"(params_count_copy), [input] "+r"(input),
481         [output] "+r"(output)
482       : [input_range_min] "r"(params.input_range_min),
483         [output_range_min] "r"(params.output_range_min),
484         [input_range_offset] "r"(params.input_range_offset),
485         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
486         [input_range_scale] "r"(params.input_range_scale)
487       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
488         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
489 }
490 
491 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)492 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 5>::Transform(
493     const int32_t* input, const Requantize& params, uint8_t* output) {
494 #ifdef DEBUG
495 #ifdef DEBUG_METAGEMM_VERBOSE
496   std::cout << __FILE__ << "(" << __LINE__
497             << ") Requantize<int32_t, uint8_t, Requantize, 16, 5>::Transform()"
498             << std::endl
499             << std::flush;
500 #endif
501 #endif
502   int params_count_copy = params.count;
503   asm volatile(
504 
505       // Requantize::Prepare
506       "vdup.32 q4, %[input_range_min]\n"
507       "vdup.32 q5, %[output_range_min]\n"
508       "vdup.32 q6, %[input_range_offset]\n"
509       "vdup.32 q7, %[input_range_scale]\n"
510       "vdup.32 q8, %[one_over_output_range_scale]\n"
511       "vsub.f32 q4, q4, q5\n"
512 
513       // Reduce count by leftovers.
514       "subs %[count], %[count], #5\n"
515       "beq 2f\n"
516 
517       "1:"
518       "subs %[count], %[count], #16\n"
519 
520       // Requantize::Transform
521       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
522       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
523       "pld [%[input], #64]\n"
524       "vcvt.f32.s32 q0, q0\n"
525       "vcvt.f32.s32 q1, q1\n"
526       "vcvt.f32.s32 q2, q2\n"
527       "vcvt.f32.s32 q3, q3\n"
528       "vsub.f32 q0, q0, q6\n"
529       "vsub.f32 q1, q1, q6\n"
530       "vsub.f32 q2, q2, q6\n"
531       "vsub.f32 q3, q3, q6\n"
532       "vmul.f32 q0, q0, q7\n"
533       "vmul.f32 q1, q1, q7\n"
534       "vmul.f32 q2, q2, q7\n"
535       "vmul.f32 q3, q3, q7\n"
536       "vadd.f32 q0, q0, q4\n"
537       "vadd.f32 q1, q1, q4\n"
538       "vadd.f32 q2, q2, q4\n"
539       "vadd.f32 q3, q3, q4\n"
540       "vmul.f32 q0, q0, q8\n"
541       "vmul.f32 q1, q1, q8\n"
542       "vmul.f32 q2, q2, q8\n"
543       "vmul.f32 q3, q3, q8\n"
544       "vcvt.s32.f32 q0, q0\n"
545       "vcvt.s32.f32 q1, q1\n"
546       "vcvt.s32.f32 q2, q2\n"
547       "vcvt.s32.f32 q3, q3\n"
548       "vqmovn.s32 d0, q0\n"
549       "vqmovn.s32 d1, q1\n"
550       "vqmovn.s32 d4, q2\n"
551       "vqmovn.s32 d5, q3\n"
552       "vqmovun.s16 d0, q0\n"
553       "vqmovun.s16 d1, q2\n"
554 
555       "vst1.32 {d0, d1}, [%[output]]!\n"
556       "pld [%[output]]\n"
557 
558       "bne 1b\n"
559       "2:"
560 
561       // Handle leftovers.
562 
563       // Requantize::Transform
564       "vld1.32 {d0, d1}, [%[input]]!\n"
565       "vld1.32 {d2[0]}, [%[input]]!\n"
566       "pld [%[input], #64]\n"
567       "vcvt.f32.s32 q0, q0\n"
568       "vcvt.f32.s32 q1, q1\n"
569       "vsub.f32 q0, q0, q6\n"
570       "vsub.f32 q1, q1, q6\n"
571       "vmul.f32 q0, q0, q7\n"
572       "vmul.f32 q1, q1, q7\n"
573       "vadd.f32 q0, q0, q4\n"
574       "vadd.f32 q1, q1, q4\n"
575       "vmul.f32 q0, q0, q8\n"
576       "vmul.f32 q1, q1, q8\n"
577       "vcvt.s32.f32 q0, q0\n"
578       "vcvt.s32.f32 q1, q1\n"
579       "vqmovn.s32 d0, q0\n"
580       "vqmovn.s32 d1, q1\n"
581       "vqmovun.s16 d0, q0\n"
582 
583       "vst1.32 {d0[0]}, [%[output]]!\n"
584       "vst1.8 {d0[4]}, [%[output]]!\n"
585       "pld [%[output]]\n"
586       : [count] "+r"(params_count_copy), [input] "+r"(input),
587         [output] "+r"(output)
588       : [input_range_min] "r"(params.input_range_min),
589         [output_range_min] "r"(params.output_range_min),
590         [input_range_offset] "r"(params.input_range_offset),
591         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
592         [input_range_scale] "r"(params.input_range_scale)
593       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
594         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
595 }
596 
597 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)598 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 6>::Transform(
599     const int32_t* input, const Requantize& params, uint8_t* output) {
600 #ifdef DEBUG
601 #ifdef DEBUG_METAGEMM_VERBOSE
602   std::cout << __FILE__ << "(" << __LINE__
603             << ") Requantize<int32_t, uint8_t, Requantize, 16, 6>::Transform()"
604             << std::endl
605             << std::flush;
606 #endif
607 #endif
608   int params_count_copy = params.count;
609   asm volatile(
610 
611       // Requantize::Prepare
612       "vdup.32 q4, %[input_range_min]\n"
613       "vdup.32 q5, %[output_range_min]\n"
614       "vdup.32 q6, %[input_range_offset]\n"
615       "vdup.32 q7, %[input_range_scale]\n"
616       "vdup.32 q8, %[one_over_output_range_scale]\n"
617       "vsub.f32 q4, q4, q5\n"
618 
619       // Reduce count by leftovers.
620       "subs %[count], %[count], #6\n"
621       "beq 2f\n"
622 
623       "1:"
624       "subs %[count], %[count], #16\n"
625 
626       // Requantize::Transform
627       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
628       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
629       "pld [%[input], #64]\n"
630       "vcvt.f32.s32 q0, q0\n"
631       "vcvt.f32.s32 q1, q1\n"
632       "vcvt.f32.s32 q2, q2\n"
633       "vcvt.f32.s32 q3, q3\n"
634       "vsub.f32 q0, q0, q6\n"
635       "vsub.f32 q1, q1, q6\n"
636       "vsub.f32 q2, q2, q6\n"
637       "vsub.f32 q3, q3, q6\n"
638       "vmul.f32 q0, q0, q7\n"
639       "vmul.f32 q1, q1, q7\n"
640       "vmul.f32 q2, q2, q7\n"
641       "vmul.f32 q3, q3, q7\n"
642       "vadd.f32 q0, q0, q4\n"
643       "vadd.f32 q1, q1, q4\n"
644       "vadd.f32 q2, q2, q4\n"
645       "vadd.f32 q3, q3, q4\n"
646       "vmul.f32 q0, q0, q8\n"
647       "vmul.f32 q1, q1, q8\n"
648       "vmul.f32 q2, q2, q8\n"
649       "vmul.f32 q3, q3, q8\n"
650       "vcvt.s32.f32 q0, q0\n"
651       "vcvt.s32.f32 q1, q1\n"
652       "vcvt.s32.f32 q2, q2\n"
653       "vcvt.s32.f32 q3, q3\n"
654       "vqmovn.s32 d0, q0\n"
655       "vqmovn.s32 d1, q1\n"
656       "vqmovn.s32 d4, q2\n"
657       "vqmovn.s32 d5, q3\n"
658       "vqmovun.s16 d0, q0\n"
659       "vqmovun.s16 d1, q2\n"
660 
661       "vst1.32 {d0, d1}, [%[output]]!\n"
662       "pld [%[output]]\n"
663 
664       "bne 1b\n"
665       "2:"
666 
667       // Handle leftovers.
668 
669       // Requantize::Transform
670       "vld1.32 {d0, d1, d2}, [%[input]]!\n"
671       "pld [%[input], #64]\n"
672       "vcvt.f32.s32 q0, q0\n"
673       "vcvt.f32.s32 q1, q1\n"
674       "vsub.f32 q0, q0, q6\n"
675       "vsub.f32 q1, q1, q6\n"
676       "vmul.f32 q0, q0, q7\n"
677       "vmul.f32 q1, q1, q7\n"
678       "vadd.f32 q0, q0, q4\n"
679       "vadd.f32 q1, q1, q4\n"
680       "vmul.f32 q0, q0, q8\n"
681       "vmul.f32 q1, q1, q8\n"
682       "vcvt.s32.f32 q0, q0\n"
683       "vcvt.s32.f32 q1, q1\n"
684       "vqmovn.s32 d0, q0\n"
685       "vqmovn.s32 d1, q1\n"
686       "vqmovun.s16 d0, q0\n"
687 
688       "vst1.32 {d0[0]}, [%[output]]!\n"
689       "vst1.16 {d0[2]}, [%[output]]!\n"
690       "pld [%[output]]\n"
691       : [count] "+r"(params_count_copy), [input] "+r"(input),
692         [output] "+r"(output)
693       : [input_range_min] "r"(params.input_range_min),
694         [output_range_min] "r"(params.output_range_min),
695         [input_range_offset] "r"(params.input_range_offset),
696         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
697         [input_range_scale] "r"(params.input_range_scale)
698       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
699         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
700 }
701 
702 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)703 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 7>::Transform(
704     const int32_t* input, const Requantize& params, uint8_t* output) {
705 #ifdef DEBUG
706 #ifdef DEBUG_METAGEMM_VERBOSE
707   std::cout << __FILE__ << "(" << __LINE__
708             << ") Requantize<int32_t, uint8_t, Requantize, 16, 7>::Transform()"
709             << std::endl
710             << std::flush;
711 #endif
712 #endif
713   int params_count_copy = params.count;
714   asm volatile(
715 
716       // Requantize::Prepare
717       "vdup.32 q4, %[input_range_min]\n"
718       "vdup.32 q5, %[output_range_min]\n"
719       "vdup.32 q6, %[input_range_offset]\n"
720       "vdup.32 q7, %[input_range_scale]\n"
721       "vdup.32 q8, %[one_over_output_range_scale]\n"
722       "vsub.f32 q4, q4, q5\n"
723 
724       // Reduce count by leftovers.
725       "subs %[count], %[count], #7\n"
726       "beq 2f\n"
727 
728       "1:"
729       "subs %[count], %[count], #16\n"
730 
731       // Requantize::Transform
732       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
733       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
734       "pld [%[input], #64]\n"
735       "vcvt.f32.s32 q0, q0\n"
736       "vcvt.f32.s32 q1, q1\n"
737       "vcvt.f32.s32 q2, q2\n"
738       "vcvt.f32.s32 q3, q3\n"
739       "vsub.f32 q0, q0, q6\n"
740       "vsub.f32 q1, q1, q6\n"
741       "vsub.f32 q2, q2, q6\n"
742       "vsub.f32 q3, q3, q6\n"
743       "vmul.f32 q0, q0, q7\n"
744       "vmul.f32 q1, q1, q7\n"
745       "vmul.f32 q2, q2, q7\n"
746       "vmul.f32 q3, q3, q7\n"
747       "vadd.f32 q0, q0, q4\n"
748       "vadd.f32 q1, q1, q4\n"
749       "vadd.f32 q2, q2, q4\n"
750       "vadd.f32 q3, q3, q4\n"
751       "vmul.f32 q0, q0, q8\n"
752       "vmul.f32 q1, q1, q8\n"
753       "vmul.f32 q2, q2, q8\n"
754       "vmul.f32 q3, q3, q8\n"
755       "vcvt.s32.f32 q0, q0\n"
756       "vcvt.s32.f32 q1, q1\n"
757       "vcvt.s32.f32 q2, q2\n"
758       "vcvt.s32.f32 q3, q3\n"
759       "vqmovn.s32 d0, q0\n"
760       "vqmovn.s32 d1, q1\n"
761       "vqmovn.s32 d4, q2\n"
762       "vqmovn.s32 d5, q3\n"
763       "vqmovun.s16 d0, q0\n"
764       "vqmovun.s16 d1, q2\n"
765 
766       "vst1.32 {d0, d1}, [%[output]]!\n"
767       "pld [%[output]]\n"
768 
769       "bne 1b\n"
770       "2:"
771 
772       // Handle leftovers.
773 
774       // Requantize::Transform
775       "vld1.32 {d0, d1, d2}, [%[input]]!\n"
776       "vld1.32 {d3[0]}, [%[input]]!\n"
777       "pld [%[input], #64]\n"
778       "vcvt.f32.s32 q0, q0\n"
779       "vcvt.f32.s32 q1, q1\n"
780       "vsub.f32 q0, q0, q6\n"
781       "vsub.f32 q1, q1, q6\n"
782       "vmul.f32 q0, q0, q7\n"
783       "vmul.f32 q1, q1, q7\n"
784       "vadd.f32 q0, q0, q4\n"
785       "vadd.f32 q1, q1, q4\n"
786       "vmul.f32 q0, q0, q8\n"
787       "vmul.f32 q1, q1, q8\n"
788       "vcvt.s32.f32 q0, q0\n"
789       "vcvt.s32.f32 q1, q1\n"
790       "vqmovn.s32 d0, q0\n"
791       "vqmovn.s32 d1, q1\n"
792       "vqmovun.s16 d0, q0\n"
793 
794       "vst1.32 {d0[0]}, [%[output]]!\n"
795       "vst1.16 {d0[2]}, [%[output]]!\n"
796       "vst1.8 {d0[6]}, [%[output]]!\n"
797       "pld [%[output]]\n"
798       : [count] "+r"(params_count_copy), [input] "+r"(input),
799         [output] "+r"(output)
800       : [input_range_min] "r"(params.input_range_min),
801         [output_range_min] "r"(params.output_range_min),
802         [input_range_offset] "r"(params.input_range_offset),
803         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
804         [input_range_scale] "r"(params.input_range_scale)
805       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
806         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
807 }
808 
809 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)810 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 8>::Transform(
811     const int32_t* input, const Requantize& params, uint8_t* output) {
812 #ifdef DEBUG
813 #ifdef DEBUG_METAGEMM_VERBOSE
814   std::cout << __FILE__ << "(" << __LINE__
815             << ") Requantize<int32_t, uint8_t, Requantize, 16, 8>::Transform()"
816             << std::endl
817             << std::flush;
818 #endif
819 #endif
820   int params_count_copy = params.count;
821   asm volatile(
822 
823       // Requantize::Prepare
824       "vdup.32 q4, %[input_range_min]\n"
825       "vdup.32 q5, %[output_range_min]\n"
826       "vdup.32 q6, %[input_range_offset]\n"
827       "vdup.32 q7, %[input_range_scale]\n"
828       "vdup.32 q8, %[one_over_output_range_scale]\n"
829       "vsub.f32 q4, q4, q5\n"
830 
831       // Reduce count by leftovers.
832       "subs %[count], %[count], #8\n"
833       "beq 2f\n"
834 
835       "1:"
836       "subs %[count], %[count], #16\n"
837 
838       // Requantize::Transform
839       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
840       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
841       "pld [%[input], #64]\n"
842       "vcvt.f32.s32 q0, q0\n"
843       "vcvt.f32.s32 q1, q1\n"
844       "vcvt.f32.s32 q2, q2\n"
845       "vcvt.f32.s32 q3, q3\n"
846       "vsub.f32 q0, q0, q6\n"
847       "vsub.f32 q1, q1, q6\n"
848       "vsub.f32 q2, q2, q6\n"
849       "vsub.f32 q3, q3, q6\n"
850       "vmul.f32 q0, q0, q7\n"
851       "vmul.f32 q1, q1, q7\n"
852       "vmul.f32 q2, q2, q7\n"
853       "vmul.f32 q3, q3, q7\n"
854       "vadd.f32 q0, q0, q4\n"
855       "vadd.f32 q1, q1, q4\n"
856       "vadd.f32 q2, q2, q4\n"
857       "vadd.f32 q3, q3, q4\n"
858       "vmul.f32 q0, q0, q8\n"
859       "vmul.f32 q1, q1, q8\n"
860       "vmul.f32 q2, q2, q8\n"
861       "vmul.f32 q3, q3, q8\n"
862       "vcvt.s32.f32 q0, q0\n"
863       "vcvt.s32.f32 q1, q1\n"
864       "vcvt.s32.f32 q2, q2\n"
865       "vcvt.s32.f32 q3, q3\n"
866       "vqmovn.s32 d0, q0\n"
867       "vqmovn.s32 d1, q1\n"
868       "vqmovn.s32 d4, q2\n"
869       "vqmovn.s32 d5, q3\n"
870       "vqmovun.s16 d0, q0\n"
871       "vqmovun.s16 d1, q2\n"
872 
873       "vst1.32 {d0, d1}, [%[output]]!\n"
874       "pld [%[output]]\n"
875 
876       "bne 1b\n"
877       "2:"
878 
879       // Handle leftovers.
880 
881       // Requantize::Transform
882       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
883       "pld [%[input], #64]\n"
884       "vcvt.f32.s32 q0, q0\n"
885       "vcvt.f32.s32 q1, q1\n"
886       "vsub.f32 q0, q0, q6\n"
887       "vsub.f32 q1, q1, q6\n"
888       "vmul.f32 q0, q0, q7\n"
889       "vmul.f32 q1, q1, q7\n"
890       "vadd.f32 q0, q0, q4\n"
891       "vadd.f32 q1, q1, q4\n"
892       "vmul.f32 q0, q0, q8\n"
893       "vmul.f32 q1, q1, q8\n"
894       "vcvt.s32.f32 q0, q0\n"
895       "vcvt.s32.f32 q1, q1\n"
896       "vqmovn.s32 d0, q0\n"
897       "vqmovn.s32 d1, q1\n"
898       "vqmovun.s16 d0, q0\n"
899 
900       "vst1.32 {d0}, [%[output]]!\n"
901       "pld [%[output]]\n"
902       : [count] "+r"(params_count_copy), [input] "+r"(input),
903         [output] "+r"(output)
904       : [input_range_min] "r"(params.input_range_min),
905         [output_range_min] "r"(params.output_range_min),
906         [input_range_offset] "r"(params.input_range_offset),
907         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
908         [input_range_scale] "r"(params.input_range_scale)
909       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
910         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
911 }
912 
913 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)914 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 9>::Transform(
915     const int32_t* input, const Requantize& params, uint8_t* output) {
916 #ifdef DEBUG
917 #ifdef DEBUG_METAGEMM_VERBOSE
918   std::cout << __FILE__ << "(" << __LINE__
919             << ") Requantize<int32_t, uint8_t, Requantize, 16, 9>::Transform()"
920             << std::endl
921             << std::flush;
922 #endif
923 #endif
924   int params_count_copy = params.count;
925   asm volatile(
926 
927       // Requantize::Prepare
928       "vdup.32 q4, %[input_range_min]\n"
929       "vdup.32 q5, %[output_range_min]\n"
930       "vdup.32 q6, %[input_range_offset]\n"
931       "vdup.32 q7, %[input_range_scale]\n"
932       "vdup.32 q8, %[one_over_output_range_scale]\n"
933       "vsub.f32 q4, q4, q5\n"
934 
935       // Reduce count by leftovers.
936       "subs %[count], %[count], #9\n"
937       "beq 2f\n"
938 
939       "1:"
940       "subs %[count], %[count], #16\n"
941 
942       // Requantize::Transform
943       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
944       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
945       "pld [%[input], #64]\n"
946       "vcvt.f32.s32 q0, q0\n"
947       "vcvt.f32.s32 q1, q1\n"
948       "vcvt.f32.s32 q2, q2\n"
949       "vcvt.f32.s32 q3, q3\n"
950       "vsub.f32 q0, q0, q6\n"
951       "vsub.f32 q1, q1, q6\n"
952       "vsub.f32 q2, q2, q6\n"
953       "vsub.f32 q3, q3, q6\n"
954       "vmul.f32 q0, q0, q7\n"
955       "vmul.f32 q1, q1, q7\n"
956       "vmul.f32 q2, q2, q7\n"
957       "vmul.f32 q3, q3, q7\n"
958       "vadd.f32 q0, q0, q4\n"
959       "vadd.f32 q1, q1, q4\n"
960       "vadd.f32 q2, q2, q4\n"
961       "vadd.f32 q3, q3, q4\n"
962       "vmul.f32 q0, q0, q8\n"
963       "vmul.f32 q1, q1, q8\n"
964       "vmul.f32 q2, q2, q8\n"
965       "vmul.f32 q3, q3, q8\n"
966       "vcvt.s32.f32 q0, q0\n"
967       "vcvt.s32.f32 q1, q1\n"
968       "vcvt.s32.f32 q2, q2\n"
969       "vcvt.s32.f32 q3, q3\n"
970       "vqmovn.s32 d0, q0\n"
971       "vqmovn.s32 d1, q1\n"
972       "vqmovn.s32 d4, q2\n"
973       "vqmovn.s32 d5, q3\n"
974       "vqmovun.s16 d0, q0\n"
975       "vqmovun.s16 d1, q2\n"
976 
977       "vst1.32 {d0, d1}, [%[output]]!\n"
978       "pld [%[output]]\n"
979 
980       "bne 1b\n"
981       "2:"
982 
983       // Handle leftovers.
984 
985       // Requantize::Transform
986       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
987       "vld1.32 {d4[0]}, [%[input]]!\n"
988       "pld [%[input], #64]\n"
989       "vcvt.f32.s32 q0, q0\n"
990       "vcvt.f32.s32 q1, q1\n"
991       "vcvt.f32.s32 q2, q2\n"
992       "vsub.f32 q0, q0, q6\n"
993       "vsub.f32 q1, q1, q6\n"
994       "vsub.f32 q2, q2, q6\n"
995       "vmul.f32 q0, q0, q7\n"
996       "vmul.f32 q1, q1, q7\n"
997       "vmul.f32 q2, q2, q7\n"
998       "vadd.f32 q0, q0, q4\n"
999       "vadd.f32 q1, q1, q4\n"
1000       "vadd.f32 q2, q2, q4\n"
1001       "vmul.f32 q0, q0, q8\n"
1002       "vmul.f32 q1, q1, q8\n"
1003       "vmul.f32 q2, q2, q8\n"
1004       "vcvt.s32.f32 q0, q0\n"
1005       "vcvt.s32.f32 q1, q1\n"
1006       "vcvt.s32.f32 q2, q2\n"
1007       "vqmovn.s32 d0, q0\n"
1008       "vqmovn.s32 d1, q1\n"
1009       "vqmovn.s32 d4, q2\n"
1010       "vqmovun.s16 d0, q0\n"
1011       "vqmovun.s16 d1, q2\n"
1012 
1013       "vst1.32 {d0}, [%[output]]!\n"
1014       "vst1.8 {d1[0]}, [%[output]]!\n"
1015       "pld [%[output]]\n"
1016       : [count] "+r"(params_count_copy), [input] "+r"(input),
1017         [output] "+r"(output)
1018       : [input_range_min] "r"(params.input_range_min),
1019         [output_range_min] "r"(params.output_range_min),
1020         [input_range_offset] "r"(params.input_range_offset),
1021         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1022         [input_range_scale] "r"(params.input_range_scale)
1023       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1024         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1025 }
1026 
1027 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)1028 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 10>::Transform(
1029     const int32_t* input, const Requantize& params, uint8_t* output) {
1030 #ifdef DEBUG
1031 #ifdef DEBUG_METAGEMM_VERBOSE
1032   std::cout << __FILE__ << "(" << __LINE__
1033             << ") Requantize<int32_t, uint8_t, Requantize, 16, 10>::Transform()"
1034             << std::endl
1035             << std::flush;
1036 #endif
1037 #endif
1038   int params_count_copy = params.count;
1039   asm volatile(
1040 
1041       // Requantize::Prepare
1042       "vdup.32 q4, %[input_range_min]\n"
1043       "vdup.32 q5, %[output_range_min]\n"
1044       "vdup.32 q6, %[input_range_offset]\n"
1045       "vdup.32 q7, %[input_range_scale]\n"
1046       "vdup.32 q8, %[one_over_output_range_scale]\n"
1047       "vsub.f32 q4, q4, q5\n"
1048 
1049       // Reduce count by leftovers.
1050       "subs %[count], %[count], #10\n"
1051       "beq 2f\n"
1052 
1053       "1:"
1054       "subs %[count], %[count], #16\n"
1055 
1056       // Requantize::Transform
1057       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1058       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1059       "pld [%[input], #64]\n"
1060       "vcvt.f32.s32 q0, q0\n"
1061       "vcvt.f32.s32 q1, q1\n"
1062       "vcvt.f32.s32 q2, q2\n"
1063       "vcvt.f32.s32 q3, q3\n"
1064       "vsub.f32 q0, q0, q6\n"
1065       "vsub.f32 q1, q1, q6\n"
1066       "vsub.f32 q2, q2, q6\n"
1067       "vsub.f32 q3, q3, q6\n"
1068       "vmul.f32 q0, q0, q7\n"
1069       "vmul.f32 q1, q1, q7\n"
1070       "vmul.f32 q2, q2, q7\n"
1071       "vmul.f32 q3, q3, q7\n"
1072       "vadd.f32 q0, q0, q4\n"
1073       "vadd.f32 q1, q1, q4\n"
1074       "vadd.f32 q2, q2, q4\n"
1075       "vadd.f32 q3, q3, q4\n"
1076       "vmul.f32 q0, q0, q8\n"
1077       "vmul.f32 q1, q1, q8\n"
1078       "vmul.f32 q2, q2, q8\n"
1079       "vmul.f32 q3, q3, q8\n"
1080       "vcvt.s32.f32 q0, q0\n"
1081       "vcvt.s32.f32 q1, q1\n"
1082       "vcvt.s32.f32 q2, q2\n"
1083       "vcvt.s32.f32 q3, q3\n"
1084       "vqmovn.s32 d0, q0\n"
1085       "vqmovn.s32 d1, q1\n"
1086       "vqmovn.s32 d4, q2\n"
1087       "vqmovn.s32 d5, q3\n"
1088       "vqmovun.s16 d0, q0\n"
1089       "vqmovun.s16 d1, q2\n"
1090 
1091       "vst1.32 {d0, d1}, [%[output]]!\n"
1092       "pld [%[output]]\n"
1093 
1094       "bne 1b\n"
1095       "2:"
1096 
1097       // Handle leftovers.
1098 
1099       // Requantize::Transform
1100       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1101       "vld1.32 {d4}, [%[input]]!\n"
1102       "pld [%[input], #64]\n"
1103       "vcvt.f32.s32 q0, q0\n"
1104       "vcvt.f32.s32 q1, q1\n"
1105       "vcvt.f32.s32 q2, q2\n"
1106       "vsub.f32 q0, q0, q6\n"
1107       "vsub.f32 q1, q1, q6\n"
1108       "vsub.f32 q2, q2, q6\n"
1109       "vmul.f32 q0, q0, q7\n"
1110       "vmul.f32 q1, q1, q7\n"
1111       "vmul.f32 q2, q2, q7\n"
1112       "vadd.f32 q0, q0, q4\n"
1113       "vadd.f32 q1, q1, q4\n"
1114       "vadd.f32 q2, q2, q4\n"
1115       "vmul.f32 q0, q0, q8\n"
1116       "vmul.f32 q1, q1, q8\n"
1117       "vmul.f32 q2, q2, q8\n"
1118       "vcvt.s32.f32 q0, q0\n"
1119       "vcvt.s32.f32 q1, q1\n"
1120       "vcvt.s32.f32 q2, q2\n"
1121       "vqmovn.s32 d0, q0\n"
1122       "vqmovn.s32 d1, q1\n"
1123       "vqmovn.s32 d4, q2\n"
1124       "vqmovun.s16 d0, q0\n"
1125       "vqmovun.s16 d1, q2\n"
1126 
1127       "vst1.32 {d0}, [%[output]]!\n"
1128       "vst1.16 {d1[0]}, [%[output]]!\n"
1129       "pld [%[output]]\n"
1130       : [count] "+r"(params_count_copy), [input] "+r"(input),
1131         [output] "+r"(output)
1132       : [input_range_min] "r"(params.input_range_min),
1133         [output_range_min] "r"(params.output_range_min),
1134         [input_range_offset] "r"(params.input_range_offset),
1135         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1136         [input_range_scale] "r"(params.input_range_scale)
1137       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1138         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1139 }
1140 
1141 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)1142 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 11>::Transform(
1143     const int32_t* input, const Requantize& params, uint8_t* output) {
1144 #ifdef DEBUG
1145 #ifdef DEBUG_METAGEMM_VERBOSE
1146   std::cout << __FILE__ << "(" << __LINE__
1147             << ") Requantize<int32_t, uint8_t, Requantize, 16, 11>::Transform()"
1148             << std::endl
1149             << std::flush;
1150 #endif
1151 #endif
1152   int params_count_copy = params.count;
1153   asm volatile(
1154 
1155       // Requantize::Prepare
1156       "vdup.32 q4, %[input_range_min]\n"
1157       "vdup.32 q5, %[output_range_min]\n"
1158       "vdup.32 q6, %[input_range_offset]\n"
1159       "vdup.32 q7, %[input_range_scale]\n"
1160       "vdup.32 q8, %[one_over_output_range_scale]\n"
1161       "vsub.f32 q4, q4, q5\n"
1162 
1163       // Reduce count by leftovers.
1164       "subs %[count], %[count], #11\n"
1165       "beq 2f\n"
1166 
1167       "1:"
1168       "subs %[count], %[count], #16\n"
1169 
1170       // Requantize::Transform
1171       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1172       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1173       "pld [%[input], #64]\n"
1174       "vcvt.f32.s32 q0, q0\n"
1175       "vcvt.f32.s32 q1, q1\n"
1176       "vcvt.f32.s32 q2, q2\n"
1177       "vcvt.f32.s32 q3, q3\n"
1178       "vsub.f32 q0, q0, q6\n"
1179       "vsub.f32 q1, q1, q6\n"
1180       "vsub.f32 q2, q2, q6\n"
1181       "vsub.f32 q3, q3, q6\n"
1182       "vmul.f32 q0, q0, q7\n"
1183       "vmul.f32 q1, q1, q7\n"
1184       "vmul.f32 q2, q2, q7\n"
1185       "vmul.f32 q3, q3, q7\n"
1186       "vadd.f32 q0, q0, q4\n"
1187       "vadd.f32 q1, q1, q4\n"
1188       "vadd.f32 q2, q2, q4\n"
1189       "vadd.f32 q3, q3, q4\n"
1190       "vmul.f32 q0, q0, q8\n"
1191       "vmul.f32 q1, q1, q8\n"
1192       "vmul.f32 q2, q2, q8\n"
1193       "vmul.f32 q3, q3, q8\n"
1194       "vcvt.s32.f32 q0, q0\n"
1195       "vcvt.s32.f32 q1, q1\n"
1196       "vcvt.s32.f32 q2, q2\n"
1197       "vcvt.s32.f32 q3, q3\n"
1198       "vqmovn.s32 d0, q0\n"
1199       "vqmovn.s32 d1, q1\n"
1200       "vqmovn.s32 d4, q2\n"
1201       "vqmovn.s32 d5, q3\n"
1202       "vqmovun.s16 d0, q0\n"
1203       "vqmovun.s16 d1, q2\n"
1204 
1205       "vst1.32 {d0, d1}, [%[output]]!\n"
1206       "pld [%[output]]\n"
1207 
1208       "bne 1b\n"
1209       "2:"
1210 
1211       // Handle leftovers.
1212 
1213       // Requantize::Transform
1214       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1215       "vld1.32 {d4}, [%[input]]!\n"
1216       "vld1.32 {d5[0]}, [%[input]]!\n"
1217       "pld [%[input], #64]\n"
1218       "vcvt.f32.s32 q0, q0\n"
1219       "vcvt.f32.s32 q1, q1\n"
1220       "vcvt.f32.s32 q2, q2\n"
1221       "vsub.f32 q0, q0, q6\n"
1222       "vsub.f32 q1, q1, q6\n"
1223       "vsub.f32 q2, q2, q6\n"
1224       "vmul.f32 q0, q0, q7\n"
1225       "vmul.f32 q1, q1, q7\n"
1226       "vmul.f32 q2, q2, q7\n"
1227       "vadd.f32 q0, q0, q4\n"
1228       "vadd.f32 q1, q1, q4\n"
1229       "vadd.f32 q2, q2, q4\n"
1230       "vmul.f32 q0, q0, q8\n"
1231       "vmul.f32 q1, q1, q8\n"
1232       "vmul.f32 q2, q2, q8\n"
1233       "vcvt.s32.f32 q0, q0\n"
1234       "vcvt.s32.f32 q1, q1\n"
1235       "vcvt.s32.f32 q2, q2\n"
1236       "vqmovn.s32 d0, q0\n"
1237       "vqmovn.s32 d1, q1\n"
1238       "vqmovn.s32 d4, q2\n"
1239       "vqmovun.s16 d0, q0\n"
1240       "vqmovun.s16 d1, q2\n"
1241 
1242       "vst1.32 {d0}, [%[output]]!\n"
1243       "vst1.16 {d1[0]}, [%[output]]!\n"
1244       "vst1.8 {d1[2]}, [%[output]]!\n"
1245       "pld [%[output]]\n"
1246       : [count] "+r"(params_count_copy), [input] "+r"(input),
1247         [output] "+r"(output)
1248       : [input_range_min] "r"(params.input_range_min),
1249         [output_range_min] "r"(params.output_range_min),
1250         [input_range_offset] "r"(params.input_range_offset),
1251         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1252         [input_range_scale] "r"(params.input_range_scale)
1253       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1254         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1255 }
1256 
1257 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)1258 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 12>::Transform(
1259     const int32_t* input, const Requantize& params, uint8_t* output) {
1260 #ifdef DEBUG
1261 #ifdef DEBUG_METAGEMM_VERBOSE
1262   std::cout << __FILE__ << "(" << __LINE__
1263             << ") Requantize<int32_t, uint8_t, Requantize, 16, 12>::Transform()"
1264             << std::endl
1265             << std::flush;
1266 #endif
1267 #endif
1268   int params_count_copy = params.count;
1269   asm volatile(
1270 
1271       // Requantize::Prepare
1272       "vdup.32 q4, %[input_range_min]\n"
1273       "vdup.32 q5, %[output_range_min]\n"
1274       "vdup.32 q6, %[input_range_offset]\n"
1275       "vdup.32 q7, %[input_range_scale]\n"
1276       "vdup.32 q8, %[one_over_output_range_scale]\n"
1277       "vsub.f32 q4, q4, q5\n"
1278 
1279       // Reduce count by leftovers.
1280       "subs %[count], %[count], #12\n"
1281       "beq 2f\n"
1282 
1283       "1:"
1284       "subs %[count], %[count], #16\n"
1285 
1286       // Requantize::Transform
1287       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1288       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1289       "pld [%[input], #64]\n"
1290       "vcvt.f32.s32 q0, q0\n"
1291       "vcvt.f32.s32 q1, q1\n"
1292       "vcvt.f32.s32 q2, q2\n"
1293       "vcvt.f32.s32 q3, q3\n"
1294       "vsub.f32 q0, q0, q6\n"
1295       "vsub.f32 q1, q1, q6\n"
1296       "vsub.f32 q2, q2, q6\n"
1297       "vsub.f32 q3, q3, q6\n"
1298       "vmul.f32 q0, q0, q7\n"
1299       "vmul.f32 q1, q1, q7\n"
1300       "vmul.f32 q2, q2, q7\n"
1301       "vmul.f32 q3, q3, q7\n"
1302       "vadd.f32 q0, q0, q4\n"
1303       "vadd.f32 q1, q1, q4\n"
1304       "vadd.f32 q2, q2, q4\n"
1305       "vadd.f32 q3, q3, q4\n"
1306       "vmul.f32 q0, q0, q8\n"
1307       "vmul.f32 q1, q1, q8\n"
1308       "vmul.f32 q2, q2, q8\n"
1309       "vmul.f32 q3, q3, q8\n"
1310       "vcvt.s32.f32 q0, q0\n"
1311       "vcvt.s32.f32 q1, q1\n"
1312       "vcvt.s32.f32 q2, q2\n"
1313       "vcvt.s32.f32 q3, q3\n"
1314       "vqmovn.s32 d0, q0\n"
1315       "vqmovn.s32 d1, q1\n"
1316       "vqmovn.s32 d4, q2\n"
1317       "vqmovn.s32 d5, q3\n"
1318       "vqmovun.s16 d0, q0\n"
1319       "vqmovun.s16 d1, q2\n"
1320 
1321       "vst1.32 {d0, d1}, [%[output]]!\n"
1322       "pld [%[output]]\n"
1323 
1324       "bne 1b\n"
1325       "2:"
1326 
1327       // Handle leftovers.
1328 
1329       // Requantize::Transform
1330       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1331       "vld1.32 {d4, d5}, [%[input]]!\n"
1332       "pld [%[input], #64]\n"
1333       "vcvt.f32.s32 q0, q0\n"
1334       "vcvt.f32.s32 q1, q1\n"
1335       "vcvt.f32.s32 q2, q2\n"
1336       "vsub.f32 q0, q0, q6\n"
1337       "vsub.f32 q1, q1, q6\n"
1338       "vsub.f32 q2, q2, q6\n"
1339       "vmul.f32 q0, q0, q7\n"
1340       "vmul.f32 q1, q1, q7\n"
1341       "vmul.f32 q2, q2, q7\n"
1342       "vadd.f32 q0, q0, q4\n"
1343       "vadd.f32 q1, q1, q4\n"
1344       "vadd.f32 q2, q2, q4\n"
1345       "vmul.f32 q0, q0, q8\n"
1346       "vmul.f32 q1, q1, q8\n"
1347       "vmul.f32 q2, q2, q8\n"
1348       "vcvt.s32.f32 q0, q0\n"
1349       "vcvt.s32.f32 q1, q1\n"
1350       "vcvt.s32.f32 q2, q2\n"
1351       "vqmovn.s32 d0, q0\n"
1352       "vqmovn.s32 d1, q1\n"
1353       "vqmovn.s32 d4, q2\n"
1354       "vqmovun.s16 d0, q0\n"
1355       "vqmovun.s16 d1, q2\n"
1356 
1357       "vst1.32 {d0}, [%[output]]!\n"
1358       "vst1.32 {d1[0]}, [%[output]]!\n"
1359       "pld [%[output]]\n"
1360       : [count] "+r"(params_count_copy), [input] "+r"(input),
1361         [output] "+r"(output)
1362       : [input_range_min] "r"(params.input_range_min),
1363         [output_range_min] "r"(params.output_range_min),
1364         [input_range_offset] "r"(params.input_range_offset),
1365         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1366         [input_range_scale] "r"(params.input_range_scale)
1367       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1368         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1369 }
1370 
1371 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)1372 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 13>::Transform(
1373     const int32_t* input, const Requantize& params, uint8_t* output) {
1374 #ifdef DEBUG
1375 #ifdef DEBUG_METAGEMM_VERBOSE
1376   std::cout << __FILE__ << "(" << __LINE__
1377             << ") Requantize<int32_t, uint8_t, Requantize, 16, 13>::Transform()"
1378             << std::endl
1379             << std::flush;
1380 #endif
1381 #endif
1382   int params_count_copy = params.count;
1383   asm volatile(
1384 
1385       // Requantize::Prepare
1386       "vdup.32 q4, %[input_range_min]\n"
1387       "vdup.32 q5, %[output_range_min]\n"
1388       "vdup.32 q6, %[input_range_offset]\n"
1389       "vdup.32 q7, %[input_range_scale]\n"
1390       "vdup.32 q8, %[one_over_output_range_scale]\n"
1391       "vsub.f32 q4, q4, q5\n"
1392 
1393       // Reduce count by leftovers.
1394       "subs %[count], %[count], #13\n"
1395       "beq 2f\n"
1396 
1397       "1:"
1398       "subs %[count], %[count], #16\n"
1399 
1400       // Requantize::Transform
1401       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1402       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1403       "pld [%[input], #64]\n"
1404       "vcvt.f32.s32 q0, q0\n"
1405       "vcvt.f32.s32 q1, q1\n"
1406       "vcvt.f32.s32 q2, q2\n"
1407       "vcvt.f32.s32 q3, q3\n"
1408       "vsub.f32 q0, q0, q6\n"
1409       "vsub.f32 q1, q1, q6\n"
1410       "vsub.f32 q2, q2, q6\n"
1411       "vsub.f32 q3, q3, q6\n"
1412       "vmul.f32 q0, q0, q7\n"
1413       "vmul.f32 q1, q1, q7\n"
1414       "vmul.f32 q2, q2, q7\n"
1415       "vmul.f32 q3, q3, q7\n"
1416       "vadd.f32 q0, q0, q4\n"
1417       "vadd.f32 q1, q1, q4\n"
1418       "vadd.f32 q2, q2, q4\n"
1419       "vadd.f32 q3, q3, q4\n"
1420       "vmul.f32 q0, q0, q8\n"
1421       "vmul.f32 q1, q1, q8\n"
1422       "vmul.f32 q2, q2, q8\n"
1423       "vmul.f32 q3, q3, q8\n"
1424       "vcvt.s32.f32 q0, q0\n"
1425       "vcvt.s32.f32 q1, q1\n"
1426       "vcvt.s32.f32 q2, q2\n"
1427       "vcvt.s32.f32 q3, q3\n"
1428       "vqmovn.s32 d0, q0\n"
1429       "vqmovn.s32 d1, q1\n"
1430       "vqmovn.s32 d4, q2\n"
1431       "vqmovn.s32 d5, q3\n"
1432       "vqmovun.s16 d0, q0\n"
1433       "vqmovun.s16 d1, q2\n"
1434 
1435       "vst1.32 {d0, d1}, [%[output]]!\n"
1436       "pld [%[output]]\n"
1437 
1438       "bne 1b\n"
1439       "2:"
1440 
1441       // Handle leftovers.
1442 
1443       // Requantize::Transform
1444       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1445       "vld1.32 {d4, d5}, [%[input]]!\n"
1446       "vld1.32 {d6[0]}, [%[input]]!\n"
1447       "pld [%[input], #64]\n"
1448       "vcvt.f32.s32 q0, q0\n"
1449       "vcvt.f32.s32 q1, q1\n"
1450       "vcvt.f32.s32 q2, q2\n"
1451       "vcvt.f32.s32 q3, q3\n"
1452       "vsub.f32 q0, q0, q6\n"
1453       "vsub.f32 q1, q1, q6\n"
1454       "vsub.f32 q2, q2, q6\n"
1455       "vsub.f32 q3, q3, q6\n"
1456       "vmul.f32 q0, q0, q7\n"
1457       "vmul.f32 q1, q1, q7\n"
1458       "vmul.f32 q2, q2, q7\n"
1459       "vmul.f32 q3, q3, q7\n"
1460       "vadd.f32 q0, q0, q4\n"
1461       "vadd.f32 q1, q1, q4\n"
1462       "vadd.f32 q2, q2, q4\n"
1463       "vadd.f32 q3, q3, q4\n"
1464       "vmul.f32 q0, q0, q8\n"
1465       "vmul.f32 q1, q1, q8\n"
1466       "vmul.f32 q2, q2, q8\n"
1467       "vmul.f32 q3, q3, q8\n"
1468       "vcvt.s32.f32 q0, q0\n"
1469       "vcvt.s32.f32 q1, q1\n"
1470       "vcvt.s32.f32 q2, q2\n"
1471       "vcvt.s32.f32 q3, q3\n"
1472       "vqmovn.s32 d0, q0\n"
1473       "vqmovn.s32 d1, q1\n"
1474       "vqmovn.s32 d4, q2\n"
1475       "vqmovn.s32 d5, q3\n"
1476       "vqmovun.s16 d0, q0\n"
1477       "vqmovun.s16 d1, q2\n"
1478 
1479       "vst1.32 {d0}, [%[output]]!\n"
1480       "vst1.32 {d1[0]}, [%[output]]!\n"
1481       "vst1.8 {d1[4]}, [%[output]]!\n"
1482       "pld [%[output]]\n"
1483       : [count] "+r"(params_count_copy), [input] "+r"(input),
1484         [output] "+r"(output)
1485       : [input_range_min] "r"(params.input_range_min),
1486         [output_range_min] "r"(params.output_range_min),
1487         [input_range_offset] "r"(params.input_range_offset),
1488         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1489         [input_range_scale] "r"(params.input_range_scale)
1490       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1491         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1492 }
1493 
1494 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)1495 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 14>::Transform(
1496     const int32_t* input, const Requantize& params, uint8_t* output) {
1497 #ifdef DEBUG
1498 #ifdef DEBUG_METAGEMM_VERBOSE
1499   std::cout << __FILE__ << "(" << __LINE__
1500             << ") Requantize<int32_t, uint8_t, Requantize, 16, 14>::Transform()"
1501             << std::endl
1502             << std::flush;
1503 #endif
1504 #endif
1505   int params_count_copy = params.count;
1506   asm volatile(
1507 
1508       // Requantize::Prepare
1509       "vdup.32 q4, %[input_range_min]\n"
1510       "vdup.32 q5, %[output_range_min]\n"
1511       "vdup.32 q6, %[input_range_offset]\n"
1512       "vdup.32 q7, %[input_range_scale]\n"
1513       "vdup.32 q8, %[one_over_output_range_scale]\n"
1514       "vsub.f32 q4, q4, q5\n"
1515 
1516       // Reduce count by leftovers.
1517       "subs %[count], %[count], #14\n"
1518       "beq 2f\n"
1519 
1520       "1:"
1521       "subs %[count], %[count], #16\n"
1522 
1523       // Requantize::Transform
1524       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1525       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1526       "pld [%[input], #64]\n"
1527       "vcvt.f32.s32 q0, q0\n"
1528       "vcvt.f32.s32 q1, q1\n"
1529       "vcvt.f32.s32 q2, q2\n"
1530       "vcvt.f32.s32 q3, q3\n"
1531       "vsub.f32 q0, q0, q6\n"
1532       "vsub.f32 q1, q1, q6\n"
1533       "vsub.f32 q2, q2, q6\n"
1534       "vsub.f32 q3, q3, q6\n"
1535       "vmul.f32 q0, q0, q7\n"
1536       "vmul.f32 q1, q1, q7\n"
1537       "vmul.f32 q2, q2, q7\n"
1538       "vmul.f32 q3, q3, q7\n"
1539       "vadd.f32 q0, q0, q4\n"
1540       "vadd.f32 q1, q1, q4\n"
1541       "vadd.f32 q2, q2, q4\n"
1542       "vadd.f32 q3, q3, q4\n"
1543       "vmul.f32 q0, q0, q8\n"
1544       "vmul.f32 q1, q1, q8\n"
1545       "vmul.f32 q2, q2, q8\n"
1546       "vmul.f32 q3, q3, q8\n"
1547       "vcvt.s32.f32 q0, q0\n"
1548       "vcvt.s32.f32 q1, q1\n"
1549       "vcvt.s32.f32 q2, q2\n"
1550       "vcvt.s32.f32 q3, q3\n"
1551       "vqmovn.s32 d0, q0\n"
1552       "vqmovn.s32 d1, q1\n"
1553       "vqmovn.s32 d4, q2\n"
1554       "vqmovn.s32 d5, q3\n"
1555       "vqmovun.s16 d0, q0\n"
1556       "vqmovun.s16 d1, q2\n"
1557 
1558       "vst1.32 {d0, d1}, [%[output]]!\n"
1559       "pld [%[output]]\n"
1560 
1561       "bne 1b\n"
1562       "2:"
1563 
1564       // Handle leftovers.
1565 
1566       // Requantize::Transform
1567       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1568       "vld1.32 {d4, d5, d6}, [%[input]]!\n"
1569       "pld [%[input], #64]\n"
1570       "vcvt.f32.s32 q0, q0\n"
1571       "vcvt.f32.s32 q1, q1\n"
1572       "vcvt.f32.s32 q2, q2\n"
1573       "vcvt.f32.s32 q3, q3\n"
1574       "vsub.f32 q0, q0, q6\n"
1575       "vsub.f32 q1, q1, q6\n"
1576       "vsub.f32 q2, q2, q6\n"
1577       "vsub.f32 q3, q3, q6\n"
1578       "vmul.f32 q0, q0, q7\n"
1579       "vmul.f32 q1, q1, q7\n"
1580       "vmul.f32 q2, q2, q7\n"
1581       "vmul.f32 q3, q3, q7\n"
1582       "vadd.f32 q0, q0, q4\n"
1583       "vadd.f32 q1, q1, q4\n"
1584       "vadd.f32 q2, q2, q4\n"
1585       "vadd.f32 q3, q3, q4\n"
1586       "vmul.f32 q0, q0, q8\n"
1587       "vmul.f32 q1, q1, q8\n"
1588       "vmul.f32 q2, q2, q8\n"
1589       "vmul.f32 q3, q3, q8\n"
1590       "vcvt.s32.f32 q0, q0\n"
1591       "vcvt.s32.f32 q1, q1\n"
1592       "vcvt.s32.f32 q2, q2\n"
1593       "vcvt.s32.f32 q3, q3\n"
1594       "vqmovn.s32 d0, q0\n"
1595       "vqmovn.s32 d1, q1\n"
1596       "vqmovn.s32 d4, q2\n"
1597       "vqmovn.s32 d5, q3\n"
1598       "vqmovun.s16 d0, q0\n"
1599       "vqmovun.s16 d1, q2\n"
1600 
1601       "vst1.32 {d0}, [%[output]]!\n"
1602       "vst1.32 {d1[0]}, [%[output]]!\n"
1603       "vst1.16 {d1[2]}, [%[output]]!\n"
1604       "pld [%[output]]\n"
1605       : [count] "+r"(params_count_copy), [input] "+r"(input),
1606         [output] "+r"(output)
1607       : [input_range_min] "r"(params.input_range_min),
1608         [output_range_min] "r"(params.output_range_min),
1609         [input_range_offset] "r"(params.input_range_offset),
1610         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1611         [input_range_scale] "r"(params.input_range_scale)
1612       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1613         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1614 }
1615 
1616 template <>
Transform(const int32_t * input,const Requantize & params,uint8_t * output)1617 inline void Transform1DKernel<int32_t, uint8_t, Requantize, 16, 15>::Transform(
1618     const int32_t* input, const Requantize& params, uint8_t* output) {
1619 #ifdef DEBUG
1620 #ifdef DEBUG_METAGEMM_VERBOSE
1621   std::cout << __FILE__ << "(" << __LINE__
1622             << ") Requantize<int32_t, uint8_t, Requantize, 16, 15>::Transform()"
1623             << std::endl
1624             << std::flush;
1625 #endif
1626 #endif
1627   int params_count_copy = params.count;
1628   asm volatile(
1629 
1630       // Requantize::Prepare
1631       "vdup.32 q4, %[input_range_min]\n"
1632       "vdup.32 q5, %[output_range_min]\n"
1633       "vdup.32 q6, %[input_range_offset]\n"
1634       "vdup.32 q7, %[input_range_scale]\n"
1635       "vdup.32 q8, %[one_over_output_range_scale]\n"
1636       "vsub.f32 q4, q4, q5\n"
1637 
1638       // Reduce count by leftovers.
1639       "subs %[count], %[count], #15\n"
1640       "beq 2f\n"
1641 
1642       "1:"
1643       "subs %[count], %[count], #16\n"
1644 
1645       // Requantize::Transform
1646       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1647       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1648       "pld [%[input], #64]\n"
1649       "vcvt.f32.s32 q0, q0\n"
1650       "vcvt.f32.s32 q1, q1\n"
1651       "vcvt.f32.s32 q2, q2\n"
1652       "vcvt.f32.s32 q3, q3\n"
1653       "vsub.f32 q0, q0, q6\n"
1654       "vsub.f32 q1, q1, q6\n"
1655       "vsub.f32 q2, q2, q6\n"
1656       "vsub.f32 q3, q3, q6\n"
1657       "vmul.f32 q0, q0, q7\n"
1658       "vmul.f32 q1, q1, q7\n"
1659       "vmul.f32 q2, q2, q7\n"
1660       "vmul.f32 q3, q3, q7\n"
1661       "vadd.f32 q0, q0, q4\n"
1662       "vadd.f32 q1, q1, q4\n"
1663       "vadd.f32 q2, q2, q4\n"
1664       "vadd.f32 q3, q3, q4\n"
1665       "vmul.f32 q0, q0, q8\n"
1666       "vmul.f32 q1, q1, q8\n"
1667       "vmul.f32 q2, q2, q8\n"
1668       "vmul.f32 q3, q3, q8\n"
1669       "vcvt.s32.f32 q0, q0\n"
1670       "vcvt.s32.f32 q1, q1\n"
1671       "vcvt.s32.f32 q2, q2\n"
1672       "vcvt.s32.f32 q3, q3\n"
1673       "vqmovn.s32 d0, q0\n"
1674       "vqmovn.s32 d1, q1\n"
1675       "vqmovn.s32 d4, q2\n"
1676       "vqmovn.s32 d5, q3\n"
1677       "vqmovun.s16 d0, q0\n"
1678       "vqmovun.s16 d1, q2\n"
1679 
1680       "vst1.32 {d0, d1}, [%[output]]!\n"
1681       "pld [%[output]]\n"
1682 
1683       "bne 1b\n"
1684       "2:"
1685 
1686       // Handle leftovers.
1687 
1688       // Requantize::Transform
1689       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1690       "vld1.32 {d4, d5, d6}, [%[input]]!\n"
1691       "vld1.32 {d7[0]}, [%[input]]!\n"
1692       "pld [%[input], #64]\n"
1693       "vcvt.f32.s32 q0, q0\n"
1694       "vcvt.f32.s32 q1, q1\n"
1695       "vcvt.f32.s32 q2, q2\n"
1696       "vcvt.f32.s32 q3, q3\n"
1697       "vsub.f32 q0, q0, q6\n"
1698       "vsub.f32 q1, q1, q6\n"
1699       "vsub.f32 q2, q2, q6\n"
1700       "vsub.f32 q3, q3, q6\n"
1701       "vmul.f32 q0, q0, q7\n"
1702       "vmul.f32 q1, q1, q7\n"
1703       "vmul.f32 q2, q2, q7\n"
1704       "vmul.f32 q3, q3, q7\n"
1705       "vadd.f32 q0, q0, q4\n"
1706       "vadd.f32 q1, q1, q4\n"
1707       "vadd.f32 q2, q2, q4\n"
1708       "vadd.f32 q3, q3, q4\n"
1709       "vmul.f32 q0, q0, q8\n"
1710       "vmul.f32 q1, q1, q8\n"
1711       "vmul.f32 q2, q2, q8\n"
1712       "vmul.f32 q3, q3, q8\n"
1713       "vcvt.s32.f32 q0, q0\n"
1714       "vcvt.s32.f32 q1, q1\n"
1715       "vcvt.s32.f32 q2, q2\n"
1716       "vcvt.s32.f32 q3, q3\n"
1717       "vqmovn.s32 d0, q0\n"
1718       "vqmovn.s32 d1, q1\n"
1719       "vqmovn.s32 d4, q2\n"
1720       "vqmovn.s32 d5, q3\n"
1721       "vqmovun.s16 d0, q0\n"
1722       "vqmovun.s16 d1, q2\n"
1723 
1724       "vst1.32 {d0}, [%[output]]!\n"
1725       "vst1.32 {d1[0]}, [%[output]]!\n"
1726       "vst1.16 {d1[2]}, [%[output]]!\n"
1727       "vst1.8 {d1[6]}, [%[output]]!\n"
1728       "pld [%[output]]\n"
1729       : [count] "+r"(params_count_copy), [input] "+r"(input),
1730         [output] "+r"(output)
1731       : [input_range_min] "r"(params.input_range_min),
1732         [output_range_min] "r"(params.output_range_min),
1733         [input_range_offset] "r"(params.input_range_offset),
1734         [one_over_output_range_scale] "r"(params.one_over_output_range_scale),
1735         [input_range_scale] "r"(params.input_range_scale)
1736       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1737         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "cc", "memory");
1738 }
1739 
1740 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)1741 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 0>::Transform(
1742     const float* input, const Quantize& params, uint8_t* output) {
1743 #ifdef DEBUG
1744 #ifdef DEBUG_METAGEMM_VERBOSE
1745   std::cout << __FILE__ << "(" << __LINE__
1746             << ") Quantize<float, uint8_t, Quantize, 16, 0>::Transform()"
1747             << std::endl
1748             << std::flush;
1749 #endif
1750 #endif
1751   int params_count_copy = params.count;
1752   asm volatile(
1753 
1754       // Quantize::Prepare
1755       "vdup.32 q4, %[range_min]\n"
1756       "vdup.32 q5, %[range_offset]\n"
1757       "vdup.32 q6, %[range_scale]\n"
1758 
1759       "1:"
1760       "subs %[count], %[count], #16\n"
1761 
1762       // Quantize::Transform
1763       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1764       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1765       "pld [%[input], #64]\n"
1766       "vsub.f32 q0, q0, q4\n"
1767       "vsub.f32 q1, q1, q4\n"
1768       "vsub.f32 q2, q2, q4\n"
1769       "vsub.f32 q3, q3, q4\n"
1770       "vmul.f32 q0, q0, q6\n"
1771       "vmul.f32 q1, q1, q6\n"
1772       "vmul.f32 q2, q2, q6\n"
1773       "vmul.f32 q3, q3, q6\n"
1774       "vadd.f32 q0, q0, q5\n"
1775       "vadd.f32 q1, q1, q5\n"
1776       "vadd.f32 q2, q2, q5\n"
1777       "vadd.f32 q3, q3, q5\n"
1778       "vcvt.s32.f32 q0, q0\n"
1779       "vcvt.s32.f32 q1, q1\n"
1780       "vcvt.s32.f32 q2, q2\n"
1781       "vcvt.s32.f32 q3, q3\n"
1782       "vqmovn.s32 d0, q0\n"
1783       "vqmovn.s32 d1, q1\n"
1784       "vqmovn.s32 d4, q2\n"
1785       "vqmovn.s32 d5, q3\n"
1786       "vqmovun.s16 d0, q0\n"
1787       "vqmovun.s16 d1, q2\n"
1788 
1789       "vst1.32 {d0, d1}, [%[output]]!\n"
1790       "pld [%[output]]\n"
1791 
1792       "bne 1b\n"
1793       : [count] "+r"(params_count_copy), [input] "+r"(input),
1794         [output] "+r"(output)
1795       : [range_offset] "r"(params.range_offset),
1796         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
1797       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1798         "d11", "d12", "d13", "cc", "memory");
1799 }
1800 
1801 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)1802 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 1>::Transform(
1803     const float* input, const Quantize& params, uint8_t* output) {
1804 #ifdef DEBUG
1805 #ifdef DEBUG_METAGEMM_VERBOSE
1806   std::cout << __FILE__ << "(" << __LINE__
1807             << ") Quantize<float, uint8_t, Quantize, 16, 1>::Transform()"
1808             << std::endl
1809             << std::flush;
1810 #endif
1811 #endif
1812   int params_count_copy = params.count;
1813   asm volatile(
1814 
1815       // Quantize::Prepare
1816       "vdup.32 q4, %[range_min]\n"
1817       "vdup.32 q5, %[range_offset]\n"
1818       "vdup.32 q6, %[range_scale]\n"
1819 
1820       // Reduce count by leftovers.
1821       "subs %[count], %[count], #1\n"
1822       "beq 2f\n"
1823 
1824       "1:"
1825       "subs %[count], %[count], #16\n"
1826 
1827       // Quantize::Transform
1828       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1829       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1830       "pld [%[input], #64]\n"
1831       "vsub.f32 q0, q0, q4\n"
1832       "vsub.f32 q1, q1, q4\n"
1833       "vsub.f32 q2, q2, q4\n"
1834       "vsub.f32 q3, q3, q4\n"
1835       "vmul.f32 q0, q0, q6\n"
1836       "vmul.f32 q1, q1, q6\n"
1837       "vmul.f32 q2, q2, q6\n"
1838       "vmul.f32 q3, q3, q6\n"
1839       "vadd.f32 q0, q0, q5\n"
1840       "vadd.f32 q1, q1, q5\n"
1841       "vadd.f32 q2, q2, q5\n"
1842       "vadd.f32 q3, q3, q5\n"
1843       "vcvt.s32.f32 q0, q0\n"
1844       "vcvt.s32.f32 q1, q1\n"
1845       "vcvt.s32.f32 q2, q2\n"
1846       "vcvt.s32.f32 q3, q3\n"
1847       "vqmovn.s32 d0, q0\n"
1848       "vqmovn.s32 d1, q1\n"
1849       "vqmovn.s32 d4, q2\n"
1850       "vqmovn.s32 d5, q3\n"
1851       "vqmovun.s16 d0, q0\n"
1852       "vqmovun.s16 d1, q2\n"
1853 
1854       "vst1.32 {d0, d1}, [%[output]]!\n"
1855       "pld [%[output]]\n"
1856 
1857       "bne 1b\n"
1858       "2:"
1859 
1860       // Handle leftovers.
1861 
1862       // Quantize::Transform
1863       "vld1.32 {d0[0]}, [%[input]]!\n"
1864       "pld [%[input], #64]\n"
1865       "vsub.f32 q0, q0, q4\n"
1866       "vmul.f32 q0, q0, q6\n"
1867       "vadd.f32 q0, q0, q5\n"
1868       "vcvt.s32.f32 q0, q0\n"
1869       "vqmovn.s32 d0, q0\n"
1870       "vqmovun.s16 d0, q0\n"
1871 
1872       "vst1.8 {d0[0]}, [%[output]]!\n"
1873       "pld [%[output]]\n"
1874       : [count] "+r"(params_count_copy), [input] "+r"(input),
1875         [output] "+r"(output)
1876       : [range_offset] "r"(params.range_offset),
1877         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
1878       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1879         "d11", "d12", "d13", "cc", "memory");
1880 }
1881 
1882 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)1883 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 2>::Transform(
1884     const float* input, const Quantize& params, uint8_t* output) {
1885 #ifdef DEBUG
1886 #ifdef DEBUG_METAGEMM_VERBOSE
1887   std::cout << __FILE__ << "(" << __LINE__
1888             << ") Quantize<float, uint8_t, Quantize, 16, 2>::Transform()"
1889             << std::endl
1890             << std::flush;
1891 #endif
1892 #endif
1893   int params_count_copy = params.count;
1894   asm volatile(
1895 
1896       // Quantize::Prepare
1897       "vdup.32 q4, %[range_min]\n"
1898       "vdup.32 q5, %[range_offset]\n"
1899       "vdup.32 q6, %[range_scale]\n"
1900 
1901       // Reduce count by leftovers.
1902       "subs %[count], %[count], #2\n"
1903       "beq 2f\n"
1904 
1905       "1:"
1906       "subs %[count], %[count], #16\n"
1907 
1908       // Quantize::Transform
1909       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1910       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1911       "pld [%[input], #64]\n"
1912       "vsub.f32 q0, q0, q4\n"
1913       "vsub.f32 q1, q1, q4\n"
1914       "vsub.f32 q2, q2, q4\n"
1915       "vsub.f32 q3, q3, q4\n"
1916       "vmul.f32 q0, q0, q6\n"
1917       "vmul.f32 q1, q1, q6\n"
1918       "vmul.f32 q2, q2, q6\n"
1919       "vmul.f32 q3, q3, q6\n"
1920       "vadd.f32 q0, q0, q5\n"
1921       "vadd.f32 q1, q1, q5\n"
1922       "vadd.f32 q2, q2, q5\n"
1923       "vadd.f32 q3, q3, q5\n"
1924       "vcvt.s32.f32 q0, q0\n"
1925       "vcvt.s32.f32 q1, q1\n"
1926       "vcvt.s32.f32 q2, q2\n"
1927       "vcvt.s32.f32 q3, q3\n"
1928       "vqmovn.s32 d0, q0\n"
1929       "vqmovn.s32 d1, q1\n"
1930       "vqmovn.s32 d4, q2\n"
1931       "vqmovn.s32 d5, q3\n"
1932       "vqmovun.s16 d0, q0\n"
1933       "vqmovun.s16 d1, q2\n"
1934 
1935       "vst1.32 {d0, d1}, [%[output]]!\n"
1936       "pld [%[output]]\n"
1937 
1938       "bne 1b\n"
1939       "2:"
1940 
1941       // Handle leftovers.
1942 
1943       // Quantize::Transform
1944       "vld1.32 {d0}, [%[input]]!\n"
1945       "pld [%[input], #64]\n"
1946       "vsub.f32 q0, q0, q4\n"
1947       "vmul.f32 q0, q0, q6\n"
1948       "vadd.f32 q0, q0, q5\n"
1949       "vcvt.s32.f32 q0, q0\n"
1950       "vqmovn.s32 d0, q0\n"
1951       "vqmovun.s16 d0, q0\n"
1952 
1953       "vst1.16 {d0[0]}, [%[output]]!\n"
1954       "pld [%[output]]\n"
1955       : [count] "+r"(params_count_copy), [input] "+r"(input),
1956         [output] "+r"(output)
1957       : [range_offset] "r"(params.range_offset),
1958         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
1959       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
1960         "d11", "d12", "d13", "cc", "memory");
1961 }
1962 
1963 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)1964 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 3>::Transform(
1965     const float* input, const Quantize& params, uint8_t* output) {
1966 #ifdef DEBUG
1967 #ifdef DEBUG_METAGEMM_VERBOSE
1968   std::cout << __FILE__ << "(" << __LINE__
1969             << ") Quantize<float, uint8_t, Quantize, 16, 3>::Transform()"
1970             << std::endl
1971             << std::flush;
1972 #endif
1973 #endif
1974   int params_count_copy = params.count;
1975   asm volatile(
1976 
1977       // Quantize::Prepare
1978       "vdup.32 q4, %[range_min]\n"
1979       "vdup.32 q5, %[range_offset]\n"
1980       "vdup.32 q6, %[range_scale]\n"
1981 
1982       // Reduce count by leftovers.
1983       "subs %[count], %[count], #3\n"
1984       "beq 2f\n"
1985 
1986       "1:"
1987       "subs %[count], %[count], #16\n"
1988 
1989       // Quantize::Transform
1990       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
1991       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
1992       "pld [%[input], #64]\n"
1993       "vsub.f32 q0, q0, q4\n"
1994       "vsub.f32 q1, q1, q4\n"
1995       "vsub.f32 q2, q2, q4\n"
1996       "vsub.f32 q3, q3, q4\n"
1997       "vmul.f32 q0, q0, q6\n"
1998       "vmul.f32 q1, q1, q6\n"
1999       "vmul.f32 q2, q2, q6\n"
2000       "vmul.f32 q3, q3, q6\n"
2001       "vadd.f32 q0, q0, q5\n"
2002       "vadd.f32 q1, q1, q5\n"
2003       "vadd.f32 q2, q2, q5\n"
2004       "vadd.f32 q3, q3, q5\n"
2005       "vcvt.s32.f32 q0, q0\n"
2006       "vcvt.s32.f32 q1, q1\n"
2007       "vcvt.s32.f32 q2, q2\n"
2008       "vcvt.s32.f32 q3, q3\n"
2009       "vqmovn.s32 d0, q0\n"
2010       "vqmovn.s32 d1, q1\n"
2011       "vqmovn.s32 d4, q2\n"
2012       "vqmovn.s32 d5, q3\n"
2013       "vqmovun.s16 d0, q0\n"
2014       "vqmovun.s16 d1, q2\n"
2015 
2016       "vst1.32 {d0, d1}, [%[output]]!\n"
2017       "pld [%[output]]\n"
2018 
2019       "bne 1b\n"
2020       "2:"
2021 
2022       // Handle leftovers.
2023 
2024       // Quantize::Transform
2025       "vld1.32 {d0}, [%[input]]!\n"
2026       "vld1.32 {d1[0]}, [%[input]]!\n"
2027       "pld [%[input], #64]\n"
2028       "vsub.f32 q0, q0, q4\n"
2029       "vmul.f32 q0, q0, q6\n"
2030       "vadd.f32 q0, q0, q5\n"
2031       "vcvt.s32.f32 q0, q0\n"
2032       "vqmovn.s32 d0, q0\n"
2033       "vqmovun.s16 d0, q0\n"
2034 
2035       "vst1.16 {d0[0]}, [%[output]]!\n"
2036       "vst1.8 {d0[2]}, [%[output]]!\n"
2037       "pld [%[output]]\n"
2038       : [count] "+r"(params_count_copy), [input] "+r"(input),
2039         [output] "+r"(output)
2040       : [range_offset] "r"(params.range_offset),
2041         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2042       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2043         "d11", "d12", "d13", "cc", "memory");
2044 }
2045 
2046 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2047 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 4>::Transform(
2048     const float* input, const Quantize& params, uint8_t* output) {
2049 #ifdef DEBUG
2050 #ifdef DEBUG_METAGEMM_VERBOSE
2051   std::cout << __FILE__ << "(" << __LINE__
2052             << ") Quantize<float, uint8_t, Quantize, 16, 4>::Transform()"
2053             << std::endl
2054             << std::flush;
2055 #endif
2056 #endif
2057   int params_count_copy = params.count;
2058   asm volatile(
2059 
2060       // Quantize::Prepare
2061       "vdup.32 q4, %[range_min]\n"
2062       "vdup.32 q5, %[range_offset]\n"
2063       "vdup.32 q6, %[range_scale]\n"
2064 
2065       // Reduce count by leftovers.
2066       "subs %[count], %[count], #4\n"
2067       "beq 2f\n"
2068 
2069       "1:"
2070       "subs %[count], %[count], #16\n"
2071 
2072       // Quantize::Transform
2073       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2074       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2075       "pld [%[input], #64]\n"
2076       "vsub.f32 q0, q0, q4\n"
2077       "vsub.f32 q1, q1, q4\n"
2078       "vsub.f32 q2, q2, q4\n"
2079       "vsub.f32 q3, q3, q4\n"
2080       "vmul.f32 q0, q0, q6\n"
2081       "vmul.f32 q1, q1, q6\n"
2082       "vmul.f32 q2, q2, q6\n"
2083       "vmul.f32 q3, q3, q6\n"
2084       "vadd.f32 q0, q0, q5\n"
2085       "vadd.f32 q1, q1, q5\n"
2086       "vadd.f32 q2, q2, q5\n"
2087       "vadd.f32 q3, q3, q5\n"
2088       "vcvt.s32.f32 q0, q0\n"
2089       "vcvt.s32.f32 q1, q1\n"
2090       "vcvt.s32.f32 q2, q2\n"
2091       "vcvt.s32.f32 q3, q3\n"
2092       "vqmovn.s32 d0, q0\n"
2093       "vqmovn.s32 d1, q1\n"
2094       "vqmovn.s32 d4, q2\n"
2095       "vqmovn.s32 d5, q3\n"
2096       "vqmovun.s16 d0, q0\n"
2097       "vqmovun.s16 d1, q2\n"
2098 
2099       "vst1.32 {d0, d1}, [%[output]]!\n"
2100       "pld [%[output]]\n"
2101 
2102       "bne 1b\n"
2103       "2:"
2104 
2105       // Handle leftovers.
2106 
2107       // Quantize::Transform
2108       "vld1.32 {d0, d1}, [%[input]]!\n"
2109       "pld [%[input], #64]\n"
2110       "vsub.f32 q0, q0, q4\n"
2111       "vmul.f32 q0, q0, q6\n"
2112       "vadd.f32 q0, q0, q5\n"
2113       "vcvt.s32.f32 q0, q0\n"
2114       "vqmovn.s32 d0, q0\n"
2115       "vqmovun.s16 d0, q0\n"
2116 
2117       "vst1.32 {d0[0]}, [%[output]]!\n"
2118       "pld [%[output]]\n"
2119       : [count] "+r"(params_count_copy), [input] "+r"(input),
2120         [output] "+r"(output)
2121       : [range_offset] "r"(params.range_offset),
2122         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2123       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2124         "d11", "d12", "d13", "cc", "memory");
2125 }
2126 
2127 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2128 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 5>::Transform(
2129     const float* input, const Quantize& params, uint8_t* output) {
2130 #ifdef DEBUG
2131 #ifdef DEBUG_METAGEMM_VERBOSE
2132   std::cout << __FILE__ << "(" << __LINE__
2133             << ") Quantize<float, uint8_t, Quantize, 16, 5>::Transform()"
2134             << std::endl
2135             << std::flush;
2136 #endif
2137 #endif
2138   int params_count_copy = params.count;
2139   asm volatile(
2140 
2141       // Quantize::Prepare
2142       "vdup.32 q4, %[range_min]\n"
2143       "vdup.32 q5, %[range_offset]\n"
2144       "vdup.32 q6, %[range_scale]\n"
2145 
2146       // Reduce count by leftovers.
2147       "subs %[count], %[count], #5\n"
2148       "beq 2f\n"
2149 
2150       "1:"
2151       "subs %[count], %[count], #16\n"
2152 
2153       // Quantize::Transform
2154       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2155       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2156       "pld [%[input], #64]\n"
2157       "vsub.f32 q0, q0, q4\n"
2158       "vsub.f32 q1, q1, q4\n"
2159       "vsub.f32 q2, q2, q4\n"
2160       "vsub.f32 q3, q3, q4\n"
2161       "vmul.f32 q0, q0, q6\n"
2162       "vmul.f32 q1, q1, q6\n"
2163       "vmul.f32 q2, q2, q6\n"
2164       "vmul.f32 q3, q3, q6\n"
2165       "vadd.f32 q0, q0, q5\n"
2166       "vadd.f32 q1, q1, q5\n"
2167       "vadd.f32 q2, q2, q5\n"
2168       "vadd.f32 q3, q3, q5\n"
2169       "vcvt.s32.f32 q0, q0\n"
2170       "vcvt.s32.f32 q1, q1\n"
2171       "vcvt.s32.f32 q2, q2\n"
2172       "vcvt.s32.f32 q3, q3\n"
2173       "vqmovn.s32 d0, q0\n"
2174       "vqmovn.s32 d1, q1\n"
2175       "vqmovn.s32 d4, q2\n"
2176       "vqmovn.s32 d5, q3\n"
2177       "vqmovun.s16 d0, q0\n"
2178       "vqmovun.s16 d1, q2\n"
2179 
2180       "vst1.32 {d0, d1}, [%[output]]!\n"
2181       "pld [%[output]]\n"
2182 
2183       "bne 1b\n"
2184       "2:"
2185 
2186       // Handle leftovers.
2187 
2188       // Quantize::Transform
2189       "vld1.32 {d0, d1}, [%[input]]!\n"
2190       "vld1.32 {d2[0]}, [%[input]]!\n"
2191       "pld [%[input], #64]\n"
2192       "vsub.f32 q0, q0, q4\n"
2193       "vsub.f32 q1, q1, q4\n"
2194       "vmul.f32 q0, q0, q6\n"
2195       "vmul.f32 q1, q1, q6\n"
2196       "vadd.f32 q0, q0, q5\n"
2197       "vadd.f32 q1, q1, q5\n"
2198       "vcvt.s32.f32 q0, q0\n"
2199       "vcvt.s32.f32 q1, q1\n"
2200       "vqmovn.s32 d0, q0\n"
2201       "vqmovn.s32 d1, q1\n"
2202       "vqmovun.s16 d0, q0\n"
2203 
2204       "vst1.32 {d0[0]}, [%[output]]!\n"
2205       "vst1.8 {d0[4]}, [%[output]]!\n"
2206       "pld [%[output]]\n"
2207       : [count] "+r"(params_count_copy), [input] "+r"(input),
2208         [output] "+r"(output)
2209       : [range_offset] "r"(params.range_offset),
2210         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2211       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2212         "d11", "d12", "d13", "cc", "memory");
2213 }
2214 
2215 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2216 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 6>::Transform(
2217     const float* input, const Quantize& params, uint8_t* output) {
2218 #ifdef DEBUG
2219 #ifdef DEBUG_METAGEMM_VERBOSE
2220   std::cout << __FILE__ << "(" << __LINE__
2221             << ") Quantize<float, uint8_t, Quantize, 16, 6>::Transform()"
2222             << std::endl
2223             << std::flush;
2224 #endif
2225 #endif
2226   int params_count_copy = params.count;
2227   asm volatile(
2228 
2229       // Quantize::Prepare
2230       "vdup.32 q4, %[range_min]\n"
2231       "vdup.32 q5, %[range_offset]\n"
2232       "vdup.32 q6, %[range_scale]\n"
2233 
2234       // Reduce count by leftovers.
2235       "subs %[count], %[count], #6\n"
2236       "beq 2f\n"
2237 
2238       "1:"
2239       "subs %[count], %[count], #16\n"
2240 
2241       // Quantize::Transform
2242       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2243       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2244       "pld [%[input], #64]\n"
2245       "vsub.f32 q0, q0, q4\n"
2246       "vsub.f32 q1, q1, q4\n"
2247       "vsub.f32 q2, q2, q4\n"
2248       "vsub.f32 q3, q3, q4\n"
2249       "vmul.f32 q0, q0, q6\n"
2250       "vmul.f32 q1, q1, q6\n"
2251       "vmul.f32 q2, q2, q6\n"
2252       "vmul.f32 q3, q3, q6\n"
2253       "vadd.f32 q0, q0, q5\n"
2254       "vadd.f32 q1, q1, q5\n"
2255       "vadd.f32 q2, q2, q5\n"
2256       "vadd.f32 q3, q3, q5\n"
2257       "vcvt.s32.f32 q0, q0\n"
2258       "vcvt.s32.f32 q1, q1\n"
2259       "vcvt.s32.f32 q2, q2\n"
2260       "vcvt.s32.f32 q3, q3\n"
2261       "vqmovn.s32 d0, q0\n"
2262       "vqmovn.s32 d1, q1\n"
2263       "vqmovn.s32 d4, q2\n"
2264       "vqmovn.s32 d5, q3\n"
2265       "vqmovun.s16 d0, q0\n"
2266       "vqmovun.s16 d1, q2\n"
2267 
2268       "vst1.32 {d0, d1}, [%[output]]!\n"
2269       "pld [%[output]]\n"
2270 
2271       "bne 1b\n"
2272       "2:"
2273 
2274       // Handle leftovers.
2275 
2276       // Quantize::Transform
2277       "vld1.32 {d0, d1, d2}, [%[input]]!\n"
2278       "pld [%[input], #64]\n"
2279       "vsub.f32 q0, q0, q4\n"
2280       "vsub.f32 q1, q1, q4\n"
2281       "vmul.f32 q0, q0, q6\n"
2282       "vmul.f32 q1, q1, q6\n"
2283       "vadd.f32 q0, q0, q5\n"
2284       "vadd.f32 q1, q1, q5\n"
2285       "vcvt.s32.f32 q0, q0\n"
2286       "vcvt.s32.f32 q1, q1\n"
2287       "vqmovn.s32 d0, q0\n"
2288       "vqmovn.s32 d1, q1\n"
2289       "vqmovun.s16 d0, q0\n"
2290 
2291       "vst1.32 {d0[0]}, [%[output]]!\n"
2292       "vst1.16 {d0[2]}, [%[output]]!\n"
2293       "pld [%[output]]\n"
2294       : [count] "+r"(params_count_copy), [input] "+r"(input),
2295         [output] "+r"(output)
2296       : [range_offset] "r"(params.range_offset),
2297         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2298       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2299         "d11", "d12", "d13", "cc", "memory");
2300 }
2301 
2302 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2303 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 7>::Transform(
2304     const float* input, const Quantize& params, uint8_t* output) {
2305 #ifdef DEBUG
2306 #ifdef DEBUG_METAGEMM_VERBOSE
2307   std::cout << __FILE__ << "(" << __LINE__
2308             << ") Quantize<float, uint8_t, Quantize, 16, 7>::Transform()"
2309             << std::endl
2310             << std::flush;
2311 #endif
2312 #endif
2313   int params_count_copy = params.count;
2314   asm volatile(
2315 
2316       // Quantize::Prepare
2317       "vdup.32 q4, %[range_min]\n"
2318       "vdup.32 q5, %[range_offset]\n"
2319       "vdup.32 q6, %[range_scale]\n"
2320 
2321       // Reduce count by leftovers.
2322       "subs %[count], %[count], #7\n"
2323       "beq 2f\n"
2324 
2325       "1:"
2326       "subs %[count], %[count], #16\n"
2327 
2328       // Quantize::Transform
2329       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2330       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2331       "pld [%[input], #64]\n"
2332       "vsub.f32 q0, q0, q4\n"
2333       "vsub.f32 q1, q1, q4\n"
2334       "vsub.f32 q2, q2, q4\n"
2335       "vsub.f32 q3, q3, q4\n"
2336       "vmul.f32 q0, q0, q6\n"
2337       "vmul.f32 q1, q1, q6\n"
2338       "vmul.f32 q2, q2, q6\n"
2339       "vmul.f32 q3, q3, q6\n"
2340       "vadd.f32 q0, q0, q5\n"
2341       "vadd.f32 q1, q1, q5\n"
2342       "vadd.f32 q2, q2, q5\n"
2343       "vadd.f32 q3, q3, q5\n"
2344       "vcvt.s32.f32 q0, q0\n"
2345       "vcvt.s32.f32 q1, q1\n"
2346       "vcvt.s32.f32 q2, q2\n"
2347       "vcvt.s32.f32 q3, q3\n"
2348       "vqmovn.s32 d0, q0\n"
2349       "vqmovn.s32 d1, q1\n"
2350       "vqmovn.s32 d4, q2\n"
2351       "vqmovn.s32 d5, q3\n"
2352       "vqmovun.s16 d0, q0\n"
2353       "vqmovun.s16 d1, q2\n"
2354 
2355       "vst1.32 {d0, d1}, [%[output]]!\n"
2356       "pld [%[output]]\n"
2357 
2358       "bne 1b\n"
2359       "2:"
2360 
2361       // Handle leftovers.
2362 
2363       // Quantize::Transform
2364       "vld1.32 {d0, d1, d2}, [%[input]]!\n"
2365       "vld1.32 {d3[0]}, [%[input]]!\n"
2366       "pld [%[input], #64]\n"
2367       "vsub.f32 q0, q0, q4\n"
2368       "vsub.f32 q1, q1, q4\n"
2369       "vmul.f32 q0, q0, q6\n"
2370       "vmul.f32 q1, q1, q6\n"
2371       "vadd.f32 q0, q0, q5\n"
2372       "vadd.f32 q1, q1, q5\n"
2373       "vcvt.s32.f32 q0, q0\n"
2374       "vcvt.s32.f32 q1, q1\n"
2375       "vqmovn.s32 d0, q0\n"
2376       "vqmovn.s32 d1, q1\n"
2377       "vqmovun.s16 d0, q0\n"
2378 
2379       "vst1.32 {d0[0]}, [%[output]]!\n"
2380       "vst1.16 {d0[2]}, [%[output]]!\n"
2381       "vst1.8 {d0[6]}, [%[output]]!\n"
2382       "pld [%[output]]\n"
2383       : [count] "+r"(params_count_copy), [input] "+r"(input),
2384         [output] "+r"(output)
2385       : [range_offset] "r"(params.range_offset),
2386         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2387       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2388         "d11", "d12", "d13", "cc", "memory");
2389 }
2390 
2391 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2392 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 8>::Transform(
2393     const float* input, const Quantize& params, uint8_t* output) {
2394 #ifdef DEBUG
2395 #ifdef DEBUG_METAGEMM_VERBOSE
2396   std::cout << __FILE__ << "(" << __LINE__
2397             << ") Quantize<float, uint8_t, Quantize, 16, 8>::Transform()"
2398             << std::endl
2399             << std::flush;
2400 #endif
2401 #endif
2402   int params_count_copy = params.count;
2403   asm volatile(
2404 
2405       // Quantize::Prepare
2406       "vdup.32 q4, %[range_min]\n"
2407       "vdup.32 q5, %[range_offset]\n"
2408       "vdup.32 q6, %[range_scale]\n"
2409 
2410       // Reduce count by leftovers.
2411       "subs %[count], %[count], #8\n"
2412       "beq 2f\n"
2413 
2414       "1:"
2415       "subs %[count], %[count], #16\n"
2416 
2417       // Quantize::Transform
2418       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2419       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2420       "pld [%[input], #64]\n"
2421       "vsub.f32 q0, q0, q4\n"
2422       "vsub.f32 q1, q1, q4\n"
2423       "vsub.f32 q2, q2, q4\n"
2424       "vsub.f32 q3, q3, q4\n"
2425       "vmul.f32 q0, q0, q6\n"
2426       "vmul.f32 q1, q1, q6\n"
2427       "vmul.f32 q2, q2, q6\n"
2428       "vmul.f32 q3, q3, q6\n"
2429       "vadd.f32 q0, q0, q5\n"
2430       "vadd.f32 q1, q1, q5\n"
2431       "vadd.f32 q2, q2, q5\n"
2432       "vadd.f32 q3, q3, q5\n"
2433       "vcvt.s32.f32 q0, q0\n"
2434       "vcvt.s32.f32 q1, q1\n"
2435       "vcvt.s32.f32 q2, q2\n"
2436       "vcvt.s32.f32 q3, q3\n"
2437       "vqmovn.s32 d0, q0\n"
2438       "vqmovn.s32 d1, q1\n"
2439       "vqmovn.s32 d4, q2\n"
2440       "vqmovn.s32 d5, q3\n"
2441       "vqmovun.s16 d0, q0\n"
2442       "vqmovun.s16 d1, q2\n"
2443 
2444       "vst1.32 {d0, d1}, [%[output]]!\n"
2445       "pld [%[output]]\n"
2446 
2447       "bne 1b\n"
2448       "2:"
2449 
2450       // Handle leftovers.
2451 
2452       // Quantize::Transform
2453       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2454       "pld [%[input], #64]\n"
2455       "vsub.f32 q0, q0, q4\n"
2456       "vsub.f32 q1, q1, q4\n"
2457       "vmul.f32 q0, q0, q6\n"
2458       "vmul.f32 q1, q1, q6\n"
2459       "vadd.f32 q0, q0, q5\n"
2460       "vadd.f32 q1, q1, q5\n"
2461       "vcvt.s32.f32 q0, q0\n"
2462       "vcvt.s32.f32 q1, q1\n"
2463       "vqmovn.s32 d0, q0\n"
2464       "vqmovn.s32 d1, q1\n"
2465       "vqmovun.s16 d0, q0\n"
2466 
2467       "vst1.32 {d0}, [%[output]]!\n"
2468       "pld [%[output]]\n"
2469       : [count] "+r"(params_count_copy), [input] "+r"(input),
2470         [output] "+r"(output)
2471       : [range_offset] "r"(params.range_offset),
2472         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2473       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2474         "d11", "d12", "d13", "cc", "memory");
2475 }
2476 
2477 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2478 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 9>::Transform(
2479     const float* input, const Quantize& params, uint8_t* output) {
2480 #ifdef DEBUG
2481 #ifdef DEBUG_METAGEMM_VERBOSE
2482   std::cout << __FILE__ << "(" << __LINE__
2483             << ") Quantize<float, uint8_t, Quantize, 16, 9>::Transform()"
2484             << std::endl
2485             << std::flush;
2486 #endif
2487 #endif
2488   int params_count_copy = params.count;
2489   asm volatile(
2490 
2491       // Quantize::Prepare
2492       "vdup.32 q4, %[range_min]\n"
2493       "vdup.32 q5, %[range_offset]\n"
2494       "vdup.32 q6, %[range_scale]\n"
2495 
2496       // Reduce count by leftovers.
2497       "subs %[count], %[count], #9\n"
2498       "beq 2f\n"
2499 
2500       "1:"
2501       "subs %[count], %[count], #16\n"
2502 
2503       // Quantize::Transform
2504       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2505       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2506       "pld [%[input], #64]\n"
2507       "vsub.f32 q0, q0, q4\n"
2508       "vsub.f32 q1, q1, q4\n"
2509       "vsub.f32 q2, q2, q4\n"
2510       "vsub.f32 q3, q3, q4\n"
2511       "vmul.f32 q0, q0, q6\n"
2512       "vmul.f32 q1, q1, q6\n"
2513       "vmul.f32 q2, q2, q6\n"
2514       "vmul.f32 q3, q3, q6\n"
2515       "vadd.f32 q0, q0, q5\n"
2516       "vadd.f32 q1, q1, q5\n"
2517       "vadd.f32 q2, q2, q5\n"
2518       "vadd.f32 q3, q3, q5\n"
2519       "vcvt.s32.f32 q0, q0\n"
2520       "vcvt.s32.f32 q1, q1\n"
2521       "vcvt.s32.f32 q2, q2\n"
2522       "vcvt.s32.f32 q3, q3\n"
2523       "vqmovn.s32 d0, q0\n"
2524       "vqmovn.s32 d1, q1\n"
2525       "vqmovn.s32 d4, q2\n"
2526       "vqmovn.s32 d5, q3\n"
2527       "vqmovun.s16 d0, q0\n"
2528       "vqmovun.s16 d1, q2\n"
2529 
2530       "vst1.32 {d0, d1}, [%[output]]!\n"
2531       "pld [%[output]]\n"
2532 
2533       "bne 1b\n"
2534       "2:"
2535 
2536       // Handle leftovers.
2537 
2538       // Quantize::Transform
2539       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2540       "vld1.32 {d4[0]}, [%[input]]!\n"
2541       "pld [%[input], #64]\n"
2542       "vsub.f32 q0, q0, q4\n"
2543       "vsub.f32 q1, q1, q4\n"
2544       "vsub.f32 q2, q2, q4\n"
2545       "vmul.f32 q0, q0, q6\n"
2546       "vmul.f32 q1, q1, q6\n"
2547       "vmul.f32 q2, q2, q6\n"
2548       "vadd.f32 q0, q0, q5\n"
2549       "vadd.f32 q1, q1, q5\n"
2550       "vadd.f32 q2, q2, q5\n"
2551       "vcvt.s32.f32 q0, q0\n"
2552       "vcvt.s32.f32 q1, q1\n"
2553       "vcvt.s32.f32 q2, q2\n"
2554       "vqmovn.s32 d0, q0\n"
2555       "vqmovn.s32 d1, q1\n"
2556       "vqmovn.s32 d4, q2\n"
2557       "vqmovun.s16 d0, q0\n"
2558       "vqmovun.s16 d1, q2\n"
2559 
2560       "vst1.32 {d0}, [%[output]]!\n"
2561       "vst1.8 {d1[0]}, [%[output]]!\n"
2562       "pld [%[output]]\n"
2563       : [count] "+r"(params_count_copy), [input] "+r"(input),
2564         [output] "+r"(output)
2565       : [range_offset] "r"(params.range_offset),
2566         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2567       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2568         "d11", "d12", "d13", "cc", "memory");
2569 }
2570 
2571 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2572 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 10>::Transform(
2573     const float* input, const Quantize& params, uint8_t* output) {
2574 #ifdef DEBUG
2575 #ifdef DEBUG_METAGEMM_VERBOSE
2576   std::cout << __FILE__ << "(" << __LINE__
2577             << ") Quantize<float, uint8_t, Quantize, 16, 10>::Transform()"
2578             << std::endl
2579             << std::flush;
2580 #endif
2581 #endif
2582   int params_count_copy = params.count;
2583   asm volatile(
2584 
2585       // Quantize::Prepare
2586       "vdup.32 q4, %[range_min]\n"
2587       "vdup.32 q5, %[range_offset]\n"
2588       "vdup.32 q6, %[range_scale]\n"
2589 
2590       // Reduce count by leftovers.
2591       "subs %[count], %[count], #10\n"
2592       "beq 2f\n"
2593 
2594       "1:"
2595       "subs %[count], %[count], #16\n"
2596 
2597       // Quantize::Transform
2598       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2599       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2600       "pld [%[input], #64]\n"
2601       "vsub.f32 q0, q0, q4\n"
2602       "vsub.f32 q1, q1, q4\n"
2603       "vsub.f32 q2, q2, q4\n"
2604       "vsub.f32 q3, q3, q4\n"
2605       "vmul.f32 q0, q0, q6\n"
2606       "vmul.f32 q1, q1, q6\n"
2607       "vmul.f32 q2, q2, q6\n"
2608       "vmul.f32 q3, q3, q6\n"
2609       "vadd.f32 q0, q0, q5\n"
2610       "vadd.f32 q1, q1, q5\n"
2611       "vadd.f32 q2, q2, q5\n"
2612       "vadd.f32 q3, q3, q5\n"
2613       "vcvt.s32.f32 q0, q0\n"
2614       "vcvt.s32.f32 q1, q1\n"
2615       "vcvt.s32.f32 q2, q2\n"
2616       "vcvt.s32.f32 q3, q3\n"
2617       "vqmovn.s32 d0, q0\n"
2618       "vqmovn.s32 d1, q1\n"
2619       "vqmovn.s32 d4, q2\n"
2620       "vqmovn.s32 d5, q3\n"
2621       "vqmovun.s16 d0, q0\n"
2622       "vqmovun.s16 d1, q2\n"
2623 
2624       "vst1.32 {d0, d1}, [%[output]]!\n"
2625       "pld [%[output]]\n"
2626 
2627       "bne 1b\n"
2628       "2:"
2629 
2630       // Handle leftovers.
2631 
2632       // Quantize::Transform
2633       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2634       "vld1.32 {d4}, [%[input]]!\n"
2635       "pld [%[input], #64]\n"
2636       "vsub.f32 q0, q0, q4\n"
2637       "vsub.f32 q1, q1, q4\n"
2638       "vsub.f32 q2, q2, q4\n"
2639       "vmul.f32 q0, q0, q6\n"
2640       "vmul.f32 q1, q1, q6\n"
2641       "vmul.f32 q2, q2, q6\n"
2642       "vadd.f32 q0, q0, q5\n"
2643       "vadd.f32 q1, q1, q5\n"
2644       "vadd.f32 q2, q2, q5\n"
2645       "vcvt.s32.f32 q0, q0\n"
2646       "vcvt.s32.f32 q1, q1\n"
2647       "vcvt.s32.f32 q2, q2\n"
2648       "vqmovn.s32 d0, q0\n"
2649       "vqmovn.s32 d1, q1\n"
2650       "vqmovn.s32 d4, q2\n"
2651       "vqmovun.s16 d0, q0\n"
2652       "vqmovun.s16 d1, q2\n"
2653 
2654       "vst1.32 {d0}, [%[output]]!\n"
2655       "vst1.16 {d1[0]}, [%[output]]!\n"
2656       "pld [%[output]]\n"
2657       : [count] "+r"(params_count_copy), [input] "+r"(input),
2658         [output] "+r"(output)
2659       : [range_offset] "r"(params.range_offset),
2660         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2661       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2662         "d11", "d12", "d13", "cc", "memory");
2663 }
2664 
2665 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2666 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 11>::Transform(
2667     const float* input, const Quantize& params, uint8_t* output) {
2668 #ifdef DEBUG
2669 #ifdef DEBUG_METAGEMM_VERBOSE
2670   std::cout << __FILE__ << "(" << __LINE__
2671             << ") Quantize<float, uint8_t, Quantize, 16, 11>::Transform()"
2672             << std::endl
2673             << std::flush;
2674 #endif
2675 #endif
2676   int params_count_copy = params.count;
2677   asm volatile(
2678 
2679       // Quantize::Prepare
2680       "vdup.32 q4, %[range_min]\n"
2681       "vdup.32 q5, %[range_offset]\n"
2682       "vdup.32 q6, %[range_scale]\n"
2683 
2684       // Reduce count by leftovers.
2685       "subs %[count], %[count], #11\n"
2686       "beq 2f\n"
2687 
2688       "1:"
2689       "subs %[count], %[count], #16\n"
2690 
2691       // Quantize::Transform
2692       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2693       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2694       "pld [%[input], #64]\n"
2695       "vsub.f32 q0, q0, q4\n"
2696       "vsub.f32 q1, q1, q4\n"
2697       "vsub.f32 q2, q2, q4\n"
2698       "vsub.f32 q3, q3, q4\n"
2699       "vmul.f32 q0, q0, q6\n"
2700       "vmul.f32 q1, q1, q6\n"
2701       "vmul.f32 q2, q2, q6\n"
2702       "vmul.f32 q3, q3, q6\n"
2703       "vadd.f32 q0, q0, q5\n"
2704       "vadd.f32 q1, q1, q5\n"
2705       "vadd.f32 q2, q2, q5\n"
2706       "vadd.f32 q3, q3, q5\n"
2707       "vcvt.s32.f32 q0, q0\n"
2708       "vcvt.s32.f32 q1, q1\n"
2709       "vcvt.s32.f32 q2, q2\n"
2710       "vcvt.s32.f32 q3, q3\n"
2711       "vqmovn.s32 d0, q0\n"
2712       "vqmovn.s32 d1, q1\n"
2713       "vqmovn.s32 d4, q2\n"
2714       "vqmovn.s32 d5, q3\n"
2715       "vqmovun.s16 d0, q0\n"
2716       "vqmovun.s16 d1, q2\n"
2717 
2718       "vst1.32 {d0, d1}, [%[output]]!\n"
2719       "pld [%[output]]\n"
2720 
2721       "bne 1b\n"
2722       "2:"
2723 
2724       // Handle leftovers.
2725 
2726       // Quantize::Transform
2727       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2728       "vld1.32 {d4}, [%[input]]!\n"
2729       "vld1.32 {d5[0]}, [%[input]]!\n"
2730       "pld [%[input], #64]\n"
2731       "vsub.f32 q0, q0, q4\n"
2732       "vsub.f32 q1, q1, q4\n"
2733       "vsub.f32 q2, q2, q4\n"
2734       "vmul.f32 q0, q0, q6\n"
2735       "vmul.f32 q1, q1, q6\n"
2736       "vmul.f32 q2, q2, q6\n"
2737       "vadd.f32 q0, q0, q5\n"
2738       "vadd.f32 q1, q1, q5\n"
2739       "vadd.f32 q2, q2, q5\n"
2740       "vcvt.s32.f32 q0, q0\n"
2741       "vcvt.s32.f32 q1, q1\n"
2742       "vcvt.s32.f32 q2, q2\n"
2743       "vqmovn.s32 d0, q0\n"
2744       "vqmovn.s32 d1, q1\n"
2745       "vqmovn.s32 d4, q2\n"
2746       "vqmovun.s16 d0, q0\n"
2747       "vqmovun.s16 d1, q2\n"
2748 
2749       "vst1.32 {d0}, [%[output]]!\n"
2750       "vst1.16 {d1[0]}, [%[output]]!\n"
2751       "vst1.8 {d1[2]}, [%[output]]!\n"
2752       "pld [%[output]]\n"
2753       : [count] "+r"(params_count_copy), [input] "+r"(input),
2754         [output] "+r"(output)
2755       : [range_offset] "r"(params.range_offset),
2756         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2757       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2758         "d11", "d12", "d13", "cc", "memory");
2759 }
2760 
2761 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2762 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 12>::Transform(
2763     const float* input, const Quantize& params, uint8_t* output) {
2764 #ifdef DEBUG
2765 #ifdef DEBUG_METAGEMM_VERBOSE
2766   std::cout << __FILE__ << "(" << __LINE__
2767             << ") Quantize<float, uint8_t, Quantize, 16, 12>::Transform()"
2768             << std::endl
2769             << std::flush;
2770 #endif
2771 #endif
2772   int params_count_copy = params.count;
2773   asm volatile(
2774 
2775       // Quantize::Prepare
2776       "vdup.32 q4, %[range_min]\n"
2777       "vdup.32 q5, %[range_offset]\n"
2778       "vdup.32 q6, %[range_scale]\n"
2779 
2780       // Reduce count by leftovers.
2781       "subs %[count], %[count], #12\n"
2782       "beq 2f\n"
2783 
2784       "1:"
2785       "subs %[count], %[count], #16\n"
2786 
2787       // Quantize::Transform
2788       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2789       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2790       "pld [%[input], #64]\n"
2791       "vsub.f32 q0, q0, q4\n"
2792       "vsub.f32 q1, q1, q4\n"
2793       "vsub.f32 q2, q2, q4\n"
2794       "vsub.f32 q3, q3, q4\n"
2795       "vmul.f32 q0, q0, q6\n"
2796       "vmul.f32 q1, q1, q6\n"
2797       "vmul.f32 q2, q2, q6\n"
2798       "vmul.f32 q3, q3, q6\n"
2799       "vadd.f32 q0, q0, q5\n"
2800       "vadd.f32 q1, q1, q5\n"
2801       "vadd.f32 q2, q2, q5\n"
2802       "vadd.f32 q3, q3, q5\n"
2803       "vcvt.s32.f32 q0, q0\n"
2804       "vcvt.s32.f32 q1, q1\n"
2805       "vcvt.s32.f32 q2, q2\n"
2806       "vcvt.s32.f32 q3, q3\n"
2807       "vqmovn.s32 d0, q0\n"
2808       "vqmovn.s32 d1, q1\n"
2809       "vqmovn.s32 d4, q2\n"
2810       "vqmovn.s32 d5, q3\n"
2811       "vqmovun.s16 d0, q0\n"
2812       "vqmovun.s16 d1, q2\n"
2813 
2814       "vst1.32 {d0, d1}, [%[output]]!\n"
2815       "pld [%[output]]\n"
2816 
2817       "bne 1b\n"
2818       "2:"
2819 
2820       // Handle leftovers.
2821 
2822       // Quantize::Transform
2823       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2824       "vld1.32 {d4, d5}, [%[input]]!\n"
2825       "pld [%[input], #64]\n"
2826       "vsub.f32 q0, q0, q4\n"
2827       "vsub.f32 q1, q1, q4\n"
2828       "vsub.f32 q2, q2, q4\n"
2829       "vmul.f32 q0, q0, q6\n"
2830       "vmul.f32 q1, q1, q6\n"
2831       "vmul.f32 q2, q2, q6\n"
2832       "vadd.f32 q0, q0, q5\n"
2833       "vadd.f32 q1, q1, q5\n"
2834       "vadd.f32 q2, q2, q5\n"
2835       "vcvt.s32.f32 q0, q0\n"
2836       "vcvt.s32.f32 q1, q1\n"
2837       "vcvt.s32.f32 q2, q2\n"
2838       "vqmovn.s32 d0, q0\n"
2839       "vqmovn.s32 d1, q1\n"
2840       "vqmovn.s32 d4, q2\n"
2841       "vqmovun.s16 d0, q0\n"
2842       "vqmovun.s16 d1, q2\n"
2843 
2844       "vst1.32 {d0}, [%[output]]!\n"
2845       "vst1.32 {d1[0]}, [%[output]]!\n"
2846       "pld [%[output]]\n"
2847       : [count] "+r"(params_count_copy), [input] "+r"(input),
2848         [output] "+r"(output)
2849       : [range_offset] "r"(params.range_offset),
2850         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2851       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2852         "d11", "d12", "d13", "cc", "memory");
2853 }
2854 
2855 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2856 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 13>::Transform(
2857     const float* input, const Quantize& params, uint8_t* output) {
2858 #ifdef DEBUG
2859 #ifdef DEBUG_METAGEMM_VERBOSE
2860   std::cout << __FILE__ << "(" << __LINE__
2861             << ") Quantize<float, uint8_t, Quantize, 16, 13>::Transform()"
2862             << std::endl
2863             << std::flush;
2864 #endif
2865 #endif
2866   int params_count_copy = params.count;
2867   asm volatile(
2868 
2869       // Quantize::Prepare
2870       "vdup.32 q4, %[range_min]\n"
2871       "vdup.32 q5, %[range_offset]\n"
2872       "vdup.32 q6, %[range_scale]\n"
2873 
2874       // Reduce count by leftovers.
2875       "subs %[count], %[count], #13\n"
2876       "beq 2f\n"
2877 
2878       "1:"
2879       "subs %[count], %[count], #16\n"
2880 
2881       // Quantize::Transform
2882       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2883       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2884       "pld [%[input], #64]\n"
2885       "vsub.f32 q0, q0, q4\n"
2886       "vsub.f32 q1, q1, q4\n"
2887       "vsub.f32 q2, q2, q4\n"
2888       "vsub.f32 q3, q3, q4\n"
2889       "vmul.f32 q0, q0, q6\n"
2890       "vmul.f32 q1, q1, q6\n"
2891       "vmul.f32 q2, q2, q6\n"
2892       "vmul.f32 q3, q3, q6\n"
2893       "vadd.f32 q0, q0, q5\n"
2894       "vadd.f32 q1, q1, q5\n"
2895       "vadd.f32 q2, q2, q5\n"
2896       "vadd.f32 q3, q3, q5\n"
2897       "vcvt.s32.f32 q0, q0\n"
2898       "vcvt.s32.f32 q1, q1\n"
2899       "vcvt.s32.f32 q2, q2\n"
2900       "vcvt.s32.f32 q3, q3\n"
2901       "vqmovn.s32 d0, q0\n"
2902       "vqmovn.s32 d1, q1\n"
2903       "vqmovn.s32 d4, q2\n"
2904       "vqmovn.s32 d5, q3\n"
2905       "vqmovun.s16 d0, q0\n"
2906       "vqmovun.s16 d1, q2\n"
2907 
2908       "vst1.32 {d0, d1}, [%[output]]!\n"
2909       "pld [%[output]]\n"
2910 
2911       "bne 1b\n"
2912       "2:"
2913 
2914       // Handle leftovers.
2915 
2916       // Quantize::Transform
2917       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2918       "vld1.32 {d4, d5}, [%[input]]!\n"
2919       "vld1.32 {d6[0]}, [%[input]]!\n"
2920       "pld [%[input], #64]\n"
2921       "vsub.f32 q0, q0, q4\n"
2922       "vsub.f32 q1, q1, q4\n"
2923       "vsub.f32 q2, q2, q4\n"
2924       "vsub.f32 q3, q3, q4\n"
2925       "vmul.f32 q0, q0, q6\n"
2926       "vmul.f32 q1, q1, q6\n"
2927       "vmul.f32 q2, q2, q6\n"
2928       "vmul.f32 q3, q3, q6\n"
2929       "vadd.f32 q0, q0, q5\n"
2930       "vadd.f32 q1, q1, q5\n"
2931       "vadd.f32 q2, q2, q5\n"
2932       "vadd.f32 q3, q3, q5\n"
2933       "vcvt.s32.f32 q0, q0\n"
2934       "vcvt.s32.f32 q1, q1\n"
2935       "vcvt.s32.f32 q2, q2\n"
2936       "vcvt.s32.f32 q3, q3\n"
2937       "vqmovn.s32 d0, q0\n"
2938       "vqmovn.s32 d1, q1\n"
2939       "vqmovn.s32 d4, q2\n"
2940       "vqmovn.s32 d5, q3\n"
2941       "vqmovun.s16 d0, q0\n"
2942       "vqmovun.s16 d1, q2\n"
2943 
2944       "vst1.32 {d0}, [%[output]]!\n"
2945       "vst1.32 {d1[0]}, [%[output]]!\n"
2946       "vst1.8 {d1[4]}, [%[output]]!\n"
2947       "pld [%[output]]\n"
2948       : [count] "+r"(params_count_copy), [input] "+r"(input),
2949         [output] "+r"(output)
2950       : [range_offset] "r"(params.range_offset),
2951         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
2952       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
2953         "d11", "d12", "d13", "cc", "memory");
2954 }
2955 
2956 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)2957 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 14>::Transform(
2958     const float* input, const Quantize& params, uint8_t* output) {
2959 #ifdef DEBUG
2960 #ifdef DEBUG_METAGEMM_VERBOSE
2961   std::cout << __FILE__ << "(" << __LINE__
2962             << ") Quantize<float, uint8_t, Quantize, 16, 14>::Transform()"
2963             << std::endl
2964             << std::flush;
2965 #endif
2966 #endif
2967   int params_count_copy = params.count;
2968   asm volatile(
2969 
2970       // Quantize::Prepare
2971       "vdup.32 q4, %[range_min]\n"
2972       "vdup.32 q5, %[range_offset]\n"
2973       "vdup.32 q6, %[range_scale]\n"
2974 
2975       // Reduce count by leftovers.
2976       "subs %[count], %[count], #14\n"
2977       "beq 2f\n"
2978 
2979       "1:"
2980       "subs %[count], %[count], #16\n"
2981 
2982       // Quantize::Transform
2983       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
2984       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
2985       "pld [%[input], #64]\n"
2986       "vsub.f32 q0, q0, q4\n"
2987       "vsub.f32 q1, q1, q4\n"
2988       "vsub.f32 q2, q2, q4\n"
2989       "vsub.f32 q3, q3, q4\n"
2990       "vmul.f32 q0, q0, q6\n"
2991       "vmul.f32 q1, q1, q6\n"
2992       "vmul.f32 q2, q2, q6\n"
2993       "vmul.f32 q3, q3, q6\n"
2994       "vadd.f32 q0, q0, q5\n"
2995       "vadd.f32 q1, q1, q5\n"
2996       "vadd.f32 q2, q2, q5\n"
2997       "vadd.f32 q3, q3, q5\n"
2998       "vcvt.s32.f32 q0, q0\n"
2999       "vcvt.s32.f32 q1, q1\n"
3000       "vcvt.s32.f32 q2, q2\n"
3001       "vcvt.s32.f32 q3, q3\n"
3002       "vqmovn.s32 d0, q0\n"
3003       "vqmovn.s32 d1, q1\n"
3004       "vqmovn.s32 d4, q2\n"
3005       "vqmovn.s32 d5, q3\n"
3006       "vqmovun.s16 d0, q0\n"
3007       "vqmovun.s16 d1, q2\n"
3008 
3009       "vst1.32 {d0, d1}, [%[output]]!\n"
3010       "pld [%[output]]\n"
3011 
3012       "bne 1b\n"
3013       "2:"
3014 
3015       // Handle leftovers.
3016 
3017       // Quantize::Transform
3018       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
3019       "vld1.32 {d4, d5, d6}, [%[input]]!\n"
3020       "pld [%[input], #64]\n"
3021       "vsub.f32 q0, q0, q4\n"
3022       "vsub.f32 q1, q1, q4\n"
3023       "vsub.f32 q2, q2, q4\n"
3024       "vsub.f32 q3, q3, q4\n"
3025       "vmul.f32 q0, q0, q6\n"
3026       "vmul.f32 q1, q1, q6\n"
3027       "vmul.f32 q2, q2, q6\n"
3028       "vmul.f32 q3, q3, q6\n"
3029       "vadd.f32 q0, q0, q5\n"
3030       "vadd.f32 q1, q1, q5\n"
3031       "vadd.f32 q2, q2, q5\n"
3032       "vadd.f32 q3, q3, q5\n"
3033       "vcvt.s32.f32 q0, q0\n"
3034       "vcvt.s32.f32 q1, q1\n"
3035       "vcvt.s32.f32 q2, q2\n"
3036       "vcvt.s32.f32 q3, q3\n"
3037       "vqmovn.s32 d0, q0\n"
3038       "vqmovn.s32 d1, q1\n"
3039       "vqmovn.s32 d4, q2\n"
3040       "vqmovn.s32 d5, q3\n"
3041       "vqmovun.s16 d0, q0\n"
3042       "vqmovun.s16 d1, q2\n"
3043 
3044       "vst1.32 {d0}, [%[output]]!\n"
3045       "vst1.32 {d1[0]}, [%[output]]!\n"
3046       "vst1.16 {d1[2]}, [%[output]]!\n"
3047       "pld [%[output]]\n"
3048       : [count] "+r"(params_count_copy), [input] "+r"(input),
3049         [output] "+r"(output)
3050       : [range_offset] "r"(params.range_offset),
3051         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3052       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3053         "d11", "d12", "d13", "cc", "memory");
3054 }
3055 
3056 template <>
Transform(const float * input,const Quantize & params,uint8_t * output)3057 inline void Transform1DKernel<float, uint8_t, Quantize, 16, 15>::Transform(
3058     const float* input, const Quantize& params, uint8_t* output) {
3059 #ifdef DEBUG
3060 #ifdef DEBUG_METAGEMM_VERBOSE
3061   std::cout << __FILE__ << "(" << __LINE__
3062             << ") Quantize<float, uint8_t, Quantize, 16, 15>::Transform()"
3063             << std::endl
3064             << std::flush;
3065 #endif
3066 #endif
3067   int params_count_copy = params.count;
3068   asm volatile(
3069 
3070       // Quantize::Prepare
3071       "vdup.32 q4, %[range_min]\n"
3072       "vdup.32 q5, %[range_offset]\n"
3073       "vdup.32 q6, %[range_scale]\n"
3074 
3075       // Reduce count by leftovers.
3076       "subs %[count], %[count], #15\n"
3077       "beq 2f\n"
3078 
3079       "1:"
3080       "subs %[count], %[count], #16\n"
3081 
3082       // Quantize::Transform
3083       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
3084       "vld1.32 {d4, d5, d6, d7}, [%[input]]!\n"
3085       "pld [%[input], #64]\n"
3086       "vsub.f32 q0, q0, q4\n"
3087       "vsub.f32 q1, q1, q4\n"
3088       "vsub.f32 q2, q2, q4\n"
3089       "vsub.f32 q3, q3, q4\n"
3090       "vmul.f32 q0, q0, q6\n"
3091       "vmul.f32 q1, q1, q6\n"
3092       "vmul.f32 q2, q2, q6\n"
3093       "vmul.f32 q3, q3, q6\n"
3094       "vadd.f32 q0, q0, q5\n"
3095       "vadd.f32 q1, q1, q5\n"
3096       "vadd.f32 q2, q2, q5\n"
3097       "vadd.f32 q3, q3, q5\n"
3098       "vcvt.s32.f32 q0, q0\n"
3099       "vcvt.s32.f32 q1, q1\n"
3100       "vcvt.s32.f32 q2, q2\n"
3101       "vcvt.s32.f32 q3, q3\n"
3102       "vqmovn.s32 d0, q0\n"
3103       "vqmovn.s32 d1, q1\n"
3104       "vqmovn.s32 d4, q2\n"
3105       "vqmovn.s32 d5, q3\n"
3106       "vqmovun.s16 d0, q0\n"
3107       "vqmovun.s16 d1, q2\n"
3108 
3109       "vst1.32 {d0, d1}, [%[output]]!\n"
3110       "pld [%[output]]\n"
3111 
3112       "bne 1b\n"
3113       "2:"
3114 
3115       // Handle leftovers.
3116 
3117       // Quantize::Transform
3118       "vld1.32 {d0, d1, d2, d3}, [%[input]]!\n"
3119       "vld1.32 {d4, d5, d6}, [%[input]]!\n"
3120       "vld1.32 {d7[0]}, [%[input]]!\n"
3121       "pld [%[input], #64]\n"
3122       "vsub.f32 q0, q0, q4\n"
3123       "vsub.f32 q1, q1, q4\n"
3124       "vsub.f32 q2, q2, q4\n"
3125       "vsub.f32 q3, q3, q4\n"
3126       "vmul.f32 q0, q0, q6\n"
3127       "vmul.f32 q1, q1, q6\n"
3128       "vmul.f32 q2, q2, q6\n"
3129       "vmul.f32 q3, q3, q6\n"
3130       "vadd.f32 q0, q0, q5\n"
3131       "vadd.f32 q1, q1, q5\n"
3132       "vadd.f32 q2, q2, q5\n"
3133       "vadd.f32 q3, q3, q5\n"
3134       "vcvt.s32.f32 q0, q0\n"
3135       "vcvt.s32.f32 q1, q1\n"
3136       "vcvt.s32.f32 q2, q2\n"
3137       "vcvt.s32.f32 q3, q3\n"
3138       "vqmovn.s32 d0, q0\n"
3139       "vqmovn.s32 d1, q1\n"
3140       "vqmovn.s32 d4, q2\n"
3141       "vqmovn.s32 d5, q3\n"
3142       "vqmovun.s16 d0, q0\n"
3143       "vqmovun.s16 d1, q2\n"
3144 
3145       "vst1.32 {d0}, [%[output]]!\n"
3146       "vst1.32 {d1[0]}, [%[output]]!\n"
3147       "vst1.16 {d1[2]}, [%[output]]!\n"
3148       "vst1.8 {d1[6]}, [%[output]]!\n"
3149       "pld [%[output]]\n"
3150       : [count] "+r"(params_count_copy), [input] "+r"(input),
3151         [output] "+r"(output)
3152       : [range_offset] "r"(params.range_offset),
3153         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3154       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3155         "d11", "d12", "d13", "cc", "memory");
3156 }
3157 
3158 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3159 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 0>::Transform(
3160     const uint8_t* input, const Dequantize& params, float* output) {
3161 #ifdef DEBUG
3162 #ifdef DEBUG_METAGEMM_VERBOSE
3163   std::cout << __FILE__ << "(" << __LINE__
3164             << ") Dequantize<uint8_t, float, Dequantize, 16, 0>::Transform()"
3165             << std::endl
3166             << std::flush;
3167 #endif
3168 #endif
3169   int params_count_copy = params.count;
3170   asm volatile(
3171 
3172       // Dequantize::Prepare
3173       "vdup.32 q4, %[range_min]\n"
3174       "vdup.32 q5, %[range_offset]\n"
3175       "vdup.32 q6, %[range_scale]\n"
3176 
3177       "1:"
3178       "subs %[count], %[count], #16\n"
3179 
3180       // Dequantize::Transform
3181       "vld1.32 {d0, d1}, [%[input]]!\n"
3182       "pld [%[input], #32]\n"
3183       "vmovl.u8 q1, d1\n"
3184       "vmovl.u8 q0, d0\n"
3185       "vmovl.s16 q3, d3\n"
3186       "vmovl.s16 q2, d2\n"
3187       "vmovl.s16 q1, d1\n"
3188       "vmovl.s16 q0, d0\n"
3189       "vcvt.f32.s32 q0, q0\n"
3190       "vcvt.f32.s32 q1, q1\n"
3191       "vcvt.f32.s32 q2, q2\n"
3192       "vcvt.f32.s32 q3, q3\n"
3193       "vsub.f32 q0, q0, q5\n"
3194       "vsub.f32 q1, q1, q5\n"
3195       "vsub.f32 q2, q2, q5\n"
3196       "vsub.f32 q3, q3, q5\n"
3197       "vmul.f32 q0, q0, q6\n"
3198       "vmul.f32 q1, q1, q6\n"
3199       "vmul.f32 q2, q2, q6\n"
3200       "vmul.f32 q3, q3, q6\n"
3201       "vadd.f32 q0, q0, q4\n"
3202       "vadd.f32 q1, q1, q4\n"
3203       "vadd.f32 q2, q2, q4\n"
3204       "vadd.f32 q3, q3, q4\n"
3205 
3206       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3207       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3208       "pld [%[output]]\n"
3209 
3210       "bne 1b\n"
3211       : [count] "+r"(params_count_copy), [input] "+r"(input),
3212         [output] "+r"(output)
3213       : [range_offset] "r"(params.range_offset),
3214         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3215       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3216         "d11", "d12", "d13", "cc", "memory");
3217 }
3218 
3219 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3220 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 1>::Transform(
3221     const uint8_t* input, const Dequantize& params, float* output) {
3222 #ifdef DEBUG
3223 #ifdef DEBUG_METAGEMM_VERBOSE
3224   std::cout << __FILE__ << "(" << __LINE__
3225             << ") Dequantize<uint8_t, float, Dequantize, 16, 1>::Transform()"
3226             << std::endl
3227             << std::flush;
3228 #endif
3229 #endif
3230   int params_count_copy = params.count;
3231   asm volatile(
3232 
3233       // Dequantize::Prepare
3234       "vdup.32 q4, %[range_min]\n"
3235       "vdup.32 q5, %[range_offset]\n"
3236       "vdup.32 q6, %[range_scale]\n"
3237 
3238       // Reduce count by leftovers.
3239       "subs %[count], %[count], #1\n"
3240       "beq 2f\n"
3241 
3242       "1:"
3243       "subs %[count], %[count], #16\n"
3244 
3245       // Dequantize::Transform
3246       "vld1.32 {d0, d1}, [%[input]]!\n"
3247       "pld [%[input], #32]\n"
3248       "vmovl.u8 q1, d1\n"
3249       "vmovl.u8 q0, d0\n"
3250       "vmovl.s16 q3, d3\n"
3251       "vmovl.s16 q2, d2\n"
3252       "vmovl.s16 q1, d1\n"
3253       "vmovl.s16 q0, d0\n"
3254       "vcvt.f32.s32 q0, q0\n"
3255       "vcvt.f32.s32 q1, q1\n"
3256       "vcvt.f32.s32 q2, q2\n"
3257       "vcvt.f32.s32 q3, q3\n"
3258       "vsub.f32 q0, q0, q5\n"
3259       "vsub.f32 q1, q1, q5\n"
3260       "vsub.f32 q2, q2, q5\n"
3261       "vsub.f32 q3, q3, q5\n"
3262       "vmul.f32 q0, q0, q6\n"
3263       "vmul.f32 q1, q1, q6\n"
3264       "vmul.f32 q2, q2, q6\n"
3265       "vmul.f32 q3, q3, q6\n"
3266       "vadd.f32 q0, q0, q4\n"
3267       "vadd.f32 q1, q1, q4\n"
3268       "vadd.f32 q2, q2, q4\n"
3269       "vadd.f32 q3, q3, q4\n"
3270 
3271       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3272       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3273       "pld [%[output]]\n"
3274 
3275       "bne 1b\n"
3276       "2:"
3277 
3278       // Handle leftovers.
3279 
3280       // Dequantize::Transform
3281       "vld1.8 {d0[0]}, [%[input]]!\n"
3282       "pld [%[input], #32]\n"
3283       "vmovl.u8 q0, d0\n"
3284       "vmovl.s16 q0, d0\n"
3285       "vcvt.f32.s32 q0, q0\n"
3286       "vsub.f32 q0, q0, q5\n"
3287       "vmul.f32 q0, q0, q6\n"
3288       "vadd.f32 q0, q0, q4\n"
3289 
3290       "vst1.32 {d0[0]}, [%[output]]!\n"
3291       "pld [%[output]]\n"
3292       : [count] "+r"(params_count_copy), [input] "+r"(input),
3293         [output] "+r"(output)
3294       : [range_offset] "r"(params.range_offset),
3295         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3296       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3297         "d11", "d12", "d13", "cc", "memory");
3298 }
3299 
3300 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3301 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 2>::Transform(
3302     const uint8_t* input, const Dequantize& params, float* output) {
3303 #ifdef DEBUG
3304 #ifdef DEBUG_METAGEMM_VERBOSE
3305   std::cout << __FILE__ << "(" << __LINE__
3306             << ") Dequantize<uint8_t, float, Dequantize, 16, 2>::Transform()"
3307             << std::endl
3308             << std::flush;
3309 #endif
3310 #endif
3311   int params_count_copy = params.count;
3312   asm volatile(
3313 
3314       // Dequantize::Prepare
3315       "vdup.32 q4, %[range_min]\n"
3316       "vdup.32 q5, %[range_offset]\n"
3317       "vdup.32 q6, %[range_scale]\n"
3318 
3319       // Reduce count by leftovers.
3320       "subs %[count], %[count], #2\n"
3321       "beq 2f\n"
3322 
3323       "1:"
3324       "subs %[count], %[count], #16\n"
3325 
3326       // Dequantize::Transform
3327       "vld1.32 {d0, d1}, [%[input]]!\n"
3328       "pld [%[input], #32]\n"
3329       "vmovl.u8 q1, d1\n"
3330       "vmovl.u8 q0, d0\n"
3331       "vmovl.s16 q3, d3\n"
3332       "vmovl.s16 q2, d2\n"
3333       "vmovl.s16 q1, d1\n"
3334       "vmovl.s16 q0, d0\n"
3335       "vcvt.f32.s32 q0, q0\n"
3336       "vcvt.f32.s32 q1, q1\n"
3337       "vcvt.f32.s32 q2, q2\n"
3338       "vcvt.f32.s32 q3, q3\n"
3339       "vsub.f32 q0, q0, q5\n"
3340       "vsub.f32 q1, q1, q5\n"
3341       "vsub.f32 q2, q2, q5\n"
3342       "vsub.f32 q3, q3, q5\n"
3343       "vmul.f32 q0, q0, q6\n"
3344       "vmul.f32 q1, q1, q6\n"
3345       "vmul.f32 q2, q2, q6\n"
3346       "vmul.f32 q3, q3, q6\n"
3347       "vadd.f32 q0, q0, q4\n"
3348       "vadd.f32 q1, q1, q4\n"
3349       "vadd.f32 q2, q2, q4\n"
3350       "vadd.f32 q3, q3, q4\n"
3351 
3352       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3353       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3354       "pld [%[output]]\n"
3355 
3356       "bne 1b\n"
3357       "2:"
3358 
3359       // Handle leftovers.
3360 
3361       // Dequantize::Transform
3362       "vld1.16 {d0[0]}, [%[input]]!\n"
3363       "pld [%[input], #32]\n"
3364       "vmovl.u8 q0, d0\n"
3365       "vmovl.s16 q0, d0\n"
3366       "vcvt.f32.s32 q0, q0\n"
3367       "vsub.f32 q0, q0, q5\n"
3368       "vmul.f32 q0, q0, q6\n"
3369       "vadd.f32 q0, q0, q4\n"
3370 
3371       "vst1.32 {d0}, [%[output]]!\n"
3372       "pld [%[output]]\n"
3373       : [count] "+r"(params_count_copy), [input] "+r"(input),
3374         [output] "+r"(output)
3375       : [range_offset] "r"(params.range_offset),
3376         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3377       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3378         "d11", "d12", "d13", "cc", "memory");
3379 }
3380 
3381 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3382 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 3>::Transform(
3383     const uint8_t* input, const Dequantize& params, float* output) {
3384 #ifdef DEBUG
3385 #ifdef DEBUG_METAGEMM_VERBOSE
3386   std::cout << __FILE__ << "(" << __LINE__
3387             << ") Dequantize<uint8_t, float, Dequantize, 16, 3>::Transform()"
3388             << std::endl
3389             << std::flush;
3390 #endif
3391 #endif
3392   int params_count_copy = params.count;
3393   asm volatile(
3394 
3395       // Dequantize::Prepare
3396       "vdup.32 q4, %[range_min]\n"
3397       "vdup.32 q5, %[range_offset]\n"
3398       "vdup.32 q6, %[range_scale]\n"
3399 
3400       // Reduce count by leftovers.
3401       "subs %[count], %[count], #3\n"
3402       "beq 2f\n"
3403 
3404       "1:"
3405       "subs %[count], %[count], #16\n"
3406 
3407       // Dequantize::Transform
3408       "vld1.32 {d0, d1}, [%[input]]!\n"
3409       "pld [%[input], #32]\n"
3410       "vmovl.u8 q1, d1\n"
3411       "vmovl.u8 q0, d0\n"
3412       "vmovl.s16 q3, d3\n"
3413       "vmovl.s16 q2, d2\n"
3414       "vmovl.s16 q1, d1\n"
3415       "vmovl.s16 q0, d0\n"
3416       "vcvt.f32.s32 q0, q0\n"
3417       "vcvt.f32.s32 q1, q1\n"
3418       "vcvt.f32.s32 q2, q2\n"
3419       "vcvt.f32.s32 q3, q3\n"
3420       "vsub.f32 q0, q0, q5\n"
3421       "vsub.f32 q1, q1, q5\n"
3422       "vsub.f32 q2, q2, q5\n"
3423       "vsub.f32 q3, q3, q5\n"
3424       "vmul.f32 q0, q0, q6\n"
3425       "vmul.f32 q1, q1, q6\n"
3426       "vmul.f32 q2, q2, q6\n"
3427       "vmul.f32 q3, q3, q6\n"
3428       "vadd.f32 q0, q0, q4\n"
3429       "vadd.f32 q1, q1, q4\n"
3430       "vadd.f32 q2, q2, q4\n"
3431       "vadd.f32 q3, q3, q4\n"
3432 
3433       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3434       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3435       "pld [%[output]]\n"
3436 
3437       "bne 1b\n"
3438       "2:"
3439 
3440       // Handle leftovers.
3441 
3442       // Dequantize::Transform
3443       "vld1.16 {d0[0]}, [%[input]]!\n"
3444       "vld1.8 {d0[2]}, [%[input]]!\n"
3445       "pld [%[input], #32]\n"
3446       "vmovl.u8 q0, d0\n"
3447       "vmovl.s16 q0, d0\n"
3448       "vcvt.f32.s32 q0, q0\n"
3449       "vsub.f32 q0, q0, q5\n"
3450       "vmul.f32 q0, q0, q6\n"
3451       "vadd.f32 q0, q0, q4\n"
3452 
3453       "vst1.32 {d0}, [%[output]]!\n"
3454       "vst1.32 {d1[0]}, [%[output]]!\n"
3455       "pld [%[output]]\n"
3456       : [count] "+r"(params_count_copy), [input] "+r"(input),
3457         [output] "+r"(output)
3458       : [range_offset] "r"(params.range_offset),
3459         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3460       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3461         "d11", "d12", "d13", "cc", "memory");
3462 }
3463 
3464 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3465 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 4>::Transform(
3466     const uint8_t* input, const Dequantize& params, float* output) {
3467 #ifdef DEBUG
3468 #ifdef DEBUG_METAGEMM_VERBOSE
3469   std::cout << __FILE__ << "(" << __LINE__
3470             << ") Dequantize<uint8_t, float, Dequantize, 16, 4>::Transform()"
3471             << std::endl
3472             << std::flush;
3473 #endif
3474 #endif
3475   int params_count_copy = params.count;
3476   asm volatile(
3477 
3478       // Dequantize::Prepare
3479       "vdup.32 q4, %[range_min]\n"
3480       "vdup.32 q5, %[range_offset]\n"
3481       "vdup.32 q6, %[range_scale]\n"
3482 
3483       // Reduce count by leftovers.
3484       "subs %[count], %[count], #4\n"
3485       "beq 2f\n"
3486 
3487       "1:"
3488       "subs %[count], %[count], #16\n"
3489 
3490       // Dequantize::Transform
3491       "vld1.32 {d0, d1}, [%[input]]!\n"
3492       "pld [%[input], #32]\n"
3493       "vmovl.u8 q1, d1\n"
3494       "vmovl.u8 q0, d0\n"
3495       "vmovl.s16 q3, d3\n"
3496       "vmovl.s16 q2, d2\n"
3497       "vmovl.s16 q1, d1\n"
3498       "vmovl.s16 q0, d0\n"
3499       "vcvt.f32.s32 q0, q0\n"
3500       "vcvt.f32.s32 q1, q1\n"
3501       "vcvt.f32.s32 q2, q2\n"
3502       "vcvt.f32.s32 q3, q3\n"
3503       "vsub.f32 q0, q0, q5\n"
3504       "vsub.f32 q1, q1, q5\n"
3505       "vsub.f32 q2, q2, q5\n"
3506       "vsub.f32 q3, q3, q5\n"
3507       "vmul.f32 q0, q0, q6\n"
3508       "vmul.f32 q1, q1, q6\n"
3509       "vmul.f32 q2, q2, q6\n"
3510       "vmul.f32 q3, q3, q6\n"
3511       "vadd.f32 q0, q0, q4\n"
3512       "vadd.f32 q1, q1, q4\n"
3513       "vadd.f32 q2, q2, q4\n"
3514       "vadd.f32 q3, q3, q4\n"
3515 
3516       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3517       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3518       "pld [%[output]]\n"
3519 
3520       "bne 1b\n"
3521       "2:"
3522 
3523       // Handle leftovers.
3524 
3525       // Dequantize::Transform
3526       "vld1.32 {d0[0]}, [%[input]]!\n"
3527       "pld [%[input], #32]\n"
3528       "vmovl.u8 q0, d0\n"
3529       "vmovl.s16 q0, d0\n"
3530       "vcvt.f32.s32 q0, q0\n"
3531       "vsub.f32 q0, q0, q5\n"
3532       "vmul.f32 q0, q0, q6\n"
3533       "vadd.f32 q0, q0, q4\n"
3534 
3535       "vst1.32 {d0, d1}, [%[output]]!\n"
3536       "pld [%[output]]\n"
3537       : [count] "+r"(params_count_copy), [input] "+r"(input),
3538         [output] "+r"(output)
3539       : [range_offset] "r"(params.range_offset),
3540         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3541       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3542         "d11", "d12", "d13", "cc", "memory");
3543 }
3544 
3545 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3546 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 5>::Transform(
3547     const uint8_t* input, const Dequantize& params, float* output) {
3548 #ifdef DEBUG
3549 #ifdef DEBUG_METAGEMM_VERBOSE
3550   std::cout << __FILE__ << "(" << __LINE__
3551             << ") Dequantize<uint8_t, float, Dequantize, 16, 5>::Transform()"
3552             << std::endl
3553             << std::flush;
3554 #endif
3555 #endif
3556   int params_count_copy = params.count;
3557   asm volatile(
3558 
3559       // Dequantize::Prepare
3560       "vdup.32 q4, %[range_min]\n"
3561       "vdup.32 q5, %[range_offset]\n"
3562       "vdup.32 q6, %[range_scale]\n"
3563 
3564       // Reduce count by leftovers.
3565       "subs %[count], %[count], #5\n"
3566       "beq 2f\n"
3567 
3568       "1:"
3569       "subs %[count], %[count], #16\n"
3570 
3571       // Dequantize::Transform
3572       "vld1.32 {d0, d1}, [%[input]]!\n"
3573       "pld [%[input], #32]\n"
3574       "vmovl.u8 q1, d1\n"
3575       "vmovl.u8 q0, d0\n"
3576       "vmovl.s16 q3, d3\n"
3577       "vmovl.s16 q2, d2\n"
3578       "vmovl.s16 q1, d1\n"
3579       "vmovl.s16 q0, d0\n"
3580       "vcvt.f32.s32 q0, q0\n"
3581       "vcvt.f32.s32 q1, q1\n"
3582       "vcvt.f32.s32 q2, q2\n"
3583       "vcvt.f32.s32 q3, q3\n"
3584       "vsub.f32 q0, q0, q5\n"
3585       "vsub.f32 q1, q1, q5\n"
3586       "vsub.f32 q2, q2, q5\n"
3587       "vsub.f32 q3, q3, q5\n"
3588       "vmul.f32 q0, q0, q6\n"
3589       "vmul.f32 q1, q1, q6\n"
3590       "vmul.f32 q2, q2, q6\n"
3591       "vmul.f32 q3, q3, q6\n"
3592       "vadd.f32 q0, q0, q4\n"
3593       "vadd.f32 q1, q1, q4\n"
3594       "vadd.f32 q2, q2, q4\n"
3595       "vadd.f32 q3, q3, q4\n"
3596 
3597       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3598       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3599       "pld [%[output]]\n"
3600 
3601       "bne 1b\n"
3602       "2:"
3603 
3604       // Handle leftovers.
3605 
3606       // Dequantize::Transform
3607       "vld1.32 {d0[0]}, [%[input]]!\n"
3608       "vld1.8 {d0[4]}, [%[input]]!\n"
3609       "pld [%[input], #32]\n"
3610       "vmovl.u8 q0, d0\n"
3611       "vmovl.s16 q1, d1\n"
3612       "vmovl.s16 q0, d0\n"
3613       "vcvt.f32.s32 q0, q0\n"
3614       "vcvt.f32.s32 q1, q1\n"
3615       "vsub.f32 q0, q0, q5\n"
3616       "vsub.f32 q1, q1, q5\n"
3617       "vmul.f32 q0, q0, q6\n"
3618       "vmul.f32 q1, q1, q6\n"
3619       "vadd.f32 q0, q0, q4\n"
3620       "vadd.f32 q1, q1, q4\n"
3621 
3622       "vst1.32 {d0, d1}, [%[output]]!\n"
3623       "vst1.32 {d2[0]}, [%[output]]!\n"
3624       "pld [%[output]]\n"
3625       : [count] "+r"(params_count_copy), [input] "+r"(input),
3626         [output] "+r"(output)
3627       : [range_offset] "r"(params.range_offset),
3628         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3629       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3630         "d11", "d12", "d13", "cc", "memory");
3631 }
3632 
3633 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3634 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 6>::Transform(
3635     const uint8_t* input, const Dequantize& params, float* output) {
3636 #ifdef DEBUG
3637 #ifdef DEBUG_METAGEMM_VERBOSE
3638   std::cout << __FILE__ << "(" << __LINE__
3639             << ") Dequantize<uint8_t, float, Dequantize, 16, 6>::Transform()"
3640             << std::endl
3641             << std::flush;
3642 #endif
3643 #endif
3644   int params_count_copy = params.count;
3645   asm volatile(
3646 
3647       // Dequantize::Prepare
3648       "vdup.32 q4, %[range_min]\n"
3649       "vdup.32 q5, %[range_offset]\n"
3650       "vdup.32 q6, %[range_scale]\n"
3651 
3652       // Reduce count by leftovers.
3653       "subs %[count], %[count], #6\n"
3654       "beq 2f\n"
3655 
3656       "1:"
3657       "subs %[count], %[count], #16\n"
3658 
3659       // Dequantize::Transform
3660       "vld1.32 {d0, d1}, [%[input]]!\n"
3661       "pld [%[input], #32]\n"
3662       "vmovl.u8 q1, d1\n"
3663       "vmovl.u8 q0, d0\n"
3664       "vmovl.s16 q3, d3\n"
3665       "vmovl.s16 q2, d2\n"
3666       "vmovl.s16 q1, d1\n"
3667       "vmovl.s16 q0, d0\n"
3668       "vcvt.f32.s32 q0, q0\n"
3669       "vcvt.f32.s32 q1, q1\n"
3670       "vcvt.f32.s32 q2, q2\n"
3671       "vcvt.f32.s32 q3, q3\n"
3672       "vsub.f32 q0, q0, q5\n"
3673       "vsub.f32 q1, q1, q5\n"
3674       "vsub.f32 q2, q2, q5\n"
3675       "vsub.f32 q3, q3, q5\n"
3676       "vmul.f32 q0, q0, q6\n"
3677       "vmul.f32 q1, q1, q6\n"
3678       "vmul.f32 q2, q2, q6\n"
3679       "vmul.f32 q3, q3, q6\n"
3680       "vadd.f32 q0, q0, q4\n"
3681       "vadd.f32 q1, q1, q4\n"
3682       "vadd.f32 q2, q2, q4\n"
3683       "vadd.f32 q3, q3, q4\n"
3684 
3685       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3686       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3687       "pld [%[output]]\n"
3688 
3689       "bne 1b\n"
3690       "2:"
3691 
3692       // Handle leftovers.
3693 
3694       // Dequantize::Transform
3695       "vld1.32 {d0[0]}, [%[input]]!\n"
3696       "vld1.16 {d0[2]}, [%[input]]!\n"
3697       "pld [%[input], #32]\n"
3698       "vmovl.u8 q0, d0\n"
3699       "vmovl.s16 q1, d1\n"
3700       "vmovl.s16 q0, d0\n"
3701       "vcvt.f32.s32 q0, q0\n"
3702       "vcvt.f32.s32 q1, q1\n"
3703       "vsub.f32 q0, q0, q5\n"
3704       "vsub.f32 q1, q1, q5\n"
3705       "vmul.f32 q0, q0, q6\n"
3706       "vmul.f32 q1, q1, q6\n"
3707       "vadd.f32 q0, q0, q4\n"
3708       "vadd.f32 q1, q1, q4\n"
3709 
3710       "vst1.32 {d0, d1, d2}, [%[output]]!\n"
3711       "pld [%[output]]\n"
3712       : [count] "+r"(params_count_copy), [input] "+r"(input),
3713         [output] "+r"(output)
3714       : [range_offset] "r"(params.range_offset),
3715         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3716       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3717         "d11", "d12", "d13", "cc", "memory");
3718 }
3719 
3720 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3721 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 7>::Transform(
3722     const uint8_t* input, const Dequantize& params, float* output) {
3723 #ifdef DEBUG
3724 #ifdef DEBUG_METAGEMM_VERBOSE
3725   std::cout << __FILE__ << "(" << __LINE__
3726             << ") Dequantize<uint8_t, float, Dequantize, 16, 7>::Transform()"
3727             << std::endl
3728             << std::flush;
3729 #endif
3730 #endif
3731   int params_count_copy = params.count;
3732   asm volatile(
3733 
3734       // Dequantize::Prepare
3735       "vdup.32 q4, %[range_min]\n"
3736       "vdup.32 q5, %[range_offset]\n"
3737       "vdup.32 q6, %[range_scale]\n"
3738 
3739       // Reduce count by leftovers.
3740       "subs %[count], %[count], #7\n"
3741       "beq 2f\n"
3742 
3743       "1:"
3744       "subs %[count], %[count], #16\n"
3745 
3746       // Dequantize::Transform
3747       "vld1.32 {d0, d1}, [%[input]]!\n"
3748       "pld [%[input], #32]\n"
3749       "vmovl.u8 q1, d1\n"
3750       "vmovl.u8 q0, d0\n"
3751       "vmovl.s16 q3, d3\n"
3752       "vmovl.s16 q2, d2\n"
3753       "vmovl.s16 q1, d1\n"
3754       "vmovl.s16 q0, d0\n"
3755       "vcvt.f32.s32 q0, q0\n"
3756       "vcvt.f32.s32 q1, q1\n"
3757       "vcvt.f32.s32 q2, q2\n"
3758       "vcvt.f32.s32 q3, q3\n"
3759       "vsub.f32 q0, q0, q5\n"
3760       "vsub.f32 q1, q1, q5\n"
3761       "vsub.f32 q2, q2, q5\n"
3762       "vsub.f32 q3, q3, q5\n"
3763       "vmul.f32 q0, q0, q6\n"
3764       "vmul.f32 q1, q1, q6\n"
3765       "vmul.f32 q2, q2, q6\n"
3766       "vmul.f32 q3, q3, q6\n"
3767       "vadd.f32 q0, q0, q4\n"
3768       "vadd.f32 q1, q1, q4\n"
3769       "vadd.f32 q2, q2, q4\n"
3770       "vadd.f32 q3, q3, q4\n"
3771 
3772       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3773       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3774       "pld [%[output]]\n"
3775 
3776       "bne 1b\n"
3777       "2:"
3778 
3779       // Handle leftovers.
3780 
3781       // Dequantize::Transform
3782       "vld1.32 {d0[0]}, [%[input]]!\n"
3783       "vld1.16 {d0[2]}, [%[input]]!\n"
3784       "vld1.8 {d0[6]}, [%[input]]!\n"
3785       "pld [%[input], #32]\n"
3786       "vmovl.u8 q0, d0\n"
3787       "vmovl.s16 q1, d1\n"
3788       "vmovl.s16 q0, d0\n"
3789       "vcvt.f32.s32 q0, q0\n"
3790       "vcvt.f32.s32 q1, q1\n"
3791       "vsub.f32 q0, q0, q5\n"
3792       "vsub.f32 q1, q1, q5\n"
3793       "vmul.f32 q0, q0, q6\n"
3794       "vmul.f32 q1, q1, q6\n"
3795       "vadd.f32 q0, q0, q4\n"
3796       "vadd.f32 q1, q1, q4\n"
3797 
3798       "vst1.32 {d0, d1, d2}, [%[output]]!\n"
3799       "vst1.32 {d3[0]}, [%[output]]!\n"
3800       "pld [%[output]]\n"
3801       : [count] "+r"(params_count_copy), [input] "+r"(input),
3802         [output] "+r"(output)
3803       : [range_offset] "r"(params.range_offset),
3804         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3805       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3806         "d11", "d12", "d13", "cc", "memory");
3807 }
3808 
3809 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3810 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 8>::Transform(
3811     const uint8_t* input, const Dequantize& params, float* output) {
3812 #ifdef DEBUG
3813 #ifdef DEBUG_METAGEMM_VERBOSE
3814   std::cout << __FILE__ << "(" << __LINE__
3815             << ") Dequantize<uint8_t, float, Dequantize, 16, 8>::Transform()"
3816             << std::endl
3817             << std::flush;
3818 #endif
3819 #endif
3820   int params_count_copy = params.count;
3821   asm volatile(
3822 
3823       // Dequantize::Prepare
3824       "vdup.32 q4, %[range_min]\n"
3825       "vdup.32 q5, %[range_offset]\n"
3826       "vdup.32 q6, %[range_scale]\n"
3827 
3828       // Reduce count by leftovers.
3829       "subs %[count], %[count], #8\n"
3830       "beq 2f\n"
3831 
3832       "1:"
3833       "subs %[count], %[count], #16\n"
3834 
3835       // Dequantize::Transform
3836       "vld1.32 {d0, d1}, [%[input]]!\n"
3837       "pld [%[input], #32]\n"
3838       "vmovl.u8 q1, d1\n"
3839       "vmovl.u8 q0, d0\n"
3840       "vmovl.s16 q3, d3\n"
3841       "vmovl.s16 q2, d2\n"
3842       "vmovl.s16 q1, d1\n"
3843       "vmovl.s16 q0, d0\n"
3844       "vcvt.f32.s32 q0, q0\n"
3845       "vcvt.f32.s32 q1, q1\n"
3846       "vcvt.f32.s32 q2, q2\n"
3847       "vcvt.f32.s32 q3, q3\n"
3848       "vsub.f32 q0, q0, q5\n"
3849       "vsub.f32 q1, q1, q5\n"
3850       "vsub.f32 q2, q2, q5\n"
3851       "vsub.f32 q3, q3, q5\n"
3852       "vmul.f32 q0, q0, q6\n"
3853       "vmul.f32 q1, q1, q6\n"
3854       "vmul.f32 q2, q2, q6\n"
3855       "vmul.f32 q3, q3, q6\n"
3856       "vadd.f32 q0, q0, q4\n"
3857       "vadd.f32 q1, q1, q4\n"
3858       "vadd.f32 q2, q2, q4\n"
3859       "vadd.f32 q3, q3, q4\n"
3860 
3861       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3862       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3863       "pld [%[output]]\n"
3864 
3865       "bne 1b\n"
3866       "2:"
3867 
3868       // Handle leftovers.
3869 
3870       // Dequantize::Transform
3871       "vld1.32 {d0}, [%[input]]!\n"
3872       "pld [%[input], #32]\n"
3873       "vmovl.u8 q0, d0\n"
3874       "vmovl.s16 q1, d1\n"
3875       "vmovl.s16 q0, d0\n"
3876       "vcvt.f32.s32 q0, q0\n"
3877       "vcvt.f32.s32 q1, q1\n"
3878       "vsub.f32 q0, q0, q5\n"
3879       "vsub.f32 q1, q1, q5\n"
3880       "vmul.f32 q0, q0, q6\n"
3881       "vmul.f32 q1, q1, q6\n"
3882       "vadd.f32 q0, q0, q4\n"
3883       "vadd.f32 q1, q1, q4\n"
3884 
3885       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3886       "pld [%[output]]\n"
3887       : [count] "+r"(params_count_copy), [input] "+r"(input),
3888         [output] "+r"(output)
3889       : [range_offset] "r"(params.range_offset),
3890         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3891       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3892         "d11", "d12", "d13", "cc", "memory");
3893 }
3894 
3895 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3896 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 9>::Transform(
3897     const uint8_t* input, const Dequantize& params, float* output) {
3898 #ifdef DEBUG
3899 #ifdef DEBUG_METAGEMM_VERBOSE
3900   std::cout << __FILE__ << "(" << __LINE__
3901             << ") Dequantize<uint8_t, float, Dequantize, 16, 9>::Transform()"
3902             << std::endl
3903             << std::flush;
3904 #endif
3905 #endif
3906   int params_count_copy = params.count;
3907   asm volatile(
3908 
3909       // Dequantize::Prepare
3910       "vdup.32 q4, %[range_min]\n"
3911       "vdup.32 q5, %[range_offset]\n"
3912       "vdup.32 q6, %[range_scale]\n"
3913 
3914       // Reduce count by leftovers.
3915       "subs %[count], %[count], #9\n"
3916       "beq 2f\n"
3917 
3918       "1:"
3919       "subs %[count], %[count], #16\n"
3920 
3921       // Dequantize::Transform
3922       "vld1.32 {d0, d1}, [%[input]]!\n"
3923       "pld [%[input], #32]\n"
3924       "vmovl.u8 q1, d1\n"
3925       "vmovl.u8 q0, d0\n"
3926       "vmovl.s16 q3, d3\n"
3927       "vmovl.s16 q2, d2\n"
3928       "vmovl.s16 q1, d1\n"
3929       "vmovl.s16 q0, d0\n"
3930       "vcvt.f32.s32 q0, q0\n"
3931       "vcvt.f32.s32 q1, q1\n"
3932       "vcvt.f32.s32 q2, q2\n"
3933       "vcvt.f32.s32 q3, q3\n"
3934       "vsub.f32 q0, q0, q5\n"
3935       "vsub.f32 q1, q1, q5\n"
3936       "vsub.f32 q2, q2, q5\n"
3937       "vsub.f32 q3, q3, q5\n"
3938       "vmul.f32 q0, q0, q6\n"
3939       "vmul.f32 q1, q1, q6\n"
3940       "vmul.f32 q2, q2, q6\n"
3941       "vmul.f32 q3, q3, q6\n"
3942       "vadd.f32 q0, q0, q4\n"
3943       "vadd.f32 q1, q1, q4\n"
3944       "vadd.f32 q2, q2, q4\n"
3945       "vadd.f32 q3, q3, q4\n"
3946 
3947       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3948       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
3949       "pld [%[output]]\n"
3950 
3951       "bne 1b\n"
3952       "2:"
3953 
3954       // Handle leftovers.
3955 
3956       // Dequantize::Transform
3957       "vld1.32 {d0}, [%[input]]!\n"
3958       "vld1.8 {d1[0]}, [%[input]]!\n"
3959       "pld [%[input], #32]\n"
3960       "vmovl.u8 q1, d1\n"
3961       "vmovl.u8 q0, d0\n"
3962       "vmovl.s16 q2, d2\n"
3963       "vmovl.s16 q1, d1\n"
3964       "vmovl.s16 q0, d0\n"
3965       "vcvt.f32.s32 q0, q0\n"
3966       "vcvt.f32.s32 q1, q1\n"
3967       "vcvt.f32.s32 q2, q2\n"
3968       "vsub.f32 q0, q0, q5\n"
3969       "vsub.f32 q1, q1, q5\n"
3970       "vsub.f32 q2, q2, q5\n"
3971       "vmul.f32 q0, q0, q6\n"
3972       "vmul.f32 q1, q1, q6\n"
3973       "vmul.f32 q2, q2, q6\n"
3974       "vadd.f32 q0, q0, q4\n"
3975       "vadd.f32 q1, q1, q4\n"
3976       "vadd.f32 q2, q2, q4\n"
3977 
3978       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
3979       "vst1.32 {d4[0]}, [%[output]]!\n"
3980       "pld [%[output]]\n"
3981       : [count] "+r"(params_count_copy), [input] "+r"(input),
3982         [output] "+r"(output)
3983       : [range_offset] "r"(params.range_offset),
3984         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
3985       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
3986         "d11", "d12", "d13", "cc", "memory");
3987 }
3988 
3989 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)3990 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 10>::Transform(
3991     const uint8_t* input, const Dequantize& params, float* output) {
3992 #ifdef DEBUG
3993 #ifdef DEBUG_METAGEMM_VERBOSE
3994   std::cout << __FILE__ << "(" << __LINE__
3995             << ") Dequantize<uint8_t, float, Dequantize, 16, 10>::Transform()"
3996             << std::endl
3997             << std::flush;
3998 #endif
3999 #endif
4000   int params_count_copy = params.count;
4001   asm volatile(
4002 
4003       // Dequantize::Prepare
4004       "vdup.32 q4, %[range_min]\n"
4005       "vdup.32 q5, %[range_offset]\n"
4006       "vdup.32 q6, %[range_scale]\n"
4007 
4008       // Reduce count by leftovers.
4009       "subs %[count], %[count], #10\n"
4010       "beq 2f\n"
4011 
4012       "1:"
4013       "subs %[count], %[count], #16\n"
4014 
4015       // Dequantize::Transform
4016       "vld1.32 {d0, d1}, [%[input]]!\n"
4017       "pld [%[input], #32]\n"
4018       "vmovl.u8 q1, d1\n"
4019       "vmovl.u8 q0, d0\n"
4020       "vmovl.s16 q3, d3\n"
4021       "vmovl.s16 q2, d2\n"
4022       "vmovl.s16 q1, d1\n"
4023       "vmovl.s16 q0, d0\n"
4024       "vcvt.f32.s32 q0, q0\n"
4025       "vcvt.f32.s32 q1, q1\n"
4026       "vcvt.f32.s32 q2, q2\n"
4027       "vcvt.f32.s32 q3, q3\n"
4028       "vsub.f32 q0, q0, q5\n"
4029       "vsub.f32 q1, q1, q5\n"
4030       "vsub.f32 q2, q2, q5\n"
4031       "vsub.f32 q3, q3, q5\n"
4032       "vmul.f32 q0, q0, q6\n"
4033       "vmul.f32 q1, q1, q6\n"
4034       "vmul.f32 q2, q2, q6\n"
4035       "vmul.f32 q3, q3, q6\n"
4036       "vadd.f32 q0, q0, q4\n"
4037       "vadd.f32 q1, q1, q4\n"
4038       "vadd.f32 q2, q2, q4\n"
4039       "vadd.f32 q3, q3, q4\n"
4040 
4041       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4042       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
4043       "pld [%[output]]\n"
4044 
4045       "bne 1b\n"
4046       "2:"
4047 
4048       // Handle leftovers.
4049 
4050       // Dequantize::Transform
4051       "vld1.32 {d0}, [%[input]]!\n"
4052       "vld1.16 {d1[0]}, [%[input]]!\n"
4053       "pld [%[input], #32]\n"
4054       "vmovl.u8 q1, d1\n"
4055       "vmovl.u8 q0, d0\n"
4056       "vmovl.s16 q2, d2\n"
4057       "vmovl.s16 q1, d1\n"
4058       "vmovl.s16 q0, d0\n"
4059       "vcvt.f32.s32 q0, q0\n"
4060       "vcvt.f32.s32 q1, q1\n"
4061       "vcvt.f32.s32 q2, q2\n"
4062       "vsub.f32 q0, q0, q5\n"
4063       "vsub.f32 q1, q1, q5\n"
4064       "vsub.f32 q2, q2, q5\n"
4065       "vmul.f32 q0, q0, q6\n"
4066       "vmul.f32 q1, q1, q6\n"
4067       "vmul.f32 q2, q2, q6\n"
4068       "vadd.f32 q0, q0, q4\n"
4069       "vadd.f32 q1, q1, q4\n"
4070       "vadd.f32 q2, q2, q4\n"
4071 
4072       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4073       "vst1.32 {d4}, [%[output]]!\n"
4074       "pld [%[output]]\n"
4075       : [count] "+r"(params_count_copy), [input] "+r"(input),
4076         [output] "+r"(output)
4077       : [range_offset] "r"(params.range_offset),
4078         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
4079       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
4080         "d11", "d12", "d13", "cc", "memory");
4081 }
4082 
4083 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)4084 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 11>::Transform(
4085     const uint8_t* input, const Dequantize& params, float* output) {
4086 #ifdef DEBUG
4087 #ifdef DEBUG_METAGEMM_VERBOSE
4088   std::cout << __FILE__ << "(" << __LINE__
4089             << ") Dequantize<uint8_t, float, Dequantize, 16, 11>::Transform()"
4090             << std::endl
4091             << std::flush;
4092 #endif
4093 #endif
4094   int params_count_copy = params.count;
4095   asm volatile(
4096 
4097       // Dequantize::Prepare
4098       "vdup.32 q4, %[range_min]\n"
4099       "vdup.32 q5, %[range_offset]\n"
4100       "vdup.32 q6, %[range_scale]\n"
4101 
4102       // Reduce count by leftovers.
4103       "subs %[count], %[count], #11\n"
4104       "beq 2f\n"
4105 
4106       "1:"
4107       "subs %[count], %[count], #16\n"
4108 
4109       // Dequantize::Transform
4110       "vld1.32 {d0, d1}, [%[input]]!\n"
4111       "pld [%[input], #32]\n"
4112       "vmovl.u8 q1, d1\n"
4113       "vmovl.u8 q0, d0\n"
4114       "vmovl.s16 q3, d3\n"
4115       "vmovl.s16 q2, d2\n"
4116       "vmovl.s16 q1, d1\n"
4117       "vmovl.s16 q0, d0\n"
4118       "vcvt.f32.s32 q0, q0\n"
4119       "vcvt.f32.s32 q1, q1\n"
4120       "vcvt.f32.s32 q2, q2\n"
4121       "vcvt.f32.s32 q3, q3\n"
4122       "vsub.f32 q0, q0, q5\n"
4123       "vsub.f32 q1, q1, q5\n"
4124       "vsub.f32 q2, q2, q5\n"
4125       "vsub.f32 q3, q3, q5\n"
4126       "vmul.f32 q0, q0, q6\n"
4127       "vmul.f32 q1, q1, q6\n"
4128       "vmul.f32 q2, q2, q6\n"
4129       "vmul.f32 q3, q3, q6\n"
4130       "vadd.f32 q0, q0, q4\n"
4131       "vadd.f32 q1, q1, q4\n"
4132       "vadd.f32 q2, q2, q4\n"
4133       "vadd.f32 q3, q3, q4\n"
4134 
4135       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4136       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
4137       "pld [%[output]]\n"
4138 
4139       "bne 1b\n"
4140       "2:"
4141 
4142       // Handle leftovers.
4143 
4144       // Dequantize::Transform
4145       "vld1.32 {d0}, [%[input]]!\n"
4146       "vld1.16 {d1[0]}, [%[input]]!\n"
4147       "vld1.8 {d1[2]}, [%[input]]!\n"
4148       "pld [%[input], #32]\n"
4149       "vmovl.u8 q1, d1\n"
4150       "vmovl.u8 q0, d0\n"
4151       "vmovl.s16 q2, d2\n"
4152       "vmovl.s16 q1, d1\n"
4153       "vmovl.s16 q0, d0\n"
4154       "vcvt.f32.s32 q0, q0\n"
4155       "vcvt.f32.s32 q1, q1\n"
4156       "vcvt.f32.s32 q2, q2\n"
4157       "vsub.f32 q0, q0, q5\n"
4158       "vsub.f32 q1, q1, q5\n"
4159       "vsub.f32 q2, q2, q5\n"
4160       "vmul.f32 q0, q0, q6\n"
4161       "vmul.f32 q1, q1, q6\n"
4162       "vmul.f32 q2, q2, q6\n"
4163       "vadd.f32 q0, q0, q4\n"
4164       "vadd.f32 q1, q1, q4\n"
4165       "vadd.f32 q2, q2, q4\n"
4166 
4167       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4168       "vst1.32 {d4}, [%[output]]!\n"
4169       "vst1.32 {d5[0]}, [%[output]]!\n"
4170       "pld [%[output]]\n"
4171       : [count] "+r"(params_count_copy), [input] "+r"(input),
4172         [output] "+r"(output)
4173       : [range_offset] "r"(params.range_offset),
4174         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
4175       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
4176         "d11", "d12", "d13", "cc", "memory");
4177 }
4178 
4179 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)4180 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 12>::Transform(
4181     const uint8_t* input, const Dequantize& params, float* output) {
4182 #ifdef DEBUG
4183 #ifdef DEBUG_METAGEMM_VERBOSE
4184   std::cout << __FILE__ << "(" << __LINE__
4185             << ") Dequantize<uint8_t, float, Dequantize, 16, 12>::Transform()"
4186             << std::endl
4187             << std::flush;
4188 #endif
4189 #endif
4190   int params_count_copy = params.count;
4191   asm volatile(
4192 
4193       // Dequantize::Prepare
4194       "vdup.32 q4, %[range_min]\n"
4195       "vdup.32 q5, %[range_offset]\n"
4196       "vdup.32 q6, %[range_scale]\n"
4197 
4198       // Reduce count by leftovers.
4199       "subs %[count], %[count], #12\n"
4200       "beq 2f\n"
4201 
4202       "1:"
4203       "subs %[count], %[count], #16\n"
4204 
4205       // Dequantize::Transform
4206       "vld1.32 {d0, d1}, [%[input]]!\n"
4207       "pld [%[input], #32]\n"
4208       "vmovl.u8 q1, d1\n"
4209       "vmovl.u8 q0, d0\n"
4210       "vmovl.s16 q3, d3\n"
4211       "vmovl.s16 q2, d2\n"
4212       "vmovl.s16 q1, d1\n"
4213       "vmovl.s16 q0, d0\n"
4214       "vcvt.f32.s32 q0, q0\n"
4215       "vcvt.f32.s32 q1, q1\n"
4216       "vcvt.f32.s32 q2, q2\n"
4217       "vcvt.f32.s32 q3, q3\n"
4218       "vsub.f32 q0, q0, q5\n"
4219       "vsub.f32 q1, q1, q5\n"
4220       "vsub.f32 q2, q2, q5\n"
4221       "vsub.f32 q3, q3, q5\n"
4222       "vmul.f32 q0, q0, q6\n"
4223       "vmul.f32 q1, q1, q6\n"
4224       "vmul.f32 q2, q2, q6\n"
4225       "vmul.f32 q3, q3, q6\n"
4226       "vadd.f32 q0, q0, q4\n"
4227       "vadd.f32 q1, q1, q4\n"
4228       "vadd.f32 q2, q2, q4\n"
4229       "vadd.f32 q3, q3, q4\n"
4230 
4231       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4232       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
4233       "pld [%[output]]\n"
4234 
4235       "bne 1b\n"
4236       "2:"
4237 
4238       // Handle leftovers.
4239 
4240       // Dequantize::Transform
4241       "vld1.32 {d0}, [%[input]]!\n"
4242       "vld1.32 {d1[0]}, [%[input]]!\n"
4243       "pld [%[input], #32]\n"
4244       "vmovl.u8 q1, d1\n"
4245       "vmovl.u8 q0, d0\n"
4246       "vmovl.s16 q2, d2\n"
4247       "vmovl.s16 q1, d1\n"
4248       "vmovl.s16 q0, d0\n"
4249       "vcvt.f32.s32 q0, q0\n"
4250       "vcvt.f32.s32 q1, q1\n"
4251       "vcvt.f32.s32 q2, q2\n"
4252       "vsub.f32 q0, q0, q5\n"
4253       "vsub.f32 q1, q1, q5\n"
4254       "vsub.f32 q2, q2, q5\n"
4255       "vmul.f32 q0, q0, q6\n"
4256       "vmul.f32 q1, q1, q6\n"
4257       "vmul.f32 q2, q2, q6\n"
4258       "vadd.f32 q0, q0, q4\n"
4259       "vadd.f32 q1, q1, q4\n"
4260       "vadd.f32 q2, q2, q4\n"
4261 
4262       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4263       "vst1.32 {d4, d5}, [%[output]]!\n"
4264       "pld [%[output]]\n"
4265       : [count] "+r"(params_count_copy), [input] "+r"(input),
4266         [output] "+r"(output)
4267       : [range_offset] "r"(params.range_offset),
4268         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
4269       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
4270         "d11", "d12", "d13", "cc", "memory");
4271 }
4272 
4273 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)4274 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 13>::Transform(
4275     const uint8_t* input, const Dequantize& params, float* output) {
4276 #ifdef DEBUG
4277 #ifdef DEBUG_METAGEMM_VERBOSE
4278   std::cout << __FILE__ << "(" << __LINE__
4279             << ") Dequantize<uint8_t, float, Dequantize, 16, 13>::Transform()"
4280             << std::endl
4281             << std::flush;
4282 #endif
4283 #endif
4284   int params_count_copy = params.count;
4285   asm volatile(
4286 
4287       // Dequantize::Prepare
4288       "vdup.32 q4, %[range_min]\n"
4289       "vdup.32 q5, %[range_offset]\n"
4290       "vdup.32 q6, %[range_scale]\n"
4291 
4292       // Reduce count by leftovers.
4293       "subs %[count], %[count], #13\n"
4294       "beq 2f\n"
4295 
4296       "1:"
4297       "subs %[count], %[count], #16\n"
4298 
4299       // Dequantize::Transform
4300       "vld1.32 {d0, d1}, [%[input]]!\n"
4301       "pld [%[input], #32]\n"
4302       "vmovl.u8 q1, d1\n"
4303       "vmovl.u8 q0, d0\n"
4304       "vmovl.s16 q3, d3\n"
4305       "vmovl.s16 q2, d2\n"
4306       "vmovl.s16 q1, d1\n"
4307       "vmovl.s16 q0, d0\n"
4308       "vcvt.f32.s32 q0, q0\n"
4309       "vcvt.f32.s32 q1, q1\n"
4310       "vcvt.f32.s32 q2, q2\n"
4311       "vcvt.f32.s32 q3, q3\n"
4312       "vsub.f32 q0, q0, q5\n"
4313       "vsub.f32 q1, q1, q5\n"
4314       "vsub.f32 q2, q2, q5\n"
4315       "vsub.f32 q3, q3, q5\n"
4316       "vmul.f32 q0, q0, q6\n"
4317       "vmul.f32 q1, q1, q6\n"
4318       "vmul.f32 q2, q2, q6\n"
4319       "vmul.f32 q3, q3, q6\n"
4320       "vadd.f32 q0, q0, q4\n"
4321       "vadd.f32 q1, q1, q4\n"
4322       "vadd.f32 q2, q2, q4\n"
4323       "vadd.f32 q3, q3, q4\n"
4324 
4325       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4326       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
4327       "pld [%[output]]\n"
4328 
4329       "bne 1b\n"
4330       "2:"
4331 
4332       // Handle leftovers.
4333 
4334       // Dequantize::Transform
4335       "vld1.32 {d0}, [%[input]]!\n"
4336       "vld1.32 {d1[0]}, [%[input]]!\n"
4337       "vld1.8 {d1[4]}, [%[input]]!\n"
4338       "pld [%[input], #32]\n"
4339       "vmovl.u8 q1, d1\n"
4340       "vmovl.u8 q0, d0\n"
4341       "vmovl.s16 q3, d3\n"
4342       "vmovl.s16 q2, d2\n"
4343       "vmovl.s16 q1, d1\n"
4344       "vmovl.s16 q0, d0\n"
4345       "vcvt.f32.s32 q0, q0\n"
4346       "vcvt.f32.s32 q1, q1\n"
4347       "vcvt.f32.s32 q2, q2\n"
4348       "vcvt.f32.s32 q3, q3\n"
4349       "vsub.f32 q0, q0, q5\n"
4350       "vsub.f32 q1, q1, q5\n"
4351       "vsub.f32 q2, q2, q5\n"
4352       "vsub.f32 q3, q3, q5\n"
4353       "vmul.f32 q0, q0, q6\n"
4354       "vmul.f32 q1, q1, q6\n"
4355       "vmul.f32 q2, q2, q6\n"
4356       "vmul.f32 q3, q3, q6\n"
4357       "vadd.f32 q0, q0, q4\n"
4358       "vadd.f32 q1, q1, q4\n"
4359       "vadd.f32 q2, q2, q4\n"
4360       "vadd.f32 q3, q3, q4\n"
4361 
4362       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4363       "vst1.32 {d4, d5}, [%[output]]!\n"
4364       "vst1.32 {d6[0]}, [%[output]]!\n"
4365       "pld [%[output]]\n"
4366       : [count] "+r"(params_count_copy), [input] "+r"(input),
4367         [output] "+r"(output)
4368       : [range_offset] "r"(params.range_offset),
4369         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
4370       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
4371         "d11", "d12", "d13", "cc", "memory");
4372 }
4373 
4374 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)4375 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 14>::Transform(
4376     const uint8_t* input, const Dequantize& params, float* output) {
4377 #ifdef DEBUG
4378 #ifdef DEBUG_METAGEMM_VERBOSE
4379   std::cout << __FILE__ << "(" << __LINE__
4380             << ") Dequantize<uint8_t, float, Dequantize, 16, 14>::Transform()"
4381             << std::endl
4382             << std::flush;
4383 #endif
4384 #endif
4385   int params_count_copy = params.count;
4386   asm volatile(
4387 
4388       // Dequantize::Prepare
4389       "vdup.32 q4, %[range_min]\n"
4390       "vdup.32 q5, %[range_offset]\n"
4391       "vdup.32 q6, %[range_scale]\n"
4392 
4393       // Reduce count by leftovers.
4394       "subs %[count], %[count], #14\n"
4395       "beq 2f\n"
4396 
4397       "1:"
4398       "subs %[count], %[count], #16\n"
4399 
4400       // Dequantize::Transform
4401       "vld1.32 {d0, d1}, [%[input]]!\n"
4402       "pld [%[input], #32]\n"
4403       "vmovl.u8 q1, d1\n"
4404       "vmovl.u8 q0, d0\n"
4405       "vmovl.s16 q3, d3\n"
4406       "vmovl.s16 q2, d2\n"
4407       "vmovl.s16 q1, d1\n"
4408       "vmovl.s16 q0, d0\n"
4409       "vcvt.f32.s32 q0, q0\n"
4410       "vcvt.f32.s32 q1, q1\n"
4411       "vcvt.f32.s32 q2, q2\n"
4412       "vcvt.f32.s32 q3, q3\n"
4413       "vsub.f32 q0, q0, q5\n"
4414       "vsub.f32 q1, q1, q5\n"
4415       "vsub.f32 q2, q2, q5\n"
4416       "vsub.f32 q3, q3, q5\n"
4417       "vmul.f32 q0, q0, q6\n"
4418       "vmul.f32 q1, q1, q6\n"
4419       "vmul.f32 q2, q2, q6\n"
4420       "vmul.f32 q3, q3, q6\n"
4421       "vadd.f32 q0, q0, q4\n"
4422       "vadd.f32 q1, q1, q4\n"
4423       "vadd.f32 q2, q2, q4\n"
4424       "vadd.f32 q3, q3, q4\n"
4425 
4426       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4427       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
4428       "pld [%[output]]\n"
4429 
4430       "bne 1b\n"
4431       "2:"
4432 
4433       // Handle leftovers.
4434 
4435       // Dequantize::Transform
4436       "vld1.32 {d0}, [%[input]]!\n"
4437       "vld1.32 {d1[0]}, [%[input]]!\n"
4438       "vld1.16 {d1[2]}, [%[input]]!\n"
4439       "pld [%[input], #32]\n"
4440       "vmovl.u8 q1, d1\n"
4441       "vmovl.u8 q0, d0\n"
4442       "vmovl.s16 q3, d3\n"
4443       "vmovl.s16 q2, d2\n"
4444       "vmovl.s16 q1, d1\n"
4445       "vmovl.s16 q0, d0\n"
4446       "vcvt.f32.s32 q0, q0\n"
4447       "vcvt.f32.s32 q1, q1\n"
4448       "vcvt.f32.s32 q2, q2\n"
4449       "vcvt.f32.s32 q3, q3\n"
4450       "vsub.f32 q0, q0, q5\n"
4451       "vsub.f32 q1, q1, q5\n"
4452       "vsub.f32 q2, q2, q5\n"
4453       "vsub.f32 q3, q3, q5\n"
4454       "vmul.f32 q0, q0, q6\n"
4455       "vmul.f32 q1, q1, q6\n"
4456       "vmul.f32 q2, q2, q6\n"
4457       "vmul.f32 q3, q3, q6\n"
4458       "vadd.f32 q0, q0, q4\n"
4459       "vadd.f32 q1, q1, q4\n"
4460       "vadd.f32 q2, q2, q4\n"
4461       "vadd.f32 q3, q3, q4\n"
4462 
4463       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4464       "vst1.32 {d4, d5, d6}, [%[output]]!\n"
4465       "pld [%[output]]\n"
4466       : [count] "+r"(params_count_copy), [input] "+r"(input),
4467         [output] "+r"(output)
4468       : [range_offset] "r"(params.range_offset),
4469         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
4470       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
4471         "d11", "d12", "d13", "cc", "memory");
4472 }
4473 
4474 template <>
Transform(const uint8_t * input,const Dequantize & params,float * output)4475 inline void Transform1DKernel<uint8_t, float, Dequantize, 16, 15>::Transform(
4476     const uint8_t* input, const Dequantize& params, float* output) {
4477 #ifdef DEBUG
4478 #ifdef DEBUG_METAGEMM_VERBOSE
4479   std::cout << __FILE__ << "(" << __LINE__
4480             << ") Dequantize<uint8_t, float, Dequantize, 16, 15>::Transform()"
4481             << std::endl
4482             << std::flush;
4483 #endif
4484 #endif
4485   int params_count_copy = params.count;
4486   asm volatile(
4487 
4488       // Dequantize::Prepare
4489       "vdup.32 q4, %[range_min]\n"
4490       "vdup.32 q5, %[range_offset]\n"
4491       "vdup.32 q6, %[range_scale]\n"
4492 
4493       // Reduce count by leftovers.
4494       "subs %[count], %[count], #15\n"
4495       "beq 2f\n"
4496 
4497       "1:"
4498       "subs %[count], %[count], #16\n"
4499 
4500       // Dequantize::Transform
4501       "vld1.32 {d0, d1}, [%[input]]!\n"
4502       "pld [%[input], #32]\n"
4503       "vmovl.u8 q1, d1\n"
4504       "vmovl.u8 q0, d0\n"
4505       "vmovl.s16 q3, d3\n"
4506       "vmovl.s16 q2, d2\n"
4507       "vmovl.s16 q1, d1\n"
4508       "vmovl.s16 q0, d0\n"
4509       "vcvt.f32.s32 q0, q0\n"
4510       "vcvt.f32.s32 q1, q1\n"
4511       "vcvt.f32.s32 q2, q2\n"
4512       "vcvt.f32.s32 q3, q3\n"
4513       "vsub.f32 q0, q0, q5\n"
4514       "vsub.f32 q1, q1, q5\n"
4515       "vsub.f32 q2, q2, q5\n"
4516       "vsub.f32 q3, q3, q5\n"
4517       "vmul.f32 q0, q0, q6\n"
4518       "vmul.f32 q1, q1, q6\n"
4519       "vmul.f32 q2, q2, q6\n"
4520       "vmul.f32 q3, q3, q6\n"
4521       "vadd.f32 q0, q0, q4\n"
4522       "vadd.f32 q1, q1, q4\n"
4523       "vadd.f32 q2, q2, q4\n"
4524       "vadd.f32 q3, q3, q4\n"
4525 
4526       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4527       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
4528       "pld [%[output]]\n"
4529 
4530       "bne 1b\n"
4531       "2:"
4532 
4533       // Handle leftovers.
4534 
4535       // Dequantize::Transform
4536       "vld1.32 {d0}, [%[input]]!\n"
4537       "vld1.32 {d1[0]}, [%[input]]!\n"
4538       "vld1.16 {d1[2]}, [%[input]]!\n"
4539       "vld1.8 {d1[6]}, [%[input]]!\n"
4540       "pld [%[input], #32]\n"
4541       "vmovl.u8 q1, d1\n"
4542       "vmovl.u8 q0, d0\n"
4543       "vmovl.s16 q3, d3\n"
4544       "vmovl.s16 q2, d2\n"
4545       "vmovl.s16 q1, d1\n"
4546       "vmovl.s16 q0, d0\n"
4547       "vcvt.f32.s32 q0, q0\n"
4548       "vcvt.f32.s32 q1, q1\n"
4549       "vcvt.f32.s32 q2, q2\n"
4550       "vcvt.f32.s32 q3, q3\n"
4551       "vsub.f32 q0, q0, q5\n"
4552       "vsub.f32 q1, q1, q5\n"
4553       "vsub.f32 q2, q2, q5\n"
4554       "vsub.f32 q3, q3, q5\n"
4555       "vmul.f32 q0, q0, q6\n"
4556       "vmul.f32 q1, q1, q6\n"
4557       "vmul.f32 q2, q2, q6\n"
4558       "vmul.f32 q3, q3, q6\n"
4559       "vadd.f32 q0, q0, q4\n"
4560       "vadd.f32 q1, q1, q4\n"
4561       "vadd.f32 q2, q2, q4\n"
4562       "vadd.f32 q3, q3, q4\n"
4563 
4564       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
4565       "vst1.32 {d4, d5, d6}, [%[output]]!\n"
4566       "vst1.32 {d7[0]}, [%[output]]!\n"
4567       "pld [%[output]]\n"
4568       : [count] "+r"(params_count_copy), [input] "+r"(input),
4569         [output] "+r"(output)
4570       : [range_offset] "r"(params.range_offset),
4571         [range_scale] "r"(params.range_scale), [range_min] "r"(params.range_min)
4572       : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
4573         "d11", "d12", "d13", "cc", "memory");
4574 }
4575 
4576 template <>
4577 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4578                               0>::Transform(const uint8_t* input,
4579                                             const MinMax<uint8_t>& params,
4580                                             uint8_t* output) {
4581 #ifdef DEBUG
4582 #ifdef DEBUG_METAGEMM_VERBOSE
4583   std::cout << __FILE__ << "(" << __LINE__
4584             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4585                "0>::Transform()"
4586             << std::endl
4587             << std::flush;
4588 #endif
4589 #endif
4590   int params_count_copy = params.count;
4591   asm volatile(
4592 
4593       // MinMax::Prepare
4594       "vdup.8 q4, %[min]\n"
4595       "vdup.8 q5, %[max]\n"
4596 
4597       "1:"
4598       "subs %[count], %[count], #16\n"
4599 
4600       // MinMax::Transform
4601       "vld1.32 {d0, d1}, [%[input]]!\n"
4602       "pld [%[input], #16]\n"
4603       "vmax.u8 q0, q0, q4\n"
4604       "vmin.u8 q0, q0, q5\n"
4605 
4606       "vst1.32 {d0, d1}, [%[output]]!\n"
4607       "pld [%[output]]\n"
4608 
4609       "bne 1b\n"
4610       : [count] "+r"(params_count_copy), [input] "+r"(input),
4611         [output] "+r"(output)
4612       : [max] "r"(params.max), [min] "r"(params.min)
4613       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4614 }
4615 
4616 template <>
4617 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4618                               1>::Transform(const uint8_t* input,
4619                                             const MinMax<uint8_t>& params,
4620                                             uint8_t* output) {
4621 #ifdef DEBUG
4622 #ifdef DEBUG_METAGEMM_VERBOSE
4623   std::cout << __FILE__ << "(" << __LINE__
4624             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4625                "1>::Transform()"
4626             << std::endl
4627             << std::flush;
4628 #endif
4629 #endif
4630   int params_count_copy = params.count;
4631   asm volatile(
4632 
4633       // MinMax::Prepare
4634       "vdup.8 q4, %[min]\n"
4635       "vdup.8 q5, %[max]\n"
4636 
4637       // Reduce count by leftovers.
4638       "subs %[count], %[count], #1\n"
4639       "beq 2f\n"
4640 
4641       "1:"
4642       "subs %[count], %[count], #16\n"
4643 
4644       // MinMax::Transform
4645       "vld1.32 {d0, d1}, [%[input]]!\n"
4646       "pld [%[input], #16]\n"
4647       "vmax.u8 q0, q0, q4\n"
4648       "vmin.u8 q0, q0, q5\n"
4649 
4650       "vst1.32 {d0, d1}, [%[output]]!\n"
4651       "pld [%[output]]\n"
4652 
4653       "bne 1b\n"
4654       "2:"
4655 
4656       // Handle leftovers.
4657 
4658       // MinMax::Transform
4659       "vld1.8 {d0[0]}, [%[input]]!\n"
4660       "pld [%[input], #16]\n"
4661       "vmax.u8 q0, q0, q4\n"
4662       "vmin.u8 q0, q0, q5\n"
4663 
4664       "vst1.8 {d0[0]}, [%[output]]!\n"
4665       "pld [%[output]]\n"
4666       : [count] "+r"(params_count_copy), [input] "+r"(input),
4667         [output] "+r"(output)
4668       : [max] "r"(params.max), [min] "r"(params.min)
4669       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4670 }
4671 
4672 template <>
4673 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4674                               2>::Transform(const uint8_t* input,
4675                                             const MinMax<uint8_t>& params,
4676                                             uint8_t* output) {
4677 #ifdef DEBUG
4678 #ifdef DEBUG_METAGEMM_VERBOSE
4679   std::cout << __FILE__ << "(" << __LINE__
4680             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4681                "2>::Transform()"
4682             << std::endl
4683             << std::flush;
4684 #endif
4685 #endif
4686   int params_count_copy = params.count;
4687   asm volatile(
4688 
4689       // MinMax::Prepare
4690       "vdup.8 q4, %[min]\n"
4691       "vdup.8 q5, %[max]\n"
4692 
4693       // Reduce count by leftovers.
4694       "subs %[count], %[count], #2\n"
4695       "beq 2f\n"
4696 
4697       "1:"
4698       "subs %[count], %[count], #16\n"
4699 
4700       // MinMax::Transform
4701       "vld1.32 {d0, d1}, [%[input]]!\n"
4702       "pld [%[input], #16]\n"
4703       "vmax.u8 q0, q0, q4\n"
4704       "vmin.u8 q0, q0, q5\n"
4705 
4706       "vst1.32 {d0, d1}, [%[output]]!\n"
4707       "pld [%[output]]\n"
4708 
4709       "bne 1b\n"
4710       "2:"
4711 
4712       // Handle leftovers.
4713 
4714       // MinMax::Transform
4715       "vld1.16 {d0[0]}, [%[input]]!\n"
4716       "pld [%[input], #16]\n"
4717       "vmax.u8 q0, q0, q4\n"
4718       "vmin.u8 q0, q0, q5\n"
4719 
4720       "vst1.16 {d0[0]}, [%[output]]!\n"
4721       "pld [%[output]]\n"
4722       : [count] "+r"(params_count_copy), [input] "+r"(input),
4723         [output] "+r"(output)
4724       : [max] "r"(params.max), [min] "r"(params.min)
4725       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4726 }
4727 
4728 template <>
4729 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4730                               3>::Transform(const uint8_t* input,
4731                                             const MinMax<uint8_t>& params,
4732                                             uint8_t* output) {
4733 #ifdef DEBUG
4734 #ifdef DEBUG_METAGEMM_VERBOSE
4735   std::cout << __FILE__ << "(" << __LINE__
4736             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4737                "3>::Transform()"
4738             << std::endl
4739             << std::flush;
4740 #endif
4741 #endif
4742   int params_count_copy = params.count;
4743   asm volatile(
4744 
4745       // MinMax::Prepare
4746       "vdup.8 q4, %[min]\n"
4747       "vdup.8 q5, %[max]\n"
4748 
4749       // Reduce count by leftovers.
4750       "subs %[count], %[count], #3\n"
4751       "beq 2f\n"
4752 
4753       "1:"
4754       "subs %[count], %[count], #16\n"
4755 
4756       // MinMax::Transform
4757       "vld1.32 {d0, d1}, [%[input]]!\n"
4758       "pld [%[input], #16]\n"
4759       "vmax.u8 q0, q0, q4\n"
4760       "vmin.u8 q0, q0, q5\n"
4761 
4762       "vst1.32 {d0, d1}, [%[output]]!\n"
4763       "pld [%[output]]\n"
4764 
4765       "bne 1b\n"
4766       "2:"
4767 
4768       // Handle leftovers.
4769 
4770       // MinMax::Transform
4771       "vld1.16 {d0[0]}, [%[input]]!\n"
4772       "vld1.8 {d0[2]}, [%[input]]!\n"
4773       "pld [%[input], #16]\n"
4774       "vmax.u8 q0, q0, q4\n"
4775       "vmin.u8 q0, q0, q5\n"
4776 
4777       "vst1.16 {d0[0]}, [%[output]]!\n"
4778       "vst1.8 {d0[2]}, [%[output]]!\n"
4779       "pld [%[output]]\n"
4780       : [count] "+r"(params_count_copy), [input] "+r"(input),
4781         [output] "+r"(output)
4782       : [max] "r"(params.max), [min] "r"(params.min)
4783       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4784 }
4785 
4786 template <>
4787 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4788                               4>::Transform(const uint8_t* input,
4789                                             const MinMax<uint8_t>& params,
4790                                             uint8_t* output) {
4791 #ifdef DEBUG
4792 #ifdef DEBUG_METAGEMM_VERBOSE
4793   std::cout << __FILE__ << "(" << __LINE__
4794             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4795                "4>::Transform()"
4796             << std::endl
4797             << std::flush;
4798 #endif
4799 #endif
4800   int params_count_copy = params.count;
4801   asm volatile(
4802 
4803       // MinMax::Prepare
4804       "vdup.8 q4, %[min]\n"
4805       "vdup.8 q5, %[max]\n"
4806 
4807       // Reduce count by leftovers.
4808       "subs %[count], %[count], #4\n"
4809       "beq 2f\n"
4810 
4811       "1:"
4812       "subs %[count], %[count], #16\n"
4813 
4814       // MinMax::Transform
4815       "vld1.32 {d0, d1}, [%[input]]!\n"
4816       "pld [%[input], #16]\n"
4817       "vmax.u8 q0, q0, q4\n"
4818       "vmin.u8 q0, q0, q5\n"
4819 
4820       "vst1.32 {d0, d1}, [%[output]]!\n"
4821       "pld [%[output]]\n"
4822 
4823       "bne 1b\n"
4824       "2:"
4825 
4826       // Handle leftovers.
4827 
4828       // MinMax::Transform
4829       "vld1.32 {d0[0]}, [%[input]]!\n"
4830       "pld [%[input], #16]\n"
4831       "vmax.u8 q0, q0, q4\n"
4832       "vmin.u8 q0, q0, q5\n"
4833 
4834       "vst1.32 {d0[0]}, [%[output]]!\n"
4835       "pld [%[output]]\n"
4836       : [count] "+r"(params_count_copy), [input] "+r"(input),
4837         [output] "+r"(output)
4838       : [max] "r"(params.max), [min] "r"(params.min)
4839       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4840 }
4841 
4842 template <>
4843 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4844                               5>::Transform(const uint8_t* input,
4845                                             const MinMax<uint8_t>& params,
4846                                             uint8_t* output) {
4847 #ifdef DEBUG
4848 #ifdef DEBUG_METAGEMM_VERBOSE
4849   std::cout << __FILE__ << "(" << __LINE__
4850             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4851                "5>::Transform()"
4852             << std::endl
4853             << std::flush;
4854 #endif
4855 #endif
4856   int params_count_copy = params.count;
4857   asm volatile(
4858 
4859       // MinMax::Prepare
4860       "vdup.8 q4, %[min]\n"
4861       "vdup.8 q5, %[max]\n"
4862 
4863       // Reduce count by leftovers.
4864       "subs %[count], %[count], #5\n"
4865       "beq 2f\n"
4866 
4867       "1:"
4868       "subs %[count], %[count], #16\n"
4869 
4870       // MinMax::Transform
4871       "vld1.32 {d0, d1}, [%[input]]!\n"
4872       "pld [%[input], #16]\n"
4873       "vmax.u8 q0, q0, q4\n"
4874       "vmin.u8 q0, q0, q5\n"
4875 
4876       "vst1.32 {d0, d1}, [%[output]]!\n"
4877       "pld [%[output]]\n"
4878 
4879       "bne 1b\n"
4880       "2:"
4881 
4882       // Handle leftovers.
4883 
4884       // MinMax::Transform
4885       "vld1.32 {d0[0]}, [%[input]]!\n"
4886       "vld1.8 {d0[4]}, [%[input]]!\n"
4887       "pld [%[input], #16]\n"
4888       "vmax.u8 q0, q0, q4\n"
4889       "vmin.u8 q0, q0, q5\n"
4890 
4891       "vst1.32 {d0[0]}, [%[output]]!\n"
4892       "vst1.8 {d0[4]}, [%[output]]!\n"
4893       "pld [%[output]]\n"
4894       : [count] "+r"(params_count_copy), [input] "+r"(input),
4895         [output] "+r"(output)
4896       : [max] "r"(params.max), [min] "r"(params.min)
4897       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4898 }
4899 
4900 template <>
4901 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4902                               6>::Transform(const uint8_t* input,
4903                                             const MinMax<uint8_t>& params,
4904                                             uint8_t* output) {
4905 #ifdef DEBUG
4906 #ifdef DEBUG_METAGEMM_VERBOSE
4907   std::cout << __FILE__ << "(" << __LINE__
4908             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4909                "6>::Transform()"
4910             << std::endl
4911             << std::flush;
4912 #endif
4913 #endif
4914   int params_count_copy = params.count;
4915   asm volatile(
4916 
4917       // MinMax::Prepare
4918       "vdup.8 q4, %[min]\n"
4919       "vdup.8 q5, %[max]\n"
4920 
4921       // Reduce count by leftovers.
4922       "subs %[count], %[count], #6\n"
4923       "beq 2f\n"
4924 
4925       "1:"
4926       "subs %[count], %[count], #16\n"
4927 
4928       // MinMax::Transform
4929       "vld1.32 {d0, d1}, [%[input]]!\n"
4930       "pld [%[input], #16]\n"
4931       "vmax.u8 q0, q0, q4\n"
4932       "vmin.u8 q0, q0, q5\n"
4933 
4934       "vst1.32 {d0, d1}, [%[output]]!\n"
4935       "pld [%[output]]\n"
4936 
4937       "bne 1b\n"
4938       "2:"
4939 
4940       // Handle leftovers.
4941 
4942       // MinMax::Transform
4943       "vld1.32 {d0[0]}, [%[input]]!\n"
4944       "vld1.16 {d0[2]}, [%[input]]!\n"
4945       "pld [%[input], #16]\n"
4946       "vmax.u8 q0, q0, q4\n"
4947       "vmin.u8 q0, q0, q5\n"
4948 
4949       "vst1.32 {d0[0]}, [%[output]]!\n"
4950       "vst1.16 {d0[2]}, [%[output]]!\n"
4951       "pld [%[output]]\n"
4952       : [count] "+r"(params_count_copy), [input] "+r"(input),
4953         [output] "+r"(output)
4954       : [max] "r"(params.max), [min] "r"(params.min)
4955       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
4956 }
4957 
4958 template <>
4959 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)4960                               7>::Transform(const uint8_t* input,
4961                                             const MinMax<uint8_t>& params,
4962                                             uint8_t* output) {
4963 #ifdef DEBUG
4964 #ifdef DEBUG_METAGEMM_VERBOSE
4965   std::cout << __FILE__ << "(" << __LINE__
4966             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
4967                "7>::Transform()"
4968             << std::endl
4969             << std::flush;
4970 #endif
4971 #endif
4972   int params_count_copy = params.count;
4973   asm volatile(
4974 
4975       // MinMax::Prepare
4976       "vdup.8 q4, %[min]\n"
4977       "vdup.8 q5, %[max]\n"
4978 
4979       // Reduce count by leftovers.
4980       "subs %[count], %[count], #7\n"
4981       "beq 2f\n"
4982 
4983       "1:"
4984       "subs %[count], %[count], #16\n"
4985 
4986       // MinMax::Transform
4987       "vld1.32 {d0, d1}, [%[input]]!\n"
4988       "pld [%[input], #16]\n"
4989       "vmax.u8 q0, q0, q4\n"
4990       "vmin.u8 q0, q0, q5\n"
4991 
4992       "vst1.32 {d0, d1}, [%[output]]!\n"
4993       "pld [%[output]]\n"
4994 
4995       "bne 1b\n"
4996       "2:"
4997 
4998       // Handle leftovers.
4999 
5000       // MinMax::Transform
5001       "vld1.32 {d0[0]}, [%[input]]!\n"
5002       "vld1.16 {d0[2]}, [%[input]]!\n"
5003       "vld1.8 {d0[6]}, [%[input]]!\n"
5004       "pld [%[input], #16]\n"
5005       "vmax.u8 q0, q0, q4\n"
5006       "vmin.u8 q0, q0, q5\n"
5007 
5008       "vst1.32 {d0[0]}, [%[output]]!\n"
5009       "vst1.16 {d0[2]}, [%[output]]!\n"
5010       "vst1.8 {d0[6]}, [%[output]]!\n"
5011       "pld [%[output]]\n"
5012       : [count] "+r"(params_count_copy), [input] "+r"(input),
5013         [output] "+r"(output)
5014       : [max] "r"(params.max), [min] "r"(params.min)
5015       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5016 }
5017 
5018 template <>
5019 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5020                               8>::Transform(const uint8_t* input,
5021                                             const MinMax<uint8_t>& params,
5022                                             uint8_t* output) {
5023 #ifdef DEBUG
5024 #ifdef DEBUG_METAGEMM_VERBOSE
5025   std::cout << __FILE__ << "(" << __LINE__
5026             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5027                "8>::Transform()"
5028             << std::endl
5029             << std::flush;
5030 #endif
5031 #endif
5032   int params_count_copy = params.count;
5033   asm volatile(
5034 
5035       // MinMax::Prepare
5036       "vdup.8 q4, %[min]\n"
5037       "vdup.8 q5, %[max]\n"
5038 
5039       // Reduce count by leftovers.
5040       "subs %[count], %[count], #8\n"
5041       "beq 2f\n"
5042 
5043       "1:"
5044       "subs %[count], %[count], #16\n"
5045 
5046       // MinMax::Transform
5047       "vld1.32 {d0, d1}, [%[input]]!\n"
5048       "pld [%[input], #16]\n"
5049       "vmax.u8 q0, q0, q4\n"
5050       "vmin.u8 q0, q0, q5\n"
5051 
5052       "vst1.32 {d0, d1}, [%[output]]!\n"
5053       "pld [%[output]]\n"
5054 
5055       "bne 1b\n"
5056       "2:"
5057 
5058       // Handle leftovers.
5059 
5060       // MinMax::Transform
5061       "vld1.32 {d0}, [%[input]]!\n"
5062       "pld [%[input], #16]\n"
5063       "vmax.u8 q0, q0, q4\n"
5064       "vmin.u8 q0, q0, q5\n"
5065 
5066       "vst1.32 {d0}, [%[output]]!\n"
5067       "pld [%[output]]\n"
5068       : [count] "+r"(params_count_copy), [input] "+r"(input),
5069         [output] "+r"(output)
5070       : [max] "r"(params.max), [min] "r"(params.min)
5071       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5072 }
5073 
5074 template <>
5075 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5076                               9>::Transform(const uint8_t* input,
5077                                             const MinMax<uint8_t>& params,
5078                                             uint8_t* output) {
5079 #ifdef DEBUG
5080 #ifdef DEBUG_METAGEMM_VERBOSE
5081   std::cout << __FILE__ << "(" << __LINE__
5082             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5083                "9>::Transform()"
5084             << std::endl
5085             << std::flush;
5086 #endif
5087 #endif
5088   int params_count_copy = params.count;
5089   asm volatile(
5090 
5091       // MinMax::Prepare
5092       "vdup.8 q4, %[min]\n"
5093       "vdup.8 q5, %[max]\n"
5094 
5095       // Reduce count by leftovers.
5096       "subs %[count], %[count], #9\n"
5097       "beq 2f\n"
5098 
5099       "1:"
5100       "subs %[count], %[count], #16\n"
5101 
5102       // MinMax::Transform
5103       "vld1.32 {d0, d1}, [%[input]]!\n"
5104       "pld [%[input], #16]\n"
5105       "vmax.u8 q0, q0, q4\n"
5106       "vmin.u8 q0, q0, q5\n"
5107 
5108       "vst1.32 {d0, d1}, [%[output]]!\n"
5109       "pld [%[output]]\n"
5110 
5111       "bne 1b\n"
5112       "2:"
5113 
5114       // Handle leftovers.
5115 
5116       // MinMax::Transform
5117       "vld1.32 {d0}, [%[input]]!\n"
5118       "vld1.8 {d1[0]}, [%[input]]!\n"
5119       "pld [%[input], #16]\n"
5120       "vmax.u8 q0, q0, q4\n"
5121       "vmin.u8 q0, q0, q5\n"
5122 
5123       "vst1.32 {d0}, [%[output]]!\n"
5124       "vst1.8 {d1[0]}, [%[output]]!\n"
5125       "pld [%[output]]\n"
5126       : [count] "+r"(params_count_copy), [input] "+r"(input),
5127         [output] "+r"(output)
5128       : [max] "r"(params.max), [min] "r"(params.min)
5129       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5130 }
5131 
5132 template <>
5133 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5134                               10>::Transform(const uint8_t* input,
5135                                              const MinMax<uint8_t>& params,
5136                                              uint8_t* output) {
5137 #ifdef DEBUG
5138 #ifdef DEBUG_METAGEMM_VERBOSE
5139   std::cout << __FILE__ << "(" << __LINE__
5140             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5141                "10>::Transform()"
5142             << std::endl
5143             << std::flush;
5144 #endif
5145 #endif
5146   int params_count_copy = params.count;
5147   asm volatile(
5148 
5149       // MinMax::Prepare
5150       "vdup.8 q4, %[min]\n"
5151       "vdup.8 q5, %[max]\n"
5152 
5153       // Reduce count by leftovers.
5154       "subs %[count], %[count], #10\n"
5155       "beq 2f\n"
5156 
5157       "1:"
5158       "subs %[count], %[count], #16\n"
5159 
5160       // MinMax::Transform
5161       "vld1.32 {d0, d1}, [%[input]]!\n"
5162       "pld [%[input], #16]\n"
5163       "vmax.u8 q0, q0, q4\n"
5164       "vmin.u8 q0, q0, q5\n"
5165 
5166       "vst1.32 {d0, d1}, [%[output]]!\n"
5167       "pld [%[output]]\n"
5168 
5169       "bne 1b\n"
5170       "2:"
5171 
5172       // Handle leftovers.
5173 
5174       // MinMax::Transform
5175       "vld1.32 {d0}, [%[input]]!\n"
5176       "vld1.16 {d1[0]}, [%[input]]!\n"
5177       "pld [%[input], #16]\n"
5178       "vmax.u8 q0, q0, q4\n"
5179       "vmin.u8 q0, q0, q5\n"
5180 
5181       "vst1.32 {d0}, [%[output]]!\n"
5182       "vst1.16 {d1[0]}, [%[output]]!\n"
5183       "pld [%[output]]\n"
5184       : [count] "+r"(params_count_copy), [input] "+r"(input),
5185         [output] "+r"(output)
5186       : [max] "r"(params.max), [min] "r"(params.min)
5187       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5188 }
5189 
5190 template <>
5191 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5192                               11>::Transform(const uint8_t* input,
5193                                              const MinMax<uint8_t>& params,
5194                                              uint8_t* output) {
5195 #ifdef DEBUG
5196 #ifdef DEBUG_METAGEMM_VERBOSE
5197   std::cout << __FILE__ << "(" << __LINE__
5198             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5199                "11>::Transform()"
5200             << std::endl
5201             << std::flush;
5202 #endif
5203 #endif
5204   int params_count_copy = params.count;
5205   asm volatile(
5206 
5207       // MinMax::Prepare
5208       "vdup.8 q4, %[min]\n"
5209       "vdup.8 q5, %[max]\n"
5210 
5211       // Reduce count by leftovers.
5212       "subs %[count], %[count], #11\n"
5213       "beq 2f\n"
5214 
5215       "1:"
5216       "subs %[count], %[count], #16\n"
5217 
5218       // MinMax::Transform
5219       "vld1.32 {d0, d1}, [%[input]]!\n"
5220       "pld [%[input], #16]\n"
5221       "vmax.u8 q0, q0, q4\n"
5222       "vmin.u8 q0, q0, q5\n"
5223 
5224       "vst1.32 {d0, d1}, [%[output]]!\n"
5225       "pld [%[output]]\n"
5226 
5227       "bne 1b\n"
5228       "2:"
5229 
5230       // Handle leftovers.
5231 
5232       // MinMax::Transform
5233       "vld1.32 {d0}, [%[input]]!\n"
5234       "vld1.16 {d1[0]}, [%[input]]!\n"
5235       "vld1.8 {d1[2]}, [%[input]]!\n"
5236       "pld [%[input], #16]\n"
5237       "vmax.u8 q0, q0, q4\n"
5238       "vmin.u8 q0, q0, q5\n"
5239 
5240       "vst1.32 {d0}, [%[output]]!\n"
5241       "vst1.16 {d1[0]}, [%[output]]!\n"
5242       "vst1.8 {d1[2]}, [%[output]]!\n"
5243       "pld [%[output]]\n"
5244       : [count] "+r"(params_count_copy), [input] "+r"(input),
5245         [output] "+r"(output)
5246       : [max] "r"(params.max), [min] "r"(params.min)
5247       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5248 }
5249 
5250 template <>
5251 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5252                               12>::Transform(const uint8_t* input,
5253                                              const MinMax<uint8_t>& params,
5254                                              uint8_t* output) {
5255 #ifdef DEBUG
5256 #ifdef DEBUG_METAGEMM_VERBOSE
5257   std::cout << __FILE__ << "(" << __LINE__
5258             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5259                "12>::Transform()"
5260             << std::endl
5261             << std::flush;
5262 #endif
5263 #endif
5264   int params_count_copy = params.count;
5265   asm volatile(
5266 
5267       // MinMax::Prepare
5268       "vdup.8 q4, %[min]\n"
5269       "vdup.8 q5, %[max]\n"
5270 
5271       // Reduce count by leftovers.
5272       "subs %[count], %[count], #12\n"
5273       "beq 2f\n"
5274 
5275       "1:"
5276       "subs %[count], %[count], #16\n"
5277 
5278       // MinMax::Transform
5279       "vld1.32 {d0, d1}, [%[input]]!\n"
5280       "pld [%[input], #16]\n"
5281       "vmax.u8 q0, q0, q4\n"
5282       "vmin.u8 q0, q0, q5\n"
5283 
5284       "vst1.32 {d0, d1}, [%[output]]!\n"
5285       "pld [%[output]]\n"
5286 
5287       "bne 1b\n"
5288       "2:"
5289 
5290       // Handle leftovers.
5291 
5292       // MinMax::Transform
5293       "vld1.32 {d0}, [%[input]]!\n"
5294       "vld1.32 {d1[0]}, [%[input]]!\n"
5295       "pld [%[input], #16]\n"
5296       "vmax.u8 q0, q0, q4\n"
5297       "vmin.u8 q0, q0, q5\n"
5298 
5299       "vst1.32 {d0}, [%[output]]!\n"
5300       "vst1.32 {d1[0]}, [%[output]]!\n"
5301       "pld [%[output]]\n"
5302       : [count] "+r"(params_count_copy), [input] "+r"(input),
5303         [output] "+r"(output)
5304       : [max] "r"(params.max), [min] "r"(params.min)
5305       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5306 }
5307 
5308 template <>
5309 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5310                               13>::Transform(const uint8_t* input,
5311                                              const MinMax<uint8_t>& params,
5312                                              uint8_t* output) {
5313 #ifdef DEBUG
5314 #ifdef DEBUG_METAGEMM_VERBOSE
5315   std::cout << __FILE__ << "(" << __LINE__
5316             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5317                "13>::Transform()"
5318             << std::endl
5319             << std::flush;
5320 #endif
5321 #endif
5322   int params_count_copy = params.count;
5323   asm volatile(
5324 
5325       // MinMax::Prepare
5326       "vdup.8 q4, %[min]\n"
5327       "vdup.8 q5, %[max]\n"
5328 
5329       // Reduce count by leftovers.
5330       "subs %[count], %[count], #13\n"
5331       "beq 2f\n"
5332 
5333       "1:"
5334       "subs %[count], %[count], #16\n"
5335 
5336       // MinMax::Transform
5337       "vld1.32 {d0, d1}, [%[input]]!\n"
5338       "pld [%[input], #16]\n"
5339       "vmax.u8 q0, q0, q4\n"
5340       "vmin.u8 q0, q0, q5\n"
5341 
5342       "vst1.32 {d0, d1}, [%[output]]!\n"
5343       "pld [%[output]]\n"
5344 
5345       "bne 1b\n"
5346       "2:"
5347 
5348       // Handle leftovers.
5349 
5350       // MinMax::Transform
5351       "vld1.32 {d0}, [%[input]]!\n"
5352       "vld1.32 {d1[0]}, [%[input]]!\n"
5353       "vld1.8 {d1[4]}, [%[input]]!\n"
5354       "pld [%[input], #16]\n"
5355       "vmax.u8 q0, q0, q4\n"
5356       "vmin.u8 q0, q0, q5\n"
5357 
5358       "vst1.32 {d0}, [%[output]]!\n"
5359       "vst1.32 {d1[0]}, [%[output]]!\n"
5360       "vst1.8 {d1[4]}, [%[output]]!\n"
5361       "pld [%[output]]\n"
5362       : [count] "+r"(params_count_copy), [input] "+r"(input),
5363         [output] "+r"(output)
5364       : [max] "r"(params.max), [min] "r"(params.min)
5365       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5366 }
5367 
5368 template <>
5369 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5370                               14>::Transform(const uint8_t* input,
5371                                              const MinMax<uint8_t>& params,
5372                                              uint8_t* output) {
5373 #ifdef DEBUG
5374 #ifdef DEBUG_METAGEMM_VERBOSE
5375   std::cout << __FILE__ << "(" << __LINE__
5376             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5377                "14>::Transform()"
5378             << std::endl
5379             << std::flush;
5380 #endif
5381 #endif
5382   int params_count_copy = params.count;
5383   asm volatile(
5384 
5385       // MinMax::Prepare
5386       "vdup.8 q4, %[min]\n"
5387       "vdup.8 q5, %[max]\n"
5388 
5389       // Reduce count by leftovers.
5390       "subs %[count], %[count], #14\n"
5391       "beq 2f\n"
5392 
5393       "1:"
5394       "subs %[count], %[count], #16\n"
5395 
5396       // MinMax::Transform
5397       "vld1.32 {d0, d1}, [%[input]]!\n"
5398       "pld [%[input], #16]\n"
5399       "vmax.u8 q0, q0, q4\n"
5400       "vmin.u8 q0, q0, q5\n"
5401 
5402       "vst1.32 {d0, d1}, [%[output]]!\n"
5403       "pld [%[output]]\n"
5404 
5405       "bne 1b\n"
5406       "2:"
5407 
5408       // Handle leftovers.
5409 
5410       // MinMax::Transform
5411       "vld1.32 {d0}, [%[input]]!\n"
5412       "vld1.32 {d1[0]}, [%[input]]!\n"
5413       "vld1.16 {d1[2]}, [%[input]]!\n"
5414       "pld [%[input], #16]\n"
5415       "vmax.u8 q0, q0, q4\n"
5416       "vmin.u8 q0, q0, q5\n"
5417 
5418       "vst1.32 {d0}, [%[output]]!\n"
5419       "vst1.32 {d1[0]}, [%[output]]!\n"
5420       "vst1.16 {d1[2]}, [%[output]]!\n"
5421       "pld [%[output]]\n"
5422       : [count] "+r"(params_count_copy), [input] "+r"(input),
5423         [output] "+r"(output)
5424       : [max] "r"(params.max), [min] "r"(params.min)
5425       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5426 }
5427 
5428 template <>
5429 inline void Transform1DKernel<uint8_t, uint8_t, MinMax<uint8_t>, 16,
Transform(const uint8_t * input,const MinMax<uint8_t> & params,uint8_t * output)5430                               15>::Transform(const uint8_t* input,
5431                                              const MinMax<uint8_t>& params,
5432                                              uint8_t* output) {
5433 #ifdef DEBUG
5434 #ifdef DEBUG_METAGEMM_VERBOSE
5435   std::cout << __FILE__ << "(" << __LINE__
5436             << ") MinMax<uint8_t><uint8_t, uint8_t, MinMax<uint8_t>, 16, "
5437                "15>::Transform()"
5438             << std::endl
5439             << std::flush;
5440 #endif
5441 #endif
5442   int params_count_copy = params.count;
5443   asm volatile(
5444 
5445       // MinMax::Prepare
5446       "vdup.8 q4, %[min]\n"
5447       "vdup.8 q5, %[max]\n"
5448 
5449       // Reduce count by leftovers.
5450       "subs %[count], %[count], #15\n"
5451       "beq 2f\n"
5452 
5453       "1:"
5454       "subs %[count], %[count], #16\n"
5455 
5456       // MinMax::Transform
5457       "vld1.32 {d0, d1}, [%[input]]!\n"
5458       "pld [%[input], #16]\n"
5459       "vmax.u8 q0, q0, q4\n"
5460       "vmin.u8 q0, q0, q5\n"
5461 
5462       "vst1.32 {d0, d1}, [%[output]]!\n"
5463       "pld [%[output]]\n"
5464 
5465       "bne 1b\n"
5466       "2:"
5467 
5468       // Handle leftovers.
5469 
5470       // MinMax::Transform
5471       "vld1.32 {d0}, [%[input]]!\n"
5472       "vld1.32 {d1[0]}, [%[input]]!\n"
5473       "vld1.16 {d1[2]}, [%[input]]!\n"
5474       "vld1.8 {d1[6]}, [%[input]]!\n"
5475       "pld [%[input], #16]\n"
5476       "vmax.u8 q0, q0, q4\n"
5477       "vmin.u8 q0, q0, q5\n"
5478 
5479       "vst1.32 {d0}, [%[output]]!\n"
5480       "vst1.32 {d1[0]}, [%[output]]!\n"
5481       "vst1.16 {d1[2]}, [%[output]]!\n"
5482       "vst1.8 {d1[6]}, [%[output]]!\n"
5483       "pld [%[output]]\n"
5484       : [count] "+r"(params_count_copy), [input] "+r"(input),
5485         [output] "+r"(output)
5486       : [max] "r"(params.max), [min] "r"(params.min)
5487       : "d0", "d1", "d8", "d9", "d10", "d11", "cc", "memory");
5488 }
5489 
5490 template <>
5491 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)5492                               0>::Transform(const uint8_t* input,
5493                                             const BiasAdd<uint8_t>& params,
5494                                             int32_t* output) {
5495 #ifdef DEBUG
5496 #ifdef DEBUG_METAGEMM_VERBOSE
5497   std::cout << __FILE__ << "(" << __LINE__
5498             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
5499                "0>::Transform()"
5500             << std::endl
5501             << std::flush;
5502 #endif
5503 #endif
5504   int params_rows_copy = params.rows;
5505   asm volatile(
5506       "ldr r0, %[input_range_min]\n"
5507       "vdup.32 q8, r0\n"
5508       "ldr r0, %[input_range_scale]\n"
5509       "vdup.32 q9, r0\n"
5510       "ldr r0, %[bias_range_min]\n"
5511       "vdup.32 q10, r0\n"
5512       "ldr r0, %[bias_range_scale]\n"
5513       "vdup.32 q11, r0\n"
5514       "ldr r0, %[output_range_min]\n"
5515       "vdup.32 q12, r0\n"
5516       "ldr r0, %[one_over_output_range_scale]\n"
5517       "vdup.32 q13, r0\n"
5518       "ldr r0, %[output_range_offset]\n"
5519       "vdup.32 q14, r0\n"
5520       "1:"
5521       "mov r0, %[count]\n"
5522       "mov r1, %[bias]\n"
5523       "2:"
5524       "subs r0, r0, #16\n"
5525 
5526       // BiasAdd::Transform
5527       "vld1.32 {d0, d1}, [%[input]]!\n"
5528       "vld1.32 {d8, d9}, [r1]!\n"
5529       "pld [%[input], #32]\n"
5530       "vmovl.u8 q1, d1\n"
5531       "vmovl.u8 q0, d0\n"
5532       "vmovl.u8 q5, d9\n"
5533       "vmovl.u8 q4, d8\n"
5534       "vmovl.s16 q3, d3\n"
5535       "vmovl.s16 q2, d2\n"
5536       "vmovl.s16 q7, d11\n"
5537       "vmovl.s16 q6, d10\n"
5538       "vmovl.s16 q1, d1\n"
5539       "vmovl.s16 q0, d0\n"
5540       "vmovl.s16 q5, d9\n"
5541       "vmovl.s16 q4, d8\n"
5542       "vcvt.f32.s32 q0, q0\n"
5543       "vcvt.f32.s32 q1, q1\n"
5544       "vcvt.f32.s32 q2, q2\n"
5545       "vcvt.f32.s32 q3, q3\n"
5546       "vcvt.f32.s32 q4, q4\n"
5547       "vcvt.f32.s32 q5, q5\n"
5548       "vcvt.f32.s32 q6, q6\n"
5549       "vcvt.f32.s32 q7, q7\n"
5550       "vmul.f32 q0, q0, q9\n"
5551       "vmul.f32 q1, q1, q9\n"
5552       "vmul.f32 q2, q2, q9\n"
5553       "vmul.f32 q3, q3, q9\n"
5554       "vmul.f32 q4, q4, q11\n"
5555       "vmul.f32 q5, q5, q11\n"
5556       "vmul.f32 q6, q6, q11\n"
5557       "vmul.f32 q7, q7, q11\n"
5558       "vadd.f32 q0, q0, q8\n"
5559       "vadd.f32 q1, q1, q8\n"
5560       "vadd.f32 q2, q2, q8\n"
5561       "vadd.f32 q3, q3, q8\n"
5562       "vadd.f32 q4, q4, q10\n"
5563       "vadd.f32 q5, q5, q10\n"
5564       "vadd.f32 q6, q6, q10\n"
5565       "vadd.f32 q7, q7, q10\n"
5566       "vadd.f32 q0, q0, q4\n"
5567       "vadd.f32 q1, q1, q5\n"
5568       "vadd.f32 q2, q2, q6\n"
5569       "vadd.f32 q3, q3, q7\n"
5570       "vsub.f32 q0, q0, q12\n"
5571       "vsub.f32 q1, q1, q12\n"
5572       "vsub.f32 q2, q2, q12\n"
5573       "vsub.f32 q3, q3, q12\n"
5574       "vmul.f32 q0, q0, q13\n"
5575       "vmul.f32 q1, q1, q13\n"
5576       "vmul.f32 q2, q2, q13\n"
5577       "vmul.f32 q3, q3, q13\n"
5578       "vadd.f32 q0, q0, q14\n"
5579       "vadd.f32 q1, q1, q14\n"
5580       "vadd.f32 q2, q2, q14\n"
5581       "vadd.f32 q3, q3, q14\n"
5582       "vcvt.s32.f32 q0, q0\n"
5583       "vcvt.s32.f32 q1, q1\n"
5584       "vcvt.s32.f32 q2, q2\n"
5585       "vcvt.s32.f32 q3, q3\n"
5586 
5587       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
5588       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
5589       "pld [%[output]]\n"
5590       "bne 2b\n"
5591       "subs %[rows], %[rows], #1\n"
5592       "bne 1b\n"
5593       : [input] "+r"(input), [output] "+r"(output)
5594       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
5595         [output_range_offset] "m"(params.output_range_offset),
5596         [input_range_scale] "m"(params.input_range_scale),
5597         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
5598         [bias_range_min] "m"(params.bias_range_min),
5599         [output_range_min] "m"(params.output_range_min),
5600         [bias_range_scale] "m"(params.bias_range_scale),
5601         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
5602       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
5603         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
5604         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
5605         "cc", "memory");
5606 }
5607 
5608 template <>
5609 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)5610                               1>::Transform(const uint8_t* input,
5611                                             const BiasAdd<uint8_t>& params,
5612                                             int32_t* output) {
5613 #ifdef DEBUG
5614 #ifdef DEBUG_METAGEMM_VERBOSE
5615   std::cout << __FILE__ << "(" << __LINE__
5616             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
5617                "1>::Transform()"
5618             << std::endl
5619             << std::flush;
5620 #endif
5621 #endif
5622   int params_rows_copy = params.rows;
5623   asm volatile(
5624       "ldr r0, %[input_range_min]\n"
5625       "vdup.32 q8, r0\n"
5626       "ldr r0, %[input_range_scale]\n"
5627       "vdup.32 q9, r0\n"
5628       "ldr r0, %[bias_range_min]\n"
5629       "vdup.32 q10, r0\n"
5630       "ldr r0, %[bias_range_scale]\n"
5631       "vdup.32 q11, r0\n"
5632       "ldr r0, %[output_range_min]\n"
5633       "vdup.32 q12, r0\n"
5634       "ldr r0, %[one_over_output_range_scale]\n"
5635       "vdup.32 q13, r0\n"
5636       "ldr r0, %[output_range_offset]\n"
5637       "vdup.32 q14, r0\n"
5638       "1:"
5639       "mov r0, %[count]\n"
5640       "mov r1, %[bias]\n"
5641       "subs r0, r0, #1\n"
5642       "beq 3f\n"
5643       "2:"
5644       "subs r0, r0, #16\n"
5645 
5646       // BiasAdd::Transform
5647       "vld1.32 {d0, d1}, [%[input]]!\n"
5648       "vld1.32 {d8, d9}, [r1]!\n"
5649       "pld [%[input], #32]\n"
5650       "vmovl.u8 q1, d1\n"
5651       "vmovl.u8 q0, d0\n"
5652       "vmovl.u8 q5, d9\n"
5653       "vmovl.u8 q4, d8\n"
5654       "vmovl.s16 q3, d3\n"
5655       "vmovl.s16 q2, d2\n"
5656       "vmovl.s16 q7, d11\n"
5657       "vmovl.s16 q6, d10\n"
5658       "vmovl.s16 q1, d1\n"
5659       "vmovl.s16 q0, d0\n"
5660       "vmovl.s16 q5, d9\n"
5661       "vmovl.s16 q4, d8\n"
5662       "vcvt.f32.s32 q0, q0\n"
5663       "vcvt.f32.s32 q1, q1\n"
5664       "vcvt.f32.s32 q2, q2\n"
5665       "vcvt.f32.s32 q3, q3\n"
5666       "vcvt.f32.s32 q4, q4\n"
5667       "vcvt.f32.s32 q5, q5\n"
5668       "vcvt.f32.s32 q6, q6\n"
5669       "vcvt.f32.s32 q7, q7\n"
5670       "vmul.f32 q0, q0, q9\n"
5671       "vmul.f32 q1, q1, q9\n"
5672       "vmul.f32 q2, q2, q9\n"
5673       "vmul.f32 q3, q3, q9\n"
5674       "vmul.f32 q4, q4, q11\n"
5675       "vmul.f32 q5, q5, q11\n"
5676       "vmul.f32 q6, q6, q11\n"
5677       "vmul.f32 q7, q7, q11\n"
5678       "vadd.f32 q0, q0, q8\n"
5679       "vadd.f32 q1, q1, q8\n"
5680       "vadd.f32 q2, q2, q8\n"
5681       "vadd.f32 q3, q3, q8\n"
5682       "vadd.f32 q4, q4, q10\n"
5683       "vadd.f32 q5, q5, q10\n"
5684       "vadd.f32 q6, q6, q10\n"
5685       "vadd.f32 q7, q7, q10\n"
5686       "vadd.f32 q0, q0, q4\n"
5687       "vadd.f32 q1, q1, q5\n"
5688       "vadd.f32 q2, q2, q6\n"
5689       "vadd.f32 q3, q3, q7\n"
5690       "vsub.f32 q0, q0, q12\n"
5691       "vsub.f32 q1, q1, q12\n"
5692       "vsub.f32 q2, q2, q12\n"
5693       "vsub.f32 q3, q3, q12\n"
5694       "vmul.f32 q0, q0, q13\n"
5695       "vmul.f32 q1, q1, q13\n"
5696       "vmul.f32 q2, q2, q13\n"
5697       "vmul.f32 q3, q3, q13\n"
5698       "vadd.f32 q0, q0, q14\n"
5699       "vadd.f32 q1, q1, q14\n"
5700       "vadd.f32 q2, q2, q14\n"
5701       "vadd.f32 q3, q3, q14\n"
5702       "vcvt.s32.f32 q0, q0\n"
5703       "vcvt.s32.f32 q1, q1\n"
5704       "vcvt.s32.f32 q2, q2\n"
5705       "vcvt.s32.f32 q3, q3\n"
5706 
5707       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
5708       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
5709       "pld [%[output]]\n"
5710       "bne 2b\n"
5711       "3:"
5712 
5713       // BiasAdd::Transform
5714       "vld1.8 {d0[0]}, [%[input]]!\n"
5715       "vld1.8 {d2[0]}, [r1]!\n"
5716       "pld [%[input], #32]\n"
5717       "vmovl.u8 q0, d0\n"
5718       "vmovl.u8 q1, d2\n"
5719       "vmovl.s16 q0, d0\n"
5720       "vmovl.s16 q1, d2\n"
5721       "vcvt.f32.s32 q0, q0\n"
5722       "vcvt.f32.s32 q1, q1\n"
5723       "vmul.f32 q0, q0, q9\n"
5724       "vmul.f32 q1, q1, q11\n"
5725       "vadd.f32 q0, q0, q8\n"
5726       "vadd.f32 q1, q1, q10\n"
5727       "vadd.f32 q0, q0, q1\n"
5728       "vsub.f32 q0, q0, q12\n"
5729       "vmul.f32 q0, q0, q13\n"
5730       "vadd.f32 q0, q0, q14\n"
5731       "vcvt.s32.f32 q0, q0\n"
5732 
5733       "vst1.32 {d0[0]}, [%[output]]!\n"
5734       "pld [%[output]]\n"
5735       "subs %[rows], %[rows], #1\n"
5736       "bne 1b\n"
5737       : [input] "+r"(input), [output] "+r"(output)
5738       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
5739         [output_range_offset] "m"(params.output_range_offset),
5740         [input_range_scale] "m"(params.input_range_scale),
5741         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
5742         [bias_range_min] "m"(params.bias_range_min),
5743         [output_range_min] "m"(params.output_range_min),
5744         [bias_range_scale] "m"(params.bias_range_scale),
5745         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
5746       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
5747         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
5748         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
5749         "cc", "memory");
5750 }
5751 
5752 template <>
5753 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)5754                               2>::Transform(const uint8_t* input,
5755                                             const BiasAdd<uint8_t>& params,
5756                                             int32_t* output) {
5757 #ifdef DEBUG
5758 #ifdef DEBUG_METAGEMM_VERBOSE
5759   std::cout << __FILE__ << "(" << __LINE__
5760             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
5761                "2>::Transform()"
5762             << std::endl
5763             << std::flush;
5764 #endif
5765 #endif
5766   int params_rows_copy = params.rows;
5767   asm volatile(
5768       "ldr r0, %[input_range_min]\n"
5769       "vdup.32 q8, r0\n"
5770       "ldr r0, %[input_range_scale]\n"
5771       "vdup.32 q9, r0\n"
5772       "ldr r0, %[bias_range_min]\n"
5773       "vdup.32 q10, r0\n"
5774       "ldr r0, %[bias_range_scale]\n"
5775       "vdup.32 q11, r0\n"
5776       "ldr r0, %[output_range_min]\n"
5777       "vdup.32 q12, r0\n"
5778       "ldr r0, %[one_over_output_range_scale]\n"
5779       "vdup.32 q13, r0\n"
5780       "ldr r0, %[output_range_offset]\n"
5781       "vdup.32 q14, r0\n"
5782       "1:"
5783       "mov r0, %[count]\n"
5784       "mov r1, %[bias]\n"
5785       "subs r0, r0, #2\n"
5786       "beq 3f\n"
5787       "2:"
5788       "subs r0, r0, #16\n"
5789 
5790       // BiasAdd::Transform
5791       "vld1.32 {d0, d1}, [%[input]]!\n"
5792       "vld1.32 {d8, d9}, [r1]!\n"
5793       "pld [%[input], #32]\n"
5794       "vmovl.u8 q1, d1\n"
5795       "vmovl.u8 q0, d0\n"
5796       "vmovl.u8 q5, d9\n"
5797       "vmovl.u8 q4, d8\n"
5798       "vmovl.s16 q3, d3\n"
5799       "vmovl.s16 q2, d2\n"
5800       "vmovl.s16 q7, d11\n"
5801       "vmovl.s16 q6, d10\n"
5802       "vmovl.s16 q1, d1\n"
5803       "vmovl.s16 q0, d0\n"
5804       "vmovl.s16 q5, d9\n"
5805       "vmovl.s16 q4, d8\n"
5806       "vcvt.f32.s32 q0, q0\n"
5807       "vcvt.f32.s32 q1, q1\n"
5808       "vcvt.f32.s32 q2, q2\n"
5809       "vcvt.f32.s32 q3, q3\n"
5810       "vcvt.f32.s32 q4, q4\n"
5811       "vcvt.f32.s32 q5, q5\n"
5812       "vcvt.f32.s32 q6, q6\n"
5813       "vcvt.f32.s32 q7, q7\n"
5814       "vmul.f32 q0, q0, q9\n"
5815       "vmul.f32 q1, q1, q9\n"
5816       "vmul.f32 q2, q2, q9\n"
5817       "vmul.f32 q3, q3, q9\n"
5818       "vmul.f32 q4, q4, q11\n"
5819       "vmul.f32 q5, q5, q11\n"
5820       "vmul.f32 q6, q6, q11\n"
5821       "vmul.f32 q7, q7, q11\n"
5822       "vadd.f32 q0, q0, q8\n"
5823       "vadd.f32 q1, q1, q8\n"
5824       "vadd.f32 q2, q2, q8\n"
5825       "vadd.f32 q3, q3, q8\n"
5826       "vadd.f32 q4, q4, q10\n"
5827       "vadd.f32 q5, q5, q10\n"
5828       "vadd.f32 q6, q6, q10\n"
5829       "vadd.f32 q7, q7, q10\n"
5830       "vadd.f32 q0, q0, q4\n"
5831       "vadd.f32 q1, q1, q5\n"
5832       "vadd.f32 q2, q2, q6\n"
5833       "vadd.f32 q3, q3, q7\n"
5834       "vsub.f32 q0, q0, q12\n"
5835       "vsub.f32 q1, q1, q12\n"
5836       "vsub.f32 q2, q2, q12\n"
5837       "vsub.f32 q3, q3, q12\n"
5838       "vmul.f32 q0, q0, q13\n"
5839       "vmul.f32 q1, q1, q13\n"
5840       "vmul.f32 q2, q2, q13\n"
5841       "vmul.f32 q3, q3, q13\n"
5842       "vadd.f32 q0, q0, q14\n"
5843       "vadd.f32 q1, q1, q14\n"
5844       "vadd.f32 q2, q2, q14\n"
5845       "vadd.f32 q3, q3, q14\n"
5846       "vcvt.s32.f32 q0, q0\n"
5847       "vcvt.s32.f32 q1, q1\n"
5848       "vcvt.s32.f32 q2, q2\n"
5849       "vcvt.s32.f32 q3, q3\n"
5850 
5851       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
5852       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
5853       "pld [%[output]]\n"
5854       "bne 2b\n"
5855       "3:"
5856 
5857       // BiasAdd::Transform
5858       "vld1.16 {d0[0]}, [%[input]]!\n"
5859       "vld1.16 {d2[0]}, [r1]!\n"
5860       "pld [%[input], #32]\n"
5861       "vmovl.u8 q0, d0\n"
5862       "vmovl.u8 q1, d2\n"
5863       "vmovl.s16 q0, d0\n"
5864       "vmovl.s16 q1, d2\n"
5865       "vcvt.f32.s32 q0, q0\n"
5866       "vcvt.f32.s32 q1, q1\n"
5867       "vmul.f32 q0, q0, q9\n"
5868       "vmul.f32 q1, q1, q11\n"
5869       "vadd.f32 q0, q0, q8\n"
5870       "vadd.f32 q1, q1, q10\n"
5871       "vadd.f32 q0, q0, q1\n"
5872       "vsub.f32 q0, q0, q12\n"
5873       "vmul.f32 q0, q0, q13\n"
5874       "vadd.f32 q0, q0, q14\n"
5875       "vcvt.s32.f32 q0, q0\n"
5876 
5877       "vst1.32 {d0}, [%[output]]!\n"
5878       "pld [%[output]]\n"
5879       "subs %[rows], %[rows], #1\n"
5880       "bne 1b\n"
5881       : [input] "+r"(input), [output] "+r"(output)
5882       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
5883         [output_range_offset] "m"(params.output_range_offset),
5884         [input_range_scale] "m"(params.input_range_scale),
5885         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
5886         [bias_range_min] "m"(params.bias_range_min),
5887         [output_range_min] "m"(params.output_range_min),
5888         [bias_range_scale] "m"(params.bias_range_scale),
5889         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
5890       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
5891         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
5892         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
5893         "cc", "memory");
5894 }
5895 
5896 template <>
5897 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)5898                               3>::Transform(const uint8_t* input,
5899                                             const BiasAdd<uint8_t>& params,
5900                                             int32_t* output) {
5901 #ifdef DEBUG
5902 #ifdef DEBUG_METAGEMM_VERBOSE
5903   std::cout << __FILE__ << "(" << __LINE__
5904             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
5905                "3>::Transform()"
5906             << std::endl
5907             << std::flush;
5908 #endif
5909 #endif
5910   int params_rows_copy = params.rows;
5911   asm volatile(
5912       "ldr r0, %[input_range_min]\n"
5913       "vdup.32 q8, r0\n"
5914       "ldr r0, %[input_range_scale]\n"
5915       "vdup.32 q9, r0\n"
5916       "ldr r0, %[bias_range_min]\n"
5917       "vdup.32 q10, r0\n"
5918       "ldr r0, %[bias_range_scale]\n"
5919       "vdup.32 q11, r0\n"
5920       "ldr r0, %[output_range_min]\n"
5921       "vdup.32 q12, r0\n"
5922       "ldr r0, %[one_over_output_range_scale]\n"
5923       "vdup.32 q13, r0\n"
5924       "ldr r0, %[output_range_offset]\n"
5925       "vdup.32 q14, r0\n"
5926       "1:"
5927       "mov r0, %[count]\n"
5928       "mov r1, %[bias]\n"
5929       "subs r0, r0, #3\n"
5930       "beq 3f\n"
5931       "2:"
5932       "subs r0, r0, #16\n"
5933 
5934       // BiasAdd::Transform
5935       "vld1.32 {d0, d1}, [%[input]]!\n"
5936       "vld1.32 {d8, d9}, [r1]!\n"
5937       "pld [%[input], #32]\n"
5938       "vmovl.u8 q1, d1\n"
5939       "vmovl.u8 q0, d0\n"
5940       "vmovl.u8 q5, d9\n"
5941       "vmovl.u8 q4, d8\n"
5942       "vmovl.s16 q3, d3\n"
5943       "vmovl.s16 q2, d2\n"
5944       "vmovl.s16 q7, d11\n"
5945       "vmovl.s16 q6, d10\n"
5946       "vmovl.s16 q1, d1\n"
5947       "vmovl.s16 q0, d0\n"
5948       "vmovl.s16 q5, d9\n"
5949       "vmovl.s16 q4, d8\n"
5950       "vcvt.f32.s32 q0, q0\n"
5951       "vcvt.f32.s32 q1, q1\n"
5952       "vcvt.f32.s32 q2, q2\n"
5953       "vcvt.f32.s32 q3, q3\n"
5954       "vcvt.f32.s32 q4, q4\n"
5955       "vcvt.f32.s32 q5, q5\n"
5956       "vcvt.f32.s32 q6, q6\n"
5957       "vcvt.f32.s32 q7, q7\n"
5958       "vmul.f32 q0, q0, q9\n"
5959       "vmul.f32 q1, q1, q9\n"
5960       "vmul.f32 q2, q2, q9\n"
5961       "vmul.f32 q3, q3, q9\n"
5962       "vmul.f32 q4, q4, q11\n"
5963       "vmul.f32 q5, q5, q11\n"
5964       "vmul.f32 q6, q6, q11\n"
5965       "vmul.f32 q7, q7, q11\n"
5966       "vadd.f32 q0, q0, q8\n"
5967       "vadd.f32 q1, q1, q8\n"
5968       "vadd.f32 q2, q2, q8\n"
5969       "vadd.f32 q3, q3, q8\n"
5970       "vadd.f32 q4, q4, q10\n"
5971       "vadd.f32 q5, q5, q10\n"
5972       "vadd.f32 q6, q6, q10\n"
5973       "vadd.f32 q7, q7, q10\n"
5974       "vadd.f32 q0, q0, q4\n"
5975       "vadd.f32 q1, q1, q5\n"
5976       "vadd.f32 q2, q2, q6\n"
5977       "vadd.f32 q3, q3, q7\n"
5978       "vsub.f32 q0, q0, q12\n"
5979       "vsub.f32 q1, q1, q12\n"
5980       "vsub.f32 q2, q2, q12\n"
5981       "vsub.f32 q3, q3, q12\n"
5982       "vmul.f32 q0, q0, q13\n"
5983       "vmul.f32 q1, q1, q13\n"
5984       "vmul.f32 q2, q2, q13\n"
5985       "vmul.f32 q3, q3, q13\n"
5986       "vadd.f32 q0, q0, q14\n"
5987       "vadd.f32 q1, q1, q14\n"
5988       "vadd.f32 q2, q2, q14\n"
5989       "vadd.f32 q3, q3, q14\n"
5990       "vcvt.s32.f32 q0, q0\n"
5991       "vcvt.s32.f32 q1, q1\n"
5992       "vcvt.s32.f32 q2, q2\n"
5993       "vcvt.s32.f32 q3, q3\n"
5994 
5995       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
5996       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
5997       "pld [%[output]]\n"
5998       "bne 2b\n"
5999       "3:"
6000 
6001       // BiasAdd::Transform
6002       "vld1.16 {d0[0]}, [%[input]]!\n"
6003       "vld1.8 {d0[2]}, [%[input]]!\n"
6004       "vld1.16 {d2[0]}, [r1]!\n"
6005       "vld1.8 {d2[2]}, [r1]!\n"
6006       "pld [%[input], #32]\n"
6007       "vmovl.u8 q0, d0\n"
6008       "vmovl.u8 q1, d2\n"
6009       "vmovl.s16 q0, d0\n"
6010       "vmovl.s16 q1, d2\n"
6011       "vcvt.f32.s32 q0, q0\n"
6012       "vcvt.f32.s32 q1, q1\n"
6013       "vmul.f32 q0, q0, q9\n"
6014       "vmul.f32 q1, q1, q11\n"
6015       "vadd.f32 q0, q0, q8\n"
6016       "vadd.f32 q1, q1, q10\n"
6017       "vadd.f32 q0, q0, q1\n"
6018       "vsub.f32 q0, q0, q12\n"
6019       "vmul.f32 q0, q0, q13\n"
6020       "vadd.f32 q0, q0, q14\n"
6021       "vcvt.s32.f32 q0, q0\n"
6022 
6023       "vst1.32 {d0}, [%[output]]!\n"
6024       "vst1.32 {d1[0]}, [%[output]]!\n"
6025       "pld [%[output]]\n"
6026       "subs %[rows], %[rows], #1\n"
6027       "bne 1b\n"
6028       : [input] "+r"(input), [output] "+r"(output)
6029       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6030         [output_range_offset] "m"(params.output_range_offset),
6031         [input_range_scale] "m"(params.input_range_scale),
6032         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6033         [bias_range_min] "m"(params.bias_range_min),
6034         [output_range_min] "m"(params.output_range_min),
6035         [bias_range_scale] "m"(params.bias_range_scale),
6036         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6037       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6038         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6039         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6040         "cc", "memory");
6041 }
6042 
6043 template <>
6044 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)6045                               4>::Transform(const uint8_t* input,
6046                                             const BiasAdd<uint8_t>& params,
6047                                             int32_t* output) {
6048 #ifdef DEBUG
6049 #ifdef DEBUG_METAGEMM_VERBOSE
6050   std::cout << __FILE__ << "(" << __LINE__
6051             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
6052                "4>::Transform()"
6053             << std::endl
6054             << std::flush;
6055 #endif
6056 #endif
6057   int params_rows_copy = params.rows;
6058   asm volatile(
6059       "ldr r0, %[input_range_min]\n"
6060       "vdup.32 q8, r0\n"
6061       "ldr r0, %[input_range_scale]\n"
6062       "vdup.32 q9, r0\n"
6063       "ldr r0, %[bias_range_min]\n"
6064       "vdup.32 q10, r0\n"
6065       "ldr r0, %[bias_range_scale]\n"
6066       "vdup.32 q11, r0\n"
6067       "ldr r0, %[output_range_min]\n"
6068       "vdup.32 q12, r0\n"
6069       "ldr r0, %[one_over_output_range_scale]\n"
6070       "vdup.32 q13, r0\n"
6071       "ldr r0, %[output_range_offset]\n"
6072       "vdup.32 q14, r0\n"
6073       "1:"
6074       "mov r0, %[count]\n"
6075       "mov r1, %[bias]\n"
6076       "subs r0, r0, #4\n"
6077       "beq 3f\n"
6078       "2:"
6079       "subs r0, r0, #16\n"
6080 
6081       // BiasAdd::Transform
6082       "vld1.32 {d0, d1}, [%[input]]!\n"
6083       "vld1.32 {d8, d9}, [r1]!\n"
6084       "pld [%[input], #32]\n"
6085       "vmovl.u8 q1, d1\n"
6086       "vmovl.u8 q0, d0\n"
6087       "vmovl.u8 q5, d9\n"
6088       "vmovl.u8 q4, d8\n"
6089       "vmovl.s16 q3, d3\n"
6090       "vmovl.s16 q2, d2\n"
6091       "vmovl.s16 q7, d11\n"
6092       "vmovl.s16 q6, d10\n"
6093       "vmovl.s16 q1, d1\n"
6094       "vmovl.s16 q0, d0\n"
6095       "vmovl.s16 q5, d9\n"
6096       "vmovl.s16 q4, d8\n"
6097       "vcvt.f32.s32 q0, q0\n"
6098       "vcvt.f32.s32 q1, q1\n"
6099       "vcvt.f32.s32 q2, q2\n"
6100       "vcvt.f32.s32 q3, q3\n"
6101       "vcvt.f32.s32 q4, q4\n"
6102       "vcvt.f32.s32 q5, q5\n"
6103       "vcvt.f32.s32 q6, q6\n"
6104       "vcvt.f32.s32 q7, q7\n"
6105       "vmul.f32 q0, q0, q9\n"
6106       "vmul.f32 q1, q1, q9\n"
6107       "vmul.f32 q2, q2, q9\n"
6108       "vmul.f32 q3, q3, q9\n"
6109       "vmul.f32 q4, q4, q11\n"
6110       "vmul.f32 q5, q5, q11\n"
6111       "vmul.f32 q6, q6, q11\n"
6112       "vmul.f32 q7, q7, q11\n"
6113       "vadd.f32 q0, q0, q8\n"
6114       "vadd.f32 q1, q1, q8\n"
6115       "vadd.f32 q2, q2, q8\n"
6116       "vadd.f32 q3, q3, q8\n"
6117       "vadd.f32 q4, q4, q10\n"
6118       "vadd.f32 q5, q5, q10\n"
6119       "vadd.f32 q6, q6, q10\n"
6120       "vadd.f32 q7, q7, q10\n"
6121       "vadd.f32 q0, q0, q4\n"
6122       "vadd.f32 q1, q1, q5\n"
6123       "vadd.f32 q2, q2, q6\n"
6124       "vadd.f32 q3, q3, q7\n"
6125       "vsub.f32 q0, q0, q12\n"
6126       "vsub.f32 q1, q1, q12\n"
6127       "vsub.f32 q2, q2, q12\n"
6128       "vsub.f32 q3, q3, q12\n"
6129       "vmul.f32 q0, q0, q13\n"
6130       "vmul.f32 q1, q1, q13\n"
6131       "vmul.f32 q2, q2, q13\n"
6132       "vmul.f32 q3, q3, q13\n"
6133       "vadd.f32 q0, q0, q14\n"
6134       "vadd.f32 q1, q1, q14\n"
6135       "vadd.f32 q2, q2, q14\n"
6136       "vadd.f32 q3, q3, q14\n"
6137       "vcvt.s32.f32 q0, q0\n"
6138       "vcvt.s32.f32 q1, q1\n"
6139       "vcvt.s32.f32 q2, q2\n"
6140       "vcvt.s32.f32 q3, q3\n"
6141 
6142       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6143       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
6144       "pld [%[output]]\n"
6145       "bne 2b\n"
6146       "3:"
6147 
6148       // BiasAdd::Transform
6149       "vld1.32 {d0[0]}, [%[input]]!\n"
6150       "vld1.32 {d2[0]}, [r1]!\n"
6151       "pld [%[input], #32]\n"
6152       "vmovl.u8 q0, d0\n"
6153       "vmovl.u8 q1, d2\n"
6154       "vmovl.s16 q0, d0\n"
6155       "vmovl.s16 q1, d2\n"
6156       "vcvt.f32.s32 q0, q0\n"
6157       "vcvt.f32.s32 q1, q1\n"
6158       "vmul.f32 q0, q0, q9\n"
6159       "vmul.f32 q1, q1, q11\n"
6160       "vadd.f32 q0, q0, q8\n"
6161       "vadd.f32 q1, q1, q10\n"
6162       "vadd.f32 q0, q0, q1\n"
6163       "vsub.f32 q0, q0, q12\n"
6164       "vmul.f32 q0, q0, q13\n"
6165       "vadd.f32 q0, q0, q14\n"
6166       "vcvt.s32.f32 q0, q0\n"
6167 
6168       "vst1.32 {d0, d1}, [%[output]]!\n"
6169       "pld [%[output]]\n"
6170       "subs %[rows], %[rows], #1\n"
6171       "bne 1b\n"
6172       : [input] "+r"(input), [output] "+r"(output)
6173       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6174         [output_range_offset] "m"(params.output_range_offset),
6175         [input_range_scale] "m"(params.input_range_scale),
6176         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6177         [bias_range_min] "m"(params.bias_range_min),
6178         [output_range_min] "m"(params.output_range_min),
6179         [bias_range_scale] "m"(params.bias_range_scale),
6180         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6181       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6182         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6183         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6184         "cc", "memory");
6185 }
6186 
6187 template <>
6188 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)6189                               5>::Transform(const uint8_t* input,
6190                                             const BiasAdd<uint8_t>& params,
6191                                             int32_t* output) {
6192 #ifdef DEBUG
6193 #ifdef DEBUG_METAGEMM_VERBOSE
6194   std::cout << __FILE__ << "(" << __LINE__
6195             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
6196                "5>::Transform()"
6197             << std::endl
6198             << std::flush;
6199 #endif
6200 #endif
6201   int params_rows_copy = params.rows;
6202   asm volatile(
6203       "ldr r0, %[input_range_min]\n"
6204       "vdup.32 q8, r0\n"
6205       "ldr r0, %[input_range_scale]\n"
6206       "vdup.32 q9, r0\n"
6207       "ldr r0, %[bias_range_min]\n"
6208       "vdup.32 q10, r0\n"
6209       "ldr r0, %[bias_range_scale]\n"
6210       "vdup.32 q11, r0\n"
6211       "ldr r0, %[output_range_min]\n"
6212       "vdup.32 q12, r0\n"
6213       "ldr r0, %[one_over_output_range_scale]\n"
6214       "vdup.32 q13, r0\n"
6215       "ldr r0, %[output_range_offset]\n"
6216       "vdup.32 q14, r0\n"
6217       "1:"
6218       "mov r0, %[count]\n"
6219       "mov r1, %[bias]\n"
6220       "subs r0, r0, #5\n"
6221       "beq 3f\n"
6222       "2:"
6223       "subs r0, r0, #16\n"
6224 
6225       // BiasAdd::Transform
6226       "vld1.32 {d0, d1}, [%[input]]!\n"
6227       "vld1.32 {d8, d9}, [r1]!\n"
6228       "pld [%[input], #32]\n"
6229       "vmovl.u8 q1, d1\n"
6230       "vmovl.u8 q0, d0\n"
6231       "vmovl.u8 q5, d9\n"
6232       "vmovl.u8 q4, d8\n"
6233       "vmovl.s16 q3, d3\n"
6234       "vmovl.s16 q2, d2\n"
6235       "vmovl.s16 q7, d11\n"
6236       "vmovl.s16 q6, d10\n"
6237       "vmovl.s16 q1, d1\n"
6238       "vmovl.s16 q0, d0\n"
6239       "vmovl.s16 q5, d9\n"
6240       "vmovl.s16 q4, d8\n"
6241       "vcvt.f32.s32 q0, q0\n"
6242       "vcvt.f32.s32 q1, q1\n"
6243       "vcvt.f32.s32 q2, q2\n"
6244       "vcvt.f32.s32 q3, q3\n"
6245       "vcvt.f32.s32 q4, q4\n"
6246       "vcvt.f32.s32 q5, q5\n"
6247       "vcvt.f32.s32 q6, q6\n"
6248       "vcvt.f32.s32 q7, q7\n"
6249       "vmul.f32 q0, q0, q9\n"
6250       "vmul.f32 q1, q1, q9\n"
6251       "vmul.f32 q2, q2, q9\n"
6252       "vmul.f32 q3, q3, q9\n"
6253       "vmul.f32 q4, q4, q11\n"
6254       "vmul.f32 q5, q5, q11\n"
6255       "vmul.f32 q6, q6, q11\n"
6256       "vmul.f32 q7, q7, q11\n"
6257       "vadd.f32 q0, q0, q8\n"
6258       "vadd.f32 q1, q1, q8\n"
6259       "vadd.f32 q2, q2, q8\n"
6260       "vadd.f32 q3, q3, q8\n"
6261       "vadd.f32 q4, q4, q10\n"
6262       "vadd.f32 q5, q5, q10\n"
6263       "vadd.f32 q6, q6, q10\n"
6264       "vadd.f32 q7, q7, q10\n"
6265       "vadd.f32 q0, q0, q4\n"
6266       "vadd.f32 q1, q1, q5\n"
6267       "vadd.f32 q2, q2, q6\n"
6268       "vadd.f32 q3, q3, q7\n"
6269       "vsub.f32 q0, q0, q12\n"
6270       "vsub.f32 q1, q1, q12\n"
6271       "vsub.f32 q2, q2, q12\n"
6272       "vsub.f32 q3, q3, q12\n"
6273       "vmul.f32 q0, q0, q13\n"
6274       "vmul.f32 q1, q1, q13\n"
6275       "vmul.f32 q2, q2, q13\n"
6276       "vmul.f32 q3, q3, q13\n"
6277       "vadd.f32 q0, q0, q14\n"
6278       "vadd.f32 q1, q1, q14\n"
6279       "vadd.f32 q2, q2, q14\n"
6280       "vadd.f32 q3, q3, q14\n"
6281       "vcvt.s32.f32 q0, q0\n"
6282       "vcvt.s32.f32 q1, q1\n"
6283       "vcvt.s32.f32 q2, q2\n"
6284       "vcvt.s32.f32 q3, q3\n"
6285 
6286       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6287       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
6288       "pld [%[output]]\n"
6289       "bne 2b\n"
6290       "3:"
6291 
6292       // BiasAdd::Transform
6293       "vld1.32 {d0[0]}, [%[input]]!\n"
6294       "vld1.8 {d0[4]}, [%[input]]!\n"
6295       "vld1.32 {d4[0]}, [r1]!\n"
6296       "vld1.8 {d4[4]}, [r1]!\n"
6297       "pld [%[input], #32]\n"
6298       "vmovl.u8 q0, d0\n"
6299       "vmovl.u8 q2, d4\n"
6300       "vmovl.s16 q1, d1\n"
6301       "vmovl.s16 q0, d0\n"
6302       "vmovl.s16 q3, d5\n"
6303       "vmovl.s16 q2, d4\n"
6304       "vcvt.f32.s32 q0, q0\n"
6305       "vcvt.f32.s32 q1, q1\n"
6306       "vcvt.f32.s32 q2, q2\n"
6307       "vcvt.f32.s32 q3, q3\n"
6308       "vmul.f32 q0, q0, q9\n"
6309       "vmul.f32 q1, q1, q9\n"
6310       "vmul.f32 q2, q2, q11\n"
6311       "vmul.f32 q3, q3, q11\n"
6312       "vadd.f32 q0, q0, q8\n"
6313       "vadd.f32 q1, q1, q8\n"
6314       "vadd.f32 q2, q2, q10\n"
6315       "vadd.f32 q3, q3, q10\n"
6316       "vadd.f32 q0, q0, q2\n"
6317       "vadd.f32 q1, q1, q3\n"
6318       "vsub.f32 q0, q0, q12\n"
6319       "vsub.f32 q1, q1, q12\n"
6320       "vmul.f32 q0, q0, q13\n"
6321       "vmul.f32 q1, q1, q13\n"
6322       "vadd.f32 q0, q0, q14\n"
6323       "vadd.f32 q1, q1, q14\n"
6324       "vcvt.s32.f32 q0, q0\n"
6325       "vcvt.s32.f32 q1, q1\n"
6326 
6327       "vst1.32 {d0, d1}, [%[output]]!\n"
6328       "vst1.32 {d2[0]}, [%[output]]!\n"
6329       "pld [%[output]]\n"
6330       "subs %[rows], %[rows], #1\n"
6331       "bne 1b\n"
6332       : [input] "+r"(input), [output] "+r"(output)
6333       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6334         [output_range_offset] "m"(params.output_range_offset),
6335         [input_range_scale] "m"(params.input_range_scale),
6336         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6337         [bias_range_min] "m"(params.bias_range_min),
6338         [output_range_min] "m"(params.output_range_min),
6339         [bias_range_scale] "m"(params.bias_range_scale),
6340         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6341       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6342         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6343         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6344         "cc", "memory");
6345 }
6346 
6347 template <>
6348 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)6349                               6>::Transform(const uint8_t* input,
6350                                             const BiasAdd<uint8_t>& params,
6351                                             int32_t* output) {
6352 #ifdef DEBUG
6353 #ifdef DEBUG_METAGEMM_VERBOSE
6354   std::cout << __FILE__ << "(" << __LINE__
6355             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
6356                "6>::Transform()"
6357             << std::endl
6358             << std::flush;
6359 #endif
6360 #endif
6361   int params_rows_copy = params.rows;
6362   asm volatile(
6363       "ldr r0, %[input_range_min]\n"
6364       "vdup.32 q8, r0\n"
6365       "ldr r0, %[input_range_scale]\n"
6366       "vdup.32 q9, r0\n"
6367       "ldr r0, %[bias_range_min]\n"
6368       "vdup.32 q10, r0\n"
6369       "ldr r0, %[bias_range_scale]\n"
6370       "vdup.32 q11, r0\n"
6371       "ldr r0, %[output_range_min]\n"
6372       "vdup.32 q12, r0\n"
6373       "ldr r0, %[one_over_output_range_scale]\n"
6374       "vdup.32 q13, r0\n"
6375       "ldr r0, %[output_range_offset]\n"
6376       "vdup.32 q14, r0\n"
6377       "1:"
6378       "mov r0, %[count]\n"
6379       "mov r1, %[bias]\n"
6380       "subs r0, r0, #6\n"
6381       "beq 3f\n"
6382       "2:"
6383       "subs r0, r0, #16\n"
6384 
6385       // BiasAdd::Transform
6386       "vld1.32 {d0, d1}, [%[input]]!\n"
6387       "vld1.32 {d8, d9}, [r1]!\n"
6388       "pld [%[input], #32]\n"
6389       "vmovl.u8 q1, d1\n"
6390       "vmovl.u8 q0, d0\n"
6391       "vmovl.u8 q5, d9\n"
6392       "vmovl.u8 q4, d8\n"
6393       "vmovl.s16 q3, d3\n"
6394       "vmovl.s16 q2, d2\n"
6395       "vmovl.s16 q7, d11\n"
6396       "vmovl.s16 q6, d10\n"
6397       "vmovl.s16 q1, d1\n"
6398       "vmovl.s16 q0, d0\n"
6399       "vmovl.s16 q5, d9\n"
6400       "vmovl.s16 q4, d8\n"
6401       "vcvt.f32.s32 q0, q0\n"
6402       "vcvt.f32.s32 q1, q1\n"
6403       "vcvt.f32.s32 q2, q2\n"
6404       "vcvt.f32.s32 q3, q3\n"
6405       "vcvt.f32.s32 q4, q4\n"
6406       "vcvt.f32.s32 q5, q5\n"
6407       "vcvt.f32.s32 q6, q6\n"
6408       "vcvt.f32.s32 q7, q7\n"
6409       "vmul.f32 q0, q0, q9\n"
6410       "vmul.f32 q1, q1, q9\n"
6411       "vmul.f32 q2, q2, q9\n"
6412       "vmul.f32 q3, q3, q9\n"
6413       "vmul.f32 q4, q4, q11\n"
6414       "vmul.f32 q5, q5, q11\n"
6415       "vmul.f32 q6, q6, q11\n"
6416       "vmul.f32 q7, q7, q11\n"
6417       "vadd.f32 q0, q0, q8\n"
6418       "vadd.f32 q1, q1, q8\n"
6419       "vadd.f32 q2, q2, q8\n"
6420       "vadd.f32 q3, q3, q8\n"
6421       "vadd.f32 q4, q4, q10\n"
6422       "vadd.f32 q5, q5, q10\n"
6423       "vadd.f32 q6, q6, q10\n"
6424       "vadd.f32 q7, q7, q10\n"
6425       "vadd.f32 q0, q0, q4\n"
6426       "vadd.f32 q1, q1, q5\n"
6427       "vadd.f32 q2, q2, q6\n"
6428       "vadd.f32 q3, q3, q7\n"
6429       "vsub.f32 q0, q0, q12\n"
6430       "vsub.f32 q1, q1, q12\n"
6431       "vsub.f32 q2, q2, q12\n"
6432       "vsub.f32 q3, q3, q12\n"
6433       "vmul.f32 q0, q0, q13\n"
6434       "vmul.f32 q1, q1, q13\n"
6435       "vmul.f32 q2, q2, q13\n"
6436       "vmul.f32 q3, q3, q13\n"
6437       "vadd.f32 q0, q0, q14\n"
6438       "vadd.f32 q1, q1, q14\n"
6439       "vadd.f32 q2, q2, q14\n"
6440       "vadd.f32 q3, q3, q14\n"
6441       "vcvt.s32.f32 q0, q0\n"
6442       "vcvt.s32.f32 q1, q1\n"
6443       "vcvt.s32.f32 q2, q2\n"
6444       "vcvt.s32.f32 q3, q3\n"
6445 
6446       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6447       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
6448       "pld [%[output]]\n"
6449       "bne 2b\n"
6450       "3:"
6451 
6452       // BiasAdd::Transform
6453       "vld1.32 {d0[0]}, [%[input]]!\n"
6454       "vld1.16 {d0[2]}, [%[input]]!\n"
6455       "vld1.32 {d4[0]}, [r1]!\n"
6456       "vld1.16 {d4[2]}, [r1]!\n"
6457       "pld [%[input], #32]\n"
6458       "vmovl.u8 q0, d0\n"
6459       "vmovl.u8 q2, d4\n"
6460       "vmovl.s16 q1, d1\n"
6461       "vmovl.s16 q0, d0\n"
6462       "vmovl.s16 q3, d5\n"
6463       "vmovl.s16 q2, d4\n"
6464       "vcvt.f32.s32 q0, q0\n"
6465       "vcvt.f32.s32 q1, q1\n"
6466       "vcvt.f32.s32 q2, q2\n"
6467       "vcvt.f32.s32 q3, q3\n"
6468       "vmul.f32 q0, q0, q9\n"
6469       "vmul.f32 q1, q1, q9\n"
6470       "vmul.f32 q2, q2, q11\n"
6471       "vmul.f32 q3, q3, q11\n"
6472       "vadd.f32 q0, q0, q8\n"
6473       "vadd.f32 q1, q1, q8\n"
6474       "vadd.f32 q2, q2, q10\n"
6475       "vadd.f32 q3, q3, q10\n"
6476       "vadd.f32 q0, q0, q2\n"
6477       "vadd.f32 q1, q1, q3\n"
6478       "vsub.f32 q0, q0, q12\n"
6479       "vsub.f32 q1, q1, q12\n"
6480       "vmul.f32 q0, q0, q13\n"
6481       "vmul.f32 q1, q1, q13\n"
6482       "vadd.f32 q0, q0, q14\n"
6483       "vadd.f32 q1, q1, q14\n"
6484       "vcvt.s32.f32 q0, q0\n"
6485       "vcvt.s32.f32 q1, q1\n"
6486 
6487       "vst1.32 {d0, d1, d2}, [%[output]]!\n"
6488       "pld [%[output]]\n"
6489       "subs %[rows], %[rows], #1\n"
6490       "bne 1b\n"
6491       : [input] "+r"(input), [output] "+r"(output)
6492       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6493         [output_range_offset] "m"(params.output_range_offset),
6494         [input_range_scale] "m"(params.input_range_scale),
6495         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6496         [bias_range_min] "m"(params.bias_range_min),
6497         [output_range_min] "m"(params.output_range_min),
6498         [bias_range_scale] "m"(params.bias_range_scale),
6499         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6500       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6501         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6502         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6503         "cc", "memory");
6504 }
6505 
6506 template <>
6507 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)6508                               7>::Transform(const uint8_t* input,
6509                                             const BiasAdd<uint8_t>& params,
6510                                             int32_t* output) {
6511 #ifdef DEBUG
6512 #ifdef DEBUG_METAGEMM_VERBOSE
6513   std::cout << __FILE__ << "(" << __LINE__
6514             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
6515                "7>::Transform()"
6516             << std::endl
6517             << std::flush;
6518 #endif
6519 #endif
6520   int params_rows_copy = params.rows;
6521   asm volatile(
6522       "ldr r0, %[input_range_min]\n"
6523       "vdup.32 q8, r0\n"
6524       "ldr r0, %[input_range_scale]\n"
6525       "vdup.32 q9, r0\n"
6526       "ldr r0, %[bias_range_min]\n"
6527       "vdup.32 q10, r0\n"
6528       "ldr r0, %[bias_range_scale]\n"
6529       "vdup.32 q11, r0\n"
6530       "ldr r0, %[output_range_min]\n"
6531       "vdup.32 q12, r0\n"
6532       "ldr r0, %[one_over_output_range_scale]\n"
6533       "vdup.32 q13, r0\n"
6534       "ldr r0, %[output_range_offset]\n"
6535       "vdup.32 q14, r0\n"
6536       "1:"
6537       "mov r0, %[count]\n"
6538       "mov r1, %[bias]\n"
6539       "subs r0, r0, #7\n"
6540       "beq 3f\n"
6541       "2:"
6542       "subs r0, r0, #16\n"
6543 
6544       // BiasAdd::Transform
6545       "vld1.32 {d0, d1}, [%[input]]!\n"
6546       "vld1.32 {d8, d9}, [r1]!\n"
6547       "pld [%[input], #32]\n"
6548       "vmovl.u8 q1, d1\n"
6549       "vmovl.u8 q0, d0\n"
6550       "vmovl.u8 q5, d9\n"
6551       "vmovl.u8 q4, d8\n"
6552       "vmovl.s16 q3, d3\n"
6553       "vmovl.s16 q2, d2\n"
6554       "vmovl.s16 q7, d11\n"
6555       "vmovl.s16 q6, d10\n"
6556       "vmovl.s16 q1, d1\n"
6557       "vmovl.s16 q0, d0\n"
6558       "vmovl.s16 q5, d9\n"
6559       "vmovl.s16 q4, d8\n"
6560       "vcvt.f32.s32 q0, q0\n"
6561       "vcvt.f32.s32 q1, q1\n"
6562       "vcvt.f32.s32 q2, q2\n"
6563       "vcvt.f32.s32 q3, q3\n"
6564       "vcvt.f32.s32 q4, q4\n"
6565       "vcvt.f32.s32 q5, q5\n"
6566       "vcvt.f32.s32 q6, q6\n"
6567       "vcvt.f32.s32 q7, q7\n"
6568       "vmul.f32 q0, q0, q9\n"
6569       "vmul.f32 q1, q1, q9\n"
6570       "vmul.f32 q2, q2, q9\n"
6571       "vmul.f32 q3, q3, q9\n"
6572       "vmul.f32 q4, q4, q11\n"
6573       "vmul.f32 q5, q5, q11\n"
6574       "vmul.f32 q6, q6, q11\n"
6575       "vmul.f32 q7, q7, q11\n"
6576       "vadd.f32 q0, q0, q8\n"
6577       "vadd.f32 q1, q1, q8\n"
6578       "vadd.f32 q2, q2, q8\n"
6579       "vadd.f32 q3, q3, q8\n"
6580       "vadd.f32 q4, q4, q10\n"
6581       "vadd.f32 q5, q5, q10\n"
6582       "vadd.f32 q6, q6, q10\n"
6583       "vadd.f32 q7, q7, q10\n"
6584       "vadd.f32 q0, q0, q4\n"
6585       "vadd.f32 q1, q1, q5\n"
6586       "vadd.f32 q2, q2, q6\n"
6587       "vadd.f32 q3, q3, q7\n"
6588       "vsub.f32 q0, q0, q12\n"
6589       "vsub.f32 q1, q1, q12\n"
6590       "vsub.f32 q2, q2, q12\n"
6591       "vsub.f32 q3, q3, q12\n"
6592       "vmul.f32 q0, q0, q13\n"
6593       "vmul.f32 q1, q1, q13\n"
6594       "vmul.f32 q2, q2, q13\n"
6595       "vmul.f32 q3, q3, q13\n"
6596       "vadd.f32 q0, q0, q14\n"
6597       "vadd.f32 q1, q1, q14\n"
6598       "vadd.f32 q2, q2, q14\n"
6599       "vadd.f32 q3, q3, q14\n"
6600       "vcvt.s32.f32 q0, q0\n"
6601       "vcvt.s32.f32 q1, q1\n"
6602       "vcvt.s32.f32 q2, q2\n"
6603       "vcvt.s32.f32 q3, q3\n"
6604 
6605       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6606       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
6607       "pld [%[output]]\n"
6608       "bne 2b\n"
6609       "3:"
6610 
6611       // BiasAdd::Transform
6612       "vld1.32 {d0[0]}, [%[input]]!\n"
6613       "vld1.16 {d0[2]}, [%[input]]!\n"
6614       "vld1.8 {d0[6]}, [%[input]]!\n"
6615       "vld1.32 {d4[0]}, [r1]!\n"
6616       "vld1.16 {d4[2]}, [r1]!\n"
6617       "vld1.8 {d4[6]}, [r1]!\n"
6618       "pld [%[input], #32]\n"
6619       "vmovl.u8 q0, d0\n"
6620       "vmovl.u8 q2, d4\n"
6621       "vmovl.s16 q1, d1\n"
6622       "vmovl.s16 q0, d0\n"
6623       "vmovl.s16 q3, d5\n"
6624       "vmovl.s16 q2, d4\n"
6625       "vcvt.f32.s32 q0, q0\n"
6626       "vcvt.f32.s32 q1, q1\n"
6627       "vcvt.f32.s32 q2, q2\n"
6628       "vcvt.f32.s32 q3, q3\n"
6629       "vmul.f32 q0, q0, q9\n"
6630       "vmul.f32 q1, q1, q9\n"
6631       "vmul.f32 q2, q2, q11\n"
6632       "vmul.f32 q3, q3, q11\n"
6633       "vadd.f32 q0, q0, q8\n"
6634       "vadd.f32 q1, q1, q8\n"
6635       "vadd.f32 q2, q2, q10\n"
6636       "vadd.f32 q3, q3, q10\n"
6637       "vadd.f32 q0, q0, q2\n"
6638       "vadd.f32 q1, q1, q3\n"
6639       "vsub.f32 q0, q0, q12\n"
6640       "vsub.f32 q1, q1, q12\n"
6641       "vmul.f32 q0, q0, q13\n"
6642       "vmul.f32 q1, q1, q13\n"
6643       "vadd.f32 q0, q0, q14\n"
6644       "vadd.f32 q1, q1, q14\n"
6645       "vcvt.s32.f32 q0, q0\n"
6646       "vcvt.s32.f32 q1, q1\n"
6647 
6648       "vst1.32 {d0, d1, d2}, [%[output]]!\n"
6649       "vst1.32 {d3[0]}, [%[output]]!\n"
6650       "pld [%[output]]\n"
6651       "subs %[rows], %[rows], #1\n"
6652       "bne 1b\n"
6653       : [input] "+r"(input), [output] "+r"(output)
6654       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6655         [output_range_offset] "m"(params.output_range_offset),
6656         [input_range_scale] "m"(params.input_range_scale),
6657         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6658         [bias_range_min] "m"(params.bias_range_min),
6659         [output_range_min] "m"(params.output_range_min),
6660         [bias_range_scale] "m"(params.bias_range_scale),
6661         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6662       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6663         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6664         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6665         "cc", "memory");
6666 }
6667 
6668 template <>
6669 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)6670                               8>::Transform(const uint8_t* input,
6671                                             const BiasAdd<uint8_t>& params,
6672                                             int32_t* output) {
6673 #ifdef DEBUG
6674 #ifdef DEBUG_METAGEMM_VERBOSE
6675   std::cout << __FILE__ << "(" << __LINE__
6676             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
6677                "8>::Transform()"
6678             << std::endl
6679             << std::flush;
6680 #endif
6681 #endif
6682   int params_rows_copy = params.rows;
6683   asm volatile(
6684       "ldr r0, %[input_range_min]\n"
6685       "vdup.32 q8, r0\n"
6686       "ldr r0, %[input_range_scale]\n"
6687       "vdup.32 q9, r0\n"
6688       "ldr r0, %[bias_range_min]\n"
6689       "vdup.32 q10, r0\n"
6690       "ldr r0, %[bias_range_scale]\n"
6691       "vdup.32 q11, r0\n"
6692       "ldr r0, %[output_range_min]\n"
6693       "vdup.32 q12, r0\n"
6694       "ldr r0, %[one_over_output_range_scale]\n"
6695       "vdup.32 q13, r0\n"
6696       "ldr r0, %[output_range_offset]\n"
6697       "vdup.32 q14, r0\n"
6698       "1:"
6699       "mov r0, %[count]\n"
6700       "mov r1, %[bias]\n"
6701       "subs r0, r0, #8\n"
6702       "beq 3f\n"
6703       "2:"
6704       "subs r0, r0, #16\n"
6705 
6706       // BiasAdd::Transform
6707       "vld1.32 {d0, d1}, [%[input]]!\n"
6708       "vld1.32 {d8, d9}, [r1]!\n"
6709       "pld [%[input], #32]\n"
6710       "vmovl.u8 q1, d1\n"
6711       "vmovl.u8 q0, d0\n"
6712       "vmovl.u8 q5, d9\n"
6713       "vmovl.u8 q4, d8\n"
6714       "vmovl.s16 q3, d3\n"
6715       "vmovl.s16 q2, d2\n"
6716       "vmovl.s16 q7, d11\n"
6717       "vmovl.s16 q6, d10\n"
6718       "vmovl.s16 q1, d1\n"
6719       "vmovl.s16 q0, d0\n"
6720       "vmovl.s16 q5, d9\n"
6721       "vmovl.s16 q4, d8\n"
6722       "vcvt.f32.s32 q0, q0\n"
6723       "vcvt.f32.s32 q1, q1\n"
6724       "vcvt.f32.s32 q2, q2\n"
6725       "vcvt.f32.s32 q3, q3\n"
6726       "vcvt.f32.s32 q4, q4\n"
6727       "vcvt.f32.s32 q5, q5\n"
6728       "vcvt.f32.s32 q6, q6\n"
6729       "vcvt.f32.s32 q7, q7\n"
6730       "vmul.f32 q0, q0, q9\n"
6731       "vmul.f32 q1, q1, q9\n"
6732       "vmul.f32 q2, q2, q9\n"
6733       "vmul.f32 q3, q3, q9\n"
6734       "vmul.f32 q4, q4, q11\n"
6735       "vmul.f32 q5, q5, q11\n"
6736       "vmul.f32 q6, q6, q11\n"
6737       "vmul.f32 q7, q7, q11\n"
6738       "vadd.f32 q0, q0, q8\n"
6739       "vadd.f32 q1, q1, q8\n"
6740       "vadd.f32 q2, q2, q8\n"
6741       "vadd.f32 q3, q3, q8\n"
6742       "vadd.f32 q4, q4, q10\n"
6743       "vadd.f32 q5, q5, q10\n"
6744       "vadd.f32 q6, q6, q10\n"
6745       "vadd.f32 q7, q7, q10\n"
6746       "vadd.f32 q0, q0, q4\n"
6747       "vadd.f32 q1, q1, q5\n"
6748       "vadd.f32 q2, q2, q6\n"
6749       "vadd.f32 q3, q3, q7\n"
6750       "vsub.f32 q0, q0, q12\n"
6751       "vsub.f32 q1, q1, q12\n"
6752       "vsub.f32 q2, q2, q12\n"
6753       "vsub.f32 q3, q3, q12\n"
6754       "vmul.f32 q0, q0, q13\n"
6755       "vmul.f32 q1, q1, q13\n"
6756       "vmul.f32 q2, q2, q13\n"
6757       "vmul.f32 q3, q3, q13\n"
6758       "vadd.f32 q0, q0, q14\n"
6759       "vadd.f32 q1, q1, q14\n"
6760       "vadd.f32 q2, q2, q14\n"
6761       "vadd.f32 q3, q3, q14\n"
6762       "vcvt.s32.f32 q0, q0\n"
6763       "vcvt.s32.f32 q1, q1\n"
6764       "vcvt.s32.f32 q2, q2\n"
6765       "vcvt.s32.f32 q3, q3\n"
6766 
6767       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6768       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
6769       "pld [%[output]]\n"
6770       "bne 2b\n"
6771       "3:"
6772 
6773       // BiasAdd::Transform
6774       "vld1.32 {d0}, [%[input]]!\n"
6775       "vld1.32 {d4}, [r1]!\n"
6776       "pld [%[input], #32]\n"
6777       "vmovl.u8 q0, d0\n"
6778       "vmovl.u8 q2, d4\n"
6779       "vmovl.s16 q1, d1\n"
6780       "vmovl.s16 q0, d0\n"
6781       "vmovl.s16 q3, d5\n"
6782       "vmovl.s16 q2, d4\n"
6783       "vcvt.f32.s32 q0, q0\n"
6784       "vcvt.f32.s32 q1, q1\n"
6785       "vcvt.f32.s32 q2, q2\n"
6786       "vcvt.f32.s32 q3, q3\n"
6787       "vmul.f32 q0, q0, q9\n"
6788       "vmul.f32 q1, q1, q9\n"
6789       "vmul.f32 q2, q2, q11\n"
6790       "vmul.f32 q3, q3, q11\n"
6791       "vadd.f32 q0, q0, q8\n"
6792       "vadd.f32 q1, q1, q8\n"
6793       "vadd.f32 q2, q2, q10\n"
6794       "vadd.f32 q3, q3, q10\n"
6795       "vadd.f32 q0, q0, q2\n"
6796       "vadd.f32 q1, q1, q3\n"
6797       "vsub.f32 q0, q0, q12\n"
6798       "vsub.f32 q1, q1, q12\n"
6799       "vmul.f32 q0, q0, q13\n"
6800       "vmul.f32 q1, q1, q13\n"
6801       "vadd.f32 q0, q0, q14\n"
6802       "vadd.f32 q1, q1, q14\n"
6803       "vcvt.s32.f32 q0, q0\n"
6804       "vcvt.s32.f32 q1, q1\n"
6805 
6806       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6807       "pld [%[output]]\n"
6808       "subs %[rows], %[rows], #1\n"
6809       "bne 1b\n"
6810       : [input] "+r"(input), [output] "+r"(output)
6811       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6812         [output_range_offset] "m"(params.output_range_offset),
6813         [input_range_scale] "m"(params.input_range_scale),
6814         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6815         [bias_range_min] "m"(params.bias_range_min),
6816         [output_range_min] "m"(params.output_range_min),
6817         [bias_range_scale] "m"(params.bias_range_scale),
6818         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6819       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6820         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6821         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6822         "cc", "memory");
6823 }
6824 
6825 template <>
6826 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)6827                               9>::Transform(const uint8_t* input,
6828                                             const BiasAdd<uint8_t>& params,
6829                                             int32_t* output) {
6830 #ifdef DEBUG
6831 #ifdef DEBUG_METAGEMM_VERBOSE
6832   std::cout << __FILE__ << "(" << __LINE__
6833             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
6834                "9>::Transform()"
6835             << std::endl
6836             << std::flush;
6837 #endif
6838 #endif
6839   int params_rows_copy = params.rows;
6840   asm volatile(
6841       "ldr r0, %[input_range_min]\n"
6842       "vdup.32 q8, r0\n"
6843       "ldr r0, %[input_range_scale]\n"
6844       "vdup.32 q9, r0\n"
6845       "ldr r0, %[bias_range_min]\n"
6846       "vdup.32 q10, r0\n"
6847       "ldr r0, %[bias_range_scale]\n"
6848       "vdup.32 q11, r0\n"
6849       "ldr r0, %[output_range_min]\n"
6850       "vdup.32 q12, r0\n"
6851       "ldr r0, %[one_over_output_range_scale]\n"
6852       "vdup.32 q13, r0\n"
6853       "ldr r0, %[output_range_offset]\n"
6854       "vdup.32 q14, r0\n"
6855       "1:"
6856       "mov r0, %[count]\n"
6857       "mov r1, %[bias]\n"
6858       "subs r0, r0, #9\n"
6859       "beq 3f\n"
6860       "2:"
6861       "subs r0, r0, #16\n"
6862 
6863       // BiasAdd::Transform
6864       "vld1.32 {d0, d1}, [%[input]]!\n"
6865       "vld1.32 {d8, d9}, [r1]!\n"
6866       "pld [%[input], #32]\n"
6867       "vmovl.u8 q1, d1\n"
6868       "vmovl.u8 q0, d0\n"
6869       "vmovl.u8 q5, d9\n"
6870       "vmovl.u8 q4, d8\n"
6871       "vmovl.s16 q3, d3\n"
6872       "vmovl.s16 q2, d2\n"
6873       "vmovl.s16 q7, d11\n"
6874       "vmovl.s16 q6, d10\n"
6875       "vmovl.s16 q1, d1\n"
6876       "vmovl.s16 q0, d0\n"
6877       "vmovl.s16 q5, d9\n"
6878       "vmovl.s16 q4, d8\n"
6879       "vcvt.f32.s32 q0, q0\n"
6880       "vcvt.f32.s32 q1, q1\n"
6881       "vcvt.f32.s32 q2, q2\n"
6882       "vcvt.f32.s32 q3, q3\n"
6883       "vcvt.f32.s32 q4, q4\n"
6884       "vcvt.f32.s32 q5, q5\n"
6885       "vcvt.f32.s32 q6, q6\n"
6886       "vcvt.f32.s32 q7, q7\n"
6887       "vmul.f32 q0, q0, q9\n"
6888       "vmul.f32 q1, q1, q9\n"
6889       "vmul.f32 q2, q2, q9\n"
6890       "vmul.f32 q3, q3, q9\n"
6891       "vmul.f32 q4, q4, q11\n"
6892       "vmul.f32 q5, q5, q11\n"
6893       "vmul.f32 q6, q6, q11\n"
6894       "vmul.f32 q7, q7, q11\n"
6895       "vadd.f32 q0, q0, q8\n"
6896       "vadd.f32 q1, q1, q8\n"
6897       "vadd.f32 q2, q2, q8\n"
6898       "vadd.f32 q3, q3, q8\n"
6899       "vadd.f32 q4, q4, q10\n"
6900       "vadd.f32 q5, q5, q10\n"
6901       "vadd.f32 q6, q6, q10\n"
6902       "vadd.f32 q7, q7, q10\n"
6903       "vadd.f32 q0, q0, q4\n"
6904       "vadd.f32 q1, q1, q5\n"
6905       "vadd.f32 q2, q2, q6\n"
6906       "vadd.f32 q3, q3, q7\n"
6907       "vsub.f32 q0, q0, q12\n"
6908       "vsub.f32 q1, q1, q12\n"
6909       "vsub.f32 q2, q2, q12\n"
6910       "vsub.f32 q3, q3, q12\n"
6911       "vmul.f32 q0, q0, q13\n"
6912       "vmul.f32 q1, q1, q13\n"
6913       "vmul.f32 q2, q2, q13\n"
6914       "vmul.f32 q3, q3, q13\n"
6915       "vadd.f32 q0, q0, q14\n"
6916       "vadd.f32 q1, q1, q14\n"
6917       "vadd.f32 q2, q2, q14\n"
6918       "vadd.f32 q3, q3, q14\n"
6919       "vcvt.s32.f32 q0, q0\n"
6920       "vcvt.s32.f32 q1, q1\n"
6921       "vcvt.s32.f32 q2, q2\n"
6922       "vcvt.s32.f32 q3, q3\n"
6923 
6924       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6925       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
6926       "pld [%[output]]\n"
6927       "bne 2b\n"
6928       "3:"
6929 
6930       // BiasAdd::Transform
6931       "vld1.32 {d0}, [%[input]]!\n"
6932       "vld1.8 {d1[0]}, [%[input]]!\n"
6933       "vld1.32 {d6}, [r1]!\n"
6934       "vld1.8 {d7[0]}, [r1]!\n"
6935       "pld [%[input], #32]\n"
6936       "vmovl.u8 q1, d1\n"
6937       "vmovl.u8 q0, d0\n"
6938       "vmovl.u8 q4, d7\n"
6939       "vmovl.u8 q3, d6\n"
6940       "vmovl.s16 q2, d2\n"
6941       "vmovl.s16 q5, d8\n"
6942       "vmovl.s16 q1, d1\n"
6943       "vmovl.s16 q0, d0\n"
6944       "vmovl.s16 q4, d7\n"
6945       "vmovl.s16 q3, d6\n"
6946       "vcvt.f32.s32 q0, q0\n"
6947       "vcvt.f32.s32 q1, q1\n"
6948       "vcvt.f32.s32 q2, q2\n"
6949       "vcvt.f32.s32 q3, q3\n"
6950       "vcvt.f32.s32 q4, q4\n"
6951       "vcvt.f32.s32 q5, q5\n"
6952       "vmul.f32 q0, q0, q9\n"
6953       "vmul.f32 q1, q1, q9\n"
6954       "vmul.f32 q2, q2, q9\n"
6955       "vmul.f32 q3, q3, q11\n"
6956       "vmul.f32 q4, q4, q11\n"
6957       "vmul.f32 q5, q5, q11\n"
6958       "vadd.f32 q0, q0, q8\n"
6959       "vadd.f32 q1, q1, q8\n"
6960       "vadd.f32 q2, q2, q8\n"
6961       "vadd.f32 q3, q3, q10\n"
6962       "vadd.f32 q4, q4, q10\n"
6963       "vadd.f32 q5, q5, q10\n"
6964       "vadd.f32 q0, q0, q3\n"
6965       "vadd.f32 q1, q1, q4\n"
6966       "vadd.f32 q2, q2, q5\n"
6967       "vsub.f32 q0, q0, q12\n"
6968       "vsub.f32 q1, q1, q12\n"
6969       "vsub.f32 q2, q2, q12\n"
6970       "vmul.f32 q0, q0, q13\n"
6971       "vmul.f32 q1, q1, q13\n"
6972       "vmul.f32 q2, q2, q13\n"
6973       "vadd.f32 q0, q0, q14\n"
6974       "vadd.f32 q1, q1, q14\n"
6975       "vadd.f32 q2, q2, q14\n"
6976       "vcvt.s32.f32 q0, q0\n"
6977       "vcvt.s32.f32 q1, q1\n"
6978       "vcvt.s32.f32 q2, q2\n"
6979 
6980       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
6981       "vst1.32 {d4[0]}, [%[output]]!\n"
6982       "pld [%[output]]\n"
6983       "subs %[rows], %[rows], #1\n"
6984       "bne 1b\n"
6985       : [input] "+r"(input), [output] "+r"(output)
6986       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
6987         [output_range_offset] "m"(params.output_range_offset),
6988         [input_range_scale] "m"(params.input_range_scale),
6989         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
6990         [bias_range_min] "m"(params.bias_range_min),
6991         [output_range_min] "m"(params.output_range_min),
6992         [bias_range_scale] "m"(params.bias_range_scale),
6993         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
6994       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
6995         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
6996         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
6997         "cc", "memory");
6998 }
6999 
7000 template <>
7001 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)7002                               10>::Transform(const uint8_t* input,
7003                                              const BiasAdd<uint8_t>& params,
7004                                              int32_t* output) {
7005 #ifdef DEBUG
7006 #ifdef DEBUG_METAGEMM_VERBOSE
7007   std::cout << __FILE__ << "(" << __LINE__
7008             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
7009                "10>::Transform()"
7010             << std::endl
7011             << std::flush;
7012 #endif
7013 #endif
7014   int params_rows_copy = params.rows;
7015   asm volatile(
7016       "ldr r0, %[input_range_min]\n"
7017       "vdup.32 q8, r0\n"
7018       "ldr r0, %[input_range_scale]\n"
7019       "vdup.32 q9, r0\n"
7020       "ldr r0, %[bias_range_min]\n"
7021       "vdup.32 q10, r0\n"
7022       "ldr r0, %[bias_range_scale]\n"
7023       "vdup.32 q11, r0\n"
7024       "ldr r0, %[output_range_min]\n"
7025       "vdup.32 q12, r0\n"
7026       "ldr r0, %[one_over_output_range_scale]\n"
7027       "vdup.32 q13, r0\n"
7028       "ldr r0, %[output_range_offset]\n"
7029       "vdup.32 q14, r0\n"
7030       "1:"
7031       "mov r0, %[count]\n"
7032       "mov r1, %[bias]\n"
7033       "subs r0, r0, #10\n"
7034       "beq 3f\n"
7035       "2:"
7036       "subs r0, r0, #16\n"
7037 
7038       // BiasAdd::Transform
7039       "vld1.32 {d0, d1}, [%[input]]!\n"
7040       "vld1.32 {d8, d9}, [r1]!\n"
7041       "pld [%[input], #32]\n"
7042       "vmovl.u8 q1, d1\n"
7043       "vmovl.u8 q0, d0\n"
7044       "vmovl.u8 q5, d9\n"
7045       "vmovl.u8 q4, d8\n"
7046       "vmovl.s16 q3, d3\n"
7047       "vmovl.s16 q2, d2\n"
7048       "vmovl.s16 q7, d11\n"
7049       "vmovl.s16 q6, d10\n"
7050       "vmovl.s16 q1, d1\n"
7051       "vmovl.s16 q0, d0\n"
7052       "vmovl.s16 q5, d9\n"
7053       "vmovl.s16 q4, d8\n"
7054       "vcvt.f32.s32 q0, q0\n"
7055       "vcvt.f32.s32 q1, q1\n"
7056       "vcvt.f32.s32 q2, q2\n"
7057       "vcvt.f32.s32 q3, q3\n"
7058       "vcvt.f32.s32 q4, q4\n"
7059       "vcvt.f32.s32 q5, q5\n"
7060       "vcvt.f32.s32 q6, q6\n"
7061       "vcvt.f32.s32 q7, q7\n"
7062       "vmul.f32 q0, q0, q9\n"
7063       "vmul.f32 q1, q1, q9\n"
7064       "vmul.f32 q2, q2, q9\n"
7065       "vmul.f32 q3, q3, q9\n"
7066       "vmul.f32 q4, q4, q11\n"
7067       "vmul.f32 q5, q5, q11\n"
7068       "vmul.f32 q6, q6, q11\n"
7069       "vmul.f32 q7, q7, q11\n"
7070       "vadd.f32 q0, q0, q8\n"
7071       "vadd.f32 q1, q1, q8\n"
7072       "vadd.f32 q2, q2, q8\n"
7073       "vadd.f32 q3, q3, q8\n"
7074       "vadd.f32 q4, q4, q10\n"
7075       "vadd.f32 q5, q5, q10\n"
7076       "vadd.f32 q6, q6, q10\n"
7077       "vadd.f32 q7, q7, q10\n"
7078       "vadd.f32 q0, q0, q4\n"
7079       "vadd.f32 q1, q1, q5\n"
7080       "vadd.f32 q2, q2, q6\n"
7081       "vadd.f32 q3, q3, q7\n"
7082       "vsub.f32 q0, q0, q12\n"
7083       "vsub.f32 q1, q1, q12\n"
7084       "vsub.f32 q2, q2, q12\n"
7085       "vsub.f32 q3, q3, q12\n"
7086       "vmul.f32 q0, q0, q13\n"
7087       "vmul.f32 q1, q1, q13\n"
7088       "vmul.f32 q2, q2, q13\n"
7089       "vmul.f32 q3, q3, q13\n"
7090       "vadd.f32 q0, q0, q14\n"
7091       "vadd.f32 q1, q1, q14\n"
7092       "vadd.f32 q2, q2, q14\n"
7093       "vadd.f32 q3, q3, q14\n"
7094       "vcvt.s32.f32 q0, q0\n"
7095       "vcvt.s32.f32 q1, q1\n"
7096       "vcvt.s32.f32 q2, q2\n"
7097       "vcvt.s32.f32 q3, q3\n"
7098 
7099       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7100       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
7101       "pld [%[output]]\n"
7102       "bne 2b\n"
7103       "3:"
7104 
7105       // BiasAdd::Transform
7106       "vld1.32 {d0}, [%[input]]!\n"
7107       "vld1.16 {d1[0]}, [%[input]]!\n"
7108       "vld1.32 {d6}, [r1]!\n"
7109       "vld1.16 {d7[0]}, [r1]!\n"
7110       "pld [%[input], #32]\n"
7111       "vmovl.u8 q1, d1\n"
7112       "vmovl.u8 q0, d0\n"
7113       "vmovl.u8 q4, d7\n"
7114       "vmovl.u8 q3, d6\n"
7115       "vmovl.s16 q2, d2\n"
7116       "vmovl.s16 q5, d8\n"
7117       "vmovl.s16 q1, d1\n"
7118       "vmovl.s16 q0, d0\n"
7119       "vmovl.s16 q4, d7\n"
7120       "vmovl.s16 q3, d6\n"
7121       "vcvt.f32.s32 q0, q0\n"
7122       "vcvt.f32.s32 q1, q1\n"
7123       "vcvt.f32.s32 q2, q2\n"
7124       "vcvt.f32.s32 q3, q3\n"
7125       "vcvt.f32.s32 q4, q4\n"
7126       "vcvt.f32.s32 q5, q5\n"
7127       "vmul.f32 q0, q0, q9\n"
7128       "vmul.f32 q1, q1, q9\n"
7129       "vmul.f32 q2, q2, q9\n"
7130       "vmul.f32 q3, q3, q11\n"
7131       "vmul.f32 q4, q4, q11\n"
7132       "vmul.f32 q5, q5, q11\n"
7133       "vadd.f32 q0, q0, q8\n"
7134       "vadd.f32 q1, q1, q8\n"
7135       "vadd.f32 q2, q2, q8\n"
7136       "vadd.f32 q3, q3, q10\n"
7137       "vadd.f32 q4, q4, q10\n"
7138       "vadd.f32 q5, q5, q10\n"
7139       "vadd.f32 q0, q0, q3\n"
7140       "vadd.f32 q1, q1, q4\n"
7141       "vadd.f32 q2, q2, q5\n"
7142       "vsub.f32 q0, q0, q12\n"
7143       "vsub.f32 q1, q1, q12\n"
7144       "vsub.f32 q2, q2, q12\n"
7145       "vmul.f32 q0, q0, q13\n"
7146       "vmul.f32 q1, q1, q13\n"
7147       "vmul.f32 q2, q2, q13\n"
7148       "vadd.f32 q0, q0, q14\n"
7149       "vadd.f32 q1, q1, q14\n"
7150       "vadd.f32 q2, q2, q14\n"
7151       "vcvt.s32.f32 q0, q0\n"
7152       "vcvt.s32.f32 q1, q1\n"
7153       "vcvt.s32.f32 q2, q2\n"
7154 
7155       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7156       "vst1.32 {d4}, [%[output]]!\n"
7157       "pld [%[output]]\n"
7158       "subs %[rows], %[rows], #1\n"
7159       "bne 1b\n"
7160       : [input] "+r"(input), [output] "+r"(output)
7161       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
7162         [output_range_offset] "m"(params.output_range_offset),
7163         [input_range_scale] "m"(params.input_range_scale),
7164         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
7165         [bias_range_min] "m"(params.bias_range_min),
7166         [output_range_min] "m"(params.output_range_min),
7167         [bias_range_scale] "m"(params.bias_range_scale),
7168         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
7169       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
7170         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
7171         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
7172         "cc", "memory");
7173 }
7174 
7175 template <>
7176 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)7177                               11>::Transform(const uint8_t* input,
7178                                              const BiasAdd<uint8_t>& params,
7179                                              int32_t* output) {
7180 #ifdef DEBUG
7181 #ifdef DEBUG_METAGEMM_VERBOSE
7182   std::cout << __FILE__ << "(" << __LINE__
7183             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
7184                "11>::Transform()"
7185             << std::endl
7186             << std::flush;
7187 #endif
7188 #endif
7189   int params_rows_copy = params.rows;
7190   asm volatile(
7191       "ldr r0, %[input_range_min]\n"
7192       "vdup.32 q8, r0\n"
7193       "ldr r0, %[input_range_scale]\n"
7194       "vdup.32 q9, r0\n"
7195       "ldr r0, %[bias_range_min]\n"
7196       "vdup.32 q10, r0\n"
7197       "ldr r0, %[bias_range_scale]\n"
7198       "vdup.32 q11, r0\n"
7199       "ldr r0, %[output_range_min]\n"
7200       "vdup.32 q12, r0\n"
7201       "ldr r0, %[one_over_output_range_scale]\n"
7202       "vdup.32 q13, r0\n"
7203       "ldr r0, %[output_range_offset]\n"
7204       "vdup.32 q14, r0\n"
7205       "1:"
7206       "mov r0, %[count]\n"
7207       "mov r1, %[bias]\n"
7208       "subs r0, r0, #11\n"
7209       "beq 3f\n"
7210       "2:"
7211       "subs r0, r0, #16\n"
7212 
7213       // BiasAdd::Transform
7214       "vld1.32 {d0, d1}, [%[input]]!\n"
7215       "vld1.32 {d8, d9}, [r1]!\n"
7216       "pld [%[input], #32]\n"
7217       "vmovl.u8 q1, d1\n"
7218       "vmovl.u8 q0, d0\n"
7219       "vmovl.u8 q5, d9\n"
7220       "vmovl.u8 q4, d8\n"
7221       "vmovl.s16 q3, d3\n"
7222       "vmovl.s16 q2, d2\n"
7223       "vmovl.s16 q7, d11\n"
7224       "vmovl.s16 q6, d10\n"
7225       "vmovl.s16 q1, d1\n"
7226       "vmovl.s16 q0, d0\n"
7227       "vmovl.s16 q5, d9\n"
7228       "vmovl.s16 q4, d8\n"
7229       "vcvt.f32.s32 q0, q0\n"
7230       "vcvt.f32.s32 q1, q1\n"
7231       "vcvt.f32.s32 q2, q2\n"
7232       "vcvt.f32.s32 q3, q3\n"
7233       "vcvt.f32.s32 q4, q4\n"
7234       "vcvt.f32.s32 q5, q5\n"
7235       "vcvt.f32.s32 q6, q6\n"
7236       "vcvt.f32.s32 q7, q7\n"
7237       "vmul.f32 q0, q0, q9\n"
7238       "vmul.f32 q1, q1, q9\n"
7239       "vmul.f32 q2, q2, q9\n"
7240       "vmul.f32 q3, q3, q9\n"
7241       "vmul.f32 q4, q4, q11\n"
7242       "vmul.f32 q5, q5, q11\n"
7243       "vmul.f32 q6, q6, q11\n"
7244       "vmul.f32 q7, q7, q11\n"
7245       "vadd.f32 q0, q0, q8\n"
7246       "vadd.f32 q1, q1, q8\n"
7247       "vadd.f32 q2, q2, q8\n"
7248       "vadd.f32 q3, q3, q8\n"
7249       "vadd.f32 q4, q4, q10\n"
7250       "vadd.f32 q5, q5, q10\n"
7251       "vadd.f32 q6, q6, q10\n"
7252       "vadd.f32 q7, q7, q10\n"
7253       "vadd.f32 q0, q0, q4\n"
7254       "vadd.f32 q1, q1, q5\n"
7255       "vadd.f32 q2, q2, q6\n"
7256       "vadd.f32 q3, q3, q7\n"
7257       "vsub.f32 q0, q0, q12\n"
7258       "vsub.f32 q1, q1, q12\n"
7259       "vsub.f32 q2, q2, q12\n"
7260       "vsub.f32 q3, q3, q12\n"
7261       "vmul.f32 q0, q0, q13\n"
7262       "vmul.f32 q1, q1, q13\n"
7263       "vmul.f32 q2, q2, q13\n"
7264       "vmul.f32 q3, q3, q13\n"
7265       "vadd.f32 q0, q0, q14\n"
7266       "vadd.f32 q1, q1, q14\n"
7267       "vadd.f32 q2, q2, q14\n"
7268       "vadd.f32 q3, q3, q14\n"
7269       "vcvt.s32.f32 q0, q0\n"
7270       "vcvt.s32.f32 q1, q1\n"
7271       "vcvt.s32.f32 q2, q2\n"
7272       "vcvt.s32.f32 q3, q3\n"
7273 
7274       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7275       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
7276       "pld [%[output]]\n"
7277       "bne 2b\n"
7278       "3:"
7279 
7280       // BiasAdd::Transform
7281       "vld1.32 {d0}, [%[input]]!\n"
7282       "vld1.16 {d1[0]}, [%[input]]!\n"
7283       "vld1.8 {d1[2]}, [%[input]]!\n"
7284       "vld1.32 {d6}, [r1]!\n"
7285       "vld1.16 {d7[0]}, [r1]!\n"
7286       "vld1.8 {d7[2]}, [r1]!\n"
7287       "pld [%[input], #32]\n"
7288       "vmovl.u8 q1, d1\n"
7289       "vmovl.u8 q0, d0\n"
7290       "vmovl.u8 q4, d7\n"
7291       "vmovl.u8 q3, d6\n"
7292       "vmovl.s16 q2, d2\n"
7293       "vmovl.s16 q5, d8\n"
7294       "vmovl.s16 q1, d1\n"
7295       "vmovl.s16 q0, d0\n"
7296       "vmovl.s16 q4, d7\n"
7297       "vmovl.s16 q3, d6\n"
7298       "vcvt.f32.s32 q0, q0\n"
7299       "vcvt.f32.s32 q1, q1\n"
7300       "vcvt.f32.s32 q2, q2\n"
7301       "vcvt.f32.s32 q3, q3\n"
7302       "vcvt.f32.s32 q4, q4\n"
7303       "vcvt.f32.s32 q5, q5\n"
7304       "vmul.f32 q0, q0, q9\n"
7305       "vmul.f32 q1, q1, q9\n"
7306       "vmul.f32 q2, q2, q9\n"
7307       "vmul.f32 q3, q3, q11\n"
7308       "vmul.f32 q4, q4, q11\n"
7309       "vmul.f32 q5, q5, q11\n"
7310       "vadd.f32 q0, q0, q8\n"
7311       "vadd.f32 q1, q1, q8\n"
7312       "vadd.f32 q2, q2, q8\n"
7313       "vadd.f32 q3, q3, q10\n"
7314       "vadd.f32 q4, q4, q10\n"
7315       "vadd.f32 q5, q5, q10\n"
7316       "vadd.f32 q0, q0, q3\n"
7317       "vadd.f32 q1, q1, q4\n"
7318       "vadd.f32 q2, q2, q5\n"
7319       "vsub.f32 q0, q0, q12\n"
7320       "vsub.f32 q1, q1, q12\n"
7321       "vsub.f32 q2, q2, q12\n"
7322       "vmul.f32 q0, q0, q13\n"
7323       "vmul.f32 q1, q1, q13\n"
7324       "vmul.f32 q2, q2, q13\n"
7325       "vadd.f32 q0, q0, q14\n"
7326       "vadd.f32 q1, q1, q14\n"
7327       "vadd.f32 q2, q2, q14\n"
7328       "vcvt.s32.f32 q0, q0\n"
7329       "vcvt.s32.f32 q1, q1\n"
7330       "vcvt.s32.f32 q2, q2\n"
7331 
7332       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7333       "vst1.32 {d4}, [%[output]]!\n"
7334       "vst1.32 {d5[0]}, [%[output]]!\n"
7335       "pld [%[output]]\n"
7336       "subs %[rows], %[rows], #1\n"
7337       "bne 1b\n"
7338       : [input] "+r"(input), [output] "+r"(output)
7339       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
7340         [output_range_offset] "m"(params.output_range_offset),
7341         [input_range_scale] "m"(params.input_range_scale),
7342         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
7343         [bias_range_min] "m"(params.bias_range_min),
7344         [output_range_min] "m"(params.output_range_min),
7345         [bias_range_scale] "m"(params.bias_range_scale),
7346         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
7347       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
7348         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
7349         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
7350         "cc", "memory");
7351 }
7352 
7353 template <>
7354 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)7355                               12>::Transform(const uint8_t* input,
7356                                              const BiasAdd<uint8_t>& params,
7357                                              int32_t* output) {
7358 #ifdef DEBUG
7359 #ifdef DEBUG_METAGEMM_VERBOSE
7360   std::cout << __FILE__ << "(" << __LINE__
7361             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
7362                "12>::Transform()"
7363             << std::endl
7364             << std::flush;
7365 #endif
7366 #endif
7367   int params_rows_copy = params.rows;
7368   asm volatile(
7369       "ldr r0, %[input_range_min]\n"
7370       "vdup.32 q8, r0\n"
7371       "ldr r0, %[input_range_scale]\n"
7372       "vdup.32 q9, r0\n"
7373       "ldr r0, %[bias_range_min]\n"
7374       "vdup.32 q10, r0\n"
7375       "ldr r0, %[bias_range_scale]\n"
7376       "vdup.32 q11, r0\n"
7377       "ldr r0, %[output_range_min]\n"
7378       "vdup.32 q12, r0\n"
7379       "ldr r0, %[one_over_output_range_scale]\n"
7380       "vdup.32 q13, r0\n"
7381       "ldr r0, %[output_range_offset]\n"
7382       "vdup.32 q14, r0\n"
7383       "1:"
7384       "mov r0, %[count]\n"
7385       "mov r1, %[bias]\n"
7386       "subs r0, r0, #12\n"
7387       "beq 3f\n"
7388       "2:"
7389       "subs r0, r0, #16\n"
7390 
7391       // BiasAdd::Transform
7392       "vld1.32 {d0, d1}, [%[input]]!\n"
7393       "vld1.32 {d8, d9}, [r1]!\n"
7394       "pld [%[input], #32]\n"
7395       "vmovl.u8 q1, d1\n"
7396       "vmovl.u8 q0, d0\n"
7397       "vmovl.u8 q5, d9\n"
7398       "vmovl.u8 q4, d8\n"
7399       "vmovl.s16 q3, d3\n"
7400       "vmovl.s16 q2, d2\n"
7401       "vmovl.s16 q7, d11\n"
7402       "vmovl.s16 q6, d10\n"
7403       "vmovl.s16 q1, d1\n"
7404       "vmovl.s16 q0, d0\n"
7405       "vmovl.s16 q5, d9\n"
7406       "vmovl.s16 q4, d8\n"
7407       "vcvt.f32.s32 q0, q0\n"
7408       "vcvt.f32.s32 q1, q1\n"
7409       "vcvt.f32.s32 q2, q2\n"
7410       "vcvt.f32.s32 q3, q3\n"
7411       "vcvt.f32.s32 q4, q4\n"
7412       "vcvt.f32.s32 q5, q5\n"
7413       "vcvt.f32.s32 q6, q6\n"
7414       "vcvt.f32.s32 q7, q7\n"
7415       "vmul.f32 q0, q0, q9\n"
7416       "vmul.f32 q1, q1, q9\n"
7417       "vmul.f32 q2, q2, q9\n"
7418       "vmul.f32 q3, q3, q9\n"
7419       "vmul.f32 q4, q4, q11\n"
7420       "vmul.f32 q5, q5, q11\n"
7421       "vmul.f32 q6, q6, q11\n"
7422       "vmul.f32 q7, q7, q11\n"
7423       "vadd.f32 q0, q0, q8\n"
7424       "vadd.f32 q1, q1, q8\n"
7425       "vadd.f32 q2, q2, q8\n"
7426       "vadd.f32 q3, q3, q8\n"
7427       "vadd.f32 q4, q4, q10\n"
7428       "vadd.f32 q5, q5, q10\n"
7429       "vadd.f32 q6, q6, q10\n"
7430       "vadd.f32 q7, q7, q10\n"
7431       "vadd.f32 q0, q0, q4\n"
7432       "vadd.f32 q1, q1, q5\n"
7433       "vadd.f32 q2, q2, q6\n"
7434       "vadd.f32 q3, q3, q7\n"
7435       "vsub.f32 q0, q0, q12\n"
7436       "vsub.f32 q1, q1, q12\n"
7437       "vsub.f32 q2, q2, q12\n"
7438       "vsub.f32 q3, q3, q12\n"
7439       "vmul.f32 q0, q0, q13\n"
7440       "vmul.f32 q1, q1, q13\n"
7441       "vmul.f32 q2, q2, q13\n"
7442       "vmul.f32 q3, q3, q13\n"
7443       "vadd.f32 q0, q0, q14\n"
7444       "vadd.f32 q1, q1, q14\n"
7445       "vadd.f32 q2, q2, q14\n"
7446       "vadd.f32 q3, q3, q14\n"
7447       "vcvt.s32.f32 q0, q0\n"
7448       "vcvt.s32.f32 q1, q1\n"
7449       "vcvt.s32.f32 q2, q2\n"
7450       "vcvt.s32.f32 q3, q3\n"
7451 
7452       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7453       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
7454       "pld [%[output]]\n"
7455       "bne 2b\n"
7456       "3:"
7457 
7458       // BiasAdd::Transform
7459       "vld1.32 {d0}, [%[input]]!\n"
7460       "vld1.32 {d1[0]}, [%[input]]!\n"
7461       "vld1.32 {d6}, [r1]!\n"
7462       "vld1.32 {d7[0]}, [r1]!\n"
7463       "pld [%[input], #32]\n"
7464       "vmovl.u8 q1, d1\n"
7465       "vmovl.u8 q0, d0\n"
7466       "vmovl.u8 q4, d7\n"
7467       "vmovl.u8 q3, d6\n"
7468       "vmovl.s16 q2, d2\n"
7469       "vmovl.s16 q5, d8\n"
7470       "vmovl.s16 q1, d1\n"
7471       "vmovl.s16 q0, d0\n"
7472       "vmovl.s16 q4, d7\n"
7473       "vmovl.s16 q3, d6\n"
7474       "vcvt.f32.s32 q0, q0\n"
7475       "vcvt.f32.s32 q1, q1\n"
7476       "vcvt.f32.s32 q2, q2\n"
7477       "vcvt.f32.s32 q3, q3\n"
7478       "vcvt.f32.s32 q4, q4\n"
7479       "vcvt.f32.s32 q5, q5\n"
7480       "vmul.f32 q0, q0, q9\n"
7481       "vmul.f32 q1, q1, q9\n"
7482       "vmul.f32 q2, q2, q9\n"
7483       "vmul.f32 q3, q3, q11\n"
7484       "vmul.f32 q4, q4, q11\n"
7485       "vmul.f32 q5, q5, q11\n"
7486       "vadd.f32 q0, q0, q8\n"
7487       "vadd.f32 q1, q1, q8\n"
7488       "vadd.f32 q2, q2, q8\n"
7489       "vadd.f32 q3, q3, q10\n"
7490       "vadd.f32 q4, q4, q10\n"
7491       "vadd.f32 q5, q5, q10\n"
7492       "vadd.f32 q0, q0, q3\n"
7493       "vadd.f32 q1, q1, q4\n"
7494       "vadd.f32 q2, q2, q5\n"
7495       "vsub.f32 q0, q0, q12\n"
7496       "vsub.f32 q1, q1, q12\n"
7497       "vsub.f32 q2, q2, q12\n"
7498       "vmul.f32 q0, q0, q13\n"
7499       "vmul.f32 q1, q1, q13\n"
7500       "vmul.f32 q2, q2, q13\n"
7501       "vadd.f32 q0, q0, q14\n"
7502       "vadd.f32 q1, q1, q14\n"
7503       "vadd.f32 q2, q2, q14\n"
7504       "vcvt.s32.f32 q0, q0\n"
7505       "vcvt.s32.f32 q1, q1\n"
7506       "vcvt.s32.f32 q2, q2\n"
7507 
7508       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7509       "vst1.32 {d4, d5}, [%[output]]!\n"
7510       "pld [%[output]]\n"
7511       "subs %[rows], %[rows], #1\n"
7512       "bne 1b\n"
7513       : [input] "+r"(input), [output] "+r"(output)
7514       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
7515         [output_range_offset] "m"(params.output_range_offset),
7516         [input_range_scale] "m"(params.input_range_scale),
7517         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
7518         [bias_range_min] "m"(params.bias_range_min),
7519         [output_range_min] "m"(params.output_range_min),
7520         [bias_range_scale] "m"(params.bias_range_scale),
7521         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
7522       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
7523         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
7524         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
7525         "cc", "memory");
7526 }
7527 
7528 template <>
7529 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)7530                               13>::Transform(const uint8_t* input,
7531                                              const BiasAdd<uint8_t>& params,
7532                                              int32_t* output) {
7533 #ifdef DEBUG
7534 #ifdef DEBUG_METAGEMM_VERBOSE
7535   std::cout << __FILE__ << "(" << __LINE__
7536             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
7537                "13>::Transform()"
7538             << std::endl
7539             << std::flush;
7540 #endif
7541 #endif
7542   int params_rows_copy = params.rows;
7543   asm volatile(
7544       "ldr r0, %[input_range_min]\n"
7545       "vdup.32 q8, r0\n"
7546       "ldr r0, %[input_range_scale]\n"
7547       "vdup.32 q9, r0\n"
7548       "ldr r0, %[bias_range_min]\n"
7549       "vdup.32 q10, r0\n"
7550       "ldr r0, %[bias_range_scale]\n"
7551       "vdup.32 q11, r0\n"
7552       "ldr r0, %[output_range_min]\n"
7553       "vdup.32 q12, r0\n"
7554       "ldr r0, %[one_over_output_range_scale]\n"
7555       "vdup.32 q13, r0\n"
7556       "ldr r0, %[output_range_offset]\n"
7557       "vdup.32 q14, r0\n"
7558       "1:"
7559       "mov r0, %[count]\n"
7560       "mov r1, %[bias]\n"
7561       "subs r0, r0, #13\n"
7562       "beq 3f\n"
7563       "2:"
7564       "subs r0, r0, #16\n"
7565 
7566       // BiasAdd::Transform
7567       "vld1.32 {d0, d1}, [%[input]]!\n"
7568       "vld1.32 {d8, d9}, [r1]!\n"
7569       "pld [%[input], #32]\n"
7570       "vmovl.u8 q1, d1\n"
7571       "vmovl.u8 q0, d0\n"
7572       "vmovl.u8 q5, d9\n"
7573       "vmovl.u8 q4, d8\n"
7574       "vmovl.s16 q3, d3\n"
7575       "vmovl.s16 q2, d2\n"
7576       "vmovl.s16 q7, d11\n"
7577       "vmovl.s16 q6, d10\n"
7578       "vmovl.s16 q1, d1\n"
7579       "vmovl.s16 q0, d0\n"
7580       "vmovl.s16 q5, d9\n"
7581       "vmovl.s16 q4, d8\n"
7582       "vcvt.f32.s32 q0, q0\n"
7583       "vcvt.f32.s32 q1, q1\n"
7584       "vcvt.f32.s32 q2, q2\n"
7585       "vcvt.f32.s32 q3, q3\n"
7586       "vcvt.f32.s32 q4, q4\n"
7587       "vcvt.f32.s32 q5, q5\n"
7588       "vcvt.f32.s32 q6, q6\n"
7589       "vcvt.f32.s32 q7, q7\n"
7590       "vmul.f32 q0, q0, q9\n"
7591       "vmul.f32 q1, q1, q9\n"
7592       "vmul.f32 q2, q2, q9\n"
7593       "vmul.f32 q3, q3, q9\n"
7594       "vmul.f32 q4, q4, q11\n"
7595       "vmul.f32 q5, q5, q11\n"
7596       "vmul.f32 q6, q6, q11\n"
7597       "vmul.f32 q7, q7, q11\n"
7598       "vadd.f32 q0, q0, q8\n"
7599       "vadd.f32 q1, q1, q8\n"
7600       "vadd.f32 q2, q2, q8\n"
7601       "vadd.f32 q3, q3, q8\n"
7602       "vadd.f32 q4, q4, q10\n"
7603       "vadd.f32 q5, q5, q10\n"
7604       "vadd.f32 q6, q6, q10\n"
7605       "vadd.f32 q7, q7, q10\n"
7606       "vadd.f32 q0, q0, q4\n"
7607       "vadd.f32 q1, q1, q5\n"
7608       "vadd.f32 q2, q2, q6\n"
7609       "vadd.f32 q3, q3, q7\n"
7610       "vsub.f32 q0, q0, q12\n"
7611       "vsub.f32 q1, q1, q12\n"
7612       "vsub.f32 q2, q2, q12\n"
7613       "vsub.f32 q3, q3, q12\n"
7614       "vmul.f32 q0, q0, q13\n"
7615       "vmul.f32 q1, q1, q13\n"
7616       "vmul.f32 q2, q2, q13\n"
7617       "vmul.f32 q3, q3, q13\n"
7618       "vadd.f32 q0, q0, q14\n"
7619       "vadd.f32 q1, q1, q14\n"
7620       "vadd.f32 q2, q2, q14\n"
7621       "vadd.f32 q3, q3, q14\n"
7622       "vcvt.s32.f32 q0, q0\n"
7623       "vcvt.s32.f32 q1, q1\n"
7624       "vcvt.s32.f32 q2, q2\n"
7625       "vcvt.s32.f32 q3, q3\n"
7626 
7627       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7628       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
7629       "pld [%[output]]\n"
7630       "bne 2b\n"
7631       "3:"
7632 
7633       // BiasAdd::Transform
7634       "vld1.32 {d0}, [%[input]]!\n"
7635       "vld1.32 {d1[0]}, [%[input]]!\n"
7636       "vld1.8 {d1[4]}, [%[input]]!\n"
7637       "vld1.32 {d8}, [r1]!\n"
7638       "vld1.32 {d9[0]}, [r1]!\n"
7639       "vld1.8 {d9[4]}, [r1]!\n"
7640       "pld [%[input], #32]\n"
7641       "vmovl.u8 q1, d1\n"
7642       "vmovl.u8 q0, d0\n"
7643       "vmovl.u8 q5, d9\n"
7644       "vmovl.u8 q4, d8\n"
7645       "vmovl.s16 q3, d3\n"
7646       "vmovl.s16 q2, d2\n"
7647       "vmovl.s16 q7, d11\n"
7648       "vmovl.s16 q6, d10\n"
7649       "vmovl.s16 q1, d1\n"
7650       "vmovl.s16 q0, d0\n"
7651       "vmovl.s16 q5, d9\n"
7652       "vmovl.s16 q4, d8\n"
7653       "vcvt.f32.s32 q0, q0\n"
7654       "vcvt.f32.s32 q1, q1\n"
7655       "vcvt.f32.s32 q2, q2\n"
7656       "vcvt.f32.s32 q3, q3\n"
7657       "vcvt.f32.s32 q4, q4\n"
7658       "vcvt.f32.s32 q5, q5\n"
7659       "vcvt.f32.s32 q6, q6\n"
7660       "vcvt.f32.s32 q7, q7\n"
7661       "vmul.f32 q0, q0, q9\n"
7662       "vmul.f32 q1, q1, q9\n"
7663       "vmul.f32 q2, q2, q9\n"
7664       "vmul.f32 q3, q3, q9\n"
7665       "vmul.f32 q4, q4, q11\n"
7666       "vmul.f32 q5, q5, q11\n"
7667       "vmul.f32 q6, q6, q11\n"
7668       "vmul.f32 q7, q7, q11\n"
7669       "vadd.f32 q0, q0, q8\n"
7670       "vadd.f32 q1, q1, q8\n"
7671       "vadd.f32 q2, q2, q8\n"
7672       "vadd.f32 q3, q3, q8\n"
7673       "vadd.f32 q4, q4, q10\n"
7674       "vadd.f32 q5, q5, q10\n"
7675       "vadd.f32 q6, q6, q10\n"
7676       "vadd.f32 q7, q7, q10\n"
7677       "vadd.f32 q0, q0, q4\n"
7678       "vadd.f32 q1, q1, q5\n"
7679       "vadd.f32 q2, q2, q6\n"
7680       "vadd.f32 q3, q3, q7\n"
7681       "vsub.f32 q0, q0, q12\n"
7682       "vsub.f32 q1, q1, q12\n"
7683       "vsub.f32 q2, q2, q12\n"
7684       "vsub.f32 q3, q3, q12\n"
7685       "vmul.f32 q0, q0, q13\n"
7686       "vmul.f32 q1, q1, q13\n"
7687       "vmul.f32 q2, q2, q13\n"
7688       "vmul.f32 q3, q3, q13\n"
7689       "vadd.f32 q0, q0, q14\n"
7690       "vadd.f32 q1, q1, q14\n"
7691       "vadd.f32 q2, q2, q14\n"
7692       "vadd.f32 q3, q3, q14\n"
7693       "vcvt.s32.f32 q0, q0\n"
7694       "vcvt.s32.f32 q1, q1\n"
7695       "vcvt.s32.f32 q2, q2\n"
7696       "vcvt.s32.f32 q3, q3\n"
7697 
7698       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7699       "vst1.32 {d4, d5}, [%[output]]!\n"
7700       "vst1.32 {d6[0]}, [%[output]]!\n"
7701       "pld [%[output]]\n"
7702       "subs %[rows], %[rows], #1\n"
7703       "bne 1b\n"
7704       : [input] "+r"(input), [output] "+r"(output)
7705       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
7706         [output_range_offset] "m"(params.output_range_offset),
7707         [input_range_scale] "m"(params.input_range_scale),
7708         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
7709         [bias_range_min] "m"(params.bias_range_min),
7710         [output_range_min] "m"(params.output_range_min),
7711         [bias_range_scale] "m"(params.bias_range_scale),
7712         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
7713       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
7714         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
7715         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
7716         "cc", "memory");
7717 }
7718 
7719 template <>
7720 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)7721                               14>::Transform(const uint8_t* input,
7722                                              const BiasAdd<uint8_t>& params,
7723                                              int32_t* output) {
7724 #ifdef DEBUG
7725 #ifdef DEBUG_METAGEMM_VERBOSE
7726   std::cout << __FILE__ << "(" << __LINE__
7727             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
7728                "14>::Transform()"
7729             << std::endl
7730             << std::flush;
7731 #endif
7732 #endif
7733   int params_rows_copy = params.rows;
7734   asm volatile(
7735       "ldr r0, %[input_range_min]\n"
7736       "vdup.32 q8, r0\n"
7737       "ldr r0, %[input_range_scale]\n"
7738       "vdup.32 q9, r0\n"
7739       "ldr r0, %[bias_range_min]\n"
7740       "vdup.32 q10, r0\n"
7741       "ldr r0, %[bias_range_scale]\n"
7742       "vdup.32 q11, r0\n"
7743       "ldr r0, %[output_range_min]\n"
7744       "vdup.32 q12, r0\n"
7745       "ldr r0, %[one_over_output_range_scale]\n"
7746       "vdup.32 q13, r0\n"
7747       "ldr r0, %[output_range_offset]\n"
7748       "vdup.32 q14, r0\n"
7749       "1:"
7750       "mov r0, %[count]\n"
7751       "mov r1, %[bias]\n"
7752       "subs r0, r0, #14\n"
7753       "beq 3f\n"
7754       "2:"
7755       "subs r0, r0, #16\n"
7756 
7757       // BiasAdd::Transform
7758       "vld1.32 {d0, d1}, [%[input]]!\n"
7759       "vld1.32 {d8, d9}, [r1]!\n"
7760       "pld [%[input], #32]\n"
7761       "vmovl.u8 q1, d1\n"
7762       "vmovl.u8 q0, d0\n"
7763       "vmovl.u8 q5, d9\n"
7764       "vmovl.u8 q4, d8\n"
7765       "vmovl.s16 q3, d3\n"
7766       "vmovl.s16 q2, d2\n"
7767       "vmovl.s16 q7, d11\n"
7768       "vmovl.s16 q6, d10\n"
7769       "vmovl.s16 q1, d1\n"
7770       "vmovl.s16 q0, d0\n"
7771       "vmovl.s16 q5, d9\n"
7772       "vmovl.s16 q4, d8\n"
7773       "vcvt.f32.s32 q0, q0\n"
7774       "vcvt.f32.s32 q1, q1\n"
7775       "vcvt.f32.s32 q2, q2\n"
7776       "vcvt.f32.s32 q3, q3\n"
7777       "vcvt.f32.s32 q4, q4\n"
7778       "vcvt.f32.s32 q5, q5\n"
7779       "vcvt.f32.s32 q6, q6\n"
7780       "vcvt.f32.s32 q7, q7\n"
7781       "vmul.f32 q0, q0, q9\n"
7782       "vmul.f32 q1, q1, q9\n"
7783       "vmul.f32 q2, q2, q9\n"
7784       "vmul.f32 q3, q3, q9\n"
7785       "vmul.f32 q4, q4, q11\n"
7786       "vmul.f32 q5, q5, q11\n"
7787       "vmul.f32 q6, q6, q11\n"
7788       "vmul.f32 q7, q7, q11\n"
7789       "vadd.f32 q0, q0, q8\n"
7790       "vadd.f32 q1, q1, q8\n"
7791       "vadd.f32 q2, q2, q8\n"
7792       "vadd.f32 q3, q3, q8\n"
7793       "vadd.f32 q4, q4, q10\n"
7794       "vadd.f32 q5, q5, q10\n"
7795       "vadd.f32 q6, q6, q10\n"
7796       "vadd.f32 q7, q7, q10\n"
7797       "vadd.f32 q0, q0, q4\n"
7798       "vadd.f32 q1, q1, q5\n"
7799       "vadd.f32 q2, q2, q6\n"
7800       "vadd.f32 q3, q3, q7\n"
7801       "vsub.f32 q0, q0, q12\n"
7802       "vsub.f32 q1, q1, q12\n"
7803       "vsub.f32 q2, q2, q12\n"
7804       "vsub.f32 q3, q3, q12\n"
7805       "vmul.f32 q0, q0, q13\n"
7806       "vmul.f32 q1, q1, q13\n"
7807       "vmul.f32 q2, q2, q13\n"
7808       "vmul.f32 q3, q3, q13\n"
7809       "vadd.f32 q0, q0, q14\n"
7810       "vadd.f32 q1, q1, q14\n"
7811       "vadd.f32 q2, q2, q14\n"
7812       "vadd.f32 q3, q3, q14\n"
7813       "vcvt.s32.f32 q0, q0\n"
7814       "vcvt.s32.f32 q1, q1\n"
7815       "vcvt.s32.f32 q2, q2\n"
7816       "vcvt.s32.f32 q3, q3\n"
7817 
7818       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7819       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
7820       "pld [%[output]]\n"
7821       "bne 2b\n"
7822       "3:"
7823 
7824       // BiasAdd::Transform
7825       "vld1.32 {d0}, [%[input]]!\n"
7826       "vld1.32 {d1[0]}, [%[input]]!\n"
7827       "vld1.16 {d1[2]}, [%[input]]!\n"
7828       "vld1.32 {d8}, [r1]!\n"
7829       "vld1.32 {d9[0]}, [r1]!\n"
7830       "vld1.16 {d9[2]}, [r1]!\n"
7831       "pld [%[input], #32]\n"
7832       "vmovl.u8 q1, d1\n"
7833       "vmovl.u8 q0, d0\n"
7834       "vmovl.u8 q5, d9\n"
7835       "vmovl.u8 q4, d8\n"
7836       "vmovl.s16 q3, d3\n"
7837       "vmovl.s16 q2, d2\n"
7838       "vmovl.s16 q7, d11\n"
7839       "vmovl.s16 q6, d10\n"
7840       "vmovl.s16 q1, d1\n"
7841       "vmovl.s16 q0, d0\n"
7842       "vmovl.s16 q5, d9\n"
7843       "vmovl.s16 q4, d8\n"
7844       "vcvt.f32.s32 q0, q0\n"
7845       "vcvt.f32.s32 q1, q1\n"
7846       "vcvt.f32.s32 q2, q2\n"
7847       "vcvt.f32.s32 q3, q3\n"
7848       "vcvt.f32.s32 q4, q4\n"
7849       "vcvt.f32.s32 q5, q5\n"
7850       "vcvt.f32.s32 q6, q6\n"
7851       "vcvt.f32.s32 q7, q7\n"
7852       "vmul.f32 q0, q0, q9\n"
7853       "vmul.f32 q1, q1, q9\n"
7854       "vmul.f32 q2, q2, q9\n"
7855       "vmul.f32 q3, q3, q9\n"
7856       "vmul.f32 q4, q4, q11\n"
7857       "vmul.f32 q5, q5, q11\n"
7858       "vmul.f32 q6, q6, q11\n"
7859       "vmul.f32 q7, q7, q11\n"
7860       "vadd.f32 q0, q0, q8\n"
7861       "vadd.f32 q1, q1, q8\n"
7862       "vadd.f32 q2, q2, q8\n"
7863       "vadd.f32 q3, q3, q8\n"
7864       "vadd.f32 q4, q4, q10\n"
7865       "vadd.f32 q5, q5, q10\n"
7866       "vadd.f32 q6, q6, q10\n"
7867       "vadd.f32 q7, q7, q10\n"
7868       "vadd.f32 q0, q0, q4\n"
7869       "vadd.f32 q1, q1, q5\n"
7870       "vadd.f32 q2, q2, q6\n"
7871       "vadd.f32 q3, q3, q7\n"
7872       "vsub.f32 q0, q0, q12\n"
7873       "vsub.f32 q1, q1, q12\n"
7874       "vsub.f32 q2, q2, q12\n"
7875       "vsub.f32 q3, q3, q12\n"
7876       "vmul.f32 q0, q0, q13\n"
7877       "vmul.f32 q1, q1, q13\n"
7878       "vmul.f32 q2, q2, q13\n"
7879       "vmul.f32 q3, q3, q13\n"
7880       "vadd.f32 q0, q0, q14\n"
7881       "vadd.f32 q1, q1, q14\n"
7882       "vadd.f32 q2, q2, q14\n"
7883       "vadd.f32 q3, q3, q14\n"
7884       "vcvt.s32.f32 q0, q0\n"
7885       "vcvt.s32.f32 q1, q1\n"
7886       "vcvt.s32.f32 q2, q2\n"
7887       "vcvt.s32.f32 q3, q3\n"
7888 
7889       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
7890       "vst1.32 {d4, d5, d6}, [%[output]]!\n"
7891       "pld [%[output]]\n"
7892       "subs %[rows], %[rows], #1\n"
7893       "bne 1b\n"
7894       : [input] "+r"(input), [output] "+r"(output)
7895       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
7896         [output_range_offset] "m"(params.output_range_offset),
7897         [input_range_scale] "m"(params.input_range_scale),
7898         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
7899         [bias_range_min] "m"(params.bias_range_min),
7900         [output_range_min] "m"(params.output_range_min),
7901         [bias_range_scale] "m"(params.bias_range_scale),
7902         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
7903       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
7904         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
7905         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
7906         "cc", "memory");
7907 }
7908 
7909 template <>
7910 inline void Transform1DKernel<uint8_t, int32_t, BiasAdd<uint8_t>, 16,
Transform(const uint8_t * input,const BiasAdd<uint8_t> & params,int32_t * output)7911                               15>::Transform(const uint8_t* input,
7912                                              const BiasAdd<uint8_t>& params,
7913                                              int32_t* output) {
7914 #ifdef DEBUG
7915 #ifdef DEBUG_METAGEMM_VERBOSE
7916   std::cout << __FILE__ << "(" << __LINE__
7917             << ") BiasAdd<uint8_t><uint8_t, int32_t, BiasAdd<uint8_t>, 16, "
7918                "15>::Transform()"
7919             << std::endl
7920             << std::flush;
7921 #endif
7922 #endif
7923   int params_rows_copy = params.rows;
7924   asm volatile(
7925       "ldr r0, %[input_range_min]\n"
7926       "vdup.32 q8, r0\n"
7927       "ldr r0, %[input_range_scale]\n"
7928       "vdup.32 q9, r0\n"
7929       "ldr r0, %[bias_range_min]\n"
7930       "vdup.32 q10, r0\n"
7931       "ldr r0, %[bias_range_scale]\n"
7932       "vdup.32 q11, r0\n"
7933       "ldr r0, %[output_range_min]\n"
7934       "vdup.32 q12, r0\n"
7935       "ldr r0, %[one_over_output_range_scale]\n"
7936       "vdup.32 q13, r0\n"
7937       "ldr r0, %[output_range_offset]\n"
7938       "vdup.32 q14, r0\n"
7939       "1:"
7940       "mov r0, %[count]\n"
7941       "mov r1, %[bias]\n"
7942       "subs r0, r0, #15\n"
7943       "beq 3f\n"
7944       "2:"
7945       "subs r0, r0, #16\n"
7946 
7947       // BiasAdd::Transform
7948       "vld1.32 {d0, d1}, [%[input]]!\n"
7949       "vld1.32 {d8, d9}, [r1]!\n"
7950       "pld [%[input], #32]\n"
7951       "vmovl.u8 q1, d1\n"
7952       "vmovl.u8 q0, d0\n"
7953       "vmovl.u8 q5, d9\n"
7954       "vmovl.u8 q4, d8\n"
7955       "vmovl.s16 q3, d3\n"
7956       "vmovl.s16 q2, d2\n"
7957       "vmovl.s16 q7, d11\n"
7958       "vmovl.s16 q6, d10\n"
7959       "vmovl.s16 q1, d1\n"
7960       "vmovl.s16 q0, d0\n"
7961       "vmovl.s16 q5, d9\n"
7962       "vmovl.s16 q4, d8\n"
7963       "vcvt.f32.s32 q0, q0\n"
7964       "vcvt.f32.s32 q1, q1\n"
7965       "vcvt.f32.s32 q2, q2\n"
7966       "vcvt.f32.s32 q3, q3\n"
7967       "vcvt.f32.s32 q4, q4\n"
7968       "vcvt.f32.s32 q5, q5\n"
7969       "vcvt.f32.s32 q6, q6\n"
7970       "vcvt.f32.s32 q7, q7\n"
7971       "vmul.f32 q0, q0, q9\n"
7972       "vmul.f32 q1, q1, q9\n"
7973       "vmul.f32 q2, q2, q9\n"
7974       "vmul.f32 q3, q3, q9\n"
7975       "vmul.f32 q4, q4, q11\n"
7976       "vmul.f32 q5, q5, q11\n"
7977       "vmul.f32 q6, q6, q11\n"
7978       "vmul.f32 q7, q7, q11\n"
7979       "vadd.f32 q0, q0, q8\n"
7980       "vadd.f32 q1, q1, q8\n"
7981       "vadd.f32 q2, q2, q8\n"
7982       "vadd.f32 q3, q3, q8\n"
7983       "vadd.f32 q4, q4, q10\n"
7984       "vadd.f32 q5, q5, q10\n"
7985       "vadd.f32 q6, q6, q10\n"
7986       "vadd.f32 q7, q7, q10\n"
7987       "vadd.f32 q0, q0, q4\n"
7988       "vadd.f32 q1, q1, q5\n"
7989       "vadd.f32 q2, q2, q6\n"
7990       "vadd.f32 q3, q3, q7\n"
7991       "vsub.f32 q0, q0, q12\n"
7992       "vsub.f32 q1, q1, q12\n"
7993       "vsub.f32 q2, q2, q12\n"
7994       "vsub.f32 q3, q3, q12\n"
7995       "vmul.f32 q0, q0, q13\n"
7996       "vmul.f32 q1, q1, q13\n"
7997       "vmul.f32 q2, q2, q13\n"
7998       "vmul.f32 q3, q3, q13\n"
7999       "vadd.f32 q0, q0, q14\n"
8000       "vadd.f32 q1, q1, q14\n"
8001       "vadd.f32 q2, q2, q14\n"
8002       "vadd.f32 q3, q3, q14\n"
8003       "vcvt.s32.f32 q0, q0\n"
8004       "vcvt.s32.f32 q1, q1\n"
8005       "vcvt.s32.f32 q2, q2\n"
8006       "vcvt.s32.f32 q3, q3\n"
8007 
8008       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
8009       "vst1.32 {d4, d5, d6, d7}, [%[output]]!\n"
8010       "pld [%[output]]\n"
8011       "bne 2b\n"
8012       "3:"
8013 
8014       // BiasAdd::Transform
8015       "vld1.32 {d0}, [%[input]]!\n"
8016       "vld1.32 {d1[0]}, [%[input]]!\n"
8017       "vld1.16 {d1[2]}, [%[input]]!\n"
8018       "vld1.8 {d1[6]}, [%[input]]!\n"
8019       "vld1.32 {d8}, [r1]!\n"
8020       "vld1.32 {d9[0]}, [r1]!\n"
8021       "vld1.16 {d9[2]}, [r1]!\n"
8022       "vld1.8 {d9[6]}, [r1]!\n"
8023       "pld [%[input], #32]\n"
8024       "vmovl.u8 q1, d1\n"
8025       "vmovl.u8 q0, d0\n"
8026       "vmovl.u8 q5, d9\n"
8027       "vmovl.u8 q4, d8\n"
8028       "vmovl.s16 q3, d3\n"
8029       "vmovl.s16 q2, d2\n"
8030       "vmovl.s16 q7, d11\n"
8031       "vmovl.s16 q6, d10\n"
8032       "vmovl.s16 q1, d1\n"
8033       "vmovl.s16 q0, d0\n"
8034       "vmovl.s16 q5, d9\n"
8035       "vmovl.s16 q4, d8\n"
8036       "vcvt.f32.s32 q0, q0\n"
8037       "vcvt.f32.s32 q1, q1\n"
8038       "vcvt.f32.s32 q2, q2\n"
8039       "vcvt.f32.s32 q3, q3\n"
8040       "vcvt.f32.s32 q4, q4\n"
8041       "vcvt.f32.s32 q5, q5\n"
8042       "vcvt.f32.s32 q6, q6\n"
8043       "vcvt.f32.s32 q7, q7\n"
8044       "vmul.f32 q0, q0, q9\n"
8045       "vmul.f32 q1, q1, q9\n"
8046       "vmul.f32 q2, q2, q9\n"
8047       "vmul.f32 q3, q3, q9\n"
8048       "vmul.f32 q4, q4, q11\n"
8049       "vmul.f32 q5, q5, q11\n"
8050       "vmul.f32 q6, q6, q11\n"
8051       "vmul.f32 q7, q7, q11\n"
8052       "vadd.f32 q0, q0, q8\n"
8053       "vadd.f32 q1, q1, q8\n"
8054       "vadd.f32 q2, q2, q8\n"
8055       "vadd.f32 q3, q3, q8\n"
8056       "vadd.f32 q4, q4, q10\n"
8057       "vadd.f32 q5, q5, q10\n"
8058       "vadd.f32 q6, q6, q10\n"
8059       "vadd.f32 q7, q7, q10\n"
8060       "vadd.f32 q0, q0, q4\n"
8061       "vadd.f32 q1, q1, q5\n"
8062       "vadd.f32 q2, q2, q6\n"
8063       "vadd.f32 q3, q3, q7\n"
8064       "vsub.f32 q0, q0, q12\n"
8065       "vsub.f32 q1, q1, q12\n"
8066       "vsub.f32 q2, q2, q12\n"
8067       "vsub.f32 q3, q3, q12\n"
8068       "vmul.f32 q0, q0, q13\n"
8069       "vmul.f32 q1, q1, q13\n"
8070       "vmul.f32 q2, q2, q13\n"
8071       "vmul.f32 q3, q3, q13\n"
8072       "vadd.f32 q0, q0, q14\n"
8073       "vadd.f32 q1, q1, q14\n"
8074       "vadd.f32 q2, q2, q14\n"
8075       "vadd.f32 q3, q3, q14\n"
8076       "vcvt.s32.f32 q0, q0\n"
8077       "vcvt.s32.f32 q1, q1\n"
8078       "vcvt.s32.f32 q2, q2\n"
8079       "vcvt.s32.f32 q3, q3\n"
8080 
8081       "vst1.32 {d0, d1, d2, d3}, [%[output]]!\n"
8082       "vst1.32 {d4, d5, d6}, [%[output]]!\n"
8083       "vst1.32 {d7[0]}, [%[output]]!\n"
8084       "pld [%[output]]\n"
8085       "subs %[rows], %[rows], #1\n"
8086       "bne 1b\n"
8087       : [input] "+r"(input), [output] "+r"(output)
8088       : [count] "r"(params.count), [rows] "r"(params_rows_copy),
8089         [output_range_offset] "m"(params.output_range_offset),
8090         [input_range_scale] "m"(params.input_range_scale),
8091         [one_over_output_range_scale] "m"(params.one_over_output_range_scale),
8092         [bias_range_min] "m"(params.bias_range_min),
8093         [output_range_min] "m"(params.output_range_min),
8094         [bias_range_scale] "m"(params.bias_range_scale),
8095         [bias] "r"(params.bias), [input_range_min] "m"(params.input_range_min)
8096       : "r0", "r1", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
8097         "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
8098         "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
8099         "cc", "memory");
8100 }
8101 
8102 }  // namespace meta
8103 }  // namespace gemmlowp
8104 
8105 #else
8106 #warning "Meta gemm for arm32 requires: GEMMLOWP_NEON_32!"
8107 #endif
8108 
8109 #endif  // GEMMLOWP_META_TRANSFORM_KERNELS_ARM_32_H_
8110