Ten problem pojawił się jako problem dodatkowy w poście na blogu pod adresem unusual C preprocessor uses. Dla 127 różnych przesunięć przesunięcia istnieją cztery różne optymalne sekwencje instrukcji SSE2 dla przesunięcia bitowego. Preprocesor sprawia, że rozsądne jest skonstruowanie funkcji zmiany, która odpowiada 129-stykowej instrukcji przełączania. Ułóż tutaj kod źródłowy; Nie mam pojęcia, jak opublikować kod bezpośrednio tutaj. Sprawdź wpis na blogu, aby dowiedzieć się, co się dzieje.
#include <emmintrin.h>
typedef __m128i XMM;
#define xmbshl(x,n) _mm_slli_si128(x,n) // xm <<= 8*n -- BYTE shift left
#define xmbshr(x,n) _mm_srli_si128(x,n) // xm >>= 8*n -- BYTE shift right
#define xmshl64(x,n) _mm_slli_epi64(x,n) // xm.hi <<= n, xm.lo <<= n
#define xmshr64(x,n) _mm_srli_epi64(x,n) // xm.hi >>= n, xm.lo >>= n
#define xmand(a,b) _mm_and_si128(a,b)
#define xmor(a,b) _mm_or_si128(a,b)
#define xmxor(a,b) _mm_xor_si128(a,b)
#define xmzero _mm_setzero_si128()
XMM xm_shl(XMM x, unsigned nbits)
{
// These macros generate (1,2,5,6) SSE2 instructions, respectively:
#define F1(n) case 8*(n): x = xmbshl(x, n); break;
#define F2(n) case n: x = xmshl64(xmbshl(x, (n)>>3), (n)&15); break;
#define F5(n) case n: x = xmor(xmshl64(x, n), xmshr64(xmbshl(x, 8), 64-(n))); break;
#define F6(n) case n: x = xmor(xmshl64(xmbshl(x, (n)>>3), (n)&15),\
xmshr64(xmbshl(x, 8+((n)>>3)), 64-((n)&155))); break;
// These macros expand to 7 or 49 cases each:
#define DO_7(f,x) f((x)+1) f((x)+2) f((x)+3) f((x)+4) f((x)+5) f((x)+6) f((x)+7)
#define DO_7x7(f,y) DO_7(f,(y)+1*8) DO_7(f,(y)+2*8) DO_7(f,(y)+3*8) DO_7(f,(y)+4*8) \
DO_7(f,(y)+5*8) DO_7(f,(y)+6*8) DO_7(f,(y)+7*8)
switch (nbits) {
case 0: break;
DO_7(F5, 0) // 1..7
DO_7(F1, 0) // 8,16,..56
DO_7(F1, 7) // 64,72,..120
DO_7x7(F6, 0) // 9..15 17..23 ... 57..63 i.e. [9..63]\[16,24,..,56]
DO_7x7(F2,56) // 65..71 73..79 ... 121..127 i.e. [65..127]\[64,72,..,120]
default: x = xmzero;
}
return x;
}
xm_shr wynosi powyżej ale zamiana "SHL" i "SHR" wszędzie w F [1256] makr. HTH.
Nie sądzę, że istnieje lepszy sposób. Napisałem odpowiedź na ostatni duplikat tego pytania: http://stackoverflow.com/q/34478328/224132. W przypadku liczenia stałych w czasie kompilacji, zmienia się w 4 insony lub 2 insns z count> = 64. Przy zmiennej liczbie, rozgałęzia się i musi "przemieścić" liczbę i 64-count z liczb całkowitych do rejestrów wektorowych. "__uint128_t" w tym przypadku jest lepsze, jeśli dane są już w rejestrach całkowitych. –