Donnés sont 2 masques de bits, qui devraient être accessibles en alternance (0,1,0,1...). J'essaie d'obtenir une solution efficace en termes de temps d'exécution, mais je ne trouve pas de meilleure façon que l'exemple suivant.
uint32_t masque[2] { ... };
uint8_t indice_masque = 0;
uint32_t f = _tzcnt_u32(masque[indice_masque]);
while (f < 32) {
// élément ajouté au vecteur de résultat supprimé, car non pertinent pour la question elle-même
masque[0] >>= f + 1;
masque[1] >>= f + 1;
indice_masque ^= 1;
f = _tzcnt_u32(masque[indice_masque]);
}
La sortie ASM (MSVC, x64) semble assez encombrée.
inc r9
add r9,rcx
mov eax,esi
mov qword ptr [rdi+rax*8],r9
inc esi
lea rax,[rcx+1]
shrx r11d,r11d,eax
mov dword ptr [rbp],r11d
shrx r8d,r8d,eax
mov dword ptr [rbp+4],r8d
xor r10b,1
movsx rax,r10b
tzcnt ecx,dword ptr [rbp+rax*4]
mov ecx,ecx
cmp rcx,20h
jb main+240h (07FF632862FD0h)
cmp r9,20h
jb main+230h (07FF632862FC0h)
Est-ce que quelqu'un a un conseil?
(Ceci est une suite à Résoudre la dépendance des données de boucle avec SIMD - trouver les transitions entre -1 et +1 dans un tableau int8_t de valeurs sgn en utilisant SIMD pour créer les masques de bits)
Mise à jour
Je me demande si une solution potentielle pourrait utiliser SIMD en chargeant des morceaux des deux flux de bits dans un registre (AVX2 dans mon cas) comme ceci:
|m0[0]|m1[0]|m0[1]|m1[1]|m0[2]|m1[2]|m0[n+1]|m1[n+1]|
ou
1 registre avec des morceaux par flux
|m0[0]|m0[1]|m0[2]|m0[n+1]|
|m1[0]|m1[1]|m1[2]|m1[n+1]|
ou diviser le flux en morceaux de même taille et traiter autant de voies que possible dans le registre à la fois. Supposons que nous ayons 256*10 éléments qui pourraient se retrouver dans 10 itérations comme ceci: |m0[0]|m0[256]|m0[512]|...| |m1[0]|m1[256]|m1[512]|...| et traiter la jointure séparément
Je ne suis pas sûr si cela pourrait être une manière d'obtenir plus d'itérations par cycle et de limiter le besoin de balayages de bits horizontaux, d'opérations de décalage/nettoyage et d'éviter les branches.