C 中 __m128 的分段错误

Segmentation fault with __m128 in C

当 运行 编译以下简短的 C 代码时出现分段错误:

#include <pmmintrin.h>
#include <stdio.h>
#include <stdlib.h>
#define VALUE 4242

typedef short int Type;
void threshold(Type *dst, const Type *src, int len)
{
  short int i, N=16;
  short int checkval[] = { VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE };

  const short int* __attribute__ ((aligned (16))) line1;

  __m128i v1, v2, v3:
  v2 = _mm_loadu_si128((__m128i*) checkval );

  for(i = 0; i < len; i+=N)
    {
      line1 = src + N*i;
      //Thisline                                                                                                                                     
      v1 = _mm_loadu_si128((__m128i*) line1 );
      v3 = _mm_cmpgt_epi16( v1, v2 );

      _mm_storeu_si128((__m128i*) (dst + N*i), v3 );

    }
  return;
}

int main()
{
  int N = 1024;
  Type dst[N], src[N];
  int i;
  for(i = 0; i < N; i++)
    src[i] = rand()%VALUE;

  threshold(dst, src, N);
  return 0;
}

我很确定 "This line" 之后的那条线给我带来了问题,但我无法判断问题是由于 line1 不适合 __m128i 还是其他一些错误引起的。

作为一个子问题-我试图对齐第 1 行中的元素,功能 _mm_load_si128 会更合适(我都试过了,但我无法避免错误)。

threshold

short int i, N=16;

应该是:

short int i, N=8;

这是因为每个向量有 8 x short int 个元素,而指针算法考虑了元素的大小(我猜你假设你需要使用 16 个字节作为大小向量 ?).

在评论对齐之前,请考虑 houssam 的评论和 ,腐败肯定来自这里。

现在,src 可能不是 16 字节对齐的。参考这个 post about alignment on static arrayssrc 至少在 2 字节字上对齐,但可能不会在 16 字节地址上对齐。

因此,即使 line1 声明为对齐指针,for 循环第一行的赋值也可能会破坏此约束。

考虑在 src 的声明中添加 __attribute__ ((aligned(8)))(在 main() 内)。

编辑

在我的评论之后要清楚:PaulR 在他的回答中指出了一个最初的根本原因,类型 __m128 的大小为 8 个短整型,而不是 16 个。另一个失败的根本原因是索引 i 有问题。通过编写 line1 = src+i*Ni+=Nsrc 的偏移量实际上在每次迭代中增加 N*N

所以你有两个独家解决方案:

  • 改变索引的增量i索引的结束限制:for(i = 0; i < len/N; i++);其余保持原样。
  • 或更改偏移量,both for src and dst: line1 = src + i;,和 _mm_storeu_si128((__m128i*) (dst + i), v3 );