2012-06-07 4 views
6

SSE2 지침을 처음 사용합니다. 두 개의 배열 요소를 추가 할 수있는 지침 _mm_add_epi8을 발견했습니다. 하지만 배열의 모든 요소를 ​​추가 할 수있는 SSE 명령이 필요합니다.배열의 모든 요소를 ​​추가하는 SSE 명령어

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

그래서 누구는 SSE2 명령어를 사용하여 배열의 모든 요소를 ​​추가 할 수 있습니다 방법을 말씀 해주십시오 수 있습니다

은이 코드를 사용하여이 개념을 개발하기 위해 노력했다?

도움이 될 것입니다.

+0

psadbw가 오버플로가없는 8 비트 요소를 합산하는 데 훨씬 더 효율적이므로 거기에서 대답하는 것이 유효합니다. 큰 배열의 경우'paddd' 또는'paddq '와 함께 사용하십시오. –

답변

18

배열의 모든 요소를 ​​합치려면 데이터를로드하고 더 넓은 요소 크기로 압축을 풀고 압축을 푼 요소를 합계해야합니다. 루프 이후까지 여러 개의 부분 합계를 유지 한 다음이 부분 합계의 최종 합계를 하나만 수행 할 수 있습니다. 예를 들어

상기 코드 확실치 않은 트릭이 있다는
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; 
} 

주 - 오히려 상기 32 개 비트 벡터 (4 개을 풀고 지시 요구) 및 한 쌍의 각각의 16 비트 벡터를 풀기보다는 다음 사 (32)를 사용하여이 비트, 우리는 효과적으로 우리에게 무료로 풀기를 제공하기 위해 1 _mm_add_epi32의 피승수와 _mm_madd_epi16 (PMADDWD)를 사용 (다른 4 명령)을 추가 그래서 우리는 4 명령 대신 8.

은 또한 참고를 사용하여 동일한 결과를 얻을 입력 배열 a[]은 16 바이트 정렬이어야하고 n은 16의 배수 여야합니다.

+0

답장을 보내 주셔서 감사합니다. 코드가 10,11,13,14 및 17 번 줄에 오류를 표시하고 있습니다. _mm_madd_epi16 명령어는 3 개의 인수를 사용할 수 없습니다. 그리고 vk0는 정의되지 않았습니까? 이 오류를 해결하십시오. – geeta

+0

죄송합니다 - 몇 가지 작업 코드를 간단한 예제로 편집하려고하면 그 일이 발생합니다. 이제는 다소 수정 된 것 같습니다. –

+0

대단히 고맙습니다 .. 작동 중입니다 ... :) – geeta

관련 문제