【发布时间】:2015-06-05 11:35:21
【问题描述】:
我找到了a question somewhat interesting,并试图回答它。作者想用 AVX 优化编译-one-source 文件(依赖于模板库),而项目的其余部分没有这些。
所以,为了看看会发生什么,我创建了一个这样的测试项目:
main.cpp
#include <iostream>
#include <string>
#include "fn_normal.h"
#include "fn_avx.h"
int main(int argc, char* argv[])
{
int number = 10; // this will come from input, but let's keep it simple for now
int result;
if (std::string(argv[argc - 1]) == "--noavx")
result = FnNormal(number);
else
{
std::cout << "AVX selected\n";
result = FnAVX(number);
}
std::cout << "Double of " << number << " is " << result << std::endl;
return 0;
}
文件fn_normal.h和fn_avx.h分别包含函数FnNormal()和FnAVX()的声明,定义如下:
fn_normal.cpp
#include "fn_normal.h"
#include "double.h"
int FnNormal(int num)
{
return RtDouble(num);
}
fn_avx.cpp
#include "fn_avx.h"
#include "double.h"
int FnAVX(int num)
{
return RtDouble(num);
}
这是模板函数定义:
double.h
template<typename T>
int RtDouble(T number)
{
// Side effect: generates avx instructions
const int N = 1000;
float a[N], b[N];
for (int n = 0; n < N; ++n)
{
a[n] = b[n] * b[n] * b[n];
}
return number * 2;
}
最终,我将“Properties-> C/C++ -> Code Generation”下的文件 fn_avx.cpp 的 Enhanced Instruction Set 设置为 AVX,将其他源设置为 Not Set,因此它应该默认为 SSE2。
我认为这样做,编译器将为包含它的每个源实例化一次模板(并通过修改模板函数名称或其他方式避免违反单一定义规则),从而调用程序--noavx 参数将使其在没有 avx 支持的 cpus 中运行良好。
但是生成的程序实际上只有一个机器代码版本的函数,带有 avx 指令,并且在旧 CPU 上会失败。
禁用所有其他优化并不能解决此问题。还尝试了No Enhanced Instructions - /arch:IA32 而不是Not Set。
由于我刚刚开始了解模板等,有人可以指出我这种行为的确切细节以及我实际上可以做些什么来实现我的目标?
我的编译器是 MSVC 2013。
附加信息: fn_normal.cpp 和 fn_avx.cpp 的 .obj 文件的字节大小几乎相同.我查看了生成的程序集列表,它们几乎相同,重要的区别是启用 avx 的源将默认 sse 的 movss/mulss 分别替换为 vmovss 和 vmulss。但是在 Visual Studio 的反汇编视图中单步执行代码 (Ctrl+Alt+D),确认 fnNormal() 确实使用了 avx 专门的指令。
【问题讨论】:
-
您确定“增强指令集为'AVX'”设置会影响名称修改吗?听起来好像没有,并且模板名称的修改在两个翻译单元中是相同的;因此,模板的定义之一被丢弃为重复项。
-
template<int option> int RtDouble(double number)您将调用为RtDouble<0>(number)和RtDouble<1>(number)应该生成单独的函数。 -
我不认为“未设置”意味着“没有增强的指令集”。
-
@SamVarshavchik 确实是这样。我添加了新的细节,请看一下。
标签: c++ templates visual-c++ compiler-optimization