GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 373 / 0 / 373
Functions: 100.0% 18 / 0 / 18
Branches: 100.0% 84 / 0 / 84

convert/intel/convert_audio_sse.cpp
Line Branch Exec Source
1 // Avisynth+
2 // https://avs-plus.net
3 //
4 // This file is part of Avisynth+ which is released under GPL2+ with exception.
5
6 // Convert Audio helper functions (SSE2/SSSE3)
7 // Copyright (c) 2020 Xinyue Lu, (c) 2021 pinterf
8
9 #include <avs/types.h>
10 #include <avs/config.h>
11
12 // Intrinsics base header + really required extension headers
13 #if defined(_MSC_VER)
14 #include <intrin.h> // MSVC
15 #else
16 #include <x86intrin.h> // GCC/MinGW/Clang/LLVM
17 #endif
18 #include <smmintrin.h> // SSE4.1
19
20 #if defined(GCC) || defined(CLANG)
21 #define SSE2 __attribute__((__target__("sse2")))
22 #define SSSE3 __attribute__((__target__("ssse3")))
23 #define SSE41 __attribute__((__target__("sse4.1")))
24 #else
25 #define SSE2
26 #define SSSE3
27 #define SSE41
28 #endif
29
30 // Easy: 32-16, 16-32, 32-8, 8-32, 16-8, 8-16
31 // Hard: 32-24, 24-32, 24-16, 16-24, 24-8, 8-24
32 // Float: 32-FLT, FLT-32
33
34 6 SSE2 void convert32To16_SSE2(void *inbuf, void *outbuf, int count) {
35 6 auto in = reinterpret_cast<int32_t *>(inbuf);
36 6 auto in16 = reinterpret_cast<int16_t *>(inbuf);
37 6 auto out = reinterpret_cast<int16_t *>(outbuf);
38
39 6 const int c_loop = count & ~7;
40
41
2/2
✓ Branch 4 → 3 taken 16 times.
✓ Branch 4 → 5 taken 6 times.
22 for (int i = c_loop; i < count; i++)
42 16 out[i] = in16[i * 2 + 1];
43
44
2/2
✓ Branch 18 → 6 taken 7 times.
✓ Branch 18 → 19 taken 6 times.
13 for (int i = 0; i < c_loop; i += 8) {
45 7 __m128i in32a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
46 7 __m128i in32b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
47 7 __m128i in16a = _mm_srai_epi32(in32a, 16);
48 7 __m128i in16b = _mm_srai_epi32(in32b, 16);
49 7 __m128i out16 = _mm_packs_epi32(in16a, in16b);
50 7 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out16); out += 8;
51 }
52 6 }
53
54 6 SSE2 void convert16To32_SSE2(void *inbuf, void *outbuf, int count) {
55 6 auto in = reinterpret_cast<int16_t *>(inbuf);
56 6 auto out = reinterpret_cast<int32_t *>(outbuf);
57 6 auto out16 = reinterpret_cast<int16_t *>(outbuf);
58
59 6 const int c_loop = count & ~7;
60
61
2/2
✓ Branch 4 → 3 taken 16 times.
✓ Branch 4 → 5 taken 6 times.
22 for (int i = c_loop; i < count; i++) {
62 16 out16[i * 2] = 0;
63 16 out16[i * 2 + 1] = in[i];
64 }
65
66 6 __m128i zero = _mm_set1_epi16(0);
67
2/2
✓ Branch 19 → 10 taken 7 times.
✓ Branch 19 → 20 taken 6 times.
13 for (int i = 0; i < c_loop; i += 8) {
68 7 __m128i in16 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 8;
69 7 __m128i out32a = _mm_unpacklo_epi16(zero, in16);
70 7 __m128i out32b = _mm_unpackhi_epi16(zero, in16);
71 7 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32a); out += 4;
72 7 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32b); out += 4;
73 }
74 6 }
75
76 6 SSE2 void convert32To8_SSE2(void *inbuf, void *outbuf, int count) {
77 6 auto in = reinterpret_cast<int32_t *>(inbuf);
78 6 auto in8 = reinterpret_cast<int8_t *>(inbuf);
79 6 auto out = reinterpret_cast<uint8_t *>(outbuf);
80
81 6 const int c_loop = count & ~15;
82
83
2/2
✓ Branch 4 → 3 taken 40 times.
✓ Branch 4 → 5 taken 6 times.
46 for (int i = c_loop; i < count; i++)
84 40 out[i] = in8[i * 4 + 3] + 128;
85
86
2/2
✓ Branch 36 → 6 taken 2 times.
✓ Branch 36 → 37 taken 6 times.
8 for (int i = 0; i < c_loop; i += 16) {
87 2 __m128i in32a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
88 2 __m128i in32b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
89 2 __m128i in32c = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
90 2 __m128i in32d = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
91
92 2 __m128i in8a = _mm_srai_epi32(in32a, 24);
93 2 __m128i in8b = _mm_srai_epi32(in32b, 24);
94 2 __m128i in8c = _mm_srai_epi32(in32c, 24);
95 2 __m128i in8d = _mm_srai_epi32(in32d, 24);
96
97 2 __m128i out8a = _mm_packs_epi32(in8a, in8b);
98 2 __m128i out8b = _mm_packs_epi32(in8c, in8d);
99
100 2 __m128i out8 = _mm_packs_epi16(out8a, out8b);
101
102 4 out8 = _mm_add_epi8(out8, _mm_set1_epi8(-128));
103 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out8); out += 16;
104 }
105 6 }
106
107 6 SSE2 void convert8To32_SSE2(void *inbuf, void *outbuf, int count) {
108 6 auto in = reinterpret_cast<uint8_t *>(inbuf);
109 6 auto out = reinterpret_cast<int32_t *>(outbuf);
110 6 auto out8 = reinterpret_cast<int8_t *>(outbuf);
111
112 6 const int c_loop = count & ~15;
113
114
2/2
✓ Branch 4 → 3 taken 40 times.
✓ Branch 4 → 5 taken 6 times.
46 for (int i = c_loop; i < count; i++) {
115 40 out8[i * 4] = 0;
116 40 out8[i * 4 + 1] = 0;
117 40 out8[i * 4 + 2] = 0;
118 40 out8[i * 4 + 3] = in[i] - 128;
119 }
120
121 6 __m128i n128 = _mm_set1_epi8(-128);
122 6 __m128i zero = _mm_set1_epi16(0);
123
2/2
✓ Branch 35 → 14 taken 2 times.
✓ Branch 35 → 36 taken 6 times.
8 for (int i = 0; i < c_loop; i += 16) {
124 2 __m128i in8 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 16;
125 2 in8 = _mm_add_epi8(in8, n128);
126 2 __m128i v16a = _mm_unpacklo_epi8(zero, in8);
127 2 __m128i v16b = _mm_unpackhi_epi8(zero, in8);
128 2 __m128i out32a = _mm_unpacklo_epi16(zero, v16a);
129 2 __m128i out32b = _mm_unpackhi_epi16(zero, v16a);
130 2 __m128i out32c = _mm_unpacklo_epi16(zero, v16b);
131 2 __m128i out32d = _mm_unpackhi_epi16(zero, v16b);
132 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32a); out += 4;
133 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32b); out += 4;
134 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32c); out += 4;
135 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32d); out += 4;
136 }
137 6 }
138
139 6 SSE2 void convert16To8_SSE2(void *inbuf, void *outbuf, int count) {
140 6 auto in = reinterpret_cast<int16_t *>(inbuf);
141 6 auto in8 = reinterpret_cast<int8_t *>(inbuf);
142 6 auto out = reinterpret_cast<uint8_t *>(outbuf);
143
144 6 const int c_loop = count & ~15;
145
146
2/2
✓ Branch 4 → 3 taken 40 times.
✓ Branch 4 → 5 taken 6 times.
46 for (int i = c_loop; i < count; i++)
147 40 out[i] = in8[i * 2 + 1] + 128;
148
149
2/2
✓ Branch 24 → 6 taken 2 times.
✓ Branch 24 → 25 taken 6 times.
8 for (int i = 0; i < c_loop; i += 16) {
150 2 __m128i in16a = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 8;
151 2 __m128i in16b = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 8;
152 2 __m128i in8a = _mm_srai_epi16(in16a, 8);
153 2 __m128i in8b = _mm_srai_epi16(in16b, 8);
154 2 __m128i out8 = _mm_packs_epi16(in8a, in8b);
155 4 out8 = _mm_add_epi8(out8, _mm_set1_epi8(-128));
156 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out8); out += 16;
157 }
158 6 }
159
160 6 SSE2 void convert8To16_SSE2(void *inbuf, void *outbuf, int count) {
161 6 auto in = reinterpret_cast<uint8_t *>(inbuf);
162 6 auto out = reinterpret_cast<int16_t *>(outbuf);
163 6 auto out8 = reinterpret_cast<int8_t *>(outbuf);
164
165 6 const int c_loop = count & ~15;
166
167
2/2
✓ Branch 4 → 3 taken 40 times.
✓ Branch 4 → 5 taken 6 times.
46 for (int i = c_loop; i < count; i++) {
168 40 out8[i * 2] = 0;
169 40 out8[i * 2 + 1] = in[i] - 128;
170 }
171
172 6 __m128i n128 = _mm_set1_epi8(-128);
173 6 __m128i zero = _mm_set1_epi16(0);
174
2/2
✓ Branch 25 → 14 taken 2 times.
✓ Branch 25 → 26 taken 6 times.
8 for (int i = 0; i < c_loop; i += 16) {
175 2 __m128i in8 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 16;
176 2 in8 = _mm_add_epi8(in8, n128);
177 2 __m128i out16a = _mm_unpacklo_epi8(zero, in8);
178 2 __m128i out16b = _mm_unpackhi_epi8(zero, in8);
179 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out16a); out += 8;
180 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out16b); out += 8;
181 }
182 6 }
183
184 21 SSSE3 void convert32To24_SSSE3(void *inbuf, void *outbuf, int count) {
185 21 auto in = reinterpret_cast<int32_t *>(inbuf);
186 21 auto in8 = reinterpret_cast<int8_t *>(inbuf);
187 21 auto out8 = reinterpret_cast<int8_t *>(outbuf);
188
189 21 const int c_loop = count & ~15;
190
191
2/2
✓ Branch 4 → 3 taken 100 times.
✓ Branch 4 → 5 taken 21 times.
121 for (int i = c_loop; i < count; i++) {
192 100 out8[i * 3 + 0] = in8[i * 4 + 1];
193 100 out8[i * 3 + 1] = in8[i * 4 + 2];
194 100 out8[i * 3 + 2] = in8[i * 4 + 3];
195 }
196
197 __m128i inv[4], outv[3], mask[6];
198 // clang-format off
199 21 mask[0] = _mm_set_epi8(
200 -1, -1, -1, -1,
201 15, 14, 13, 11,
202 10, 9, 7, 6,
203 5, 3, 2, 1);
204 21 mask[1] = _mm_set_epi8(
205 5, 3, 2, 1,
206 -1, -1, -1, -1,
207 -1, -1, -1, -1,
208 -1, -1, -1, -1);
209 21 mask[2] = _mm_set_epi8(
210 -1, -1, -1, -1,
211 -1, -1, -1, -1,
212 15, 14, 13, 11,
213 10, 9, 7, 6);
214 21 mask[3] = _mm_set_epi8(
215 10, 9, 7, 6,
216 5, 3, 2, 1,
217 -1, -1, -1, -1,
218 -1, -1, -1, -1);
219 21 mask[4] = _mm_set_epi8(
220 -1, -1, -1, -1,
221 -1, -1, -1, -1,
222 -1, -1, -1, -1,
223 15, 14, 13, 11);
224 21 mask[5] = _mm_set_epi8(
225 15, 14, 13, 11,
226 10, 9, 7, 6,
227 5, 3, 2, 1,
228 -1, -1, -1, -1);
229
230
2/2
✓ Branch 48 → 18 taken 8 times.
✓ Branch 48 → 49 taken 21 times.
29 for (int i = 0; i < c_loop; i += 16) {
231 8 inv[0] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
232 8 inv[1] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
233 8 inv[2] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
234 8 inv[3] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
235
236 24 outv[0] = _mm_or_si128(
237 _mm_shuffle_epi8(inv[0], mask[0]),
238 _mm_shuffle_epi8(inv[1], mask[1])
239 );
240 24 outv[1] = _mm_or_si128(
241 _mm_shuffle_epi8(inv[1], mask[2]),
242 _mm_shuffle_epi8(inv[2], mask[3])
243 );
244 24 outv[2] = _mm_or_si128(
245 _mm_shuffle_epi8(inv[2], mask[4]),
246 _mm_shuffle_epi8(inv[3], mask[5])
247 );
248
249 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[0]); out8 += 16;
250 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[1]); out8 += 16;
251 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[2]); out8 += 16;
252 }
253 // clang-format on
254 21 }
255
256 21 SSSE3 void convert24To32_SSSE3(void *inbuf, void *outbuf, int count) {
257 21 auto in8 = reinterpret_cast<int8_t *>(inbuf);
258 21 auto out8 = reinterpret_cast<int8_t *>(outbuf);
259 21 auto out = reinterpret_cast<int32_t *>(outbuf);
260
261 21 const int c_loop = count & ~15;
262
263
2/2
✓ Branch 4 → 3 taken 100 times.
✓ Branch 4 → 5 taken 21 times.
121 for (int i = c_loop; i < count; i++) {
264 100 out8[i * 4] = 0;
265 100 out8[i * 4 + 1] = in8[i * 3 + 0];
266 100 out8[i * 4 + 2] = in8[i * 3 + 1];
267 100 out8[i * 4 + 3] = in8[i * 3 + 2];
268 }
269
270 __m128i inv[3], outv[4], mask[6];
271 // clang-format off
272 21 mask[0] = _mm_set_epi8(
273 11, 10, 9, -1,
274 8, 7, 6, -1,
275 5, 4, 3, -1,
276 2, 1, 0, -1);
277 21 mask[1] = _mm_set_epi8(
278 -1, -1, -1, -1,
279 -1, -1, -1, -1,
280 -1, -1, 15, -1,
281 14, 13, 12, -1);
282 21 mask[2] = _mm_set_epi8(
283 7, 6, 5, -1,
284 4, 3, 2, -1,
285 1, 0, -1, -1,
286 -1, -1, -1, -1);
287 21 mask[3] = _mm_set_epi8(
288 -1, -1, -1, -1,
289 -1, 15, 14, -1,
290 13, 12, 11, -1,
291 10, 9, 8, -1);
292 21 mask[4] = _mm_set_epi8(
293 3, 2, 1, -1,
294 0, -1, -1, -1,
295 -1, -1, -1, -1,
296 -1, -1, -1, -1);
297 21 mask[5] = _mm_set_epi8(
298 15, 14, 13, -1,
299 12, 11, 10, -1,
300 9, 8, 7, -1,
301 6, 5, 4, -1);
302
303
2/2
✓ Branch 45 → 18 taken 8 times.
✓ Branch 45 → 46 taken 21 times.
29 for (int i = 0; i < c_loop; i += 16) {
304 8 inv[0] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
305 8 inv[1] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
306 8 inv[2] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
307
308 8 outv[0] = _mm_shuffle_epi8(inv[0], mask[0]);
309 24 outv[1] = _mm_or_si128(
310 _mm_shuffle_epi8(inv[0], mask[1]),
311 _mm_shuffle_epi8(inv[1], mask[2])
312 );
313 24 outv[2] = _mm_or_si128(
314 _mm_shuffle_epi8(inv[1], mask[3]),
315 _mm_shuffle_epi8(inv[2], mask[4])
316 );
317 8 outv[3] = _mm_shuffle_epi8(inv[2], mask[5]);
318
319 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv[0]); out += 4;
320 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv[1]); out += 4;
321 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv[2]); out += 4;
322 8 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv[3]); out += 4;
323 }
324 // clang-format on
325 21 }
326
327 3 SSSE3 void convert24To16_SSSE3(void *inbuf, void *outbuf, int count) {
328 3 auto in8 = reinterpret_cast<int8_t *>(inbuf);
329 3 auto out8 = reinterpret_cast<int8_t *>(outbuf);
330 3 auto out = reinterpret_cast<int16_t *>(outbuf);
331
332 3 const int c_loop = count & ~15;
333
334
2/2
✓ Branch 4 → 3 taken 16 times.
✓ Branch 4 → 5 taken 3 times.
19 for (int i = c_loop; i < count; i++) {
335 16 out8[i * 2 + 0] = in8[i * 3 + 1];
336 16 out8[i * 2 + 1] = in8[i * 3 + 2];
337 }
338
339 __m128i inv[3], outv[2], mask[4];
340 // clang-format off
341 3 mask[0] = _mm_set_epi8(
342 -1, -1, -1, -1,
343 -1, -1, 14, 13,
344 11, 10, 8, 7,
345 5, 4, 2, 1);
346 3 mask[1] = _mm_set_epi8(
347 7, 6, 4, 3,
348 1, 0, -1, -1,
349 -1, -1, -1, -1,
350 -1, -1, -1, -1);
351 3 mask[2] = _mm_set_epi8(
352 -1, -1, -1, -1,
353 -1, -1, -1, -1,
354 -1, -1, -1, 15,
355 13, 12, 10, 9);
356 3 mask[3] = _mm_set_epi8(
357 15, 14, 12, 11,
358 9, 8, 6, 5,
359 3, 2, 0, -1,
360 -1, -1, -1, -1);
361
362
2/2
✓ Branch 35 → 14 taken 2 times.
✓ Branch 35 → 36 taken 3 times.
5 for (int i = 0; i < c_loop; i += 16) {
363 2 inv[0] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
364 2 inv[1] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
365 2 inv[2] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
366
367 6 outv[0] = _mm_or_si128(
368 _mm_shuffle_epi8(inv[0], mask[0]),
369 _mm_shuffle_epi8(inv[1], mask[1])
370 );
371 6 outv[1] = _mm_or_si128(
372 _mm_shuffle_epi8(inv[1], mask[2]),
373 _mm_shuffle_epi8(inv[2], mask[3])
374 );
375
376 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv[0]); out += 8;
377 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv[1]); out += 8;
378 }
379 // clang-format on
380 3 }
381
382 3 SSSE3 void convert16To24_SSSE3(void *inbuf, void *outbuf, int count) {
383 3 auto in = reinterpret_cast<int16_t *>(inbuf);
384 3 auto in8 = reinterpret_cast<int8_t *>(inbuf);
385 3 auto out8 = reinterpret_cast<int8_t *>(outbuf);
386
387 3 const int c_loop = count & ~15;
388
389
2/2
✓ Branch 4 → 3 taken 16 times.
✓ Branch 4 → 5 taken 3 times.
19 for (int i = c_loop; i < count; i++) {
390 16 out8[i * 3] = 0;
391 16 out8[i * 3 + 1] = in8[i * 2 + 0];
392 16 out8[i * 3 + 2] = in8[i * 2 + 1];
393 }
394
395 __m128i inv[2], outv[3], mask[4];
396 // clang-format off
397 3 mask[0] = _mm_set_epi8(
398 -1, 9, 8, -1,
399 7, 6, -1, 5,
400 4, -1, 3, 2,
401 -1, 1, 0, -1);
402 3 mask[1] = _mm_set_epi8(
403 -1, -1, -1, -1,
404 -1, -1, -1, -1,
405 15, 14, -1, 13,
406 12, -1, 11, 10);
407 3 mask[2] = _mm_set_epi8(
408 4, -1, 3, 2,
409 -1, 1, 0, -1,
410 -1, -1, -1, -1,
411 -1, -1, -1, -1);
412 3 mask[3] = _mm_set_epi8(
413 15, 14, -1, 13,
414 12, -1, 11, 10,
415 -1, 9, 8, -1,
416 7, 6, -1, 5);
417
418
2/2
✓ Branch 32 → 14 taken 2 times.
✓ Branch 32 → 33 taken 3 times.
5 for (int i = 0; i < c_loop; i += 16) {
419 2 inv[0] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 8;
420 2 inv[1] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 8;
421
422 2 outv[0] = _mm_shuffle_epi8(inv[0], mask[0]);
423 6 outv[1] = _mm_or_si128(
424 _mm_shuffle_epi8(inv[0], mask[1]),
425 _mm_shuffle_epi8(inv[1], mask[2])
426 );
427 2 outv[2] = _mm_shuffle_epi8(inv[1], mask[3]);
428
429 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[0]); out8 += 16;
430 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[1]); out8 += 16;
431 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[2]); out8 += 16;
432 }
433 // clang-format on
434 3 }
435
436 3 SSSE3 void convert24To8_SSSE3(void *inbuf, void *outbuf, int count) {
437 3 auto in8 = reinterpret_cast<int8_t *>(inbuf);
438 3 auto out = reinterpret_cast<uint8_t *>(outbuf);
439
440 3 const int c_loop = count & ~15;
441
442
2/2
✓ Branch 4 → 3 taken 16 times.
✓ Branch 4 → 5 taken 3 times.
19 for (int i = c_loop; i < count; i++)
443 16 out[i] = in8[i * 3 + 2] + 128;
444
445 __m128i inv[3], outv, mask[3];
446 3 __m128i n128 = _mm_set1_epi8(-128);
447 // clang-format off
448 3 mask[0] = _mm_set_epi8(
449 -1, -1, -1, -1,
450 -1, -1, -1, -1,
451 -1, -1, -1, 14,
452 11, 8, 5, 2);
453 3 mask[1] = _mm_set_epi8(
454 -1, -1, -1, -1,
455 -1, -1, 13, 10,
456 7, 4, 1, -1,
457 -1, -1, -1, -1);
458 3 mask[2] = _mm_set_epi8(
459 15, 12, 9, 6,
460 3, 0, -1, -1,
461 -1, -1, -1, -1,
462 -1, -1, -1, -1);
463
464
2/2
✓ Branch 36 → 16 taken 2 times.
✓ Branch 36 → 37 taken 3 times.
5 for (int i = 0; i < c_loop; i += 16) {
465 2 inv[0] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
466 2 inv[1] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
467 2 inv[2] = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in8)); in8 += 16;
468
469 6 outv = _mm_or_si128(
470 _mm_shuffle_epi8(inv[0], mask[0]),
471 _mm_shuffle_epi8(inv[1], mask[1])
472 );
473 6 outv = _mm_or_si128(
474 outv,
475 _mm_shuffle_epi8(inv[2], mask[2])
476 );
477 2 outv = _mm_add_epi8(outv, n128);
478 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), outv); out += 16;
479 }
480 // clang-format on
481 3 }
482
483 3 SSSE3 void convert8To24_SSSE3(void *inbuf, void *outbuf, int count) {
484 3 auto in = reinterpret_cast<uint8_t *>(inbuf);
485 3 auto out8 = reinterpret_cast<int8_t *>(outbuf);
486
487 3 const int c_loop = count & ~15;
488
489
2/2
✓ Branch 4 → 3 taken 16 times.
✓ Branch 4 → 5 taken 3 times.
19 for (int i = c_loop; i < count; i++) {
490 16 out8[i * 3] = 0;
491 16 out8[i * 3 + 1] = 0;
492 16 out8[i * 3 + 2] = in[i] - 128;
493 }
494
495 __m128i inv, outv[3], mask[3];
496 3 __m128i n128 = _mm_set1_epi8(-128);
497 // clang-format off
498 3 mask[0] = _mm_set_epi8(
499 -1, 4, -1, -1,
500 3, -1, -1, 2,
501 -1, -1, 1, -1,
502 -1, 0, -1, -1);
503 3 mask[1] = _mm_set_epi8(
504 -1, -1, 9, -1,
505 -1, 8, -1, -1,
506 7, -1, -1, 6,
507 -1, -1, 5, -1);
508 3 mask[2] = _mm_set_epi8(
509 15, -1, -1, 14,
510 -1, -1, 13, -1,
511 -1, 12, -1, -1,
512 11, -1, -1, 10);
513
514
2/2
✓ Branch 30 → 16 taken 2 times.
✓ Branch 30 → 31 taken 3 times.
5 for (int i = 0; i < c_loop; i += 16) {
515 2 inv = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 16;
516 2 inv = _mm_add_epi8(inv, n128);
517
518 2 outv[0] = _mm_shuffle_epi8(inv, mask[0]);
519 2 outv[1] = _mm_shuffle_epi8(inv, mask[1]);
520 2 outv[2] = _mm_shuffle_epi8(inv, mask[2]);
521 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[0]); out8 += 16;
522 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[1]); out8 += 16;
523 2 _mm_storeu_si128(reinterpret_cast<__m128i *>(out8), outv[2]); out8 += 16;
524 }
525 // clang-format on
526 3 }
527
528 9 SSE41 void convert8ToFLT_SSE41(void* inbuf, void* outbuf, int count) {
529 9 auto in = reinterpret_cast<uint8_t*>(inbuf);
530 9 auto out = reinterpret_cast<SFLOAT*>(outbuf);
531 9 constexpr float divisor = 1.0f / 128.f; // 1 << 7
532
533 9 const int c_loop = count & ~3;
534
535
2/2
✓ Branch 4 → 3 taken 12 times.
✓ Branch 4 → 5 taken 9 times.
21 for (int i = c_loop; i < count; i++)
536 12 out[i] = (in[i] - 128) * divisor;
537
538 9 __m128 divv = _mm_set1_ps(divisor);
539
2/2
✓ Branch 26 → 8 taken 18 times.
✓ Branch 26 → 27 taken 9 times.
27 for (int i = 0; i < c_loop; i += 4) {
540 54 __m128i in32 = _mm_cvtepu8_epi32(_mm_castps_si128(_mm_load_ss(reinterpret_cast<float *>(in)))); in += 4;
541 36 in32 = _mm_sub_epi32(in32, _mm_set1_epi32(128));
542 18 __m128 infl = _mm_cvtepi32_ps(in32);
543 18 __m128 outfl = _mm_mul_ps(infl, divv);
544 18 _mm_storeu_ps(out, outfl); out += 4;
545 }
546 9 }
547
548 10 SSE2 void convertFLTTo8_SSE2(void* inbuf, void* outbuf, int count) {
549 10 auto in = reinterpret_cast<SFLOAT*>(inbuf);
550 10 auto out = reinterpret_cast<uint8_t*>(outbuf);
551 10 constexpr float multiplier = 128.f;
552 10 constexpr float max8 = 127.f;
553 10 constexpr float min8 = -128.f;
554
555 10 const int c_loop = count & ~3;
556
557
2/2
✓ Branch 9 → 3 taken 13 times.
✓ Branch 9 → 10 taken 10 times.
23 for (int i = c_loop; i < count; i++) {
558 13 float val = in[i] * multiplier;
559 uint8_t result;
560
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 11 times.
13 if (val >= max8) result = 255;
561
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 9 times.
11 else if (val <= min8) result = 0;
562 9 else result = static_cast<int8_t>(val) + 128;
563 13 out[i] = result;
564 }
565
566 10 __m128 mulv = _mm_set1_ps(multiplier);
567 10 __m128 maxv = _mm_set1_ps(max8);
568 10 __m128 minv = _mm_set1_ps(min8);
569
2/2
✓ Branch 40 → 17 taken 22 times.
✓ Branch 40 → 41 taken 10 times.
32 for (int i = 0; i < c_loop; i += 4) {
570 22 __m128 infl = _mm_loadu_ps(in); in += 4;
571 66 __m128 outfl = _mm_max_ps(minv, _mm_min_ps(maxv,_mm_mul_ps(infl, mulv)));
572 22 __m128i out32 = _mm_cvttps_epi32(outfl);
573 22 __m128i out16 = _mm_packs_epi32(out32, out32);
574 22 __m128i out8 = _mm_packs_epi16(out16, out16);
575 44 out8 = _mm_add_epi8(out8, _mm_set1_epi8(-128)); // 128
576 22 *(uint32_t *)(out) = _mm_cvtsi128_si32(out8); out += 4;
577 }
578 10 }
579
580 9 SSE41 void convert16ToFLT_SSE41(void* inbuf, void* outbuf, int count) {
581 9 auto in = reinterpret_cast<int16_t*>(inbuf);
582 9 auto out = reinterpret_cast<SFLOAT*>(outbuf);
583 9 constexpr float divisor = 1.0f / 32768.f; // 1 << 15
584
585 9 const int c_loop = count & ~3;
586
587
2/2
✓ Branch 4 → 3 taken 12 times.
✓ Branch 4 → 5 taken 9 times.
21 for (int i = c_loop; i < count; i++)
588 12 out[i] = in[i] * divisor;
589
590 9 __m128 divv = _mm_set1_ps(divisor);
591
2/2
✓ Branch 22 → 8 taken 18 times.
✓ Branch 22 → 23 taken 9 times.
27 for (int i = 0; i < c_loop; i += 4) {
592 36 __m128i in32 = _mm_cvtepi16_epi32(_mm_loadl_epi64(reinterpret_cast<const __m128i*>(in))); in += 4;
593 18 __m128 infl = _mm_cvtepi32_ps(in32);
594 18 __m128 outfl = _mm_mul_ps(infl, divv);
595 18 _mm_storeu_ps(out, outfl); out += 4;
596 }
597 9 }
598
599 10 SSE2 void convertFLTTo16_SSE2(void* inbuf, void* outbuf, int count) {
600 10 auto in = reinterpret_cast<SFLOAT*>(inbuf);
601 10 auto out = reinterpret_cast<int16_t*>(outbuf);
602 10 constexpr float multiplier = 32768.f;
603 10 constexpr float max16 = 32767.f;
604 10 constexpr float min16 = -32768.f;
605
606 10 const int c_loop = count & ~3;
607
608
2/2
✓ Branch 9 → 3 taken 13 times.
✓ Branch 9 → 10 taken 10 times.
23 for (int i = c_loop; i < count; i++) {
609 13 float val = in[i] * multiplier;
610 int16_t result;
611
2/2
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 11 times.
13 if (val >= max16) result = 32767;
612
2/2
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 9 times.
11 else if (val <= min16) result = (int16_t)-32768;
613 9 else result = static_cast<int16_t>(val);
614 13 out[i] = result;
615 }
616
617 10 __m128 mulv = _mm_set1_ps(multiplier);
618 10 __m128 maxv = _mm_set1_ps(max16);
619 10 __m128 minv = _mm_set1_ps(min16);
620
2/2
✓ Branch 31 → 17 taken 22 times.
✓ Branch 31 → 32 taken 10 times.
32 for (int i = 0; i < c_loop; i += 4) {
621 22 __m128 infl = _mm_loadu_ps(in); in += 4;
622 66 __m128 outfl = _mm_max_ps(minv, _mm_min_ps(maxv, _mm_mul_ps(infl, mulv)));
623 22 __m128i out32 = _mm_cvttps_epi32(outfl);
624 22 __m128i out16 = _mm_packs_epi32(out32, out32);
625 22 _mm_storel_epi64(reinterpret_cast<__m128i*>(out), out16); out += 4;
626 }
627 10 }
628
629 21 SSE2 void convert32ToFLT_SSE2(void *inbuf, void *outbuf, int count) {
630 21 auto in = reinterpret_cast<int32_t *>(inbuf);
631 21 auto out = reinterpret_cast<SFLOAT *>(outbuf);
632 21 const float divisor = 1.0f/2147483648.0f;
633
634 21 const int c_loop = count & ~3;
635
636
2/2
✓ Branch 4 → 3 taken 28 times.
✓ Branch 4 → 5 taken 21 times.
49 for (int i = c_loop; i < count; i++)
637 28 out[i] = in[i] * divisor;
638
639 21 __m128 divv = _mm_set1_ps(divisor);
640
2/2
✓ Branch 16 → 8 taken 44 times.
✓ Branch 16 → 17 taken 21 times.
65 for (int i = 0; i < c_loop; i += 4) {
641 44 __m128i in32 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)); in += 4;
642 44 __m128 infl = _mm_cvtepi32_ps(in32);
643 44 __m128 outfl = _mm_mul_ps(infl, divv);
644 44 _mm_storeu_ps(out, outfl); out += 4;
645 }
646 21 }
647
648 22 SSE41 void convertFLTTo32_SSE41(void *inbuf, void *outbuf, int count) {
649 22 auto in = reinterpret_cast<SFLOAT *>(inbuf);
650 22 auto out = reinterpret_cast<int32_t *>(outbuf);
651 22 constexpr float multiplier = 2147483648.0f;
652 22 constexpr float max32 = 2147483647.0f; // 2147483648.0f in reality
653 22 constexpr float min32 = -2147483648.0f;
654
655 22 const int c_loop = count & ~3;
656
657
2/2
✓ Branch 9 → 3 taken 29 times.
✓ Branch 9 → 10 taken 22 times.
51 for (int i = c_loop; i < count; i++) {
658 29 float val = in[i] * multiplier;
659 int32_t result;
660
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 26 times.
29 if (val >= max32) result = 0x7FFFFFFF; // 2147483647
661
2/2
✓ Branch 5 → 6 taken 6 times.
✓ Branch 5 → 7 taken 20 times.
26 else if (val <= min32) result = 0x80000000; // -2147483648
662 20 else result = static_cast<int32_t>(val);
663 29 out[i] = result;
664 }
665
666 22 __m128 mulv = _mm_set1_ps(multiplier);
667 22 __m128 maxv = _mm_set1_ps(max32);
668 22 __m128 minv = _mm_set1_ps(min32);
669 22 __m128i maxv_i = _mm_set1_epi32(0x7FFFFFFF); // 2147483647
670 22 __m128i minv_i = _mm_set1_epi32(0x80000000); // -2147483648
671
2/2
✓ Branch 45 → 25 taken 48 times.
✓ Branch 45 → 46 taken 22 times.
70 for (int i = 0; i < c_loop; i += 4) {
672 48 __m128 infl = _mm_loadu_ps(in); in += 4;
673 48 __m128 outfl = _mm_mul_ps(infl, mulv);
674 96 __m128i cmphigh = _mm_castps_si128(_mm_cmpge_ps(outfl, maxv));
675 96 __m128i cmplow = _mm_castps_si128(_mm_cmpge_ps(minv, outfl));
676 48 __m128i out32 = _mm_cvttps_epi32(outfl);
677 48 out32 = _mm_blendv_epi8(out32, maxv_i, cmphigh);
678 48 out32 = _mm_blendv_epi8(out32, minv_i, cmplow);
679 48 _mm_storeu_si128(reinterpret_cast<__m128i *>(out), out32); out += 4;
680 }
681 22 }
682