C SSE?mm?负载?pd工作,而?mm?存储?pd故障

C SSE?mm?负载?pd工作,而?mm?存储?pd故障,c,sse,simd,intrinsics,C,Sse,Simd,Intrinsics,我试图学习C语言中SSE内部函数的诀窍。我有一段代码,其中我加载了一个双数据的双分量向量,向它添加一些东西,然后尝试将它存储回内存。 一切正常:我可以将数据加载到SEE寄存器中,我可以对这些SSE寄存器中的数据进行操作,但当我试图将处理后的数据写回原始阵列(我首先从原始阵列读取数据!)时,我遇到了分段错误 有谁能在这个问题上给我一些建议吗?这让我发疯了 double res[2] __attribute__((aligned(16))); for(int k=0; k<n; k++){

我试图学习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];
  }
}
我有一个分割错误

我怎么可能用对齐内存版本的_mm_load_pd(所以C必须在内存中对齐!)从C中读取,而写回它却不起作用?“C”必须对齐,正如您所看到的,“res”也必须对齐

免责声明:我的原始代码已阅读

_mm_store_pd(&C[i+k*n], cik);
这也产生了分割错误,我开始引入带有显式对齐的“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;
尝试使用posix_memalign解决方案

为了解决写入原始一维数组时的分段错误问题,我现在对相应的矩阵使用缓冲区。然而,当试图写回C_buff时,这仍然是错误的

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];
    }
}
double res[2]uuuuu属性_uuuu((对齐(16));
双*A_T;
posix_memalign((void**)和A_T,16,n*n*sizeof(double));
双倍B_buff;
posix_memalign((void**)和B_buff,16,n*n*sizeof(double));
双*C_buff;
posix_memalign((void**)和C_buff,16,n*n*sizeof(double));

对于(int y=0;y即使使用
\uuuu属性(aligned(32)))
,我也得到了相同的错误(错误对齐的几率为%50)。然后我使用以下函数获得了%100的对齐几率(a应该是2的幂):

那么主要的用法是:

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;
}

当然,这是C++中的,所以只需要改变一些函数参数样式就可以了。

一个简单的技巧就是执行断言,并查看它是否触发:

ASSERT( ((size_t)(&C_buff[i+k*n]) & 0xF) == 0);
当地址未对齐时,将触发断言。 默认情况下,64位构建应提供16B对齐。 如果您计划使用32位代码,请使用上述align_malloc函数之一。
你需要使用相关的align\u free,否则会崩溃。

当你删除
\u mm\u store\u pd(&C\u buff[i+k*n],cik);
整个循环都得到了优化和删除。编译器推断整个for循环不会导致任何有意义的工作并将其删除。这就是你不再出现分段错误的原因。
我确信分割错误是因为数组的大小。 根据你的例子考虑这个简单的程序:

#include <stdio.h>
#include "emmintrin.h"

int main(){
int n = 15;
int y,x,k,i,j;

double * A;
posix_memalign((void**)&A, 16, n*n*sizeof(double));

double * B;
posix_memalign((void**)&B, 16, n*n*sizeof(double));

double * C;
posix_memalign((void**)&C, 16, n*n*sizeof(double));

for(y=0; y<n; y++)
  for(x=0; x<n; x++)
    A[x+y*n] = 0.1;

for(x=0; x<n; x++)
  for(y=0; y<n; y++)
    B[y+x*n] = 0.1;

for(x=0; x<n; x++)
  for( y=0; y<n; y++)
    C[y+x*n] = 0.1;

for( k=0; k<n; k++){
   i=0;
  for(; i+1<n; i+=2)
    {
      __m128d cik = _mm_load_pd(&C[i+k*n]);
       j = 0;
      for(; j+1<n; j+=2)
        {
          __m128d aTij = _mm_load_pd(&A[j+i*n]);
          __m128d bjk = _mm_load_pd(&B[j+k*n]);
          __m128d dotpr = _mm_add_pd(aTij, bjk);
          cik = _mm_add_pd(cik, dotpr);
        }
      _mm_store_pd(&C[i+k*n], cik);
    }
}
printf("C[15]: %f\n", C[15]);
printf("C[14]: %f\n", C[14]);
#包括
#包括“emmintrin.h”
int main(){
int n=15;
int y,x,k,i,j;
双*A;
posix_memalign((void**)和A,16,n*n*sizeof(double));
双*B;
posix_memalign((void**)和B,16,n*n*sizeof(double));
双*C;
posix_memalign((void**)和C,16,n*n*sizeof(double));

对于(y=0;y@TonyTheLion请参阅有问题的附录。据我所知,malloc试图对齐它分配的内存块,但并非总是成功实现所有目的。我对上述问题的主要困惑是,我可以从“C”中的特定位置读取,但无法写入。所以“C”显示对齐是为了阅读而不是写作?我认为假设
malloc
将对齐任何内容都是不确定的,如果您使用的是GCC或MSVC,您可能希望使用它。@TonyTheLion谢谢您的建议。因为我对
A
B
C
是如何对齐的问题无能为力最初已分配,现在我将它们的值复制到一维数组中,并按照您的建议使用
aligned\u malloc
进行分配。但是,在尝试回写
C
C\u buff
的缓冲区时,我仍然会遇到分段错误。您是否在数组的范围内写入?我的意思是,如果代码与_mm\u loadu一起工作_pd和_-mm\u-storeu\u-pd那么至少你知道问题出在哪里了。注意,在GCC/clang上有memalign,在VC++上有_-aligned\u-malloct。他们似乎用类似的方法工作,但同时释放了无用的片段,我无法在函数中这样做,因为我不知道如何告诉编译器要释放的新大小。你知道吗你可以打电话免费查询memalign和_aligned_malloc的结果。那很好。我会看的。谢谢。
ASSERT( ((size_t)(&C_buff[i+k*n]) & 0xF) == 0);
#include <stdio.h>
#include "emmintrin.h"

int main(){
int n = 15;
int y,x,k,i,j;

double * A;
posix_memalign((void**)&A, 16, n*n*sizeof(double));

double * B;
posix_memalign((void**)&B, 16, n*n*sizeof(double));

double * C;
posix_memalign((void**)&C, 16, n*n*sizeof(double));

for(y=0; y<n; y++)
  for(x=0; x<n; x++)
    A[x+y*n] = 0.1;

for(x=0; x<n; x++)
  for(y=0; y<n; y++)
    B[y+x*n] = 0.1;

for(x=0; x<n; x++)
  for( y=0; y<n; y++)
    C[y+x*n] = 0.1;

for( k=0; k<n; k++){
   i=0;
  for(; i+1<n; i+=2)
    {
      __m128d cik = _mm_load_pd(&C[i+k*n]);
       j = 0;
      for(; j+1<n; j+=2)
        {
          __m128d aTij = _mm_load_pd(&A[j+i*n]);
          __m128d bjk = _mm_load_pd(&B[j+k*n]);
          __m128d dotpr = _mm_add_pd(aTij, bjk);
          cik = _mm_add_pd(cik, dotpr);
        }
      _mm_store_pd(&C[i+k*n], cik);
    }
}
printf("C[15]: %f\n", C[15]);
printf("C[14]: %f\n", C[14]);