Như @MaratDukhan đã nhận thấy, _mm256_shuffle_epi8
(ví dụ: VPSHUFB
đối với ymm-s) không thực hiện trộn hoàn toàn 32 byte. Đối với tôi, nó là khá một điều đáng tiếc ...
Đó là lý do để bắt chước nó mà không AVX2 bạn chỉ có thể chia nhỏ từng đăng ký thành hai nửa, mỗi nửa hoán, sau đó kết hợp với nhau:
//AVX only
__m256i _emu_mm256_shuffle_epi8(__m256i reg, __m256i shuf) {
__m128i reg0 = _mm256_castsi256_si128(reg);
__m128i reg1 = _mm256_extractf128_si256(reg, 1);
__m128i shuf0 = _mm256_castsi256_si128(shuf);
__m128i shuf1 = _mm256_extractf128_si256(shuf, 1);
__m128i res0 = _mm_shuffle_epi8(reg0, shuf0);
__m128i res1 = _mm_shuffle_epi8(reg1, shuf1);
__m256i res = _mm256_setr_m128i(res0, res1);
return res;
}
Nếu bạn thực sự muốn trộn hoàn toàn thanh ghi 32 byte, bạn có thể làm theo cách tiếp cận từ this paper. Trộn từng nửa với mỗi nửa, sau đó trộn kết quả lại với nhau. Nếu không có AVX2 nó sẽ là một cái gì đó như thế:
//AVX only
__m256i _emu_mm256_shuffle32_epi8(__m256i reg, __m256i shuf) {
__m128i reg0 = _mm256_castsi256_si128(reg);
__m128i reg1 = _mm256_extractf128_si256(reg, 1);
__m128i shuf0 = _mm256_castsi256_si128(shuf);
__m128i shuf1 = _mm256_extractf128_si256(shuf, 1);
__m128i res00 = _mm_shuffle_epi8(reg0, shuf0);
__m128i res01 = _mm_shuffle_epi8(reg0, shuf1);
__m128i res10 = _mm_shuffle_epi8(reg1, shuf0);
__m128i res11 = _mm_shuffle_epi8(reg1, shuf1);
__m128i res0 = _mm_blendv_epi8(res10, res00, _mm_cmplt_epi8(shuf0, _mm_set1_epi8(16)));
__m128i res1 = _mm_blendv_epi8(res11, res01, _mm_cmplt_epi8(shuf1, _mm_set1_epi8(16)));
__m256i res = _mm256_setr_m128i(res0, res1);
return res;
}
Nếu bạn biết chắc chắn rằng chỉ có nửa dưới của reg
được sử dụng, sau đó bạn có thể loại bỏ các nếp cho reg1
, res10
, res11
, và loại bỏ sự so sánh và trộn. Thật vậy, nó có thể hiệu quả hơn để gắn bó với SSE và sử dụng thanh ghi 128-bit nếu bạn không có AVX2.
Tổng 32-byte xáo trộn có thể được tối ưu hóa đáng kể với AVX2:
//Uses AVX2
__m256i _ext_mm256_shuffle32_epi8(__m256i reg, __m256i shuf) {
__m256i regAll0 = _mm256_permute2x128_si256(reg, reg, 0x00);
__m256i regAll1 = _mm256_permute2x128_si256(reg, reg, 0x11);
__m256i resR0 = _mm256_shuffle_epi8(regAll0, shuf);
__m256i resR1 = _mm256_shuffle_epi8(regAll1, shuf);
__m256i res = _mm256_blendv_epi8(resR1, resR0, _mm256_cmpgt_epi8(_mm256_set1_epi8(16), shuf));
return res;
}
Hãy coi chừng: Mã chưa được thử nghiệm!
Có thể bạn đã không nhận thấy, nhưng AVX2 'VPSHUFB ymm, ymm, ymm/m256' không thực sự là một phát ngẫu nhiên 256 bit, thay vào đó là xáo trộn 128 bit. –
Thú vị. Cảm ơn! – alecco