__int128 gcc -O SSE 优化对齐段错误
__int128 alignment segment fault with gcc -O SSE optimize
我使用 __int128
作为结构的成员。
它适用于 -O0
(无优化)。
但是,如果启用优化 (-O1
),它会因段错误而崩溃。
它在指令 movdqa
处崩溃,该指令需要 var 对齐 16。
地址由 malloc()
分配,仅按 8.
对齐
我试图通过 -mno-sse
禁用 SSE 优化,但编译失败:
/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:27:1: error: SSE register return with SSE disabled
如果我想同时使用 __int128
和 -O1
怎么办?
提前致谢
吴
顺便说一句,如果 __int128
仅用于堆栈(而不是堆)似乎没问题。
==== 编辑 ====
对不起,我没有说实话。
其实我没有用malloc()
。我使用了一个 returns 地址按 8 对齐的内存池库。
我说malloc()
只是想简单点。
经过测试,我知道 malloc()
是按 16 对齐的。而且 __int128
成员在 struct 中也是按 16 对齐的。
所以问题只是我的内存池库。
非常感谢。
对于 x86-64 System V,alignof(max_align_t) == 16
所以 malloc
总是 returns 16 字节对齐的指针。听起来你的分配器坏了,如果也用于 long double
也会违反 ABI。 (将此作为答案重新发布,因为事实证明 是 答案)。
malloc
返回的内存保证能够容纳任何标准类型,这意味着如果大小足够大,则足够对齐。
这不能是 32 位代码,因为 gcc 在 32 位目标中不支持 __int128
。 (我认为 32 位 glibc malloc
仅保证 8 字节对齐。实际上在当前系统上,alignof(max_align_t) == 16
在 32 位模式下也是如此。)
一般来说,如果您违反了类型的对齐要求,编译器允许生成错误的代码。在 x86 上,事情通常只适用于未对齐的内存,直到编译器使用需要对齐的 SIMD 指令。即使 uint16_t*
未对齐的自动矢量化也会出错 (),所以不要假设窄类型总是安全的。如果需要在 C 中表达未对齐的负载,请使用 memcpy
。
显然 alignof(__int128)
是 16。所以他们没有重复 i386 System V 中的怪异之处,即使是 8 字节的对象也只能保证 4 字节对齐,而结构打包规则意味着编译器不能'不要总是让他们自然对齐。
这是一件好事,因为它使使用 SSE 进行复制变得高效,并且意味着 _Atomic __int128
不需要任何额外的特殊处理来避免缓存行拆分,这会使 lock cmpxchg16b
很慢。
我使用 __int128
作为结构的成员。
它适用于 -O0
(无优化)。
但是,如果启用优化 (-O1
),它会因段错误而崩溃。
它在指令 movdqa
处崩溃,该指令需要 var 对齐 16。
地址由 malloc()
分配,仅按 8.
我试图通过 -mno-sse
禁用 SSE 优化,但编译失败:
/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:27:1: error: SSE register return with SSE disabled
如果我想同时使用 __int128
和 -O1
怎么办?
提前致谢 吴
顺便说一句,如果 __int128
仅用于堆栈(而不是堆)似乎没问题。
==== 编辑 ====
对不起,我没有说实话。
其实我没有用malloc()
。我使用了一个 returns 地址按 8 对齐的内存池库。
我说malloc()
只是想简单点。
经过测试,我知道 malloc()
是按 16 对齐的。而且 __int128
成员在 struct 中也是按 16 对齐的。
所以问题只是我的内存池库。
非常感谢。
对于 x86-64 System V,alignof(max_align_t) == 16
所以 malloc
总是 returns 16 字节对齐的指针。听起来你的分配器坏了,如果也用于 long double
也会违反 ABI。 (将此作为答案重新发布,因为事实证明 是 答案)。
malloc
返回的内存保证能够容纳任何标准类型,这意味着如果大小足够大,则足够对齐。
这不能是 32 位代码,因为 gcc 在 32 位目标中不支持 __int128
。 (我认为 32 位 glibc malloc
仅保证 8 字节对齐。实际上在当前系统上,alignof(max_align_t) == 16
在 32 位模式下也是如此。)
一般来说,如果您违反了类型的对齐要求,编译器允许生成错误的代码。在 x86 上,事情通常只适用于未对齐的内存,直到编译器使用需要对齐的 SIMD 指令。即使 uint16_t*
未对齐的自动矢量化也会出错 (memcpy
。
显然 alignof(__int128)
是 16。所以他们没有重复 i386 System V 中的怪异之处,即使是 8 字节的对象也只能保证 4 字节对齐,而结构打包规则意味着编译器不能'不要总是让他们自然对齐。
这是一件好事,因为它使使用 SSE 进行复制变得高效,并且意味着 _Atomic __int128
不需要任何额外的特殊处理来避免缓存行拆分,这会使 lock cmpxchg16b
很慢。