2014-10-01 112 views
3

如何從__m256向量中的索引中提取單個浮點數並將其廣播到結果向量?向另一個向量廣播特定向量元素

僞代碼:

__m256 input = { 2, 3, 4, 5, 6, 7, 8, 9 }; 
__m256 output = __mm256_selectidx(input, 2); 

// output [0 .. 7] now consists of input[2], that is, {4, 4, 4, 4, 4, 4, 4, 4} 

相關功能似乎是提取/插入或置換,但文檔是稀缺的/我真的不明白。廣播系列也看起來不錯,但只適用於內存操作數?

+1

是元素的索引(2在你上面的例子)編譯時間常量,或它是否需要成爲運行時間值(即變量)? – 2014-10-01 12:35:58

+0

這是一個立即值/常數 – Shaggi 2014-10-01 13:36:53

回答

3

對於AVX-只(即沒有AVX2),你可以這樣做:

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

#define _mm256_selectidx(v, i) ({\ 
    __m256 vt = _mm256_permute2f128_ps(v, v, (i >> 2) | ((i >> 2) << 4)); \ 
    vt = _mm256_permute_ps(vt, _MM_SHUFFLE(i & 3, i & 3, i & 3, i & 3)); \ 
}) 

int main(void) 
{ 
    __m256 v0 = _mm256_setr_ps(2, 3, 4, 5, 6, 7, 8, 9); 
    __m256 v1 = _mm256_selectidx(v0, 2); 
    float f0[8], f1[8]; 

    _mm256_storeu_ps(f0, v0); 
    _mm256_storeu_ps(f1, v1); 

    printf("v0: %g %g %g %g %g %g %g %g\n", f0[0], f0[1], f0[2], f0[3], f0[4], f0[5], f0[6], f0[7]); 
    printf("v1: %g %g %g %g %g %g %g %g\n", f1[0], f1[1], f1[2], f1[3], f1[4], f1[5], f1[6], f1[7]); 

    return 0; 
} 

測試:

$ gcc -Wall -mavx test_avx_select.c && ./a.out 
v0: 2 3 4 5 6 7 8 9 
v1: 4 4 4 4 4 4 4 4 

請注意,此代碼使用gcc擴展來表示宏,它可以像函數一樣行事 - 如果您使用的編譯器不支持此擴展,那麼您可能需要使用內聯函數,並希望編譯器可以處理AVX內在函數所需的編譯時常量。

+0

聰明的解決方案(+1)。我想知道AVX2版本如何與僅AVX版本相比。 – 2014-10-01 14:44:04

+1

感謝 - AVX版本可能更高效,但它僅限於元素索引的編譯時常量,而AVX2版本將與運行時元素索引配合使用。 – 2014-10-01 14:53:37

+0

正是我想要的,謝謝。此解決方案(有些修改)是否也可用於SSE2? – Shaggi 2014-10-02 09:01:02

2

如果你有AVX2然後可以使用_mm256_permutevar8x32_ps

#define _mm256_selectidx(v, i) _mm256_permutevar8x32_ps(v, _mm256_set1_epi32(i)) 

顯然,這將產生幾個指令,這取決於你的編譯器如何處理_mm256_set1_epi32以及是否元素索引是一個編譯時間常數或沒有。

演示:

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

#define _mm256_selectidx(v, i) _mm256_permutevar8x32_ps(v, _mm256_set1_epi32(i)) 

int main(void) 
{ 
    __m256 v0 = _mm256_setr_ps(2, 3, 4, 5, 6, 7, 8, 9); 
    __m256 v1 = _mm256_selectidx(v0, 2); 
    float f0[8], f1[8]; 

    _mm256_storeu_ps(f0, v0); 
    _mm256_storeu_ps(f1, v1); 

    printf("v0: %g %g %g %g %g %g %g %g\n", f0[0], f0[1], f0[2], f0[3], f0[4], f0[5], f0[6], f0[7]); 
    printf("v1: %g %g %g %g %g %g %g %g\n", f1[0], f1[1], f1[2], f1[3], f1[4], f1[5], f1[6], f1[7]); 

    return 0; 
} 

測試:

$ gcc -Wall -mavx2 test_avx2_select.c && ./a.out 
v0: 2 3 4 5 6 7 8 9 
v1: 4 4 4 4 4 4 4 4 
+0

不幸的是,我只用AVX卡...只有SSE2的解決方案也是受歡迎的 – Shaggi 2014-10-01 13:37:35

+0

好的 - 我現在已經添加了一個單獨的AVX回答,它與編譯時常量爲元素索引。 – 2014-10-01 14:20:16

1

對於SSE很簡單得多 - 你可以用_mm_shuffle_ps

#include <stdio.h> 
#include <xmmintrin.h> 

#define _mm_selectidx(v, i) _mm_shuffle_ps(v, v, _MM_SHUFFLE(i, i, i, i)) 

int main(void) 
{ 
    __m128 v0 = _mm_setr_ps(2, 3, 4, 5); 
    __m128 v1 = _mm_selectidx(v0, 2); 
    float f0[4], f1[4]; 

    _mm_storeu_ps(f0, v0); 
    _mm_storeu_ps(f1, v1); 

    printf("v0: %g %g %g %g\n", f0[0], f0[1], f0[2], f0[3]); 
    printf("v1: %g %g %g %g\n", f1[0], f1[1], f1[2], f1[3]); 

    return 0; 
} 

測試:

$ gcc -Wall -msse test_sse_select.c && ./a.out 
v0: 2 3 4 5 
v1: 4 4 4 4 
+1

+1你是我的英雄。 – Shaggi 2014-10-02 09:29:08

相關問題