2017-09-20 4 views
2

Existe-t-il un moyen (rapide) d'effectuer des bits inverses de valeurs int 32 bits dans le registre avx2? E.g.avx2 bits de registre inverse

_mm256_set1_epi32(2732370386); 
<do something here> 
//binary: 10100010110111001010100111010010 => 1001011100101010011101101000101 
//register contains 1268071237 which is decimal representation of 1001011100101010011101101000101 
+0

Vous voulez inverser les bits d'un seul int32 dans un registre d'entiers AVX2, ou vous voulez inverser les bits de chacun de ces 8 entiers? –

+1

@JohnZwinck, ça n'a pas vraiment d'importance: une fois que j'ai l'idée de comment faire ça, je peux mélanger les valeurs de 32 bits dans le registre comme je le souhaite. –

+0

L'ancienne façon (inverser les octets, inverser les groupes de 4 avec 'pshufb', résultats OU) généraliser à AVX2, je ne peux pas trouver immédiatement la dupe si – harold

Répondre

5

Puisque je ne trouve pas de dupe approprié, je vais juste le poster.

L'idée principale ici est de faire usage de pshufb à double usage d'une recherche de table parallèle de 16 entrées pour inverser les bits de chaque quartet. Inverser les octets est évident. Inverser l'ordre des deux grignoter dans chaque octet pourrait être fait en le construisant dans les tables de recherche (sauvegarde un décalage) ou en déplaçant explicitement la partie basse grignotant (sauvegarde une table).

Quelque chose comme ça au total, non testé:

__m256i rbit32(__m256i x) { 
    __m256i shufbytes = _mm256_setr_epi8(3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12); 
    __m256i luthigh = _mm256_setr_epi8(0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15, 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15); 
    __m256i lutlow = _mm256_slli_epi16(luthigh, 4); 
    __m256i lowmask = _mm256_set1_epi8(15); 
    __m256i rbytes = _mm256_shuffle_epi8(x, shufbytes); 
    __m256i high = _mm256_shuffle_epi8(lutlow, _mm256_and_si256(rbytes, lowmask)); 
    __m256i low = _mm256_shuffle_epi8(luthigh, _mm256_and_si256(_mm256_srli_epi16(rbytes, 4), lowmask)); 
    return _mm256_or_si256(low, high); 
} 

Dans un contexte typique dans une boucle, ces charges doivent être évacuées. Curieusement Clang uses 4 shuffles, il duplique le premier shuffle.

+1

il y a une solution pour AVX2 [ici] (https://stackoverflow.com/a/24058332/995714) –

+0

@ LưuVĩnhPhúc ok oui, je cherchais seulement les balises SSE – harold

+0

@ LưuVĩnhPhúc La solution dans votre lien retourne des octets au lieu de 32 Inbit-bits. – wim