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 arrays,src
至少在 2 字节字上对齐,但可能不会在 16 字节地址上对齐。
因此,即使 line1
声明为对齐指针,for 循环第一行的赋值也可能会破坏此约束。
考虑在 src
的声明中添加 __attribute__ ((aligned(8)))
(在 main()
内)。
编辑
在我的评论之后要清楚:PaulR 在他的回答中指出了一个最初的根本原因,类型 __m128
的大小为 8 个短整型,而不是 16 个。另一个失败的根本原因是索引 i
有问题。通过编写 line1 = src+i*N
和 i+=N
,src
的偏移量实际上在每次迭代中增加 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 );
当 运行 编译以下简短的 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 arrays,src
至少在 2 字节字上对齐,但可能不会在 16 字节地址上对齐。
因此,即使 line1
声明为对齐指针,for 循环第一行的赋值也可能会破坏此约束。
考虑在 src
的声明中添加 __attribute__ ((aligned(8)))
(在 main()
内)。
编辑
在我的评论之后要清楚:PaulR 在他的回答中指出了一个最初的根本原因,类型 __m128
的大小为 8 个短整型,而不是 16 个。另一个失败的根本原因是索引 i
有问题。通过编写 line1 = src+i*N
和 i+=N
,src
的偏移量实际上在每次迭代中增加 N*N
。
所以你有两个独家解决方案:
- 改变索引的增量
i
和索引的结束限制:for(i = 0; i < len/N; i++)
;其余保持原样。 - 或更改偏移量,both for
src
anddst
:line1 = src + i;
,和_mm_storeu_si128((__m128i*) (dst + i), v3 );