在 GCC 上设置打包的 long long 的正确对齐以与 avx2 指令一起使用
Posted
技术标签:
【中文标题】在 GCC 上设置打包的 long long 的正确对齐以与 avx2 指令一起使用【英文标题】:Setting proper alignment of packed long long on GCC to use use with avx2 instructions 【发布时间】:2019-08-10 10:34:42 【问题描述】:简介:
我正在编写一个函数来使用AVX2
指令处理x86_64
程序集中的4 个压缩long long int
。这是我的头文件的样子:
avx2.h
#define AVX2_ALIGNMENT 32
// Processes 4 packed long long int and
// returns a pointer to a result
long long * process(long long *);
process
函数的汇编实现如下:
avx2.S
:
global process
process:
vmovaps ymm0, [rdi]
;other instructions omitted
vmovaps ymm0, [rdi]
要求 rdi
是 32 字节对齐的。在汇编中它由align 32
指令控制。
问题:
当使用 GCC
编译时,它具有 __BIGGEST_ALIGNMENT__
定义,在我的实现中是 16。6.2.8/3
的 C18 标准声称
扩展对齐由大于的对齐表示
_Alignof (max_align_t)
。是否支持任何扩展对齐以及存储持续时间是由实现定义的 支持。
所以 GCC 上实现定义的扩展对齐也是 16,我不确定代码是否会导致 UB:
#include "avx2.h"
//AVX2_ALIGNMENT = 32, __BIGGEST_ALIGNMENT__ = 16
_Alignas(AVX2_ALIGNMENT) long long longs[] = 1, 32, 432, 433;
long long *result = process(longs);
有没有办法在没有 UB 的情况下重写代码? (我知道内在的immintrin.h
,这不是问题的主题)。
【问题讨论】:
您当然可以只使用vmovups
而不是vmovaps
并忘记对齐。
@PaulR 我刚刚检查了vmovaps
/vmovups
的延迟/TP/uops 并注意到它们在Skylake
上几乎相同(都具有 10c 延迟和 2uops)所以很可能vmovups
应该是可取的......不是吗?
如果您的数据恰好是 32 字节对齐的,那么性能应该没有明显差异。如果它没有对齐,那么由于相当微妙的缓存/内存问题,您可能会看到相对较小的性能差异,这在您的用例中可能很重要,也可能不重要,具体取决于代码对性能的关键程度,您的内存访问模式,以及在初始加载后您正在执行多少计算。
【参考方案1】:
您的代码已经没有 UB。任何体面的编译器都会在它不支持的 _Alignas()
上出错。
请注意,该标准表示此支持的存在/不存在是实现定义的。它没有在任何地方提到UB。 实现应该知道它支持什么,并在编译时检查它是否可以支持给定的_Alignas
。
我猜测一个糟糕的低质量实现会决定_Alignas()
的过高值是 UB。我还没有真正检查过。
可以编译此代码的实现 (gcc/clang/MSVC/ICC) 都至少支持 _Alignas(256)
用于自动和静态存储,AFAIK。 (我遗漏了可能仍然存在并且可能支持 AVX2 的 SunCC。我认为它也很好,但我没有查看它的 asm 输出)
可能几乎是任意大的,尤其是对于静态存储。
所有这些编译器都知道如何将堆栈过度对齐到 32 或 64,因此除了堆栈大小限制之外,没有理由不能将堆栈过度对齐。
可以安全地假设每个支持 Intel 内在函数的编译器也支持 _Alignas()
的扩展对齐,至少达到几个缓存行的大小。
(仅供参考,您可以#include <alignof.h>
,因此您可以像在 C++ 中一样使用alignas()
)。
警告:__m256
变量的 MinGW 堆栈对齐
最后我听说,MinGW 还是坏了。它知道如何为_Alignas(32)
对齐堆栈,但无法为__m256
/__m256i/d
变量这样做,可能会以未对齐的vmovaps
溢出/重新加载它们。
或者类似的东西。如果你关心 MinGW,最好看看这个。或者只在面向 Windows 时使用 clang。
【讨论】:
实现应该知道它支持什么,并在编译时检查它是否支持给定的 _Alignas。 我用我的gcc-7.4.0
和允许的最大对齐方式对其进行了测试运行良好的是8192 * 8192 * 4
。尝试设置_Alignas(8192 * 8192 * 8)
会导致error: requested alignment is too large
。
@St.Antario:哦,太好了,感谢您测试 gcc 至少按我预期的方式工作。以上是关于在 GCC 上设置打包的 long long 的正确对齐以与 avx2 指令一起使用的主要内容,如果未能解决你的问题,请参考以下文章
GCC 发出的那两个 long in vtable 汇编代码是啥? [复制]
Tar大量数据打包-bash: /bin/tar: Argument list too long
在 C 中给出 unsigned long long 变量值的警告