2016-07-05 16 views
6

I endeksleri I0, I1, I2, I3 içeren bir bellek, tam sayıların, hizalanmış bir dizi var. Amacım I0 içeren bir __m256i kayıt, l0 + 1, I1, I1 + 1, I2, I2 + 1, I3, I3 + 1 zor kısmı I0'ın olarak 256 bit kayıt bunları elde ettiğini, l0 içine elde etmektir I1, I1, I2, I2, I3, I3, bundan sonra sadece 0, 1, 0, 1, 0, 1, 0, 1 içeren bir kayıt ekleyebilirim.AVX2, nasıl verimli bir 256 Bit Register Hatta Endeksler Dört Tamsayılar yükleyin ve Odd Endeksler kopyala için?

İçsel olanı buldum, _mm256_castsi128_si256, 4 tam sayıyı 256 bit registerın 128 bitine yüklememe izin ver, ama oradan kullanmak için en iyi intrinsikleri bulmaya çalışıyorum.

Herhangi bir yardım

mutluluk duyacağız. Tüm SSE sürümlerine, AVX ve AVX2'ye erişimim var ve bunu yalnızca içsel kullanarak yapmak istiyorum.

Düzenleme:

umarım bu işe düşünüyorum, ama onu test sürecinde ... değil ne kadar etkili değilim.

// _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 düşündüğümden şekilde davranmaz çünkü Yukarıdaki kod çalışmaz. Yukarıdaki kod I0, I0 + 1, I1, I1 + 1, I0, I0 + 1, I1, I1 + 1 ile sonuçlanacaktır. Bir yol bulamıyorum sürece

__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); 

cevap

6

Sizin 2 versiyonu, olması mümkün olduğunca verimli:

Edit3: yine ben en verimli olup olmadığından emin değilim gerçi Aşağıdaki kod çalışır Bu karışıklığı bir 128b yüküne katlayabilir. Bu, kaynaştırılmış etki alanı uop çıktısı için biraz yardımcı olabilir, ancak kullanılmayan etki alanı için değil.

1 yük (vmovdqa), (aka _mm256_permutevar8x32_epi32vpermd) 1 karıştır ve 1 add (vpaddd) oldukça hafif olduğunu. Eğer elemanları 1 ve 2 arasındaki bölünmüş bir hizalanmamış 256B yükünü yapmak sürece, üst 128b içine üst 2 elemanlarını almak için şerit geçme shuffle çeşit gerekir. Eğer AVX2 kullanabilirsiniz yana vpermd için shuffle maskesi yüklerken bir sorun değilse

, çözüm büyüktür. (basınç/önbellek eksiklerini kaydedin).


bir karışık-maskesi vektör sabiti önler, ama daha kötüsü aksi olan bir alternatif:

vpmovzxdq üst 128bit şeride üst iki öğe almak için başka bir seçenektir.

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

Veya, shuffle portu tüm döngü bir darboğaz olduğunu muhtemelen daha yüksek verim eğer. (Söz konusu vpermd sürümüne göre daha da kötüsü, gerçi.)

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 

vardiya ve OR içinde şeritli karıştır değiştirin.

İlgili konular