7 c sse simd intrinsics
我试图在C中学习SSE内在函数的绳索.我有一段代码,我在其中加载双数据的双组分向量,向其添加内容然后尝试将其存储回内存.一切正常:我可以将数据加载到SEE寄存器中,我可以对那些SSE寄存器中的数据进行操作,但是当我尝试将处理后的数据写回原始数组时(我在第一次读取数据时)我得到了一个分段错误.
任何人都可以在这个问题上建议我 - 这让我疯了.
double res[2] __attribute__((aligned(16)));
for(int k=0; k<n; k++){
int i=0;
for(; i+1<n; i+=2)
{
__m128d cik = _mm_load_pd(&C[i+k*n]);
int j = 0;
for(; j+1<n; j+=2)
{
__m128d aTij = _mm_load_pd(&A_T[j+i*n]);
__m128d bjk = _mm_load_pd(&B[j+k*n]);
__m128d dotpr = _mm_dp_pd(aTij, bjk,2);
cik = _mm_add_pd(cik, dotpr);
}
_mm_store_pd(res, cik);
//C[i+k*n] = res[0];
}
}
Run Code Online (Sandbox Code Playgroud)
正如我上面所说的,除了我将结果存储到一维数组"C"的地方之外,一切都在这个代码中工作,我在那里从头读取数据.也就是说,当我删除前面的评论标志时
//C[i+k*n] = res[0];
Run Code Online (Sandbox Code Playgroud)
我遇到了分段错误.
我怎样才能从C读取_mm_load_pd的对齐内存版本(所以C必须在内存中对齐!),而回写它不起作用?"C"必须对齐,正如您所见,"res"也必须对齐.
免责声明:我的原始代码阅读
_mm_store_pd(&C[i+k*n], cik);
Run Code Online (Sandbox Code Playgroud)
这也产生了一个分段错误,我开始在我尝试解决问题的过程中引入"res"和显式对齐.
附录
A,B,C声明如下:
buf = (double*) malloc (3 * nmax * nmax * sizeof(double));
double* A = buf + 0;
double* B = A + nmax*nmax;
double* C = B + nmax*nmax;
Run Code Online (Sandbox Code Playgroud)
尝试使用posix_memalign解决方案
为了在写入原始一维数组时解决分段错误问题,我现在使用缓冲区用于相应的矩阵.但是,当尝试写回C_buff时,这仍然是segfauls!
double res[2] __attribute__((aligned(16)));
double * A_T;
posix_memalign((void**)&A_T, 16, n*n*sizeof(double));
double * B_buff;
posix_memalign((void**)&B_buff, 16, n*n*sizeof(double));
double * C_buff;
posix_memalign((void**)&C_buff, 16, n*n*sizeof(double));
for(int y=0; y<n; y++)
for(int x=0; x<n; x++)
A_T[x+y*n] = A[y+x*n];
for(int x=0; x<n; x++)
for(int y=0; y<n; y++)
B_buff[y+x*n] = B[y+x*n];
for(int x=0; x<n; x++)
for(int y=0; y<n; y++)
C_buff[y+x*n] = C[y+x*n];
for(int k=0; k<n; k++){
int i=0;
for(; i+1<n; i+=2)
{
__m128d cik = _mm_load_pd(&C_buff[i+k*n]);
int j = 0;
for(; j+1<n; j+=2)
{
__m128d aTij = _mm_load_pd(&A_T[j+i*n]);
__m128d bjk = _mm_load_pd(&B_buff[j+k*n]);
__m128d dotpr = _mm_dp_pd(aTij, bjk,2);
cik = _mm_add_pd(cik, dotpr);
}
_mm_store_pd(&C_buff[i+k*n], cik);
//_mm_store_pd(res, cik);
//C_buff[i+k*n] = res[0];
//C_buff[i+1+k*n] = res[1];
}
}
Run Code Online (Sandbox Code Playgroud)
即使使用__attribute__((aligned(32))),我也遇到了同样的错误(有 %50 的机会出现错误对准)。然后我使用以下函数获得 %100 的对齐机会(a 应该是 2 的幂):
void * malloc_float_align(size_t n, unsigned int a/*alignment*/, float *& output)
{
void * adres=NULL;
void * adres2=NULL;
adres=malloc(n*sizeof(float)+a);
size_t adr=(size_t)adres;
size_t adr2=adr+a-(adr&(a-1u)); // a valid address for a alignment
adres2=(void * ) adr2;
output=(float *)adres2;
return adres; //pointer to be used in free()
}
Run Code Online (Sandbox Code Playgroud)
然后在 main 中使用:
int main()
{
float * res=NULL;
void * origin=malloc_float_align(1024,32u,res);
//use res for sse/avx
free(origin); // actual allocation is more than 1024 elements
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当然,这是用 C++ 编写的,因此您只需更改一些函数参数样式即可使其工作。