Decidí continuar con la optimización de esquinas rápidas y concentré en _mm_movemask_epi8
instrucción SSE. ¿Cómo puedo reescribirlo para ARM Neon con la entrada uint8x16_t
?SSE _mm_movemask_epi8 método equivalente para ARM NEON
Respuesta
después de algunas pruebas Parece siguiente código funciona correctamente:
int32_t _mm_movemask_epi8_neon(uint8x16_t input)
{
const int8_t __attribute__ ((aligned (16))) xr[8] = {-7,-6,-5,-4,-3,-2,-1,0};
uint8x8_t mask_and = vdup_n_u8(0x80);
int8x8_t mask_shift = vld1_s8(xr);
uint8x8_t lo = vget_low_u8(input);
uint8x8_t hi = vget_high_u8(input);
lo = vand_u8(lo, mask_and);
lo = vshl_u8(lo, mask_shift);
hi = vand_u8(hi, mask_and);
hi = vshl_u8(hi, mask_shift);
lo = vpadd_u8(lo,lo);
lo = vpadd_u8(lo,lo);
lo = vpadd_u8(lo,lo);
hi = vpadd_u8(hi,hi);
hi = vpadd_u8(hi,hi);
hi = vpadd_u8(hi,hi);
return ((hi[0] << 8) | (lo[0] & 0xFF));
}
Tenga en cuenta que no he probado nada de esto, pero algo como esto podría funcionar:
X := the vector that you want to create the mask from
A := 0x808080808080...
B := 0x00FFFEFDFCFB... (i.e. 0,-1,-2,-3,...)
X = vand_u8(X, A); // Keep d7 of each byte in X
X = vshl_u8(X, B); // X[7]>>=0; X[6]>>=1; X[5]>>=2; ...
// Each byte of X now contains its msb shifted 7-N bits to the right, where N
// is the byte index.
// Do 3 pairwise adds in order to pack all these into X[0]
X = vpadd_u8(X, X);
X = vpadd_u8(X, X);
X = vpadd_u8(X, X);
// X[0] should now contain the mask. Clear the remaining bytes if necessary
Esto tendría que ser repetido una vez para procesar un vector de 128 bits, ya que sólo funciona en vpadd
64 vectores de bits.
Sé que este post es bastante anticuado pero he encontrado que es útil para dar mi solución (validado). Asume todos los ceros todos/todos en cada carril del argumento de entrada.
const uint8_t __attribute__ ((aligned (16))) _Powers[16]=
{ 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128 };
// Set the powers of 2 (do it once for all, if applicable)
uint8x16_t Powers= vld1q_u8(_Powers);
// Compute the mask from the input
uint64x2_t Mask= vpaddlq_u32(vpaddlq_u16(vpaddlq_u8(vandq_u8(Input, Powers))));
// Get the resulting bytes
uint16_t Output;
vst1q_lane_u8((uint8_t*)&Output + 0, (uint8x16_t)Mask, 0);
vst1q_lane_u8((uint8_t*)&Output + 1, (uint8x16_t)Mask, 8);
(Mente http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47553, de todos modos.)
Al igual que Michael, el truco consiste en formar las potencias de los índices de las entradas que no son nulos, y para resumir ellos dos a dos en tres ocasiones. Esto se debe hacer aumentando el tamaño de los datos para doblar la zancada en cada adición. Se reducen de 2 x 8 entradas de 8 bits a 2 x 4 de 16 bits, luego 2 x 2 de 32 bits y 2 x 1 de 64 bits. El byte bajo de estos dos números da la solución. No creo que haya una manera fácil de agruparlos para formar un único valor corto usando NEON.
Toma 6 instrucciones NEON si la entrada está en la forma adecuada y las potencias se pueden precargar.
- 1. ¿ARM y NEON pueden trabajar en paralelo?
- 2. ARM NEON: comparando valores de 128 bit
- 3. ¿Existe una buena referencia para los intrínsecos de ARM Neon?
- 4. Convención de llamada ARM a C, registros NEON para guardar
- 5. NEON vs Intel SSE - equivalencia de ciertas operaciones
- 6. Neón equivalente a intrínseca SSE
- 7. ARM Cortex-A8: Cómo hacer uso de NEON y vfpv3
- 8. Rotación de 128 bits utilizando intrínsecos de ARM Neon
- 9. ARM NEON: ¿Cuál es la diferencia entre vld4_f32 y vld4q_f32?
- 10. ¿Cómo inicializar const float32x4x4_t (ARM NEON intrinsic, GCC)?
- 11. equivalente Método para @InjectMocks
- 12. ¿Hay algún equivalente ARM de Intel IPP?
- 13. Suma todos los elementos en un vector de cuatro palabras en el ensamblaje ARM con NEON
- 14. ¿Cómo reordeno los datos vectoriales utilizando los intrínsecos de ARM Neon?
- 15. ¿Libm optimizado para ARM?
- 16. Equivalente a 'int 3' en procesadores ARM/iOS
- 17. Modelo de procesador de detección de iPhone/Soporte de NEON
- 18. Android ARM arquitecturas ARM
- 19. retorno registro SSE con SSE discapacitados
- 20. Equivalente equivalente al método Unity RegisterInstance
- 21. Uso de objdump para arquitectura ARM: Desarmado a ARM
- 22. Android ARMv6/v7 y VFP/NEON
- 23. SSE y Servlet 3.0
- 24. Cross Compile perl para ARM
- 25. binario universal para diferentes versiones de SSE
- 26. SSE SSE2 y SSE3 para GNU C++
- 27. arm-linux-gcc vs arm-elf-gcc
- 28. ¿Hay un método equivalente LINQ?
- 29. funcionalidad glibc y SSE
- 30. ¿Cuál es mejor, gcc o armcc para las optimizaciones de NEON?
Hola @Michael thanx para el ejemplo. ¿Puedes explicar cómo puedo llenar el vector B con los bytes requeridos? para A puedo usar vdup_n_u8 (0x80) pero ¿cómo debo hacerlo para A? también escribes vshl_u8 pero en el comentario hay un cambio ¿no? – inspirit
Para inicializar el vector B: 'vld1' desde una matriz const (?). Acerca del desplazamiento correcto: la documentación de ARM establece _ "Si el valor de desplazamiento es positivo, la operación es un desplazamiento a la izquierda. De lo contrario, es un cambio a la derecha". _. No estoy del todo seguro si ese es el caso si los datos que cambias son 'u8', o si necesitas usar' s8'. – Michael
sí, entiendo que necesito cargar B de una matriz, me preguntaba sobre los valores suministrados en ese vector. ¿puedes ser más específico al respecto? debería ser solo [0, -1, -2, -3, -4, -5, -6, -7]? y sí, lo necesito para el vector de datos u8 en el momento – inspirit