如何使用SSE来处理使用条件的整数数组

时间:2013-06-14 09:29:29

标签: c++ sse

我是SSE的新手,知识有限。我正在尝试向量化我的代码(C ++,使用gcc),这实际上非常简单。 我有一个无符号整数数组,我只检查> =或< =比某些常量的元素。结果,我需要一个包含传递条件的元素的数组。 我正在考虑使用'mm_cmpge_ps'作为掩码,但这个构造可以在浮点数上工作而不是整数!? :(

任何建议,非常感谢帮助。

3 个答案:

答案 0 :(得分:2)

很容易掩盖掉(即设置为0)所有不匹配的整数。 e.g。

#include <emmintrin.h>    // SSE2 intrinsics

for (int i = 0; i < N; i += 4)
{
    __m128i v = _mm_load_si128(&a[i]);
    __m128i vcmp0 = _mm_cmpgt_epi32(v, _mm_set1_epi32(MIN_VAL - 1));
    __m128i vcmp1 = _mm_cmplt_epi32(v, _mm_set1_epi32(MAX_VAL + 1));
    __m128i vcmp = _mm_and_si128(vcmp0, vcmp1);
    v = _mm_and_si128(v, vcmp);
    _mm_store_si128(&a[i], v);
}

请注意,a需要16字节对齐,而N需要是4的倍数 - 如果这些约束是一个问题,那么扩展代码以应对此问题并不困难。

答案 1 :(得分:1)

你走了。这是三个功能。

第一个函数foo_v1基于Paul R的答案。

第二个功能foo_v2基于今天流行的问题Fastest way to determine if an integer is between two integers (inclusive) with known sets of values

第三个函数foo_v3使用了Agner Fog的vectorclass,我只是为了表明使用他的类更容易和更清洁。如果您没有该课程,则只需注释掉#include "vectorclass.h"行和foo_v3功能。我使用Vec8ui这意味着它将使用AVX2(如果可用)并将其分解为两个Vec4ui,否则您不必更改代码以获得AVX2的好处。

#include <stdio.h>
#include <nmmintrin.h>                 // SSE4.2
#include "vectorclass.h"

void foo_v1(const int N, int *a, const int MAX_VAL, const int MIN_VAL) {
    for (int i = 0; i < N; i += 4) {
        __m128i v = _mm_load_si128((const __m128i*)&a[i]);
        __m128i vcmp0 = _mm_cmpgt_epi32(v, _mm_set1_epi32(MIN_VAL - 1));
        __m128i vcmp1 = _mm_cmplt_epi32(v, _mm_set1_epi32(MAX_VAL + 1));
        __m128i vcmp = _mm_and_si128(vcmp0, vcmp1);
        v = _mm_and_si128(v, vcmp);
        _mm_store_si128((__m128i*)&a[i], v);
    }
}

void foo_v2(const int N, int *a, const int MAX_VAL, const int MIN_VAL) {
    //if ((unsigned)(number-lower) < (upper-lower))
    for (int i = 0; i < N; i += 4) {
        __m128i v = _mm_load_si128((const __m128i*)&a[i]);
        __m128i dv = _mm_sub_epi32(v, _mm_set1_epi32(MIN_VAL));
        __m128i min_ab = _mm_min_epu32(dv,_mm_set1_epi32(MAX_VAL-MIN_VAL));
        __m128i vcmp = _mm_cmpeq_epi32(dv,min_ab);
        v = _mm_and_si128(v, vcmp);
        _mm_store_si128((__m128i*)&a[i], v);
    }
}

void foo_v3(const int N, int *a, const int MAX_VAL, const int MIN_VAL) {
    //if ((unsigned)(number-lower) < (upper-lower))
    for (int i = 0; i < N; i += 8) {
        Vec8ui va = Vec8ui().load(&a[i]);
        va &= (va - MIN_VAL) <= (MAX_VAL-MIN_VAL);
        va.store(&a[i]);
    }
}

int main() {
    const int N = 16;
    int* a = (int*)_mm_malloc(sizeof(int)*N, 16);
    for(int i=0; i<N; i++) {
        a[i] = i;
    }
    foo_v2(N, a, 7, 3);
    for(int i=0; i<N; i++) {
        printf("%d ", a[i]);
    } printf("\n");
    _mm_free(a);
}

答案 2 :(得分:0)

首先要查看的地方可能是Intel® Intrinsics Guide