Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

170
Vistas
Multiplicar-restar en SSE

Estoy vectorizando un fragmento de código y en algún momento tengo la siguiente configuración:

 register m128 a = { 99,99,99,99,99,99,99,99 } register m128 b = { 100,50,119,30,99,40,50,20 }

Actualmente estoy empaquetando s short en estos registros, por lo que tengo 8 valores por registro. Lo que me gustaría hacer es restar el i-ésimo elemento en b con el valor correspondiente en a si el i-ésimo valor de b es mayor o igual que el valor en a (En este caso, a se llena con la constante 99 ). Con este fin, primero uso una operación mayor o igual que entre b y a , lo que produce, para este ejemplo:

 register m128 c = { 1,0,1,0,1,0,0,0 }

Para completar la operación, me gustaría usar multiplicar y restar, es decir, almacenar en b la operación b -= a*c . El resultado sería entonces:

 b = { 1,50,20,30,0,40,50,20 }

¿Hay alguna operación que haga tal cosa? Lo que encontré fueron operaciones fusionadas para Haswell, pero actualmente estoy trabajando en Sandy-Bridge. Además, si alguien tiene una mejor idea para hacer esto, hágamelo saber (por ejemplo, podría hacer una resta lógica: si 1 en c entonces resto, nada de lo contrario.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Básicamente, desea una versión SSE de este código, ¿verdad?

 if (b >= a) t = ba else t = b b = t

Dado que queremos evitar condicionales para la versión SSE, podemos deshacernos del flujo de control de esta manera (tenga en cuenta que la máscara está invertida):

 uint16_t mask = (b>=a)-1 uint16_t tmp = ba; uint16_t d = (b & mask) | (tmp & ~mask) b = d

Revisé el intrínseco _mm_cmpgt_epi16 y tiene una buena propiedad que devuelve 0x0000 para falso o 0xFFFF para verdadero, en lugar de un solo bit 0 o 1 (eliminando así la necesidad de la primera resta). Por lo tanto, nuestra versión SSE podría verse así.

 __m128i mask = _mm_cmpgt_epi16 (b, a) __m128i tmp = _mm_sub_epi16 (b, a) __m128 d = _mm_or_ps (_mm_and_ps (mask, tmp), _mm_andnot_ps (mask, b))

EDITAR : Harold ha mencionado una respuesta mucho menos complicada. La solución anterior puede ser útil si necesita modificar la parte else de if/else .

 uint16_t mask = ~( (b>=a)-1 ) uint16_t tmp = a & mask b = b - tmp

el código SSE será

 __m128i mask = _mm_cmpgt_epi16 (b, a) __m128i t = _mm_sub_epi16 (b, _mm_and_si128 (mask, a))
over 4 years ago · Santiago Trujillo Denunciar

0

Otra alternativa, si sus entradas no están firmadas, puede calcular

 b = min(b, ba);

Esto funciona, porque si a>b entonces ba se ajusta y se garantiza que dará como resultado un valor mayor que b . Para a<=b siempre obtendrá un valor entre 0 y b inclusive.

 b = _mm_min_epu16(b, _mm_sub_epi16(b,a));

El _mm_min_epu16 requerido requiere SSE4.1 o posterior ( _mm_min_epu8 solo requeriría SSE2).

over 4 years ago · Santiago Trujillo Denunciar

0

Puede copiar b a c , restar a de c , realizar un desplazamiento aritmético de 15 posiciones a la derecha en los valores de 16 bits, complementar el valor de c , enmascarar c con a y finalmente restar c de b .

No estoy familiarizado con la sintaxis intrínseca, pero los pasos son:

 register m128 c = b; c -= a; c >>= 15; c = ~c; c &= a; b -= c;

aquí hay una alternativa con menos pasos:

 register m128 c = compare_ge(b, a); c = -c; c &= a; b -= c;
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda