我使用两台电脑,一台支持 AVX,另一台不支持。希望我的代码能够在运行时查找 CPU 支持的指令集,并选择合适的代码路径,这样会很方便。
我已经按照 Agner Fog 的建议编写了一个 CPU dispatcher (http://www.agner.org/optimize/#vectorclass)。但是,在不支持 AVX 的机器上,使用 Visual Studio 编译和链接启用了 AVX 的代码时,运行后会导致代码崩溃。
举个例子,我有两个源文件,一个定义了 SSE2 指令集并包含一些 SSE2 指令,另一个定义了 AVX 指令集并包含一些 AVX 指令。在我的主函数中,如果我只引用 SSE2 函数,则代码仍然会崩溃,因为其中任何源代码启用了 AVX 并包含 AVX 指令。您有什么解决方法吗?
编辑: 好的,我想我找到了问题所在。我正在使用 Agner Fog 的向量类,并将其定义为三个源文件:
我已经按照 Agner Fog 的建议编写了一个 CPU dispatcher (http://www.agner.org/optimize/#vectorclass)。但是,在不支持 AVX 的机器上,使用 Visual Studio 编译和链接启用了 AVX 的代码时,运行后会导致代码崩溃。
举个例子,我有两个源文件,一个定义了 SSE2 指令集并包含一些 SSE2 指令,另一个定义了 AVX 指令集并包含一些 AVX 指令。在我的主函数中,如果我只引用 SSE2 函数,则代码仍然会崩溃,因为其中任何源代码启用了 AVX 并包含 AVX 指令。您有什么解决方法吗?
编辑: 好的,我想我找到了问题所在。我正在使用 Agner Fog 的向量类,并将其定义为三个源文件:
//file sse2.cpp - compiled with /arch:SSE2
#include "vectorclass.h"
float func_sse2(const float* a) {
Vec8f v1 = Vec8f().load(a);
float sum = horizontal_add(v1);
return sum;
}
//file avx.cpp - compiled with /arch:AVX
#include "vectorclass.h"
float func_avx(const float* a) {
Vec8f v1 = Vec8f().load(a);
float sum = horizontal_add(v1);
return sum;
}
//file foo.cpp - compiled with /arch:SSE2
#include <stdio.h>
extern float func_sse2(const float* a);
extern float func_avx(const float* a);
int main() {
float (*fp)(const float*a);
float a[] = {1,2,3,4,5,6,7,8};
int iset = 6;
if(iset>=7) {
fp = func_avx;
}
else {
fp = func_sse2;
}
float sum = (*fp)(a);
printf("sum %f\n", sum);
}
这段代码会崩溃。但如果我在func_SSE2中使用Vec4f,则不会崩溃。 我不理解这个问题。只要没有另一个AVX源文件,我就可以单独使用Vec8f和SSE2。Agner Fog的手册说:
“除非指定了AVX指令集,否则使用256位浮点向量类(Vec8f、Vec4d)没有优势,但是如果同一源代码在有或没有AVX的情况下使用,则使用这些类可能很方便。在编译时,每个256位向量将被拆分为两个128位向量。”
但是,当我有两个源文件都含有Vec8f,其中一个使用SSE2编译,另一个使用AVX编译时,程序会崩溃。
编辑2:我可以从命令行中让它工作。
>cl -c sse2.cpp
>cl -c /arch:AVX avx.cpp
>cl foo.cpp sse2.obj avx.obj
>foo.exe
编辑3: 然而,这会导致崩溃。
>cl -c sse2.cpp
>cl -c /arch:AVX avx.cpp
>cl foo.cpp avx.obj sse2.obj
>foo.exe
另一个线索是,链接的顺序很重要。如果avx.obj在sse2.obj之前,则会崩溃,但如果sse2.obj在avx.obj之前,则不会崩溃。我不确定它是否选择了正确的代码路径(我现在无法访问我的AVX系统),但至少它不会崩溃。