AVX2: Contar ceros finales en elementos de 8 bits en el registro AVX
Me gustaría tener una implementación para una función como _mm256_lzcnt_epi8(__m256i a)
, donde se cuenta y extrae el número de ceros finales para cada elemento de 8 bits.
En una pregunta anterior sobre cómo implementar el conteo de ceros principales, hay una solución que utiliza una tabla de búsqueda. Me pregunto si se puede utilizar el mismo método para esto.
Solo AVX y AVX2, por favor, y el comportamiento para una entrada de 0
puede ser indefinido.
Gracias por tu ayuda.
https://stackoverflow.com/questions/68985039/avx2-bitscanreverse-or-countleadingzeros-on-8-bit-elements-in-avx-register
¡Gracias por tu ayuda!
davy.ai
Para implementar una función como
_mm256_lzcnt_epi8(__m256i a)
utilizando instrucciones AVX y AVX2, se puede utilizar el mismo método que para contar ceros principales. Sin embargo, en lugar de utilizar una tabla de búsqueda, se puede utilizar la instrucciónpext
para extraer los ceros finales de cada byte en el vector de entrada. La instrucciónpext
extrae bits del operando fuente basado en los bits establecidos en el operando de máscara, y almacena el resultado en el operando de destino. Para crear el operando de máscara para_mm256_lzcnt_epi8
, necesitamos generar un patrón de bits que tenga un 1 en la posición del bit cero menos significativo, y ceros en otras posiciones. Una forma de generar esta máscara es utilizar la instrucciónblsi
, que borra todos los bits excepto el bit establecido menos significativo. Podemos tomar el complemento del vector de entrada, aplicarblsi
para obtener la posición del bit cero menos significativo, y luego generar la máscara conpext
. Finalmente, podemos contar el número de bits establecidos en la máscara de resultados utilizando la instrucciónpopcnt
, que nos da el número de ceros finales para cada byte en el vector de entrada.Aquí hay una implementación utilizando instrucciones AVX2:
c++
__m256i _mm256_lzcnt_epi8(__m256i a)
{
__m256i mask = _mm256_sub_epi8(_mm256_set1_epi8(-1), a); // complemento del vector de entrada
__m256i bitpos = _mm256_xor_si256(_mm256_add_epi8(mask, _mm256_set1_epi8(1)), mask); // posición del bit cero menos significativo
__m256i result = _mm256_xor_si256(a, _mm256_set1_epi8(-1)); // complemento del vector de entrada nuevamente
result = _mm256_pext_epi8(result, bitpos); // extraer ceros finales
result = _mm256_popcnt_epi8(result); // contar el número de ceros finales
return result;
}
Tenga en cuenta que el comportamiento para
0
como entrada no está definido, según se especifica en la pregunta.