对于之前的非描述性问题,我们深表歉意。请允许我再次重新提出问题:
设置:
我需要使用SSE同时对来自4个阵列的4个32位值进行ADD和一些有点操作。这4个数组中的所有元素都是整数(32位)。结果将转到第5个阵列。
所以我的问题是:
另一个问题,如果我需要从整数A中读取最后一位,从整数B读取第一位,并将整数C中的最后一位和第一位替换为刚刚读取的值,我可以在这里使用SSE吗?或者有任何快速的方法吗?在正常情况下,而不是3次访问?
保罗提供的代码
#include <stdint.h>
#include <emmintrin.h>
const size_t N = 4096; // size of input/output arrays
int32_t array0[N]; // 4 x input arrays
int32_t array1[N];
int32_t array2[N];
int32_t array3[N];
int32_t array_sum[N]; // output array
for (size_t i = 0; i < N; i += 4)
{
__m128i v0 = _mm_load_si128(&array0[i]); // load 4 x vectors of 4 x int
__m128i v1 = _mm_load_si128(&array1[i]);
__m128i v2 = _mm_load_si128(&array2[i]);
__m128i v3 = _mm_load_si128(&array3[i]);
__m128i vsum = _mm_add_epi32(v0, v1); // sum vectors
__m128i vsum = _mm_add_epi32(vsum, v2);
__m128i vsum = _mm_add_epi32(vsum, v3);
_mm_store_si128(&array_out[i], vsum); // store sum
}
答案 0 :(得分:9)
你所拥有的代码确实会有所改变。
#include <stdint.h>
#include <emmintrin.h>
const size_t N = 4096; // size of input/output arrays
__declspec(align(16)) int32_t array0[N]; // 4 x input arrays
__declspec(align(16)) int32_t array1[N];
__declspec(align(16)) int32_t array2[N];
__declspec(align(16)) int32_t array3[N];
__declspec(align(16)) int32_t array_sum[N]; // output array
for (size_t i = 0; i < N; i += 4)
{
__m128i v0 = _mm_load_si128(&array0[i]); // load 4 x vectors of 4 x int
__m128i v1 = _mm_load_si128(&array1[i]);
__m128i v2 = _mm_load_si128(&array2[i]);
__m128i v3 = _mm_load_si128(&array3[i]);
__m128i vsum = _mm_add_epi32(v0, v1); // sum vectors
__m128i vsum = _mm_add_epi32(vsum, v2);
__m128i vsum = _mm_add_epi32(vsum, v3);
_mm_store_si128(&array_sum[i], vsum); // store sum
}
在使用内在函数时,我喜欢包含<immintrin.h>
并使用gcc -march=native
进行编译。这样可以访问当前硬件上实际可用的所有指令集扩展。
在另一个问题上,是的,你当然可以这样做,但只有在整数A,B和C的数组上才能有效。
示例:
__declspec(align(16)) int32_t A[N]; // input arrays
__declspec(align(16)) int32_t B[N];
__declspec(align(16)) int32_t C[N];
__declspec(align(16)) int32_t R[N]; // output array
__m128i* As = (__m128i*)A; // cast them to SSE type, avoids separate load/store calls later
__m128i* Bs = (__m128i*)B;
__m128i* Cs = (__m128i*)C;
__m128i* Rs = (__m128i*)R;
__m128i A_mask = _mm_set1_epi32(1<<31); // select these bits from A, B, and C
__m128i B_mask = _mm_set1_epi32(1);
__m128i C_mask = _mm_set1_epi32(0xffffffff ^ ( 1<<31 | 1 ));
for (size_t i = 0; i < N / 4; i ++)
{
__m128i a = _mm_and_si128(A_mask, As[i]);
__m128i b = _mm_and_si128(B_mask, Bs[i]);
__m128i c = _mm_and_si128(C_mask, Cs[i]);
Rs[i] = _mm_or_si128( _mm_or_si128(a, b), c );
}
如上所述,将int32_t数组别名化为__m128i并不是更有效,如果编译器很好,它应该编译成完全相同的代码,但它会导致更简洁的代码。推荐:))
答案 1 :(得分:2)
要使用gcc编译SSE代码,您只需要-msse2
标志,例如
$ gcc -Wall -O3 -msse2 foo.c -o foo
至于其他要求,最好是你可以发布你想要矢量化的工作(标量)示例代码,因为从上面的描述中不是很清楚。