2016-07-05 4 views
6

私はインデックスI0、I1、I2、I3を含む整数の配列をメモリに持っています。私の目標は、I0、I0 + 1、I1、I1 + 1、I2、I2 + 1、I3、I3 + 1を含む__m256iレジスタにそれらを入れることです。難しい部分はI0、I0 、I1、I1、I2、I2、I3、I3、私は0、1、0、1、0、1、0、1AVX2、256ビットレジスタの偶数インデックスに効率的に4つの整数をロードし、奇数インデックスにコピーする方法?

を含むレジスタを追加することができ、私は、内因、_mm256_castsi128_si256を発見したそのあと私は4つの整数を256ビットレジスタの下位128ビットにロードすることができますが、そこから使用するために最高の組み込み関数を見つけるのには苦労しています。

ご協力いただければ幸いです。私はすべてのSSEバージョン、AVX、およびAVX2にアクセスでき、組み込み関数を使用してこれを実行したいと考えています。

編集:

私はこれがうまくいくと思うが、私はそれがどのように効率的な...それをテストするプロセスではありませんよ。

// _mm128_load_si128: Loads 4 integer values into a temporary 128bit register. 
// _mm256_broadcastsi128_si256: Copies 4 integer values in the 128 bit register to the low and high 128 bits of the 256 bit register. 
__m256i tmpStuff = _mm256_broadcastsi128_si256 ((_mm_load_si128((__m128i*) indicesArray))); 

// _mm256_unpacklo_epi32: Interleaves the integer values of source0 and source1. 
__m256i indices = _mm256_unpacklo_epi32(tmpStuff, tmpStuff); 

__m256i regToAdd = _mm256_set_epi32 (0, 1, 0, 1, 0, 1, 0, 1); 
indices = _mm256_add_epi32(indices, regToAdd); 

EDIT2:_mm256_unpacklo_epi32は私が思ったように動作しないので、上記のコードは動作しません。上記のコードは、I0、I0 + 1、I1、I1 + 1、I0、I0 + 1、I1、I1 + 1となります。

EDIT3:もう一度、私はそれが最も効率的だかはわからないけれども、次のコードは、動作します。私は道を欠けている場合を除き

__m256i tmpStuff = _mm256_castsi128_si256(_mm_loadu_si128((__m128i*) indicesArray)); 
__m256i mask = _mm256_set_epi32 (3, 3, 2, 2, 1, 1, 0, 0); 
__m256i indices= _mm256_permutevar8x32_epi32(tmpStuff, mask); 
__m256i regToAdd = _mm256_set_epi32 (1, 0, 1, 0, 1, 0, 1, 0); // Set in reverse order. 
indices= _mm256_add_epi32(indices, regToAdd); 

答えて

6

あなたの第二版は、それがために可能だとして効率的ですシャッフルを128bの負荷に折り畳むことができます。これは、融合ドメインのuopスループットではわずかに役立ちますが、非融合ドメインではそうではありません。

1負荷(vmovdqa)、1つのシャッフル(vpermd、別名_mm256_permutevar8x32_epi32)と1個のアドオン(vpadddは)かなり軽量です。要素1と要素2の間で分割されていない256bのアラインメントを行わない限り、上の2つの要素を上の128bに入れるには、何らかの種類の車線交差シャッフルが必要です。

AVX2を使用できるので、vpermdのシャッフルマスクをロードすることは問題ありません。 (レジスタ圧/キャッシュミス)。


シャッフルマスクベクトル定数を避けたが、悪化しそうある代替:

vpmovzxdqが上位128ビットのレーンに上部の2つの要素を取得するための別のオプションです。

vpmovzxdq ymm0, [src] 
vpshufd ymm1, ymm0, _MM_SHUFFLE(2,2, 0,0) ; duplicate elements 
vpaddd  ... 

または、シャッフルポートはループ全体のボトルネックである場合は、おそらくより高いスループット。

vpmovzxdq ymm0, [src] 
vpsrlq  ymm1, ymm0,32  ; left shift by 32 
vpaddd  ...     ; ymm1 +=1 in odd elements only 
vpor  ...     ; OR the incremented odd elements with the original even elements 

シフト(それでも。ただし、問題のvpermdバージョンよりも悪い)とOR車線内シャッフルを交換してください。

関連する問題