gpt4 book ai didi

c++ - 将 avx 变量传递给 std::function 时引发 bad_function_call 和段错误

转载 作者:行者123 更新时间:2023-12-05 01:22:32 31 4
gpt4 key购买 nike

这个问题是在写一些计算机图形相关的代码时发现的,简化版代码如下:

#include <bits/stdc++.h>

#define __AVX__ 1
#define __AVX2__ 1
#pragma GCC target("avx,avx2,popcnt,tune=native")
#include <immintrin.h>

namespace with_avx {
class vec {
public:
vec(double x = 0, double y = 0, double z = 0, double t = 0) {
vec_data = _mm256_set_pd(t, z, y, x);
}
__m256d vec_data;
};
} // namespace with_avx

namespace without_avx {
class vec {
public:
vec(double x = 0, double y = 0, double z = 0, double t = 0) {
vec_data[0] = x, vec_data[1] = y, vec_data[2] = z, vec_data[3] = t;
}
double vec_data[4];
};
} // namespace without_avx

#ifdef USE_AVX
using namespace with_avx;
#else
using namespace without_avx;
#endif

vec same(vec x) { return x; }
std::function<vec(vec)> stdfunc = same;

int main() {
vec rand_vec(rand(), rand(), rand());
vec ret = stdfunc(rand_vec);
std::cout<<(double)ret.vec_data[0];
}

如果我使用标志 USE_AVX 编译代码,如下所示:

 g++-12 stdfunction_test.cpp -o ../build/unit_test -D USE_AVX -g

g++ 会输出一些警告:

In file included from /usr/include/c++/12/functional:59,
from /usr/include/x86_64-linux-gnu/c++/12/bits/stdc++.h:71,
from stdfunction_test.cpp:2:
/usr/include/c++/12/bits/std_function.h: In member function ‘_Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = with_avx::vec; _ArgTypes = {with_avx::vec}]’:
/usr/include/c++/12/bits/std_function.h:587:7: note: the ABI for passing parameters with 32-byte alignment has changed in GCC 4.6
587 | operator()(_ArgTypes... __args) const
| ^~~~~~~~

然后,如果我运行代码,有时会导致以下输出导致段错误:

[1]    12710 segmentation fault  ../build/unit_test

有时,bad_function_call 会抛出以下输出:

terminate called after throwing an instance of 'std::bad_function_call'
what(): bad_function_call
[1] 12678 IOT instruction ../build/unit_test

这两个错误都是在执行这一行时出现的:

vec ret = stdfunc(rand_vec);

然后我使用 gdb 进行回溯:

(gdb) bt
#0 0x00007ffff7e35521 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00007ffff7e2c6f4 in std::__throw_bad_function_call() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x000055555555558b in std::function<with_avx::vec (with_avx::vec)>::operator()(with_avx::vec) const (this=0x7fffffffda74,
__args#0=...) at /usr/include/c++/12/bits/std_function.h:590
#3 0x000055555555528d in main () at stdfunction_test.cpp:39

但是,如果我不添加标志,代码将正常运行。

我认为这可能是由某种对齐问题引起的,比如警告说我只是不知道如何解决这个问题。

我的环境如下,希望对你有用:

  • g++ 版本:g++-12 (Ubuntu 12-20220319-1ubuntu1) 12.0.1 20220319(实验)[master r12-7719-g8ca61ad148f]
  • 操作系统:在 WSL2 上运行的 Ubuntu-22.04

最佳答案

在文件中途更改目标体系结构导致了您的问题。据推测,std::function 的部分实现会随着目标体系结构的变化而变化。将 pragma 移动到文件的开头可以解决问题:https://godbolt.org/z/WP5ah38WP

如果您通过编译器命令行(例如 -mavx2)设置架构目标,通常会更安全,这将确保您的所有代码都使用相同的架构编译:https://godbolt.org/z/z5j79c5eh
或者更好的是,使用 -march=haswell-march=native 也可以设置调整选项并启用相关的 ISA 功能,如 BMI1/2,因为 Why doesn't gcc resolve _mm256_loadu_pd as single vmovupd?


传递 double __attribute__((vector_size(32))) 的调用约定(例如 __m256d)在 AVX 可用时发生变化。

如你所见on Godbolt ,没有 AVX,它通过一个隐藏的指针(在 RDI 中)返回到返回值对象。假定 AVX 调用约定的调用者不会将 RDI 设置为有效指针,只需将其传递到 YMM0 中即可。 (对于按值传递,在堆栈上与在 YMM0 中会导致数据错误,但不会直接导致段错误。)

std::function 成员函数是在没有 AVX 的情况下定义的,因为您在 pragma 之前包含了 C++ 标准头文件。但是您以后的代码将与 __m256d 一起使用它。

关于c++ - 将 avx 变量传递给 std::function 时引发 bad_function_call 和段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73842421/

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