2012-08-08 17 views

risposta

0

dopo alcuni test Sembra seguente codice funziona correttamente:

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

Si noti che non ho ancora testato niente di tutto questo, ma qualcosa di simile potrebbe funzionare:

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 

Ciò avrebbe bisogno di essere ripetuta una volta per elaborare un 128-bit vettore, dal momento che vpadd funziona solo su 64 -bit vettori.

+0

hi @Michael grazie per l'esempio. puoi spiegare come posso riempire il vettore B con i byte richiesti? per A posso usare vdup_n_u8 (0x80) ma come dovrei farlo per A? anche tu scrivi vshl_u8 ma nel commento c'è il cambiamento giusto? – inspirit

+0

Per inizializzare il vettore B: 'vld1' da un array const (?). Informazioni sul cambio a destra: la documentazione di ARM afferma: "Se il valore di spostamento è positivo, l'operazione è uno spostamento a sinistra, altrimenti è uno spostamento verso destra." _. Non sono del tutto sicuro se questo è il caso se i dati che si spostano sono 'u8', o se è necessario usare' s8'. – Michael

+0

sì capisco che ho bisogno di caricare B da un array mi stavo solo chiedendo i valori forniti in quel vettore. puoi essere più specifico a riguardo? dovrebbe essere solo [0, -1, -2, -3, -4, -5, -6, -7]? e sì ho bisogno per il vettore di dati u8 al momento – inspirit

5

So che questo post è piuttosto vecchio, ma ho trovato utile per dare la mia soluzione (convalidato). Assume tutti/tutti gli zeri in ogni corsia dell'argomento Input.

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, comunque.)

Analogamente a Michael, il trucco è quello di formare le competenze degli indici delle voci non nulli, e riassumere loro a coppie tre volte. Questo deve essere fatto con l'aumento delle dimensioni dei dati per raddoppiare il passo su ogni aggiunta. Riduci da 2 x 8 voci a 8 bit a 2 x 4 a 16 bit, quindi 2 x 2 a 32 bit e 2 x 1 a 64 bit. Il byte basso di questi due numeri dà la soluzione. Non penso che ci sia un modo semplice per riunirli insieme per formare un singolo valore corto usando NEON.

Richiede 6 istruzioni NEON se l'ingresso è nella forma appropriata e le potenze possono essere precaricate.

Problemi correlati