Jak napisać wersję przenośną, która nie jest zależna od wewnętrznego zestawu x861?Wektory rodzime GNU C: jak emitować skalar, jak _mm_set1_epi16,
typedef uint16_t v8su __attribute__((vector_size(16)));
v8su set1_u16_x86(uint16_t scalar) {
return (v8su)_mm_set1_epi16(scalar); // cast needed for gcc
}
pewnością nie musi być lepszy sposób niż
v8su set1_u16(uint16_t s) {
return (v8su){s,s,s,s, s,s,s,s};
}
Nie chcę napisać wersję AVX2 tego za nadawanie jednego bajta!
Nawet gcc-only lub dzyń tylko odpowiedzieć na tę część byłaby interesująca, w przypadkach, w których chcesz przypisać do zmiennej zamiast tylko używając jako argumentu do operatora binarnego (który działa dobrze z gcc patrz poniżej).
Jeśli chcę użyć broadcast-skalar jako jeden operand operatora binarnego, to działa z gcc (as documented in the manual), ale nie z brzękiem:
v8su vecdiv10(v8su v) { return v/10; } // doesn't compile with clang
Z brzękiem, jeśli I” m kierowania tylko x86 i tylko przy użyciu natywnego wektor składni to get the compiler to generate modular multiplicative inverse constants and instructions for me, mogę napisać:
v8su vecdiv_set1(v8su v) {
return v/(v8su)_mm_set1_epi16(10); // gcc needs the cast
}
Ale potem muszę zmienić wewnętrzna gdybym poszerzyć wektor (do _mm256_set1_epi16
), zamiast konwertować cały kod na AVX2, zmieniając go na vector_size(32)
w jednym miejscu (dla czysto pionowej karty SIMD, która nie wymaga tasowania). To także pokonuje część celu wektorów natywnych, ponieważ nie będzie to kompilacja dla ARM ani żadnego innego celu niż x86.
Brzydki rzut jest wymagany, ponieważ gcc, w przeciwieństwie do klang, nie uważa v8us {aka __vector(8) short unsigned int}
kompatybilny z __m128i {aka __vector(2) long long int}
.
BTW, wszystko to kompiluje się do dobrego asm z gcc i clang (see it on Godbolt). To tylko kwestia tego, jak pisać elegancko, z czytelną składnią, która nie powtarza skali N razy. na przykład v/10
jest na tyle kompaktowy, że nie trzeba nawet umieszczać go we własnej funkcji.
Efektywne kompilowanie z ICC to bonus, ale nie jest wymagany. Natywne wektory GNU C są oczywiste dla ICC, a nawet simple stuff like this doesn't compile efficiently. set1_u16
kompiluje do 8 magazynów skalarnych i obciążenia wektorowego zamiast MOVD/VPBROADCASTW (z włączoną -xHOST
, ponieważ nie rozpoznaje -march=haswell
, ale Godbolt działa na serwerze z obsługą AVX2). Czysto rzucając wyniki wewnątrzinżynierii jest w porządku, ale podział wywołuje funkcję SVML!
Nie można rozsądnie używać wewnętrznej wektorów gcc w clang * tak czy inaczej *, ponieważ tak ochoczo postanowili zaimplementować całkowicie inną semantykę '__bultin_shuffle()'. – EOF
Właśnie znalazłem jakiś stary kod, który napisałem, gdzie pracowałem nad brakującą wewnętrzną transmisją wektorów gcc, wykonując 'vectype v = {0}; v + = typ_skalowy; '. gcc optymalizuje to do transmisji. Nie jest ładny (ponieważ nie może być "const"), ale jest dość krótki. – EOF