SSE增加了字符

时间:2014-04-15 00:55:47

标签: c sse

我有一个包含0或1的16个char的向量,我想使用SSE添加每个4个非重叠元素。

没有矢量化的代码的简化版本如下所示

char a[16]={1,0,0,1 ,0,0,1,0, 0,1,0,0, 0,0,0,1};
char sum1 = a[0]  + a[1]  + a[2]  + a[3];
char sum2 = a[4]  + a[5]  + a[6]  + a[7];
char sum3 = a[8]  + a[9]  + a[10] + a[11];
char sum4 = a[12] + a[13] + a[14] + a[15];

在我的应用程序中,向量的长度远大于16但它总是16的倍数。我使用其他SSE逻辑运算得到这个向量,这为我提供了一个很好的加速,所以我想知道我是怎么做的可以矢量化那些添加物。下面是完整的代码,其中vec1,vec2和vec3具有相同的长度n(16的倍数),矢量计数是n / 4。

void myfunc( const char *vec1, const char *vec2, char *vec3, int *counts, int n){
  __m128i *r1   = (__m128i*)vec1;
  __m128i *r2   = (__m128i*)vec2;
  char *a = vec3;
  char temp[16] __attribute__ ((aligned (16)));

  for ( int i = 0; i < n; i+=16, r1++, r2++, a+=16 ) {
    _mm_store_si128((__m128i*)a, _mm_and_si128(*r1, *r2));

    _mm_store_si128((__m128i*)temp, _mm_or_si128(*r1, *r2));

    char size = a[0]+a[1]+a[2]+a[3];
    if( size == 0 ){
        memcpy(a, temp, 4*sizeof(char));
        counts[k]++;
    }
    k++;

    size = a[4]+a[5]+a[6]+a[7];
    if( size == 0 ){
        memcpy(a+4, temp+4, 4*sizeof(char));
        counts[k]++;
    }
    k++;

    size = a[8]+a[9]+a[10]+a[11];
    if( size == 0 ){
        memcpy(a+8, temp+8, 4*sizeof(char));
        counts[k]++;
    }
    k++;

    size = a[12]+a[13]+a[14]+a[15];
    if( size == 0 ){
        memcpy(a+12, temp+12, 4*sizeof(char));
        counts[k]++;
    }
    k++;
  }
}

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

您可以比较整数,而不是比较字节。将atempcounts中的四个整数加载到SSE寄存器中(在下面的代码中将它们称为a4tmp4counts4 。然后,您可以使用SSE一次处理四个整数。这假设count是一个int32数组。

例如,假设a4 = {0,3,0,4},counts4 = {1,2,3,4},tmp4 = {5,6,7,8}。在下面的代码中 test将为{-1,0,-1,0}。从计数中减去计数得出count = {2,2,4,4}。 testtmp4的逻辑AND为{5,0,7,0}。将其添加到a4得到a4 = {5,3,7,4}。这应该做你想要的。

for ( int i = 0; i < n; i+=16, r1++, r2++, a+=16, k+=4 ) {
    _mm_store_si128((__m128i*)a, _mm_and_si128(*r1, *r2));
    _mm_store_si128((__m128i*)temp, _mm_or_si128(*r1, *r2));

    __m128i a4 = _mm_load_si128((__m128i*)a);
    __m128i tmp4 = _mm_load_si128((__m128i*)tmp);
    __m128i counts4 = _mm_load_si128((__m128i*)&counts[k]);

    __m128i test = _mm_cmpeq_epi32(_mm_set1_epi32(0), a4);
    a4 = _mm_add_epi32(a4, _mm_and_si128(tmp4,test));        
    counts4 = _mm_sub_epi32(counts4, test);

    _mm_store_si128((__m128i*)a, a4);
    _mm_store_si128((__m128i*)counts, counts4);        
}