2012-06-07 14 views
6

Soy nuevo en las instrucciones SSE2. Encontré una instrucción _mm_add_epi8 que puede agregar dos elementos de matriz. Pero quiero una instrucción SSE que pueda agregar todos los elementos de una matriz.Instrucciones de SSE para agregar todos los elementos de una matriz

yo estaba tratando de desarrollar este concepto utilizando este código:

#include <iostream> 
#include <conio.h> 
#include <emmintrin.h> 

void sse(unsigned char* a,unsigned char* b); 

void main() 
{ 
    /*unsigned char *arr; 
    arr=(unsigned char *)malloc(50);*/ 

    unsigned char arr[]={'a','b','c','d','e','f','i','j','k','l','m','n','o','p','q','r','a','b','c','d','e','f','i','j','k','l','m','n','o','p','q','r'}; 
    unsigned char *next_arr=arr+16; 
    for(int i=0;i<16;i++) 
      printf("%d,%c ",next_arr[i],next_arr[i]); 
    sse(arr,next_arr); 

    getch(); 
} 

void sse(unsigned char* a,unsigned char* b)                                           
{                                                                                                
    __m128i* l = (__m128i*)a;                                              
    __m128i* r = (__m128i*)b; 
    __m128i result; 

     result= _mm_add_epi8(*l, *r); 

     unsigned char *p; 
     p=(unsigned char *)&result; 

     for(int i=0;i<16;i++) 
      printf("%d ",p[i]); 

     printf("\n"); 
     l=(__m128i*)p; 
     r=(__m128i*)(p+8);   
     result=_mm_add_epi8(*l, *r); 
     p=(unsigned char *)&result; 
     printf("%d ",p[0]); 

     l=(__m128i*)p; 
     r=(__m128i*)(p+4); 
     result=_mm_add_epi8(*l, *r); 
     p=(unsigned char *)&result; 
     l=(__m128i*)p; 
     r=(__m128i*)(p+2); 
     result=_mm_add_epi8(*l, *r); 
     p=(unsigned char *)&result; 
     l=(__m128i*)p; 
     r=(__m128i*)(p+1); 
     result=_mm_add_epi8(*l, *r); 
      p=(unsigned char *)&result; 
      printf("result =%d ",p[0]); 
} 

Así puede alguien por favor dígame cómo es posible añadir todos los elementos de una matriz mediante instrucciones SSE2?

Cualquier ayuda será apreciada.

+0

Cerrado como duplicado porque 'psadbw' es * significativamente * más eficiente para sumar elementos de 8 bits sin desbordamiento, y la respuesta allí lo usa. Úselo con 'paddd' o' paddq' para arreglos grandes. –

Respuesta

18

Si solo desea sumar todos los elementos de una matriz, deberá cargar los datos, descomprimirlos en un elemento de mayor tamaño y luego sumar los elementos desempaquetados. Tenga en cuenta que puede mantener múltiples sumas parciales hasta después del bucle y luego solo hacer una suma final de estas sumas parciales. Por ejemplo:

uint32_t sum_array(const uint8_t a[], int n) 
{ 
    const __m128i vk0 = _mm_set1_epi8(0);  // constant vector of all 0s for use with _mm_unpacklo_epi8/_mm_unpackhi_epi8 
    const __m128i vk1 = _mm_set1_epi16(1);  // constant vector of all 1s for use with _mm_madd_epi16 
    __m128i vsum = _mm_set1_epi32(0);   // initialise vector of four partial 32 bit sums 
    uint32_t sum; 
    int i; 

    for (i = 0; i < n; i += 16) 
    { 
     __m128i v = _mm_load_si128(&a[i]);  // load vector of 8 bit values 
     __m128i vl = _mm_unpacklo_epi8(v, vk0); // unpack to two vectors of 16 bit values 
     __m128i vh = _mm_unpackhi_epi8(v, vk0); 
     vsum = _mm_add_epi32(vsum, _mm_madd_epi16(vl, vk1)); 
     vsum = _mm_add_epi32(vsum, _mm_madd_epi16(vh, vk1)); 
               // unpack and accumulate 16 bit values to 
               // 32 bit partial sum vector 

    } 
    // horizontal add of four 32 bit partial sums and return result 
    vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8)); 
    vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4)); 
    sum = _mm_cvtsi128_si32(vsum); 
    return sum; 
} 

en cuenta que hay un truco no evidente en el código anterior - en lugar de desembalaje más cada vector de 16 bits a un par de vectores de bits 32 (que requieren 4 instrucciones de desempaquetado) y a continuación, utilizando cuatro 32 poco añade otro 4 (instrucciones), utilizamos _mm_madd_epi16 (PMADDWD) con un multiplicando de 1 y _mm_add_epi32 para darnos efectivamente desembalaje libre, por lo que tenemos el mismo resultado utilizando 4 instrucciones en lugar de 8.

Tenga en cuenta también que la entrada array, a[], debe estar alineado 16 bytes, y n debe ser un múltiplo de 16.

+0

Gracias por responder .. Su código muestra un error en el número de línea 10,11,13,14 y 17. La instrucción _mm_madd_epi16 no puede tomar 3 argumentos. Y vk0 no está definido? Por favor, resuelve estos errores. – geeta

+0

Lo siento, eso es lo que sucede cuando tomas un código que funciona e intentas editarlo en un simple ejemplo: creo que ahora está más o menos solucionado. –

+0

Muchas gracias ... Está funcionando ... :) – geeta

Cuestiones relacionadas