2011-11-03 11 views
11

Jak sprawdzić, czy zmienna __m128i ma dowolną wartość niezerową w procesorach SSE-2 i wcześniejszych?Czy zmienna __m128i jest równa zero?

+0

Czy chodzi o niezerowy bit, czy też o 8/16/32-bitowy element całkowity? –

+0

@BrettHale: Testuję, czy wszystkie są zerowe. – Mehrdad

Odpowiedz

11

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.

+2

+1, to lepsze niż moje. :) Nigdy nie użyłem instrukcji movemask, więc nie wiedziałem, że możesz to zrobić. XD – Mysticial

+0

+1 najbardziej kompaktowe rozwiązanie, jakie widziałem, dzięki! – Mehrdad

+3

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

1

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.

+1

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). –

+0

@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

+1

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 "). –

Powiązane problemy