gpt4 book ai didi

c++ - GCC __attribute__ 在 32 字节处对齐的 AVX 向量化代码中的段错误

转载 作者:行者123 更新时间:2023-11-30 02:42:55 25 4
gpt4 key购买 nike

只有当循环在 AVX 机器(Intel(R) Core(TM) i5-3570K CPU @ 3.40GHz)上完全矢量化时,我才会在循环中遇到段错误。

使用 gcc -c -march=native MyClass.cpp -O3 -ftree-vectorizer-verbose=6 编译

我正在尝试对齐数组,以避免来自 -ftree-vectorizer-verbose=6 的这些消息:

MyClass.cpp:352: note: dependence distance modulo vf == 0 between this_7(D)->x[i_101] and this_7(D)->x[i_101]
MyClass.cpp:352: note: vect_model_load_cost: unaligned supported by hardware.
MyClass.cpp:352: note: vect_get_data_access_cost: inside_cost = 2, outside_cost = 0.
MyClass.cpp:352: note: vect_model_store_cost: unaligned supported by hardware.
MyClass.cpp:352: note: vect_get_data_access_cost: inside_cost = 2, outside_cost = 0.
MyClass.cpp:352: note: Alignment of access forced using peeling.
MyClass.cpp:352: note: vect_model_load_cost: aligned.
MyClass.cpp:352: note: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
MyClass.cpp:352: note: vect_model_simple_cost: inside_cost = 1, outside_cost = 1 .
MyClass.cpp:352: note: vect_model_store_cost: aligned.
MyClass.cpp:352: note: vect_model_store_cost: inside_cost = 1, outside_cost = 0 .
MyClass.cpp:352: note: cost model: prologue peel iters set to vf/2.
MyClass.cpp:352: note: cost model: epilogue peel iters set to vf/2 because peeling for alignment is unknown .

我想看到(也确实看到了)的是:

MyClass.cpp:352: note: dependence distance modulo vf == 0 between this_7(D)->x[i_101] and this_7(D)->x[i_101]
MyClass.cpp:352: note: vect_model_load_cost: aligned.
MyClass.cpp:352: note: vect_get_data_access_cost: inside_cost = 1, outside_cost = 0.
MyClass.cpp:352: note: vect_model_store_cost: aligned.
MyClass.cpp:352: note: vect_get_data_access_cost: inside_cost = 2, outside_cost = 0.
MyClass.cpp:352: note: vect_model_load_cost: aligned.
MyClass.cpp:352: note: vect_model_load_cost: inside_cost = 1, outside_cost = 0 .
MyClass.cpp:352: note: vect_model_simple_cost: inside_cost = 1, outside_cost = 1 .
MyClass.cpp:352: note: vect_model_store_cost: aligned.
MyClass.cpp:352: note: vect_model_store_cost: inside_cost = 1, outside_cost = 0 .

现在,我无论如何都不是 C/C++/汇编大师,但是当我遇到段错误时,我假设我的代码中有一些指针/数组/其他错误,并且完全矢量化的循环只是暴露了这个.但是在学习了两天的汇编程序之后,我无法找到它。所以我在这里。

代码看起来像这样(希望我包括了所有相关的东西——我不能在这里完整地分享实际的 .cpp):

class MyClass {

private:
static const long maxElems = 1024;
static const double otherVar = 0.9;
double x[maxElems] __attribute__ ((aligned (32))); <-- gcc reports fully vectorized
//double x[maxElems]; <-- leads to unaligned peeling

public:
void myFunc() {
// Always works
for (int i=0; i<maxElems; ++i) printf("Test: %d %.4e\n", i, x[i]);

// Seg fault if fully vectorized (no peeling)
for (int i=0; i<maxElems; ++i) {
x[i] = x[i] - 42;
}

// Works if no seg fault earlier
for (int i=0; i<maxElems; ++i) printf("Test: %d %.4e\n", i, x[i]);
}
}

当它完全矢量化时,我看到(使用 -Wa,-alh 标志来查看汇编程序):

 989      00
990 0b56 488B4424 movq 40(%rsp), %rax
990 28
991 0b5b C5FD280D vmovapd .LC8(%rip), %ymm1
991 00000000
992 .p2align 4,,10
993 0b63 0F1F4400 .p2align 3
993 00
994 .L153:
995 0b68 C5FD2800 vmovapd (%rax), %ymm0
996 0b6c C5FD5CC1 vsubpd %ymm1, %ymm0, %ymm0
997 0b70 C5FD2900 vmovapd %ymm0, (%rax)
998 0b74 4883C020 addq $32, %rax
999 0b78 4C39E0 cmpq %r12, %rax
1000 0b7b 75EB jne .L153

同样,关于“不了解汇编器”的常见警告,但我确实花了相当多的时间打印指针和检查汇编器以说服自己这个循环在数组的开始和结束处开始和结束。但是当我遇到段错误时,x 的起始地址不能被 32 整除。我认为这就是造成麻烦的原因。

是的,我知道我可以在堆上分配 x 并选择它最终对齐的位置。但是我在这里的部分实验是让 MyClass 的所有数据都固定大小(想想:缓存效率),所以我在堆上分配了 MyClass 的实例,在集合中指向它们的指针,并且 x 在 MyClass 内部.

align attribute 不是应该将 x 放在 32 字节边界上吗?编译器假设,然后 vmovapd 爆炸了,因为它不是,对吧?

关于对齐的 GCC 文档:https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html

我是否必须以某种方式在堆上对齐 MyClass?我怎么做?我如何告诉 GCC 我这样做了,以便它像我想要的那样矢量化?

编辑:我已经解决了这个问题(部分归功于下面的评论和答案)。通过覆盖默认的 new 运算符,可以保证在堆上创建对象时对齐。当我这样做时,我没有遇到任何段错误,而且我的代码仍然按照我的意愿完美矢量化。我是怎么做到的:

static void* operator new(size_t size) throw (std::bad_alloc) {
void *alignedPointer;
int alignError = 0;

// Try to allocate the required amount of memory (using POSIX standard aligned allocation)
alignError = posix_memalign(&alignedPointer, VECTOR_ALIGN_BYTES, size);

// Throw/Report error if any
if (alignError) {
throw std::bad_alloc();
}

// Return a pointer to this aligned memory location
return alignedPointer;
}

static void operator delete(void* alignedPointer) {
// POSIX aligned memory allocation can be freed normally with free()
free(alignedPointer);
}

C++ 会在调用运算符之后/之前为您调用构造函数/析构函数。因此,对齐由类本身控制。如果您有不同的偏好,也可以使用其他对齐的内存分配器。我用的是 POSIX。

两个注意事项:如果有人用任意地址调用 placement new,您仍然不会对齐。如果有人将您的类声明为他们类的成员,并且他们的类分配在堆上,则您可能未对齐。我已经检查了我的构造函数,如果检测到它会抛出错误。

最佳答案

__attribute__((aligned(32))

可能不会像我们认为的那样(错误?功能?)。

它基本上告诉编译器它可以假设这个东西是对齐的,但它可能不是。如果它在堆上,则需要使用 posix_memalign 或类似方法进行分配。

如果设置了 __attribute__((aligned(...)) 但分配未对齐,GCC 实际上会得到指针算术错误。

s2->aligned_var = 0x199c030
&s2->aligned_var % 0x40 = 0x0

https://gcc.gnu.org/ml/gcc/2014-06/msg00308.html

关于c++ - GCC __attribute__ 在 32 字节处对齐的 AVX 向量化代码中的段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26620862/

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