Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly SIMD按变量旋转_Assembly_X86_X86 64_Sse_Avx - Fatal编程技术网

Assembly SIMD按变量旋转

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,

以仅在运行时已知的数量对整个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, 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);
}