Home | History | Annotate | Download | only in meta
      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 <>
     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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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 <>
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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,
   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