Skip to content

Commit 8b12d38

Browse files
committed
perf(avx512f): single vpermt2 for zip_lo/zip_hi
The AVX-512 zip_lo/zip_hi lowered the interleave as per-128-bit unpacklo/unpackhi followed by a 3x insertf32x4 / extractf32x4 lane-fixup pile (~7 shuffle-port uops) needed to undo AVX-512's in-lane element ordering. A single 2-source cross-lane permute (vpermt2d/vpermt2q for integral, vpermt2ps/vpermt2pd for float/double) produces the same result in one port-5 uop.
1 parent e79f9d3 commit 8b12d38

1 file changed

Lines changed: 21 additions & 60 deletions

File tree

include/xsimd/arch/xsimd_avx512f.hpp

Lines changed: 21 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2806,7 +2806,6 @@ namespace xsimd
28062806
XSIMD_INLINE batch<T, A>
28072807
zip_hi(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
28082808
{
2809-
__m512i lo, hi;
28102809
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
28112810
{
28122811
assert(false && "not implemented yet");
@@ -2819,62 +2818,43 @@ namespace xsimd
28192818
}
28202819
else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
28212820
{
2822-
lo = _mm512_unpacklo_epi32(self, other);
2823-
hi = _mm512_unpackhi_epi32(self, other);
2821+
__m512i idx = _mm512_setr_epi32(8, 24, 9, 25, 10, 26, 11, 27,
2822+
12, 28, 13, 29, 14, 30, 15, 31);
2823+
return _mm512_permutex2var_epi32(self, idx, other);
28242824
}
28252825
else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
28262826
{
2827-
lo = _mm512_unpacklo_epi64(self, other);
2828-
hi = _mm512_unpackhi_epi64(self, other);
2827+
__m512i idx = _mm512_setr_epi64(4, 12, 5, 13, 6, 14, 7, 15);
2828+
return _mm512_permutex2var_epi64(self, idx, other);
28292829
}
28302830
else
28312831
{
28322832
assert(false && "unsupported arch/op combination");
28332833
return {};
28342834
}
2835-
return _mm512_inserti32x4(
2836-
_mm512_inserti32x4(
2837-
_mm512_inserti32x4(hi, _mm512_extracti32x4_epi32(lo, 2), 0),
2838-
_mm512_extracti32x4_epi32(lo, 3),
2839-
2),
2840-
_mm512_extracti32x4_epi32(hi, 2),
2841-
1);
28422835
}
28432836
template <class A>
28442837
XSIMD_INLINE batch<float, A>
28452838
zip_hi(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
28462839
{
2847-
auto lo = _mm512_unpacklo_ps(self, other);
2848-
auto hi = _mm512_unpackhi_ps(self, other);
2849-
return _mm512_insertf32x4(
2850-
_mm512_insertf32x4(
2851-
_mm512_insertf32x4(hi, _mm512_extractf32x4_ps(lo, 2), 0),
2852-
_mm512_extractf32x4_ps(lo, 3),
2853-
2),
2854-
_mm512_extractf32x4_ps(hi, 2),
2855-
1);
2840+
__m512i idx = _mm512_setr_epi32(8, 24, 9, 25, 10, 26, 11, 27,
2841+
12, 28, 13, 29, 14, 30, 15, 31);
2842+
return _mm512_permutex2var_ps(self, idx, other);
28562843
}
28572844
template <class A>
28582845
XSIMD_INLINE batch<double, A>
28592846
zip_hi(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
28602847
{
2861-
auto lo = _mm512_castpd_ps(_mm512_unpacklo_pd(self, other));
2862-
auto hi = _mm512_castpd_ps(_mm512_unpackhi_pd(self, other));
2863-
return _mm512_castps_pd(_mm512_insertf32x4(
2864-
_mm512_insertf32x4(
2865-
_mm512_insertf32x4(hi, _mm512_extractf32x4_ps(lo, 2), 0),
2866-
_mm512_extractf32x4_ps(lo, 3),
2867-
2),
2868-
_mm512_extractf32x4_ps(hi, 2),
2869-
1));
2848+
__m512i idx = _mm512_setr_epi64(4, 12, 5, 13, 6, 14, 7, 15);
2849+
return _mm512_permutex2var_pd(self, idx, other);
28702850
}
28712851

28722852
// zip_lo
2853+
// See zip_hi: one vpermt2{d,q,ps,pd} in place of the unpack+insert128 pile.
28732854
template <class A, class T, class = std::enable_if_t<std::is_integral<T>::value>>
28742855
XSIMD_INLINE batch<T, A>
28752856
zip_lo(batch<T, A> const& self, batch<T, A> const& other, requires_arch<avx512f>) noexcept
28762857
{
2877-
__m512i lo, hi;
28782858
XSIMD_IF_CONSTEXPR(sizeof(T) == 1)
28792859
{
28802860
assert(false && "not implemented yet");
@@ -2887,54 +2867,35 @@ namespace xsimd
28872867
}
28882868
else XSIMD_IF_CONSTEXPR(sizeof(T) == 4)
28892869
{
2890-
lo = _mm512_unpacklo_epi32(self, other);
2891-
hi = _mm512_unpackhi_epi32(self, other);
2870+
__m512i idx = _mm512_setr_epi32(0, 16, 1, 17, 2, 18, 3, 19,
2871+
4, 20, 5, 21, 6, 22, 7, 23);
2872+
return _mm512_permutex2var_epi32(self, idx, other);
28922873
}
28932874
else XSIMD_IF_CONSTEXPR(sizeof(T) == 8)
28942875
{
2895-
lo = _mm512_unpacklo_epi64(self, other);
2896-
hi = _mm512_unpackhi_epi64(self, other);
2876+
__m512i idx = _mm512_setr_epi64(0, 8, 1, 9, 2, 10, 3, 11);
2877+
return _mm512_permutex2var_epi64(self, idx, other);
28972878
}
28982879
else
28992880
{
29002881
assert(false && "unsupported arch/op combination");
29012882
return {};
29022883
}
2903-
return _mm512_inserti32x4(
2904-
_mm512_inserti32x4(
2905-
_mm512_inserti32x4(lo, _mm512_extracti32x4_epi32(hi, 0), 1),
2906-
_mm512_extracti32x4_epi32(hi, 1),
2907-
3),
2908-
_mm512_extracti32x4_epi32(lo, 1),
2909-
2);
29102884
}
29112885
template <class A>
29122886
XSIMD_INLINE batch<float, A>
29132887
zip_lo(batch<float, A> const& self, batch<float, A> const& other, requires_arch<avx512f>) noexcept
29142888
{
2915-
auto lo = _mm512_unpacklo_ps(self, other);
2916-
auto hi = _mm512_unpackhi_ps(self, other);
2917-
return _mm512_insertf32x4(
2918-
_mm512_insertf32x4(
2919-
_mm512_insertf32x4(lo, _mm512_extractf32x4_ps(hi, 0), 1),
2920-
_mm512_extractf32x4_ps(hi, 1),
2921-
3),
2922-
_mm512_extractf32x4_ps(lo, 1),
2923-
2);
2889+
__m512i idx = _mm512_setr_epi32(0, 16, 1, 17, 2, 18, 3, 19,
2890+
4, 20, 5, 21, 6, 22, 7, 23);
2891+
return _mm512_permutex2var_ps(self, idx, other);
29242892
}
29252893
template <class A>
29262894
XSIMD_INLINE batch<double, A>
29272895
zip_lo(batch<double, A> const& self, batch<double, A> const& other, requires_arch<avx512f>) noexcept
29282896
{
2929-
auto lo = _mm512_castpd_ps(_mm512_unpacklo_pd(self, other));
2930-
auto hi = _mm512_castpd_ps(_mm512_unpackhi_pd(self, other));
2931-
return _mm512_castps_pd(_mm512_insertf32x4(
2932-
_mm512_insertf32x4(
2933-
_mm512_insertf32x4(lo, _mm512_extractf32x4_ps(hi, 0), 1),
2934-
_mm512_extractf32x4_ps(hi, 1),
2935-
3),
2936-
_mm512_extractf32x4_ps(lo, 1),
2937-
2));
2897+
__m512i idx = _mm512_setr_epi64(0, 8, 1, 9, 2, 10, 3, 11);
2898+
return _mm512_permutex2var_pd(self, idx, other);
29382899
}
29392900

29402901
// widen

0 commit comments

Comments
 (0)