使用AVX内在函数压缩掩码

dsd*_*dsd 5 c x86 simd intrinsics avx

我想通过省略每64位双精度的上半部分,将两个256位向量(__m256d)包含掩码作为比较操作(例如_mm256_cmp_pd)到一个256位向量的结果.

因此,如果在下面,a_i, b_i, ...是32位字,我有两个256位(4 x双)矢量具有以下结构:

a_0, a_0, b_0, b_0, c_0, c_0, d_0, d_0,和a_1, a_1, b_1, b_1, c_1, c_1, d_1, d_1.

我想要一个具有以下结构的256位向量:

a_0, b_0, c_0, d_0, a_1, b_1, c_1, d_1.

如何使用英特尔内在函数有效地完成此操作?可用的指令集是AVX的一切.

Pau*_*l R 4

看起来您可以利用以下事实:全 1 的位模式NaN在单精度和双精度中都是 a,类似地,全 0 的位模式在这两种情况下都是 0.0。因此,要将两个双掩码向量打包到单个浮点向量中,您可以这样做:

 __m256 v = _mm256_set_m128(_mm256_cvtpd_ps(v0), _mm256_cvtpd_ps(v1));
Run Code Online (Sandbox Code Playgroud)

请注意,如果您没有_mm256_set_m128,则可以将其定义为:

#define _mm256_set_m128(va, vb) \
        _mm256_insertf128_ps(_mm256_castps128_ps256(vb), va, 1)
Run Code Online (Sandbox Code Playgroud)

这是一个演示:

#include <stdio.h>
#include <immintrin.h>

#define _mm256_set_m128(va, vb) \
        _mm256_insertf128_ps(_mm256_castps128_ps256(vb), va, 1)

static void printvd(const char * label, __m256d v)
{
    int64_t a[4];
    _mm256_storeu_pd((double *)a, v);
    printf("%s = %lld %lld %lld %lld\n", label, a[0],  a[1],  a[2],  a[3]);
}

static void printvf(const char * label, __m256 v)
{
    int32_t a[8];
    _mm256_storeu_ps((float *)a, v);
    printf("%s = %d %d %d %d %d %d %d %d\n", label, a[0],  a[1],  a[2],  a[3],  a[4],  a[5],  a[6],  a[7]);
}

int main()
{
    __m256d v0 = _mm256_set_pd(0.0, 1.0, 2.0, 3.0);
    __m256d v1 = _mm256_set_pd(3.0, 2.0, 1.0, 0.0);
    __m256d vcmp0 = _mm256_cmp_pd(v0, v1, 1);
    __m256d vcmp1 = _mm256_cmp_pd(v1, v0, 1);
    __m256 vcmp = _mm256_set_m128(_mm256_cvtpd_ps(vcmp0), _mm256_cvtpd_ps(vcmp1));
    printvd("vcmp0", vcmp0);
    printvd("vcmp1", vcmp1);
    printvf("vcmp ", vcmp);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

测试:

$ gcc -Wall -mavx so_avx_test.c && ./a.out
vcmp0 = 0 0 -1 -1
vcmp1 = -1 -1 0 0
vcmp  = -1 -1 0 0 0 0 -1 -1
Run Code Online (Sandbox Code Playgroud)

  • 如果没有 AVX2,很难做得更好。 (2认同)