Home | History | Annotate | Download | only in internal
      1 // Copyright 2015 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 // kernel_neon.h: a collection of NEON optimized kernels.
     16 // Check in kernel_default.h which one(s) are actually used by default.
     17 // Others are mere experiments; they are still covered by tests
     18 // in case they might be useful some day.
     19 
     20 #ifndef GEMMLOWP_INTERNAL_KERNEL_NEON_H_
     21 #define GEMMLOWP_INTERNAL_KERNEL_NEON_H_
     22 
     23 #include "kernel.h"
     24 
     25 #include <arm_neon.h>
     26 #include <cassert>
     27 
     28 namespace gemmlowp {
     29 
     30 // The kernels here are specifically arm 32bit assembly, not arm 64bit.
     31 #ifdef GEMMLOWP_NEON_32
     32 
     33 // Our main GEMM kernel.
     34 struct NEON_32_Kernel12x4Depth2 : KernelBase {
     35   typedef KernelFormat<KernelSideFormat<CellFormat<4, 2>, 3>,
     36                        KernelSideFormat<CellFormat<4, 2>, 1> >
     37       Format;
     38 
     39   const char* Name() const override { return "NEON, 12x4, depth 2"; }
     40 
     41   // TODO(benoitjacob): reorder function arguments so dst comes last
     42   void Run(std::int32_t* dst_ptr, std::size_t dst_row_stride,
     43            std::size_t dst_col_stride, const std::uint8_t* lhs_ptr,
     44            const std::uint8_t* rhs_ptr, std::size_t start_depth,
     45            std::size_t run_depth) const override {
     46     ScopedProfilingLabel label("optimized kernel (NEON 12x4)");
     47 
     48 // For iOS assembler, the %= style of local labels cause compilation errors,
     49 //  so use numerical ones instead. See
     50 // http://stackoverflow.com/questions/3898435/labels-in-gcc-inline-assembly
     51 // If you add any labels, remember to undef them at the end.
     52 #define GEMMLOWP_LABEL_CLEAR_ACCUMULATORS "1"
     53 #define GEMMLOWP_LABEL_BEFORE_LOOP "2"
     54 #define GEMMLOWP_LABEL_LOOP "3"
     55 #define GEMMLOWP_LABEL_AFTER_LOOP "4"
     56 
     57     assert(dst_row_stride == 1);
     58     asm volatile(
     59         // Overview of register layout:
     60         //
     61         // A 2x4 cell of Rhs is stored in 16bit in d0--d1 (q0).
     62         // A 12x2 block of 3 4x2 cells Lhs is stored in 16bit in d2--d7
     63         // (q1--q3).
     64         // A 12x4 block of accumulators is stored in 32bit in q4--q15.
     65         //
     66         //                   +-----+-----+-----+-----+
     67         //                   |d0[0]|d0[1]|d0[2]|d0[3]|
     68         //              Rhs  +-----+-----+-----+-----+
     69         //                   |d1[0]|d1[1]|d1[2]|d1[3]|
     70         //                   +-----+-----+-----+-----+
     71         //
     72         //                   |     |     |     |     |
     73         //
     74         //    Lhs            |     |     |     |     |
     75         //
     76         //  +--+--+ - - - -  +-----+-----+-----+-----+
     77         //  |d2|d3|          | q4  | q5  | q6  | q7  |
     78         //  |d2|d3|          | q4  | q5  | q6  | q7  |
     79         //  |d2|d3|          | q4  | q5  | q6  | q7  |
     80         //  |d2|d3|          | q4  | q5  | q6  | q7  |
     81         //  +--+--+ - - - -  +-----+-----+-----+-----+
     82         //  |d4|d5|          | q8  | q9  | q10 | q11 |
     83         //  |d4|d5|          | q8  | q9  | q10 | q11 |
     84         //  |d4|d5|          | q8  | q9  | q10 | q11 |
     85         //  |d4|d5|          | q8  | q9  | q10 | q11 |
     86         //  +--+--+ - - - -  +-----+-----+-----+-----+
     87         //  |d6|d7|          | q12 | q13 | q14 | q15 |
     88         //  |d6|d7|          | q12 | q13 | q14 | q15 |
     89         //  |d6|d7|          | q12 | q13 | q14 | q15 |
     90         //  |d6|d7|          | q12 | q13 | q14 | q15 |
     91         //  +--+--+ - - - -  +-----+-----+-----+-----+
     92         //
     93         //                            Accumulator
     94 
     95         // Load 1 Rhs cell of size 2x4
     96         "vld1.8 {d0}, [%[rhs_ptr]]!\n"
     97         // Load 3 Lhs cells of size 4x2 each
     98         "vld1.8 {d2}, [%[lhs_ptr]]!\n"
     99         "vld1.8 {d4}, [%[lhs_ptr]]!\n"
    100         "vld1.8 {d6}, [%[lhs_ptr]]!\n"
    101 
    102         // Check if start_depth==0 to decide whether we will clear
    103         // accumulators or load existing accumulators.
    104         "cmp %[start_depth], #0\n"
    105 
    106         // Multiply dst_col_stride by 4 == sizeof(int32) to use
    107         // it as a byte offset below.
    108         "lsl %[dst_col_stride], #2\n"
    109 
    110         "beq " GEMMLOWP_LABEL_CLEAR_ACCUMULATORS
    111         "f\n"
    112 
    113         // Load accumulators (start_depth != 0)
    114         "mov r1, %[dst_ptr]\n"
    115         "subs %[run_depth], #2\n"
    116         "mov r0, r1\n"
    117         "vld1.32 {d8, d9},   [r0]!\n"
    118         "add r1, %[dst_col_stride]\n"
    119         "vld1.32 {d16, d17}, [r0]!\n"
    120         "vld1.32 {d24, d25}, [r0]\n"
    121         "mov r0, r1\n"
    122         "vld1.32 {d10, d11}, [r0]!\n"
    123         "add r1, %[dst_col_stride]\n"
    124         "vld1.32 {d18, d19}, [r0]!\n"
    125         "vld1.32 {d26, d27}, [r0]\n"
    126         "mov r0, r1\n"
    127         "vld1.32 {d12, d13}, [r0]!\n"
    128         "add r1, %[dst_col_stride]\n"
    129         "vld1.32 {d20, d21}, [r0]!\n"
    130         "vld1.32 {d28, d29}, [r0]\n"
    131         "mov r0, r1\n"
    132         "vld1.32 {d14, d15}, [r0]!\n"
    133         "vld1.32 {d22, d23}, [r0]!\n"
    134         "vld1.32 {d30, d31}, [r0]\n"
    135 
    136         "b " GEMMLOWP_LABEL_BEFORE_LOOP "f\n"
    137 
    138         GEMMLOWP_LABEL_CLEAR_ACCUMULATORS
    139         ":\n"
    140 
    141         // Clear accumulators (start_depth == 0)
    142         "vmov.s32 q4, #0\n"
    143         "subs %[run_depth], #2\n"
    144         "vmov.s32 q8, q4\n"
    145         "vmov.s32 q12, q4\n"
    146         "vmov.s32 q5, q4\n"
    147         "vmov.s32 q9, q4\n"
    148         "vmov.s32 q13, q4\n"
    149         "vmov.s32 q6, q4\n"
    150         "vmov.s32 q10, q4\n"
    151         "vmov.s32 q14, q4\n"
    152         "vmov.s32 q7, q4\n"
    153         "vmov.s32 q11, q4\n"
    154         "vmov.s32 q15, q4\n"
    155 
    156         GEMMLOWP_LABEL_BEFORE_LOOP
    157         ":\n"
    158 
    159         // If there are only two levels of depth, skip the loop.
    160         "beq " GEMMLOWP_LABEL_AFTER_LOOP "f\n"
    161 
    162         GEMMLOWP_LABEL_LOOP
    163         ":\n"
    164         // Expand Lhs/Rhs cells to 16 bit.
    165         // Note: moving theses vmovls further down to allow for
    166         // longer data pipelining helps a little on A57 but is
    167         // harmful on A53 --- It looks as if A53 doesn't like
    168         // interleaving vmovl's into the vmlal's.
    169         "vmovl.u8 q0, d0\n"
    170         "vmovl.u8 q1, d2\n"
    171         "vmovl.u8 q2, d4\n"
    172         "vmovl.u8 q3, d6\n"
    173 
    174         // Multiply-accumulate, level of depth 0
    175         "vmlal.u16 q4, d2, d0[0]\n"
    176         "vmlal.u16 q5, d2, d0[1]\n"
    177         "vmlal.u16 q6, d2, d0[2]\n"
    178         "vmlal.u16 q7, d2, d0[3]\n"
    179         "vldr d2, [%[lhs_ptr]]\n"
    180         "vmlal.u16 q8, d4, d0[0]\n"
    181         "vmlal.u16 q9, d4, d0[1]\n"
    182         "vmlal.u16 q10, d4, d0[2]\n"
    183         "vmlal.u16 q11, d4, d0[3]\n"
    184         "vldr d4, [%[lhs_ptr], #8]\n"
    185         "vmlal.u16 q12, d6, d0[0]\n"
    186         "vmlal.u16 q13, d6, d0[1]\n"
    187         "vmlal.u16 q14, d6, d0[2]\n"
    188         "vmlal.u16 q15, d6, d0[3]\n"
    189         "vldr d6, [%[lhs_ptr], #16]\n"
    190         "vldr d0, [%[rhs_ptr]]\n"
    191 
    192         // Multiply-accumulate, level of depth 1
    193         "vmlal.u16 q4, d3, d1[0]\n"
    194         "vmlal.u16 q5, d3, d1[1]\n"
    195         "add %[lhs_ptr], #24\n"
    196         "vmlal.u16 q6, d3, d1[2]\n"
    197         "vmlal.u16 q7, d3, d1[3]\n"
    198         "add %[rhs_ptr], #8\n"
    199         "vmlal.u16 q8, d5, d1[0]\n"
    200         "vmlal.u16 q9, d5, d1[1]\n"
    201         "subs %[run_depth], #2\n"
    202         "vmlal.u16 q10, d5, d1[2]\n"
    203         "vmlal.u16 q11, d5, d1[3]\n"
    204         "vmlal.u16 q12, d7, d1[0]\n"
    205         "vmlal.u16 q13, d7, d1[1]\n"
    206         "vmlal.u16 q14, d7, d1[2]\n"
    207         "vmlal.u16 q15, d7, d1[3]\n"
    208 
    209         "bne " GEMMLOWP_LABEL_LOOP "b\n"
    210 
    211         GEMMLOWP_LABEL_AFTER_LOOP
    212         ":\n"
    213 
    214         // Do remaining arithmetic for the last 2 levels of depth.
    215 
    216         // Expand Lhs/Rhs cells to 16 bit.
    217         "vmovl.u8 q0, d0\n"
    218         "vmovl.u8 q1, d2\n"
    219         "vmovl.u8 q2, d4\n"
    220         "vmovl.u8 q3, d6\n"
    221 
    222         // Multiply-accumulate, level of depth 0
    223         "vmlal.u16 q4, d2, d0[0]\n"
    224         "vmlal.u16 q5, d2, d0[1]\n"
    225         "vmlal.u16 q6, d2, d0[2]\n"
    226         "vmlal.u16 q7, d2, d0[3]\n"
    227         "vmlal.u16 q8, d4, d0[0]\n"
    228         "vmlal.u16 q9, d4, d0[1]\n"
    229         "vmlal.u16 q10, d4, d0[2]\n"
    230         "vmlal.u16 q11, d4, d0[3]\n"
    231         "vmlal.u16 q12, d6, d0[0]\n"
    232         "vmlal.u16 q13, d6, d0[1]\n"
    233         "vmlal.u16 q14, d6, d0[2]\n"
    234         "vmlal.u16 q15, d6, d0[3]\n"
    235 
    236         // Multiply-accumulate, level of depth 1
    237         "vmlal.u16 q4, d3, d1[0]\n"
    238         "vmlal.u16 q5, d3, d1[1]\n"
    239         "vmlal.u16 q6, d3, d1[2]\n"
    240         "vmlal.u16 q7, d3, d1[3]\n"
    241         "vmlal.u16 q8, d5, d1[0]\n"
    242         "vmlal.u16 q9, d5, d1[1]\n"
    243         "vmlal.u16 q10, d5, d1[2]\n"
    244         "vmlal.u16 q11, d5, d1[3]\n"
    245         "vmlal.u16 q12, d7, d1[0]\n"
    246         "vmlal.u16 q13, d7, d1[1]\n"
    247         "vmlal.u16 q14, d7, d1[2]\n"
    248         "vmlal.u16 q15, d7, d1[3]\n"
    249 
    250         // Store accumulators
    251         "mov r1, %[dst_ptr]\n"
    252         "mov r0, r1\n"
    253         "vst1.32 {d8, d9},   [r0]!\n"
    254         "add r1, %[dst_col_stride]\n"
    255         "vst1.32 {d16, d17}, [r0]!\n"
    256         "vst1.32 {d24, d25}, [r0]\n"
    257         "mov r0, r1\n"
    258         "vst1.32 {d10, d11}, [r0]!\n"
    259         "add r1, %[dst_col_stride]\n"
    260         "vst1.32 {d18, d19}, [r0]!\n"
    261         "vst1.32 {d26, d27}, [r0]\n"
    262         "mov r0, r1\n"
    263         "vst1.32 {d12, d13}, [r0]!\n"
    264         "add r1, %[dst_col_stride]\n"
    265         "vst1.32 {d20, d21}, [r0]!\n"
    266         "vst1.32 {d28, d29}, [r0]\n"
    267         "mov r0, r1\n"
    268         "vst1.32 {d14, d15}, [r0]!\n"
    269         "vst1.32 {d22, d23}, [r0]!\n"
    270         "vst1.32 {d30, d31}, [r0]\n"
    271         :  // outputs
    272         [lhs_ptr] "+r"(lhs_ptr), [rhs_ptr] "+r"(rhs_ptr),
    273         [dst_ptr] "+r"(dst_ptr),
    274         [run_depth] "+r"(run_depth)
    275         :  // inputs
    276         [start_depth] "r"(start_depth),
    277         [dst_col_stride] "r"(dst_col_stride)
    278         :  // clobbers
    279         "cc", "memory", "r0", "r1",
    280         // note: someone on internet says that quad registers are
    281         // unsupported in the clobber list!
    282         "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
    283         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
    284         "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
    285         "d31");
    286 #undef GEMMLOWP_LABEL_CLEAR_ACCUMULATORS
    287 #undef GEMMLOWP_LABEL_BEFORE_LOOP
    288 #undef GEMMLOWP_LABEL_LOOP
    289 #undef GEMMLOWP_LABEL_AFTER_LOOP
    290   }
    291 };
    292 
    293 struct NEON_32_Kernel12x4Depth2Assuming12BitProducts : KernelBase {
    294   typedef KernelFormat<
    295       KernelSideFormat<CellFormat<4, 2, CellOrder::WidthMajor>, 3>,
    296       KernelSideFormat<CellFormat<4, 2, CellOrder::WidthMajor>, 1> >
    297       Format;
    298 
    299   const char* Name() const override {
    300     return "NEON, 12x4, depth 2, assuming 12-bit products";
    301   }
    302 
    303   // TODO(benoitjacob): reorder function arguments so dst comes last
    304   void Run(std::int32_t* dst_ptr, std::size_t dst_row_stride,
    305            std::size_t dst_col_stride, const std::uint8_t* lhs_ptr,
    306            const std::uint8_t* rhs_ptr, std::size_t start_depth,
    307            std::size_t run_depth) const override {
    308     ScopedProfilingLabel label(
    309         "optimized kernel (NEON 12x4, assuming 12-bit products)");
    310     assert(dst_row_stride == 1);
    311 
    312 // See comments above for why we need local numerical labels in our asm.
    313 #define GEMMLOWP_LOOP_NEON_32_KERNEL_12X4_DEPTH2_ASSUMING_12BIT_PRODUCTS "1"
    314 #define GEMMLOWP_LOAD_GLOBAL_ACCUMULATORS_NEON_32_KERNEL_12X4_DEPTH2_12BIT "2"
    315 #define GEMMLOWP_LABEL_32 "3"
    316 #define GEMMLOWP_LABEL_24 "4"
    317 #define GEMMLOWP_LABEL_16 "5"
    318 #define GEMMLOWP_LABEL_8 "6"
    319 #define GEMMLOWP_LABEL_2 "7"
    320 
    321     // This kernel is special in that it uses local 16-bit accumulators.
    322     // Because it assumes that each product fits in 12 bits, it can accumulate
    323     // 16 products into a local 16-bit accumulator without risking overflow.
    324     // At that point, it must accumulate these local 16-bit accumulators back
    325     // into global 32-bit accumulators, which have to be stored in memory for
    326     // lack of register space.
    327     // This 12x4 block of global accumulators is laid out as 3 cells of size 4x4
    328     // stored in diagonal-major order like this for the first 4x4 cell:
    329     //
    330     //   0   4   8  12
    331     //  13   1   5   9
    332     //  10  14   2   6
    333     //   7  11  15   3
    334     //
    335     // and likewise for the 2nd  cell (16--31) and 3rd cell (32--47)
    336     std::int32_t global_accumulators[3 * 4 * 4];
    337     asm volatile(
    338         // Compute stride between consecutive columns, in bytes
    339         "mov r0, #4\n"  // multiply by 4 = sizeof(int32)
    340         "mul %[dst_col_stride], r0\n"
    341 
    342         "cmp %[start_depth], #0\n"
    343         "bne"
    344         " " GEMMLOWP_LOAD_GLOBAL_ACCUMULATORS_NEON_32_KERNEL_12X4_DEPTH2_12BIT
    345         "f\n"
    346 
    347         // If start_depth==0, we need to clear our global accumulators
    348         "mov r0, %[global_accumulators]\n"
    349         "vmov.s32 q8, #0\n"
    350         "vmov.s32 q9, q8\n"
    351         "vst1.32 {d16,d17,d18,d19}, [r0]!\n"
    352         "vst1.32 {d16,d17,d18,d19}, [r0]!\n"
    353         "vst1.32 {d16,d17,d18,d19}, [r0]!\n"
    354         "vst1.32 {d16,d17,d18,d19}, [r0]!\n"
    355         "vst1.32 {d16,d17,d18,d19}, [r0]!\n"
    356         "vst1.32 {d16,d17,d18,d19}, [r0]!\n"
    357         "b " GEMMLOWP_LOOP_NEON_32_KERNEL_12X4_DEPTH2_ASSUMING_12BIT_PRODUCTS
    358         "f\n"
    359 
    360         // If start_depth!=0, we need to load our existing global accumulators
    361         GEMMLOWP_LOAD_GLOBAL_ACCUMULATORS_NEON_32_KERNEL_12X4_DEPTH2_12BIT
    362         ":\n"
    363         // Load global accumulators from destination matrix, column-major
    364         "mov r1, %[dst_ptr]\n"
    365         "mov r0, %[dst_col_stride]\n"
    366         "sub r0, #32\n"
    367         "vld1.32 {d0,d1}, [r1]!\n"
    368         "vld1.32 {d8,d9}, [r1]!\n"
    369         "vld1.32 {d16,d17}, [r1], r0\n"
    370         "vld1.32 {d2,d3}, [r1]!\n"
    371         "vld1.32 {d10,d11}, [r1]!\n"
    372         "vld1.32 {d18,d19}, [r1], r0\n"
    373         "vld1.32 {d4,d5}, [r1]!\n"
    374         "vld1.32 {d12,d13}, [r1]!\n"
    375         "vld1.32 {d20,d21}, [r1], r0\n"
    376         "vld1.32 {d6,d7}, [r1]!\n"
    377         "vld1.32 {d14,d15}, [r1]!\n"
    378         "vld1.32 {d22,d23}, [r1], r0\n"
    379         // Now we need to convert the global accumulator registers to
    380         // 4x4-block-wise diagonal-major order. What we effectively want to do
    381         // is to rotate the rows, however the accumulators are stored in
    382         // column-major order in registers. So we achieve this by
    383         // transposing, rotating the registers, and transposing again each
    384         // 4x4 block.
    385         //
    386         // Transpose 3 4x4 blocks separately
    387         "vtrn.32 q0, q1\n"
    388         "vtrn.32 q2, q3\n"
    389         "vswp d1, d4\n"
    390         "vswp d3, d6\n"
    391         "vtrn.32 q4, q5\n"
    392         "vtrn.32 q6, q7\n"
    393         "vswp d9, d12\n"
    394         "vswp d11, d14\n"
    395         "vtrn.32 q8, q9\n"
    396         "vtrn.32 q10, q11\n"
    397         "vswp d17, d20\n"
    398         "vswp d19, d22\n"
    399         // Rotate the registers
    400         "vext.32 q1, q1, q1, #1\n"
    401         "vext.32 q2, q2, q2, #2\n"
    402         "vext.32 q3, q3, q3, #3\n"
    403         "vext.32 q5, q5, q5, #1\n"
    404         "vext.32 q6, q6, q6, #2\n"
    405         "vext.32 q7, q7, q7, #3\n"
    406         "vext.32 q9, q9, q9, #1\n"
    407         "vext.32 q10, q10, q10, #2\n"
    408         "vext.32 q11, q11, q11, #3\n"
    409         // Transpose again and store into our global accumulators
    410         // buffer. These two operations are done at once using vst4.
    411         "mov r0, %[global_accumulators]\n"
    412         "vst4.32 {d0,d2,d4,d6}, [r0]!\n"
    413         "vst4.32 {d1,d3,d5,d7}, [r0]!\n"
    414         "vst4.32 {d8,d10,d12,d14}, [r0]!\n"
    415         "vst4.32 {d9,d11,d13,d15}, [r0]!\n"
    416         "vst4.32 {d16,d18,d20,d22}, [r0]!\n"
    417         "vst4.32 {d17,d19,d21,d23}, [r0]!\n"
    418 
    419         /* Main loop */
    420 
    421         GEMMLOWP_LOOP_NEON_32_KERNEL_12X4_DEPTH2_ASSUMING_12BIT_PRODUCTS
    422         ":\n"
    423 
    424     // Overview of register layout:
    425     //
    426     // Registers q4--q16 are the local 16-bit accumulators.
    427     // However, each entry in the result matrix is represented
    428     // by *two* local 16-bit accumulators: one for even levels
    429     // of depth and one for odd levels of depth. These correspond
    430     // to the scalars at even and odd indices within each q-register.
    431     // Thus we effectively use 32 bits of register space for each
    432     // entry in the result matrix. The accumulators register layout
    433     // is the same as was described above for the global 32-bit
    434     // accumulators (3 cells of size 4x4 in diagonal-major order)
    435     // with the only difference that instead of 32bit values we have
    436     // pairs of 16bit values.
    437     //
    438     // A 2x4 cell of Rhs is stored in 8bit in d0.
    439     // A 12x2 block of 3 4x2 cells Lhs is stored in 8bit in d1--d3.
    440     //
    441     //                      +--------+--------+--------+--------+
    442     //                      |d0[0]   |d0[2]   |d0[4]   |d0[6]   |
    443     //                 Rhs  +--------+--------+--------+--------+
    444     //                      |d0[1]   |d0[3]   |d0[5]   |d0[7]   |
    445     //                      +--------+--------+--------+--------+
    446     //
    447     //                      |        |        |        |        |
    448     //
    449     //    Lhs               |        |        |        |        |
    450     //
    451     //  +-----+-----+ - - - +--------+--------+--------+--------+
    452     //  |d1[0]|d1[1]|       |q4[0,1] |q5[0,1] |q6[0,1] |q7[0,1] |
    453     //  |d1[2]|d1[3]|       |q7[2,3] |q4[2,3] |q5[2,3] |q6[2,3] |
    454     //  |d1[4]|d1[5]|       |q6[4,5] |q7[4,5] |q4[4,5] |q5[4,5] |
    455     //  |d1[6]|d1[7]|       |q5[6,7] |q6[6,7] |q7[6,7] |q4[6,7] |
    456     //  +-----+-----+ - - - +--------+--------+--------+--------+
    457     //  |d2[0]|d2[1]|       |q8[0,1] |q8[0,1] |q8[0,1] |q8[0,1] |
    458     //  |d2[2]|d2[3]|       |q9[2,3] |q9[2,3] |q9[2,3] |q9[2,3] |
    459     //  |d2[4]|d2[5]|       |q10[4,5]|q10[4,5]|q10[4,5]|q10[4,5]|
    460     //  |d2[6]|d2[7]|       |q11[6,7]|q11[6,7]|q11[6,7]|q11[6,7]|
    461     //  +-----+-----+ - - - +--------+--------+--------+--------+
    462     //  |d3[0]|d3[1]|       |q12[0,1]|q12[0,1]|q12[0,1]|q12[0,1]|
    463     //  |d3[2]|d3[3]|       |q13[2,3]|q13[2,3]|q13[2,3]|q13[2,3]|
    464     //  |d3[4]|d3[5]|       |q14[4,5]|q14[4,5]|q14[4,5]|q14[4,5]|
    465     //  |d3[6]|d3[7]|       |q15[6,7]|q15[6,7]|q15[6,7]|q15[6,7]|
    466     //  +-----+-----+ - - - +--------+--------+--------+--------+
    467     //
    468     //                            Local 16-bit accumulators
    469     //                         Note: 2 scalars per matrix entry
    470 
    471 #define GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH \
    472   /* Load 3 Lhs cells of size 4x2 */          \
    473   "vld1.8 {d1,d2,d3}, [%[lhs_ptr]:64]!\n"     \
    474                                               \
    475   /* Load 1 Rhs cell of size 2x4 */           \
    476   "vld1.8 {d0}, [%[rhs_ptr]:64]!\n"           \
    477                                               \
    478   /* Multiply-accumulate */                   \
    479   "vmlal.u8 q4, d1, d0\n"                     \
    480   "vmlal.u8 q8, d2, d0\n"                     \
    481   "vmlal.u8 q12, d3, d0\n"                    \
    482   "vext.8 d0, d0, d0, #2\n"                   \
    483   "vmlal.u8 q5, d1, d0\n"                     \
    484   "vmlal.u8 q9, d2, d0\n"                     \
    485   "vmlal.u8 q13, d3, d0\n"                    \
    486   "vext.8 d0, d0, d0, #2\n"                   \
    487   "vmlal.u8 q6, d1, d0\n"                     \
    488   "vmlal.u8 q10, d2, d0\n"                    \
    489   "vmlal.u8 q14, d3, d0\n"                    \
    490   "vext.8 d0, d0, d0, #2\n"                   \
    491   "vmlal.u8 q7, d1, d0\n"                     \
    492   "vmlal.u8 q11, d2, d0\n"                    \
    493   "vmlal.u8 q15, d3, d0\n"                    \
    494                                               \
    495   "sub %[run_depth], #2\n"
    496 
    497 #define GEMMLOWP_ACCUMULATE_8_LEVELS_OF_DEPTH \
    498   GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH       \
    499   GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH       \
    500   GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH       \
    501   GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH
    502 
    503         // Clear local 16-bit accumulators
    504         "vmov.s32 q4, #0\n"
    505         "vmov.s32 q5, q4\n"
    506         "vmov.s32 q6, q4\n"
    507         "vmov.s32 q7, q4\n"
    508         "vmov.s32 q8, q4\n"
    509         "vmov.s32 q9, q4\n"
    510         "vmov.s32 q10, q4\n"
    511         "vmov.s32 q11, q4\n"
    512         "vmov.s32 q12, q4\n"
    513         "vmov.s32 q13, q4\n"
    514         "vmov.s32 q14, q4\n"
    515         "vmov.s32 q15, q4\n"
    516 
    517         // Select a suitable number of depth levels
    518         // to process at this iteration. TODO (benoitjacob) I guess that
    519         // someone who really knows asm should make this a jump table.
    520         "cmp %[run_depth], #32\n"
    521         "bge " GEMMLOWP_LABEL_32
    522         "f\n"
    523         "cmp %[run_depth], #24\n"
    524         "bge " GEMMLOWP_LABEL_24
    525         "f\n"
    526         "cmp %[run_depth], #16\n"
    527         "bge " GEMMLOWP_LABEL_16
    528         "f\n"
    529         "cmp %[run_depth], #8\n"
    530         "bge " GEMMLOWP_LABEL_8
    531         "f\n"
    532         "b " GEMMLOWP_LABEL_2 "f\n"
    533 
    534         GEMMLOWP_LABEL_32
    535         ":\n" GEMMLOWP_ACCUMULATE_8_LEVELS_OF_DEPTH GEMMLOWP_LABEL_24
    536         ":\n" GEMMLOWP_ACCUMULATE_8_LEVELS_OF_DEPTH GEMMLOWP_LABEL_16
    537         ":\n" GEMMLOWP_ACCUMULATE_8_LEVELS_OF_DEPTH GEMMLOWP_LABEL_8
    538         ":\n" GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH
    539             GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH
    540                 GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH GEMMLOWP_LABEL_2
    541         ":\n" GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH
    542 
    543         // Accumulate the local accumulators into the global accumulators.
    544         // This is about summing adjacent pairs of 16-bit scalars into
    545         // single 32-bit scalars, so we use pairwise long addition (vpadal).
    546         "mov r0, %[global_accumulators]\n"
    547         "mov r1, %[global_accumulators]\n"
    548         "vld1.32 {d0,d1,d2,d3}, [r0]!\n"
    549         "vld1.32 {d4,d5,d6,d7}, [r0]!\n"
    550         "vpadal.u16 q0, q4\n"
    551         "vpadal.u16 q1, q5\n"
    552         "vpadal.u16 q2, q6\n"
    553         "vpadal.u16 q3, q7\n"
    554         "vst1.32 {d0,d1,d2,d3}, [r1]!\n"
    555         "vst1.32 {d4,d5,d6,d7}, [r1]!\n"
    556         "vld1.32 {d0,d1,d2,d3}, [r0]!\n"
    557         "vld1.32 {d4,d5,d6,d7}, [r0]!\n"
    558         "vpadal.u16 q0, q8\n"
    559         "vpadal.u16 q1, q9\n"
    560         "vpadal.u16 q2, q10\n"
    561         "vpadal.u16 q3, q11\n"
    562         "vst1.32 {d0,d1,d2,d3}, [r1]!\n"
    563         "vst1.32 {d4,d5,d6,d7}, [r1]!\n"
    564         "vld1.32 {d0,d1,d2,d3}, [r0]!\n"
    565         "vld1.32 {d4,d5,d6,d7}, [r0]!\n"
    566         "vpadal.u16 q0, q12\n"
    567         "vpadal.u16 q1, q13\n"
    568         "vpadal.u16 q2, q14\n"
    569         "vpadal.u16 q3, q15\n"
    570         "vst1.32 {d0,d1,d2,d3}, [r1]!\n"
    571         "vst1.32 {d4,d5,d6,d7}, [r1]!\n"
    572 
    573         // Loop.
    574         "cmp %[run_depth], #0\n"
    575         "bne " GEMMLOWP_LOOP_NEON_32_KERNEL_12X4_DEPTH2_ASSUMING_12BIT_PRODUCTS
    576         "b\n"
    577 
    578 #undef GEMMLOWP_CLEAR_LOCAL_ACCUMULATORS
    579 #undef GEMMLOWP_ACCUMULATE_8_LEVELS_OF_DEPTH
    580 #undef GEMMLOWP_ACCUMULATE_2_LEVELS_OF_DEPTH
    581 #undef GEMMLOWP_ADD_TO_GLOBAL_ACCUMULATORS
    582 
    583         /* end of main loop */
    584 
    585         // Store the global accumulators to the destination matrix
    586         // (column-major)
    587         // This is the reverse of the steps that we followed at the beginning
    588         // when we load the global accumulators from the destination matrix.
    589         // The problem is the same: how to convert 4x4 blocks
    590         // between column-major and diagonal-major orders.
    591         // Like above, we do this by rotating rows, and we achieve that by
    592         // tranposing, rotating columns, and transposing again.
    593         //
    594         // Load and transpose 4x4 blocks of global accumulators
    595         // These two steps are done at once by the vld4 instruction.
    596         "mov r0, %[global_accumulators]\n"
    597         "vld4.32 {d0,d2,d4,d6}, [r0]!\n"
    598         "vld4.32 {d1,d3,d5,d7}, [r0]!\n"
    599         "vld4.32 {d8,d10,d12,d14}, [r0]!\n"
    600         "vld4.32 {d9,d11,d13,d15}, [r0]!\n"
    601         "vld4.32 {d16,d18,d20,d22}, [r0]!\n"
    602         "vld4.32 {d17,d19,d21,d23}, [r0]!\n"
    603         // Rotate the rows of each 4x4 block
    604         "vext.32 q1, q1, q1, #3\n"
    605         "vext.32 q2, q2, q2, #2\n"
    606         "vext.32 q3, q3, q3, #1\n"
    607         "vext.32 q5, q5, q5, #3\n"
    608         "vext.32 q6, q6, q6, #2\n"
    609         "vext.32 q7, q7, q7, #1\n"
    610         "vext.32 q9, q9, q9, #3\n"
    611         "vext.32 q10, q10, q10, #2\n"
    612         "vext.32 q11, q11, q11, #1\n"
    613         // Transpose again each 4x4 block
    614         "vtrn.32 q0, q1\n"
    615         "vtrn.32 q2, q3\n"
    616         "vswp d1, d4\n"
    617         "vswp d3, d6\n"
    618         "vtrn.32 q4, q5\n"
    619         "vtrn.32 q6, q7\n"
    620         "vswp d9, d12\n"
    621         "vswp d11, d14\n"
    622         "vtrn.32 q8, q9\n"
    623         "vtrn.32 q10, q11\n"
    624         "vswp d17, d20\n"
    625         "vswp d19, d22\n"
    626         // Store into the column-major destination matrix
    627         "mov r1, %[dst_ptr]\n"
    628         "mov r0, %[dst_col_stride]\n"
    629         "sub r0, #32\n"
    630         "vst1.32 {d0,d1}, [r1]!\n"
    631         "vst1.32 {d8,d9}, [r1]!\n"
    632         "vst1.32 {d16,d17}, [r1], r0\n"
    633         "vst1.32 {d2,d3}, [r1]!\n"
    634         "vst1.32 {d10,d11}, [r1]!\n"
    635         "vst1.32 {d18,d19}, [r1], r0\n"
    636         "vst1.32 {d4,d5}, [r1]!\n"
    637         "vst1.32 {d12,d13}, [r1]!\n"
    638         "vst1.32 {d20,d21}, [r1], r0\n"
    639         "vst1.32 {d6,d7}, [r1]!\n"
    640         "vst1.32 {d14,d15}, [r1]!\n"
    641         "vst1.32 {d22,d23}, [r1], r0\n"
    642         :  // outputs
    643         [lhs_ptr] "+r"(lhs_ptr), [rhs_ptr] "+r"(rhs_ptr),
    644         [dst_ptr] "+r"(dst_ptr),
    645         [run_depth] "+r"(run_depth)
    646         :  // inputs
    647         [start_depth] "r"(start_depth), [dst_col_stride] "r"(dst_col_stride),
    648         [global_accumulators] "r"(&global_accumulators[0])
    649         :  // clobbers
    650         "cc", "memory", "r0", "r1",
    651         // note: someone on internet says that quad registers are
    652         // unsupported in the clobber list!
    653         "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10",
    654         "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20",
    655         "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30",
    656         "d31");
    657 #undef GEMMLOWP_LOOP_NEON_32_KERNEL_12X4_DEPTH2_ASSUMING_12BIT_PRODUCTS
    658 #undef GEMMLOWP_LOAD_GLOBAL_ACCUMULATORS_NEON_32_KERNEL_12X4_DEPTH2_12BIT
    659 #undef GEMMLOWP_LABEL_32
    660 #undef GEMMLOWP_LABEL_24
    661 #undef GEMMLOWP_LABEL_16
    662 #undef GEMMLOWP_LABEL_8
    663 #undef GEMMLOWP_LABEL_2
    664   }
    665 };
    666 
    667 struct NEON_32bit_GEMM_Int8Operands_LhsNonzero : KernelBase {
    668   typedef KernelFormat<
    669       KernelSideFormatInt8<CellFormat<4, 16, CellOrder::WidthMajor>, 1>,
    670       KernelSideFormatInt8<CellFormat<2, 16, CellOrder::WidthMajor>, 1> >
    671       Format;
    672   const char* Name() const override {
    673     return "NEON, 4x2, depth 16, accumulating two within signed int16";
    674   }
    675 
    676   // TODO(benoitjacob): reorder function arguments so dst comes last
    677   void Run(std::int32_t* dst_ptr, std::size_t dst_row_stride,
    678            std::size_t dst_col_stride, const std::uint8_t* lhs_ptr,
    679            const std::uint8_t* rhs_ptr, std::size_t start_depth,
    680            std::size_t run_depth) const override {
    681 #define GEMMLOWP_LABEL_AFTER_LOOP "1"
    682 #define GEMMLOWP_LABEL_LOOP "2"
    683 #define GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES "3"
    684 #define GEMMLOWP_LABEL_STORE "4"
    685     asm volatile(
    686         // Multiply dst_col_stride by 4 == sizeof(int32) to use
    687         // it as a byte offset below.
    688         "lsl %[dst_col_stride], %[dst_col_stride], #2\n"
    689 
    690         // Overview of register layout:
    691         //
    692         // A 2x16 block of Rhs is stored in 8 bit in d0--d3.
    693         // A 4x16 block of Lhs is stored in 8 bit in d4--d7. That is only
    694         // half of the register space required, so we loop over these registers
    695         // twice. Only half of it, a 2x16 block, is stored in d4--d7 at
    696         // any given time.
    697         //
    698         // A 4x2 block of accumulators is stored in q8--q15 (as 4x32 bit
    699         // components which need to be horizontally-added at the end)
    700         //
    701         // The Lhs vectors are multiplied by the Rhs vectors with a widening
    702         // multiply over the 8 first levels of depth, producing int16x8
    703         // vectors of products for each position in the accumulator matrix.
    704         // Here comes the special trick: since the operands are signed int8,
    705         // their range being [ -2^7 , 2^7 ), their products are in range
    706         // [ -2^14 , 2^14 - 1 ), meaning that we can add two such values
    707         // without any risk of overflowing int16.
    708         // We thus proceed with the 8 next levels of depth, multiplying
    709         // again Lhs by Rhs, accumulating into this existing int16x8 vector.
    710         //
    711         // Only then, having processed 16 levels of depth, do we need to
    712         // horizontally add these int16x8 accumulators into the final
    713         // int32x4 accumulators.
    714         //
    715         // As we do not have enough registers to store all 16 int16x8
    716         // temporary-16bit-accumulators, we have them cycle through q4--q7.
    717         //
    718         //
    719         // Register layout (ignoring the q4--q7 temporary 16bit accumulators):
    720         //
    721         //                               +----+----+
    722         //                               | d0 | d2 |
    723         //                               | .  | .  |
    724         //                               | .  | .  |
    725         //                               | .  | .  |
    726         //                       Rhs     +----+----+
    727         //                               | d1 | d3 |
    728         //                               | .  | .  |
    729         //                               | .  | .  |
    730         //                               | .  | .  |
    731         //                               +----+----+
    732         //
    733         //                               |    |    |
    734         //
    735         //    Lhs                        |    |    |
    736         //
    737         //  +--------+--------+ - - - -  +----+----+
    738         //  | d4 ... | d5 ... |          | q8 | q9 |
    739         //  | d6 ... | d7 ... |          | q10| q11|
    740         //  | d4 ... | d5 ... |          | q12| q13|
    741         //  | d6 ... | d7 ... |          | q14| q15|
    742         //  +--------+--------+ - - - -  +----+----+
    743         //
    744         //                               Accumulator
    745         //
    746 
    747         // Clear accumulators, and, interleaved with it,
    748         // initial loads of the first loop iteration,
    749         // taken out of the loop so that in the loop itself we have
    750         // optimal streaming of data from memory.
    751         "vldr d0, [%[rhs_ptr], #0]\n"
    752         "vmov.i32 q8, #0\n"
    753         "vldr d4, [%[lhs_ptr], #0]\n"
    754         "vmov.i32 q9, #0\n"
    755         "vldr d2, [%[rhs_ptr], #16]\n"
    756         "vmov.i32 q10, q8\n"
    757         "vldr d6, [%[lhs_ptr], #16]\n"
    758         "vmov.i32 q11, q8\n"
    759         "vldr d1, [%[rhs_ptr], #8]\n"
    760         "vmov.i32 q12, q8\n"
    761         "vldr d5, [%[lhs_ptr], #8]\n"
    762         "vmov.i32 q13, q8\n"
    763         "vldr d3, [%[rhs_ptr], #24]\n"
    764         "vmov.i32 q14, q8\n"
    765         "vldr d7, [%[lhs_ptr], #24]\n"
    766         "vmov.i32 q15, q8\n"
    767 
    768         // General loop.
    769         GEMMLOWP_LABEL_LOOP
    770         ":\n"
    771 
    772         // Multiply 8 first levels of depth.
    773         "vmull.s8    q4,  d0,  d4\n"
    774         "add %[rhs_ptr], %[rhs_ptr], #32\n"
    775         "vmull.s8    q5,  d2,  d4\n"
    776         "vldr d4, [%[lhs_ptr], #32]\n"
    777         "vmull.s8    q6,  d0,  d6\n"
    778         "vmull.s8    q7,  d2,  d6\n"
    779         "vldr d6, [%[lhs_ptr], #48]\n"
    780 
    781         // Multiply-accumulate second-half, again into the same
    782         // 16bit local accumulator registers. This is where we
    783         // take advantage of having int8 instead of uint8 and therefore
    784         // being able to accumulate two products into int16.
    785         "vmlal.s8    q4,  d1,  d5\n"
    786         "vmlal.s8    q5,  d3,  d5\n"
    787         "vldr d5, [%[lhs_ptr], #40]\n"
    788         "vmlal.s8    q6,  d1,  d7\n"
    789         "vmlal.s8    q7,  d3,  d7\n"
    790         "vldr d7, [%[lhs_ptr], #56]\n"
    791 
    792         // Add pairwise, accumulate into 32-bit accumulators.
    793         "vpadal.s16   q8,  q4\n"
    794         "add %[lhs_ptr], %[lhs_ptr], #64\n"
    795         "vpadal.s16   q9,  q5\n"
    796         "subs %[run_depth], %[run_depth], #16\n"
    797         "vpadal.s16   q10, q6\n"
    798         "vpadal.s16   q11, q7\n"
    799 
    800         "beq " GEMMLOWP_LABEL_AFTER_LOOP
    801         "f\n"
    802 
    803         // Multiply first half.
    804         "vmull.s8    q4,  d0,  d4\n"
    805         "vmull.s8    q5,  d2,  d4\n"
    806         "vldr d4, [%[lhs_ptr], #0]\n"
    807         "vmull.s8    q6,  d0,  d6\n"
    808         "vldr d0, [%[rhs_ptr], #0]\n"
    809         "vmull.s8    q7,  d2,  d6\n"
    810         "vldr d2, [%[rhs_ptr], #16]\n"
    811 
    812         // Multiply-accumulate second-half, again into the same
    813         // 16bit local accumulator registers. This is where we
    814         // take advantage of having int8 instead of uint8 and therefore
    815         // being able to accumulate two products into int16.
    816         "vmlal.s8    q4,  d1,  d5\n"
    817         "vldr d6, [%[lhs_ptr], #16]\n"
    818         "vmlal.s8    q5,  d3,  d5\n"
    819         "vldr d5, [%[lhs_ptr], #8]\n"
    820         "vmlal.s8    q6,  d1,  d7\n"
    821         "vldr d1, [%[rhs_ptr], #8]\n"
    822         "vmlal.s8    q7,  d3,  d7\n"
    823         "vldr d3, [%[rhs_ptr], #24]\n"
    824 
    825         // Add pairwise, accumulate into 32-bit accumulators.
    826         "vpadal.s16   q12, q4\n"
    827         "vldr d7, [%[lhs_ptr], #24]\n"
    828         "vpadal.s16   q13, q5\n"
    829         "vpadal.s16   q14, q6\n"
    830         "vpadal.s16   q15, q7\n"
    831 
    832         "b " GEMMLOWP_LABEL_LOOP "b\n"
    833 
    834         GEMMLOWP_LABEL_AFTER_LOOP
    835         ":\n"
    836 
    837         // Multiply first half.
    838         "vmull.s8    q4,  d0,  d4\n"
    839         "vmull.s8    q5,  d2,  d4\n"
    840         "vmull.s8    q6,  d0,  d6\n"
    841         "vmull.s8    q7,  d2,  d6\n"
    842 
    843         // Multiply-accumulate second-half, again into the same
    844         // 16bit local accumulator registers. This is where we
    845         // take advantage of having int8 instead of uint8 and therefore
    846         // being able to accumulate two products into int16.
    847         "vmlal.s8    q4,  d1,  d5\n"
    848         "vmlal.s8    q5,  d3,  d5\n"
    849         "vmlal.s8    q6,  d1,  d7\n"
    850         "vmlal.s8    q7,  d3,  d7\n"
    851 
    852         // Add pairwise, accumulate into 32-bit accumulators.
    853         "vpadal.s16   q12, q4\n"
    854         "vpadal.s16   q13, q5\n"
    855         "vpadal.s16   q14, q6\n"
    856         "vpadal.s16   q15, q7\n"
    857         "cmp %[start_depth], #0\n"
    858 
    859         // Reduce 32bit accumulators horizontally.
    860         "vpadd.s32 d0, d16, d17\n"
    861         "vpadd.s32 d1, d18, d19\n"
    862         "vpadd.s32 d2, d20, d21\n"
    863         "vpadd.s32 d3, d22, d23\n"
    864         "vpadd.s32 d4, d24, d25\n"
    865         "vpadd.s32 d5, d26, d27\n"
    866         "vpadd.s32 d6, d28, d29\n"
    867         "vpadd.s32 d7, d30, d31\n"
    868 
    869         "bne " GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES
    870         "f\n"
    871 
    872         // Reduce 32bit accumulators horizontally, second pass
    873         // (each pass adds pairwise. we need to add 4-wise).
    874         "vpadd.s32 d8, d0, d2\n"
    875         "vpadd.s32 d9, d4, d6\n"
    876         "vpadd.s32 d10, d1, d3\n"
    877         "vpadd.s32 d11, d5, d7\n"
    878 
    879         "b " GEMMLOWP_LABEL_STORE "f\n"
    880 
    881         GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES
    882         ":\n"
    883 
    884         // Reduce 32bit accumulators horizontally, second pass
    885         // (each pass adds pairwise. we need to add 4-wise),
    886         // and load destination values from memory.
    887         "mov r0, %[dst_ptr]\n"
    888         "vld1.32 {d16, d17}, [r0], %[dst_col_stride]\n"
    889         "vpadd.s32 d8, d0, d2\n"
    890         "vpadd.s32 d9, d4, d6\n"
    891         "vld1.32 {d18, d19}, [r0]\n"
    892         "vpadd.s32 d10, d1, d3\n"
    893         "vpadd.s32 d11, d5, d7\n"
    894 
    895         // Add horizontally-reduced accumulators into
    896         // the values loaded from memory
    897         "vadd.s32 q4, q8, q4\n"
    898         "vadd.s32 q5, q9, q5\n"
    899 
    900         GEMMLOWP_LABEL_STORE
    901         ":\n"
    902         // Store back into memory
    903         "mov r0, %[dst_ptr]\n"
    904         "vst1.32 {d8, d9}, [r0], %[dst_col_stride]\n"
    905         "vst1.32 {d10, d11}, [r0]\n"
    906         :  // outputs
    907         [lhs_ptr] "+r"(lhs_ptr), [rhs_ptr] "+r"(rhs_ptr),
    908         [dst_ptr] "+r"(dst_ptr), [run_depth] "+r"(run_depth)
    909         :  // inputs
    910         [start_depth] "r"(start_depth),
    911         [dst_col_stride] "r"(dst_col_stride)
    912         :  // clobbers
    913         "cc", "memory", "r0", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
    914         "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17",
    915         "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27",
    916         "d28", "d29", "d30", "d31");
    917 #undef GEMMLOWP_LABEL_LOOP
    918 #undef GEMMLOWP_LABEL_AFTER_LOOP
    919 #undef GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES
    920 #undef GEMMLOWP_LABEL_STORE
    921   }
    922 };
    923 
    924 #endif  // GEMMLOWP_NEON_32
    925 
    926 // The kernels here are specifically arm 64bit assembly, not arm 32bit.
    927 #ifdef GEMMLOWP_NEON_64
    928 
    929 struct NEON_64bit_GEMM_Int8Operands_LhsNonzero : KernelBase {
    930   typedef KernelFormat<
    931       KernelSideFormatInt8<CellFormat<4, 16, CellOrder::WidthMajor>, 1>,
    932       KernelSideFormatInt8<CellFormat<4, 16, CellOrder::WidthMajor>, 1> >
    933       Format;
    934   const char* Name() const override {
    935     return "NEON, 4x4, depth 16, accumulating two within signed int16";
    936   }
    937 
    938   // TODO(benoitjacob): reorder function arguments so dst comes last
    939   void Run(std::int32_t* dst_ptr, std::size_t dst_row_stride,
    940            std::size_t dst_col_stride, const std::uint8_t* lhs_ptr,
    941            const std::uint8_t* rhs_ptr, std::size_t start_depth,
    942            std::size_t run_depth) const override {
    943 #define GEMMLOWP_LABEL_AFTER_LOOP_LAST16 "1"
    944 #define GEMMLOWP_LABEL_LOOP "2"
    945 #define GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES "3"
    946 #define GEMMLOWP_LABEL_STORE "4"
    947     asm volatile(
    948         // Clear accumulators, and, interleaved with it,
    949         // initial loads of the first loop iteration,
    950         // taken out of the loop so that in the loop itself we have
    951         // optimal streaming of data from memory.
    952         "ld1 {v0.16b}, [%[rhs_ptr]], #16\n"
    953         "dup v16.4s, wzr\n"
    954         "ld1 {v4.16b}, [%[lhs_ptr]], #16\n"
    955         "dup v17.4s, wzr\n"
    956         "ld1 {v1.16b}, [%[rhs_ptr]], #16\n"
    957         "dup v18.4s, wzr\n"
    958         "ld1 {v5.16b}, [%[lhs_ptr]], #16\n"
    959         "dup v19.4s, wzr\n"
    960         "ld1 {v2.16b}, [%[rhs_ptr]], #16\n"
    961         "dup v20.4s, wzr\n"
    962         "ld1 {v3.16b}, [%[rhs_ptr]], #16\n"
    963         "dup v21.4s, wzr\n"
    964         "ld1 {v6.16b}, [%[lhs_ptr]], #16\n"
    965         "dup v22.4s, wzr\n"
    966         "ld1 {v7.16b}, [%[lhs_ptr]], #16\n"
    967         "dup v23.4s, wzr\n"
    968         "dup v24.4s, wzr\n"
    969         "dup v25.4s, wzr\n"
    970         "dup v26.4s, wzr\n"
    971         "dup v27.4s, wzr\n"
    972         "dup v28.4s, wzr\n"
    973         "dup v29.4s, wzr\n"
    974         "dup v30.4s, wzr\n"
    975         "dup v31.4s, wzr\n"
    976 
    977         // Multiply dst_col_stride by 4 == sizeof(int32) to use
    978         // it as a byte offset below.
    979         "lsl %[dst_col_stride], %[dst_col_stride], #2\n"
    980 
    981         // Initial arithmetic of the first loop iteration,
    982         // taken out of the loop so that in the loop itself we have
    983         // optimal streaming of data from memory.
    984         "smull    v8.8h,  v0.8b,  v4.8b\n"
    985         "smull    v9.8h,  v1.8b,  v4.8b\n"
    986         "smull    v10.8h,  v2.8b,  v4.8b\n"
    987         "smull    v11.8h,  v3.8b,  v4.8b\n"
    988         "smull    v12.8h,  v0.8b,  v5.8b\n"
    989         "smull    v13.8h,  v1.8b,  v5.8b\n"
    990         "smull    v14.8h,  v2.8b,  v5.8b\n"
    991         "smull    v15.8h,  v3.8b,  v5.8b\n"
    992 
    993         // Multiply-accumulate second-half, again into the same
    994         // 16bit local accumulator registers. This is where we
    995         // take advantage of having int8 instead of uint8 and therefore
    996         // being able to accumulate two products into int16.
    997         "smlal2   v8.8h,  v0.16b,  v4.16b\n"
    998         "smlal2   v9.8h,  v1.16b,  v4.16b\n"
    999         "smlal2   v10.8h,  v2.16b,  v4.16b\n"
   1000         "smlal2   v11.8h,  v3.16b,  v4.16b\n"
   1001         "smlal2   v12.8h,  v0.16b,  v5.16b\n"
   1002         "smlal2   v13.8h,  v1.16b,  v5.16b\n"
   1003         "smlal2   v14.8h,  v2.16b,  v5.16b\n"
   1004         "smlal2   v15.8h,  v3.16b,  v5.16b\n"
   1005 
   1006         "subs %[run_depth], %[run_depth], #16\n"
   1007 
   1008         // If the loop depth is only 16, then we can skip the general loop
   1009         // and go straight to the final part of the code.
   1010         "beq " GEMMLOWP_LABEL_AFTER_LOOP_LAST16 "f\n"
   1011 
   1012         // General loop.
   1013         GEMMLOWP_LABEL_LOOP
   1014         ":\n"
   1015 
   1016         // Overview of register layout:
   1017         //
   1018         // A 4x16 block of Rhs is stored in 8 bit in v0--v3.
   1019         // A 4x16 block of Lhs is stored in 8 bit in v4--v7.
   1020         //
   1021         // A 4x4 block of accumulators is stored in v16-v31 (as 4x32 bit
   1022         // components which need to be horizontally-added at the end)
   1023         //
   1024         // The Lhs vectors are multiplied by the Rhs vectors with a widening
   1025         // multiply over the 8 first levels of depth, producing int16x8
   1026         // vectors of products for each position in the accumulator matrix.
   1027         // Here comes the special trick: since the operands are signed int8,
   1028         // their range being [ -2^7 , 2^7 ), their products are in range
   1029         // [ -2^14 , 2^14 - 1 ), meaning that we can add two such values
   1030         // without any risk of overflowing int16.
   1031         // We thus proceed with the 8 next levels of depth, multiplying
   1032         // again Lhs by Rhs, accumulating into this existing int16x8 vector.
   1033         //
   1034         // Only then, having processed 16 levels of depth, do we need to
   1035         // horizontally add these int16x8 accumulators into the final
   1036         // int32x4 accumulators.
   1037         //
   1038         // As we do not have enough registers to store all 16 int16x8
   1039         // temporary-16bit-accumulators, we have them cycle through v8--v15.
   1040         //
   1041         //
   1042         // Register layout (ignoring the v8--v15 temporary 16bit accumulators):
   1043         //
   1044         //                               +--------+--------+--------+--------+
   1045         //                               |v0.b[0] |v1.b[0] |v2.b[0] |v3.b[0] |
   1046         //                          Rhs  +--------+--------+--------+--------+
   1047         //                               |  ...   |  ...   |  ...   |  ...   |
   1048         //                               +--------+--------+--------+--------|
   1049         //                               |v0.b[15]|v1.b[15]|v2.b[15]|v3.b[15]|
   1050         //                               +--------+--------+--------+--------+
   1051         //
   1052         //                               |        |        |        |        |
   1053         //
   1054         //    Lhs                        |        |        |        |        |
   1055         //
   1056         //  +-------+-----+--------+ - - +--------+--------+--------+--------+
   1057         //  |v4.b[0]| ... |v4.b[15]|     | v16.4s | v17.4s | v18.4s | v19.4s |
   1058         //  |v5.b[0]| ... |v5.b[15]|     | v20.4s | v21.4s | v22.4s | v23.4s |
   1059         //  |v6.b[0]| ... |v6.b[15]|     | v24.4s | v25.4s | v26.4s | v27.4s |
   1060         //  |v7.b[0]| ... |v7.b[15]|     | v28.4s | v29.4s | v30.4s | v31.4s |
   1061         //  +-------+--------------+ - - +--------+--------+--------+--------+
   1062         //
   1063         //                                                Accumulator
   1064         //
   1065 
   1066         // Some multiplications and 16-bit accumulation were already done above,
   1067         // so we start right away in the middle.
   1068         "sadalp  v16.4s, v8.8h\n"
   1069         "ld1 {v4.16b}, [%[lhs_ptr]], #16\n"
   1070         "smull    v8.8h,  v0.8b,  v6.8b\n"
   1071         "sadalp  v17.4s, v9.8h\n"
   1072         "ld1 {v5.16b}, [%[lhs_ptr]], #16\n"
   1073         "smull    v9.8h,  v1.8b,  v6.8b\n"
   1074         "sadalp  v18.4s, v10.8h\n"
   1075         "smull    v10.8h,  v2.8b,  v6.8b\n"
   1076         "sadalp  v19.4s, v11.8h\n"
   1077         "smull    v11.8h,  v3.8b,  v6.8b\n"
   1078         "sadalp  v20.4s, v12.8h\n"
   1079         "smull    v12.8h,  v0.8b,  v7.8b\n"
   1080         "sadalp  v21.4s, v13.8h\n"
   1081         "smull    v13.8h,  v1.8b,  v7.8b\n"
   1082         "sadalp  v22.4s, v14.8h\n"
   1083         "smull    v14.8h,  v2.8b,  v7.8b\n"
   1084         "sadalp  v23.4s, v15.8h\n"
   1085         "smull    v15.8h,  v3.8b,  v7.8b\n"
   1086 
   1087         // Multiply-accumulate second-half, again into the same
   1088         // 16bit local accumulator registers. This is where we
   1089         // take advantage of having int8 instead of uint8 and therefore
   1090         // being able to accumulate two products into int16.
   1091         "smlal2   v8.8h,  v0.16b,  v6.16b\n"
   1092         "smlal2   v9.8h,  v1.16b,  v6.16b\n"
   1093         "smlal2   v10.8h,  v2.16b,  v6.16b\n"
   1094         "smlal2   v11.8h,  v3.16b,  v6.16b\n"
   1095 
   1096         "ld1 {v6.16b}, [%[lhs_ptr]], #16\n"
   1097 
   1098         "smlal2   v12.8h,  v0.16b,  v7.16b\n"
   1099         "ld1 {v0.16b}, [%[rhs_ptr]], #16\n"
   1100         "smlal2   v13.8h,  v1.16b,  v7.16b\n"
   1101         "ld1 {v1.16b}, [%[rhs_ptr]], #16\n"
   1102         "smlal2   v14.8h,  v2.16b,  v7.16b\n"
   1103         "ld1 {v2.16b}, [%[rhs_ptr]], #16\n"
   1104         "smlal2   v15.8h,  v3.16b,  v7.16b\n"
   1105         "ld1 {v3.16b}, [%[rhs_ptr]], #16\n"
   1106 
   1107         "sadalp  v24.4s, v8.8h\n"
   1108         "smull    v8.8h,  v0.8b,  v4.8b\n"
   1109         "sadalp  v25.4s, v9.8h\n"
   1110         "ld1 {v7.16b}, [%[lhs_ptr]], #16\n"
   1111         "smull    v9.8h,  v1.8b,  v4.8b\n"
   1112         "sadalp  v26.4s, v10.8h\n"
   1113         "smull    v10.8h,  v2.8b,  v4.8b\n"
   1114         "sadalp  v27.4s, v11.8h\n"
   1115         "smull    v11.8h,  v3.8b,  v4.8b\n"
   1116         "sadalp  v28.4s, v12.8h\n"
   1117         "smull    v12.8h,  v0.8b,  v5.8b\n"
   1118         "sadalp  v29.4s, v13.8h\n"
   1119         "smull    v13.8h,  v1.8b,  v5.8b\n"
   1120         "sadalp  v30.4s, v14.8h\n"
   1121         "smull    v14.8h,  v2.8b,  v5.8b\n"
   1122         "sadalp  v31.4s, v15.8h\n"
   1123         "smull    v15.8h,  v3.8b,  v5.8b\n"
   1124 
   1125         // Multiply-accumulate second-half, again into the same
   1126         // 16bit local accumulator registers. This is where we
   1127         // take advantage of having int8 instead of uint8 and therefore
   1128         // being able to accumulate two products into int16.
   1129         "smlal2   v8.8h,  v0.16b,  v4.16b\n"
   1130         "smlal2   v9.8h,  v1.16b,  v4.16b\n"
   1131         "smlal2   v10.8h,  v2.16b,  v4.16b\n"
   1132         "smlal2   v11.8h,  v3.16b,  v4.16b\n"
   1133 
   1134         // Loop. Decrement loop index (depth) by 16, since we just handled
   1135         // 16 levels of depth.  Do this subs a bit before the end of the loop
   1136         // for better dispatch on A57.
   1137         "subs %[run_depth], %[run_depth], #16\n"
   1138 
   1139         "smlal2   v12.8h,  v0.16b,  v5.16b\n"
   1140         "smlal2   v13.8h,  v1.16b,  v5.16b\n"
   1141         "smlal2   v14.8h,  v2.16b,  v5.16b\n"
   1142         "smlal2   v15.8h,  v3.16b,  v5.16b\n"
   1143 
   1144         "bne " GEMMLOWP_LABEL_LOOP "b\n"
   1145 
   1146         // Final code for the last 16 levels of depth.
   1147         // There is nothing to load anymore, only some arithmetic to finish.
   1148         GEMMLOWP_LABEL_AFTER_LOOP_LAST16
   1149         ":\n"
   1150 
   1151         // Some multiplications and 16-bit accumulation were already done above,
   1152         // so we start right away in the middle.
   1153         "sadalp  v16.4s, v8.8h\n"
   1154         "smull    v8.8h,  v0.8b,  v6.8b\n"
   1155         "sadalp  v17.4s, v9.8h\n"
   1156         "smull    v9.8h,  v1.8b,  v6.8b\n"
   1157         "sadalp  v18.4s, v10.8h\n"
   1158         "smull    v10.8h,  v2.8b,  v6.8b\n"
   1159         "sadalp  v19.4s, v11.8h\n"
   1160         "smull    v11.8h,  v3.8b,  v6.8b\n"
   1161         "sadalp  v20.4s, v12.8h\n"
   1162         "smull    v12.8h,  v0.8b,  v7.8b\n"
   1163         "sadalp  v21.4s, v13.8h\n"
   1164         "smull    v13.8h,  v1.8b,  v7.8b\n"
   1165         "sadalp  v22.4s, v14.8h\n"
   1166         "smull    v14.8h,  v2.8b,  v7.8b\n"
   1167         "sadalp  v23.4s, v15.8h\n"
   1168         "smull    v15.8h,  v3.8b,  v7.8b\n"
   1169 
   1170         // Multiply-accumulate second-half, again into the same
   1171         // 16bit local accumulator registers. This is where we
   1172         // take advantage of having int8 instead of uint8 and therefore
   1173         // being able to accumulate two products into int16.
   1174         "smlal2   v8.8h,  v0.16b,  v6.16b\n"
   1175         "smlal2   v9.8h,  v1.16b,  v6.16b\n"
   1176         "smlal2   v10.8h,  v2.16b,  v6.16b\n"
   1177         "smlal2   v11.8h,  v3.16b,  v6.16b\n"
   1178         "smlal2   v12.8h,  v0.16b,  v7.16b\n"
   1179         "smlal2   v13.8h,  v1.16b,  v7.16b\n"
   1180         "smlal2   v14.8h,  v2.16b,  v7.16b\n"
   1181         "smlal2   v15.8h,  v3.16b,  v7.16b\n"
   1182 
   1183         "sadalp  v24.4s, v8.8h\n"
   1184         "sadalp  v25.4s, v9.8h\n"
   1185         "sadalp  v26.4s, v10.8h\n"
   1186         "sadalp  v27.4s, v11.8h\n"
   1187         "sadalp  v28.4s, v12.8h\n"
   1188         "sadalp  v29.4s, v13.8h\n"
   1189         "sadalp  v30.4s, v14.8h\n"
   1190         "sadalp  v31.4s, v15.8h\n"
   1191 
   1192         // Reduce 32bit accumulators horizontally.
   1193         "addp v0.4s, v16.4s, v20.4s\n"
   1194         "addp v2.4s, v17.4s, v21.4s\n"
   1195         "addp v4.4s, v18.4s, v22.4s\n"
   1196         "addp v6.4s, v19.4s, v23.4s\n"
   1197         "addp v1.4s, v24.4s, v28.4s\n"
   1198         "addp v3.4s, v25.4s, v29.4s\n"
   1199         "addp v5.4s, v26.4s, v30.4s\n"
   1200         "addp v7.4s, v27.4s, v31.4s\n"
   1201 
   1202         "cmp %[start_depth], #0\n"
   1203         "bne " GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES
   1204         "f\n"
   1205 
   1206         // Reduce 32bit accumulators horizontally, second pass
   1207         // (each pass adds pairwise. we need to add 4-wise).
   1208         "addp v12.4s, v0.4s, v1.4s\n"
   1209         "addp v13.4s, v2.4s, v3.4s\n"
   1210         "addp v14.4s, v4.4s, v5.4s\n"
   1211         "addp v15.4s, v6.4s, v7.4s\n"
   1212 
   1213         "b " GEMMLOWP_LABEL_STORE "f\n"
   1214 
   1215         GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES
   1216         ":\n"
   1217 
   1218         // Reduce 32bit accumulators horizontally, second pass
   1219         // (each pass adds pairwise. we need to add 4-wise),
   1220         // and load destination values from memory.
   1221         "mov x0, %[dst_ptr]\n"
   1222         "ld1 {v12.16b}, [x0], %[dst_col_stride]\n"
   1223         "addp v8.4s, v0.4s, v1.4s\n"
   1224         "ld1 {v13.16b}, [x0], %[dst_col_stride]\n"
   1225         "addp v9.4s, v2.4s, v3.4s\n"
   1226         "ld1 {v14.16b}, [x0], %[dst_col_stride]\n"
   1227         "addp v10.4s, v4.4s, v5.4s\n"
   1228         "ld1 {v15.16b}, [x0]\n"
   1229         "addp v11.4s, v6.4s, v7.4s\n"
   1230 
   1231         // Add horizontally-reduced accumulators into
   1232         // the values loaded from memory
   1233         "add v12.4s, v12.4s, v8.4s\n"
   1234         "add v13.4s, v13.4s, v9.4s\n"
   1235         "add v14.4s, v14.4s, v10.4s\n"
   1236         "add v15.4s, v15.4s, v11.4s\n"
   1237 
   1238         GEMMLOWP_LABEL_STORE
   1239         ":\n"
   1240         // Store back into memory
   1241         "mov x0, %[dst_ptr]\n"
   1242         "st1 {v12.16b}, [x0], %[dst_col_stride]\n"
   1243         "st1 {v13.16b}, [x0], %[dst_col_stride]\n"
   1244         "st1 {v14.16b}, [x0], %[dst_col_stride]\n"
   1245         "st1 {v15.16b}, [x0]\n"
   1246         :  // outputs
   1247         [lhs_ptr] "+r"(lhs_ptr), [rhs_ptr] "+r"(rhs_ptr),
   1248         [dst_ptr] "+r"(dst_ptr), [run_depth] "+r"(run_depth),
   1249         [dst_col_stride] "+r"(dst_col_stride)
   1250         :  // inputs
   1251         [start_depth] "r"(start_depth)
   1252         :  // clobbers
   1253         "cc", "memory", "x0", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
   1254         "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17",
   1255         "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27",
   1256         "v28", "v29", "v30", "v31");
   1257 #undef GEMMLOWP_LABEL_LOOP
   1258 #undef GEMMLOWP_LABEL_AFTER_LOOP_LAST16
   1259 #undef GEMMLOWP_LABEL_ACCUMULATE_EXISTING_DST_VALUES
   1260 #undef GEMMLOWP_LABEL_STORE
   1261   }
   1262 };
   1263 
   1264 // Our main GEMM kernel.
   1265 struct NEON_64_Kernel12x8Depth2 : KernelBase {
   1266   typedef KernelFormat<KernelSideFormat<CellFormat<4, 2>, 3>,
   1267                        KernelSideFormat<CellFormat<4, 2>, 2> >
   1268       Format;
   1269 
   1270   const char* Name() const override { return "NEON, 12x8, depth 2"; }
   1271 
   1272   // TODO(benoitjacob): reorder function arguments so dst comes last
   1273   void Run(std::int32_t* dst_ptr, std::size_t dst_row_stride,
   1274            std::size_t dst_col_stride, const std::uint8_t* lhs_ptr,
   1275            const std::uint8_t* rhs_ptr, std::size_t start_depth,
   1276            std::size_t run_depth) const override {
   1277     ScopedProfilingLabel label("optimized kernel (NEON 12x8)");
   1278 // See comments above for why we need local numerical labels in our asm.
   1279 #define GEMMLOWP_LABEL_CLEAR_ACCUMULATORS "1"
   1280 #define GEMMLOWP_LABEL_BEFORE_LOOP "2"
   1281 #define GEMMLOWP_LABEL_LOOP "3"
   1282 #define GEMMLOWP_LABEL_AFTER_LOOP "4"
   1283 
   1284     assert(dst_row_stride == 1);
   1285     asm volatile(
   1286         // Load 1 Rhs cell of size 2x8
   1287         "ld1 {v5.8b}, [%[rhs_ptr]], #8\n"
   1288         "ld1 {v6.8b}, [%[rhs_ptr]], #8\n"
   1289 
   1290         // Load 3 Lhs cells of size 4x2 each
   1291         "ld1 {v2.8b}, [%[lhs_ptr]], #8\n"
   1292         "ld1 {v3.8b}, [%[lhs_ptr]], #8\n"
   1293         "ld1 {v4.8b}, [%[lhs_ptr]], #8\n"
   1294 
   1295         // Multiply dst_col_stride by 4 == sizeof(int32) to use
   1296         // it as a byte offset below.
   1297         "lsl %[dst_col_stride], %[dst_col_stride], #2\n"
   1298 
   1299         "cmp %[start_depth], #0\n"
   1300         "beq " GEMMLOWP_LABEL_CLEAR_ACCUMULATORS
   1301         "f\n"
   1302 
   1303         // Load accumulators
   1304         "mov x1, %[dst_ptr]\n"
   1305         "mov x0, x1\n"
   1306         "ld1 {v8.16b}, [x0], #16\n"
   1307         "subs %[run_depth], %[run_depth], #2\n"
   1308         "ld1 {v16.16b}, [x0], #16\n"
   1309         "add x1, x1, %[dst_col_stride]\n"
   1310         "ld1 {v24.16b}, [x0]\n"
   1311         "mov x0, x1\n"
   1312         "ld1 {v9.16b}, [x0], #16\n"
   1313         "add x1, x1, %[dst_col_stride]\n"
   1314         "ld1 {v17.16b}, [x0], #16\n"
   1315         "ld1 {v25.16b}, [x0]\n"
   1316         "mov x0, x1\n"
   1317         "ld1 {v10.16b}, [x0], #16\n"
   1318         "add x1, x1, %[dst_col_stride]\n"
   1319         "ld1 {v18.16b}, [x0], #16\n"
   1320         "ld1 {v26.16b}, [x0]\n"
   1321         "mov x0, x1\n"
   1322         "ld1 {v11.16b}, [x0], #16\n"
   1323         "add x1, x1, %[dst_col_stride]\n"
   1324         "ld1 {v19.16b}, [x0], #16\n"
   1325         "ld1 {v27.16b}, [x0]\n"
   1326         "mov x0, x1\n"
   1327         "ld1 {v12.16b}, [x0], #16\n"
   1328         "add x1, x1, %[dst_col_stride]\n"
   1329         "ld1 {v20.16b}, [x0], #16\n"
   1330         "ld1 {v28.16b}, [x0]\n"
   1331         "mov x0, x1\n"
   1332         "ld1 {v13.16b}, [x0], #16\n"
   1333         "add x1, x1, %[dst_col_stride]\n"
   1334         "ld1 {v21.16b}, [x0], #16\n"
   1335         "ld1 {v29.16b}, [x0]\n"
   1336         "mov x0, x1\n"
   1337         "ld1 {v14.16b}, [x0], #16\n"
   1338         "add x1, x1, %[dst_col_stride]\n"
   1339         "ld1 {v22.16b}, [x0], #16\n"
   1340         "ld1 {v30.16b}, [x0]\n"
   1341         "mov x0, x1\n"
   1342         "ld1 {v15.16b}, [x0], #16\n"
   1343         "ld1 {v23.16b}, [x0], #16\n"
   1344         "ld1 {v31.16b}, [x0]\n"
   1345 
   1346         "b " GEMMLOWP_LABEL_BEFORE_LOOP "f\n"
   1347 
   1348         GEMMLOWP_LABEL_CLEAR_ACCUMULATORS
   1349         ":\n"
   1350 
   1351         // Clear accumulator registers (see layout below)
   1352         "dup v8.4s, wzr\n"
   1353         "subs %[run_depth], %[run_depth], #2\n"
   1354         "dup v9.4s, wzr\n"
   1355         "dup v10.4s, wzr\n"
   1356         "dup v11.4s, wzr\n"
   1357         "dup v12.4s, wzr\n"
   1358         "dup v13.4s, wzr\n"
   1359         "dup v14.4s, wzr\n"
   1360         "dup v15.4s, wzr\n"
   1361         "dup v16.4s, wzr\n"
   1362         "dup v17.4s, wzr\n"
   1363         "dup v18.4s, wzr\n"
   1364         "dup v19.4s, wzr\n"
   1365         "dup v20.4s, wzr\n"
   1366         "dup v21.4s, wzr\n"
   1367         "dup v22.4s, wzr\n"
   1368         "dup v23.4s, wzr\n"
   1369         "dup v24.4s, wzr\n"
   1370         "dup v25.4s, wzr\n"
   1371         "dup v26.4s, wzr\n"
   1372         "dup v27.4s, wzr\n"
   1373         "dup v28.4s, wzr\n"
   1374         "dup v29.4s, wzr\n"
   1375         "dup v30.4s, wzr\n"
   1376         "dup v31.4s, wzr\n"
   1377 
   1378         GEMMLOWP_LABEL_BEFORE_LOOP
   1379         ":\n"
   1380 
   1381         "beq " GEMMLOWP_LABEL_AFTER_LOOP "f\n"
   1382 
   1383         GEMMLOWP_LABEL_LOOP
   1384         ":\n"
   1385 
   1386         // Overview of register layout:
   1387         //
   1388         // A 2x8 block of 2 2x4 cells of Rhs is stored in 16bit in v0--v1.
   1389         // A 12x2 block of 3 4x2 cells Lhs is stored in 16bit in v2--v4.
   1390         // A 12x8 block of accumulators is stored in 32bit in v8--v31.
   1391         //
   1392         //                         +--------+--------+-----+--------+--------+
   1393         //                         |v0.h[0] |v0.h[1] | ... |v1.h[2] |v1.h[3] |
   1394         //                    Rhs  +--------+--------+-----+--------+--------+
   1395         //                         |v0.h[4] |v0.h[5] | ... |v1.h[6] |v1.h[7] |
   1396         //                         +--------+--------+-----+--------+--------+
   1397         //
   1398         //                         |        |        |     |        |        |
   1399         //
   1400         //    Lhs                  |        |        |     |        |        |
   1401         //
   1402         //  +-------+-------+ - -  +--------+--------+-----+--------+--------+
   1403         //  |v2.h[0]|v2.h[4]|      |v8.s[0] |v9.s[0] | ... |v14.s[0]|v15.s[0]|
   1404         //  |v2.h[1]|v2.h[5]|      |v8.s[1] |v9.s[1] | ... |v14.s[1]|v15.s[1]|
   1405         //  |v2.h[2]|v2.h[6]|      |v8.s[2] |v9.s[2] | ... |v14.s[2]|v15.s[2]|
   1406         //  |v2.h[3]|v2.h[7]|      |v8.s[3] |v9.s[3] | ... |v14.s[3]|v15.s[3]|
   1407         //  +-------+-------+ - -  +--------+--------+-----+--------+--------+
   1408         //  |v3.h[0]|v3.h[4]|      |v16.s[0]|v17.s[0]| ... |v22.s[0]|v23.s[0]|
   1409         //  |v3.h[1]|v3.h[5]|      |v16.s[1]|v17.s[1]| ... |v22.s[1]|v23.s[1]|
   1410         //  |v3.h[2]|v3.h[6]|      |v16.s[2]|v17.s[2]| ... |v22.s[2]|v23.s[2]|
   1411         //  |v3.h[3]|v3.h[7]|      |v16.s[3]|v17.s[3]| ... |v22.s[3]|v23.s[3]|
   1412         //  +-------+-------+ - -  +--------+--------+-----+--------+--------+
   1413         //  |v4.h[0]|v4.h[4]|      |v24.s[0]|v25.s[0]| ... |v30.s[0]|v31.s[0]|
   1414         //  |v4.h[1]|v4.h[5]|      |v24.s[1]|v25.s[1]| ... |v30.s[1]|v31.s[1]|
   1415         //  |v4.h[2]|v4.h[6]|      |v24.s[2]|v25.s[2]| ... |v30.s[2]|v31.s[2]|
   1416         //  |v4.h[3]|v4.h[7]|      |v24.s[3]|v25.s[3]| ... |v30.s[3]|v31.s[3]|
   1417         //  +-------+-------+ - -  +--------+--------+-----+--------+--------+
   1418         //
   1419         //                            Accumulator
   1420 
   1421         // Expand Lhs/Rhs cells to 16 bit.
   1422         "uxtl v0.8h, v5.8b\n"
   1423         "ld1 {v5.8b}, [%[rhs_ptr]], #8\n"
   1424         "uxtl v1.8h, v6.8b\n"
   1425         "ld1 {v6.8b}, [%[rhs_ptr]], #8\n"
   1426         "uxtl v2.8h, v2.8b\n"
   1427         "uxtl v3.8h, v3.8b\n"
   1428         "uxtl v4.8h, v4.8b\n"
   1429 
   1430         // Multiply-accumulate, top third
   1431         "umlal v8.4s, v2.4h, v0.h[0]\n"
   1432         "umlal v9.4s, v2.4h, v0.h[1]\n"
   1433         "umlal v10.4s, v2.4h, v0.h[2]\n"
   1434         "umlal v11.4s, v2.4h, v0.h[3]\n"
   1435         "umlal v12.4s, v2.4h, v1.h[0]\n"
   1436         "umlal v13.4s, v2.4h, v1.h[1]\n"
   1437         "umlal v14.4s, v2.4h, v1.h[2]\n"
   1438         "umlal v15.4s, v2.4h, v1.h[3]\n"
   1439         "umlal2 v8.4s, v2.8h, v0.h[4]\n"
   1440         "umlal2 v9.4s, v2.8h, v0.h[5]\n"
   1441         "umlal2 v10.4s, v2.8h, v0.h[6]\n"
   1442         "umlal2 v11.4s, v2.8h, v0.h[7]\n"
   1443         "umlal2 v12.4s, v2.8h, v1.h[4]\n"
   1444         "umlal2 v13.4s, v2.8h, v1.h[5]\n"
   1445         "umlal2 v14.4s, v2.8h, v1.h[6]\n"
   1446         "umlal2 v15.4s, v2.8h, v1.h[7]\n"
   1447         "ld1 {v2.8b}, [%[lhs_ptr]], #8\n"
   1448 
   1449         // Multiply-accumulate, middle third
   1450         "umlal v16.4s, v3.4h, v0.h[0]\n"
   1451         "umlal v17.4s, v3.4h, v0.h[1]\n"
   1452         "umlal v18.4s, v3.4h, v0.h[2]\n"
   1453         "umlal v19.4s, v3.4h, v0.h[3]\n"
   1454         "umlal v20.4s, v3.4h, v1.h[0]\n"
   1455         "umlal v21.4s, v3.4h, v1.h[1]\n"
   1456         "umlal v22.4s, v3.4h, v1.h[2]\n"
   1457         "umlal v23.4s, v3.4h, v1.h[3]\n"
   1458         "umlal2 v16.4s, v3.8h, v0.h[4]\n"
   1459         "umlal2 v17.4s, v3.8h, v0.h[5]\n"
   1460         "umlal2 v18.4s, v3.8h, v0.h[6]\n"
   1461         "umlal2 v19.4s, v3.8h, v0.h[7]\n"
   1462         "umlal2 v20.4s, v3.8h, v1.h[4]\n"
   1463         "umlal2 v21.4s, v3.8h, v1.h[5]\n"
   1464         "umlal2 v22.4s, v3.8h, v1.h[6]\n"
   1465         "umlal2 v23.4s, v3.8h, v1.h[7]\n"
   1466         "ld1 {v3.8b}, [%[lhs_ptr]], #8\n"
   1467 
   1468         "subs %[run_depth], %[run_depth], #2\n"
   1469 
   1470         // Multiply-accumulate, bottom third
   1471         "umlal v24.4s, v4.4h, v0.h[0]\n"
   1472         "umlal v25.4s, v4.4h, v0.h[1]\n"
   1473         "umlal v26.4s, v4.4h, v0.h[2]\n"
   1474         "umlal v27.4s, v4.4h, v0.h[3]\n"
   1475         "umlal v28.4s, v4.4h, v1.h[0]\n"
   1476         "umlal v29.4s, v4.4h, v1.h[1]\n"
   1477         "umlal v30.4s, v4.4h, v1.h[2]\n"
   1478         "umlal v31.4s, v4.4h, v1.h[3]\n"
   1479         "umlal2 v24.4s, v4.8h, v0.h[4]\n"
   1480         "umlal2 v25.4s, v4.8h, v0.h[5]\n"
   1481         "umlal2 v26.4s, v4.8h, v0.h[6]\n"
   1482         "umlal2 v27.4s, v4.8h, v0.h[7]\n"
   1483         "umlal2 v28.4s, v4.8h, v1.h[4]\n"
   1484         "umlal2 v29.4s, v4.8h, v1.h[5]\n"
   1485         "umlal2 v30.4s, v4.8h, v1.h[6]\n"
   1486         "umlal2 v31.4s, v4.8h, v1.h[7]\n"
   1487         "ld1 {v4.8b}, [%[lhs_ptr]], #8\n"
   1488 
   1489         "bne " GEMMLOWP_LABEL_LOOP "b\n"
   1490 
   1491         GEMMLOWP_LABEL_AFTER_LOOP
   1492         ":\n"
   1493 
   1494         // Expand Lhs/Rhs cells to 16 bit.
   1495         "uxtl v0.8h, v5.8b\n"
   1496         "uxtl v1.8h, v6.8b\n"
   1497         "uxtl v2.8h, v2.8b\n"
   1498         "uxtl v3.8h, v3.8b\n"
   1499         "uxtl v4.8h, v4.8b\n"
   1500 
   1501         // Multiply-accumulate, level of depth 0
   1502         "umlal v8.4s, v2.4h, v0.h[0]\n"
   1503         "umlal v9.4s, v2.4h, v0.h[1]\n"
   1504         "umlal v10.4s, v2.4h, v0.h[2]\n"
   1505         "umlal v11.4s, v2.4h, v0.h[3]\n"
   1506         "umlal v12.4s, v2.4h, v1.h[0]\n"
   1507         "umlal v13.4s, v2.4h, v1.h[1]\n"
   1508         "umlal v14.4s, v2.4h, v1.h[2]\n"
   1509         "umlal v15.4s, v2.4h, v1.h[3]\n"
   1510         "umlal v16.4s, v3.4h, v0.h[0]\n"
   1511         "umlal v17.4s, v3.4h, v0.h[1]\n"
   1512         "umlal v18.4s, v3.4h, v0.h[2]\n"
   1513         "umlal v19.4s, v3.4h, v0.h[3]\n"
   1514         "umlal v20.4s, v3.4h, v1.h[0]\n"
   1515         "umlal v21.4s, v3.4h, v1.h[1]\n"
   1516         "umlal v22.4s, v3.4h, v1.h[2]\n"
   1517         "umlal v23.4s, v3.4h, v1.h[3]\n"
   1518         "umlal v24.4s, v4.4h, v0.h[0]\n"
   1519         "umlal v25.4s, v4.4h, v0.h[1]\n"
   1520         "umlal v26.4s, v4.4h, v0.h[2]\n"
   1521         "umlal v27.4s, v4.4h, v0.h[3]\n"
   1522         "umlal v28.4s, v4.4h, v1.h[0]\n"
   1523         "umlal v29.4s, v4.4h, v1.h[1]\n"
   1524         "umlal v30.4s, v4.4h, v1.h[2]\n"
   1525         "umlal v31.4s, v4.4h, v1.h[3]\n"
   1526 
   1527         // Multiply-accumulate, level of depth 1
   1528         "umlal2 v8.4s, v2.8h, v0.h[4]\n"
   1529         "umlal2 v9.4s, v2.8h, v0.h[5]\n"
   1530         "umlal2 v10.4s, v2.8h, v0.h[6]\n"
   1531         "umlal2 v11.4s, v2.8h, v0.h[7]\n"
   1532         "umlal2 v12.4s, v2.8h, v1.h[4]\n"
   1533         "umlal2 v13.4s, v2.8h, v1.h[5]\n"
   1534         "umlal2 v14.4s, v2.8h, v1.h[6]\n"
   1535         "umlal2 v15.4s, v2.8h, v1.h[7]\n"
   1536         "umlal2 v16.4s, v3.8h, v0.h[4]\n"
   1537         "umlal2 v17.4s, v3.8h, v0.h[5]\n"
   1538         "umlal2 v18.4s, v3.8h, v0.h[6]\n"
   1539         "umlal2 v19.4s, v3.8h, v0.h[7]\n"
   1540         "umlal2 v20.4s, v3.8h, v1.h[4]\n"
   1541         "umlal2 v21.4s, v3.8h, v1.h[5]\n"
   1542         "umlal2 v22.4s, v3.8h, v1.h[6]\n"
   1543         "umlal2 v23.4s, v3.8h, v1.h[7]\n"
   1544         "umlal2 v24.4s, v4.8h, v0.h[4]\n"
   1545         "umlal2 v25.4s, v4.8h, v0.h[5]\n"
   1546         "umlal2 v26.4s, v4.8h, v0.h[6]\n"
   1547         "umlal2 v27.4s, v4.8h, v0.h[7]\n"
   1548         "umlal2 v28.4s, v4.8h, v1.h[4]\n"
   1549         "umlal2 v29.4s, v4.8h, v1.h[5]\n"
   1550         "umlal2 v30.4s, v4.8h, v1.h[6]\n"
   1551         "umlal2 v31.4s, v4.8h, v1.h[7]\n"
   1552 
   1553         // Store accumulators
   1554         "mov x1, %[dst_ptr]\n"
   1555         "mov x0, x1\n"
   1556         "st1 {v8.16b}, [x0], #16\n"
   1557         "subs %[run_depth], %[run_depth], #2\n"
   1558         "st1 {v16.16b}, [x0], #16\n"
   1559         "add x1, x1, %[dst_col_stride]\n"
   1560         "st1 {v24.16b}, [x0]\n"
   1561         "mov x0, x1\n"
   1562         "st1 {v9.16b}, [x0], #16\n"
   1563         "add x1, x1, %[dst_col_stride]\n"
   1564         "st1 {v17.16b}, [x0], #16\n"
   1565         "st1 {v25.16b}, [x0]\n"
   1566         "mov x0, x1\n"
   1567         "st1 {v10.16b}, [x0], #16\n"
   1568         "add x1, x1, %[dst_col_stride]\n"
   1569         "st1 {v18.16b}, [x0], #16\n"
   1570         "st1 {v26.16b}, [x0]\n"
   1571         "mov x0, x1\n"
   1572         "st1 {v11.16b}, [x0], #16\n"
   1573         "add x1, x1, %[dst_col_stride]\n"
   1574         "st1 {v19.16b}, [x0], #16\n"
   1575         "st1 {v27.16b}, [x0]\n"
   1576         "mov x0, x1\n"
   1577         "st1 {v12.16b}, [x0], #16\n"
   1578         "add x1, x1, %[dst_col_stride]\n"
   1579         "st1 {v20.16b}, [x0], #16\n"
   1580         "st1 {v28.16b}, [x0]\n"
   1581         "mov x0, x1\n"
   1582         "st1 {v13.16b}, [x0], #16\n"
   1583         "add x1, x1, %[dst_col_stride]\n"
   1584         "st1 {v21.16b}, [x0], #16\n"
   1585         "st1 {v29.16b}, [x0]\n"
   1586         "mov x0, x1\n"
   1587         "st1 {v14.16b}, [x0], #16\n"
   1588         "add x1, x1, %[dst_col_stride]\n"
   1589         "st1 {v22.16b}, [x0], #16\n"
   1590         "st1 {v30.16b}, [x0]\n"
   1591         "mov x0, x1\n"
   1592         "st1 {v15.16b}, [x0], #16\n"
   1593         "st1 {v23.16b}, [x0], #16\n"
   1594         "st1 {v31.16b}, [x0]\n"
   1595 #undef GEMMLOWP_LABEL_CLEAR_ACCUMULATORS
   1596 #undef GEMMLOWP_LABEL_BEFORE_LOOP
   1597 #undef GEMMLOWP_LABEL_LOOP
   1598 #undef GEMMLOWP_LABEL_AFTER_LOOP
   1599         :  // outputs
   1600         [lhs_ptr] "+r"(lhs_ptr), [rhs_ptr] "+r"(rhs_ptr),
   1601         [dst_ptr] "+r"(dst_ptr),
   1602         [run_depth] "+r"(run_depth)
   1603         :  // inputs
   1604         [start_depth] "r"(start_depth),
   1605         [dst_col_stride] "r"(dst_col_stride)
   1606         :  // clobbers
   1607         "cc", "memory", "x0", "x1", "v0", "v1", "v2", "v3", "v4", "v5", "v6",
   1608         "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16",
   1609         "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26",
   1610         "v27", "v28", "v29", "v30", "v31");
   1611   }
   1612 };
   1613 
   1614 #endif  // GEMMLOWP_NEON_64
   1615 
   1616 }  // namespace gemmlowp
   1617 
   1618 #endif  // GEMMLOWP_INTERNAL_KERNEL_NEON_H_
   1619