2013-08-13 7 views
7

Piszę program testowy, aby przyzwyczaić się do rozszerzeń języka Clang dla wektorów stylu OpenCL. Mogę uruchomić kod, ale mam problemy z uzyskaniem jednego aspektu. Nie mogę się domyślić, jak uzyskać klang, żeby ładnie ładować wektor z tablicy skalarnej.Lepszy sposób ładowania wektorów z pamięci. (clang)

W tej chwili muszę zrobić coś takiego:

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]}; 

bym idealnie jak coś takiego:

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

Które można łatwo zrobić za pomocą odpowiednich intrinsics dla ARM lub x86. Ale ten kod powoduje awarię programu mimo kompilacji.

+0

Czy nie "memcpy (& va, & argv [1] [start], sizeof (va))" działa? – jxh

Odpowiedz

5

Jedną z przyczyn wystąpienia awarii na X86 jest problem z wyrównaniem. Nie mam ucisku w moim systemie, aby odtworzyć problem, ale mogę to zademonstrować na przykładzie GCC.

Jeśli zrobisz coś takiego:

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

/* Global pointer. */ 
char * foo; 

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

Teraz, jeśli skompilować go na wektorze-zdolny x86 z:

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

dostaniesz następujący zestaw do badań:

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

Należy zauważyć, że ruch jest wyrównany, co oczywiście jest nieprawidłowe. Teraz, jeśli byś inline tę funkcję w głównym, i trzeba będzie coś takiego:

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

będzie dobrze, a otrzymasz instrukcję niewyrównana. Jest to rodzaj błędu, który nie ma bardzo dobrej poprawki w kompilatorze, ponieważ wymagałoby interproceduralnej optymalizacji z dodaniem nowych struktur danych, itp.

Źródłem problemu jest to, że kompilator zakłada, że typy wektorowe są wyrównane, więc gdy usuniesz tablicę z wyrównanych typów wektorowych, możesz użyć wyrównanego ruchu. Jako obejście problemu w GCC można określić typ aligné wektorowych, takich jak:

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

i użyć go do nieprawidłowego pamięci aligné.

Nie jestem pewien, czy trafiasz dokładnie na ten problem w swoim setupie, ale jest to coś, co polecam sprawdzić, sprawdzając dane wyjściowe zespołu z kompilatora.

+0

Cóż, w takim przypadku nie widzę żadnego powodu, dla którego powinien on zawieść ... Możesz spróbować zrobić coś takiego: 'struct b16 { char x [16]; }; struct b16 x = * (struct b16 *) & argv [1] [0]; ' –

+1

Uderzyłem podobne problemy używając Clanga, a podczas sprawdzania zespołu (montaż ARM, poszukaj" ': 64'" lub "': 128' "w polu adresu) Widziałem, że używa on wyrównanych wersji instrukcji ładowania i przechowywania. To rozwiązanie działa dla mnie. – sh1