soporte requisitos procesador pcsx2 con x86 simd intrinsics avx avx2

x86 - requisitos - avx2 tensorflow



_mm_alignr_epi8(PALIGNR) equivalente en AVX2 (3)

La única solución que pude encontrar para esto es:

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) { if (n < 16) { __m128i v0h = _mm256_extractf128_si256(v0, 0); __m128i v0l = _mm256_extractf128_si256(v0, 1); __m128i v1h = _mm256_extractf128_si256(v1, 0); __m128i vouth = _mm_alignr_epi8(v0l, v0h, n); __m128i voutl = _mm_alignr_epi8(v1h, v0l, n); __m256i vout = _mm256_set_m128i(voutl, vouth); return vout; } else { __m128i v0h = _mm256_extractf128_si256(v0, 1); __m128i v0l = _mm256_extractf128_si256(v1, 0); __m128i v1h = _mm256_extractf128_si256(v1, 1); __m128i vouth = _mm_alignr_epi8(v0l, v0h, n - 16); __m128i voutl = _mm_alignr_epi8(v1h, v0l, n - 16); __m256i vout = _mm256_set_m128i(voutl, vouth); return vout; } }

que creo que es bastante idéntico a su solución, excepto que también maneja cambios de> = 16 bytes.

En SSE3, la instrucción PALIGNR realiza lo siguiente:

PALIGNR concatena el operando de destino (el primer operando) y el operando fuente (el segundo operando) en un compuesto intermedio, desplaza el compuesto en granularidad de bytes hacia la derecha por una constante inmediata, y extrae el resultado alineado a la derecha en el destino.

Actualmente estoy en medio de portar mi código SSE4 para usar las instrucciones AVX2 y trabajar en registros de 256 bits en lugar de 128 bits. Ingenuamente, creí que la función intrínseca _mm256_alignr_epi8 (VPALIGNR) realiza la misma operación que _mm_alignr_epi8 solo en los registros de 256 bits. Lamentablemente, sin embargo, ese no es exactamente el caso. De hecho, _mm256_alignr_epi8 trata el registro de 256 bits como 2 registros de 128 bits y realiza 2 operaciones de "alineación" en los dos registros vecinos de 128 bits. Efectivamente realizando la misma operación que _mm_alignr_epi8 pero en 2 registros a la vez. Está más claramente ilustrado aquí: _mm256_alignr_epi8

Actualmente mi solución es seguir usando _mm_alignr_epi8 dividiendo los registros de ymm (256 bits) en dos registros de xmm (128 bits) (alto y bajo), de esta manera:

__m128i xmm_ymm1_hi = _mm256_extractf128_si256(ymm1, 0); __m128i xmm_ymm1_lo = _mm256_extractf128_si256(ymm1, 1); __m128i xmm_ymm2_hi = _mm256_extractf128_si256(ymm2, 0); __m128i xmm_ymm_aligned_lo = _mm_alignr_epi8(xmm_ymm1_lo, xmm_ymm1_hi, 1); __m128i xmm_ymm_aligned_hi = _mm_alignr_epi8(xmm_ymm2_hi, xmm_ymm1_lo, 1); __m256i xmm_ymm_aligned = _mm256_set_m128i(xmm_ymm_aligned_lo, xmm_ymm_aligned_hi);

Esto funciona, pero tiene que haber una mejor manera, ¿verdad? ¿Hay una instrucción AVX2 tal vez más "general" que debería usarse para obtener el mismo resultado?


¿Para qué estás usando palignr ? Si solo se trata de manejar la desalineación de datos, simplemente use cargas desalineadas; en general, son "lo suficientemente rápidos" en arquitecturas μ modernas de Intel (y le ahorrarán mucho tamaño de código).

Si necesita palignr comportamiento similar al de palignr por alguna otra razón, simplemente puede aprovechar el soporte de carga desalineado para hacerlo sin ramificaciones. A menos que estés totalmente conectado a la tienda de carga, esta es probablemente la expresión preferida.

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) { // Do whatever your compiler needs to make this buffer 64-byte aligned. // You want to avoid the possibility of a page-boundary crossing load. char buffer[64]; // Two aligned stores to fill the buffer. _mm256_store_si256((__m256i *)&buffer[0], v0); _mm256_store_si256((__m256i *)&buffer[32], v1); // Misaligned load to get the data we want. return _mm256_loadu_si256((__m256i *)&buffer[n]); }

Si puede proporcionar más información acerca de cómo exactamente está usando palignr , probablemente pueda ser más útil.