【发布时间】:2018-01-18 23:52:59
【问题描述】:
我有一个名为 A 的 array,其中包含 32 个 unsigned char 值。
我想使用此规则将这些值解压缩到 4 个 __m256 变量中,假设我们对来自 A 的所有值都有一个从 0 到 31 的索引,解压缩后的 4 个变量将具有这些值:
B_0 = A[0], A[4], A[8], A[12], A[16], A[20], A[24], A[28]
B_1 = A[1], A[5], A[9], A[13], A[17], A[21], A[25], A[29]
B_2 = A[2], A[6], A[10], A[14], A[18], A[22], A[26], A[30]
B_3 = A[3], A[7], A[11], A[15], A[19], A[23], A[27], A[31]
为此,我有以下代码:
const auto mask = _mm256_set1_epi32( 0x000000FF );
...
const auto A_values = _mm256_i32gather_epi32(reinterpret_cast<const int*>(A.data(), A_positions.values_, 4);
// This code bellow is equivalent to B_0 = static_cast<float>((A_value >> 24) & 0x000000FF)
const auto B_0 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 24), mask));
const auto B_1 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 16), mask));
const auto B_2 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 8), mask));
const auto B_3 = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_srai_epi32(A_values, 0), mask));
这很好用,但我想知道是否有更快的方法来做到这一点,特别是关于我用来检索值的右移和和运算符。
另外,为了澄清起见,我说 array A 的大小为 32,但这不是真的,这个数组包含更多的值,我需要从不同的位置访问它的元素(但总是从块4 uint8_t) 这就是为什么我使用 _mm256_i32gather_epi23 来检索这些值。为了简单起见,我只是在此示例中限制了 array 的大小。
【问题讨论】:
-
显然可以删除 0 的移位,Clang 会自动执行此操作,但 GCC 和 MSVC 不会。
-
使用
_mm256_srai_epi32(A_values, 24)不需要用二进制and 0x000000FF屏蔽高位,因为它们已经是0。 -
@wim 也改成
_mm256_srli_epi32然后 -
@harold 是的,逻辑移位而不是算术移位。我没有注意到
_mm256_srai_epi32中的a。 -
输出的顺序是一成不变的吗?否则,使用
_mm256_cvtepi32_ps(_mm256_cvtepu8_epi32(...))可能是另一种选择。
标签: c++ performance simd avx2