Assembly SIMD按变量旋转
以仅在运行时已知的数量对整个YMM寄存器执行旋转操作的最快方法是什么Assembly SIMD按变量旋转,assembly,x86,x86-64,sse,avx,Assembly,X86,X86 64,Sse,Avx,以仅在运行时已知的数量对整个YMM寄存器执行旋转操作的最快方法是什么 已知旋转是64位的倍数。对于AVX2,您可以使用\u mm256\u permutevar8x32\u epi32。伪代码(未测试,常量可能错误): 您可以使用AVX向右旋转,如下所示。假设您的输入是x: __m256d t0 = _mm256_permute_pd(x, 0x05); // [x2 x3 x0 x1] __m256d t1 = _mm256_permute2f128_pd(t0,
已知旋转是64位的倍数。对于AVX2,您可以使用
\u mm256\u permutevar8x32\u epi32
。伪代码(未测试,常量可能错误):
您可以使用AVX向右旋转,如下所示。假设您的输入是
x
:
__m256d t0 = _mm256_permute_pd(x, 0x05); // [x2 x3 x0 x1]
__m256d t1 = _mm256_permute2f128_pd(t0, t0, 0x01); // [x0 x1 x2 x3]
__m256d y = _mm256_blend_pd(t0, t1, 0x0a); // [x0 x3 x2 x1]
结果显示为y
。通过反转混合遮罩,可以向左旋转:
__m256d t0 = _mm256_permute_pd(x, 0x05); // [x2 x3 x0 x1]
__m256d t1 = _mm256_permute2f128_pd(t0, t0, 0x01); // [x0 x1 x2 x3]
__m256d y = _mm256_blend_pd(t0, t1, 0x05); // [x2 x1 x0 x3]
有四种旋转:0位、64位、128位和192位。0位是微不足道的。Felix Whyss的解决方案适用于64位,适用于AVX的解决方案适用于192位。但是对于128位,您可以简单地交换高128位和低128位字。这是AVX和AVX2的最佳解决方案
_mm256_permute2f128_pd(x,x,0x01)如果您仅限于AVX指令,您仍然可以使用条件混合指令(
VBLENDVPD
)来选择正确的旋转,而无需使用开关。这可能会更快,尤其是当情况无法轻易预测时
正确轮换的全面实施(已测试):
左旋转可以简单地完成如下操作
__m256d rotate_pd_left(__m256d x, int n) {
return rotate_pd_right(x, -n);
}
需要明确的是,这是一个
向右旋转(\uuuum256i x,无符号n)
。使用AVX怎么样?我的电脑只有一个常春藤网桥处理器。你可以用一个带有4个机箱的交换机。我不认为有一个有效的方法来做AVX。实际上我不需要这个,只有其他3种情况
// rotate packed double vector right by n
__m256d rotate_pd_right(__m256d x, int n) {
__m128i c = _mm_cvtsi32_si128(n);
__m128i cc = _mm_unpacklo_epi64(c,c);
// create blend masks (highest bit)
__m128d half_low = _mm_castsi128_pd(_mm_slli_epi64(cc, 63));
__m128d swap_low = _mm_castsi128_pd(_mm_slli_epi64(cc, 62));
__m256d half = _mm256_insertf128_pd(_mm256_castpd128_pd256(half_low), half_low, 1);
__m256d swap = _mm256_insertf128_pd(_mm256_castpd128_pd256(swap_low), swap_low, 1);
// compute rotations
__m256d t0 = _mm256_permute_pd(x, 0x05); // [2 3 0 1]
__m256d t1 = _mm256_permute2f128_pd(t0, t0, 0x01); // [1 0 2 3]
__m256d y0 = x; // [3 2 1 0]
__m256d y1 = _mm256_blend_pd(t0, t1, 0x0a); // [0 3 2 1]
__m256d y2 = _mm256_permute2f128_pd(x, x, 0x01); // [1 0 3 2]
__m256d y3 = _mm256_blend_pd(t0, t1, 0x05); // [2 1 0 3]
// select correct rotation
__m256d y01 = _mm256_blendv_pd(y0, y1, half);
__m256d y23 = _mm256_blendv_pd(y2, y3, half);
__m256d yn = _mm256_blendv_pd(y01, y23, swap);
return yn;
}
__m256d rotate_pd_left(__m256d x, int n) {
return rotate_pd_right(x, -n);
}