| @@ -0,0 +1,354 @@ | |||
| // Tencent is pleased to support the open source community by making ncnn available. | |||
| // | |||
| // Copyright (C) 2020 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. | |||
| static void conv1x1s1_sgemm_transform_kernel_pack4to8_fp16sa_neon(const Mat& kernel, Mat& kernel_tm_pack4to8, int inch, int outch) | |||
| { | |||
| // interleave | |||
| // src = inch-outch | |||
| // dst = 8b-4a-inch/4a-outch/8b | |||
| kernel_tm_pack4to8.create(8*4, inch / 4, outch / 8, (size_t)2u, 1); | |||
| int q = 0; | |||
| for (; q + 7 < outch; q += 8) | |||
| { | |||
| const float* k0 = (const float*)kernel + (q + 0) * inch; | |||
| const float* k1 = (const float*)kernel + (q + 1) * inch; | |||
| const float* k2 = (const float*)kernel + (q + 2) * inch; | |||
| const float* k3 = (const float*)kernel + (q + 3) * inch; | |||
| const float* k4 = (const float*)kernel + (q + 4) * inch; | |||
| const float* k5 = (const float*)kernel + (q + 5) * inch; | |||
| const float* k6 = (const float*)kernel + (q + 6) * inch; | |||
| const float* k7 = (const float*)kernel + (q + 7) * inch; | |||
| __fp16* g0 = kernel_tm_pack4to8.channel(q / 8); | |||
| for (int p = 0; p + 3 < inch; p += 4) | |||
| { | |||
| for (int i = 0; i < 4; i++) | |||
| { | |||
| g0[0] = (__fp16)k0[i]; | |||
| g0[1] = (__fp16)k1[i]; | |||
| g0[2] = (__fp16)k2[i]; | |||
| g0[3] = (__fp16)k3[i]; | |||
| g0[4] = (__fp16)k4[i]; | |||
| g0[5] = (__fp16)k5[i]; | |||
| g0[6] = (__fp16)k6[i]; | |||
| g0[7] = (__fp16)k7[i]; | |||
| g0 += 8; | |||
| } | |||
| k0 += 4; | |||
| k1 += 4; | |||
| k2 += 4; | |||
| k3 += 4; | |||
| k4 += 4; | |||
| k5 += 4; | |||
| k6 += 4; | |||
| k7 += 4; | |||
| } | |||
| } | |||
| } | |||
| static void conv1x1s1_sgemm_pack4to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt) | |||
| { | |||
| int w = bottom_blob.w; | |||
| int h = bottom_blob.h; | |||
| int inch = bottom_blob.c; | |||
| int outch = top_blob.c; | |||
| size_t elemsize = bottom_blob.elemsize; | |||
| int elempack = bottom_blob.elempack; | |||
| const int size = w * h; | |||
| const __fp16* bias = _bias; | |||
| // interleave | |||
| Mat tmp; | |||
| if (size >= 8) | |||
| tmp.create(8, inch, size / 8 + size % 8, elemsize, elempack, opt.workspace_allocator); | |||
| else // if (size >= 1) | |||
| tmp.create(1, inch, size, elemsize, elempack, opt.workspace_allocator); | |||
| { | |||
| int nn_size; | |||
| int remain_size_start = 0; | |||
| nn_size = (size - remain_size_start) >> 3; | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int ii = 0; ii < nn_size; ii++) | |||
| { | |||
| int i = remain_size_start + ii * 8; | |||
| const __fp16* img0 = bottom_blob.channel(0); | |||
| img0 += i * 4; | |||
| __fp16* tmpptr = tmp.channel(i / 8); | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| // transpose 4x8 | |||
| asm volatile( | |||
| "prfm pldl1keep, [%0, #512] \n" | |||
| "ld4 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0] \n" | |||
| "st1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%1], #64 \n" | |||
| : "=r"(img0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(img0), | |||
| "1"(tmpptr) | |||
| : "memory", "v0", "v1", "v2", "v3"); | |||
| img0 += bottom_blob.cstep * 4; | |||
| } | |||
| } | |||
| remain_size_start += nn_size << 3; | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int i = remain_size_start; i < size; i++) | |||
| { | |||
| const __fp16* img0 = bottom_blob.channel(0); | |||
| img0 += i * 4; | |||
| __fp16* tmpptr = tmp.channel(i / 8 + i % 8); | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| asm volatile( | |||
| "prfm pldl1keep, [%0, #64] \n" | |||
| "ld1 {v0.4h}, [%0] \n" | |||
| "st1 {v0.4h}, [%1], #8 \n" | |||
| : "=r"(img0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(img0), | |||
| "1"(tmpptr) | |||
| : "memory", "v0"); | |||
| img0 += bottom_blob.cstep * 4; | |||
| } | |||
| } | |||
| } | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int p = 0; p < outch; p++) | |||
| { | |||
| __fp16* outptr0 = top_blob.channel(p); | |||
| const __fp16 zeros[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; | |||
| const __fp16* biasptr = bias ? bias + p * 8 : zeros; | |||
| int i = 0; | |||
| for (; i + 7 < size; i += 8) | |||
| { | |||
| __fp16* tmpptr = tmp.channel(i / 8); | |||
| const __fp16* kptr = kernel.channel(p); | |||
| int nn = inch; // inch always > 0 | |||
| asm volatile( | |||
| "ld1 {v16.8h}, [%8] \n" | |||
| "mov v17.16b, v16.16b \n" | |||
| "mov v18.16b, v16.16b \n" | |||
| "mov v19.16b, v16.16b \n" | |||
| "mov v20.16b, v16.16b \n" | |||
| "mov v21.16b, v16.16b \n" | |||
| "mov v22.16b, v16.16b \n" | |||
| "mov v23.16b, v16.16b \n" | |||
| "0: \n" | |||
| "prfm pldl1keep, [%2, #512] \n" | |||
| "ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%2], #64 \n" // r0123 | |||
| "prfm pldl1keep, [%3, #512] \n" | |||
| "ld1 {v8.8h, v9.8h, v10.8h, v11.8h}, [%3], #64 \n" // w0123 | |||
| "fmla v16.8h, v8.8h, v0.h[0] \n" | |||
| "fmla v17.8h, v8.8h, v0.h[1] \n" | |||
| "fmla v18.8h, v8.8h, v0.h[2] \n" | |||
| "fmla v19.8h, v8.8h, v0.h[3] \n" | |||
| "fmla v20.8h, v8.8h, v0.h[4] \n" | |||
| "fmla v21.8h, v8.8h, v0.h[5] \n" | |||
| "fmla v22.8h, v8.8h, v0.h[6] \n" | |||
| "fmla v23.8h, v8.8h, v0.h[7] \n" | |||
| "fmla v16.8h, v9.8h, v1.h[0] \n" | |||
| "fmla v17.8h, v9.8h, v1.h[1] \n" | |||
| "fmla v18.8h, v9.8h, v1.h[2] \n" | |||
| "fmla v19.8h, v9.8h, v1.h[3] \n" | |||
| "fmla v20.8h, v9.8h, v1.h[4] \n" | |||
| "fmla v21.8h, v9.8h, v1.h[5] \n" | |||
| "fmla v22.8h, v9.8h, v1.h[6] \n" | |||
| "fmla v23.8h, v9.8h, v1.h[7] \n" | |||
| "fmla v16.8h, v10.8h, v2.h[0] \n" | |||
| "fmla v17.8h, v10.8h, v2.h[1] \n" | |||
| "fmla v18.8h, v10.8h, v2.h[2] \n" | |||
| "fmla v19.8h, v10.8h, v2.h[3] \n" | |||
| "fmla v20.8h, v10.8h, v2.h[4] \n" | |||
| "fmla v21.8h, v10.8h, v2.h[5] \n" | |||
| "fmla v22.8h, v10.8h, v2.h[6] \n" | |||
| "fmla v23.8h, v10.8h, v2.h[7] \n" | |||
| "fmla v16.8h, v11.8h, v3.h[0] \n" | |||
| "fmla v17.8h, v11.8h, v3.h[1] \n" | |||
| "fmla v18.8h, v11.8h, v3.h[2] \n" | |||
| "fmla v19.8h, v11.8h, v3.h[3] \n" | |||
| "fmla v20.8h, v11.8h, v3.h[4] \n" | |||
| "fmla v21.8h, v11.8h, v3.h[5] \n" | |||
| "fmla v22.8h, v11.8h, v3.h[6] \n" | |||
| "fmla v23.8h, v11.8h, v3.h[7] \n" | |||
| "subs %w0, %w0, #1 \n" | |||
| "bne 0b \n" | |||
| "st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n" | |||
| "st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n" | |||
| : "=r"(nn), // %0 | |||
| "=r"(outptr0), // %1 | |||
| "=r"(tmpptr), // %2 | |||
| "=r"(kptr) // %3 | |||
| : "0"(nn), | |||
| "1"(outptr0), | |||
| "2"(tmpptr), | |||
| "3"(kptr), | |||
| "r"(biasptr) // %8 | |||
| : "cc", "memory", "v0", "v1", "v2", "v3", "v8", "v9", "v10", "v11", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); | |||
| } | |||
| for (; i < size; i++) | |||
| { | |||
| __fp16* tmpptr = tmp.channel(i / 8 + i % 8); | |||
| const __fp16* kptr = kernel.channel(p); | |||
| float16x8_t _sum0 = vld1q_f16(biasptr); | |||
| int q = 0; | |||
| for (; q < inch; q++) | |||
| { | |||
| float16x4_t _r0 = vld1_f16(tmpptr); | |||
| float16x8_t _k0 = vld1q_f16(kptr); | |||
| float16x8_t _k1 = vld1q_f16(kptr + 8); | |||
| float16x8_t _k2 = vld1q_f16(kptr + 16); | |||
| float16x8_t _k3 = vld1q_f16(kptr + 24); | |||
| _sum0 = vfmaq_lane_f16(_sum0, _k0, _r0, 0); | |||
| _sum0 = vfmaq_lane_f16(_sum0, _k1, _r0, 1); | |||
| _sum0 = vfmaq_lane_f16(_sum0, _k2, _r0, 2); | |||
| _sum0 = vfmaq_lane_f16(_sum0, _k3, _r0, 3); | |||
| kptr += 32; | |||
| tmpptr += 4; | |||
| } | |||
| vst1q_f16(outptr0, _sum0); | |||
| outptr0 += 8; | |||
| } | |||
| } | |||
| // // NOTE sgemm | |||
| // for (; p<outch; p++) | |||
| // { | |||
| // Mat out0 = top_blob.channel(p); | |||
| // | |||
| // const __fp16 bias0 = bias ? bias[p] : 0.f; | |||
| // | |||
| // __fp16* outptr0 = out0; | |||
| // | |||
| // for (int i=0; i<size; i++) | |||
| // { | |||
| // __fp16 sum = bias0; | |||
| // | |||
| // const __fp16* kptr = _kernel.channel(p); | |||
| // | |||
| // for (int q=0; q<inch; q++) | |||
| // { | |||
| // const __fp16* img0 = bottom_blob.channel(q); | |||
| // | |||
| // sum += img0[i] * kptr[0]; | |||
| // kptr ++; | |||
| // } | |||
| // | |||
| // outptr0[i] = sum; | |||
| // } | |||
| // } | |||
| } | |||
| static void conv1x1s2_pack4to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt) | |||
| { | |||
| int w = bottom_blob.w; | |||
| int channels = bottom_blob.c; | |||
| size_t elemsize = bottom_blob.elemsize; | |||
| int elempack = bottom_blob.elempack; | |||
| int outw = top_blob.w; | |||
| int outh = top_blob.h; | |||
| const int tailstep = (w - 2 * outw + w) * 4; | |||
| Mat bottom_blob_shrinked; | |||
| bottom_blob_shrinked.create(outw, outh, channels, elemsize, elempack, opt.workspace_allocator); | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int p = 0; p < channels; p++) | |||
| { | |||
| const __fp16* r0 = bottom_blob.channel(p); | |||
| __fp16* outptr = bottom_blob_shrinked.channel(p); | |||
| for (int i = 0; i < outh; i++) | |||
| { | |||
| int j = 0; | |||
| for (; j + 3 < outw; j += 4) | |||
| { | |||
| float16x4_t _v0 = vld1_f16(r0); | |||
| float16x4_t _v1 = vld1_f16(r0 + 8); | |||
| float16x4_t _v2 = vld1_f16(r0 + 16); | |||
| float16x4_t _v3 = vld1_f16(r0 + 24); | |||
| vst1_f16(outptr, _v0); | |||
| vst1_f16(outptr + 4, _v1); | |||
| vst1_f16(outptr + 8, _v2); | |||
| vst1_f16(outptr + 12, _v3); | |||
| r0 += 32; | |||
| outptr += 16; | |||
| } | |||
| for (; j + 1 < outw; j += 2) | |||
| { | |||
| float16x4_t _v0 = vld1_f16(r0); | |||
| float16x4_t _v1 = vld1_f16(r0 + 8); | |||
| vst1_f16(outptr, _v0); | |||
| vst1_f16(outptr + 4, _v1); | |||
| r0 += 16; | |||
| outptr += 8; | |||
| } | |||
| for (; j < outw; j++) | |||
| { | |||
| float16x4_t _v = vld1_f16(r0); | |||
| vst1_f16(outptr, _v); | |||
| r0 += 8; | |||
| outptr += 4; | |||
| } | |||
| r0 += tailstep; | |||
| } | |||
| } | |||
| conv1x1s1_sgemm_pack4to8_fp16sa_neon(bottom_blob_shrinked, top_blob, kernel, _bias, opt); | |||
| } | |||
| @@ -115,18 +115,18 @@ static void conv1x1s1_sgemm_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_b | |||
| "sub %0, %0, #128 \n" | |||
| "uzp1 v20.8h, v0.8h, v4.8h \n"// 0 | |||
| "uzp1 v21.8h, v16.8h, v1.8h \n"// 1 | |||
| "uzp1 v22.8h, v5.8h, v17.8h \n"// 2 | |||
| "uzp1 v23.8h, v2.8h, v6.8h \n"// 3 | |||
| "uzp1 v24.8h, v18.8h, v3.8h \n"// 4 | |||
| "uzp1 v25.8h, v7.8h, v19.8h \n"// 5 | |||
| "uzp2 v26.8h, v0.8h, v4.8h \n"// 6 | |||
| "uzp2 v27.8h, v16.8h, v1.8h \n"// 7 | |||
| "uzp2 v28.8h, v5.8h, v17.8h \n"// 8 | |||
| "uzp2 v29.8h, v2.8h, v6.8h \n"// 9 | |||
| "uzp2 v30.8h, v18.8h, v3.8h \n"// 10 | |||
| "uzp2 v31.8h, v7.8h, v19.8h \n"// 11 | |||
| "uzp1 v20.8h, v0.8h, v4.8h \n" // 0 | |||
| "uzp1 v21.8h, v16.8h, v1.8h \n" // 1 | |||
| "uzp1 v22.8h, v5.8h, v17.8h \n" // 2 | |||
| "uzp1 v23.8h, v2.8h, v6.8h \n" // 3 | |||
| "uzp1 v24.8h, v18.8h, v3.8h \n" // 4 | |||
| "uzp1 v25.8h, v7.8h, v19.8h \n" // 5 | |||
| "uzp2 v26.8h, v0.8h, v4.8h \n" // 6 | |||
| "uzp2 v27.8h, v16.8h, v1.8h \n" // 7 | |||
| "uzp2 v28.8h, v5.8h, v17.8h \n" // 8 | |||
| "uzp2 v29.8h, v2.8h, v6.8h \n" // 9 | |||
| "uzp2 v30.8h, v18.8h, v3.8h \n" // 10 | |||
| "uzp2 v31.8h, v7.8h, v19.8h \n" // 11 | |||
| "st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n" | |||
| "st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%1], #64 \n" | |||
| @@ -0,0 +1,640 @@ | |||
| // Tencent is pleased to support the open source community by making ncnn available. | |||
| // | |||
| // Copyright (C) 2020 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. | |||
| static void conv1x1s1_sgemm_transform_kernel_pack8to4_fp16sa_neon(const Mat& kernel, Mat& kernel_tm_pack8to4, int inch, int outch) | |||
| { | |||
| // interleave | |||
| // src = inch-outch | |||
| // dst = 4b-8a-inch/8a-outch/4 | |||
| kernel_tm_pack8to4.create(4*8, inch / 8, outch / 8 + (outch % 8) / 4, (size_t)2u * 2, 2); | |||
| int p = 0; | |||
| for (; p + 7 < outch; p += 8) | |||
| { | |||
| const float* k0 = (const float*)kernel + (p + 0) * inch; | |||
| const float* k1 = (const float*)kernel + (p + 1) * inch; | |||
| const float* k2 = (const float*)kernel + (p + 2) * inch; | |||
| const float* k3 = (const float*)kernel + (p + 3) * inch; | |||
| const float* k4 = (const float*)kernel + (p + 4) * inch; | |||
| const float* k5 = (const float*)kernel + (p + 5) * inch; | |||
| const float* k6 = (const float*)kernel + (p + 6) * inch; | |||
| const float* k7 = (const float*)kernel + (p + 7) * inch; | |||
| __fp16* g0 = kernel_tm_pack8to4.channel(p / 8); | |||
| for (int q = 0; q + 7 < inch; q += 8) | |||
| { | |||
| for (int i = 0; i < 8; i++) | |||
| { | |||
| g0[0] = (__fp16)k0[i]; | |||
| g0[1] = (__fp16)k1[i]; | |||
| g0[2] = (__fp16)k2[i]; | |||
| g0[3] = (__fp16)k3[i]; | |||
| g0[4] = (__fp16)k4[i]; | |||
| g0[5] = (__fp16)k5[i]; | |||
| g0[6] = (__fp16)k6[i]; | |||
| g0[7] = (__fp16)k7[i]; | |||
| g0 += 8; | |||
| } | |||
| k0 += 8; | |||
| k1 += 8; | |||
| k2 += 8; | |||
| k3 += 8; | |||
| k4 += 8; | |||
| k5 += 8; | |||
| k6 += 8; | |||
| k7 += 8; | |||
| } | |||
| } | |||
| for (; p + 3 < outch; p += 4) | |||
| { | |||
| const float* k0 = (const float*)kernel + (p + 0) * inch; | |||
| const float* k1 = (const float*)kernel + (p + 1) * inch; | |||
| const float* k2 = (const float*)kernel + (p + 2) * inch; | |||
| const float* k3 = (const float*)kernel + (p + 3) * inch; | |||
| __fp16* g0 = kernel_tm_pack8to4.channel(p / 8 + (p % 8) / 4); | |||
| for (int q = 0; q + 7 < inch; q += 8) | |||
| { | |||
| for (int i = 0; i < 8; i++) | |||
| { | |||
| g0[0] = (__fp16)k0[i]; | |||
| g0[1] = (__fp16)k1[i]; | |||
| g0[2] = (__fp16)k2[i]; | |||
| g0[3] = (__fp16)k3[i]; | |||
| g0 += 4; | |||
| } | |||
| k0 += 8; | |||
| k1 += 8; | |||
| k2 += 8; | |||
| k3 += 8; | |||
| } | |||
| } | |||
| } | |||
| static void conv1x1s1_sgemm_pack8to4_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt) | |||
| { | |||
| int w = bottom_blob.w; | |||
| int h = bottom_blob.h; | |||
| int inch = bottom_blob.c; | |||
| int outch = top_blob.c; | |||
| size_t elemsize = bottom_blob.elemsize; | |||
| int elempack = bottom_blob.elempack; | |||
| const int size = w * h; | |||
| const __fp16* bias = _bias; | |||
| // interleave | |||
| Mat tmp; | |||
| if (size >= 8) | |||
| tmp.create(8, inch, size / 8 + size % 8, elemsize, elempack, opt.workspace_allocator); | |||
| else // if (size >= 1) | |||
| tmp.create(1, inch, size, elemsize, elempack, opt.workspace_allocator); | |||
| { | |||
| int nn_size; | |||
| int remain_size_start = 0; | |||
| nn_size = (size - remain_size_start) >> 3; | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int ii = 0; ii < nn_size; ii++) | |||
| { | |||
| int i = remain_size_start + ii * 8; | |||
| const __fp16* img0 = bottom_blob.channel(0); | |||
| img0 += i * 8; | |||
| __fp16* tmpptr = tmp.channel(i / 8); | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| // transpose 8x8 | |||
| asm volatile( | |||
| "prfm pldl1keep, [%0, #512] \n" | |||
| "ld4 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0], #64 \n" | |||
| "ld4 {v4.8h, v5.8h, v6.8h, v7.8h}, [%0] \n" | |||
| "sub %0, %0, #64 \n" | |||
| "uzp1 v16.8h, v0.8h, v4.8h \n" | |||
| "uzp2 v20.8h, v0.8h, v4.8h \n" | |||
| "uzp1 v17.8h, v1.8h, v5.8h \n" | |||
| "uzp2 v21.8h, v1.8h, v5.8h \n" | |||
| "uzp1 v18.8h, v2.8h, v6.8h \n" | |||
| "uzp2 v22.8h, v2.8h, v6.8h \n" | |||
| "uzp1 v19.8h, v3.8h, v7.8h \n" | |||
| "uzp2 v23.8h, v3.8h, v7.8h \n" | |||
| "st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n" | |||
| "st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n" | |||
| : "=r"(img0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(img0), | |||
| "1"(tmpptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23"); | |||
| img0 += bottom_blob.cstep * 8; | |||
| } | |||
| } | |||
| remain_size_start += nn_size << 3; | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int i = remain_size_start; i < size; i++) | |||
| { | |||
| const __fp16* img0 = bottom_blob.channel(0); | |||
| img0 += i * 8; | |||
| __fp16* tmpptr = tmp.channel(i / 8 + i % 8); | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| asm volatile( | |||
| "prfm pldl1keep, [%0, #128] \n" | |||
| "ld1 {v0.8h}, [%0] \n" | |||
| "st1 {v0.8h}, [%1], #16 \n" | |||
| : "=r"(img0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(img0), | |||
| "1"(tmpptr) | |||
| : "memory", "v0"); | |||
| img0 += bottom_blob.cstep * 8; | |||
| } | |||
| } | |||
| } | |||
| int nn_outch = 0; | |||
| int remain_outch_start = 0; | |||
| nn_outch = outch >> 1; | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int pp = 0; pp < nn_outch; pp++) | |||
| { | |||
| int p = pp * 2; | |||
| __fp16* outptr0 = top_blob.channel(p); | |||
| __fp16* outptr1 = top_blob.channel(p + 1); | |||
| const __fp16 zeros[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; | |||
| const __fp16* biasptr = bias ? bias + p : zeros; | |||
| float16x8_t _bias0 = vld1q_f16(biasptr); | |||
| int i = 0; | |||
| for (; i + 7 < size; i += 8) | |||
| { | |||
| __fp16* tmpptr = tmp.channel(i / 8); | |||
| const __fp16* kptr = kernel.channel(p / 2); | |||
| int nn = inch; // inch always > 0 | |||
| asm volatile( | |||
| "mov v24.16b, %10.16b \n" | |||
| "mov v25.16b, %10.16b \n" | |||
| "mov v26.16b, %10.16b \n" | |||
| "mov v27.16b, %10.16b \n" | |||
| "mov v28.16b, %10.16b \n" | |||
| "mov v29.16b, %10.16b \n" | |||
| "mov v30.16b, %10.16b \n" | |||
| "mov v31.16b, %10.16b \n" | |||
| "0: \n" | |||
| "prfm pldl1keep, [%4, #512] \n" | |||
| "ld1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%4], #64 \n" | |||
| "prfm pldl1keep, [%3, #512] \n" | |||
| "ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%3], #64 \n" | |||
| "fmla v24.8h, v16.8h, v0.h[0] \n" | |||
| "fmla v25.8h, v16.8h, v0.h[1] \n" | |||
| "fmla v26.8h, v16.8h, v0.h[2] \n" | |||
| "fmla v27.8h, v16.8h, v0.h[3] \n" | |||
| "fmla v28.8h, v16.8h, v0.h[4] \n" | |||
| "fmla v29.8h, v16.8h, v0.h[5] \n" | |||
| "fmla v30.8h, v16.8h, v0.h[6] \n" | |||
| "fmla v31.8h, v16.8h, v0.h[7] \n" | |||
| "fmla v24.8h, v17.8h, v1.h[0] \n" | |||
| "fmla v25.8h, v17.8h, v1.h[1] \n" | |||
| "fmla v26.8h, v17.8h, v1.h[2] \n" | |||
| "fmla v27.8h, v17.8h, v1.h[3] \n" | |||
| "fmla v28.8h, v17.8h, v1.h[4] \n" | |||
| "fmla v29.8h, v17.8h, v1.h[5] \n" | |||
| "fmla v30.8h, v17.8h, v1.h[6] \n" | |||
| "fmla v31.8h, v17.8h, v1.h[7] \n" | |||
| "prfm pldl1keep, [%4, #512] \n" | |||
| "ld1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%4], #64 \n" | |||
| "fmla v24.8h, v18.8h, v2.h[0] \n" | |||
| "fmla v25.8h, v18.8h, v2.h[1] \n" | |||
| "fmla v26.8h, v18.8h, v2.h[2] \n" | |||
| "fmla v27.8h, v18.8h, v2.h[3] \n" | |||
| "fmla v28.8h, v18.8h, v2.h[4] \n" | |||
| "fmla v29.8h, v18.8h, v2.h[5] \n" | |||
| "fmla v30.8h, v18.8h, v2.h[6] \n" | |||
| "fmla v31.8h, v18.8h, v2.h[7] \n" | |||
| "prfm pldl1keep, [%3, #512] \n" | |||
| "ld1 {v4.8h, v5.8h, v6.8h, v7.8h}, [%3], #64 \n" | |||
| "fmla v24.8h, v19.8h, v3.h[0] \n" | |||
| "fmla v25.8h, v19.8h, v3.h[1] \n" | |||
| "fmla v26.8h, v19.8h, v3.h[2] \n" | |||
| "fmla v27.8h, v19.8h, v3.h[3] \n" | |||
| "fmla v28.8h, v19.8h, v3.h[4] \n" | |||
| "fmla v29.8h, v19.8h, v3.h[5] \n" | |||
| "fmla v30.8h, v19.8h, v3.h[6] \n" | |||
| "fmla v31.8h, v19.8h, v3.h[7] \n" | |||
| "fmla v24.8h, v20.8h, v4.h[0] \n" | |||
| "fmla v25.8h, v20.8h, v4.h[1] \n" | |||
| "fmla v26.8h, v20.8h, v4.h[2] \n" | |||
| "fmla v27.8h, v20.8h, v4.h[3] \n" | |||
| "fmla v28.8h, v20.8h, v4.h[4] \n" | |||
| "fmla v29.8h, v20.8h, v4.h[5] \n" | |||
| "fmla v30.8h, v20.8h, v4.h[6] \n" | |||
| "fmla v31.8h, v20.8h, v4.h[7] \n" | |||
| "fmla v24.8h, v21.8h, v5.h[0] \n" | |||
| "fmla v25.8h, v21.8h, v5.h[1] \n" | |||
| "fmla v26.8h, v21.8h, v5.h[2] \n" | |||
| "fmla v27.8h, v21.8h, v5.h[3] \n" | |||
| "fmla v28.8h, v21.8h, v5.h[4] \n" | |||
| "fmla v29.8h, v21.8h, v5.h[5] \n" | |||
| "fmla v30.8h, v21.8h, v5.h[6] \n" | |||
| "fmla v31.8h, v21.8h, v5.h[7] \n" | |||
| "fmla v24.8h, v22.8h, v6.h[0] \n" | |||
| "fmla v25.8h, v22.8h, v6.h[1] \n" | |||
| "fmla v26.8h, v22.8h, v6.h[2] \n" | |||
| "fmla v27.8h, v22.8h, v6.h[3] \n" | |||
| "fmla v28.8h, v22.8h, v6.h[4] \n" | |||
| "fmla v29.8h, v22.8h, v6.h[5] \n" | |||
| "fmla v30.8h, v22.8h, v6.h[6] \n" | |||
| "fmla v31.8h, v22.8h, v6.h[7] \n" | |||
| "subs %w0, %w0, #1 \n" | |||
| "fmla v24.8h, v23.8h, v7.h[0] \n" | |||
| "fmla v25.8h, v23.8h, v7.h[1] \n" | |||
| "fmla v26.8h, v23.8h, v7.h[2] \n" | |||
| "fmla v27.8h, v23.8h, v7.h[3] \n" | |||
| "fmla v28.8h, v23.8h, v7.h[4] \n" | |||
| "fmla v29.8h, v23.8h, v7.h[5] \n" | |||
| "fmla v30.8h, v23.8h, v7.h[6] \n" | |||
| "fmla v31.8h, v23.8h, v7.h[7] \n" | |||
| "bne 0b \n" | |||
| "st1 {v24.4h, v25.4h, v26.4h, v27.4h}, [%1], #32 \n" | |||
| "st1 {v28.4h, v29.4h, v30.4h, v31.4h}, [%1], #32 \n" | |||
| "ext v24.16b, v24.16b, v24.16b, #8 \n" | |||
| "ext v25.16b, v25.16b, v25.16b, #8 \n" | |||
| "ext v26.16b, v26.16b, v26.16b, #8 \n" | |||
| "ext v27.16b, v27.16b, v27.16b, #8 \n" | |||
| "ext v28.16b, v28.16b, v28.16b, #8 \n" | |||
| "ext v29.16b, v29.16b, v29.16b, #8 \n" | |||
| "ext v30.16b, v30.16b, v30.16b, #8 \n" | |||
| "ext v31.16b, v31.16b, v31.16b, #8 \n" | |||
| "st1 {v24.4h, v25.4h, v26.4h, v27.4h}, [%2], #32 \n" | |||
| "st1 {v28.4h, v29.4h, v30.4h, v31.4h}, [%2], #32 \n" | |||
| : "=r"(nn), // %0 | |||
| "=r"(outptr0), // %1 | |||
| "=r"(outptr1), // %2 | |||
| "=r"(tmpptr), // %3 | |||
| "=r"(kptr) // %4 | |||
| : "0"(nn), | |||
| "1"(outptr0), | |||
| "2"(outptr1), | |||
| "3"(tmpptr), | |||
| "4"(kptr), | |||
| "w"(_bias0) // %10 | |||
| : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; i < size; i++) | |||
| { | |||
| __fp16* tmpptr = tmp.channel(i / 8 + i % 8); | |||
| const __fp16* kptr = kernel.channel(p / 2); | |||
| float16x8_t _sum0 = _bias0; | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| float16x8_t _r0 = vld1q_f16(tmpptr); | |||
| float16x8_t _k0 = vld1q_f16(kptr); | |||
| float16x8_t _k1 = vld1q_f16(kptr + 8); | |||
| float16x8_t _k2 = vld1q_f16(kptr + 16); | |||
| float16x8_t _k3 = vld1q_f16(kptr + 24); | |||
| float16x8_t _k4 = vld1q_f16(kptr + 32); | |||
| float16x8_t _k5 = vld1q_f16(kptr + 40); | |||
| float16x8_t _k6 = vld1q_f16(kptr + 48); | |||
| float16x8_t _k7 = vld1q_f16(kptr + 56); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k0, _r0, 0); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k1, _r0, 1); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k2, _r0, 2); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k3, _r0, 3); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k4, _r0, 4); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k5, _r0, 5); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k6, _r0, 6); | |||
| _sum0 = vfmaq_laneq_f16(_sum0, _k7, _r0, 7); | |||
| kptr += 64; | |||
| tmpptr += 8; | |||
| } | |||
| vst1_f16(outptr0, vget_low_f16(_sum0)); | |||
| vst1_f16(outptr1, vget_high_f16(_sum0)); | |||
| outptr0 += 4; | |||
| outptr1 += 4; | |||
| } | |||
| } | |||
| remain_outch_start += nn_outch << 1; | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int p = remain_outch_start; p < outch; p++) | |||
| { | |||
| __fp16* outptr0 = top_blob.channel(p); | |||
| const __fp16 zeros[4] = {0.f, 0.f, 0.f, 0.f}; | |||
| const __fp16* biasptr = bias ? bias + p * 4 : zeros; | |||
| float16x4_t _bias0 = vld1_f16(biasptr); | |||
| int i = 0; | |||
| for (; i + 7 < size; i += 8) | |||
| { | |||
| __fp16* tmpptr = tmp.channel(i / 8); | |||
| const __fp16* kptr = kernel.channel(p / 2 + p % 2); | |||
| float16x4_t _sum0 = _bias0; | |||
| float16x4_t _sum1 = _bias0; | |||
| float16x4_t _sum2 = _bias0; | |||
| float16x4_t _sum3 = _bias0; | |||
| float16x4_t _sum4 = _bias0; | |||
| float16x4_t _sum5 = _bias0; | |||
| float16x4_t _sum6 = _bias0; | |||
| float16x4_t _sum7 = _bias0; | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| float16x8_t _r0 = vld1q_f16(tmpptr); | |||
| float16x8_t _r1 = vld1q_f16(tmpptr + 8); | |||
| float16x8_t _r2 = vld1q_f16(tmpptr + 16); | |||
| float16x8_t _r3 = vld1q_f16(tmpptr + 24); | |||
| float16x8_t _r4 = vld1q_f16(tmpptr + 32); | |||
| float16x8_t _r5 = vld1q_f16(tmpptr + 40); | |||
| float16x8_t _r6 = vld1q_f16(tmpptr + 48); | |||
| float16x8_t _r7 = vld1q_f16(tmpptr + 56); | |||
| float16x4_t _k0 = vld1_f16(kptr); | |||
| float16x4_t _k1 = vld1_f16(kptr + 4); | |||
| float16x4_t _k2 = vld1_f16(kptr + 8); | |||
| float16x4_t _k3 = vld1_f16(kptr + 12); | |||
| float16x4_t _k4 = vld1_f16(kptr + 16); | |||
| float16x4_t _k5 = vld1_f16(kptr + 20); | |||
| float16x4_t _k6 = vld1_f16(kptr + 24); | |||
| float16x4_t _k7 = vld1_f16(kptr + 28); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k0, _r0, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k0, _r0, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k0, _r0, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k0, _r0, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k0, _r0, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k0, _r0, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k0, _r0, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k0, _r0, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k1, _r1, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k1, _r1, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k1, _r1, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k1, _r1, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k1, _r1, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k1, _r1, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k1, _r1, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k1, _r1, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k2, _r2, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k2, _r2, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k2, _r2, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k2, _r2, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k2, _r2, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k2, _r2, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k2, _r2, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k2, _r2, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k3, _r3, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k3, _r3, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k3, _r3, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k3, _r3, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k3, _r3, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k3, _r3, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k3, _r3, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k3, _r3, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k4, _r4, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k4, _r4, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k4, _r4, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k4, _r4, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k4, _r4, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k4, _r4, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k4, _r4, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k4, _r4, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k5, _r5, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k5, _r5, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k5, _r5, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k5, _r5, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k5, _r5, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k5, _r5, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k5, _r5, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k5, _r5, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k6, _r6, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k6, _r6, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k6, _r6, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k6, _r6, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k6, _r6, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k6, _r6, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k6, _r6, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k6, _r6, 7); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k7, _r7, 0); | |||
| _sum1 = vfma_laneq_f16(_sum1, _k7, _r7, 1); | |||
| _sum2 = vfma_laneq_f16(_sum2, _k7, _r7, 2); | |||
| _sum3 = vfma_laneq_f16(_sum3, _k7, _r7, 3); | |||
| _sum4 = vfma_laneq_f16(_sum4, _k7, _r7, 4); | |||
| _sum5 = vfma_laneq_f16(_sum5, _k7, _r7, 5); | |||
| _sum6 = vfma_laneq_f16(_sum6, _k7, _r7, 6); | |||
| _sum7 = vfma_laneq_f16(_sum7, _k7, _r7, 7); | |||
| kptr += 32; | |||
| tmpptr += 64; | |||
| } | |||
| vst1_f16(outptr0, _sum0); | |||
| vst1_f16(outptr0 + 4, _sum1); | |||
| vst1_f16(outptr0 + 8, _sum2); | |||
| vst1_f16(outptr0 + 12, _sum3); | |||
| vst1_f16(outptr0 + 16, _sum4); | |||
| vst1_f16(outptr0 + 20, _sum5); | |||
| vst1_f16(outptr0 + 24, _sum6); | |||
| vst1_f16(outptr0 + 28, _sum7); | |||
| outptr0 += 32; | |||
| } | |||
| for (; i < size; i++) | |||
| { | |||
| __fp16* tmpptr = tmp.channel(i / 8 + i % 8); | |||
| const __fp16* kptr = kernel.channel(p / 2 + p % 2); | |||
| float16x4_t _sum0 = _bias0; | |||
| for (int q = 0; q < inch; q++) | |||
| { | |||
| float16x8_t _r0 = vld1q_f16(tmpptr); | |||
| float16x4_t _k0 = vld1_f16(kptr); | |||
| float16x4_t _k1 = vld1_f16(kptr + 4); | |||
| float16x4_t _k2 = vld1_f16(kptr + 8); | |||
| float16x4_t _k3 = vld1_f16(kptr + 12); | |||
| float16x4_t _k4 = vld1_f16(kptr + 16); | |||
| float16x4_t _k5 = vld1_f16(kptr + 20); | |||
| float16x4_t _k6 = vld1_f16(kptr + 24); | |||
| float16x4_t _k7 = vld1_f16(kptr + 28); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k0, _r0, 0); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k1, _r0, 1); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k2, _r0, 2); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k3, _r0, 3); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k4, _r0, 4); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k5, _r0, 5); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k6, _r0, 6); | |||
| _sum0 = vfma_laneq_f16(_sum0, _k7, _r0, 7); | |||
| kptr += 32; | |||
| tmpptr += 8; | |||
| } | |||
| vst1_f16(outptr0, _sum0); | |||
| outptr0 += 4; | |||
| } | |||
| } | |||
| // // NOTE sgemm | |||
| // for (; p<outch; p++) | |||
| // { | |||
| // Mat out0 = top_blob.channel(p); | |||
| // | |||
| // const float bias0 = bias ? bias[p] : 0.f; | |||
| // | |||
| // __fp16* outptr0 = out0; | |||
| // | |||
| // for (int i=0; i<size; i++) | |||
| // { | |||
| // float sum = bias0; | |||
| // | |||
| // const __fp16* kptr = _kernel.channel(p); | |||
| // | |||
| // for (int q=0; q<inch; q++) | |||
| // { | |||
| // const __fp16* img0 = bottom_blob.channel(q); | |||
| // | |||
| // sum += img0[i] * kptr[0]; | |||
| // kptr ++; | |||
| // } | |||
| // | |||
| // outptr0[i] = sum; | |||
| // } | |||
| // } | |||
| } | |||
| static void conv1x1s2_pack8to4_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, const Mat& kernel, const Mat& _bias, const Option& opt) | |||
| { | |||
| int w = bottom_blob.w; | |||
| int channels = bottom_blob.c; | |||
| size_t elemsize = bottom_blob.elemsize; | |||
| int elempack = bottom_blob.elempack; | |||
| int outw = top_blob.w; | |||
| int outh = top_blob.h; | |||
| const int tailstep = (w - 2 * outw + w) * 8; | |||
| Mat bottom_blob_shrinked; | |||
| bottom_blob_shrinked.create(outw, outh, channels, elemsize, elempack, opt.workspace_allocator); | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| for (int p = 0; p < channels; p++) | |||
| { | |||
| const __fp16* r0 = bottom_blob.channel(p); | |||
| __fp16* outptr = bottom_blob_shrinked.channel(p); | |||
| for (int i = 0; i < outh; i++) | |||
| { | |||
| int j = 0; | |||
| for (; j + 3 < outw; j += 4) | |||
| { | |||
| float16x8_t _v0 = vld1q_f16(r0); | |||
| float16x8_t _v1 = vld1q_f16(r0 + 16); | |||
| float16x8_t _v2 = vld1q_f16(r0 + 32); | |||
| float16x8_t _v3 = vld1q_f16(r0 + 48); | |||
| vst1q_f16(outptr, _v0); | |||
| vst1q_f16(outptr + 8, _v1); | |||
| vst1q_f16(outptr + 16, _v2); | |||
| vst1q_f16(outptr + 24, _v3); | |||
| r0 += 64; | |||
| outptr += 32; | |||
| } | |||
| for (; j + 1 < outw; j += 2) | |||
| { | |||
| float16x8_t _v0 = vld1q_f16(r0); | |||
| float16x8_t _v1 = vld1q_f16(r0 + 16); | |||
| vst1q_f16(outptr, _v0); | |||
| vst1q_f16(outptr + 8, _v1); | |||
| r0 += 32; | |||
| outptr += 16; | |||
| } | |||
| for (; j < outw; j++) | |||
| { | |||
| float16x8_t _v = vld1q_f16(r0); | |||
| vst1q_f16(outptr, _v); | |||
| r0 += 16; | |||
| outptr += 8; | |||
| } | |||
| r0 += tailstep; | |||
| } | |||
| } | |||
| conv1x1s1_sgemm_pack8to4_fp16sa_neon(bottom_blob_shrinked, top_blob, kernel, _bias, opt); | |||
| } | |||
| @@ -163,10 +163,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%0], #64 \n" | |||
| "st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%0], #64 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -248,10 +248,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%0], #64 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -309,10 +309,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v30.8h, v31.8h}, [%0], #32 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -361,10 +361,10 @@ static void conv3x3s1_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v30.8h}, [%0], #16 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -503,10 +503,10 @@ static void conv3x3s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%0], #64 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -563,10 +563,10 @@ static void conv3x3s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v30.8h, v31.8h}, [%0], #32 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -615,10 +615,10 @@ static void conv3x3s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "st1 {v30.8h}, [%0], #16 \n" | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "=r"(outptr0), // %0 | |||
| "=r"(r0), // %1 | |||
| "=r"(r1), // %2 | |||
| "=r"(r2) // %3 | |||
| : "0"(outptr0), | |||
| "1"(r0), | |||
| "2"(r1), | |||
| @@ -394,18 +394,18 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "sub %0, %0, #128 \n" | |||
| "uzp1 v20.8h, v0.8h, v4.8h \n"// 0 | |||
| "uzp1 v21.8h, v16.8h, v1.8h \n"// 1 | |||
| "uzp1 v22.8h, v5.8h, v17.8h \n"// 2 | |||
| "uzp1 v23.8h, v2.8h, v6.8h \n"// 3 | |||
| "uzp1 v24.8h, v18.8h, v3.8h \n"// 4 | |||
| "uzp1 v25.8h, v7.8h, v19.8h \n"// 5 | |||
| "uzp2 v26.8h, v0.8h, v4.8h \n"// 6 | |||
| "uzp2 v27.8h, v16.8h, v1.8h \n"// 7 | |||
| "uzp2 v28.8h, v5.8h, v17.8h \n"// 8 | |||
| "uzp2 v29.8h, v2.8h, v6.8h \n"// 9 | |||
| "uzp2 v30.8h, v18.8h, v3.8h \n"// 10 | |||
| "uzp2 v31.8h, v7.8h, v19.8h \n"// 11 | |||
| "uzp1 v20.8h, v0.8h, v4.8h \n" // 0 | |||
| "uzp1 v21.8h, v16.8h, v1.8h \n" // 1 | |||
| "uzp1 v22.8h, v5.8h, v17.8h \n" // 2 | |||
| "uzp1 v23.8h, v2.8h, v6.8h \n" // 3 | |||
| "uzp1 v24.8h, v18.8h, v3.8h \n" // 4 | |||
| "uzp1 v25.8h, v7.8h, v19.8h \n" // 5 | |||
| "uzp2 v26.8h, v0.8h, v4.8h \n" // 6 | |||
| "uzp2 v27.8h, v16.8h, v1.8h \n" // 7 | |||
| "uzp2 v28.8h, v5.8h, v17.8h \n" // 8 | |||
| "uzp2 v29.8h, v2.8h, v6.8h \n" // 9 | |||
| "uzp2 v30.8h, v18.8h, v3.8h \n" // 10 | |||
| "uzp2 v31.8h, v7.8h, v19.8h \n" // 11 | |||
| "st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n" | |||
| "st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%1], #64 \n" | |||
| @@ -447,7 +447,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n" | |||
| "st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n" | |||
| : "=r"(r0), // %0 | |||
| : "=r"(r0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(r0), | |||
| "1"(tmpptr) | |||
| @@ -470,7 +470,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "prfm pldl1keep, [%0, #512] \n" | |||
| "ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%0] \n" | |||
| "st1 {v0.8h, v1.8h, v2.8h, v3.8h}, [%1], #64 \n" | |||
| : "=r"(r0), // %0 | |||
| : "=r"(r0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(r0), | |||
| "1"(tmpptr) | |||
| @@ -493,7 +493,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "prfm pldl1keep, [%0, #256] \n" | |||
| "ld1 {v0.8h, v1.8h}, [%0] \n" | |||
| "st1 {v0.8h, v1.8h}, [%1], #32 \n" | |||
| : "=r"(r0), // %0 | |||
| : "=r"(r0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(r0), | |||
| "1"(tmpptr) | |||
| @@ -516,7 +516,7 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "prfm pldl1keep, [%0, #128] \n" | |||
| "ld1 {v0.8h}, [%0] \n" | |||
| "st1 {v0.8h}, [%1], #16 \n" | |||
| : "=r"(r0), // %0 | |||
| : "=r"(r0), // %0 | |||
| "=r"(tmpptr) // %1 | |||
| : "0"(r0), | |||
| "1"(tmpptr) | |||
| @@ -694,10 +694,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "st1 {v24.8h, v25.8h, v26.8h, v27.8h}, [%1], #64 \n" | |||
| "st1 {v28.8h, v29.8h, v30.8h, v31.8h}, [%1], #64 \n" | |||
| : "=r"(nn), // %0 | |||
| : "=r"(nn), // %0 | |||
| "=r"(output0_tm), // %1 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| : "0"(nn), | |||
| "1"(output0_tm), | |||
| "2"(r0), | |||
| @@ -815,10 +815,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "st1 {v20.8h, v21.8h, v22.8h, v23.8h}, [%1], #64 \n" | |||
| : "=r"(nn), // %0 | |||
| : "=r"(nn), // %0 | |||
| "=r"(output0_tm), // %1 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| : "0"(nn), | |||
| "1"(output0_tm), | |||
| "2"(r0), | |||
| @@ -895,10 +895,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "st1 {v16.8h, v17.8h, v18.8h, v19.8h}, [%1], #64 \n" | |||
| : "=r"(nn), // %0 | |||
| : "=r"(nn), // %0 | |||
| "=r"(output0_tm), // %1 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| : "0"(nn), | |||
| "1"(output0_tm), | |||
| "2"(r0), | |||
| @@ -957,10 +957,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "st1 {v16.8h, v17.8h}, [%1], #32 \n" | |||
| : "=r"(nn), // %0 | |||
| : "=r"(nn), // %0 | |||
| "=r"(output0_tm), // %1 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| : "0"(nn), | |||
| "1"(output0_tm), | |||
| "2"(r0), | |||
| @@ -1006,10 +1006,10 @@ static void conv3x3s1_winograd64_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& | |||
| "st1 {v16.8h}, [%1], #16 \n" | |||
| : "=r"(nn), // %0 | |||
| : "=r"(nn), // %0 | |||
| "=r"(output0_tm), // %1 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| "=r"(r0), // %2 | |||
| "=r"(k0) // %3 | |||
| : "0"(nn), | |||
| "1"(output0_tm), | |||
| "2"(r0), | |||
| @@ -1704,8 +1704,7 @@ static void conv3x3s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "2"(r1), | |||
| "3"(r2), | |||
| "4"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j + 1 < outw; j += 2) | |||
| { | |||
| @@ -1977,8 +1976,7 @@ static void conv3x3s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "2"(r1), | |||
| "3"(r2), | |||
| "4"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j < outw; j++) | |||
| { | |||
| @@ -2175,8 +2173,7 @@ static void conv3x3s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "2"(r1), | |||
| "3"(r2), | |||
| "4"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| r0 += tailstep; | |||
| @@ -1111,8 +1111,7 @@ static void conv5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j + 1 < outw; j += 2) | |||
| { | |||
| @@ -1780,8 +1779,7 @@ static void conv5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v8", "v9", "v10", "v11", "v12", "v13", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v8", "v9", "v10", "v11", "v12", "v13", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j < outw; j++) | |||
| { | |||
| @@ -2250,8 +2248,7 @@ static void conv5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| r0 += 4 * 8; | |||
| @@ -2969,8 +2966,7 @@ static void conv5x5s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j < outw; j++) | |||
| { | |||
| @@ -3439,8 +3435,7 @@ static void conv5x5s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, c | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| r0 += tailstep; | |||
| @@ -607,8 +607,7 @@ static void conv7x7s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "6"(r5), | |||
| "7"(r6), | |||
| "8"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v4", "v5", "v6", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v4", "v5", "v6", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j + 3 < outw; j += 4) | |||
| { | |||
| @@ -957,8 +956,7 @@ static void conv7x7s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "6"(r5), | |||
| "7"(r6), | |||
| "8"(kptr) | |||
| : "memory", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j < outw; j++) | |||
| { | |||
| @@ -1141,8 +1139,7 @@ static void conv7x7s2_pack1to8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob | |||
| "6"(r5), | |||
| "7"(r6), | |||
| "8"(kptr) | |||
| : "memory", "v0", "v1", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31" | |||
| ); | |||
| : "memory", "v0", "v1", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v28", "v29", "v30", "v31"); | |||
| } | |||
| r0 += tailstep; | |||
| @@ -58,7 +58,9 @@ namespace ncnn { | |||
| #if __ARM_FEATURE_FP16_VECTOR_ARITHMETIC | |||
| #include "convolution_1x1_fp16s.h" | |||
| #include "convolution_1x1_pack8_fp16s.h" | |||
| #include "convolution_1x1_pack4to8_fp16s.h" | |||
| #include "convolution_1x1_pack8to1_fp16s.h" | |||
| #include "convolution_1x1_pack8to4_fp16s.h" | |||
| #include "convolution_3x3_pack1to8_fp16s.h" | |||
| #include "convolution_3x3_pack8_fp16s.h" | |||
| #include "convolution_3x3_pack8to1_fp16s.h" | |||
| @@ -1111,6 +1113,19 @@ int Convolution_arm::create_pipeline_fp16s(const Option& opt) | |||
| } | |||
| } | |||
| // pack4to8 | |||
| if (elempack == 4 && out_elempack == 8) | |||
| { | |||
| if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1) | |||
| { | |||
| conv1x1s1_sgemm_transform_kernel_pack4to8_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output); | |||
| } | |||
| else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2) | |||
| { | |||
| conv1x1s1_sgemm_transform_kernel_pack4to8_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output); | |||
| } | |||
| } | |||
| // pack8to1 | |||
| if (elempack == 8 && out_elempack == 1) | |||
| { | |||
| @@ -1128,6 +1143,19 @@ int Convolution_arm::create_pipeline_fp16s(const Option& opt) | |||
| } | |||
| } | |||
| // pack8to4 | |||
| if (elempack == 8 && out_elempack == 4) | |||
| { | |||
| if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1) | |||
| { | |||
| conv1x1s1_sgemm_transform_kernel_pack8to4_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output); | |||
| } | |||
| else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2) | |||
| { | |||
| conv1x1s1_sgemm_transform_kernel_pack8to4_fp16sa_neon(weight_data, weight_data_fp16, num_input, num_output); | |||
| } | |||
| } | |||
| // pack1 | |||
| if (elempack == 1 && out_elempack == 1) | |||
| { | |||
| @@ -1668,6 +1696,25 @@ int Convolution_arm::forward_fp16sa(const Mat& bottom_blob, Mat& top_blob, const | |||
| if (elempack == 4 && out_elempack == 8) | |||
| { | |||
| if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1) | |||
| { | |||
| conv1x1s1_sgemm_pack4to8_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt); | |||
| if (activation) | |||
| { | |||
| activation->forward_inplace(top_blob, opt); | |||
| } | |||
| } | |||
| else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2) | |||
| { | |||
| conv1x1s2_pack4to8_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt); | |||
| if (activation) | |||
| { | |||
| activation->forward_inplace(top_blob, opt); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // num_output | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| @@ -1808,6 +1855,25 @@ int Convolution_arm::forward_fp16sa(const Mat& bottom_blob, Mat& top_blob, const | |||
| if (elempack == 8 && out_elempack == 4) | |||
| { | |||
| if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 1 && stride_h == 1) | |||
| { | |||
| conv1x1s1_sgemm_pack8to4_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt); | |||
| if (activation) | |||
| { | |||
| activation->forward_inplace(top_blob, opt); | |||
| } | |||
| } | |||
| else if (kernel_w == 1 && kernel_h == 1 && dilation_w == 1 && dilation_h == 1 && stride_w == 2 && stride_h == 2) | |||
| { | |||
| conv1x1s2_pack8to4_fp16sa_neon(bottom_blob_bordered, top_blob, weight_data_fp16, bias_data_fp16, opt); | |||
| if (activation) | |||
| { | |||
| activation->forward_inplace(top_blob, opt); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| // num_output | |||
| #pragma omp parallel for num_threads(opt.num_threads) | |||
| @@ -32,8 +32,8 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| const __fp16* k0 = kernel.row<const __fp16>(g); | |||
| __fp16* outptr0 = out.row<__fp16>(0); | |||
| __fp16* outptr1 = out.row<__fp16>(1); | |||
| __fp16* outptr0 = out.row<__fp16>(0); | |||
| __fp16* outptr1 = out.row<__fp16>(1); | |||
| const Mat img0 = bottom_blob.channel(g); | |||
| @@ -396,7 +396,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| "6"(r4), | |||
| "7"(r5), | |||
| "8"(k0), | |||
| "r"(bias0_data_ptr) // %18 | |||
| "r"(bias0_data_ptr) // %18 | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"); | |||
| } | |||
| @@ -611,7 +611,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| "6"(r4), | |||
| "7"(r5), | |||
| "8"(k0), | |||
| "w"(_bias0) // %18 | |||
| "w"(_bias0) // %18 | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j < outw; j++) | |||
| @@ -769,7 +769,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| "6"(r4), | |||
| "7"(r5), | |||
| "8"(k0), | |||
| "w"(_bias0) // %18 | |||
| "w"(_bias0) // %18 | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v30", "v31"); | |||
| } | |||
| @@ -991,7 +991,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(k0), | |||
| "w"(_bias0) // %14 | |||
| "w"(_bias0) // %14 | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"); | |||
| } | |||
| for (; j + 1 < outw; j += 2) | |||
| @@ -1135,7 +1135,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(k0), | |||
| "w"(_bias0) // %14 | |||
| "w"(_bias0) // %14 | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v30", "v31"); | |||
| } | |||
| for (; j < outw; j++) | |||
| @@ -1257,7 +1257,7 @@ static void convdw5x5s1_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| "4"(r3), | |||
| "5"(r4), | |||
| "6"(k0), | |||
| "w"(_bias0) // %14 | |||
| "w"(_bias0) // %14 | |||
| : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v30"); | |||
| } | |||
| @@ -1292,7 +1292,7 @@ static void convdw5x5s2_pack8_fp16sa_neon(const Mat& bottom_blob, Mat& top_blob, | |||
| const __fp16* k0 = kernel.row<const __fp16>(g); | |||
| __fp16* outptr0 = out.row<__fp16>(0); | |||
| __fp16* outptr0 = out.row<__fp16>(0); | |||
| const Mat img0 = bottom_blob.channel(g); | |||
| @@ -154,7 +154,7 @@ static void padding_constant_pack8_fp16s_neon(const Mat& src, Mat& dst, int top, | |||
| "r"(right), // %7 | |||
| "r"(top_size), // %8 | |||
| "r"(bottom_size), // %9 | |||
| "w"(_v) // %10 | |||
| "w"(_v) // %10 | |||
| : "cc", "memory", "x4", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19"); | |||
| } | |||
| @@ -82,30 +82,30 @@ static int test_convolution_0() | |||
| || test_convolution(9, 7, 4, 13, k, d, s, p, 0) | |||
| || test_convolution(9, 7, 13, 4, k, d, s, p, 1) | |||
| || test_convolution(9, 7, 4, 8, k, d, s, p, 0) | |||
| || test_convolution(9, 7, 8, 4, k, d, s, p, 1) | |||
| || test_convolution(9, 7, 8, 12, k, d, s, p, 1) | |||
| || test_convolution(9, 7, 8, 13, k, d, s, p, 0) | |||
| || test_convolution(9, 7, 13, 8, k, d, s, p, 1) | |||
| || test_convolution(9, 7, 4, 16, k, d, s, p, 0) | |||
| || test_convolution(9, 7, 12, 16, k, d, s, p, 0) | |||
| || test_convolution(9, 7, 15, 15, k, d, s, p, 0) | |||
| || test_convolution(9, 7, 16, 16, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 1, 1, k, d, s, p, 1) | |||
| || test_convolution(18, 17, 4, 13, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 13, 4, k, d, s, p, 1) | |||
| || test_convolution(18, 17, 4, 8, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 8, 4, k, d, s, p, 1) | |||
| || test_convolution(18, 17, 8, 12, k, d, s, p, 1) | |||
| || test_convolution(18, 17, 8, 13, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 13, 8, k, d, s, p, 1) | |||
| || test_convolution(18, 17, 4, 16, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 12, 16, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 15, 15, k, d, s, p, 0) | |||
| || test_convolution(18, 17, 16, 16, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 1, 1, k, d, s, p, 1) | |||
| || test_convolution(25, 33, 4, 13, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 13, 4, k, d, s, p, 1) | |||
| || test_convolution(25, 33, 4, 8, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 8, 4, k, d, s, p, 1) | |||
| || test_convolution(25, 33, 8, 12, k, d, s, p, 1) | |||
| || test_convolution(25, 33, 8, 13, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 13, 8, k, d, s, p, 1) | |||
| || test_convolution(25, 33, 4, 16, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 12, 16, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 15, 15, k, d, s, p, 0) | |||
| || test_convolution(25, 33, 16, 16, k, d, s, p, 0); | |||