gpt4 book ai didi

gcc - 使用 AVX/AVX2 内在函数进行对齐和未对齐的内存访问

转载 作者:行者123 更新时间:2023-12-04 01:08:11 28 4
gpt4 key购买 nike

根据英特尔的软件开发人员手册(第 14.9 节),AVX 放宽了内存访问的对齐要求。如果直接在处理指令中加载数据,例如

vaddps ymm0,ymm0,YMMWORD PTR [rax]

加载地址不必对齐。但是,如果使用专用的对齐加载指令,例如
vmovaps ymm0,YMMWORD PTR [rax]

加载地址必须对齐(为 32 的倍数),否则会引发异常。

让我困惑的是从内部函数自动生成代码,在我的例子中是 gcc/g++(4.6.3,Linux)。请看下面的测试代码:
#include <x86intrin.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define SIZE (1L << 26)
#define OFFSET 1

int main() {
float *data;
assert(!posix_memalign((void**)&data, 32, SIZE*sizeof(float)));
for (unsigned i = 0; i < SIZE; i++) data[i] = drand48();
float res[8] __attribute__ ((aligned(32)));
__m256 sum = _mm256_setzero_ps(), elem;
for (float *d = data + OFFSET; d < data + SIZE - 8; d += 8) {
elem = _mm256_load_ps(d);
// sum = _mm256_add_ps(elem, elem);
sum = _mm256_add_ps(sum, elem);
}
_mm256_store_ps(res, sum);
for (int i = 0; i < 8; i++) printf("%g ", res[i]); printf("\n");
return 0;
}

(是的,我知道代码有问题,因为我在未对齐的地址上使用了对齐加载,但请耐心等待......)

我编译代码
g++ -Wall -O3 -march=native -o memtest memtest.C

在带有 AVX 的 CPU 上。如果我通过使用检查由 g++ 生成的代码
objdump -S -M intel-mnemonic memtest | more

我看到编译器并没有生成对齐的加载指令,而是直接在向量加法指令中加载数据:
vaddps ymm0,ymm0,YMMWORD PTR [rax]

即使内存地址未对齐(OFFSET 为 1),代码执行也没有任何问题。这很明显,因为 vaddps 容忍未对齐的地址。

如果我取消注释第二个加法内在的行,编译器无法融合负载和加法,因为 vaddps 只能有一个内存源操作数,并生成:
vmovaps ymm0,YMMWORD PTR [rax]
vaddps ymm1,ymm0,ymm0
vaddps ymm0,ymm1,ymm0

现在程序出现段错误,因为使用了专用的对齐加载指令,但内存地址未对齐。 (顺便说一下,如果我使用 _mm256_loadu_ps,或者如果我将 OFFSET 设置为 0,该程序不会出现段错误。)

在我看来,这让程序员受编译器的支配,并使行为部分不可预测。

我的问题是:有没有办法强制 C 编译器在处理指令(例如 vaddps)中生成直接加载或生成专用加载指令(例如 vmovaps)?

最佳答案

无法使用内在函数显式控制负载的折叠。我认为这是内在的弱点。如果要显式控制折叠,则必须使用程序集。

在以前版本的 GCC 中,我能够使用对齐或未对齐的负载在一定程度上控制折叠。但是,情况似乎不再如此(GCC 4.9.2)。我的意思是例如在函数 AddDot4x4_vec_block_8widehere cargo 被折叠

vmulps  ymm9, ymm0, YMMWORD PTR [rax-256]
vaddps ymm8, ymm9, ymm8

然而 in a previous verison of GCC cargo 没有折叠:
vmovups ymm9, YMMWORD PTR [rax-256]
vmulps ymm9, ymm0, ymm9
vaddps ymm8, ymm8, ymm9

显然,正确的解决方案是,仅当您知道数据已对齐并且您确实想明确控制折叠使用程序集时才使用对齐的加载。

关于gcc - 使用 AVX/AVX2 内在函数进行对齐和未对齐的内存访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31089502/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com