2012-06-07 8 views
6

SSE2命令の新機能です。私は命令_mm_add_epi8を見つけました。これは2つの配列要素を追加することができます。しかし、配列のすべての要素を追加できる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

配列のすべての要素を合計したい場合は、データをロードし、それをより広い要素サイズに展開して、アンパックされた要素を合計する必要があります。ループの後まで、複数の部分合計を維持し、これらの部分合計の最終的な合計を1つだけ行うことができます。例えば: - なくさらに32ビットベクトル(4つのアンパック命令を必要とする)一対の各16ビットベクトルを開梱した後、4つの32を使用するより上のコード内の1つの非自明なトリックがあること

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

注ビットは、我々は、効果的に私たちに無料の開梱を与えるために1と_mm_add_epi32の被乗数と_mm_madd_epi16PMADDWD)を使用します(別の4つの命令)を追加しますので、我々は4つの命令の代わりに、8

ことにも注意してくださいを使用して同じ結果を得る入力配列a[]は、16バイトに整列する必要があり、nは16の倍数である必要があります。

+0

返信ありがとうございます。あなたのコードは行番号10,11,13,14、および17にエラーを表示しています。_mm_madd_epi16命令は3つの引数を取ることができません。そしてvk0は未定義ですか?これらのエラーを解決してください。 – geeta

+0

申し訳ありません - 作業コードをいくつか取り、単純な例に編集しようとするとどうなりますか?今は多少なりとも修正されていると思います。 –

+0

ありがとうございました..それは働いています... :) – geeta

関連する問題