2012-08-08 30 views

Respuesta

0

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)); 
} 
0

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.

+0

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

+0

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

+0

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

5

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.

Cuestiones relacionadas