Jak sprawdzić, czy zmienna __m128i
ma dowolną wartość niezerową w procesorach SSE-2 i wcześniejszych?Czy zmienna __m128i jest równa zero?
Odpowiedz
W SSE2 można zrobić:
__m128i zero = _mm_setzero_si128();
if(_mm_movemask_epi8(_mm_cmpeq_epi32(x,zero)) == 0xFFFF)
{
//the code...
}
to przetestuje cztery INT vs zerowy następnie powrócić maskę za każdy bajt, więc wiertła-offsety z których każda odpowiada int
będzie na 0, 4, 8 & 12, ale powyższy test zostanie przechwycony, jeśli ustawiony zostanie jakikolwiek bit, wtedy jeśli zachowasz maskę, możesz w razie potrzeby pracować z drobniejszymi częściami.
+1, to lepsze niż moje. :) Nigdy nie użyłem instrukcji movemask, więc nie wiedziałem, że możesz to zrobić. XD – Mysticial
+1 najbardziej kompaktowe rozwiązanie, jakie widziałem, dzięki! – Mehrdad
Istnieje błąd w znakomitej odpowiedzi - jeśli sprawdzasz wszystkie zera, powinno to być 'if (_mm_movemask_epi8 (_mm_cmpeq_epi32 (x, zero)) == 0xFFFF)'. Dzieje się tak, ponieważ '_mm_cmpeq_epi32' ustawia int na wszystkie 1, nie wszystkie 0, jeśli jest równe zero, a następnie' _mm_movemask_epi8' ustawia pierwsze 16 bitów na podstawie najbardziej znaczącego bitu każdego bajtu w argumencie. Mam nadzieję, że autor może edytować odpowiedź - próbowałem, ale zostałem odrzucony. – FarmerBob
Ze względu na kompletność, z SSE4 można użyć _mm_testz_si128.
const bool isAllZero = _mm_testz_si128(a,a);
Należy pamiętać, że jest to prawdągdy wszystkie bity są zerowe.
To jest rzeczywiście nieco szybsze i nie wymaga rejestru z pełnym zerem do przetestowania. 'ptest' /' jz' to 2 + 1 uop (nie makro-fuse). 'pcmpeq' (1uop) /' pmovmsk' (1uop)/'i 0xffff' (1uop) /' cmp 0xffff/je' (1uop). Jeśli testowałeś drugi przypadek (* dowolne * zero elementów, a nie * wszystkie * zero elementów), miałyby one mniej więcej taką samą wydajność na obecnych procesorach Intel i AMD: 'ptest' /' jnz' (3 uops) . 'pcmpeq' /' pmovmsk'/'test/jnz' (3 uops). –
@PeterCordes Co, w takim przypadku, mieć zestaw rejestrów na wszystkich i używając '_mm_testc_si128'? Coś jak 'const bool atLeastOneZero = _mm_testc_si128 (a, allOnes)' – Antonio
Ponownie, 'ptest' jest nieco szybszy. Aby zrobić to bez 'ptest', użyjesz' pcmpeq' w stosunku do wektora all-one, a następnie wykonasz dokładnie tę samą sekwencję, aby sprawdzić, czy wszystkie elementy są zgodne. Sprawdzanie, czy wszystko-zero lub all-one z 'pcmpeq' jest takie samo jak przy sprawdzaniu == do dowolnego innego wzorca, z tym wyjątkiem, że stałe są łatwiejsze do wygenerowania w locie (' pxor same, same' lub 'pcmpeqw same, samo "). –
Czy chodzi o niezerowy bit, czy też o 8/16/32-bitowy element całkowity? –
@BrettHale: Testuję, czy wszystkie są zerowe. – Mehrdad