convert/intel/convert_audio_avx2.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 (AVX2) | ||
| 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 <immintrin.h> // AVX2 | ||
| 19 | |||
| 20 | |||
| 21 | // Easy: 32-16, 16-32 | ||
| 22 | // Float: 8/16/32-FLT, FLT-8/16/32 | ||
| 23 | |||
| 24 | 6 | void convert32To16_AVX2(void *inbuf, void *outbuf, int count) { | |
| 25 | 6 | auto in = reinterpret_cast<int32_t *>(inbuf); | |
| 26 | 6 | auto in16 = reinterpret_cast<int16_t *>(inbuf); | |
| 27 | 6 | auto out = reinterpret_cast<int16_t *>(outbuf); | |
| 28 | |||
| 29 | 6 | const int c_loop = count & ~15; | |
| 30 | |||
| 31 |
2/2✓ Branch 4 → 3 taken 40 times.
✓ Branch 4 → 5 taken 6 times.
|
46 | for (int i = c_loop; i < count; i++) |
| 32 | 40 | out[i] = in16[i * 2 + 1]; | |
| 33 | |||
| 34 |
2/2✓ Branch 18 → 6 taken 2 times.
✓ Branch 18 → 19 taken 6 times.
|
8 | for (int i = 0; i < c_loop; i += 16) { |
| 35 | 2 | __m256i in32a = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); in += 8; | |
| 36 | 2 | __m256i in32b = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); in += 8; | |
| 37 | 2 | __m256i in16a = _mm256_srai_epi32(in32a, 16); | |
| 38 | 2 | __m256i in16b = _mm256_srai_epi32(in32b, 16); | |
| 39 | 2 | __m256i out16 = _mm256_packs_epi32(in16a, in16b); | |
| 40 | 2 | out16 = _mm256_permute4x64_epi64(out16, 216); | |
| 41 | 2 | _mm256_storeu_si256(reinterpret_cast<__m256i *>(out), out16); out += 16; | |
| 42 | } | ||
| 43 | 6 | } | |
| 44 | |||
| 45 | 6 | void convert16To32_AVX2(void *inbuf, void *outbuf, int count) { | |
| 46 | 6 | auto in = reinterpret_cast<int16_t *>(inbuf); | |
| 47 | 6 | auto out = reinterpret_cast<int32_t *>(outbuf); | |
| 48 | 6 | auto out16 = reinterpret_cast<int16_t *>(outbuf); | |
| 49 | |||
| 50 | 6 | const int c_loop = count & ~15; | |
| 51 | |||
| 52 |
2/2✓ Branch 4 → 3 taken 40 times.
✓ Branch 4 → 5 taken 6 times.
|
46 | for (int i = c_loop; i < count; i++) { |
| 53 | 40 | out16[i * 2] = 0; | |
| 54 | 40 | out16[i * 2 + 1] = in[i]; | |
| 55 | } | ||
| 56 | |||
| 57 | 6 | __m256i zero = _mm256_set1_epi16(0); | |
| 58 |
2/2✓ Branch 19 → 10 taken 2 times.
✓ Branch 19 → 20 taken 6 times.
|
8 | for (int i = 0; i < c_loop; i += 16) { |
| 59 | 2 | __m256i in16 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); in += 16; | |
| 60 | 2 | in16 = _mm256_permute4x64_epi64(in16, 216); | |
| 61 | 2 | __m256i out32a = _mm256_unpacklo_epi16(zero, in16); | |
| 62 | 2 | __m256i out32b = _mm256_unpackhi_epi16(zero, in16); | |
| 63 | 2 | _mm256_storeu_si256(reinterpret_cast<__m256i *>(out), out32a); out += 8; | |
| 64 | 2 | _mm256_storeu_si256(reinterpret_cast<__m256i *>(out), out32b); out += 8; | |
| 65 | } | ||
| 66 | 6 | } | |
| 67 | |||
| 68 | 9 | void convert8ToFLT_AVX2(void* inbuf, void* outbuf, int count) { | |
| 69 | 9 | auto in = reinterpret_cast<uint8_t*>(inbuf); | |
| 70 | 9 | auto out = reinterpret_cast<SFLOAT*>(outbuf); | |
| 71 | 9 | constexpr float divisor = 1.0f / 128.f; // 1 << 7 | |
| 72 | |||
| 73 | 9 | const int c_loop = count & ~7; | |
| 74 | |||
| 75 |
2/2✓ Branch 4 → 3 taken 28 times.
✓ Branch 4 → 5 taken 9 times.
|
37 | for (int i = c_loop; i < count; i++) |
| 76 | 28 | out[i] = (in[i] - 128) * divisor; | |
| 77 | |||
| 78 | 9 | __m256 divv = _mm256_set1_ps(divisor); | |
| 79 |
2/2✓ Branch 26 → 8 taken 7 times.
✓ Branch 26 → 27 taken 9 times.
|
16 | for (int i = 0; i < c_loop; i += 8) { |
| 80 | 7 | __m128i src = _mm_loadl_epi64(reinterpret_cast<__m128i*>(in)); in += 8; | |
| 81 | 7 | __m256i in32 = _mm256_cvtepu8_epi32(src); | |
| 82 | 14 | in32 = _mm256_sub_epi32(in32, _mm256_set1_epi32(128)); | |
| 83 | 7 | __m256 infl = _mm256_cvtepi32_ps(in32); | |
| 84 | 7 | __m256 outfl = _mm256_mul_ps(infl, divv); | |
| 85 | 7 | _mm256_storeu_ps(out, outfl); out += 8; | |
| 86 | } | ||
| 87 | 9 | } | |
| 88 | |||
| 89 | 10 | void convertFLTTo8_AVX2(void* inbuf, void* outbuf, int count) { | |
| 90 | 10 | auto in = reinterpret_cast<SFLOAT*>(inbuf); | |
| 91 | 10 | auto out = reinterpret_cast<uint8_t*>(outbuf); | |
| 92 | 10 | constexpr float multiplier = 128.f; | |
| 93 | 10 | constexpr float max8 = 127.f; | |
| 94 | 10 | constexpr float min8 = -128.f; | |
| 95 | |||
| 96 | 10 | const int c_loop = count & ~15; | |
| 97 | |||
| 98 |
2/2✓ Branch 9 → 3 taken 53 times.
✓ Branch 9 → 10 taken 10 times.
|
63 | for (int i = c_loop; i < count; i++) { |
| 99 | 53 | float val = in[i] * multiplier; | |
| 100 | uint8_t result; | ||
| 101 |
2/2✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 51 times.
|
53 | if (val >= max8) result = 255; |
| 102 |
2/2✓ Branch 5 → 6 taken 14 times.
✓ Branch 5 → 7 taken 37 times.
|
51 | else if (val <= min8) result = 0; |
| 103 | 37 | else result = static_cast<int8_t>(val) + 128; | |
| 104 | 53 | out[i] = result; | |
| 105 | } | ||
| 106 | |||
| 107 | 10 | __m256 mulv = _mm256_set1_ps(multiplier); | |
| 108 | 10 | __m256 maxv = _mm256_set1_ps(max8); | |
| 109 | 10 | __m256 minv = _mm256_set1_ps(min8); | |
| 110 |
2/2✓ Branch 51 → 17 taken 3 times.
✓ Branch 51 → 52 taken 10 times.
|
13 | for (int i = 0; i < c_loop; i += 16) { |
| 111 | 3 | __m256 infl_lo = _mm256_loadu_ps(in); in += 8; | |
| 112 | 3 | __m256 infl_hi = _mm256_loadu_ps(in); in += 8; | |
| 113 | 9 | __m256 outfl_lo = _mm256_max_ps(minv, _mm256_min_ps(maxv, _mm256_mul_ps(infl_lo, mulv))); | |
| 114 | 9 | __m256 outfl_hi = _mm256_max_ps(minv, _mm256_min_ps(maxv, _mm256_mul_ps(infl_hi, mulv))); | |
| 115 | 3 | __m256i out32_lo = _mm256_cvttps_epi32(outfl_lo); | |
| 116 | 3 | __m256i out32_hi = _mm256_cvttps_epi32(outfl_hi); | |
| 117 | 3 | __m256i out16 = _mm256_packs_epi32(out32_lo, out32_hi); | |
| 118 | |||
| 119 | 3 | out16 = _mm256_permute4x64_epi64(out16, (0 << 0) | (2 << 2) | (1 << 4) | (3 << 6)); | |
| 120 | 3 | __m128i out16_lo = _mm256_castsi256_si128(out16); | |
| 121 | 3 | __m128i out16_hi = _mm256_extractf128_si256(out16, 1); | |
| 122 | 3 | __m128i out8 = _mm_packs_epi16(out16_lo, out16_hi); | |
| 123 | 6 | out8 = _mm_add_epi8(out8, _mm_set1_epi8(-128)); // 128 | |
| 124 | 3 | _mm_storeu_si128(reinterpret_cast<__m128i*>(out), out8); out += 16; | |
| 125 | } | ||
| 126 | 10 | } | |
| 127 | |||
| 128 | 10 | void convert16ToFLT_AVX2(void* inbuf, void* outbuf, int count) { | |
| 129 | 10 | auto in = reinterpret_cast<int16_t*>(inbuf); | |
| 130 | 10 | auto out = reinterpret_cast<SFLOAT*>(outbuf); | |
| 131 | 10 | constexpr float divisor = 1.0f / 32768.f; // 1 << 15 | |
| 132 | |||
| 133 | 10 | const int c_loop = count & ~7; | |
| 134 | |||
| 135 |
2/2✓ Branch 4 → 3 taken 32 times.
✓ Branch 4 → 5 taken 10 times.
|
42 | for (int i = c_loop; i < count; i++) |
| 136 | 32 | out[i] = in[i] * divisor; | |
| 137 | |||
| 138 | 10 | __m256 divv = _mm256_set1_ps(divisor); | |
| 139 |
2/2✓ Branch 18 → 8 taken 7 times.
✓ Branch 18 → 19 taken 10 times.
|
17 | for (int i = 0; i < c_loop; i += 8) { |
| 140 | 7 | __m128i src = _mm_loadu_si128(reinterpret_cast<__m128i*>(in)); in += 8; | |
| 141 | 7 | __m256i in32 = _mm256_cvtepi16_epi32(src); | |
| 142 | 7 | __m256 infl = _mm256_cvtepi32_ps(in32); | |
| 143 | 7 | __m256 outfl = _mm256_mul_ps(infl, divv); | |
| 144 | 7 | _mm256_storeu_ps(out, outfl); out += 8; | |
| 145 | } | ||
| 146 | 10 | } | |
| 147 | |||
| 148 | 12 | void convertFLTTo16_AVX2(void* inbuf, void* outbuf, int count) { | |
| 149 | 12 | auto in = reinterpret_cast<SFLOAT*>(inbuf); | |
| 150 | 12 | auto out = reinterpret_cast<int16_t*>(outbuf); | |
| 151 | 12 | constexpr float multiplier = 32768.f; | |
| 152 | 12 | constexpr float max16 = 32767.f; | |
| 153 | 12 | constexpr float min16 = -32768.f; | |
| 154 | |||
| 155 | 12 | const int c_loop = count & ~7; | |
| 156 | |||
| 157 |
2/2✓ Branch 9 → 3 taken 37 times.
✓ Branch 9 → 10 taken 12 times.
|
49 | for (int i = c_loop; i < count; i++) { |
| 158 | 37 | float val = in[i] * multiplier; | |
| 159 | int16_t result; | ||
| 160 |
2/2✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 5 taken 33 times.
|
37 | if (val >= max16) result = 32767; |
| 161 |
2/2✓ Branch 5 → 6 taken 10 times.
✓ Branch 5 → 7 taken 23 times.
|
33 | else if (val <= min16) result = (int16_t)-32768; |
| 162 | 23 | else result = static_cast<int16_t>(val); | |
| 163 | 37 | out[i] = result; | |
| 164 | } | ||
| 165 | |||
| 166 | 12 | __m256 mulv = _mm256_set1_ps(multiplier); | |
| 167 | 12 | __m256 maxv = _mm256_set1_ps(max16); | |
| 168 | 12 | __m256 minv = _mm256_set1_ps(min16); | |
| 169 |
2/2✓ Branch 33 → 17 taken 9 times.
✓ Branch 33 → 34 taken 12 times.
|
21 | for (int i = 0; i < c_loop; i += 8) { |
| 170 | 9 | __m256 infl = _mm256_loadu_ps(in); in += 8; | |
| 171 | 27 | __m256 outfl = _mm256_max_ps(minv, _mm256_min_ps(maxv, _mm256_mul_ps(infl, mulv))); | |
| 172 | 9 | __m256i out32 = _mm256_cvttps_epi32(outfl); | |
| 173 | 9 | __m256i out16 = _mm256_packs_epi32(out32, out32); | |
| 174 | |||
| 175 | 9 | out16 = _mm256_permute4x64_epi64(out16, (0 << 0) | (2 << 2) | (1 << 4) | (3 << 6)); | |
| 176 | |||
| 177 | 9 | _mm_storeu_si128(reinterpret_cast<__m128i*>(out), _mm256_castsi256_si128(out16)); out += 8; | |
| 178 | } | ||
| 179 | 12 | } | |
| 180 | |||
| 181 | |||
| 182 | |||
| 183 | 21 | void convert32ToFLT_AVX2(void *inbuf, void *outbuf, int count) { | |
| 184 | 21 | auto in = reinterpret_cast<int32_t *>(inbuf); | |
| 185 | 21 | auto out = reinterpret_cast<SFLOAT *>(outbuf); | |
| 186 | 21 | const float divisor = 1.0f/2147483648.0f; | |
| 187 | |||
| 188 | 21 | const int c_loop = count & ~7; | |
| 189 | |||
| 190 |
2/2✓ Branch 4 → 3 taken 68 times.
✓ Branch 4 → 5 taken 21 times.
|
89 | for (int i = c_loop; i < count; i++) |
| 191 | 68 | out[i] = in[i] * divisor; | |
| 192 | |||
| 193 | 21 | __m256 divv = _mm256_set1_ps(divisor); | |
| 194 |
2/2✓ Branch 16 → 8 taken 17 times.
✓ Branch 16 → 17 taken 21 times.
|
38 | for (int i = 0; i < c_loop; i += 8) { |
| 195 | 17 | __m256i in32 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); in += 8; | |
| 196 | 17 | __m256 infl = _mm256_cvtepi32_ps(in32); | |
| 197 | 17 | __m256 outfl = _mm256_mul_ps(infl, divv); | |
| 198 | 17 | _mm256_storeu_ps(out, outfl); out += 8; | |
| 199 | } | ||
| 200 | 21 | } | |
| 201 | |||
| 202 | 22 | void convertFLTTo32_AVX2(void *inbuf, void *outbuf, int count) { | |
| 203 | 22 | auto in = reinterpret_cast<SFLOAT *>(inbuf); | |
| 204 | 22 | auto out = reinterpret_cast<int32_t *>(outbuf); | |
| 205 | 22 | const float multiplier = 2147483648.0f; | |
| 206 | 22 | const float max32 = 2147483647.0f; // 2147483648.0f in reality | |
| 207 | 22 | const float min32 = -2147483648.0f; | |
| 208 | |||
| 209 | 22 | const int c_loop = count & ~7; | |
| 210 | |||
| 211 |
2/2✓ Branch 9 → 3 taken 69 times.
✓ Branch 9 → 10 taken 22 times.
|
91 | for (int i = c_loop; i < count; i++) { |
| 212 | 69 | float val = in[i] * multiplier; | |
| 213 | int32_t result; | ||
| 214 |
2/2✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 66 times.
|
69 | if (val >= max32) result = 0x7FFFFFFF; // 2147483647 |
| 215 |
2/2✓ Branch 5 → 6 taken 20 times.
✓ Branch 5 → 7 taken 46 times.
|
66 | else if (val <= min32) result = 0x80000000; // -2147483648 |
| 216 | 46 | else result = static_cast<int32_t>(val); | |
| 217 | 69 | out[i] = result; | |
| 218 | } | ||
| 219 | |||
| 220 | 22 | __m256 mulv = _mm256_set1_ps(multiplier); | |
| 221 | 22 | __m256 maxv = _mm256_set1_ps(max32); | |
| 222 | 22 | __m256 minv = _mm256_set1_ps(min32); | |
| 223 | 22 | __m256i maxv_i = _mm256_set1_epi32(0x7FFFFFFF); // 2147483647 | |
| 224 | 22 | __m256i minv_i = _mm256_set1_epi32(0x80000000); // -2147483648 | |
| 225 |
2/2✓ Branch 37 → 21 taken 19 times.
✓ Branch 37 → 38 taken 22 times.
|
41 | for (int i = 0; i < c_loop; i += 8) { |
| 226 | 19 | __m256 infl = _mm256_loadu_ps(in); in += 8; | |
| 227 | 19 | __m256 outfl = _mm256_mul_ps(infl, mulv); | |
| 228 | 19 | __m256i cmphigh = _mm256_castps_si256(_mm256_cmp_ps(outfl, maxv, _CMP_GE_OS)); | |
| 229 | 38 | __m256i cmplow = _mm256_castps_si256(_mm256_cmp_ps(minv, outfl, _CMP_GE_OS)); | |
| 230 | 19 | __m256i out32 = _mm256_cvttps_epi32(outfl); | |
| 231 | 19 | out32 = _mm256_blendv_epi8(out32, maxv_i, cmphigh); | |
| 232 | 19 | out32 = _mm256_blendv_epi8(out32, minv_i, cmplow); | |
| 233 | |||
| 234 | 19 | _mm256_storeu_si256(reinterpret_cast<__m256i *>(out), out32); out += 8; | |
| 235 | } | ||
| 236 | 22 | } | |
| 237 |