在 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
简介:
我正在编写一个函数来使用 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