Skip to content

Commit f0837a9

Browse files
nihuivlordier
authored andcommitted
x86 concat slice flatten reshape crop padding packing support fp16 bf16 storage (Tencent#6593)
1 parent 1cb050b commit f0837a9

17 files changed

Lines changed: 4874 additions & 36 deletions

src/layer/x86/concat_x86.cpp

Lines changed: 814 additions & 1 deletion
Large diffs are not rendered by default.

src/layer/x86/concat_x86.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019 Tencent
1+
// Copyright 2026 Tencent
22
// SPDX-License-Identifier: BSD-3-Clause
33

44
#ifndef LAYER_CONCAT_X86_H
@@ -14,6 +14,9 @@ class Concat_x86 : public Concat
1414
Concat_x86();
1515

1616
virtual int forward(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const;
17+
18+
protected:
19+
int forward_bf16s_fp16s(const std::vector<Mat>& bottom_blobs, std::vector<Mat>& top_blobs, const Option& opt) const;
1720
};
1821

1922
} // namespace ncnn

src/layer/x86/crop_x86.cpp

Lines changed: 172 additions & 25 deletions
Large diffs are not rendered by default.

src/layer/x86/crop_x86.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019 Tencent
1+
// Copyright 2026 Tencent
22
// SPDX-License-Identifier: BSD-3-Clause
33

44
#ifndef LAYER_CROP_X86_H

src/layer/x86/flatten_x86.cpp

Lines changed: 322 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019 Tencent
1+
// Copyright 2026 Tencent
22
// SPDX-License-Identifier: BSD-3-Clause
33

44
#include "flatten_x86.h"
@@ -10,6 +10,7 @@
1010
#endif
1111
#endif // __SSE2__
1212

13+
#include "cpu.h"
1314
#include "x86_usability.h"
1415

1516
namespace ncnn {
@@ -19,6 +20,10 @@ Flatten_x86::Flatten_x86()
1920
#if __SSE2__
2021
support_packing = true;
2122
#endif // __SSE2__
23+
support_fp16_storage = cpu_support_x86_f16c();
24+
#if NCNN_BF16
25+
support_bf16_storage = true;
26+
#endif
2227
}
2328

2429
int Flatten_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
@@ -28,6 +33,9 @@ int Flatten_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op
2833
if (elembits == 8)
2934
return forward_int8(bottom_blob, top_blob, opt);
3035

36+
if (elembits == 16)
37+
return forward_bf16s_fp16s(bottom_blob, top_blob, opt);
38+
3139
int dims = bottom_blob.dims;
3240

3341
if (dims == 1)
@@ -552,6 +560,319 @@ int Flatten_x86::forward(const Mat& bottom_blob, Mat& top_blob, const Option& op
552560
return 0;
553561
}
554562

563+
int Flatten_x86::forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
564+
{
565+
int dims = bottom_blob.dims;
566+
567+
if (dims == 1)
568+
{
569+
top_blob = bottom_blob;
570+
return 0;
571+
}
572+
573+
int w = bottom_blob.w;
574+
int h = bottom_blob.h;
575+
int d = bottom_blob.d;
576+
int channels = bottom_blob.c;
577+
size_t elemsize = bottom_blob.elemsize;
578+
int elempack = bottom_blob.elempack;
579+
int size = w * h * d;
580+
581+
int total = size * channels * elempack;
582+
583+
int out_elempack = 1;
584+
#if __SSE2__
585+
if (opt.use_packing_layout)
586+
{
587+
#if __AVX512F__
588+
out_elempack = total % 16 == 0 ? 16 : total % 8 == 0 ? 8 : total % 4 == 0 ? 4 : 1;
589+
#elif __AVX__
590+
out_elempack = total % 8 == 0 ? 8 : total % 4 == 0 ? 4 : 1;
591+
#else
592+
out_elempack = total % 4 == 0 ? 4 : 1;
593+
#endif
594+
}
595+
#endif // __SSE2__
596+
size_t out_elemsize = elemsize / elempack * out_elempack;
597+
598+
if (out_elempack == 1)
599+
{
600+
return Flatten::forward(bottom_blob, top_blob, opt);
601+
}
602+
603+
if (dims == 2 && elempack == 1) // out_elempack == 4 || out_elempack == 8 || out_elempack == 16
604+
{
605+
top_blob = bottom_blob;
606+
top_blob.dims = 1;
607+
top_blob.w = total / out_elempack;
608+
top_blob.h = 1;
609+
top_blob.cstep = bottom_blob.cstep / out_elempack;
610+
top_blob.elemsize = out_elemsize;
611+
top_blob.elempack = out_elempack;
612+
return 0;
613+
}
614+
615+
top_blob.create(total / out_elempack, out_elemsize, out_elempack, opt.blob_allocator);
616+
if (top_blob.empty())
617+
return -100;
618+
619+
if (dims == 2)
620+
{
621+
#if __SSE2__
622+
#if __AVX__
623+
#if __AVX512F__
624+
if (elempack == 16) // out_elempack == 16
625+
{
626+
#pragma omp parallel for num_threads(opt.num_threads)
627+
for (int i = 0; i < h; i++)
628+
{
629+
const unsigned short* ptr = bottom_blob.row<const unsigned short>(i);
630+
unsigned short* outptr0 = (unsigned short*)top_blob + w * i * 16;
631+
unsigned short* outptr1 = (unsigned short*)top_blob + w * (i * 16 + 1);
632+
unsigned short* outptr2 = (unsigned short*)top_blob + w * (i * 16 + 2);
633+
unsigned short* outptr3 = (unsigned short*)top_blob + w * (i * 16 + 3);
634+
unsigned short* outptr4 = (unsigned short*)top_blob + w * (i * 16 + 4);
635+
unsigned short* outptr5 = (unsigned short*)top_blob + w * (i * 16 + 5);
636+
unsigned short* outptr6 = (unsigned short*)top_blob + w * (i * 16 + 6);
637+
unsigned short* outptr7 = (unsigned short*)top_blob + w * (i * 16 + 7);
638+
unsigned short* outptr8 = (unsigned short*)top_blob + w * (i * 16 + 8);
639+
unsigned short* outptr9 = (unsigned short*)top_blob + w * (i * 16 + 9);
640+
unsigned short* outptra = (unsigned short*)top_blob + w * (i * 16 + 10);
641+
unsigned short* outptrb = (unsigned short*)top_blob + w * (i * 16 + 11);
642+
unsigned short* outptrc = (unsigned short*)top_blob + w * (i * 16 + 12);
643+
unsigned short* outptrd = (unsigned short*)top_blob + w * (i * 16 + 13);
644+
unsigned short* outptre = (unsigned short*)top_blob + w * (i * 16 + 14);
645+
unsigned short* outptrf = (unsigned short*)top_blob + w * (i * 16 + 15);
646+
647+
for (int j = 0; j < w; j++)
648+
{
649+
*outptr0++ = ptr[0];
650+
*outptr1++ = ptr[1];
651+
*outptr2++ = ptr[2];
652+
*outptr3++ = ptr[3];
653+
*outptr4++ = ptr[4];
654+
*outptr5++ = ptr[5];
655+
*outptr6++ = ptr[6];
656+
*outptr7++ = ptr[7];
657+
*outptr8++ = ptr[8];
658+
*outptr9++ = ptr[9];
659+
*outptra++ = ptr[10];
660+
*outptrb++ = ptr[11];
661+
*outptrc++ = ptr[12];
662+
*outptrd++ = ptr[13];
663+
*outptre++ = ptr[14];
664+
*outptrf++ = ptr[15];
665+
666+
ptr += 16;
667+
}
668+
}
669+
}
670+
#endif // __AVX512F__
671+
672+
if (elempack == 8) // out_elempack == 8 || out_elempack == 16
673+
{
674+
#pragma omp parallel for num_threads(opt.num_threads)
675+
for (int i = 0; i < h; i++)
676+
{
677+
const unsigned short* ptr = bottom_blob.row<const unsigned short>(i);
678+
unsigned short* outptr0 = (unsigned short*)top_blob + w * i * 8;
679+
unsigned short* outptr1 = (unsigned short*)top_blob + w * (i * 8 + 1);
680+
unsigned short* outptr2 = (unsigned short*)top_blob + w * (i * 8 + 2);
681+
unsigned short* outptr3 = (unsigned short*)top_blob + w * (i * 8 + 3);
682+
unsigned short* outptr4 = (unsigned short*)top_blob + w * (i * 8 + 4);
683+
unsigned short* outptr5 = (unsigned short*)top_blob + w * (i * 8 + 5);
684+
unsigned short* outptr6 = (unsigned short*)top_blob + w * (i * 8 + 6);
685+
unsigned short* outptr7 = (unsigned short*)top_blob + w * (i * 8 + 7);
686+
687+
for (int j = 0; j < w; j++)
688+
{
689+
*outptr0++ = ptr[0];
690+
*outptr1++ = ptr[1];
691+
*outptr2++ = ptr[2];
692+
*outptr3++ = ptr[3];
693+
*outptr4++ = ptr[4];
694+
*outptr5++ = ptr[5];
695+
*outptr6++ = ptr[6];
696+
*outptr7++ = ptr[7];
697+
698+
ptr += 8;
699+
}
700+
}
701+
}
702+
#endif // __AVX__
703+
704+
if (elempack == 4) // out_elempack == 4 || out_elempack == 8 || out_elempack == 16
705+
{
706+
#pragma omp parallel for num_threads(opt.num_threads)
707+
for (int i = 0; i < h; i++)
708+
{
709+
const unsigned short* ptr = bottom_blob.row<const unsigned short>(i);
710+
unsigned short* outptr0 = (unsigned short*)top_blob + w * i * 4;
711+
unsigned short* outptr1 = (unsigned short*)top_blob + w * (i * 4 + 1);
712+
unsigned short* outptr2 = (unsigned short*)top_blob + w * (i * 4 + 2);
713+
unsigned short* outptr3 = (unsigned short*)top_blob + w * (i * 4 + 3);
714+
715+
for (int j = 0; j < w; j++)
716+
{
717+
*outptr0++ = ptr[0];
718+
*outptr1++ = ptr[1];
719+
*outptr2++ = ptr[2];
720+
*outptr3++ = ptr[3];
721+
722+
ptr += 4;
723+
}
724+
}
725+
}
726+
#endif // __SSE2__
727+
}
728+
729+
if (dims == 3 || dims == 4)
730+
{
731+
#if __SSE2__
732+
#if __AVX__
733+
#if __AVX512F__
734+
if (elempack == 16) // out_elempack == 16
735+
{
736+
#pragma omp parallel for num_threads(opt.num_threads)
737+
for (int q = 0; q < channels; q++)
738+
{
739+
const unsigned short* ptr = bottom_blob.channel(q);
740+
unsigned short* outptr0 = (unsigned short*)top_blob + size * q * 16;
741+
unsigned short* outptr1 = (unsigned short*)top_blob + size * (q * 16 + 1);
742+
unsigned short* outptr2 = (unsigned short*)top_blob + size * (q * 16 + 2);
743+
unsigned short* outptr3 = (unsigned short*)top_blob + size * (q * 16 + 3);
744+
unsigned short* outptr4 = (unsigned short*)top_blob + size * (q * 16 + 4);
745+
unsigned short* outptr5 = (unsigned short*)top_blob + size * (q * 16 + 5);
746+
unsigned short* outptr6 = (unsigned short*)top_blob + size * (q * 16 + 6);
747+
unsigned short* outptr7 = (unsigned short*)top_blob + size * (q * 16 + 7);
748+
unsigned short* outptr8 = (unsigned short*)top_blob + size * (q * 16 + 8);
749+
unsigned short* outptr9 = (unsigned short*)top_blob + size * (q * 16 + 9);
750+
unsigned short* outptra = (unsigned short*)top_blob + size * (q * 16 + 10);
751+
unsigned short* outptrb = (unsigned short*)top_blob + size * (q * 16 + 11);
752+
unsigned short* outptrc = (unsigned short*)top_blob + size * (q * 16 + 12);
753+
unsigned short* outptrd = (unsigned short*)top_blob + size * (q * 16 + 13);
754+
unsigned short* outptre = (unsigned short*)top_blob + size * (q * 16 + 14);
755+
unsigned short* outptrf = (unsigned short*)top_blob + size * (q * 16 + 15);
756+
757+
for (int i = 0; i < size; i++)
758+
{
759+
*outptr0++ = ptr[0];
760+
*outptr1++ = ptr[1];
761+
*outptr2++ = ptr[2];
762+
*outptr3++ = ptr[3];
763+
*outptr4++ = ptr[4];
764+
*outptr5++ = ptr[5];
765+
*outptr6++ = ptr[6];
766+
*outptr7++ = ptr[7];
767+
*outptr8++ = ptr[8];
768+
*outptr9++ = ptr[9];
769+
*outptra++ = ptr[10];
770+
*outptrb++ = ptr[11];
771+
*outptrc++ = ptr[12];
772+
*outptrd++ = ptr[13];
773+
*outptre++ = ptr[14];
774+
*outptrf++ = ptr[15];
775+
776+
ptr += 16;
777+
}
778+
}
779+
}
780+
#endif // __AVX512F__
781+
782+
if (elempack == 8) // out_elempack == 8 || out_elempack == 16
783+
{
784+
#pragma omp parallel for num_threads(opt.num_threads)
785+
for (int q = 0; q < channels; q++)
786+
{
787+
const unsigned short* ptr = bottom_blob.channel(q);
788+
unsigned short* outptr0 = (unsigned short*)top_blob + size * q * 8;
789+
unsigned short* outptr1 = (unsigned short*)top_blob + size * (q * 8 + 1);
790+
unsigned short* outptr2 = (unsigned short*)top_blob + size * (q * 8 + 2);
791+
unsigned short* outptr3 = (unsigned short*)top_blob + size * (q * 8 + 3);
792+
unsigned short* outptr4 = (unsigned short*)top_blob + size * (q * 8 + 4);
793+
unsigned short* outptr5 = (unsigned short*)top_blob + size * (q * 8 + 5);
794+
unsigned short* outptr6 = (unsigned short*)top_blob + size * (q * 8 + 6);
795+
unsigned short* outptr7 = (unsigned short*)top_blob + size * (q * 8 + 7);
796+
797+
for (int i = 0; i < size; i++)
798+
{
799+
*outptr0++ = ptr[0];
800+
*outptr1++ = ptr[1];
801+
*outptr2++ = ptr[2];
802+
*outptr3++ = ptr[3];
803+
*outptr4++ = ptr[4];
804+
*outptr5++ = ptr[5];
805+
*outptr6++ = ptr[6];
806+
*outptr7++ = ptr[7];
807+
808+
ptr += 8;
809+
}
810+
}
811+
}
812+
#endif // __AVX__
813+
814+
if (elempack == 4) // out_elempack == 4 || out_elempack == 8 || out_elempack == 16
815+
{
816+
#pragma omp parallel for num_threads(opt.num_threads)
817+
for (int q = 0; q < channels; q++)
818+
{
819+
const unsigned short* ptr = bottom_blob.channel(q);
820+
unsigned short* outptr0 = (unsigned short*)top_blob + size * q * 4;
821+
unsigned short* outptr1 = (unsigned short*)top_blob + size * (q * 4 + 1);
822+
unsigned short* outptr2 = (unsigned short*)top_blob + size * (q * 4 + 2);
823+
unsigned short* outptr3 = (unsigned short*)top_blob + size * (q * 4 + 3);
824+
825+
for (int i = 0; i < size; i++)
826+
{
827+
*outptr0++ = ptr[0];
828+
*outptr1++ = ptr[1];
829+
*outptr2++ = ptr[2];
830+
*outptr3++ = ptr[3];
831+
832+
ptr += 4;
833+
}
834+
}
835+
}
836+
#endif // __SSE2__
837+
838+
if (elempack == 1) // out_elempack == 4 || out_elempack == 8 || out_elempack == 16
839+
{
840+
#pragma omp parallel for num_threads(opt.num_threads)
841+
for (int q = 0; q < channels; q++)
842+
{
843+
const unsigned short* ptr = bottom_blob.channel(q);
844+
unsigned short* outptr = (unsigned short*)top_blob + size * q;
845+
846+
int i = 0;
847+
#if __SSE2__
848+
#if __AVX__
849+
for (; i + 15 < size; i += 16)
850+
{
851+
__m256i _v = _mm256_loadu_si256((const __m256i*)ptr);
852+
_mm256_storeu_si256((__m256i*)outptr, _v);
853+
ptr += 16;
854+
outptr += 16;
855+
}
856+
#endif
857+
for (; i + 7 < size; i += 8)
858+
{
859+
__m128i _v = _mm_loadu_si128((const __m128i*)ptr);
860+
_mm_storeu_si128((__m128i*)outptr, _v);
861+
ptr += 8;
862+
outptr += 8;
863+
}
864+
#endif // __SSE2__
865+
for (; i < size; i++)
866+
{
867+
*outptr++ = *ptr++;
868+
}
869+
}
870+
}
871+
}
872+
873+
return 0;
874+
}
875+
555876
int Flatten_x86::forward_int8(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const
556877
{
557878
int dims = bottom_blob.dims;

src/layer/x86/flatten_x86.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2019 Tencent
1+
// Copyright 2026 Tencent
22
// SPDX-License-Identifier: BSD-3-Clause
33

44
#ifndef LAYER_FLATTEN_X86_H
@@ -16,6 +16,7 @@ class Flatten_x86 : public Flatten
1616
virtual int forward(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const;
1717

1818
protected:
19+
int forward_bf16s_fp16s(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const;
1920
int forward_int8(const Mat& bottom_blob, Mat& top_blob, const Option& opt) const;
2021
};
2122

0 commit comments

Comments
 (0)