2013-08-13 14 views
7

Sto scrivendo un programma di test per abituarmi alle estensioni del linguaggio di Clang per i vettori di stile OpenCL. Posso far funzionare il codice, ma ho dei problemi con un aspetto negativo. Non riesco a capire come ottenere clang a caricare semplicemente un vettore da uno schieramento scalare.Un modo migliore per caricare i vettori dalla memoria. (clang)

Al momento devo fare qualcosa di simile:

byte16 va = (byte16){ argv[1][start], argv[1][start + 1], argv[1][start + 2], 
         argv[1][start + 3], argv[1][start + 4], argv[1][start + 5], 
         argv[1][start + 6], argv[1][start + 7], argv[1][start + 8], 
         argv[1][start + 9], argv[1][start + 10], argv[1][start + 11], 
         argv[1][start + 12], argv[1][start + 13], argv[1][start + 14], 
         argv[1][start + 15]}; 

Vorrei idealmente come qualcosa di simile:

byte16 va = *(byte16 *)(&(argv[1][start])); 

cui posso facilmente fare utilizzando gli intrinseci appropriate per ARM o x86. Ma quel codice causa il crash del programma sebbene compili.

+0

Non funziona 'memcpy (& va, & argv [1] [inizio], sizeof (va))'? – jxh

risposta

5

Uno dei motivi per cui l'arresto anomalo potrebbe verificarsi su x86 è dovuto a problemi di allineamento. Non ho clang sul mio sistema per riprodurre il problema, ma posso dimostrarlo sull'esempio di GCC.

Se si fa qualcosa di simile:

/* Define a vector type of 16 characters. */ 
typedef char __attribute__ ((vector_size (16))) byte16; 

/* Global pointer. */ 
char * foo; 

byte16 test() 
{ 
    return *(byte16 *)&foo[1]; 
} 

Ora, se si compila su un x86 vettore-capace con:

$ gcc -O3 -march=native -mtune=native a.c 

otterrete la seguente assemblea per il test:

test: 
    movq foo(%rip), %rax 
    vmovdqa 1(%rax), %xmm0 
    ret 

Si prega di notare che il movimento è allineato, il che è ovviamente sbagliato. Ora, se si inline questa funzione nel principale, e si avrà qualcosa di simile:

int main() 
{ 
    foo = __builtin_malloc (22); 
    byte16 x = *(byte16 *)&foo[1]; 
    return x[0]; 
} 

vi andrà bene, e si otterrà l'istruzione non allineati. Questo è un tipo di bug, che non ha una correzione molto buona nel compilatore, poiché richiederebbe ottimizzazioni interprocedurali con aggiunta di nuove strutture dati, ecc.

L'origine del problema è che il compilatore presume che i tipi di vettore sono allineati, quindi quando si denota un array di tipi di vettore allineati è possibile utilizzare una mossa allineata. Come una soluzione per il problema in GCC si può definire un tipo di vettore non allineato come:

typedef char __attribute__ ((vector_size (16),aligned (1))) unaligned_byte16; 

E usarlo per dereferenziare memoria non allineati.

Non sono sicuro che si stia verificando esattamente questo problema all'interno della configurazione, ma questo è qualcosa che consiglierei di verificare controllando l'output dell'assieme dal compilatore.

+0

Beh, in tal caso non vedo alcuna ragione per cui dovrebbe fallire ... Puoi provare a fare qualcosa del genere: 'struct b16 { char x [16]; }; struct b16 x = * (struct b16 *) & argv [1] [0]; ' –

+1

Ho riscontrato problemi analoghi usando Clang e ispezionando l'assembly (assembly ARM, cercare" ': 64'" o "':: 128' "nel campo dell'indirizzo) ho potuto vedere che stava usando le versioni allineate delle istruzioni di caricamento e di archiviazione. Questa soluzione funziona per me. – sh1

Problemi correlati