2012-06-07 8 views
6

Ich bin neu in SSE2-Anweisungen. Ich habe eine Anweisung _mm_add_epi8 gefunden, die zwei Array-Elemente hinzufügen kann. Aber ich möchte einen SSE-Befehl, der alle Elemente eines Arrays hinzufügen kann.SSE-Anweisungen zum Hinzufügen aller Elemente eines Arrays

Ich habe versucht, dieses Konzept mit diesem Code zu entwickeln:

#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]); 
} 

So jemand kann mir bitte sagen, wie es möglich ist, alle Elemente eines Arrays mit SSE2 Befehle hinzufügen?

Jede Hilfe wird geschätzt.

+0

Geschlossen als Duplikat, weil 'psadbw' * signifikant * effizienter ist, um 8-Bit-Elemente ohne Überlauf zu summieren, und die Antwort dort verwendet das. Verwenden Sie es mit "Paddd" oder "Paddq" für große Arrays. –

Antwort

18

Wenn Sie nur alle Elemente eines Arrays summieren möchten, müssen Sie die Daten laden, sie auf eine größere Elementgröße entpacken und dann die entpackten Elemente summieren. Beachten Sie, dass Sie mehrere Partialsummen bis nach der Schleife beibehalten und dann nur eine letzte Summe dieser Partialsummen eingeben können. Zum Beispiel:

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; 
} 

anzumerken, dass es ein nicht-offensichtlicher Trick ist in der obigen Code - 32 anstatt weiter Auspacken jeden 16-Bit-Vektor, um ein Paar von 32-Bit-Vektoren (erfordern 4 auspacken Anweisungen) und unter Verwendung von vier dann Bit addiert (weitere 4 Anweisungen), verwenden wir _mm_madd_epi16 (PMADDWD) mit einem Multiplikanden von 1 und _mm_add_epi32 effektiv uns frei auspacken zu geben, so dass wir das gleiche Ergebnis mit 4 Befehle statt 8.

Beachten Sie auch, dass der Eingang Array, a[], muss 16 Byte ausgerichtet sein, und n sollte ein Vielfaches von 16 sein.

+0

Danke für die Antwort .. Ihr Code zeigt Fehler in der Zeile Nummer 10,11,13,14 und 17. Der Befehl _mm_madd_epi16 kann nicht 3 Argumente nehmen. Und vk0 ist undefiniert? Bitte beheben Sie diese Fehler. – geeta

+0

Entschuldigung - das passiert, wenn Sie etwas Arbeitscode nehmen und versuchen, es in ein einfaches Beispiel zu schneiden - ich denke, es ist jetzt mehr oder weniger behoben. –

+0

Vielen Dank .. Es funktioniert ... :) – geeta