Extensión del vector GCC C: ¿Cómo verificar si el resultado de CUALQUIER comparación de elementos es verdadero, y cuál?

5 minutos de lectura

avatar de usuario
usuario1649948

Soy nuevo en las extensiones de vector C de GCC. Según el manual, el resultado de comparar un vector con otro en la forma (test = vec1 > vec2;) es que “test” contiene un 0 en cada elemento que es falso y un -1 en cada elemento que es verdadero.

Pero, ¿cómo verificar rápidamente si CUALQUIERA de las comparaciones de elementos fue verdadera? Y, además, ¿cómo saber cuál es el primer elemento para el que la comparación fue verdadera?

Por ejemplo, con:

vec1 = {1,1,3,1};
vec2 = {1,2,2,2};
test = vec1 > vec2;

Quiero determinar si la “prueba” contiene alguna verdad (elementos distintos de cero). En este caso, quiero que “prueba” se reduzca a verdadero, porque existe un elemento para el cual vec1 es mayor que vec2 y, por lo tanto, un elemento en prueba que contiene -1.

Además, o alternativamente, quiero descubrir rápidamente QUÉ elemento no pasa la prueba. En este caso, este sería simplemente el número 2. Dicho de otra manera, quiero probar cuál es el primer elemento distinto de cero.

int hasAnyTruth = ...; // should be non-zero. "bool" works too since C99
int whichTrue = ...; // should contain 2, because test[2] == -1

Me imagino que podríamos usar un comando simd de reducción y suma (?) para sumar todo en el vector en un número y comparar esa suma con 0, pero no sé cómo (o si hay una forma más rápida). Supongo que se necesita alguna forma de argmax para la segunda pregunta, pero nuevamente, no sé cómo indicarle a GCC que lo use en los vectores.

  • _mm_movemask_epi8()

    – Místico

    23 de julio de 2015 a las 20:49

  • Vaya, me gusta esto. 1) ¿Es portátil? 2) ¿Alguna ventaja sobre memcmp? 3) ¿Funciona con registros de 256 bits (AVX) o vectores con diferente número de elementos?

    – usuario1649948

    23 de julio de 2015 a las 20:56


  • Es más portátil que las extensiones vectoriales GCC. Está estandarizado por Intel, por lo que funcionará en todos los principales compiladores: GCC, Clang, MSVC, ICC, etc… software.intel.com/sites/landingpage/IntrinsicsGuide

    – Místico

    23 de julio de 2015 a las 20:59

  • Hay una instrucción para eso en x86: ptest.

    – FEO

    23 de julio de 2015 a las 21:22


  • Sospecho que la forma más rápida de implementar memcmp() en un x86 con (al menos) sse4_1 usará ptest. Si desea usarlo en gcc, está disponible en microarquitecturas x86 que lo admiten como __builtin_ia32_ptestc128/ptestnzc128/ptestz128/256.

    – FEO

    23 de julio de 2015 a las 21:36

La extensión del vector de Clang hace un buen trabajo con el any función.

#if defined(__clang__)
typedef int64_t vli __attribute__ ((ext_vector_type(VLI_SIZE)));
typedef double  vdf __attribute__ ((ext_vector_type(VDF_SIZE)));
#else
typedef int32_t vsi __attribute__ ((vector_size (SIMD_SIZE)));
typedef int64_t vli __attribute__ ((vector_size (SIMD_SIZE)));
#endif

static bool any(vli const & x) {
  for(int i=0; i<VLI_SIZE; i++) if(x[i]) return true;
  return false;
}

Asamblea

any(long __vector(4) const&): # @any(long __vector(4) const&)
  vmovdqa ymm0, ymmword ptr [rdi]
  vptest ymm0, ymm0
  setne al
  vzeroupper
  ret

A pesar de que pmovmskb Todavía podría ser una mejor opción ptest sigue siendo una gran mejora con respecto a lo que hace GCC

any(long __vector(4) const&):
  cmp QWORD PTR [rdi], 0
  jne .L5
  cmp QWORD PTR [rdi+8], 0
  jne .L5
  cmp QWORD PTR [rdi+16], 0
  jne .L5
  cmp QWORD PTR [rdi+24], 0
  setne al
  ret
.L5:
  mov eax, 1
  ret

GCC debería arreglar esto. sonido es aunque no es óptimo para AVX512.

los any función Yo diría que es una función vectorial crítica, por lo que los compiladores deberían proporcionar una función integrada como lo hacen para la reproducción aleatoria (por ejemplo, __builtin_shuffle para CCG y __builtin_shufflevector para clang) o el compilador debe ser lo suficientemente inteligente como para descubrir el código óptimo como lo hace Clang al menos para SSE y AVX pero no para AVX512.

  • +1 Me quedé sin votos positivos cuando respondiste por primera vez, ¡pero buena respuesta! Perdón por el que publiqué en la comunidad antes de copiar la respuesta de Mysticial de los comentarios. Eso fue en un momento en que me dediqué a tratar de moderar y preservar la “posteridad del sitio”. Lo eliminaría, excepto que no puedo hasta que se cambie la respuesta.

    usuario4842163

    22 de enero de 2018 a las 19:18


De Mística:

_mm_movemask_epi8()

Es más portátil que las extensiones vectoriales GCC. Está estandarizado por Intel, por lo que funcionará en todos los principales compiladores: GCC, Clang, MSVC, ICC, etc…

http://software.intel.com/sites/landingpage/IntrinsicsGuide

  • Esto no es más portátil que las extensiones vectoriales de GCC. Por ejemplo, es inútil en ARM.

    – bosón Z

    17 de enero de 2018 a las 14:29

  • @Zboson Tengo que referirme a Mysticial para obtener una respuesta, ya que terminé simplemente publicando en la comunidad su comentario de la pregunta como una respuesta para la posteridad, ya que la pregunta originalmente no tuvo respuestas durante un buen tiempo y parecía resuelta a través de comentarios, definitivamente no hardware. -portátil.

    usuario4842163

    17 de enero de 2018 a las 15:03


Esto es lo que terminé usando en un caso:

#define V_EQ(v1, v2) \
  ({ \
    __typeof__ (v1) v_d = (v1) != (v2); \
    __typeof__ (v_d) v_0 = { 0 }; \
    memcmp (&v_d, &v_0, sizeof v_d) == 0; \
  })

assert (V_EQ (v4ldblo, v4ldbli - 1));

Para hacer esto, podemos usar funciones intrínsecas, al usar funciones intrínsecas podemos lograr más velocidad en la ejecución del código.
Consulte el siguiente enlace

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad