Download src/layer/x86/convolution_packed_int8.h from camenduru/ncnn: direct link, hf CLI and curl.
- Browser
- Download file 296 kB
-
https://huggingface.co/camenduru/ncnn/resolve/main/src/layer/x86/convolution_packed_int8.h
- Command line
-
hf download hf://camenduru/ncnn/src/layer/x86/convolution_packed_int8.h
-
curl -L -o convolution_packed_int8.h https://huggingface.co/camenduru/ncnn/resolve/main/src/layer/x86/convolution_packed_int8.h
296 kB
| // Tencent is pleased to support the open source community by making ncnn available. | |
| // | |
| // Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. | |
| // | |
| // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except | |
| // in compliance with the License. You may obtain a copy of the License at | |
| // | |
| // https://opensource.org/licenses/BSD-3-Clause | |
| // | |
| // Unless required by applicable law or agreed to in writing, software distributed | |
| // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR | |
| // CONDITIONS OF ANY KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations under the License. | |
| void convolution_transform_kernel_packed_int8_avx2(const Mat& kernel, Mat& kernel_tm, int inch, int outch, int kernel_w, int kernel_h); | |
| void convolution_packed_int8_avx512vnni(const Mat& bottom_blob, Mat& top_blob, const Mat& weight_data_tm, int kernel_w, int kernel_h, int dilation_w, int dilation_h, int stride_w, int stride_h, const Option& opt); | |
| void convolution_packed_int8_avxvnni(const Mat& bottom_blob, Mat& top_blob, const Mat& weight_data_tm, int kernel_w, int kernel_h, int dilation_w, int dilation_h, int stride_w, int stride_h, const Option& opt); | |
| void convolution_packed_int8_avx2(const Mat& bottom_blob, Mat& top_blob, const Mat& weight_data_tm, int kernel_w, int kernel_h, int dilation_w, int dilation_h, int stride_w, int stride_h, const Option& opt); | |
| void convolution_packed_int8_xop(const Mat& bottom_blob, Mat& top_blob, const Mat& weight_data_tm, int kernel_w, int kernel_h, int dilation_w, int dilation_h, int stride_w, int stride_h, const Option& opt); | |
| static void convolution_transform_kernel_packed_int8(const Mat& kernel, Mat& kernel_tm, int inch, int outch, int kernel_w, int kernel_h) | |
| { | |
| if (ncnn::cpu_support_x86_avx2()) | |
| { | |
| convolution_transform_kernel_packed_int8_avx2(kernel, kernel_tm, inch, outch, kernel_w, kernel_h); | |
| return; | |
| } | |
| const int maxk = kernel_w * kernel_h; | |
| // src = kw-kh-inch-outch | |
| // dst = pb-pa-kw-kh-inch/pa-outch/pb | |
| // clang-format off | |
| // *INDENT-OFF* | |
| if (outch >= 16) | |
| { | |
| if (inch >= 16) | |
| kernel_tm.create(maxk, inch / 16 + (inch % 16) / 8 + (inch % 8) / 2 + inch % 2, outch / 16 + (outch % 16) / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)256u, 256); | |
| else if (inch >= 8) | |
| kernel_tm.create(maxk, inch / 8 + (inch % 8) / 2 + inch % 2, outch / 16 + (outch % 16) / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)128u, 128); | |
| else if (inch >= 2) | |
| kernel_tm.create(maxk, inch / 2 + inch % 2, outch / 16 + (outch % 16) / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)32u, 32); | |
| else | |
| kernel_tm.create(maxk, inch, outch / 16 + (outch % 16) / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)16u, 16); | |
| } | |
| else | |
| if (outch >= 8) | |
| { | |
| if (inch >= 16) | |
| kernel_tm.create(maxk, inch / 16 + (inch % 16) / 8 + (inch % 8) / 2 + inch % 2, outch / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)128u, 128); | |
| else | |
| if (inch >= 8) | |
| kernel_tm.create(maxk, inch / 8 + (inch % 8) / 2 + inch % 2, outch / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)64u, 64); | |
| else if (inch >= 2) | |
| kernel_tm.create(maxk, inch / 2 + inch % 2, outch / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)16u, 16); | |
| else | |
| kernel_tm.create(maxk, inch, outch / 8 + (outch % 8) / 4 + (outch % 4) / 2 + outch % 2, (size_t)8u, 8); | |
| } | |
| else | |
| if (outch >= 4) | |
| { | |
| if (inch >= 16) | |
| kernel_tm.create(maxk, inch / 16 + (inch % 16) / 8 + (inch % 8) / 2 + inch % 2, outch / 4 + (outch % 4) / 2 + outch % 2, (size_t)64u, 64); | |
| else | |
| if (inch >= 8) | |
| kernel_tm.create(maxk, inch / 8 + (inch % 8) / 2 + inch % 2, outch / 4 + (outch % 4) / 2 + outch % 2, (size_t)32u, 32); | |
| else if (inch >= 2) | |
| kernel_tm.create(maxk, inch / 2 + inch % 2, outch / 4 + (outch % 4) / 2 + outch % 2, (size_t)8u, 8); | |
| else | |
| kernel_tm.create(maxk, inch, outch / 4 + (outch % 4) / 2 + outch % 2, (size_t)4u, 4); | |
| } | |
| else | |
| if (outch >= 2) | |
| { | |
| if (inch >= 16) | |
| kernel_tm.create(maxk, inch / 16 + (inch % 16) / 8 + (inch % 8) / 2 + inch % 2, outch / 2 + outch % 2, (size_t)32u, 32); | |
| else | |
| if (inch >= 8) | |
| kernel_tm.create(maxk, inch / 8 + (inch % 8) / 2 + inch % 2, outch / 2 + outch % 2, (size_t)16u, 16); | |
| else | |
| if (inch >= 2) | |
| kernel_tm.create(maxk, inch / 2 + inch % 2, outch / 2 + outch % 2, (size_t)4u, 4); | |
| else | |
| kernel_tm.create(maxk, inch, outch / 2 + outch % 2, (size_t)2u, 2); | |
| } | |
| else | |
| { | |
| if (inch >= 16) | |
| kernel_tm.create(maxk, inch / 16 + (inch % 16) / 8 + (inch % 8) / 2 + inch % 2, outch, (size_t)16u, 16); | |
| else | |
| if (inch >= 8) | |
| kernel_tm.create(maxk, inch / 8 + (inch % 8) / 2 + inch % 2, outch, (size_t)8u, 8); | |
| else | |
| if (inch >= 2) | |
| kernel_tm.create(maxk, inch / 2 + inch % 2, outch, (size_t)2u, 2); | |
| else | |
| kernel_tm.create(maxk, inch, outch, (size_t)1u, 1); | |
| } | |
| // *INDENT-ON* | |
| // clang-format on | |
| int q = 0; | |
| for (; q + 15 < outch; q += 16) | |
| { | |
| const signed char* kptr0 = (const signed char*)kernel + q * inch * maxk; | |
| const signed char* kptr1 = (const signed char*)kernel + (q + 1) * inch * maxk; | |
| const signed char* kptr2 = (const signed char*)kernel + (q + 2) * inch * maxk; | |
| const signed char* kptr3 = (const signed char*)kernel + (q + 3) * inch * maxk; | |
| const signed char* kptr4 = (const signed char*)kernel + (q + 4) * inch * maxk; | |
| const signed char* kptr5 = (const signed char*)kernel + (q + 5) * inch * maxk; | |
| const signed char* kptr6 = (const signed char*)kernel + (q + 6) * inch * maxk; | |
| const signed char* kptr7 = (const signed char*)kernel + (q + 7) * inch * maxk; | |
| const signed char* kptr8 = (const signed char*)kernel + (q + 8) * inch * maxk; | |
| const signed char* kptr9 = (const signed char*)kernel + (q + 9) * inch * maxk; | |
| const signed char* kptra = (const signed char*)kernel + (q + 10) * inch * maxk; | |
| const signed char* kptrb = (const signed char*)kernel + (q + 11) * inch * maxk; | |
| const signed char* kptrc = (const signed char*)kernel + (q + 12) * inch * maxk; | |
| const signed char* kptrd = (const signed char*)kernel + (q + 13) * inch * maxk; | |
| const signed char* kptre = (const signed char*)kernel + (q + 14) * inch * maxk; | |
| const signed char* kptrf = (const signed char*)kernel + (q + 15) * inch * maxk; | |
| signed char* g00 = kernel_tm.channel(q / 16); | |
| int p = 0; | |
| for (; p + 15 < inch; p += 16) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(maxk)); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| __m128i _w1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr1 + k), sizeof(signed char))); | |
| __m128i _w2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr2 + k), sizeof(signed char))); | |
| __m128i _w3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr3 + k), sizeof(signed char))); | |
| __m128i _w4 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr4 + k), sizeof(signed char))); | |
| __m128i _w5 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr5 + k), sizeof(signed char))); | |
| __m128i _w6 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr6 + k), sizeof(signed char))); | |
| __m128i _w7 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr7 + k), sizeof(signed char))); | |
| __m128i _w8 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr8 + k), sizeof(signed char))); | |
| __m128i _w9 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr9 + k), sizeof(signed char))); | |
| __m128i _wa = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptra + k), sizeof(signed char))); | |
| __m128i _wb = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptrb + k), sizeof(signed char))); | |
| __m128i _wc = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptrc + k), sizeof(signed char))); | |
| __m128i _wd = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptrd + k), sizeof(signed char))); | |
| __m128i _we = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptre + k), sizeof(signed char))); | |
| __m128i _wf = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptrf + k), sizeof(signed char))); | |
| transpose8x16_epi16(_w0, _w1, _w2, _w3, _w4, _w5, _w6, _w7, _w8, _w9, _wa, _wb, _wc, _wd, _we, _wf); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| _mm_storeu_si128((__m128i*)(g00 + 16), _w1); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 2), _w2); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 3), _w3); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 4), _w4); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 5), _w5); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 6), _w6); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 7), _w7); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 8), _w8); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 9), _w9); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 10), _wa); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 11), _wb); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 12), _wc); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 13), _wd); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 14), _we); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 15), _wf); | |
| g00 += 256; | |
| } | |
| kptr0 += maxk * 16; | |
| kptr1 += maxk * 16; | |
| kptr2 += maxk * 16; | |
| kptr3 += maxk * 16; | |
| kptr4 += maxk * 16; | |
| kptr5 += maxk * 16; | |
| kptr6 += maxk * 16; | |
| kptr7 += maxk * 16; | |
| kptr8 += maxk * 16; | |
| kptr9 += maxk * 16; | |
| kptra += maxk * 16; | |
| kptrb += maxk * 16; | |
| kptrc += maxk * 16; | |
| kptrd += maxk * 16; | |
| kptre += maxk * 16; | |
| kptrf += maxk * 16; | |
| } | |
| for (; p + 7 < inch; p += 8) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(maxk)); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr0 + k), _vindex, sizeof(signed char))); | |
| __m128i _w1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr1 + k), _vindex, sizeof(signed char))); | |
| __m128i _w2 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr2 + k), _vindex, sizeof(signed char))); | |
| __m128i _w3 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr3 + k), _vindex, sizeof(signed char))); | |
| __m128i _w4 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr4 + k), _vindex, sizeof(signed char))); | |
| __m128i _w5 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr5 + k), _vindex, sizeof(signed char))); | |
| __m128i _w6 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr6 + k), _vindex, sizeof(signed char))); | |
| __m128i _w7 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr7 + k), _vindex, sizeof(signed char))); | |
| __m128i _w8 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr8 + k), _vindex, sizeof(signed char))); | |
| __m128i _w9 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr9 + k), _vindex, sizeof(signed char))); | |
| __m128i _wa = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptra + k), _vindex, sizeof(signed char))); | |
| __m128i _wb = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptrb + k), _vindex, sizeof(signed char))); | |
| __m128i _wc = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptrc + k), _vindex, sizeof(signed char))); | |
| __m128i _wd = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptrd + k), _vindex, sizeof(signed char))); | |
| __m128i _we = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptre + k), _vindex, sizeof(signed char))); | |
| __m128i _wf = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptrf + k), _vindex, sizeof(signed char))); | |
| __m128i _w08 = _mm_unpacklo_epi64(_w0, _w8); | |
| __m128i _w19 = _mm_unpacklo_epi64(_w1, _w9); | |
| __m128i _w2a = _mm_unpacklo_epi64(_w2, _wa); | |
| __m128i _w3b = _mm_unpacklo_epi64(_w3, _wb); | |
| __m128i _w4c = _mm_unpacklo_epi64(_w4, _wc); | |
| __m128i _w5d = _mm_unpacklo_epi64(_w5, _wd); | |
| __m128i _w6e = _mm_unpacklo_epi64(_w6, _we); | |
| __m128i _w7f = _mm_unpacklo_epi64(_w7, _wf); | |
| transpose8x8_epi16(_w08, _w19, _w2a, _w3b, _w4c, _w5d, _w6e, _w7f); | |
| _mm_storeu_si128((__m128i*)g00, _w08); | |
| _mm_storeu_si128((__m128i*)(g00 + 16), _w4c); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 2), _w19); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 3), _w5d); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 4), _w2a); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 5), _w6e); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 6), _w3b); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 7), _w7f); | |
| g00 += 128; | |
| } | |
| kptr0 += maxk * 8; | |
| kptr1 += maxk * 8; | |
| kptr2 += maxk * 8; | |
| kptr3 += maxk * 8; | |
| kptr4 += maxk * 8; | |
| kptr5 += maxk * 8; | |
| kptr6 += maxk * 8; | |
| kptr7 += maxk * 8; | |
| kptr8 += maxk * 8; | |
| kptr9 += maxk * 8; | |
| kptra += maxk * 8; | |
| kptrb += maxk * 8; | |
| kptrc += maxk * 8; | |
| kptrd += maxk * 8; | |
| kptre += maxk * 8; | |
| kptrf += maxk * 8; | |
| } | |
| for (; p + 1 < inch; p += 2) | |
| { | |
| __m128i _vindex0 = _mm_setr_epi32(0, maxk, inch * maxk, inch * maxk + maxk); | |
| __m128i _vindex1 = _mm_add_epi32(_vindex0, _mm_set1_epi32(inch * maxk * 2)); | |
| __m256i _vindex01 = _mm256_inserti128_si256(_mm256_castsi128_si256(_vindex0), _vindex1, 1); | |
| __m256i _vindex23 = _mm256_add_epi32(_vindex01, _mm256_set1_epi32(inch * maxk * 4)); | |
| __m512i _vindex = _mm512_inserti64x4(_mm512_castsi256_si512(_vindex01), _vindex23, 1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| __m128i _w1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr8 + k), sizeof(signed char))); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| _mm_storeu_si128((__m128i*)(g00 + 16), _w1); | |
| g00 += 32; | |
| } | |
| kptr0 += maxk * 2; | |
| kptr8 += maxk * 2; | |
| } | |
| for (; p < inch; p++) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(inch * maxk)); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| g00 += 16; | |
| } | |
| } | |
| } | |
| for (; q + 7 < outch; q += 8) | |
| { | |
| const signed char* kptr0 = (const signed char*)kernel + q * inch * maxk; | |
| const signed char* kptr1 = (const signed char*)kernel + (q + 1) * inch * maxk; | |
| const signed char* kptr2 = (const signed char*)kernel + (q + 2) * inch * maxk; | |
| const signed char* kptr3 = (const signed char*)kernel + (q + 3) * inch * maxk; | |
| const signed char* kptr4 = (const signed char*)kernel + (q + 4) * inch * maxk; | |
| const signed char* kptr5 = (const signed char*)kernel + (q + 5) * inch * maxk; | |
| const signed char* kptr6 = (const signed char*)kernel + (q + 6) * inch * maxk; | |
| const signed char* kptr7 = (const signed char*)kernel + (q + 7) * inch * maxk; | |
| signed char* g00 = kernel_tm.channel(q / 16 + (q % 16) / 8); | |
| signed char* g00 = kernel_tm.channel(q / 8); | |
| int p = 0; | |
| for (; p + 15 < inch; p += 16) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(maxk)); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| __m128i _w1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr1 + k), sizeof(signed char))); | |
| __m128i _w2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr2 + k), sizeof(signed char))); | |
| __m128i _w3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr3 + k), sizeof(signed char))); | |
| __m128i _w4 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr4 + k), sizeof(signed char))); | |
| __m128i _w5 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr5 + k), sizeof(signed char))); | |
| __m128i _w6 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr6 + k), sizeof(signed char))); | |
| __m128i _w7 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr7 + k), sizeof(signed char))); | |
| transpose8x8_epi16(_w0, _w1, _w2, _w3, _w4, _w5, _w6, _w7); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| _mm_storeu_si128((__m128i*)(g00 + 16), _w1); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 2), _w2); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 3), _w3); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 4), _w4); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 5), _w5); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 6), _w6); | |
| _mm_storeu_si128((__m128i*)(g00 + 16 * 7), _w7); | |
| g00 += 128; | |
| } | |
| kptr0 += maxk * 16; | |
| kptr1 += maxk * 16; | |
| kptr2 += maxk * 16; | |
| kptr3 += maxk * 16; | |
| kptr4 += maxk * 16; | |
| kptr5 += maxk * 16; | |
| kptr6 += maxk * 16; | |
| kptr7 += maxk * 16; | |
| } | |
| for (; p + 7 < inch; p += 8) | |
| { | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| const signed char* k2 = kptr2 + k; | |
| const signed char* k3 = kptr3 + k; | |
| const signed char* k4 = kptr4 + k; | |
| const signed char* k5 = kptr5 + k; | |
| const signed char* k6 = kptr6 + k; | |
| const signed char* k7 = kptr7 + k; | |
| for (int i = 0; i < 4; i++) | |
| { | |
| g00[0] = k0[0]; | |
| g00[1] = k0[maxk]; | |
| g00[2] = k1[0]; | |
| g00[3] = k1[maxk]; | |
| g00[4] = k2[0]; | |
| g00[5] = k2[maxk]; | |
| g00[6] = k3[0]; | |
| g00[7] = k3[maxk]; | |
| g00[8] = k4[0]; | |
| g00[9] = k4[maxk]; | |
| g00[10] = k5[0]; | |
| g00[11] = k5[maxk]; | |
| g00[12] = k6[0]; | |
| g00[13] = k6[maxk]; | |
| g00[14] = k7[0]; | |
| g00[15] = k7[maxk]; | |
| g00 += 16; | |
| k0 += maxk * 2; | |
| k1 += maxk * 2; | |
| k2 += maxk * 2; | |
| k3 += maxk * 2; | |
| k4 += maxk * 2; | |
| k5 += maxk * 2; | |
| k6 += maxk * 2; | |
| k7 += maxk * 2; | |
| } | |
| } | |
| kptr0 += maxk * 8; | |
| kptr1 += maxk * 8; | |
| kptr2 += maxk * 8; | |
| kptr3 += maxk * 8; | |
| kptr4 += maxk * 8; | |
| kptr5 += maxk * 8; | |
| kptr6 += maxk * 8; | |
| kptr7 += maxk * 8; | |
| } | |
| for (; p + 1 < inch; p += 2) | |
| { | |
| __m128i _vindex0 = _mm_setr_epi32(0, maxk, inch * maxk, inch * maxk + maxk); | |
| __m128i _vindex1 = _mm_add_epi32(_vindex0, _mm_set1_epi32(inch * maxk * 2)); | |
| __m256i _vindex01 = _mm256_inserti128_si256(_mm256_castsi128_si256(_vindex0), _vindex1, 1); | |
| __m256i _vindex23 = _mm256_add_epi32(_vindex01, _mm256_set1_epi32(inch * maxk * 4)); | |
| __m512i _vindex = _mm512_inserti64x4(_mm512_castsi256_si512(_vindex01), _vindex23, 1); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| __m256i _w01 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)(kptr0 + k), _vindex01, sizeof(signed char)), _sindex88); | |
| __m256i _w23 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)(kptr4 + k), _vindex01, sizeof(signed char)), _sindex88); | |
| __m128i _w01xx = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w01, 0), _mm256_extracti128_si256(_w01, 1)); | |
| __m128i _w23xx = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w23, 0), _mm256_extracti128_si256(_w23, 1)); | |
| __m128i _w0 = _mm_unpacklo_epi64(_w01xx, _w23xx); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| g00 += 16; | |
| } | |
| kptr0 += maxk * 2; | |
| kptr4 += maxk * 2; | |
| } | |
| for (; p < inch; p++) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(inch * maxk)); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m256i _w32 = _mm256_i32gather_epi32((const int*)(kptr0 + k), _vindex, sizeof(signed char)); | |
| __m128i _w0 = _mm256_cvtepi32_epi8(_w32); | |
| __m256i _w01 = _mm256_shuffle_epi8(_w32, _sindex88); | |
| __m128i _w0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w01, 0), _mm256_extracti128_si256(_w01, 1)); | |
| _mm_storel_epi64((__m128i*)g00, _w0); | |
| g00 += 8; | |
| } | |
| } | |
| } | |
| for (; q + 3 < outch; q += 4) | |
| { | |
| const signed char* kptr0 = (const signed char*)kernel + q * inch * maxk; | |
| const signed char* kptr1 = (const signed char*)kernel + (q + 1) * inch * maxk; | |
| const signed char* kptr2 = (const signed char*)kernel + (q + 2) * inch * maxk; | |
| const signed char* kptr3 = (const signed char*)kernel + (q + 3) * inch * maxk; | |
| signed char* g00 = kernel_tm.channel(q / 16 + (q % 16) / 8 + (q % 8) / 4); | |
| signed char* g00 = kernel_tm.channel(q / 8 + (q % 8) / 4); | |
| signed char* g00 = kernel_tm.channel(q / 4); | |
| int p = 0; | |
| for (; p + 15 < inch; p += 16) | |
| { | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| const signed char* k2 = kptr2 + k; | |
| const signed char* k3 = kptr3 + k; | |
| for (int i = 0; i < 8; i++) | |
| { | |
| g00[0] = k0[0]; | |
| g00[1] = k0[maxk]; | |
| g00[2] = k1[0]; | |
| g00[3] = k1[maxk]; | |
| g00[4] = k2[0]; | |
| g00[5] = k2[maxk]; | |
| g00[6] = k3[0]; | |
| g00[7] = k3[maxk]; | |
| g00 += 8; | |
| k0 += maxk * 2; | |
| k1 += maxk * 2; | |
| k2 += maxk * 2; | |
| k3 += maxk * 2; | |
| } | |
| } | |
| kptr0 += maxk * 16; | |
| kptr1 += maxk * 16; | |
| kptr2 += maxk * 16; | |
| kptr3 += maxk * 16; | |
| } | |
| for (; p + 7 < inch; p += 8) | |
| { | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| const signed char* k2 = kptr2 + k; | |
| const signed char* k3 = kptr3 + k; | |
| for (int i = 0; i < 4; i++) | |
| { | |
| g00[0] = k0[0]; | |
| g00[1] = k0[maxk]; | |
| g00[2] = k1[0]; | |
| g00[3] = k1[maxk]; | |
| g00[4] = k2[0]; | |
| g00[5] = k2[maxk]; | |
| g00[6] = k3[0]; | |
| g00[7] = k3[maxk]; | |
| g00 += 8; | |
| k0 += maxk * 2; | |
| k1 += maxk * 2; | |
| k2 += maxk * 2; | |
| k3 += maxk * 2; | |
| } | |
| } | |
| kptr0 += maxk * 8; | |
| kptr1 += maxk * 8; | |
| kptr2 += maxk * 8; | |
| kptr3 += maxk * 8; | |
| } | |
| for (; p + 1 < inch; p += 2) | |
| { | |
| __m128i _vindex0 = _mm_setr_epi32(0, maxk, inch * maxk, inch * maxk + maxk); | |
| __m128i _vindex1 = _mm_add_epi32(_vindex0, _mm_set1_epi32(inch * maxk * 2)); | |
| __m256i _vindex01 = _mm256_inserti128_si256(_mm256_castsi128_si256(_vindex0), _vindex1, 1); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr0 + k), _vindex01, sizeof(signed char))); | |
| _mm_storel_epi64((__m128i*)g00, _w0); | |
| __m256i _w01 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)(kptr0 + k), _vindex01, sizeof(signed char)), _sindex88); | |
| __m128i _w0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w01, 0), _mm256_extracti128_si256(_w01, 1)); | |
| _mm_storel_epi64((__m128i*)g00, _w0); | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| const signed char* k2 = kptr2 + k; | |
| const signed char* k3 = kptr3 + k; | |
| g00[0] = k0[0]; | |
| g00[1] = k0[maxk]; | |
| g00[2] = k1[0]; | |
| g00[3] = k1[maxk]; | |
| g00[4] = k2[0]; | |
| g00[5] = k2[maxk]; | |
| g00[6] = k3[0]; | |
| g00[7] = k3[maxk]; | |
| g00 += 8; | |
| } | |
| kptr0 += maxk * 2; | |
| kptr1 += maxk * 2; | |
| kptr2 += maxk * 2; | |
| kptr3 += maxk * 2; | |
| } | |
| for (; p < inch; p++) | |
| { | |
| __m128i _vindex = _mm_mullo_epi32(_mm_setr_epi32(0, 1, 2, 3), _mm_set1_epi32(inch * maxk)); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm_cvtepi32_epi8(_mm_i32gather_epi32((const int*)(kptr0 + k), _vindex, sizeof(signed char))); | |
| _mm_store_ss((float*)g00, _mm_castsi128_ps(_w0)); | |
| __m128i _w0 = _mm_shuffle_epi8(_mm_i32gather_epi32((const int*)(kptr0 + k), _vindex, sizeof(signed char)), _sindex8); | |
| _mm_store_ss((float*)g00, _mm_castsi128_ps(_w0)); | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| const signed char* k2 = kptr2 + k; | |
| const signed char* k3 = kptr3 + k; | |
| g00[0] = k0[0]; | |
| g00[1] = k1[0]; | |
| g00[2] = k2[0]; | |
| g00[3] = k3[0]; | |
| g00 += 4; | |
| } | |
| } | |
| } | |
| for (; q + 1 < outch; q += 2) | |
| { | |
| const signed char* kptr0 = (const signed char*)kernel + q * inch * maxk; | |
| const signed char* kptr1 = (const signed char*)kernel + (q + 1) * inch * maxk; | |
| signed char* g00 = kernel_tm.channel(q / 16 + (q % 16) / 8 + (q % 8) / 4 + (q % 4) / 2); | |
| signed char* g00 = kernel_tm.channel(q / 8 + (q % 8) / 4 + (q % 4) / 2); | |
| signed char* g00 = kernel_tm.channel(q / 4 + (q % 4) / 2); | |
| signed char* g00 = kernel_tm.channel(q / 2); | |
| int p = 0; | |
| for (; p + 15 < inch; p += 16) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(maxk)); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| __m128i _w1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr1 + k), sizeof(signed char))); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| _mm_storeu_si128((__m128i*)(g00 + 16), _w1); | |
| g00 += 32; | |
| } | |
| kptr0 += maxk * 16; | |
| kptr1 += maxk * 16; | |
| } | |
| for (; p + 7 < inch; p += 8) | |
| { | |
| __m256i _vindex0 = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex0 = _mm256_mullo_epi32(_vindex0, _mm256_set1_epi32(maxk)); | |
| __m256i _vindex1 = _mm256_add_epi32(_vindex0, _mm256_set1_epi32(inch * maxk)); | |
| __m512i _vindex = _mm512_inserti64x4(_mm512_castsi256_si512(_vindex0), _vindex1, 1); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr0 + k), sizeof(signed char))); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| __m256i _w00 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)(kptr0 + k), _vindex0, sizeof(signed char)), _sindex88); | |
| __m256i _w11 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)(kptr1 + k), _vindex0, sizeof(signed char)), _sindex88); | |
| __m128i _w0x = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w00, 0), _mm256_extracti128_si256(_w00, 1)); | |
| __m128i _w1x = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w11, 0), _mm256_extracti128_si256(_w11, 1)); | |
| __m128i _w0 = _mm_unpacklo_epi64(_w0x, _w1x); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| g00[0] = k0[0]; | |
| g00[1] = k0[maxk]; | |
| g00[2] = k0[maxk * 2]; | |
| g00[3] = k0[maxk * 3]; | |
| g00[4] = k0[maxk * 4]; | |
| g00[5] = k0[maxk * 5]; | |
| g00[6] = k0[maxk * 6]; | |
| g00[7] = k0[maxk * 7]; | |
| g00[8] = k1[0]; | |
| g00[9] = k1[maxk]; | |
| g00[10] = k1[maxk * 2]; | |
| g00[11] = k1[maxk * 3]; | |
| g00[12] = k1[maxk * 4]; | |
| g00[13] = k1[maxk * 5]; | |
| g00[14] = k1[maxk * 6]; | |
| g00[15] = k1[maxk * 7]; | |
| g00 += 16; | |
| } | |
| kptr0 += maxk * 8; | |
| kptr1 += maxk * 8; | |
| } | |
| for (; p + 1 < inch; p += 2) | |
| { | |
| __m128i _vindex = _mm_setr_epi32(0, inch * maxk, maxk, inch * maxk + maxk); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm_cvtepi32_epi8(_mm_i32gather_epi32((const int*)(kptr0 + k), _vindex, sizeof(signed char))); | |
| _mm_store_ss((float*)g00, _mm_castsi128_ps(_w0)); | |
| __m128i _w0 = _mm_shuffle_epi8(_mm_i32gather_epi32((const int*)(kptr0 + k), _vindex, sizeof(signed char)), _sindex8); | |
| _mm_store_ss((float*)g00, _mm_castsi128_ps(_w0)); | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| g00[0] = k0[0]; | |
| g00[1] = k1[0]; | |
| g00[2] = k0[maxk]; | |
| g00[3] = k1[maxk]; | |
| g00 += 4; | |
| } | |
| kptr0 += maxk * 2; | |
| kptr1 += maxk * 2; | |
| } | |
| for (; p < inch; p++) | |
| { | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* k0 = kptr0 + k; | |
| const signed char* k1 = kptr1 + k; | |
| g00[0] = k0[0]; | |
| g00[1] = k1[0]; | |
| g00 += 2; | |
| } | |
| } | |
| } | |
| for (; q < outch; q++) | |
| { | |
| const signed char* kptr = (const signed char*)kernel + q * inch * maxk; | |
| signed char* g00 = kernel_tm.channel(q / 16 + (q % 16) / 8 + (q % 8) / 4 + (q % 4) / 2 + q % 2); | |
| signed char* g00 = kernel_tm.channel(q / 8 + (q % 8) / 4 + (q % 4) / 2 + q % 2); | |
| signed char* g00 = kernel_tm.channel(q / 4 + (q % 4) / 2 + q % 2); | |
| signed char* g00 = kernel_tm.channel(q / 2 + q % 2); | |
| int p = 0; | |
| for (; p + 15 < inch; p += 16) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(maxk)); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(kptr + k), sizeof(signed char))); | |
| _mm_storeu_si128((__m128i*)g00, _w0); | |
| g00 += 16; | |
| } | |
| kptr += maxk * 16; | |
| } | |
| for (; p + 7 < inch; p += 8) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(maxk)); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| __m128i _w0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)(kptr + k), _vindex, sizeof(signed char))); | |
| _mm_storel_epi64((__m128i*)g00, _w0); | |
| g00 += 8; | |
| __m256i _w00 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)(kptr + k), _vindex, sizeof(signed char)), _sindex88); | |
| __m128i _w0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_w00, 0), _mm256_extracti128_si256(_w00, 1)); | |
| _mm_storel_epi64((__m128i*)g00, _w0); | |
| g00 += 8; | |
| const signed char* k0 = kptr + k; | |
| for (int i = 0; i < 8; i++) | |
| { | |
| g00[0] = k0[0]; | |
| k0 += maxk; | |
| g00 += 1; | |
| } | |
| } | |
| kptr += maxk * 8; | |
| } | |
| for (; p + 1 < inch; p += 2) | |
| { | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* k0 = kptr + k; | |
| g00[0] = k0[0]; | |
| g00[1] = k0[maxk]; | |
| g00 += 2; | |
| } | |
| kptr += maxk * 2; | |
| } | |
| for (; p < inch; p++) | |
| { | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* k0 = kptr + k; | |
| g00[0] = k0[0]; | |
| g00++; | |
| } | |
| } | |
| } | |
| } | |
| static void convolution_packed_int8(const Mat& bottom_blob, Mat& top_blob, const Mat& weight_data_tm, int kernel_w, int kernel_h, int dilation_w, int dilation_h, int stride_w, int stride_h, const Option& opt) | |
| { | |
| if (ncnn::cpu_support_x86_avx512_vnni()) | |
| { | |
| convolution_packed_int8_avx512vnni(bottom_blob, top_blob, weight_data_tm, kernel_w, kernel_h, dilation_w, dilation_h, stride_w, stride_h, opt); | |
| return; | |
| } | |
| if (ncnn::cpu_support_x86_avx_vnni()) | |
| { | |
| convolution_packed_int8_avxvnni(bottom_blob, top_blob, weight_data_tm, kernel_w, kernel_h, dilation_w, dilation_h, stride_w, stride_h, opt); | |
| return; | |
| } | |
| if (ncnn::cpu_support_x86_avx2()) | |
| { | |
| convolution_packed_int8_avx2(bottom_blob, top_blob, weight_data_tm, kernel_w, kernel_h, dilation_w, dilation_h, stride_w, stride_h, opt); | |
| return; | |
| } | |
| if (ncnn::cpu_support_x86_xop()) | |
| { | |
| convolution_packed_int8_xop(bottom_blob, top_blob, weight_data_tm, kernel_w, kernel_h, dilation_w, dilation_h, stride_w, stride_h, opt); | |
| return; | |
| } | |
| const int w = bottom_blob.w; | |
| const int elempack = bottom_blob.elempack; | |
| const int inch = bottom_blob.c * elempack; | |
| const int N = bottom_blob.cstep * elempack; | |
| const int outw = top_blob.w; | |
| const int outh = top_blob.h; | |
| const int out_elempack = top_blob.elempack; | |
| const int outch = top_blob.c * out_elempack; | |
| const int maxk = kernel_w * kernel_h; | |
| // kernel offsets | |
| std::vector<int> _space_ofs(maxk); | |
| int* space_ofs = &_space_ofs[0]; | |
| { | |
| int p1 = 0; | |
| int p2 = 0; | |
| int gap = w * dilation_h - kernel_w * dilation_w; | |
| for (int i = 0; i < kernel_h; i++) | |
| { | |
| for (int j = 0; j < kernel_w; j++) | |
| { | |
| space_ofs[p1] = p2 * elempack; | |
| p1++; | |
| p2 += dilation_w; | |
| } | |
| p2 += gap; | |
| } | |
| } | |
| int nn_outch = 0; | |
| int remain_outch_start = 0; | |
| nn_outch = outch / 16; | |
| for (int pp = 0; pp < nn_outch; pp++) | |
| { | |
| const int p = pp * 16; | |
| // shadowed variable for less openmp task args | |
| const int outw = top_blob.w; | |
| const int outh = top_blob.h; | |
| const int N = bottom_blob.cstep * elempack; | |
| const int M = top_blob.cstep * out_elempack; | |
| int* outptr = top_blob.channel(p / out_elempack); | |
| int ij = 0; | |
| for (; ij + 3 < outw * outh; ij += 4) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int i2 = (ij + 2) / outw; | |
| const int i3 = (ij + 3) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| const int j2 = (ij + 2) % outw; | |
| const int j3 = (ij + 3) % outw; | |
| __m512i _sum0 = _mm512_setzero_si512(); | |
| __m512i _sum1 = _mm512_setzero_si512(); | |
| __m512i _sum2 = _mm512_setzero_si512(); | |
| __m512i _sum3 = _mm512_setzero_si512(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8); | |
| int q = 0; | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| _r2 = _mm_load_si128((const __m128i*)r2s); | |
| _r3 = _mm_load_si128((const __m128i*)r3s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| __m128i _t4 = _mm_loadl_epi64((const __m128i*)r2s); | |
| __m128i _t5 = _mm_loadl_epi64((const __m128i*)(r2s + N)); | |
| __m128i _t6 = _mm_loadl_epi64((const __m128i*)r3s); | |
| __m128i _t7 = _mm_loadl_epi64((const __m128i*)(r3s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| _r2 = _mm_unpacklo_epi64(_t4, _t5); | |
| _r3 = _mm_unpacklo_epi64(_t6, _t7); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| _r2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r2s), sizeof(signed char))); | |
| _r3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r3s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _rr1 = _mm256_cvtepi8_epi16(_r1); | |
| __m256i _rr2 = _mm256_cvtepi8_epi16(_r2); | |
| __m256i _rr3 = _mm256_cvtepi8_epi16(_r3); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w45 = _mm512_load_si512((const __m512i*)(kptr + 128)); | |
| __m512i _w67 = _mm512_load_si512((const __m512i*)(kptr + 192)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| __m512i _w4 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w45, 0)); | |
| __m512i _w5 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w45, 1)); | |
| __m512i _w6 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w67, 0)); | |
| __m512i _w7 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w67, 1)); | |
| // 01234567 89abcdef -> 01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101 | |
| __m512i _rrrr00 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr0, 0)); | |
| __m512i _rrrr01 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr0, 1)); | |
| __m512i _rrrr10 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr1, 0)); | |
| __m512i _rrrr11 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr1, 1)); | |
| __m512i _rrrr20 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr2, 0)); | |
| __m512i _rrrr21 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr2, 1)); | |
| __m512i _rrrr30 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr3, 0)); | |
| __m512i _rrrr31 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr3, 1)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_AAAA), _w0); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_AAAA), _w0); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr20, _MM_PERM_AAAA), _w0); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr30, _MM_PERM_AAAA), _w0); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_BBBB), _w1); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_BBBB), _w1); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr20, _MM_PERM_BBBB), _w1); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr30, _MM_PERM_BBBB), _w1); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_CCCC), _w2); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_CCCC), _w2); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr20, _MM_PERM_CCCC), _w2); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr30, _MM_PERM_CCCC), _w2); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_DDDD), _w3); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_DDDD), _w3); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr20, _MM_PERM_DDDD), _w3); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr30, _MM_PERM_DDDD), _w3); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_AAAA), _w4); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_AAAA), _w4); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr21, _MM_PERM_AAAA), _w4); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr31, _MM_PERM_AAAA), _w4); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_BBBB), _w5); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_BBBB), _w5); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr21, _MM_PERM_BBBB), _w5); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr31, _MM_PERM_BBBB), _w5); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_CCCC), _w6); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_CCCC), _w6); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr21, _MM_PERM_CCCC), _w6); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr31, _MM_PERM_CCCC), _w6); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_DDDD), _w7); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_DDDD), _w7); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr21, _MM_PERM_DDDD), _w7); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr31, _MM_PERM_DDDD), _w7); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_AAAA), _w0)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_AAAA), _w0)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr20, _MM_PERM_AAAA), _w0)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr30, _MM_PERM_AAAA), _w0)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_BBBB), _w1)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_BBBB), _w1)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr20, _MM_PERM_BBBB), _w1)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr30, _MM_PERM_BBBB), _w1)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_CCCC), _w2)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_CCCC), _w2)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr20, _MM_PERM_CCCC), _w2)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr30, _MM_PERM_CCCC), _w2)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_DDDD), _w3)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_DDDD), _w3)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr20, _MM_PERM_DDDD), _w3)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr30, _MM_PERM_DDDD), _w3)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_AAAA), _w4)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_AAAA), _w4)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr21, _MM_PERM_AAAA), _w4)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr31, _MM_PERM_AAAA), _w4)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_BBBB), _w5)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_BBBB), _w5)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr21, _MM_PERM_BBBB), _w5)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr31, _MM_PERM_BBBB), _w5)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_CCCC), _w6)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_CCCC), _w6)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr21, _MM_PERM_CCCC), _w6)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr31, _MM_PERM_CCCC), _w6)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_DDDD), _w7)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_DDDD), _w7)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr21, _MM_PERM_DDDD), _w7)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr31, _MM_PERM_DDDD), _w7)); | |
| kptr += 256; | |
| } | |
| } | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| _r2 = _mm_loadl_epi64((const __m128i*)r2s); | |
| _r3 = _mm_loadl_epi64((const __m128i*)r3s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| _r2 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char))); | |
| _r3 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char))); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r2 = _mm_cvtepi8_epi16(_r2); | |
| _r3 = _mm_cvtepi8_epi16(_r3); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| // 01234567 -> 01010101 01010101 01010101 01010101 | |
| __m512i _rrrr0 = _mm512_broadcast_i32x4(_r0); | |
| __m512i _rrrr1 = _mm512_broadcast_i32x4(_r1); | |
| __m512i _rrrr2 = _mm512_broadcast_i32x4(_r2); | |
| __m512i _rrrr3 = _mm512_broadcast_i32x4(_r3); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_AAAA), _w0); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_AAAA), _w0); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr2, _MM_PERM_AAAA), _w0); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr3, _MM_PERM_AAAA), _w0); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_BBBB), _w1); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_BBBB), _w1); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr2, _MM_PERM_BBBB), _w1); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr3, _MM_PERM_BBBB), _w1); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_CCCC), _w2); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_CCCC), _w2); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr2, _MM_PERM_CCCC), _w2); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr3, _MM_PERM_CCCC), _w2); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_DDDD), _w3); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_DDDD), _w3); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr2, _MM_PERM_DDDD), _w3); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr3, _MM_PERM_DDDD), _w3); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_AAAA), _w0)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_AAAA), _w0)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr2, _MM_PERM_AAAA), _w0)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr3, _MM_PERM_AAAA), _w0)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_BBBB), _w1)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_BBBB), _w1)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr2, _MM_PERM_BBBB), _w1)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr3, _MM_PERM_BBBB), _w1)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_CCCC), _w2)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_CCCC), _w2)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr2, _MM_PERM_CCCC), _w2)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr3, _MM_PERM_CCCC), _w2)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_DDDD), _w3)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_DDDD), _w3)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr2, _MM_PERM_DDDD), _w3)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr3, _MM_PERM_DDDD), _w3)); | |
| kptr += 128; | |
| } | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m512i _r0 = _mm512_broadcastd_epi32(_mm_setr_epi16(r0s[0], r0s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _r1 = _mm512_broadcastd_epi32(_mm_setr_epi16(r1s[0], r1s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _r2 = _mm512_broadcastd_epi32(_mm_setr_epi16(r2s[0], r2s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _r3 = _mm512_broadcastd_epi32(_mm_setr_epi16(r3s[0], r3s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _w = _mm512_cvtepi8_epi16(_mm256_load_si256((const __m256i*)kptr)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _r1, _w); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _r2, _w); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _r3, _w); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_r0, _w)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_r1, _w)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_r2, _w)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_r3, _w)); | |
| kptr += 32; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m256i _r0 = _mm256_set1_epi16(r0s[0]); | |
| __m256i _r1 = _mm256_set1_epi16(r1s[0]); | |
| __m256i _r2 = _mm256_set1_epi16(r2s[0]); | |
| __m256i _r3 = _mm256_set1_epi16(r3s[0]); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_r0, _w))); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_r1, _w))); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_r2, _w))); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_r3, _w))); | |
| kptr += 16; | |
| } | |
| } | |
| } | |
| if (out_elempack == 16) | |
| { | |
| _mm512_store_si512((__m512i*)outptr, _sum0); | |
| _mm512_store_si512((__m512i*)(outptr + 16), _sum1); | |
| _mm512_store_si512((__m512i*)(outptr + 32), _sum2); | |
| _mm512_store_si512((__m512i*)(outptr + 48), _sum3); | |
| outptr += 64; | |
| } | |
| if (out_elempack == 8) | |
| { | |
| _mm256_store_si256((__m256i*)outptr, _mm512_extracti32x8_epi32(_sum0, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M), _mm512_extracti32x8_epi32(_sum0, 1)); | |
| _mm256_store_si256((__m256i*)(outptr + 8), _mm512_extracti32x8_epi32(_sum1, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M + 8), _mm512_extracti32x8_epi32(_sum1, 1)); | |
| _mm256_store_si256((__m256i*)(outptr + 16), _mm512_extracti32x8_epi32(_sum2, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M + 16), _mm512_extracti32x8_epi32(_sum2, 1)); | |
| _mm256_store_si256((__m256i*)(outptr + 24), _mm512_extracti32x8_epi32(_sum3, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M + 24), _mm512_extracti32x8_epi32(_sum3, 1)); | |
| outptr += 32; | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _mm512_extracti32x4_epi32(_sum0, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M), _mm512_extracti32x4_epi32(_sum0, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2), _mm512_extracti32x4_epi32(_sum0, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3), _mm512_extracti32x4_epi32(_sum0, 3)); | |
| _mm_store_si128((__m128i*)(outptr + 4), _mm512_extracti32x4_epi32(_sum1, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 4), _mm512_extracti32x4_epi32(_sum1, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2 + 4), _mm512_extracti32x4_epi32(_sum1, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3 + 4), _mm512_extracti32x4_epi32(_sum1, 3)); | |
| _mm_store_si128((__m128i*)(outptr + 8), _mm512_extracti32x4_epi32(_sum2, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 8), _mm512_extracti32x4_epi32(_sum2, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2 + 8), _mm512_extracti32x4_epi32(_sum2, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3 + 8), _mm512_extracti32x4_epi32(_sum2, 3)); | |
| _mm_store_si128((__m128i*)(outptr + 12), _mm512_extracti32x4_epi32(_sum3, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 12), _mm512_extracti32x4_epi32(_sum3, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2 + 12), _mm512_extracti32x4_epi32(_sum3, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3 + 12), _mm512_extracti32x4_epi32(_sum3, 3)); | |
| outptr += 16; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(M)); | |
| _mm512_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| _mm512_i32scatter_epi32(outptr + 1, _vindex, _sum1, sizeof(int)); | |
| _mm512_i32scatter_epi32(outptr + 2, _vindex, _sum2, sizeof(int)); | |
| _mm512_i32scatter_epi32(outptr + 3, _vindex, _sum3, sizeof(int)); | |
| outptr += 4; | |
| } | |
| } | |
| for (; ij + 1 < outw * outh; ij += 2) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| __m512i _sum0 = _mm512_setzero_si512(); | |
| __m512i _sum1 = _mm512_setzero_si512(); | |
| __m512i _sum2 = _mm512_setzero_si512(); | |
| __m512i _sum3 = _mm512_setzero_si512(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8); | |
| int q = 0; | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _rr1 = _mm256_cvtepi8_epi16(_r1); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w45 = _mm512_load_si512((const __m512i*)(kptr + 128)); | |
| __m512i _w67 = _mm512_load_si512((const __m512i*)(kptr + 192)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| __m512i _w4 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w45, 0)); | |
| __m512i _w5 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w45, 1)); | |
| __m512i _w6 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w67, 0)); | |
| __m512i _w7 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w67, 1)); | |
| // 01234567 89abcdef -> 01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101 | |
| __m512i _rrrr00 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr0, 0)); | |
| __m512i _rrrr01 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr0, 1)); | |
| __m512i _rrrr10 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr1, 0)); | |
| __m512i _rrrr11 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr1, 1)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_AAAA), _w0); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_AAAA), _w0); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_BBBB), _w1); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_BBBB), _w1); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_CCCC), _w2); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_CCCC), _w2); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_DDDD), _w3); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr10, _MM_PERM_DDDD), _w3); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_AAAA), _w4); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_AAAA), _w4); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_BBBB), _w5); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_BBBB), _w5); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_CCCC), _w6); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_CCCC), _w6); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_DDDD), _w7); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr11, _MM_PERM_DDDD), _w7); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_AAAA), _w0)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_AAAA), _w0)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_BBBB), _w1)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_BBBB), _w1)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_CCCC), _w2)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_CCCC), _w2)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_DDDD), _w3)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr10, _MM_PERM_DDDD), _w3)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_AAAA), _w4)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_AAAA), _w4)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_BBBB), _w5)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_BBBB), _w5)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_CCCC), _w6)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_CCCC), _w6)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_DDDD), _w7)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr11, _MM_PERM_DDDD), _w7)); | |
| kptr += 256; | |
| } | |
| } | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| // 01234567 -> 01010101 01010101 01010101 01010101 | |
| __m512i _rrrr0 = _mm512_broadcast_i32x4(_r0); | |
| __m512i _rrrr1 = _mm512_broadcast_i32x4(_r1); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_AAAA), _w0); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_AAAA), _w0); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_BBBB), _w1); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_BBBB), _w1); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_CCCC), _w2); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_CCCC), _w2); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_DDDD), _w3); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr1, _MM_PERM_DDDD), _w3); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_AAAA), _w0)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_AAAA), _w0)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_BBBB), _w1)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_BBBB), _w1)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_CCCC), _w2)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_CCCC), _w2)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_DDDD), _w3)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr1, _MM_PERM_DDDD), _w3)); | |
| kptr += 128; | |
| } | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m512i _r0 = _mm512_broadcastd_epi32(_mm_setr_epi16(r0s[0], r0s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _r1 = _mm512_broadcastd_epi32(_mm_setr_epi16(r1s[0], r1s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _w = _mm512_cvtepi8_epi16(_mm256_load_si256((const __m256i*)kptr)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _r1, _w); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_r0, _w)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_r1, _w)); | |
| kptr += 32; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m256i _r0 = _mm256_set1_epi16(r0s[0]); | |
| __m256i _r1 = _mm256_set1_epi16(r1s[0]); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_r0, _w))); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_r1, _w))); | |
| kptr += 16; | |
| } | |
| } | |
| } | |
| _sum0 = _mm512_add_epi32(_sum0, _sum2); | |
| _sum1 = _mm512_add_epi32(_sum1, _sum3); | |
| if (out_elempack == 16) | |
| { | |
| _mm512_store_si512((__m512i*)outptr, _sum0); | |
| _mm512_store_si512((__m512i*)(outptr + 16), _sum1); | |
| outptr += 32; | |
| } | |
| if (out_elempack == 8) | |
| { | |
| _mm256_store_si256((__m256i*)outptr, _mm512_extracti32x8_epi32(_sum0, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M), _mm512_extracti32x8_epi32(_sum0, 1)); | |
| _mm256_store_si256((__m256i*)(outptr + 8), _mm512_extracti32x8_epi32(_sum1, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M + 8), _mm512_extracti32x8_epi32(_sum1, 1)); | |
| outptr += 16; | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _mm512_extracti32x4_epi32(_sum0, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M), _mm512_extracti32x4_epi32(_sum0, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2), _mm512_extracti32x4_epi32(_sum0, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3), _mm512_extracti32x4_epi32(_sum0, 3)); | |
| _mm_store_si128((__m128i*)(outptr + 4), _mm512_extracti32x4_epi32(_sum1, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 4), _mm512_extracti32x4_epi32(_sum1, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2 + 4), _mm512_extracti32x4_epi32(_sum1, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3 + 4), _mm512_extracti32x4_epi32(_sum1, 3)); | |
| outptr += 8; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(M)); | |
| _mm512_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| _mm512_i32scatter_epi32(outptr + 1, _vindex, _sum1, sizeof(int)); | |
| outptr += 2; | |
| } | |
| } | |
| for (; ij < outw * outh; ij++) | |
| { | |
| const int i = ij / outw; | |
| const int j = ij % outw; | |
| __m512i _sum0 = _mm512_setzero_si512(); | |
| __m512i _sum1 = _mm512_setzero_si512(); | |
| __m512i _sum2 = _mm512_setzero_si512(); | |
| __m512i _sum3 = _mm512_setzero_si512(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8); | |
| int q = 0; | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w45 = _mm512_load_si512((const __m512i*)(kptr + 128)); | |
| __m512i _w67 = _mm512_load_si512((const __m512i*)(kptr + 192)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| __m512i _w4 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w45, 0)); | |
| __m512i _w5 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w45, 1)); | |
| __m512i _w6 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w67, 0)); | |
| __m512i _w7 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w67, 1)); | |
| // 01234567 89abcdef -> 01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101 | |
| __m512i _rrrr00 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr0, 0)); | |
| __m512i _rrrr01 = _mm512_broadcast_i32x4(_mm256_extracti128_si256(_rr0, 1)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_AAAA), _w0); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_BBBB), _w1); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_CCCC), _w2); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr00, _MM_PERM_DDDD), _w3); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_AAAA), _w4); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_BBBB), _w5); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_CCCC), _w6); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr01, _MM_PERM_DDDD), _w7); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_AAAA), _w0)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_BBBB), _w1)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_CCCC), _w2)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr00, _MM_PERM_DDDD), _w3)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_AAAA), _w4)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_BBBB), _w5)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_CCCC), _w6)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr01, _MM_PERM_DDDD), _w7)); | |
| kptr += 256; | |
| } | |
| } | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| // 01234567 -> 01010101 01010101 01010101 01010101 | |
| __m512i _rrrr0 = _mm512_broadcast_i32x4(_r0); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_AAAA), _w0); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_BBBB), _w1); | |
| _sum2 = _mm512_dpwssd_epi32(_sum2, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_CCCC), _w2); | |
| _sum3 = _mm512_dpwssd_epi32(_sum3, _mm512_shuffle_epi32(_rrrr0, _MM_PERM_DDDD), _w3); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_AAAA), _w0)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_BBBB), _w1)); | |
| _sum2 = _mm512_add_epi32(_sum2, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_CCCC), _w2)); | |
| _sum3 = _mm512_add_epi32(_sum3, _mm512_madd_epi16(_mm512_shuffle_epi32(_rrrr0, _MM_PERM_DDDD), _w3)); | |
| kptr += 128; | |
| } | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m512i _val = _mm512_broadcastd_epi32(_mm_setr_epi16(r0s[0], r0s[N], 0, 0, 0, 0, 0, 0)); | |
| __m512i _w = _mm512_cvtepi8_epi16(_mm256_load_si256((const __m256i*)kptr)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _val, _w); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_val, _w)); | |
| kptr += 32; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m256i _val = _mm256_set1_epi16(r0s[0]); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_cvtepi16_epi32(_mm256_mullo_epi16(_val, _w))); | |
| kptr += 16; | |
| } | |
| } | |
| } | |
| _sum0 = _mm512_add_epi32(_sum0, _sum1); | |
| _sum2 = _mm512_add_epi32(_sum2, _sum3); | |
| _sum0 = _mm512_add_epi32(_sum0, _sum2); | |
| if (out_elempack == 16) | |
| { | |
| _mm512_store_si512((__m512i*)outptr, _sum0); | |
| outptr += 16; | |
| } | |
| if (out_elempack == 8) | |
| { | |
| _mm256_store_si256((__m256i*)outptr, _mm512_extracti32x8_epi32(_sum0, 0)); | |
| _mm256_store_si256((__m256i*)(outptr + M), _mm512_extracti32x8_epi32(_sum0, 1)); | |
| outptr += 8; | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _mm512_extracti32x4_epi32(_sum0, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M), _mm512_extracti32x4_epi32(_sum0, 1)); | |
| _mm_store_si128((__m128i*)(outptr + M * 2), _mm512_extracti32x4_epi32(_sum0, 2)); | |
| _mm_store_si128((__m128i*)(outptr + M * 3), _mm512_extracti32x4_epi32(_sum0, 3)); | |
| outptr += 4; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(M)); | |
| _mm512_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| outptr += 1; | |
| } | |
| } | |
| } | |
| remain_outch_start += nn_outch * 16; | |
| nn_outch = (outch - remain_outch_start) / 8; | |
| nn_outch = (outch - remain_outch_start) / 8; | |
| for (int pp = 0; pp < nn_outch; pp++) | |
| { | |
| const int p = remain_outch_start + pp * 8; | |
| // shadowed variable for less openmp task args | |
| const int outw = top_blob.w; | |
| const int outh = top_blob.h; | |
| const int N = bottom_blob.cstep * elempack; | |
| const int M = top_blob.cstep * out_elempack; | |
| int* outptr = top_blob.channel(p / out_elempack); | |
| int ij = 0; | |
| for (; ij + 3 < outw * outh; ij += 4) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int i2 = (ij + 2) / outw; | |
| const int i3 = (ij + 3) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| const int j2 = (ij + 2) % outw; | |
| const int j3 = (ij + 3) % outw; | |
| __m256i _sum0 = _mm256_setzero_si256(); | |
| __m256i _sum1 = _mm256_setzero_si256(); | |
| __m256i _sum2 = _mm256_setzero_si256(); | |
| __m256i _sum3 = _mm256_setzero_si256(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8); | |
| const signed char* kptr = weight_data_tm.channel(p / 8); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| __m512i _sum22 = _mm512_setzero_si512(); | |
| __m512i _sum33 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| _r2 = _mm_load_si128((const __m128i*)r2s); | |
| _r3 = _mm_load_si128((const __m128i*)r3s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| __m128i _t4 = _mm_loadl_epi64((const __m128i*)r2s); | |
| __m128i _t5 = _mm_loadl_epi64((const __m128i*)(r2s + N)); | |
| __m128i _t6 = _mm_loadl_epi64((const __m128i*)r3s); | |
| __m128i _t7 = _mm_loadl_epi64((const __m128i*)(r3s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| _r2 = _mm_unpacklo_epi64(_t4, _t5); | |
| _r3 = _mm_unpacklo_epi64(_t6, _t7); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| _r2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r2s), sizeof(signed char))); | |
| _r3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r3s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _rr1 = _mm256_cvtepi8_epi16(_r1); | |
| __m256i _rr2 = _mm256_cvtepi8_epi16(_r2); | |
| __m256i _rr3 = _mm256_cvtepi8_epi16(_r3); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| // 01234567 89abcdef -> 01010101 01010101 23232323 23232323 | |
| __m512i _rrr0 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr0), _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr1 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr1), _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr2 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr2), _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr3 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr3), _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| _rrr0 = _mm512_unpacklo_epi32(_rrr0, _rrr0); | |
| _rrr1 = _mm512_unpacklo_epi32(_rrr1, _rrr1); | |
| _rrr2 = _mm512_unpacklo_epi32(_rrr2, _rrr2); | |
| _rrr3 = _mm512_unpacklo_epi32(_rrr3, _rrr3); | |
| __m512i _rrr0l = _mm512_unpacklo_epi64(_rrr0, _rrr0); | |
| __m512i _rrr0h = _mm512_unpackhi_epi64(_rrr0, _rrr0); | |
| __m512i _rrr1l = _mm512_unpacklo_epi64(_rrr1, _rrr1); | |
| __m512i _rrr1h = _mm512_unpackhi_epi64(_rrr1, _rrr1); | |
| __m512i _rrr2l = _mm512_unpacklo_epi64(_rrr2, _rrr2); | |
| __m512i _rrr2h = _mm512_unpackhi_epi64(_rrr2, _rrr2); | |
| __m512i _rrr3l = _mm512_unpacklo_epi64(_rrr3, _rrr3); | |
| __m512i _rrr3h = _mm512_unpackhi_epi64(_rrr3, _rrr3); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 128; | |
| } | |
| } | |
| _sum0 = _mm256_add_epi32(_sum0, _mm512_extracti64x4_epi64(_sum00, 0)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm512_extracti64x4_epi64(_sum00, 1)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm512_extracti64x4_epi64(_sum11, 0)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm512_extracti64x4_epi64(_sum11, 1)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm512_extracti64x4_epi64(_sum22, 0)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm512_extracti64x4_epi64(_sum22, 1)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm512_extracti64x4_epi64(_sum33, 0)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm512_extracti64x4_epi64(_sum33, 1)); | |
| } | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| _r2 = _mm_loadl_epi64((const __m128i*)r2s); | |
| _r3 = _mm_loadl_epi64((const __m128i*)r3s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| _r2 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char))); | |
| _r3 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val2_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val3_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r2 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val2_32, 0), _mm256_extracti128_si256(_val2_32, 1)); | |
| _r3 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val3_32, 0), _mm256_extracti128_si256(_val3_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r2 = _mm_setr_epi8(r2s[0], r2s[N], r2s[N * 2], r2s[N * 3], r2s[N * 4], r2s[N * 5], r2s[N * 6], r2s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r3 = _mm_setr_epi8(r3s[0], r3s[N], r3s[N * 2], r3s[N * 3], r3s[N * 4], r3s[N * 5], r3s[N * 6], r3s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r2 = _mm_cvtepi8_epi16(_r2); | |
| _r3 = _mm_cvtepi8_epi16(_r3); | |
| __m256i _w01 = _mm256_load_si256((const __m256i*)kptr); | |
| __m256i _w23 = _mm256_load_si256((const __m256i*)(kptr + 32)); | |
| __m256i _w0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w01, 0)); | |
| __m256i _w1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w01, 1)); | |
| __m256i _w2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w23, 0)); | |
| __m256i _w3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w23, 1)); | |
| // 01234567 -> 01010101 01010101 | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _r0, 1); | |
| __m256i _rr1 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r1), _r1, 1); | |
| __m256i _rr2 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r2), _r2, 1); | |
| __m256i _rr3 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r3), _r3, 1); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 64; | |
| } | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_setr_epi16(r0s[0], r0s[N], 0, 0, 0, 0, 0, 0); | |
| __m128i _r1 = _mm_setr_epi16(r1s[0], r1s[N], 0, 0, 0, 0, 0, 0); | |
| __m128i _r2 = _mm_setr_epi16(r2s[0], r2s[N], 0, 0, 0, 0, 0, 0); | |
| __m128i _r3 = _mm_setr_epi16(r3s[0], r3s[N], 0, 0, 0, 0, 0, 0); | |
| __m256i _rr0 = _mm256_broadcastd_epi32(_r0); | |
| __m256i _rr1 = _mm256_broadcastd_epi32(_r1); | |
| __m256i _rr2 = _mm256_broadcastd_epi32(_r2); | |
| __m256i _rr3 = _mm256_broadcastd_epi32(_r3); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _rr0, _w); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _rr1, _w); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _rr2, _w); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _rr3, _w); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_rr0, _w)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_rr1, _w)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_rr2, _w)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_rr3, _w)); | |
| kptr += 16; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_set1_epi16(r0s[0]); | |
| __m128i _r1 = _mm_set1_epi16(r1s[0]); | |
| __m128i _r2 = _mm_set1_epi16(r2s[0]); | |
| __m128i _r3 = _mm_set1_epi16(r3s[0]); | |
| __m128i _w = _mm_cvtepi8_epi16(_mm_loadl_epi64((const __m128i*)kptr)); | |
| __m256i _s0 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_r0, _w)); | |
| __m256i _s1 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_r1, _w)); | |
| __m256i _s2 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_r2, _w)); | |
| __m256i _s3 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_r3, _w)); | |
| _sum0 = _mm256_add_epi32(_sum0, _s0); | |
| _sum1 = _mm256_add_epi32(_sum1, _s1); | |
| _sum2 = _mm256_add_epi32(_sum2, _s2); | |
| _sum3 = _mm256_add_epi32(_sum3, _s3); | |
| kptr += 8; | |
| } | |
| } | |
| } | |
| if (out_elempack == 8) | |
| { | |
| _mm256_store_si256((__m256i*)outptr, _sum0); | |
| _mm256_store_si256((__m256i*)(outptr + 8), _sum1); | |
| _mm256_store_si256((__m256i*)(outptr + 16), _sum2); | |
| _mm256_store_si256((__m256i*)(outptr + 24), _sum3); | |
| outptr += 32; | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _mm256_extracti128_si256(_sum0, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M), _mm256_extracti128_si256(_sum0, 1)); | |
| _mm_store_si128((__m128i*)(outptr + 4), _mm256_extracti128_si256(_sum1, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 4), _mm256_extracti128_si256(_sum1, 1)); | |
| _mm_store_si128((__m128i*)(outptr + 8), _mm256_extracti128_si256(_sum2, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 8), _mm256_extracti128_si256(_sum2, 1)); | |
| _mm_store_si128((__m128i*)(outptr + 12), _mm256_extracti128_si256(_sum3, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 12), _mm256_extracti128_si256(_sum3, 1)); | |
| outptr += 16; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(M)); | |
| _mm256_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| _mm256_i32scatter_epi32(outptr + 1, _vindex, _sum1, sizeof(int)); | |
| _mm256_i32scatter_epi32(outptr + 2, _vindex, _sum2, sizeof(int)); | |
| _mm256_i32scatter_epi32(outptr + 3, _vindex, _sum3, sizeof(int)); | |
| int sum0[8]; | |
| int sum1[8]; | |
| int sum2[8]; | |
| int sum3[8]; | |
| _mm256_storeu_si256((__m256i*)sum0, _sum0); | |
| _mm256_storeu_si256((__m256i*)sum1, _sum1); | |
| _mm256_storeu_si256((__m256i*)sum2, _sum2); | |
| _mm256_storeu_si256((__m256i*)sum3, _sum3); | |
| outptr[0] = sum0[0]; | |
| outptr[1] = sum1[0]; | |
| outptr[2] = sum2[0]; | |
| outptr[3] = sum3[0]; | |
| outptr[M] = sum0[1]; | |
| outptr[M + 1] = sum1[1]; | |
| outptr[M + 2] = sum2[1]; | |
| outptr[M + 3] = sum3[1]; | |
| outptr[M * 2] = sum0[2]; | |
| outptr[M * 2 + 1] = sum1[2]; | |
| outptr[M * 2 + 2] = sum2[2]; | |
| outptr[M * 2 + 3] = sum3[2]; | |
| outptr[M * 3] = sum0[3]; | |
| outptr[M * 3 + 1] = sum1[3]; | |
| outptr[M * 3 + 2] = sum2[3]; | |
| outptr[M * 3 + 3] = sum3[3]; | |
| outptr[M * 4] = sum0[4]; | |
| outptr[M * 4 + 1] = sum1[4]; | |
| outptr[M * 4 + 2] = sum2[4]; | |
| outptr[M * 4 + 3] = sum3[4]; | |
| outptr[M * 5] = sum0[5]; | |
| outptr[M * 5 + 1] = sum1[5]; | |
| outptr[M * 5 + 2] = sum2[5]; | |
| outptr[M * 5 + 3] = sum3[5]; | |
| outptr[M * 6] = sum0[6]; | |
| outptr[M * 6 + 1] = sum1[6]; | |
| outptr[M * 6 + 2] = sum2[6]; | |
| outptr[M * 6 + 3] = sum3[6]; | |
| outptr[M * 7] = sum0[7]; | |
| outptr[M * 7 + 1] = sum1[7]; | |
| outptr[M * 7 + 2] = sum2[7]; | |
| outptr[M * 7 + 3] = sum3[7]; | |
| outptr += 4; | |
| } | |
| } | |
| for (; ij + 1 < outw * outh; ij += 2) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| __m256i _sum0 = _mm256_setzero_si256(); | |
| __m256i _sum1 = _mm256_setzero_si256(); | |
| __m256i _sum2 = _mm256_setzero_si256(); | |
| __m256i _sum3 = _mm256_setzero_si256(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8); | |
| const signed char* kptr = weight_data_tm.channel(p / 8); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| __m512i _sum22 = _mm512_setzero_si512(); | |
| __m512i _sum33 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _rr1 = _mm256_cvtepi8_epi16(_r1); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| // 01234567 89abcdef -> 01010101 01010101 23232323 23232323 | |
| __m512i _rrr0 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr0), _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr1 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr1), _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| _rrr0 = _mm512_unpacklo_epi32(_rrr0, _rrr0); | |
| _rrr1 = _mm512_unpacklo_epi32(_rrr1, _rrr1); | |
| __m512i _rrr0l = _mm512_unpacklo_epi64(_rrr0, _rrr0); | |
| __m512i _rrr0h = _mm512_unpackhi_epi64(_rrr0, _rrr0); | |
| __m512i _rrr1l = _mm512_unpacklo_epi64(_rrr1, _rrr1); | |
| __m512i _rrr1h = _mm512_unpackhi_epi64(_rrr1, _rrr1); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 128; | |
| } | |
| } | |
| _sum0 = _mm256_add_epi32(_sum0, _mm512_extracti64x4_epi64(_sum00, 0)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm512_extracti64x4_epi64(_sum00, 1)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm512_extracti64x4_epi64(_sum11, 0)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm512_extracti64x4_epi64(_sum11, 1)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm512_extracti64x4_epi64(_sum22, 0)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm512_extracti64x4_epi64(_sum22, 1)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm512_extracti64x4_epi64(_sum33, 0)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm512_extracti64x4_epi64(_sum33, 1)); | |
| } | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| __m256i _w01 = _mm256_load_si256((const __m256i*)kptr); | |
| __m256i _w23 = _mm256_load_si256((const __m256i*)(kptr + 32)); | |
| __m256i _w0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w01, 0)); | |
| __m256i _w1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w01, 1)); | |
| __m256i _w2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w23, 0)); | |
| __m256i _w3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w23, 1)); | |
| // 01234567 -> 01010101 01010101 | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _r0, 1); | |
| __m256i _rr1 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r1), _r1, 1); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 64; | |
| } | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_setr_epi16(r0s[0], r0s[N], 0, 0, 0, 0, 0, 0); | |
| __m128i _r1 = _mm_setr_epi16(r1s[0], r1s[N], 0, 0, 0, 0, 0, 0); | |
| __m256i _rr0 = _mm256_broadcastd_epi32(_r0); | |
| __m256i _rr1 = _mm256_broadcastd_epi32(_r1); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _rr0, _w); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _rr1, _w); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_rr0, _w)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_rr1, _w)); | |
| kptr += 16; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_set1_epi16(r0s[0]); | |
| __m128i _r1 = _mm_set1_epi16(r1s[0]); | |
| __m128i _w = _mm_cvtepi8_epi16(_mm_loadl_epi64((const __m128i*)kptr)); | |
| __m256i _s0 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_r0, _w)); | |
| __m256i _s1 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_r1, _w)); | |
| _sum0 = _mm256_add_epi32(_sum0, _s0); | |
| _sum1 = _mm256_add_epi32(_sum1, _s1); | |
| kptr += 8; | |
| } | |
| } | |
| } | |
| _sum0 = _mm256_add_epi32(_sum0, _sum2); | |
| _sum1 = _mm256_add_epi32(_sum1, _sum3); | |
| if (out_elempack == 8) | |
| { | |
| _mm256_store_si256((__m256i*)outptr, _sum0); | |
| _mm256_store_si256((__m256i*)(outptr + 8), _sum1); | |
| outptr += 16; | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _mm256_extracti128_si256(_sum0, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M), _mm256_extracti128_si256(_sum0, 1)); | |
| _mm_store_si128((__m128i*)(outptr + 4), _mm256_extracti128_si256(_sum1, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M + 4), _mm256_extracti128_si256(_sum1, 1)); | |
| outptr += 8; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(M)); | |
| _mm256_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| _mm256_i32scatter_epi32(outptr + 1, _vindex, _sum1, sizeof(int)); | |
| int sum0[8]; | |
| int sum1[8]; | |
| _mm256_storeu_si256((__m256i*)sum0, _sum0); | |
| _mm256_storeu_si256((__m256i*)sum1, _sum1); | |
| outptr[0] = sum0[0]; | |
| outptr[1] = sum1[0]; | |
| outptr[M] = sum0[1]; | |
| outptr[M + 1] = sum1[1]; | |
| outptr[M * 2] = sum0[2]; | |
| outptr[M * 2 + 1] = sum1[2]; | |
| outptr[M * 3] = sum0[3]; | |
| outptr[M * 3 + 1] = sum1[3]; | |
| outptr[M * 4] = sum0[4]; | |
| outptr[M * 4 + 1] = sum1[4]; | |
| outptr[M * 5] = sum0[5]; | |
| outptr[M * 5 + 1] = sum1[5]; | |
| outptr[M * 6] = sum0[6]; | |
| outptr[M * 6 + 1] = sum1[6]; | |
| outptr[M * 7] = sum0[7]; | |
| outptr[M * 7 + 1] = sum1[7]; | |
| outptr += 2; | |
| } | |
| } | |
| for (; ij < outw * outh; ij++) | |
| { | |
| const int i = ij / outw; | |
| const int j = ij % outw; | |
| __m256i _sum0 = _mm256_setzero_si256(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8); | |
| const signed char* kptr = weight_data_tm.channel(p / 8); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| __m512i _sum22 = _mm512_setzero_si512(); | |
| __m512i _sum33 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m512i _w01 = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w23 = _mm512_load_si512((const __m512i*)(kptr + 64)); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w01, 1)); | |
| __m512i _w2 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 0)); | |
| __m512i _w3 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w23, 1)); | |
| // 01234567 89abcdef -> 01010101 01010101 23232323 23232323 | |
| __m512i _rrr0 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr0), _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| _rrr0 = _mm512_unpacklo_epi32(_rrr0, _rrr0); | |
| __m512i _rrr0l = _mm512_unpacklo_epi64(_rrr0, _rrr0); | |
| __m512i _rrr0h = _mm512_unpackhi_epi64(_rrr0, _rrr0); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(1, 1, 1, 1)), _w2); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(1, 1, 1, 1)), _w2)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 128; | |
| } | |
| } | |
| _sum00 = _mm512_add_epi32(_sum00, _sum11); | |
| _sum22 = _mm512_add_epi32(_sum22, _sum33); | |
| _sum00 = _mm512_add_epi32(_sum00, _sum22); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm512_extracti64x4_epi64(_sum00, 0)); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm512_extracti64x4_epi64(_sum00, 1)); | |
| } | |
| { | |
| __m256i _sum1 = _mm256_setzero_si256(); | |
| __m256i _sum2 = _mm256_setzero_si256(); | |
| __m256i _sum3 = _mm256_setzero_si256(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val32, 0), _mm256_extracti128_si256(_val32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| __m256i _w01 = _mm256_load_si256((const __m256i*)kptr); | |
| __m256i _w23 = _mm256_load_si256((const __m256i*)(kptr + 32)); | |
| __m256i _w0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w01, 0)); | |
| __m256i _w1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w01, 1)); | |
| __m256i _w2 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w23, 0)); | |
| __m256i _w3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w23, 1)); | |
| // 01234567 -> 01010101 01010101 | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _r0, 1); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 1, 1, 1)), _w1); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w2); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 3, 3, 3)), _w3); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 64; | |
| } | |
| } | |
| _sum0 = _mm256_add_epi32(_sum0, _sum1); | |
| _sum2 = _mm256_add_epi32(_sum2, _sum3); | |
| _sum0 = _mm256_add_epi32(_sum0, _sum2); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _val0 = _mm_setr_epi16(r0s[0], r0s[N], 0, 0, 0, 0, 0, 0); | |
| __m256i _val = _mm256_broadcastd_epi32(_val0); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _val, _w); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_val, _w)); | |
| kptr += 16; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _val = _mm_set1_epi16(r0s[0]); | |
| __m128i _w = _mm_cvtepi8_epi16(_mm_loadl_epi64((const __m128i*)kptr)); | |
| __m256i _s0 = _mm256_cvtepi16_epi32(_mm_mullo_epi16(_val, _w)); | |
| _sum0 = _mm256_add_epi32(_sum0, _s0); | |
| kptr += 8; | |
| } | |
| } | |
| } | |
| if (out_elempack == 8) | |
| { | |
| _mm256_store_si256((__m256i*)outptr, _sum0); | |
| outptr += 8; | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _mm256_extracti128_si256(_sum0, 0)); | |
| _mm_store_si128((__m128i*)(outptr + M), _mm256_extracti128_si256(_sum0, 1)); | |
| outptr += 4; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(M)); | |
| _mm256_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| int sum[8]; | |
| _mm256_storeu_si256((__m256i*)sum, _sum0); | |
| outptr[0] = sum[0]; | |
| outptr[M] = sum[1]; | |
| outptr[M * 2] = sum[2]; | |
| outptr[M * 3] = sum[3]; | |
| outptr[M * 4] = sum[4]; | |
| outptr[M * 5] = sum[5]; | |
| outptr[M * 6] = sum[6]; | |
| outptr[M * 7] = sum[7]; | |
| outptr += 1; | |
| } | |
| } | |
| } | |
| remain_outch_start += nn_outch * 8; | |
| nn_outch = (outch - remain_outch_start) / 4; | |
| nn_outch = (outch - remain_outch_start) / 4; | |
| for (int pp = 0; pp < nn_outch; pp++) | |
| { | |
| const int p = remain_outch_start + pp * 4; | |
| // shadowed variable for less openmp task args | |
| const int outw = top_blob.w; | |
| const int outh = top_blob.h; | |
| const int N = bottom_blob.cstep * elempack; | |
| const int M = top_blob.cstep * out_elempack; | |
| int* outptr = top_blob.channel(p / out_elempack); | |
| int ij = 0; | |
| for (; ij + 3 < outw * outh; ij += 4) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int i2 = (ij + 2) / outw; | |
| const int i3 = (ij + 3) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| const int j2 = (ij + 2) % outw; | |
| const int j3 = (ij + 3) % outw; | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| __m128i _sum2 = _mm_setzero_si128(); | |
| __m128i _sum3 = _mm_setzero_si128(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4); | |
| const signed char* kptr = weight_data_tm.channel(p / 4); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| __m512i _sum22 = _mm512_setzero_si512(); | |
| __m512i _sum33 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| _r2 = _mm_load_si128((const __m128i*)r2s); | |
| _r3 = _mm_load_si128((const __m128i*)r3s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| __m128i _t4 = _mm_loadl_epi64((const __m128i*)r2s); | |
| __m128i _t5 = _mm_loadl_epi64((const __m128i*)(r2s + N)); | |
| __m128i _t6 = _mm_loadl_epi64((const __m128i*)r3s); | |
| __m128i _t7 = _mm_loadl_epi64((const __m128i*)(r3s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| _r2 = _mm_unpacklo_epi64(_t4, _t5); | |
| _r3 = _mm_unpacklo_epi64(_t6, _t7); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| _r2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r2s), sizeof(signed char))); | |
| _r3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r3s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _rr1 = _mm256_cvtepi8_epi16(_r1); | |
| __m256i _rr2 = _mm256_cvtepi8_epi16(_r2); | |
| __m256i _rr3 = _mm256_cvtepi8_epi16(_r3); | |
| __m512i _w = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w, 1)); | |
| // 01234567 89abcdef -> 01010101 23232323 45454545 67676767 | |
| _rr0 = _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 1, 2, 0)); | |
| _rr1 = _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(3, 1, 2, 0)); | |
| _rr2 = _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(3, 1, 2, 0)); | |
| _rr3 = _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(3, 1, 2, 0)); | |
| __m512i _rrr0 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr0), _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr1 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr1), _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr2 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr2), _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr3 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr3), _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| _rrr0 = _mm512_unpacklo_epi32(_rrr0, _rrr0); | |
| _rrr1 = _mm512_unpacklo_epi32(_rrr1, _rrr1); | |
| _rrr2 = _mm512_unpacklo_epi32(_rrr2, _rrr2); | |
| _rrr3 = _mm512_unpacklo_epi32(_rrr3, _rrr3); | |
| __m512i _rrr0l = _mm512_unpacklo_epi64(_rrr0, _rrr0); | |
| __m512i _rrr0h = _mm512_unpackhi_epi64(_rrr0, _rrr0); | |
| __m512i _rrr1l = _mm512_unpacklo_epi64(_rrr1, _rrr1); | |
| __m512i _rrr1h = _mm512_unpackhi_epi64(_rrr1, _rrr1); | |
| __m512i _rrr2l = _mm512_unpacklo_epi64(_rrr2, _rrr2); | |
| __m512i _rrr2h = _mm512_unpackhi_epi64(_rrr2, _rrr2); | |
| __m512i _rrr3l = _mm512_unpacklo_epi64(_rrr3, _rrr3); | |
| __m512i _rrr3h = _mm512_unpackhi_epi64(_rrr3, _rrr3); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr2l, _rrr2h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr3l, _rrr3h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| kptr += 64; | |
| } | |
| } | |
| __m256i _ss0 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum00, 0), _mm512_extracti64x4_epi64(_sum00, 1)); | |
| __m256i _ss1 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum11, 0), _mm512_extracti64x4_epi64(_sum11, 1)); | |
| __m256i _ss2 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum22, 0), _mm512_extracti64x4_epi64(_sum22, 1)); | |
| __m256i _ss3 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum33, 0), _mm512_extracti64x4_epi64(_sum33, 1)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 0)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 1)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss1, 0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss1, 1)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm256_extracti128_si256(_ss2, 0)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm256_extracti128_si256(_ss2, 1)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm256_extracti128_si256(_ss3, 0)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm256_extracti128_si256(_ss3, 1)); | |
| } | |
| { | |
| __m256i _sum00 = _mm256_setzero_si256(); | |
| __m256i _sum11 = _mm256_setzero_si256(); | |
| __m256i _sum22 = _mm256_setzero_si256(); | |
| __m256i _sum33 = _mm256_setzero_si256(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| _r2 = _mm_loadl_epi64((const __m128i*)r2s); | |
| _r3 = _mm_loadl_epi64((const __m128i*)r3s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| _r2 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char))); | |
| _r3 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val2_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val3_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r2 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val2_32, 0), _mm256_extracti128_si256(_val2_32, 1)); | |
| _r3 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val3_32, 0), _mm256_extracti128_si256(_val3_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r2 = _mm_setr_epi8(r2s[0], r2s[N], r2s[N * 2], r2s[N * 3], r2s[N * 4], r2s[N * 5], r2s[N * 6], r2s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r3 = _mm_setr_epi8(r3s[0], r3s[N], r3s[N * 2], r3s[N * 3], r3s[N * 4], r3s[N * 5], r3s[N * 6], r3s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r2 = _mm_cvtepi8_epi16(_r2); | |
| _r3 = _mm_cvtepi8_epi16(_r3); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| _r1 = _mm_unpacklo_epi8(_r1, _mm_cmpgt_epi8(_mm_setzero_si128(), _r1)); | |
| _r2 = _mm_unpacklo_epi8(_r2, _mm_cmpgt_epi8(_mm_setzero_si128(), _r2)); | |
| _r3 = _mm_unpacklo_epi8(_r3, _mm_cmpgt_epi8(_mm_setzero_si128(), _r3)); | |
| __m256i _w = _mm256_load_si256((const __m256i*)kptr); | |
| __m256i _w0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w, 0)); | |
| __m256i _w1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w, 1)); | |
| // 01234567 -> 01010101 23232323 | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| __m256i _rr1 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r1), _mm_shuffle_epi32(_r1, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| __m256i _rr2 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r2), _mm_shuffle_epi32(_r2, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| __m256i _rr3 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r3), _mm_shuffle_epi32(_r3, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| _sum00 = _mm256_dpwssd_epi32(_sum00, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum11 = _mm256_dpwssd_epi32(_sum11, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum22 = _mm256_dpwssd_epi32(_sum22, _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum33 = _mm256_dpwssd_epi32(_sum33, _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum00 = _mm256_dpwssd_epi32(_sum00, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum11 = _mm256_dpwssd_epi32(_sum11, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum22 = _mm256_dpwssd_epi32(_sum22, _mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum33 = _mm256_dpwssd_epi32(_sum33, _mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum00 = _mm256_add_epi32(_sum00, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum11 = _mm256_add_epi32(_sum11, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum22 = _mm256_add_epi32(_sum22, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum33 = _mm256_add_epi32(_sum33, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum00 = _mm256_add_epi32(_sum00, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum11 = _mm256_add_epi32(_sum11, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum22 = _mm256_add_epi32(_sum22, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr2, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum33 = _mm256_add_epi32(_sum33, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr3, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| __m128i _w01 = _mm_load_si128((const __m128i*)kptr); | |
| __m128i _w23 = _mm_load_si128((const __m128i*)(kptr + 16)); | |
| __m128i _extw01 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w01); | |
| __m128i _extw23 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w23); | |
| __m128i _w0 = _mm_unpacklo_epi8(_w01, _extw01); | |
| __m128i _w1 = _mm_unpackhi_epi8(_w01, _extw01); | |
| __m128i _w2 = _mm_unpacklo_epi8(_w23, _extw23); | |
| __m128i _w3 = _mm_unpackhi_epi8(_w23, _extw23); | |
| // 01234567 -> 01010101 | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum3); | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum3); | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum3); | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum3); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r2, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r3, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 32; | |
| } | |
| } | |
| __m128i _ss0 = _mm_add_epi32(_mm256_extracti128_si256(_sum00, 0), _mm256_extracti128_si256(_sum00, 1)); | |
| __m128i _ss1 = _mm_add_epi32(_mm256_extracti128_si256(_sum11, 0), _mm256_extracti128_si256(_sum11, 1)); | |
| __m128i _ss2 = _mm_add_epi32(_mm256_extracti128_si256(_sum22, 0), _mm256_extracti128_si256(_sum22, 1)); | |
| __m128i _ss3 = _mm_add_epi32(_mm256_extracti128_si256(_sum33, 0), _mm256_extracti128_si256(_sum33, 1)); | |
| _sum0 = _mm_add_epi32(_sum0, _ss0); | |
| _sum1 = _mm_add_epi32(_sum1, _ss1); | |
| _sum2 = _mm_add_epi32(_sum2, _ss2); | |
| _sum3 = _mm_add_epi32(_sum3, _ss3); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_setr_epi16(r0s[0], r0s[N], r0s[0], r0s[N], r0s[0], r0s[N], r0s[0], r0s[N]); | |
| __m128i _r1 = _mm_setr_epi16(r1s[0], r1s[N], r1s[0], r1s[N], r1s[0], r1s[N], r1s[0], r1s[N]); | |
| __m128i _r2 = _mm_setr_epi16(r2s[0], r2s[N], r2s[0], r2s[N], r2s[0], r2s[N], r2s[0], r2s[N]); | |
| __m128i _r3 = _mm_setr_epi16(r3s[0], r3s[N], r3s[0], r3s[N], r3s[0], r3s[N], r3s[0], r3s[N]); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _sum0 = _mm_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum1 = _mm_dpwssd_epi32(_sum1, _r1, _w); | |
| _sum2 = _mm_dpwssd_epi32(_sum2, _r2, _w); | |
| _sum3 = _mm_dpwssd_epi32(_sum3, _r3, _w); | |
| _sum0 = _mm_maddd_epi16(_r0, _w, _sum0); | |
| _sum1 = _mm_maddd_epi16(_r1, _w, _sum1); | |
| _sum2 = _mm_maddd_epi16(_r2, _w, _sum2); | |
| _sum3 = _mm_maddd_epi16(_r3, _w, _sum3); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r0, _w)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_r1, _w)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_r2, _w)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_r3, _w)); | |
| kptr += 8; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_set1_epi16(r0s[0]); | |
| __m128i _r1 = _mm_set1_epi16(r1s[0]); | |
| __m128i _r2 = _mm_set1_epi16(r2s[0]); | |
| __m128i _r3 = _mm_set1_epi16(r3s[0]); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _w = _mm_unpacklo_epi16(_w, _mm_setzero_si128()); | |
| _sum0 = _mm_maccd_epi16(_r0, _w, _sum0); | |
| _sum1 = _mm_maccd_epi16(_r1, _w, _sum1); | |
| _sum2 = _mm_maccd_epi16(_r2, _w, _sum2); | |
| _sum3 = _mm_maccd_epi16(_r3, _w, _sum3); | |
| __m128i _sl0 = _mm_mullo_epi16(_r0, _w); | |
| __m128i _sh0 = _mm_mulhi_epi16(_r0, _w); | |
| __m128i _sl1 = _mm_mullo_epi16(_r1, _w); | |
| __m128i _sh1 = _mm_mulhi_epi16(_r1, _w); | |
| __m128i _sl2 = _mm_mullo_epi16(_r2, _w); | |
| __m128i _sh2 = _mm_mulhi_epi16(_r2, _w); | |
| __m128i _sl3 = _mm_mullo_epi16(_r3, _w); | |
| __m128i _sh3 = _mm_mulhi_epi16(_r3, _w); | |
| __m128i _s0 = _mm_unpacklo_epi16(_sl0, _sh0); | |
| __m128i _s1 = _mm_unpacklo_epi16(_sl1, _sh1); | |
| __m128i _s2 = _mm_unpacklo_epi16(_sl2, _sh2); | |
| __m128i _s3 = _mm_unpacklo_epi16(_sl3, _sh3); | |
| _sum0 = _mm_add_epi32(_sum0, _s0); | |
| _sum1 = _mm_add_epi32(_sum1, _s1); | |
| _sum2 = _mm_add_epi32(_sum2, _s2); | |
| _sum3 = _mm_add_epi32(_sum3, _s3); | |
| kptr += 4; | |
| } | |
| } | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _sum0); | |
| _mm_store_si128((__m128i*)(outptr + 4), _sum1); | |
| _mm_store_si128((__m128i*)(outptr + 8), _sum2); | |
| _mm_store_si128((__m128i*)(outptr + 12), _sum3); | |
| outptr += 16; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m128i _vindex = _mm_setr_epi32(0, 1, 2, 3); | |
| _vindex = _mm_mullo_epi32(_vindex, _mm_set1_epi32(M)); | |
| _mm_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| _mm_i32scatter_epi32(outptr + 1, _vindex, _sum1, sizeof(int)); | |
| _mm_i32scatter_epi32(outptr + 2, _vindex, _sum2, sizeof(int)); | |
| _mm_i32scatter_epi32(outptr + 3, _vindex, _sum3, sizeof(int)); | |
| int sum0[4]; | |
| int sum1[4]; | |
| int sum2[4]; | |
| int sum3[4]; | |
| _mm_storeu_si128((__m128i*)sum0, _sum0); | |
| _mm_storeu_si128((__m128i*)sum1, _sum1); | |
| _mm_storeu_si128((__m128i*)sum2, _sum2); | |
| _mm_storeu_si128((__m128i*)sum3, _sum3); | |
| outptr[0] = sum0[0]; | |
| outptr[1] = sum1[0]; | |
| outptr[2] = sum2[0]; | |
| outptr[3] = sum3[0]; | |
| outptr[M] = sum0[1]; | |
| outptr[M + 1] = sum1[1]; | |
| outptr[M + 2] = sum2[1]; | |
| outptr[M + 3] = sum3[1]; | |
| outptr[M * 2] = sum0[2]; | |
| outptr[M * 2 + 1] = sum1[2]; | |
| outptr[M * 2 + 2] = sum2[2]; | |
| outptr[M * 2 + 3] = sum3[2]; | |
| outptr[M * 3] = sum0[3]; | |
| outptr[M * 3 + 1] = sum1[3]; | |
| outptr[M * 3 + 2] = sum2[3]; | |
| outptr[M * 3 + 3] = sum3[3]; | |
| outptr += 4; | |
| } | |
| } | |
| for (; ij + 1 < outw * outh; ij += 2) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| __m128i _sum2 = _mm_setzero_si128(); | |
| __m128i _sum3 = _mm_setzero_si128(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4); | |
| const signed char* kptr = weight_data_tm.channel(p / 4); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| __m512i _sum22 = _mm512_setzero_si512(); | |
| __m512i _sum33 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _rr1 = _mm256_cvtepi8_epi16(_r1); | |
| __m512i _w = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w, 1)); | |
| // 01234567 89abcdef -> 01010101 23232323 45454545 67676767 | |
| _rr0 = _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 1, 2, 0)); | |
| _rr1 = _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(3, 1, 2, 0)); | |
| __m512i _rrr0 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr0), _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| __m512i _rrr1 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr1), _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| _rrr0 = _mm512_unpacklo_epi32(_rrr0, _rrr0); | |
| _rrr1 = _mm512_unpacklo_epi32(_rrr1, _rrr1); | |
| __m512i _rrr0l = _mm512_unpacklo_epi64(_rrr0, _rrr0); | |
| __m512i _rrr0h = _mm512_unpackhi_epi64(_rrr0, _rrr0); | |
| __m512i _rrr1l = _mm512_unpacklo_epi64(_rrr1, _rrr1); | |
| __m512i _rrr1h = _mm512_unpackhi_epi64(_rrr1, _rrr1); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr1l, _rrr1h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| kptr += 64; | |
| } | |
| } | |
| __m256i _ss0 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum00, 0), _mm512_extracti64x4_epi64(_sum00, 1)); | |
| __m256i _ss1 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum11, 0), _mm512_extracti64x4_epi64(_sum11, 1)); | |
| __m256i _ss2 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum22, 0), _mm512_extracti64x4_epi64(_sum22, 1)); | |
| __m256i _ss3 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum33, 0), _mm512_extracti64x4_epi64(_sum33, 1)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 0)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 1)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss1, 0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss1, 1)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm256_extracti128_si256(_ss2, 0)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm256_extracti128_si256(_ss2, 1)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm256_extracti128_si256(_ss3, 0)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm256_extracti128_si256(_ss3, 1)); | |
| } | |
| { | |
| __m256i _sum00 = _mm256_setzero_si256(); | |
| __m256i _sum11 = _mm256_setzero_si256(); | |
| __m256i _sum22 = _mm256_setzero_si256(); | |
| __m256i _sum33 = _mm256_setzero_si256(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| _r1 = _mm_unpacklo_epi8(_r1, _mm_cmpgt_epi8(_mm_setzero_si128(), _r1)); | |
| __m256i _w = _mm256_load_si256((const __m256i*)kptr); | |
| __m256i _w0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w, 0)); | |
| __m256i _w1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w, 1)); | |
| // 01234567 -> 01010101 23232323 | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| __m256i _rr1 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r1), _mm_shuffle_epi32(_r1, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| _sum00 = _mm256_dpwssd_epi32(_sum00, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum11 = _mm256_dpwssd_epi32(_sum11, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum22 = _mm256_dpwssd_epi32(_sum22, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum33 = _mm256_dpwssd_epi32(_sum33, _mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum00 = _mm256_add_epi32(_sum00, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum11 = _mm256_add_epi32(_sum11, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum22 = _mm256_add_epi32(_sum22, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| _sum33 = _mm256_add_epi32(_sum33, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr1, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| __m128i _w01 = _mm_load_si128((const __m128i*)kptr); | |
| __m128i _w23 = _mm_load_si128((const __m128i*)(kptr + 16)); | |
| __m128i _extw01 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w01); | |
| __m128i _extw23 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w23); | |
| __m128i _w0 = _mm_unpacklo_epi8(_w01, _extw01); | |
| __m128i _w1 = _mm_unpackhi_epi8(_w01, _extw01); | |
| __m128i _w2 = _mm_unpacklo_epi8(_w23, _extw23); | |
| __m128i _w3 = _mm_unpackhi_epi8(_w23, _extw23); | |
| // 01234567 -> 01010101 | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum3); | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum3); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r1, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 32; | |
| } | |
| } | |
| __m128i _ss0 = _mm_add_epi32(_mm256_extracti128_si256(_sum00, 0), _mm256_extracti128_si256(_sum00, 1)); | |
| __m128i _ss1 = _mm_add_epi32(_mm256_extracti128_si256(_sum11, 0), _mm256_extracti128_si256(_sum11, 1)); | |
| __m128i _ss2 = _mm_add_epi32(_mm256_extracti128_si256(_sum22, 0), _mm256_extracti128_si256(_sum22, 1)); | |
| __m128i _ss3 = _mm_add_epi32(_mm256_extracti128_si256(_sum33, 0), _mm256_extracti128_si256(_sum33, 1)); | |
| _sum0 = _mm_add_epi32(_sum0, _ss0); | |
| _sum1 = _mm_add_epi32(_sum1, _ss1); | |
| _sum2 = _mm_add_epi32(_sum2, _ss2); | |
| _sum3 = _mm_add_epi32(_sum3, _ss3); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_setr_epi16(r0s[0], r0s[N], r0s[0], r0s[N], r0s[0], r0s[N], r0s[0], r0s[N]); | |
| __m128i _r1 = _mm_setr_epi16(r1s[0], r1s[N], r1s[0], r1s[N], r1s[0], r1s[N], r1s[0], r1s[N]); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _sum0 = _mm_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum1 = _mm_dpwssd_epi32(_sum1, _r1, _w); | |
| _sum0 = _mm_maddd_epi16(_r0, _w, _sum0); | |
| _sum1 = _mm_maddd_epi16(_r1, _w, _sum1); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r0, _w)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_r1, _w)); | |
| kptr += 8; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_set1_epi16(r0s[0]); | |
| __m128i _r1 = _mm_set1_epi16(r1s[0]); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _w = _mm_unpacklo_epi16(_w, _mm_setzero_si128()); | |
| _sum0 = _mm_maccd_epi16(_r0, _w, _sum0); | |
| _sum1 = _mm_maccd_epi16(_r1, _w, _sum1); | |
| __m128i _sl0 = _mm_mullo_epi16(_r0, _w); | |
| __m128i _sh0 = _mm_mulhi_epi16(_r0, _w); | |
| __m128i _sl1 = _mm_mullo_epi16(_r1, _w); | |
| __m128i _sh1 = _mm_mulhi_epi16(_r1, _w); | |
| __m128i _s0 = _mm_unpacklo_epi16(_sl0, _sh0); | |
| __m128i _s1 = _mm_unpacklo_epi16(_sl1, _sh1); | |
| _sum0 = _mm_add_epi32(_sum0, _s0); | |
| _sum1 = _mm_add_epi32(_sum1, _s1); | |
| kptr += 4; | |
| } | |
| } | |
| } | |
| _sum0 = _mm_add_epi32(_sum0, _sum2); | |
| _sum1 = _mm_add_epi32(_sum1, _sum3); | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _sum0); | |
| _mm_store_si128((__m128i*)(outptr + 4), _sum1); | |
| outptr += 8; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m128i _vindex = _mm_setr_epi32(0, 1, 2, 3); | |
| _vindex = _mm_mullo_epi32(_vindex, _mm_set1_epi32(M)); | |
| _mm_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| _mm_i32scatter_epi32(outptr + 1, _vindex, _sum1, sizeof(int)); | |
| int sum0[4]; | |
| int sum1[4]; | |
| _mm_storeu_si128((__m128i*)sum0, _sum0); | |
| _mm_storeu_si128((__m128i*)sum1, _sum1); | |
| outptr[0] = sum0[0]; | |
| outptr[1] = sum1[0]; | |
| outptr[M] = sum0[1]; | |
| outptr[M + 1] = sum1[1]; | |
| outptr[M * 2] = sum0[2]; | |
| outptr[M * 2 + 1] = sum1[2]; | |
| outptr[M * 3] = sum0[3]; | |
| outptr[M * 3 + 1] = sum1[3]; | |
| outptr += 2; | |
| } | |
| } | |
| for (; ij < outw * outh; ij++) | |
| { | |
| const int i = ij / outw; | |
| const int j = ij % outw; | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4); | |
| const signed char* kptr = weight_data_tm.channel(p / 4); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| } | |
| __m256i _rr0 = _mm256_cvtepi8_epi16(_r0); | |
| __m512i _w = _mm512_load_si512((const __m512i*)kptr); | |
| __m512i _w0 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w, 0)); | |
| __m512i _w1 = _mm512_cvtepi8_epi16(_mm512_extracti64x4_epi64(_w, 1)); | |
| // 01234567 89abcdef -> 01010101 23232323 45454545 67676767 | |
| _rr0 = _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(3, 1, 2, 0)); | |
| __m512i _rrr0 = _mm512_inserti64x4(_mm512_castsi256_si512(_rr0), _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(1, 0, 3, 2)), 1); | |
| _rrr0 = _mm512_unpacklo_epi32(_rrr0, _rrr0); | |
| __m512i _rrr0l = _mm512_unpacklo_epi64(_rrr0, _rrr0); | |
| __m512i _rrr0h = _mm512_unpackhi_epi64(_rrr0, _rrr0); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 0, 2, 0)), _w0); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 1, 3, 1)), _w1); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(2, 0, 2, 0)), _w0)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_mm512_shuffle_i32x4(_rrr0l, _rrr0h, _MM_SHUFFLE(3, 1, 3, 1)), _w1)); | |
| kptr += 64; | |
| } | |
| } | |
| _sum00 = _mm512_add_epi32(_sum00, _sum11); | |
| __m256i _ss0 = _mm256_add_epi32(_mm512_extracti64x4_epi64(_sum00, 0), _mm512_extracti64x4_epi64(_sum00, 1)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 0)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 1)); | |
| } | |
| { | |
| __m256i _sum00 = _mm256_setzero_si256(); | |
| __m256i _sum11 = _mm256_setzero_si256(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| __m128i _sum2 = _mm_setzero_si128(); | |
| __m128i _sum3 = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val32, 0), _mm256_extracti128_si256(_val32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| __m256i _w = _mm256_load_si256((const __m256i*)kptr); | |
| __m256i _w0 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w, 0)); | |
| __m256i _w1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(_w, 1)); | |
| // 01234567 -> 01010101 23232323 | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 3, 0, 1)), 1); | |
| _sum00 = _mm256_dpwssd_epi32(_sum00, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0); | |
| _sum11 = _mm256_dpwssd_epi32(_sum11, _mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w1); | |
| _sum00 = _mm256_add_epi32(_sum00, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum11 = _mm256_add_epi32(_sum11, _mm256_madd_epi16(_mm256_shuffle_epi32(_rr0, _MM_SHUFFLE(2, 2, 2, 2)), _w1)); | |
| __m128i _w01 = _mm_load_si128((const __m128i*)kptr); | |
| __m128i _w23 = _mm_load_si128((const __m128i*)(kptr + 16)); | |
| __m128i _extw01 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w01); | |
| __m128i _extw23 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w23); | |
| __m128i _w0 = _mm_unpacklo_epi8(_w01, _extw01); | |
| __m128i _w1 = _mm_unpackhi_epi8(_w01, _extw01); | |
| __m128i _w2 = _mm_unpacklo_epi8(_w23, _extw23); | |
| __m128i _w3 = _mm_unpackhi_epi8(_w23, _extw23); | |
| // 01234567 -> 01010101 | |
| _sum0 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(0, 0, 0, 0)), _w0, _sum0); | |
| _sum1 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(1, 1, 1, 1)), _w1, _sum1); | |
| _sum2 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 2, 2, 2)), _w2, _sum2); | |
| _sum3 = _mm_maddd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(3, 3, 3, 3)), _w3, _sum3); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(0, 0, 0, 0)), _w0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(1, 1, 1, 1)), _w1)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(2, 2, 2, 2)), _w2)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_mm_shuffle_epi32(_r0, _MM_SHUFFLE(3, 3, 3, 3)), _w3)); | |
| kptr += 32; | |
| } | |
| } | |
| _sum00 = _mm256_add_epi32(_sum00, _sum11); | |
| __m128i _ss = _mm_add_epi32(_mm256_extracti128_si256(_sum00, 0), _mm256_extracti128_si256(_sum00, 1)); | |
| _sum0 = _mm_add_epi32(_sum0, _ss); | |
| _sum0 = _mm_add_epi32(_sum0, _sum1); | |
| _sum2 = _mm_add_epi32(_sum2, _sum3); | |
| _sum0 = _mm_add_epi32(_sum0, _sum2); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_setr_epi16(r0s[0], r0s[N], r0s[0], r0s[N], r0s[0], r0s[N], r0s[0], r0s[N]); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _sum0 = _mm_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum0 = _mm_maddd_epi16(_r0, _w, _sum0); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r0, _w)); | |
| kptr += 8; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r0 = _mm_set1_epi16(r0s[0]); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _w = _mm_unpacklo_epi16(_w, _mm_setzero_si128()); | |
| _sum0 = _mm_maccd_epi16(_r0, _w, _sum0); | |
| __m128i _sl = _mm_mullo_epi16(_r0, _w); | |
| __m128i _sh = _mm_mulhi_epi16(_r0, _w); | |
| __m128i _s0 = _mm_unpacklo_epi16(_sl, _sh); | |
| _sum0 = _mm_add_epi32(_sum0, _s0); | |
| kptr += 4; | |
| } | |
| } | |
| } | |
| if (out_elempack == 4) | |
| { | |
| _mm_store_si128((__m128i*)outptr, _sum0); | |
| outptr += 4; | |
| } | |
| if (out_elempack == 1) | |
| { | |
| __m128i _vindex = _mm_setr_epi32(0, 1, 2, 3); | |
| _vindex = _mm_mullo_epi32(_vindex, _mm_set1_epi32(M)); | |
| _mm_i32scatter_epi32(outptr, _vindex, _sum0, sizeof(int)); | |
| int sum[4]; | |
| _mm_storeu_si128((__m128i*)sum, _sum0); | |
| outptr[0] = sum[0]; | |
| outptr[M] = sum[1]; | |
| outptr[M * 2] = sum[2]; | |
| outptr[M * 3] = sum[3]; | |
| outptr += 1; | |
| } | |
| } | |
| } | |
| remain_outch_start += nn_outch * 4; | |
| nn_outch = (outch - remain_outch_start) / 2; | |
| nn_outch = (outch - remain_outch_start) / 2; | |
| for (int pp = 0; pp < nn_outch; pp++) | |
| { | |
| const int p = remain_outch_start + pp * 2; | |
| // shadowed variable for less openmp task args | |
| const int outw = top_blob.w; | |
| const int outh = top_blob.h; | |
| const int N = bottom_blob.cstep * elempack; | |
| int* outptr0 = top_blob.channel(p); | |
| int* outptr1 = top_blob.channel(p + 1); | |
| int ij = 0; | |
| for (; ij + 3 < outw * outh; ij += 4) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int i2 = (ij + 2) / outw; | |
| const int i3 = (ij + 3) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| const int j2 = (ij + 2) % outw; | |
| const int j3 = (ij + 3) % outw; | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 4 + (p % 4) / 2); | |
| int q = 0; | |
| { | |
| __m512i _sum00 = _mm512_setzero_si512(); | |
| __m512i _sum11 = _mm512_setzero_si512(); | |
| __m512i _sum22 = _mm512_setzero_si512(); | |
| __m512i _sum33 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| _r2 = _mm_load_si128((const __m128i*)r2s); | |
| _r3 = _mm_load_si128((const __m128i*)r3s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| __m128i _t4 = _mm_loadl_epi64((const __m128i*)r2s); | |
| __m128i _t5 = _mm_loadl_epi64((const __m128i*)(r2s + N)); | |
| __m128i _t6 = _mm_loadl_epi64((const __m128i*)r3s); | |
| __m128i _t7 = _mm_loadl_epi64((const __m128i*)(r3s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| _r2 = _mm_unpacklo_epi64(_t4, _t5); | |
| _r3 = _mm_unpacklo_epi64(_t6, _t7); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| _r2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r2s), sizeof(signed char))); | |
| _r3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r3s), sizeof(signed char))); | |
| } | |
| __m256i _val0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _val1 = _mm256_cvtepi8_epi16(_r1); | |
| __m256i _val2 = _mm256_cvtepi8_epi16(_r2); | |
| __m256i _val3 = _mm256_cvtepi8_epi16(_r3); | |
| __m512i _valval0 = _mm512_inserti64x4(_mm512_castsi256_si512(_val0), _val0, 1); | |
| __m512i _valval1 = _mm512_inserti64x4(_mm512_castsi256_si512(_val1), _val1, 1); | |
| __m512i _valval2 = _mm512_inserti64x4(_mm512_castsi256_si512(_val2), _val2, 1); | |
| __m512i _valval3 = _mm512_inserti64x4(_mm512_castsi256_si512(_val3), _val3, 1); | |
| __m512i _w = _mm512_cvtepi8_epi16(_mm256_load_si256((const __m256i*)kptr)); | |
| _sum00 = _mm512_dpwssd_epi32(_sum00, _valval0, _w); | |
| _sum11 = _mm512_dpwssd_epi32(_sum11, _valval1, _w); | |
| _sum22 = _mm512_dpwssd_epi32(_sum22, _valval2, _w); | |
| _sum33 = _mm512_dpwssd_epi32(_sum33, _valval3, _w); | |
| _sum00 = _mm512_add_epi32(_sum00, _mm512_madd_epi16(_valval0, _w)); | |
| _sum11 = _mm512_add_epi32(_sum11, _mm512_madd_epi16(_valval1, _w)); | |
| _sum22 = _mm512_add_epi32(_sum22, _mm512_madd_epi16(_valval2, _w)); | |
| _sum33 = _mm512_add_epi32(_sum33, _mm512_madd_epi16(_valval3, _w)); | |
| kptr += 32; | |
| } | |
| } | |
| __m256i _sum010 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum00, 0), _mm512_extracti64x4_epi64(_sum11, 0)); | |
| __m256i _sum230 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum22, 0), _mm512_extracti64x4_epi64(_sum33, 0)); | |
| __m256i _sum011 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum00, 1), _mm512_extracti64x4_epi64(_sum11, 1)); | |
| __m256i _sum231 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum22, 1), _mm512_extracti64x4_epi64(_sum33, 1)); | |
| __m256i _ss0 = _mm256_hadd_epi32(_sum010, _sum230); | |
| __m256i _ss1 = _mm256_hadd_epi32(_sum011, _sum231); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 0)); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss0, 1)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss1, 0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss1, 1)); | |
| } | |
| { | |
| __m256i _sum00 = _mm256_setzero_si256(); | |
| __m256i _sum11 = _mm256_setzero_si256(); | |
| __m256i _sum22 = _mm256_setzero_si256(); | |
| __m256i _sum33 = _mm256_setzero_si256(); | |
| __m128i _sum00 = _mm_setzero_si128(); | |
| __m128i _sum10 = _mm_setzero_si128(); | |
| __m128i _sum01 = _mm_setzero_si128(); | |
| __m128i _sum11 = _mm_setzero_si128(); | |
| __m128i _sum02 = _mm_setzero_si128(); | |
| __m128i _sum12 = _mm_setzero_si128(); | |
| __m128i _sum03 = _mm_setzero_si128(); | |
| __m128i _sum13 = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| _r2 = _mm_loadl_epi64((const __m128i*)r2s); | |
| _r3 = _mm_loadl_epi64((const __m128i*)r3s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| _r2 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char))); | |
| _r3 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val2_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val3_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r2 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val2_32, 0), _mm256_extracti128_si256(_val2_32, 1)); | |
| _r3 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val3_32, 0), _mm256_extracti128_si256(_val3_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r2 = _mm_setr_epi8(r2s[0], r2s[N], r2s[N * 2], r2s[N * 3], r2s[N * 4], r2s[N * 5], r2s[N * 6], r2s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r3 = _mm_setr_epi8(r3s[0], r3s[N], r3s[N * 2], r3s[N * 3], r3s[N * 4], r3s[N * 5], r3s[N * 6], r3s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r2 = _mm_cvtepi8_epi16(_r2); | |
| _r3 = _mm_cvtepi8_epi16(_r3); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| _r1 = _mm_unpacklo_epi8(_r1, _mm_cmpgt_epi8(_mm_setzero_si128(), _r1)); | |
| _r2 = _mm_unpacklo_epi8(_r2, _mm_cmpgt_epi8(_mm_setzero_si128(), _r2)); | |
| _r3 = _mm_unpacklo_epi8(_r3, _mm_cmpgt_epi8(_mm_setzero_si128(), _r3)); | |
| __m128i _w01 = _mm_load_si128((const __m128i*)kptr); | |
| __m256i _valval0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _r0, 1); | |
| __m256i _valval1 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r1), _r1, 1); | |
| __m256i _valval2 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r2), _r2, 1); | |
| __m256i _valval3 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r3), _r3, 1); | |
| __m256i _w = _mm256_cvtepi8_epi16(_w01); | |
| _sum00 = _mm256_dpwssd_epi32(_sum00, _valval0, _w); | |
| _sum11 = _mm256_dpwssd_epi32(_sum11, _valval1, _w); | |
| _sum22 = _mm256_dpwssd_epi32(_sum22, _valval2, _w); | |
| _sum33 = _mm256_dpwssd_epi32(_sum33, _valval3, _w); | |
| _sum00 = _mm256_add_epi32(_sum00, _mm256_madd_epi16(_valval0, _w)); | |
| _sum11 = _mm256_add_epi32(_sum11, _mm256_madd_epi16(_valval1, _w)); | |
| _sum22 = _mm256_add_epi32(_sum22, _mm256_madd_epi16(_valval2, _w)); | |
| _sum33 = _mm256_add_epi32(_sum33, _mm256_madd_epi16(_valval3, _w)); | |
| __m128i _extw01 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w01); | |
| __m128i _w0 = _mm_unpacklo_epi8(_w01, _extw01); | |
| __m128i _w1 = _mm_unpackhi_epi8(_w01, _extw01); | |
| _sum00 = _mm_maddd_epi16(_r0, _w0, _sum00); | |
| _sum10 = _mm_maddd_epi16(_r0, _w1, _sum10); | |
| _sum01 = _mm_maddd_epi16(_r1, _w0, _sum01); | |
| _sum11 = _mm_maddd_epi16(_r1, _w1, _sum11); | |
| _sum02 = _mm_maddd_epi16(_r2, _w0, _sum02); | |
| _sum12 = _mm_maddd_epi16(_r2, _w1, _sum12); | |
| _sum03 = _mm_maddd_epi16(_r3, _w0, _sum03); | |
| _sum13 = _mm_maddd_epi16(_r3, _w1, _sum13); | |
| _sum00 = _mm_add_epi32(_sum00, _mm_madd_epi16(_r0, _w0)); | |
| _sum10 = _mm_add_epi32(_sum10, _mm_madd_epi16(_r0, _w1)); | |
| _sum01 = _mm_add_epi32(_sum01, _mm_madd_epi16(_r1, _w0)); | |
| _sum11 = _mm_add_epi32(_sum11, _mm_madd_epi16(_r1, _w1)); | |
| _sum02 = _mm_add_epi32(_sum02, _mm_madd_epi16(_r2, _w0)); | |
| _sum12 = _mm_add_epi32(_sum12, _mm_madd_epi16(_r2, _w1)); | |
| _sum03 = _mm_add_epi32(_sum03, _mm_madd_epi16(_r3, _w0)); | |
| _sum13 = _mm_add_epi32(_sum13, _mm_madd_epi16(_r3, _w1)); | |
| kptr += 16; | |
| } | |
| } | |
| __m256i _sum01 = _mm256_hadd_epi32(_sum00, _sum11); | |
| __m256i _sum23 = _mm256_hadd_epi32(_sum22, _sum33); | |
| __m256i _ss = _mm256_hadd_epi32(_sum01, _sum23); | |
| _sum0 = _mm_add_epi32(_sum0, _mm256_extracti128_si256(_ss, 0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm256_extracti128_si256(_ss, 1)); | |
| // transpose 4x4 | |
| __m128i _tmp00 = _mm_unpacklo_epi32(_sum00, _sum01); | |
| __m128i _tmp01 = _mm_unpacklo_epi32(_sum02, _sum03); | |
| __m128i _tmp02 = _mm_unpackhi_epi32(_sum00, _sum01); | |
| __m128i _tmp03 = _mm_unpackhi_epi32(_sum02, _sum03); | |
| __m128i _tmp10 = _mm_unpacklo_epi32(_sum10, _sum11); | |
| __m128i _tmp11 = _mm_unpacklo_epi32(_sum12, _sum13); | |
| __m128i _tmp12 = _mm_unpackhi_epi32(_sum10, _sum11); | |
| __m128i _tmp13 = _mm_unpackhi_epi32(_sum12, _sum13); | |
| _sum00 = _mm_unpacklo_epi64(_tmp00, _tmp01); | |
| _sum01 = _mm_unpackhi_epi64(_tmp00, _tmp01); | |
| _sum02 = _mm_unpacklo_epi64(_tmp02, _tmp03); | |
| _sum03 = _mm_unpackhi_epi64(_tmp02, _tmp03); | |
| _sum10 = _mm_unpacklo_epi64(_tmp10, _tmp11); | |
| _sum11 = _mm_unpackhi_epi64(_tmp10, _tmp11); | |
| _sum12 = _mm_unpacklo_epi64(_tmp12, _tmp13); | |
| _sum13 = _mm_unpackhi_epi64(_tmp12, _tmp13); | |
| _sum00 = _mm_add_epi32(_sum00, _sum01); | |
| _sum02 = _mm_add_epi32(_sum02, _sum03); | |
| _sum10 = _mm_add_epi32(_sum10, _sum11); | |
| _sum12 = _mm_add_epi32(_sum12, _sum13); | |
| _sum0 = _mm_add_epi32(_sum0, _sum00); | |
| _sum0 = _mm_add_epi32(_sum0, _sum02); | |
| _sum1 = _mm_add_epi32(_sum1, _sum10); | |
| _sum1 = _mm_add_epi32(_sum1, _sum12); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r = _mm_setr_epi16(r0s[0], r0s[N], r1s[0], r1s[N], r2s[0], r2s[N], r3s[0], r3s[N]); | |
| __m128i _w0 = _mm_setr_epi16(kptr[0], kptr[2], kptr[0], kptr[2], kptr[0], kptr[2], kptr[0], kptr[2]); | |
| __m128i _w1 = _mm_setr_epi16(kptr[1], kptr[3], kptr[1], kptr[3], kptr[1], kptr[3], kptr[1], kptr[3]); | |
| _sum0 = _mm_maddd_epi16(_r, _w0, _sum0); | |
| _sum1 = _mm_maddd_epi16(_r, _w1, _sum1); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r, _w0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_r, _w1)); | |
| kptr += 4; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r = _mm_setr_epi16(r0s[0], r1s[0], r2s[0], r3s[0], r0s[0], r1s[0], r2s[0], r3s[0]); | |
| __m128i _w = _mm_setr_epi16(kptr[0], kptr[0], kptr[0], kptr[0], kptr[1], kptr[1], kptr[1], kptr[1]); | |
| __m128i _sl = _mm_mullo_epi16(_r, _w); | |
| __m128i _sh = _mm_mulhi_epi16(_r, _w); | |
| __m128i _s0 = _mm_unpacklo_epi16(_sl, _sh); | |
| __m128i _s1 = _mm_unpackhi_epi16(_sl, _sh); | |
| _sum0 = _mm_add_epi32(_sum0, _s0); | |
| _sum1 = _mm_add_epi32(_sum1, _s1); | |
| kptr += 2; | |
| } | |
| } | |
| } | |
| _mm_store_si128((__m128i*)outptr0, _sum0); | |
| _mm_store_si128((__m128i*)outptr1, _sum1); | |
| outptr0 += 4; | |
| outptr1 += 4; | |
| } | |
| for (; ij + 1 < outw * outh; ij += 2) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| int sum00 = 0; | |
| int sum01 = 0; | |
| int sum10 = 0; | |
| int sum11 = 0; | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 2); | |
| int q = 0; | |
| { | |
| __m512i _sum0 = _mm512_setzero_si512(); | |
| __m512i _sum1 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| } | |
| __m256i _val0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _val1 = _mm256_cvtepi8_epi16(_r1); | |
| __m512i _valval0 = _mm512_inserti64x4(_mm512_castsi256_si512(_val0), _val0, 1); | |
| __m512i _valval1 = _mm512_inserti64x4(_mm512_castsi256_si512(_val1), _val1, 1); | |
| __m512i _w = _mm512_cvtepi8_epi16(_mm256_load_si256((const __m256i*)kptr)); | |
| _sum0 = _mm512_dpwssd_epi32(_sum0, _valval0, _w); | |
| _sum1 = _mm512_dpwssd_epi32(_sum1, _valval1, _w); | |
| _sum0 = _mm512_add_epi32(_sum0, _mm512_madd_epi16(_valval0, _w)); | |
| _sum1 = _mm512_add_epi32(_sum1, _mm512_madd_epi16(_valval1, _w)); | |
| kptr += 32; | |
| } | |
| } | |
| __m256i _sum010 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum0, 0), _mm512_extracti64x4_epi64(_sum0, 1)); | |
| __m256i _sum011 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum1, 0), _mm512_extracti64x4_epi64(_sum1, 1)); | |
| __m128i _ss0 = _mm_add_epi32(_mm256_extracti128_si256(_sum010, 0), _mm256_extracti128_si256(_sum010, 1)); | |
| __m128i _ss1 = _mm_add_epi32(_mm256_extracti128_si256(_sum011, 0), _mm256_extracti128_si256(_sum011, 1)); | |
| sum00 += _mm_extract_epi32(_ss0, 0) + _mm_extract_epi32(_ss0, 1); | |
| sum10 += _mm_extract_epi32(_ss0, 2) + _mm_extract_epi32(_ss0, 3); | |
| sum01 += _mm_extract_epi32(_ss1, 0) + _mm_extract_epi32(_ss1, 1); | |
| sum11 += _mm_extract_epi32(_ss1, 2) + _mm_extract_epi32(_ss1, 3); | |
| } | |
| { | |
| __m256i _sum0 = _mm256_setzero_si256(); | |
| __m256i _sum1 = _mm256_setzero_si256(); | |
| __m128i _sum00 = _mm_setzero_si128(); | |
| __m128i _sum10 = _mm_setzero_si128(); | |
| __m128i _sum01 = _mm_setzero_si128(); | |
| __m128i _sum11 = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| _r1 = _mm_unpacklo_epi8(_r1, _mm_cmpgt_epi8(_mm_setzero_si128(), _r1)); | |
| __m128i _w01 = _mm_load_si128((const __m128i*)kptr); | |
| __m256i _w = _mm256_cvtepi8_epi16(_w01); | |
| __m256i _valval0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _r0, 1); | |
| __m256i _valval1 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r1), _r1, 1); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _valval0, _w); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _valval1, _w); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_valval0, _w)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_valval1, _w)); | |
| __m128i _extw01 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w01); | |
| __m128i _w0 = _mm_unpacklo_epi8(_w01, _extw01); | |
| __m128i _w1 = _mm_unpackhi_epi8(_w01, _extw01); | |
| _sum00 = _mm_maddd_epi16(_r0, _w0, _sum00); | |
| _sum10 = _mm_maddd_epi16(_r0, _w1, _sum10); | |
| _sum01 = _mm_maddd_epi16(_r1, _w0, _sum01); | |
| _sum11 = _mm_maddd_epi16(_r1, _w1, _sum11); | |
| _sum00 = _mm_add_epi32(_sum00, _mm_madd_epi16(_r0, _w0)); | |
| _sum10 = _mm_add_epi32(_sum10, _mm_madd_epi16(_r0, _w1)); | |
| _sum01 = _mm_add_epi32(_sum01, _mm_madd_epi16(_r1, _w0)); | |
| _sum11 = _mm_add_epi32(_sum11, _mm_madd_epi16(_r1, _w1)); | |
| kptr += 16; | |
| } | |
| } | |
| sum00 += _mm_reduce_add_epi32(_mm256_extracti128_si256(_sum0, 0)); | |
| sum10 += _mm_reduce_add_epi32(_mm256_extracti128_si256(_sum0, 1)); | |
| sum01 += _mm_reduce_add_epi32(_mm256_extracti128_si256(_sum1, 0)); | |
| sum11 += _mm_reduce_add_epi32(_mm256_extracti128_si256(_sum1, 1)); | |
| sum00 += _mm_reduce_add_epi32(_sum00); | |
| sum10 += _mm_reduce_add_epi32(_sum10); | |
| sum01 += _mm_reduce_add_epi32(_sum01); | |
| sum11 += _mm_reduce_add_epi32(_sum11); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum00 += r0s[0] * kptr[0]; | |
| sum10 += r0s[0] * kptr[1]; | |
| sum00 += r0s[N] * kptr[2]; | |
| sum10 += r0s[N] * kptr[3]; | |
| sum01 += r1s[0] * kptr[0]; | |
| sum11 += r1s[0] * kptr[1]; | |
| sum01 += r1s[N] * kptr[2]; | |
| sum11 += r1s[N] * kptr[3]; | |
| kptr += 4; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum00 += r0s[0] * kptr[0]; | |
| sum10 += r0s[0] * kptr[1]; | |
| sum01 += r1s[0] * kptr[0]; | |
| sum11 += r1s[0] * kptr[1]; | |
| kptr += 2; | |
| } | |
| } | |
| } | |
| outptr0[0] = sum00; | |
| outptr0[1] = sum01; | |
| outptr1[0] = sum10; | |
| outptr1[1] = sum11; | |
| outptr0 += 2; | |
| outptr1 += 2; | |
| } | |
| for (; ij < outw * outh; ij++) | |
| { | |
| const int i = ij / outw; | |
| const int j = ij % outw; | |
| int sum0 = 0; | |
| int sum1 = 0; | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 4 + (p % 4) / 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 2); | |
| int q = 0; | |
| { | |
| __m512i _sum01 = _mm512_setzero_si512(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| } | |
| __m256i _val = _mm256_cvtepi8_epi16(_r0); | |
| __m512i _valval = _mm512_inserti64x4(_mm512_castsi256_si512(_val), _val, 1); | |
| __m512i _w = _mm512_cvtepi8_epi16(_mm256_load_si256((const __m256i*)kptr)); | |
| _sum01 = _mm512_dpwssd_epi32(_sum01, _valval, _w); | |
| _sum01 = _mm512_add_epi32(_sum01, _mm512_madd_epi16(_valval, _w)); | |
| kptr += 32; | |
| } | |
| } | |
| __m256i _sum0101 = _mm256_hadd_epi32(_mm512_extracti64x4_epi64(_sum01, 0), _mm512_extracti64x4_epi64(_sum01, 1)); | |
| __m128i _ss = _mm_add_epi32(_mm256_extracti128_si256(_sum0101, 0), _mm256_extracti128_si256(_sum0101, 1)); | |
| sum0 += _mm_extract_epi32(_ss, 0) + _mm_extract_epi32(_ss, 1); | |
| sum1 += _mm_extract_epi32(_ss, 2) + _mm_extract_epi32(_ss, 3); | |
| } | |
| { | |
| __m256i _sum = _mm256_setzero_si256(); | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val32, 0), _mm256_extracti128_si256(_val32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| __m128i _w01 = _mm_load_si128((const __m128i*)kptr); | |
| __m256i _w = _mm256_cvtepi8_epi16(_w01); | |
| __m256i _rr0 = _mm256_inserti128_si256(_mm256_castsi128_si256(_r0), _r0, 1); | |
| _sum = _mm256_dpwssd_epi32(_sum, _rr0, _w); | |
| _sum = _mm256_add_epi32(_sum, _mm256_madd_epi16(_rr0, _w)); | |
| __m128i _extw01 = _mm_cmpgt_epi8(_mm_setzero_si128(), _w01); | |
| __m128i _w0 = _mm_unpacklo_epi8(_w01, _extw01); | |
| __m128i _w1 = _mm_unpackhi_epi8(_w01, _extw01); | |
| _sum0 = _mm_maddd_epi16(_r0, _w0, _sum0); | |
| _sum1 = _mm_maddd_epi16(_r0, _w1, _sum1); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r0, _w0)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_r0, _w1)); | |
| kptr += 16; | |
| } | |
| } | |
| sum0 += _mm_reduce_add_epi32(_mm256_extracti128_si256(_sum, 0)); | |
| sum1 += _mm_reduce_add_epi32(_mm256_extracti128_si256(_sum, 1)); | |
| sum0 += _mm_reduce_add_epi32(_sum0); | |
| sum1 += _mm_reduce_add_epi32(_sum1); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum0 += r0s[0] * kptr[0]; | |
| sum1 += r0s[0] * kptr[1]; | |
| sum0 += r0s[N] * kptr[2]; | |
| sum1 += r0s[N] * kptr[3]; | |
| kptr += 4; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum0 += r0s[0] * kptr[0]; | |
| sum1 += r0s[0] * kptr[1]; | |
| kptr += 2; | |
| } | |
| } | |
| } | |
| outptr0[0] = sum0; | |
| outptr1[0] = sum1; | |
| outptr0 += 1; | |
| outptr1 += 1; | |
| } | |
| } | |
| remain_outch_start += nn_outch * 2; | |
| for (int p = remain_outch_start; p < outch; p++) | |
| { | |
| int* outptr = top_blob.channel(p); | |
| int ij = 0; | |
| for (; ij + 3 < outw * outh; ij += 4) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int i2 = (ij + 2) / outw; | |
| const int i3 = (ij + 3) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| const int j2 = (ij + 2) % outw; | |
| const int j3 = (ij + 3) % outw; | |
| __m128i _sum = _mm_setzero_si128(); | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 4 + (p % 4) / 2 + p % 2); | |
| int q = 0; | |
| { | |
| __m256i _sum0 = _mm256_setzero_si256(); | |
| __m256i _sum1 = _mm256_setzero_si256(); | |
| __m256i _sum2 = _mm256_setzero_si256(); | |
| __m256i _sum3 = _mm256_setzero_si256(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| _r2 = _mm_load_si128((const __m128i*)r2s); | |
| _r3 = _mm_load_si128((const __m128i*)r3s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| __m128i _t4 = _mm_loadl_epi64((const __m128i*)r2s); | |
| __m128i _t5 = _mm_loadl_epi64((const __m128i*)(r2s + N)); | |
| __m128i _t6 = _mm_loadl_epi64((const __m128i*)r3s); | |
| __m128i _t7 = _mm_loadl_epi64((const __m128i*)(r3s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| _r2 = _mm_unpacklo_epi64(_t4, _t5); | |
| _r3 = _mm_unpacklo_epi64(_t6, _t7); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| _r2 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r2s), sizeof(signed char))); | |
| _r3 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r3s), sizeof(signed char))); | |
| } | |
| __m256i _val0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _val1 = _mm256_cvtepi8_epi16(_r1); | |
| __m256i _val2 = _mm256_cvtepi8_epi16(_r2); | |
| __m256i _val3 = _mm256_cvtepi8_epi16(_r3); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _val0, _w); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _val1, _w); | |
| _sum2 = _mm256_dpwssd_epi32(_sum2, _val2, _w); | |
| _sum3 = _mm256_dpwssd_epi32(_sum3, _val3, _w); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_val0, _w)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_val1, _w)); | |
| _sum2 = _mm256_add_epi32(_sum2, _mm256_madd_epi16(_val2, _w)); | |
| _sum3 = _mm256_add_epi32(_sum3, _mm256_madd_epi16(_val3, _w)); | |
| kptr += 16; | |
| } | |
| } | |
| _sum0 = _mm256_hadd_epi32(_sum0, _sum1); | |
| _sum2 = _mm256_hadd_epi32(_sum2, _sum3); | |
| _sum0 = _mm256_hadd_epi32(_sum0, _sum2); | |
| _sum = _mm_add_epi32(_sum, _mm256_extracti128_si256(_sum0, 0)); | |
| _sum = _mm_add_epi32(_sum, _mm256_extracti128_si256(_sum0, 1)); | |
| } | |
| { | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| __m128i _sum2 = _mm_setzero_si128(); | |
| __m128i _sum3 = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| const signed char* r2 = bottom_blob.channel(q / elempack).row<const signed char>(i2 * stride_h) + j2 * stride_w * elempack; | |
| const signed char* r3 = bottom_blob.channel(q / elempack).row<const signed char>(i3 * stride_h) + j3 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| __m128i _r2; | |
| __m128i _r3; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| _r2 = _mm_loadl_epi64((const __m128i*)r2s); | |
| _r3 = _mm_loadl_epi64((const __m128i*)r3s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| _r2 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char))); | |
| _r3 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val2_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r2s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val3_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r3s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r2 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val2_32, 0), _mm256_extracti128_si256(_val2_32, 1)); | |
| _r3 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val3_32, 0), _mm256_extracti128_si256(_val3_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r2 = _mm_setr_epi8(r2s[0], r2s[N], r2s[N * 2], r2s[N * 3], r2s[N * 4], r2s[N * 5], r2s[N * 6], r2s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r3 = _mm_setr_epi8(r3s[0], r3s[N], r3s[N * 2], r3s[N * 3], r3s[N * 4], r3s[N * 5], r3s[N * 6], r3s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r2 = _mm_cvtepi8_epi16(_r2); | |
| _r3 = _mm_cvtepi8_epi16(_r3); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| _r1 = _mm_unpacklo_epi8(_r1, _mm_cmpgt_epi8(_mm_setzero_si128(), _r1)); | |
| _r2 = _mm_unpacklo_epi8(_r2, _mm_cmpgt_epi8(_mm_setzero_si128(), _r2)); | |
| _r3 = _mm_unpacklo_epi8(_r3, _mm_cmpgt_epi8(_mm_setzero_si128(), _r3)); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _sum0 = _mm_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum1 = _mm_dpwssd_epi32(_sum1, _r1, _w); | |
| _sum2 = _mm_dpwssd_epi32(_sum2, _r2, _w); | |
| _sum3 = _mm_dpwssd_epi32(_sum3, _r3, _w); | |
| _sum0 = _mm_maddd_epi16(_r0, _w, _sum0); | |
| _sum1 = _mm_maddd_epi16(_r1, _w, _sum1); | |
| _sum2 = _mm_maddd_epi16(_r2, _w, _sum2); | |
| _sum3 = _mm_maddd_epi16(_r3, _w, _sum3); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r0, _w)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_r1, _w)); | |
| _sum2 = _mm_add_epi32(_sum2, _mm_madd_epi16(_r2, _w)); | |
| _sum3 = _mm_add_epi32(_sum3, _mm_madd_epi16(_r3, _w)); | |
| kptr += 8; | |
| } | |
| } | |
| __m128i _ss = _mm_hadd_epi32(_mm_hadd_epi32(_sum0, _sum1), _mm_hadd_epi32(_sum2, _sum3)); | |
| _sum = _mm_add_epi32(_sum, _ss); | |
| // transpose 4x4 | |
| __m128i _tmp0 = _mm_unpacklo_epi32(_sum0, _sum1); | |
| __m128i _tmp1 = _mm_unpacklo_epi32(_sum2, _sum3); | |
| __m128i _tmp2 = _mm_unpackhi_epi32(_sum0, _sum1); | |
| __m128i _tmp3 = _mm_unpackhi_epi32(_sum2, _sum3); | |
| _sum0 = _mm_unpacklo_epi64(_tmp0, _tmp1); | |
| _sum1 = _mm_unpackhi_epi64(_tmp0, _tmp1); | |
| _sum2 = _mm_unpacklo_epi64(_tmp2, _tmp3); | |
| _sum3 = _mm_unpackhi_epi64(_tmp2, _tmp3); | |
| _sum0 = _mm_add_epi32(_sum0, _sum1); | |
| _sum2 = _mm_add_epi32(_sum2, _sum3); | |
| _sum = _mm_add_epi32(_sum, _sum0); | |
| _sum = _mm_add_epi32(_sum, _sum2); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _r = _mm_setr_epi16(r0s[0], r0s[N], r1s[0], r1s[N], r2s[0], r2s[N], r3s[0], r3s[N]); | |
| __m128i _w = _mm_setr_epi16(kptr[0], kptr[1], kptr[0], kptr[1], kptr[0], kptr[1], kptr[0], kptr[1]); | |
| _sum = _mm_maddd_epi16(_r, _w, _sum); | |
| _sum = _mm_add_epi32(_sum, _mm_madd_epi16(_r, _w)); | |
| kptr += 2; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| const signed char* r2 = bottom_blob.channel(q).row<const signed char>(i2 * stride_h) + j2 * stride_w; | |
| const signed char* r3 = bottom_blob.channel(q).row<const signed char>(i3 * stride_h) + j3 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| const signed char* r2s = r2 + space_ofs[k]; | |
| const signed char* r3s = r3 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| __m128i _w = _mm_set1_epi16(kptr[0]); | |
| __m128i _r = _mm_setr_epi16(r0s[0], 0, r1s[0], 0, r2s[0], 0, r3s[0], 0); | |
| _sum = _mm_maccd_epi16(_r, _w, _sum); | |
| __m128i _r = _mm_setr_epi16(r0s[0], r1s[0], r2s[0], r3s[0], 0, 0, 0, 0); | |
| __m128i _sl = _mm_mullo_epi16(_r, _w); | |
| __m128i _sh = _mm_mulhi_epi16(_r, _w); | |
| __m128i _s0 = _mm_unpacklo_epi16(_sl, _sh); | |
| _sum = _mm_add_epi32(_sum, _s0); | |
| kptr += 1; | |
| } | |
| } | |
| } | |
| _mm_store_si128((__m128i*)outptr, _sum); | |
| outptr += 4; | |
| } | |
| for (; ij + 1 < outw * outh; ij += 2) | |
| { | |
| const int i0 = ij / outw; | |
| const int i1 = (ij + 1) / outw; | |
| const int j0 = ij % outw; | |
| const int j1 = (ij + 1) % outw; | |
| int sum0 = 0; | |
| int sum1 = 0; | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 2 + p % 2); | |
| int q = 0; | |
| { | |
| __m256i _sum0 = _mm256_setzero_si256(); | |
| __m256i _sum1 = _mm256_setzero_si256(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_load_si128((const __m128i*)r0s); | |
| _r1 = _mm_load_si128((const __m128i*)r1s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| __m128i _t2 = _mm_loadl_epi64((const __m128i*)r1s); | |
| __m128i _t3 = _mm_loadl_epi64((const __m128i*)(r1s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| _r1 = _mm_unpacklo_epi64(_t2, _t3); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| _r1 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r1s), sizeof(signed char))); | |
| } | |
| __m256i _val0 = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _val1 = _mm256_cvtepi8_epi16(_r1); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum0 = _mm256_dpwssd_epi32(_sum0, _val0, _w); | |
| _sum1 = _mm256_dpwssd_epi32(_sum1, _val1, _w); | |
| _sum0 = _mm256_add_epi32(_sum0, _mm256_madd_epi16(_val0, _w)); | |
| _sum1 = _mm256_add_epi32(_sum1, _mm256_madd_epi16(_val1, _w)); | |
| kptr += 16; | |
| } | |
| } | |
| __m128i _ss0 = _mm_add_epi32(_mm256_extracti128_si256(_sum0, 0), _mm256_extracti128_si256(_sum0, 1)); | |
| __m128i _ss1 = _mm_add_epi32(_mm256_extracti128_si256(_sum1, 0), _mm256_extracti128_si256(_sum1, 1)); | |
| sum0 += _mm_reduce_add_epi32(_ss0); | |
| sum1 += _mm_reduce_add_epi32(_ss1); | |
| } | |
| { | |
| __m128i _sum0 = _mm_setzero_si128(); | |
| __m128i _sum1 = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i0 * stride_h) + j0 * stride_w * elempack; | |
| const signed char* r1 = bottom_blob.channel(q / elempack).row<const signed char>(i1 * stride_h) + j1 * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| __m128i _r0; | |
| __m128i _r1; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| _r1 = _mm_loadl_epi64((const __m128i*)r1s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| _r1 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val0_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| __m256i _val1_32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r1s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val0_32, 0), _mm256_extracti128_si256(_val0_32, 1)); | |
| _r1 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val1_32, 0), _mm256_extracti128_si256(_val1_32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| _r1 = _mm_setr_epi8(r1s[0], r1s[N], r1s[N * 2], r1s[N * 3], r1s[N * 4], r1s[N * 5], r1s[N * 6], r1s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r1 = _mm_cvtepi8_epi16(_r1); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| _r1 = _mm_unpacklo_epi8(_r1, _mm_cmpgt_epi8(_mm_setzero_si128(), _r1)); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _sum0 = _mm_dpwssd_epi32(_sum0, _r0, _w); | |
| _sum1 = _mm_dpwssd_epi32(_sum1, _r1, _w); | |
| _sum0 = _mm_maddd_epi16(_r0, _w, _sum0); | |
| _sum1 = _mm_maddd_epi16(_r1, _w, _sum1); | |
| _sum0 = _mm_add_epi32(_sum0, _mm_madd_epi16(_r0, _w)); | |
| _sum1 = _mm_add_epi32(_sum1, _mm_madd_epi16(_r1, _w)); | |
| kptr += 8; | |
| } | |
| } | |
| sum0 += _mm_reduce_add_epi32(_sum0); | |
| sum1 += _mm_reduce_add_epi32(_sum1); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum0 += r0s[0] * kptr[0]; | |
| sum0 += r0s[N] * kptr[1]; | |
| sum1 += r1s[0] * kptr[0]; | |
| sum1 += r1s[N] * kptr[1]; | |
| kptr += 2; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i0 * stride_h) + j0 * stride_w; | |
| const signed char* r1 = bottom_blob.channel(q).row<const signed char>(i1 * stride_h) + j1 * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| const signed char* r1s = r1 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum0 += r0s[0] * kptr[0]; | |
| sum1 += r1s[0] * kptr[0]; | |
| kptr += 1; | |
| } | |
| } | |
| } | |
| outptr[0] = sum0; | |
| outptr[1] = sum1; | |
| outptr += 2; | |
| } | |
| for (; ij < outw * outh; ij++) | |
| { | |
| const int i = ij / outw; | |
| const int j = ij % outw; | |
| int sum = 0; | |
| const signed char* kptr = weight_data_tm.channel(p / 16 + (p % 16) / 8 + (p % 8) / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 8 + (p % 8) / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 4 + (p % 4) / 2 + p % 2); | |
| const signed char* kptr = weight_data_tm.channel(p / 2 + p % 2); | |
| int q = 0; | |
| { | |
| __m256i _sum = _mm256_setzero_si256(); | |
| for (; q + 15 < inch; q += 16) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 16) | |
| { | |
| _r0 = _mm_loadu_si128((const __m128i*)r0s); | |
| } | |
| else if (elempack == 8) | |
| { | |
| __m128i _t0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| __m128i _t1 = _mm_loadl_epi64((const __m128i*)(r0s + N)); | |
| _r0 = _mm_unpacklo_epi64(_t0, _t1); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m512i _vindex = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); | |
| _vindex = _mm512_mullo_epi32(_vindex, _mm512_set1_epi32(N)); | |
| _r0 = _mm512_cvtepi32_epi8(_mm512_i32gather_epi32(_vindex, (const int*)(r0s), sizeof(signed char))); | |
| } | |
| __m256i _val = _mm256_cvtepi8_epi16(_r0); | |
| __m256i _w = _mm256_cvtepi8_epi16(_mm_load_si128((const __m128i*)kptr)); | |
| _sum = _mm256_dpwssd_epi32(_sum, _val, _w); | |
| _sum = _mm256_add_epi32(_sum, _mm256_madd_epi16(_val, _w)); | |
| kptr += 16; | |
| } | |
| } | |
| __m128i _ss = _mm_add_epi32(_mm256_extracti128_si256(_sum, 0), _mm256_extracti128_si256(_sum, 1)); | |
| sum += _mm_reduce_add_epi32(_ss); | |
| } | |
| { | |
| __m128i _sum = _mm_setzero_si128(); | |
| for (; q + 7 < inch; q += 8) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q / elempack).row<const signed char>(i * stride_h) + j * stride_w * elempack; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| __m128i _r0; | |
| if (elempack == 8) | |
| { | |
| _r0 = _mm_loadl_epi64((const __m128i*)r0s); | |
| } | |
| else // if (elempack == 1) | |
| { | |
| __m256i _vindex = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); | |
| _vindex = _mm256_mullo_epi32(_vindex, _mm256_set1_epi32(N)); | |
| _r0 = _mm256_cvtepi32_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char))); | |
| __m128i _sindex8 = _mm_setr_epi8(0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); | |
| __m256i _sindex88 = _mm256_inserti128_si256(_mm256_castsi128_si256(_sindex8), _sindex8, 1); | |
| __m256i _val32 = _mm256_shuffle_epi8(_mm256_i32gather_epi32((const int*)r0s, _vindex, sizeof(signed char)), _sindex88); | |
| _r0 = _mm_unpacklo_epi32(_mm256_extracti128_si256(_val32, 0), _mm256_extracti128_si256(_val32, 1)); | |
| _r0 = _mm_setr_epi8(r0s[0], r0s[N], r0s[N * 2], r0s[N * 3], r0s[N * 4], r0s[N * 5], r0s[N * 6], r0s[N * 7], 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| _r0 = _mm_cvtepi8_epi16(_r0); | |
| _r0 = _mm_unpacklo_epi8(_r0, _mm_cmpgt_epi8(_mm_setzero_si128(), _r0)); | |
| __m128i _w = _mm_loadl_epi64((const __m128i*)kptr); | |
| _w = _mm_cvtepi8_epi16(_w); | |
| _w = _mm_unpacklo_epi8(_w, _mm_cmpgt_epi8(_mm_setzero_si128(), _w)); | |
| _sum = _mm_dpwssd_epi32(_sum, _r0, _w); | |
| _sum = _mm_maddd_epi16(_r0, _w, _sum); | |
| _sum = _mm_add_epi32(_sum, _mm_madd_epi16(_r0, _w)); | |
| kptr += 8; | |
| } | |
| } | |
| sum += _mm_reduce_add_epi32(_sum); | |
| } | |
| for (; q + 1 < inch; q += 2) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum += r0s[0] * kptr[0]; | |
| sum += r0s[N] * kptr[1]; | |
| kptr += 2; | |
| } | |
| } | |
| } | |
| for (; q < inch; q++) | |
| { | |
| const signed char* r0 = bottom_blob.channel(q).row<const signed char>(i * stride_h) + j * stride_w; | |
| for (int k = 0; k < maxk; k++) | |
| { | |
| const signed char* r0s = r0 + space_ofs[k]; | |
| // if (elempack == 1) | |
| { | |
| sum += r0s[0] * kptr[0]; | |
| kptr += 1; | |
| } | |
| } | |
| } | |
| outptr[0] = sum; | |
| outptr += 1; | |
| } | |
| } | |
| } | |