C 使用AVX内部函数压缩掩码

C 使用AVX内部函数压缩掩码,c,x86,simd,intrinsics,avx,C,X86,Simd,Intrinsics,Avx,我想将两个256位向量(\uuuuum256d)组合到一个256位向量,通过省略每个64位双精度的上半部分,将它们作为比较操作(例如\umm256\ucmp\upd)的结果而包含掩码 因此,如果在下面的中,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、

我想将两个256位向量(
\uuuuum256d
)组合到一个256位向量,通过省略每个64位双精度的上半部分,将它们作为比较操作(例如
\umm256\ucmp\upd
)的结果而包含掩码

因此,如果在下面的中,
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


如何使用Intel Intrinsic有效地执行此操作?可用的指令集都是AVX。

看起来您可以利用以下事实:所有1的位模式在单精度和双精度下都是
NaN
,同样,所有0的位模式在这两种情况下都是0.0。因此,要将两个双掩码向量打包为一个浮点向量,可以执行以下操作:

 __m256 v = _mm256_set_m128(_mm256_cvtpd_ps(v0), _mm256_cvtpd_ps(v1));
请注意,如果您没有
\u mm256\u set\u m128
,则可以将其定义为:

#define _mm256_set_m128(va, vb) \
        _mm256_insertf128_ps(_mm256_castps128_ps256(vb), va, 1)
下面是一个演示:

#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;
}

在下面的代码中,
function1()
执行该操作。主程序提供样本数据并打印结果。样本数据的FFFFFF部分是要省略的上半部分。样本数据的其余DWORD包含唯一的模式。程序输出为:

v0=A0000000 FFFFFFFF B0000000 FFFFFFFF C0000000 FFFFFFFF D0000000 FFFFFFFF
v1=A0000001 FFFFFFFF B0000001 FFFFFFFF C0000001 FFFFFFFF D0000001 FFFFFFFF
vr=A0000000 B0000000 C0000000 D0000000 A0000001 B0000001 C0000001 D0000001
使用VS2013使用命令行
cl/Ox/arch:AVX-sample.c
对代码进行测试,使用gcc 4.9.0使用命令行
gcc-O3-mavx-c-sample.c
对代码进行测试

AVX有限的交叉车道能力使得解决方案相对复杂

#include <intrin.h>
#include <stdint.h>
#include <stdio.h>

//---------------------------------------------------------------------------

static void dump (void *data)
    {
    uint32_t *d32 = data;
    int index;

    for (index = 0; index < 8; index++)
        printf ("%08X ", d32 [index]);
    printf ("\n");
    }

//---------------------------------------------------------------------------

 static __m256d function1 (__m256d v0, __m256d v1)
    {
    __m256d tmp0 = _mm256_permute2f128_pd (v0, v1, 0x20);
    __m256d tmp1 = _mm256_permute2f128_pd (v0, v1, 0x31);
    return _mm256_castps_pd (_mm256_shuffle_ps (_mm256_castpd_ps (tmp0), _mm256_castpd_ps (tmp1), 0x88));
    }

//---------------------------------------------------------------------------

int main (void)
    {
    __m256d v0, v1, vr;

    v0 = _mm256_castsi256_pd (_mm256_set_epi32 (0xffffffff, 0xd0000000, 0xffffffff, 0xc0000000, 0xffffffff, 0xb0000000, 0xffffffff, 0xa0000000));
    v1 = _mm256_castsi256_pd (_mm256_set_epi32 (0xffffffff, 0xd0000001, 0xffffffff, 0xc0000001, 0xffffffff, 0xb0000001, 0xffffffff, 0xa0000001));
    vr = function1 (v0, v1);
    printf ("v0="); dump (&v0);
    printf ("v1="); dump (&v1);
    printf ("vr="); dump (&vr);
    return 0;
    }
#包括
#包括
#包括
//---------------------------------------------------------------------------
静态无效转储(无效*数据)
{
uint32_t*d32=数据;
整数指数;
用于(索引=0;索引<8;索引++)
printf(“%08X”,d32[索引]);
printf(“\n”);
}
//---------------------------------------------------------------------------
静态m256d功能1(m256d v0和m256d v1)
{
__m256d tmp0=_mm256_permute2f128_pd(v0,v1,0x20);
__m256d tmp1=_mm256_permute2f128_pd(v0,v1,0x31);
返回mm256_castps_pd(mm256_shuffle_ps(mm256_castpd_ps(tmp0),mm256_castpd_ps(tmp1),0x88));
}
//---------------------------------------------------------------------------
内部主(空)
{
__m256d v0,v1,vr;
v0=_mm256_castsi256_pd(_mm256_set_epi32(0xffffffff,0xd0000000,0xFFFFFF,0xc0000000,0xFFFFFF,0xb0000000,0xffffffff,0xa0000000));
v1=mm256_castsi256_pd(mm256_set_epi32(0xffffffff,0xd0000001,0xFFFFFF,0xc0000001,0xFFFFFF,0xb0000001,0xffffffff,0xa0000001));
vr=功能1(v0,v1);
printf(“v0=”);转储(&v0);
printf(“v1=”);转储(&v1);
printf(“vr=”);转储(&vr);
返回0;
}

没有AVX2很难做得更好。我拥有的唯一定义_mm256_set_m128()的编译器是Visual Studio 2013,由于参数类型的原因,它不接受此代码。cast内部函数正确吗?@ScottD:没问题-我在上面的答案中添加了一个用于
\u mm256\u set\u m128
的宏。感谢使用了与VS2013相同的\u mm256\u set\u m128宏。但是问题仍然存在:由于参数类型不正确,代码无法生成。很抱歉,有一个小错误(
\uuuuum256d
应该是
\uuuuum256
),我现在已经修复了。我还添加了演示代码,它似乎可以工作(至少在我的编译器中是这样)。我假设您打算用mm_cmp_pd代替mm_cmp_pd。但是,它返回m128d。
#include <intrin.h>
#include <stdint.h>
#include <stdio.h>

//---------------------------------------------------------------------------

static void dump (void *data)
    {
    uint32_t *d32 = data;
    int index;

    for (index = 0; index < 8; index++)
        printf ("%08X ", d32 [index]);
    printf ("\n");
    }

//---------------------------------------------------------------------------

 static __m256d function1 (__m256d v0, __m256d v1)
    {
    __m256d tmp0 = _mm256_permute2f128_pd (v0, v1, 0x20);
    __m256d tmp1 = _mm256_permute2f128_pd (v0, v1, 0x31);
    return _mm256_castps_pd (_mm256_shuffle_ps (_mm256_castpd_ps (tmp0), _mm256_castpd_ps (tmp1), 0x88));
    }

//---------------------------------------------------------------------------

int main (void)
    {
    __m256d v0, v1, vr;

    v0 = _mm256_castsi256_pd (_mm256_set_epi32 (0xffffffff, 0xd0000000, 0xffffffff, 0xc0000000, 0xffffffff, 0xb0000000, 0xffffffff, 0xa0000000));
    v1 = _mm256_castsi256_pd (_mm256_set_epi32 (0xffffffff, 0xd0000001, 0xffffffff, 0xc0000001, 0xffffffff, 0xb0000001, 0xffffffff, 0xa0000001));
    vr = function1 (v0, v1);
    printf ("v0="); dump (&v0);
    printf ("v1="); dump (&v1);
    printf ("vr="); dump (&vr);
    return 0;
    }