這個問題是在寫一些計算機圖形相關的代碼時發現的,簡化版的代碼如下圖所示:
#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 (experimental) [master r12-7719-g8ca61ad148f] - 作業系統:在 WSL2 上運行的 Ubuntu-22.04
uj5u.com熱心網友回復:
在檔案中途更改目標體系結構會導致您的問題。據推測,部分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.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/510556.html
標籤:C 调试克 矢量化avx
下一篇:由于精度問題而導致錯誤答案?
