/work/libde265/libde265/x86/transform-avx512.cc
Line | Count | Source |
1 | | /* |
2 | | * H.265 video codec. |
3 | | * Copyright (c) 2026 Dirk Farin <dirk.farin@gmail.com> |
4 | | * |
5 | | * This file is part of libde265. |
6 | | * |
7 | | * libde265 is free software: you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation, either version 3 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * libde265 is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with libde265. If not, see <http://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | // AVX-512 (F + BW) inverse transform for 32x32, 8-bit. |
22 | | // |
23 | | // A full 32-column row fits in one zmm (32 int16), so the vertical pass |
24 | | // processes all 32 columns at once (twice the AVX2 width). The per-column |
25 | | // butterfly is the same arithmetic as the AVX2/SSE versions: every 512-bit op |
26 | | // acts independently per 128-bit lane, so each of the 4 lanes does what the SSE |
27 | | // does for 8 columns -> 32 columns, bit-identical. The even part reuses a |
28 | | // 16-point core (a 32-pt inverse DCT's even half is a 16-pt inverse DCT of the |
29 | | // even rows). The 32x32 transpose between passes is done at 256-bit width using |
30 | | // the proven AVX2 path (split each zmm into its two ymm halves, transpose, |
31 | | // recombine) since the transpose is shuffle-bound, not the hot path. |
32 | | |
33 | | #include "x86/transform-avx512.h" |
34 | | |
35 | | #ifdef HAVE_CONFIG_H |
36 | | #include "config.h" |
37 | | #endif |
38 | | |
39 | | #if HAVE_AVX512 |
40 | | |
41 | | #include <immintrin.h> |
42 | | #include "x86/transform-dct-tables.h" // idct_T16_{1,2,3}, idct_T32 |
43 | | |
44 | | namespace { |
45 | | |
46 | 0 | #define shift_1st 7 |
47 | 0 | #define add_1st (1 << (shift_1st - 1)) // 64 |
48 | 0 | #define shift_2nd 12 |
49 | 0 | #define add_2nd (1 << (shift_2nd - 1)) // 2048 |
50 | | |
51 | | // broadcast a 128-bit (8 int16) madd pattern to all four 128-bit lanes |
52 | 0 | static inline __m512i bc(const int16_t* p) { |
53 | 0 | return _mm512_broadcast_i32x4(_mm_load_si128((const __m128i*)p)); |
54 | 0 | } |
55 | | |
56 | | // --- 256-bit transpose helpers (identical to transform-avx2.cc) ---------- |
57 | | |
58 | 0 | static inline void transpose8x8_lanes(__m256i a[8]) { |
59 | 0 | __m256i b0=_mm256_unpacklo_epi16(a[0],a[1]), b1=_mm256_unpackhi_epi16(a[0],a[1]); |
60 | 0 | __m256i b2=_mm256_unpacklo_epi16(a[2],a[3]), b3=_mm256_unpackhi_epi16(a[2],a[3]); |
61 | 0 | __m256i b4=_mm256_unpacklo_epi16(a[4],a[5]), b5=_mm256_unpackhi_epi16(a[4],a[5]); |
62 | 0 | __m256i b6=_mm256_unpacklo_epi16(a[6],a[7]), b7=_mm256_unpackhi_epi16(a[6],a[7]); |
63 | 0 | __m256i c0=_mm256_unpacklo_epi32(b0,b2), c1=_mm256_unpackhi_epi32(b0,b2); |
64 | 0 | __m256i c2=_mm256_unpacklo_epi32(b1,b3), c3=_mm256_unpackhi_epi32(b1,b3); |
65 | 0 | __m256i c4=_mm256_unpacklo_epi32(b4,b6), c5=_mm256_unpackhi_epi32(b4,b6); |
66 | 0 | __m256i c6=_mm256_unpacklo_epi32(b5,b7), c7=_mm256_unpackhi_epi32(b5,b7); |
67 | 0 | a[0]=_mm256_unpacklo_epi64(c0,c4); a[1]=_mm256_unpackhi_epi64(c0,c4); |
68 | 0 | a[2]=_mm256_unpacklo_epi64(c1,c5); a[3]=_mm256_unpackhi_epi64(c1,c5); |
69 | 0 | a[4]=_mm256_unpacklo_epi64(c2,c6); a[5]=_mm256_unpackhi_epi64(c2,c6); |
70 | 0 | a[6]=_mm256_unpacklo_epi64(c3,c7); a[7]=_mm256_unpackhi_epi64(c3,c7); |
71 | 0 | } |
72 | 0 | static inline void transpose16x16(__m256i S[16]) { |
73 | 0 | __m256i top[8], bot[8]; |
74 | 0 | for (int r=0;r<8;r++){ top[r]=S[r]; bot[r]=S[r+8]; } |
75 | 0 | transpose8x8_lanes(top); transpose8x8_lanes(bot); |
76 | 0 | for (int r=0;r<8;r++){ |
77 | 0 | S[r] = _mm256_permute2x128_si256(top[r], bot[r], 0x20); |
78 | 0 | S[r+8] = _mm256_permute2x128_si256(top[r], bot[r], 0x31); |
79 | 0 | } |
80 | 0 | } |
81 | 0 | static inline void transpose32x32_ymm(__m256i Lo[32], __m256i Hi[32]) { |
82 | 0 | __m256i A[16],B[16],C[16],D[16]; |
83 | 0 | for (int r=0;r<16;r++){ A[r]=Lo[r]; B[r]=Hi[r]; C[r]=Lo[r+16]; D[r]=Hi[r+16]; } |
84 | 0 | transpose16x16(A); transpose16x16(B); transpose16x16(C); transpose16x16(D); |
85 | 0 | for (int r=0;r<16;r++){ Lo[r]=A[r]; Hi[r]=C[r]; Lo[r+16]=B[r]; Hi[r+16]=D[r]; } |
86 | 0 | } |
87 | | |
88 | | // 32x32 transpose of zmm rows, via the 256-bit path. |
89 | 0 | static inline void transpose32x32_z(__m512i S[32]) { |
90 | 0 | __m256i Lo[32], Hi[32]; |
91 | 0 | for (int r=0;r<32;r++){ |
92 | 0 | Lo[r]=_mm512_castsi512_si256(S[r]); |
93 | 0 | Hi[r]=_mm512_extracti64x4_epi64(S[r], 1); |
94 | 0 | } |
95 | 0 | transpose32x32_ymm(Lo, Hi); |
96 | 0 | for (int r=0;r<32;r++) |
97 | 0 | S[r]=_mm512_inserti64x4(_mm512_castsi256_si512(Lo[r]), Hi[r], 1); |
98 | 0 | } |
99 | | |
100 | | // --- 16-point core (32 columns) ------------------------------------------ |
101 | | |
102 | 0 | static inline void idct16_core_512(const __m512i S[16], __m512i resL[16], __m512i resH[16]) { |
103 | 0 | const __m512i T00=bc(idct_T16_1[0][0]),T01=bc(idct_T16_1[0][1]),T02=bc(idct_T16_1[0][2]),T03=bc(idct_T16_1[0][3]); |
104 | 0 | const __m512i T04=bc(idct_T16_1[0][4]),T05=bc(idct_T16_1[0][5]),T06=bc(idct_T16_1[0][6]),T07=bc(idct_T16_1[0][7]); |
105 | 0 | const __m512i T10=bc(idct_T16_1[1][0]),T11=bc(idct_T16_1[1][1]),T12=bc(idct_T16_1[1][2]),T13=bc(idct_T16_1[1][3]); |
106 | 0 | const __m512i T14=bc(idct_T16_1[1][4]),T15=bc(idct_T16_1[1][5]),T16=bc(idct_T16_1[1][6]),T17=bc(idct_T16_1[1][7]); |
107 | 0 | const __m512i T20=bc(idct_T16_1[2][0]),T21=bc(idct_T16_1[2][1]),T22=bc(idct_T16_1[2][2]),T23=bc(idct_T16_1[2][3]); |
108 | 0 | const __m512i T24=bc(idct_T16_1[2][4]),T25=bc(idct_T16_1[2][5]),T26=bc(idct_T16_1[2][6]),T27=bc(idct_T16_1[2][7]); |
109 | 0 | const __m512i T30=bc(idct_T16_1[3][0]),T31=bc(idct_T16_1[3][1]),T32_=bc(idct_T16_1[3][2]),T33=bc(idct_T16_1[3][3]); |
110 | 0 | const __m512i T34=bc(idct_T16_1[3][4]),T35=bc(idct_T16_1[3][5]),T36=bc(idct_T16_1[3][6]),T37=bc(idct_T16_1[3][7]); |
111 | 0 | const __m512i U00=bc(idct_T16_2[0][0]),U01=bc(idct_T16_2[0][1]),U02=bc(idct_T16_2[0][2]),U03=bc(idct_T16_2[0][3]); |
112 | 0 | const __m512i U10=bc(idct_T16_2[1][0]),U11=bc(idct_T16_2[1][1]),U12=bc(idct_T16_2[1][2]),U13=bc(idct_T16_2[1][3]); |
113 | 0 | const __m512i V00=bc(idct_T16_3[0][0]),V01=bc(idct_T16_3[0][1]),V10=bc(idct_T16_3[1][0]),V11=bc(idct_T16_3[1][1]); |
114 | |
|
115 | 0 | __m512i m0,m1,m2,m3,m4,m5,m6,m7; |
116 | 0 | __m512i E0l,E1l,E2l,E3l,E0h,E1h,E2h,E3h; |
117 | 0 | __m512i O0l,O1l,O2l,O3l,O4l,O5l,O6l,O7l,O0h,O1h,O2h,O3h,O4h,O5h,O6h,O7h; |
118 | 0 | __m512i E00l,E01l,E00h,E01h,EE0l,EE1l,EE2l,EE3l,EE0h,EE1h,EE2h,EE3h; |
119 | 0 | __m512i E4l,E5l,E6l,E7l,E4h,E5h,E6h,E7h; |
120 | |
|
121 | 0 | m0=_mm512_unpacklo_epi16(S[1],S[3]); E0l=_mm512_madd_epi16(m0,T00); |
122 | 0 | m1=_mm512_unpackhi_epi16(S[1],S[3]); E0h=_mm512_madd_epi16(m1,T00); |
123 | 0 | m2=_mm512_unpacklo_epi16(S[5],S[7]); E1l=_mm512_madd_epi16(m2,T10); |
124 | 0 | m3=_mm512_unpackhi_epi16(S[5],S[7]); E1h=_mm512_madd_epi16(m3,T10); |
125 | 0 | m4=_mm512_unpacklo_epi16(S[9],S[11]); E2l=_mm512_madd_epi16(m4,T20); |
126 | 0 | m5=_mm512_unpackhi_epi16(S[9],S[11]); E2h=_mm512_madd_epi16(m5,T20); |
127 | 0 | m6=_mm512_unpacklo_epi16(S[13],S[15]);E3l=_mm512_madd_epi16(m6,T30); |
128 | 0 | m7=_mm512_unpackhi_epi16(S[13],S[15]);E3h=_mm512_madd_epi16(m7,T30); |
129 | 0 | O0l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
130 | 0 | O0h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
131 | |
|
132 | 0 | E0l=_mm512_madd_epi16(m0,T01);E0h=_mm512_madd_epi16(m1,T01);E1l=_mm512_madd_epi16(m2,T11);E1h=_mm512_madd_epi16(m3,T11); |
133 | 0 | E2l=_mm512_madd_epi16(m4,T21);E2h=_mm512_madd_epi16(m5,T21);E3l=_mm512_madd_epi16(m6,T31);E3h=_mm512_madd_epi16(m7,T31); |
134 | 0 | O1l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
135 | 0 | O1h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
136 | |
|
137 | 0 | E0l=_mm512_madd_epi16(m0,T02);E0h=_mm512_madd_epi16(m1,T02);E1l=_mm512_madd_epi16(m2,T12);E1h=_mm512_madd_epi16(m3,T12); |
138 | 0 | E2l=_mm512_madd_epi16(m4,T22);E2h=_mm512_madd_epi16(m5,T22);E3l=_mm512_madd_epi16(m6,T32_);E3h=_mm512_madd_epi16(m7,T32_); |
139 | 0 | O2l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
140 | 0 | O2h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
141 | |
|
142 | 0 | E0l=_mm512_madd_epi16(m0,T03);E0h=_mm512_madd_epi16(m1,T03);E1l=_mm512_madd_epi16(m2,T13);E1h=_mm512_madd_epi16(m3,T13); |
143 | 0 | E2l=_mm512_madd_epi16(m4,T23);E2h=_mm512_madd_epi16(m5,T23);E3l=_mm512_madd_epi16(m6,T33);E3h=_mm512_madd_epi16(m7,T33); |
144 | 0 | O3l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
145 | 0 | O3h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
146 | |
|
147 | 0 | E0l=_mm512_madd_epi16(m0,T04);E0h=_mm512_madd_epi16(m1,T04);E1l=_mm512_madd_epi16(m2,T14);E1h=_mm512_madd_epi16(m3,T14); |
148 | 0 | E2l=_mm512_madd_epi16(m4,T24);E2h=_mm512_madd_epi16(m5,T24);E3l=_mm512_madd_epi16(m6,T34);E3h=_mm512_madd_epi16(m7,T34); |
149 | 0 | O4l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
150 | 0 | O4h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
151 | |
|
152 | 0 | E0l=_mm512_madd_epi16(m0,T05);E0h=_mm512_madd_epi16(m1,T05);E1l=_mm512_madd_epi16(m2,T15);E1h=_mm512_madd_epi16(m3,T15); |
153 | 0 | E2l=_mm512_madd_epi16(m4,T25);E2h=_mm512_madd_epi16(m5,T25);E3l=_mm512_madd_epi16(m6,T35);E3h=_mm512_madd_epi16(m7,T35); |
154 | 0 | O5l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
155 | 0 | O5h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
156 | |
|
157 | 0 | E0l=_mm512_madd_epi16(m0,T06);E0h=_mm512_madd_epi16(m1,T06);E1l=_mm512_madd_epi16(m2,T16);E1h=_mm512_madd_epi16(m3,T16); |
158 | 0 | E2l=_mm512_madd_epi16(m4,T26);E2h=_mm512_madd_epi16(m5,T26);E3l=_mm512_madd_epi16(m6,T36);E3h=_mm512_madd_epi16(m7,T36); |
159 | 0 | O6l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
160 | 0 | O6h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
161 | |
|
162 | 0 | E0l=_mm512_madd_epi16(m0,T07);E0h=_mm512_madd_epi16(m1,T07);E1l=_mm512_madd_epi16(m2,T17);E1h=_mm512_madd_epi16(m3,T17); |
163 | 0 | E2l=_mm512_madd_epi16(m4,T27);E2h=_mm512_madd_epi16(m5,T27);E3l=_mm512_madd_epi16(m6,T37);E3h=_mm512_madd_epi16(m7,T37); |
164 | 0 | O7l=_mm512_add_epi32(_mm512_add_epi32(E0l,E1l),_mm512_add_epi32(E2l,E3l)); |
165 | 0 | O7h=_mm512_add_epi32(_mm512_add_epi32(E0h,E1h),_mm512_add_epi32(E2h,E3h)); |
166 | | |
167 | | // even part |
168 | 0 | m0=_mm512_unpacklo_epi16(S[2],S[6]); E0l=_mm512_madd_epi16(m0,U00); |
169 | 0 | m1=_mm512_unpackhi_epi16(S[2],S[6]); E0h=_mm512_madd_epi16(m1,U00); |
170 | 0 | m2=_mm512_unpacklo_epi16(S[10],S[14]);E0l=_mm512_add_epi32(E0l,_mm512_madd_epi16(m2,U10)); |
171 | 0 | m3=_mm512_unpackhi_epi16(S[10],S[14]);E0h=_mm512_add_epi32(E0h,_mm512_madd_epi16(m3,U10)); |
172 | 0 | E1l=_mm512_madd_epi16(m0,U01);E1h=_mm512_madd_epi16(m1,U01); |
173 | 0 | E1l=_mm512_add_epi32(E1l,_mm512_madd_epi16(m2,U11));E1h=_mm512_add_epi32(E1h,_mm512_madd_epi16(m3,U11)); |
174 | 0 | E2l=_mm512_madd_epi16(m0,U02);E2h=_mm512_madd_epi16(m1,U02); |
175 | 0 | E2l=_mm512_add_epi32(E2l,_mm512_madd_epi16(m2,U12));E2h=_mm512_add_epi32(E2h,_mm512_madd_epi16(m3,U12)); |
176 | 0 | E3l=_mm512_madd_epi16(m0,U03);E3h=_mm512_madd_epi16(m1,U03); |
177 | 0 | E3l=_mm512_add_epi32(E3l,_mm512_madd_epi16(m2,U13));E3h=_mm512_add_epi32(E3h,_mm512_madd_epi16(m3,U13)); |
178 | |
|
179 | 0 | m0=_mm512_unpacklo_epi16(S[4],S[12]); E00l=_mm512_madd_epi16(m0,V00); |
180 | 0 | m1=_mm512_unpackhi_epi16(S[4],S[12]); E00h=_mm512_madd_epi16(m1,V00); |
181 | 0 | m2=_mm512_unpacklo_epi16(S[0],S[8]); EE0l=_mm512_madd_epi16(m2,V10); |
182 | 0 | m3=_mm512_unpackhi_epi16(S[0],S[8]); EE0h=_mm512_madd_epi16(m3,V10); |
183 | 0 | E01l=_mm512_madd_epi16(m0,V01);E01h=_mm512_madd_epi16(m1,V01); |
184 | 0 | EE1l=_mm512_madd_epi16(m2,V11);EE1h=_mm512_madd_epi16(m3,V11); |
185 | |
|
186 | 0 | EE2l=_mm512_sub_epi32(EE1l,E01l);EE3l=_mm512_sub_epi32(EE0l,E00l); |
187 | 0 | EE2h=_mm512_sub_epi32(EE1h,E01h);EE3h=_mm512_sub_epi32(EE0h,E00h); |
188 | 0 | EE0l=_mm512_add_epi32(EE0l,E00l);EE1l=_mm512_add_epi32(EE1l,E01l); |
189 | 0 | EE0h=_mm512_add_epi32(EE0h,E00h);EE1h=_mm512_add_epi32(EE1h,E01h); |
190 | |
|
191 | 0 | E4l=_mm512_sub_epi32(EE3l,E3l); E5l=_mm512_sub_epi32(EE2l,E2l); |
192 | 0 | E6l=_mm512_sub_epi32(EE1l,E1l); E7l=_mm512_sub_epi32(EE0l,E0l); |
193 | 0 | E4h=_mm512_sub_epi32(EE3h,E3h); E5h=_mm512_sub_epi32(EE2h,E2h); |
194 | 0 | E6h=_mm512_sub_epi32(EE1h,E1h); E7h=_mm512_sub_epi32(EE0h,E0h); |
195 | 0 | E0l=_mm512_add_epi32(EE0l,E0l); E1l=_mm512_add_epi32(EE1l,E1l); |
196 | 0 | E2l=_mm512_add_epi32(EE2l,E2l); E3l=_mm512_add_epi32(EE3l,E3l); |
197 | 0 | E0h=_mm512_add_epi32(EE0h,E0h); E1h=_mm512_add_epi32(EE1h,E1h); |
198 | 0 | E2h=_mm512_add_epi32(EE2h,E2h); E3h=_mm512_add_epi32(EE3h,E3h); |
199 | |
|
200 | 0 | resL[0]=_mm512_add_epi32(E0l,O0l); resH[0]=_mm512_add_epi32(E0h,O0h); |
201 | 0 | resL[1]=_mm512_add_epi32(E1l,O1l); resH[1]=_mm512_add_epi32(E1h,O1h); |
202 | 0 | resL[2]=_mm512_add_epi32(E2l,O2l); resH[2]=_mm512_add_epi32(E2h,O2h); |
203 | 0 | resL[3]=_mm512_add_epi32(E3l,O3l); resH[3]=_mm512_add_epi32(E3h,O3h); |
204 | 0 | resL[4]=_mm512_add_epi32(E4l,O4l); resH[4]=_mm512_add_epi32(E4h,O4h); |
205 | 0 | resL[5]=_mm512_add_epi32(E5l,O5l); resH[5]=_mm512_add_epi32(E5h,O5h); |
206 | 0 | resL[6]=_mm512_add_epi32(E6l,O6l); resH[6]=_mm512_add_epi32(E6h,O6h); |
207 | 0 | resL[7]=_mm512_add_epi32(E7l,O7l); resH[7]=_mm512_add_epi32(E7h,O7h); |
208 | 0 | resL[15]=_mm512_sub_epi32(E0l,O0l); resH[15]=_mm512_sub_epi32(E0h,O0h); |
209 | 0 | resL[14]=_mm512_sub_epi32(E1l,O1l); resH[14]=_mm512_sub_epi32(E1h,O1h); |
210 | 0 | resL[13]=_mm512_sub_epi32(E2l,O2l); resH[13]=_mm512_sub_epi32(E2h,O2h); |
211 | 0 | resL[12]=_mm512_sub_epi32(E3l,O3l); resH[12]=_mm512_sub_epi32(E3h,O3h); |
212 | 0 | resL[11]=_mm512_sub_epi32(E4l,O4l); resH[11]=_mm512_sub_epi32(E4h,O4h); |
213 | 0 | resL[10]=_mm512_sub_epi32(E5l,O5l); resH[10]=_mm512_sub_epi32(E5h,O5h); |
214 | 0 | resL[9] =_mm512_sub_epi32(E6l,O6l); resH[9] =_mm512_sub_epi32(E6h,O6h); |
215 | 0 | resL[8] =_mm512_sub_epi32(E7l,O7l); resH[8] =_mm512_sub_epi32(E7h,O7h); |
216 | 0 | } |
217 | | |
218 | 0 | static inline __m512i round_shift_pack(__m512i lo, __m512i hi, __m512i vr, int shift) { |
219 | 0 | return _mm512_packs_epi32( |
220 | 0 | _mm512_srai_epi32(_mm512_add_epi32(lo,vr),shift), |
221 | 0 | _mm512_srai_epi32(_mm512_add_epi32(hi,vr),shift)); |
222 | 0 | } |
223 | | |
224 | | // 1-D 32-point inverse transform in place on S[0..31] (32 columns). |
225 | 0 | static inline void idct32_vpass_512(__m512i S[32], int add, int shift) { |
226 | 0 | __m512i ev[16]; |
227 | 0 | for (int i=0;i<16;i++) ev[i]=S[2*i]; |
228 | 0 | __m512i EL[16], EH[16]; |
229 | 0 | idct16_core_512(ev, EL, EH); |
230 | |
|
231 | 0 | __m512i pl[8], ph[8]; |
232 | 0 | for (int g=0; g<8; g++) { |
233 | 0 | pl[g]=_mm512_unpacklo_epi16(S[4*g+1], S[4*g+3]); |
234 | 0 | ph[g]=_mm512_unpackhi_epi16(S[4*g+1], S[4*g+3]); |
235 | 0 | } |
236 | |
|
237 | 0 | const __m512i vr = _mm512_set1_epi32(add); |
238 | 0 | for (int k=0;k<16;k++) { |
239 | 0 | __m512i OL=_mm512_madd_epi16(pl[0], bc(idct_T32[0][k])); |
240 | 0 | __m512i OH=_mm512_madd_epi16(ph[0], bc(idct_T32[0][k])); |
241 | 0 | for (int g=1; g<8; g++) { |
242 | 0 | OL=_mm512_add_epi32(OL,_mm512_madd_epi16(pl[g], bc(idct_T32[g][k]))); |
243 | 0 | OH=_mm512_add_epi32(OH,_mm512_madd_epi16(ph[g], bc(idct_T32[g][k]))); |
244 | 0 | } |
245 | 0 | S[k] = round_shift_pack(_mm512_add_epi32(EL[k],OL), _mm512_add_epi32(EH[k],OH), vr, shift); |
246 | 0 | S[31-k] = round_shift_pack(_mm512_sub_epi32(EL[k],OL), _mm512_sub_epi32(EH[k],OH), vr, shift); |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | | } // namespace |
251 | | |
252 | | |
253 | | void transform_32x32_add_8_avx512(uint8_t *dst, const int16_t *coeffs, ptrdiff_t stride) |
254 | 0 | { |
255 | 0 | __m512i S[32]; |
256 | 0 | for (int r=0;r<32;r++) S[r]=_mm512_loadu_si512((const void*)(coeffs + r*32)); |
257 | |
|
258 | 0 | idct32_vpass_512(S, add_1st, shift_1st); |
259 | 0 | transpose32x32_z(S); |
260 | 0 | idct32_vpass_512(S, add_2nd, shift_2nd); |
261 | 0 | transpose32x32_z(S); |
262 | | |
263 | | // index to gather the low qword of each 128-bit lane into a contiguous 256 |
264 | 0 | const __m512i gather = _mm512_setr_epi64(0,2,4,6, 1,3,5,7); |
265 | 0 | for (int r=0;r<32;r++) { |
266 | 0 | uint8_t* d = dst + r*stride; |
267 | 0 | __m512i pred = _mm512_cvtepu8_epi16(_mm256_loadu_si256((const __m256i*)d)); // 32 int16 |
268 | 0 | __m512i sum = _mm512_adds_epi16(S[r], pred); |
269 | 0 | __m512i pk = _mm512_packus_epi16(sum, sum); // per lane: [c|c] |
270 | 0 | pk = _mm512_permutexvar_epi64(gather, pk); // low 256 = c0..c31 |
271 | 0 | _mm256_storeu_si256((__m256i*)d, _mm512_castsi512_si256(pk)); |
272 | 0 | } |
273 | 0 | } |
274 | | |
275 | | #endif // HAVE_AVX512 |