ttz*_*ytt 3 c++ debugging g++ vectorization avx
这个问题是在编写一些与计算机图形学相关的代码时发现的,简化版的代码如下所示:
\n#include <bits/stdc++.h>\n\n#define __AVX__ 1\n#define __AVX2__ 1\n#pragma GCC target("avx,avx2,popcnt,tune=native")\n#include <immintrin.h>\n\nnamespace with_avx {\nclass vec {\n public:\n vec(double x = 0, double y = 0, double z = 0, double t = 0) {\n vec_data = _mm256_set_pd(t, z, y, x);\n }\n __m256d vec_data;\n};\n} // namespace with_avx\n\nnamespace without_avx {\nclass vec {\n public:\n vec(double x = 0, double y = 0, double z = 0, double t = 0) {\n vec_data[0] = x, vec_data[1] = y, vec_data[2] = z, vec_data[3] = t;\n }\n double vec_data[4];\n};\n} // namespace without_avx\n\n#ifdef USE_AVX\nusing namespace with_avx;\n#else\nusing namespace without_avx;\n#endif\n\nvec same(vec x) { return x; }\nstd::function<vec(vec)> stdfunc = same;\n\nint main() { \n vec rand_vec(rand(), rand(), rand());\n vec ret = stdfunc(rand_vec);\n std::cout<<(double)ret.vec_data[0];\n}\nRun Code Online (Sandbox Code Playgroud)\nUSE_AVX如果我使用如下标志编译代码:
g++-12 stdfunction_test.cpp -o ../build/unit_test -D USE_AVX -g\nRun Code Online (Sandbox Code Playgroud)\ng++ 将输出一些警告:
\nIn file included from /usr/include/c++/12/functional:59,\n from /usr/include/x86_64-linux-gnu/c++/12/bits/stdc++.h:71,\n from stdfunction_test.cpp:2:\n/usr/include/c++/12/bits/std_function.h: In member function \xe2\x80\x98_Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = with_avx::vec; _ArgTypes = {with_avx::vec}]\xe2\x80\x99:\n/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\n 587 | operator()(_ArgTypes... __args) const\n | ^~~~~~~~\nRun Code Online (Sandbox Code Playgroud)\n然后,如果我运行代码,有时会出现以下输出导致分段错误:
\n[1] 12710 segmentation fault ../build/unit_test\nRun Code Online (Sandbox Code Playgroud)\n有时,会抛出 bad_function_call 并输出以下内容:
\nterminate called after throwing an instance of \'std::bad_function_call\'\n what(): bad_function_call\n[1] 12678 IOT instruction ../build/unit_test\nRun Code Online (Sandbox Code Playgroud)\n执行此行时会出现这两个错误:
\n g++-12 stdfunction_test.cpp -o ../build/unit_test -D USE_AVX -g\nRun Code Online (Sandbox Code Playgroud)\n然后我使用 gdb 进行回溯:
\n(gdb) bt\n#0 0x00007ffff7e35521 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6\n#1 0x00007ffff7e2c6f4 in std::__throw_bad_function_call() () from /lib/x86_64-linux-gnu/libstdc++.so.6\n#2 0x000055555555558b in std::function<with_avx::vec (with_avx::vec)>::operator()(with_avx::vec) const (this=0x7fffffffda74,\n __args#0=...) at /usr/include/c++/12/bits/std_function.h:590\n#3 0x000055555555528d in main () at stdfunction_test.cpp:39\nRun Code Online (Sandbox Code Playgroud)\n但是,如果我不添加该标志,代码将正常运行。
\n我认为这可能是由某种对齐问题引起的,例如警告说我只是不知道如何解决这个问题。
\n我的环境如下,希望对你有用:
\ng++-12 (Ubuntu 12-20220319-1ubuntu1) 12.0.1 20220319 (experimental) [master r12-7719-g8ca61ad148f]在文件中更改目标架构会导致您的问题。据推测,部分std::function实现会随着目标架构的变化而变化。将您的编译指示移动到文件的开头可以解决问题:https ://godbolt.org/z/WP5ah38WP
一般来说,如果您通过编译器命令行设置架构目标(例如-mavx2),这将确保所有代码都使用相同的架构进行编译:https://godbolt.org/z/z5j79c5eh
或者更好,使用-march=haswell或-march=native还可以设置调整选项并启用相关 ISA 功能(例如 BMI1/2),因为诸如“为什么 gcc 不将 _mm256_loadu_pd 解析为单个 vmovupd?”之类的事情?
当 AVX 可用时,传递 a double __attribute__((vector_size(32)))(例如)的调用约定会发生变化。__m256d
正如您在 Godbolt 上看到的,没有 AVX,它通过隐藏指针(在 RDI 中)返回到返回值对象。假定 AVX 调用约定的调用者不会将 RDI 设置为有效指针,只需将其传递到 YMM0 中即可。(对于按值传递,在堆栈上与在 YMM0 中会导致错误数据,但不会直接导致段错误。)
成员std::function函数是在没有AVX 的情况下定义的,因为您在此之前包含了 C++ 标准头文件pragma。但您以后的代码将使用它与__m256d.
| 归档时间: |
|
| 查看次数: |
165 次 |
| 最近记录: |