2014-05-23 24 views
4

我想將包含掩碼的兩個256位向量(__m256d)與比較操作(例如_mm256_cmp_pd)結合爲一個256位向量,方法是省略上半部分每64位加倍。使用AVX內在函數的壓縮模板

所以,如果在下文中,a_i, b_i, ...是32個比特的字,並且我有具有以下結構中的兩個2​​56位(4×雙)載體:

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的一切。

+1

我假設您打算使用_mm_cmp_pd來代替__mm_cmp_pd。但_mm_cmp_pd返回__m128d。 – ScottD

回答

4

看起來你可以利用這樣一個事實,即所有1的位模式都是單精度和雙精度的NaN,並且在所有情況下,所有0的位模式都是0.0。所以,收拾你的兩個雙面膜載體,以單精度浮點矢量,你可以這樣做:

__m256 v = _mm256_set_m128(_mm256_cvtpd_ps(v0), _mm256_cvtpd_ps(v1)); 

需要注意的是,如果你沒有_mm256_set_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; 
} 

測試:

$ 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 
+1

這確實可行 - 但性能特點不佳。 – dsd

+2

如果沒有AVX2,這將會很困難。 –

+0

我定義_mm256_set_m128()的唯一編譯器是Visual Studio 2013,並且由於參數類型它不接受此代碼。投影內在函數是否正確? – ScottD

2

在下面的代碼中,function1()執行該操作。主程序提供樣本數據並打印結果。樣本數據的FFFFFFFF部分是要省略的上半部分。樣本數據的其餘雙字包含獨特的模式。該程序輸出是:

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 

該代碼使用命令行cl /Ox /arch:AVX sample.c和用gcc 4.9.0使用命令行gcc -O3 -mavx -c sample.c與VS2013測試。

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