short
(veya int
) türünde bir hedef diziye eklenmesi gereken çok uzun bayt dizilerim var. Böyle bir SSE komutu var mı? Ya da onların seti?SSE Talimatlar: Byte + Short
cevap
8 bit değerlerinin her bir vektörünü 16 bitlik iki vektöre boşaltmanız ve sonra bunları eklemeniz gerekir. v
16 x 8 bit değerlerinin ve vl
bir vektördür
__m128i v = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
__m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); // vl = { 7, 6, 5, 4, 3, 2, 1, 0 }
__m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); // vh = { 15, 14, 13, 12, 11, 10, 9, 8 }
, vh
8 x 16 bit değerlerinin iki ambalajsız vektörleridir.
8 bit değerlerinin işaretsiz olduğunu varsaydığımı varsayalım, bu nedenle 16 bit'e paketten çıkarma yaparken, yüksek bayt 0'a (yani, işaret uzantısı yok) ayarlanır.
Bu vektörlerin çoğunu toplamak ve 32 bit sonuç elde etmek istiyorsanız, yararlı bir numara _mm_madd_epi16
'u 1 çarpanıyla kullanmaktır. Eğer yerine bayt vektörleri kayıt uzatmak gerekiyorsa
__m128i vsuml = _mm_set1_epi32(0);
__m128i vsumh = _mm_set1_epi32(0);
__m128i vsum;
int sum;
for (int i = 0; i < N; i += 16)
{
__m128i v = _mm_load_si128(&x[i]);
__m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0));
__m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0));
vsuml = _mm_add_epi32(vsuml, _mm_madd_epi16(vl, _mm_set1_epi16(1)));
vsumh = _mm_add_epi32(vsumh, _mm_madd_epi16(vh, _mm_set1_epi16(1)));
}
// do horizontal sum of 4 partial sums and store in scalar int
vsum = _mm_add_epi32(vsuml, vsumh);
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8));
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4));
sum = _mm_cvtsi128_si32(vsum);
pmovsxbw
(_mm_cvtepi8_epi16
) kullanın sıfır-uzatın. Hi/lo komutlarını açmadan farklı olarak, bir src kaydının sadece yarım/çeyrek/sekizinci yarısından itibaren pmovsx yapabilirsiniz.
Eğer intrinsics bu gerçekten beceriksiz olsa bile pmovsx'i doğrudan bellekten yapabilirsiniz. Shuffle verimi çoğu CPU'larda yük çıkışından daha sınırlı olduğu için, muhtemelen bir load + üç shuffle yapmaktan iki load + pmovsx yapmak tercih edilir.
Cehaletimi affet ama bunun doğru olduğuna emin misin? Bu vsum = _mm_madd_epi16 (vh, _mm_set1_epi16 (1)); vsum'un önceki değerini siler. – Alexandros
@Alexandros: Haklısınız, ve orada da en az bir hatayı görüyorum - sanırım bu cevabı yazdığım zaman acelem vardı - yakında kodu düzeltirim ama ben de mevcut. –
Teşekkürler Paul, acele etme. Geçmişte bana çok yardımcı oldunuz, bu sayede istediğiniz zaman düzeltin. İyi yolculuklar!! – Alexandros