在 GCC 上设置 packed long long 的正确对齐以与 avx2 指令一起使用

Setting proper alignment of packed long long on GCC to use use with avx2 instructions

简介:

我正在编写一个函数来使用 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 标准声称

An extended alignment is represented by an alignment greater than _Alignof (max_align_t). It is implementation-defined whether any extended alignments are supported and the storage durations for which they are supported.

所以 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重写代码的方法? (我知道 intrinsic immintrin.h,这不是问题的主题)。

您的代码已经没有 UB。任何体面的编译器都会在它不支持的 _Alignas() 上出错。

请注意,标准表示此支持的 presence/absence 是 实现定义的 。它没有在任何地方提到 UB。 一个实现应该知道它支持什么,并在编译时检查它是否可以支持给定的 _Alignas

我可以 猜测 认为 _Alignas() 的过高值是 UB,这是一个糟糕的低质量实施。我还没有真正检查过。


可以编译此代码的实现 (gcc/clang/MSVC/ICC) 都至少支持 _Alignas(256) 自动和静态存储,AFAIK。 (我遗漏了可能仍然存在并且可能支持 AVX2 的 SunCC。我认为它也很好,但我没有看过它的 asm 输出) 可能几乎是任意大,特别是对于静态存储。

所有这些编译器肯定都知道如何将堆栈过度对齐到 32 或 64,因此除了堆栈大小限制之外,他们没有理由不能将其调整到任意大。

可以安全地假设每个支持英特尔内部函数的编译器也支持 _Alignas() 的扩展对齐,至少达到几个缓存行的大小。

(仅供参考,您可以 #include <alignof.h> 因此您可以像在 C++ 中一样使用 alignas()


警告:__m256 变量的 MinGW 堆栈对齐

最后我听说,MinGW 还是坏了。它知道如何为 _Alignas(32) 对齐堆栈,但无法为 __m256/__m256i/d 变量对齐,可能 spilling/reloading 它们未对齐 vmovaps.

或者类似这样的东西。如果您关心 MinGW,最好研究一下。或者在定位 Windows.

时只使用 clang