Pregunta La manera más eficiente de verificar si todos los componentes de __m128i son 0 [utilizando los intrínsecos de SSE]


Estoy utilizando intrínseca SSE para determinar si un rectángulo (definido por cuatro int32 valores) ha cambiado:

__m128i oldRect; // contains old left, top, right, bottom packed to 128 bits
__m128i newRect; // contains new left, top, right, bottom packed to 128 bits

__m128i xor = _mm_xor_si128(oldRect, newRect);

En este punto, el resultado xor el valor será todos ceros si el rectángulo no ha cambiado. ¿Cuál es entonces la forma más eficiente de determinar eso?

Actualmente lo estoy haciendo:

if (xor.m128i_u64[0] | xor.m128i_u64[1])
{
    // rectangle changed
}

Pero supongo que hay una manera más inteligente (posiblemente usando algunas instrucciones de SSE que aún no he encontrado).

Me estoy dirigiendo a SSE4.1 en x64 y estoy codificando C ++ en Visual Studio 2013.


8
2018-01-12 15:44


origen


Respuestas:


Puede usar la instilación PTEST a través del _mm_testz_si128 intrínseco (SSE4.1), así:

#include "smmintrin.h" // SSE4.1 header

if (!_mm_testz_si128(xor, xor))
{
    // rectangle has changed
}

Tenga en cuenta que _mm_testz_si128 devuelve 1 si el bit a nivel AND de los dos argumentos es cero.


10
2018-01-12 15:59



Irónicamente, ptest la instrucción de SSE 4.1 puede ser más lenta que pmovmskb de SSE2 en algunos casos. Sugiero usar simplemente:

__m128i cmp = _mm_cmpeq_epi32(oldRect, newRect);
if (_mm_movemask_epi8(cmp) != 0xFFFF)
  //registers are different

Tenga en cuenta que si realmente necesita eso xor valor, tendrás que calcularlo por separado.

Para procesadores Intel como Ivy Bridge, la versión de PaulR con xor y _mm_testz_si128 se traduce en 4 uops, mientras que la versión sugerida sin computar xor se traduce en 3 uops (vea también este hilo) Esto puede dar como resultado un mejor rendimiento de mi versión.


5
2017-09-17 18:05