我是 SSE 新手,知识有限。我正在尝试矢量化我的代码(C++,使用 gcc),这实际上非常简单。我有一个无符号整数数组,我只检查 >= 或 <= 的元素而不是某个常量。结果,我需要一个包含通过条件的元素的数组。我正在考虑使用'mm_cmpge_ps'作为掩码,但是这个构造在浮点而不是整数上工作!?:(
任何建议,非常感谢帮助。
屏蔽掉(即设置为 0)所有不匹配的整数非常容易。例如
#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 的倍数 - 如果这些约束是一个问题,那么扩展代码来解决这个问题并不难。
干得好。这里有三个功能。
第一个函数foo_v1
是基于 Paul R 的回答。
第二个函数foo_v2
是基于当今一个流行的问题确定一个整数是否介于两个具有已知值集的整数(含)之间的最快方法
第三个函数,foo_v3
使用 Agner Fog 的矢量类,我添加它只是为了显示使用他的类是多么容易和清洁。如果您没有该类,则只需注释掉该#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);
}
首先要看的可能是英特尔® 内在指南