我正在对科学应用进行一些数值优化.我注意到的一件事是GCC会pow(a,2)通过编译来优化调用a*a,但调用pow(a,6)没有优化,实际上会调用库函数pow,这会大大降低性能.(相比之下,英特尔C++编译器,可执行文件icc,将消除库调用pow(a,6).)
我很好奇的是,当我更换pow(a,6)与a*a*a*a*a*a使用GCC 4.5.1和选项" -O3 -lm -funroll-loops -msse4",它采用5分mulsd的说明:
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
Run Code Online (Sandbox Code Playgroud)
如果我写(a*a*a)*(a*a*a),它会产生
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm13, %xmm13
Run Code Online (Sandbox Code Playgroud)
这将乘法指令的数量减少到3. icc具有类似的行为.
为什么编译器不能识别这种优化技巧?
我有一个小测试程序,它使用llvm来计算某些方程式的值.设置如下:我创建了一个包含添加,乘法,除法,减法和平方双数的函数的bc文件.现在我通过组合加法和乘法函数来设置具有不同参数的线性方程.然后我使用万花筒示例中的优化器转换函数.这很好用 - 结果函数将x作为参数,只进行2次浮点计算(乘法和加法).设置这些功能的代码是:
Function* createLinearFunction(const std::string& name, double factor, double summand, Module* module)
{
LLVMContext& context = getGlobalContext();
Function* func = cast<Function>(module->getOrInsertFunction(name.c_str(),Type::getDoubleTy(context),Type::getDoubleTy(context),(Type *)0));
//add basic block
BasicBlock* bb1 = BasicBlock::Create(context,"EntryBlock",func);
IRBuilder<> builder(bb1);
Argument* x0 = func->arg_begin();
x0->setName("x0");
Value* x1 = ConstantFP::get(context,APFloat(factor));
Value* x2 = ConstantFP::get(context,APFloat(summand));
std::vector<Value*> args1;
args1.push_back(x0);
args1.push_back(x1);
Value* x3 = builder.CreateCall(mul_d_dd,args1,"");
std::vector<Value*> args2;
args2.push_back(x2);
args2.push_back(x3);
Value* x4 = builder.CreateCall(add_d_dd,args2,"");
builder.CreateRet(x4);
return func;
}
Run Code Online (Sandbox Code Playgroud)
我现在想要的是以下内容 - 当我生成一个因子1的函数时,它应该优化乘法,并且使用summand 0它应该优化加法.使用因子0,它应该只返回summand.有通行证已经做到了吗?我只是假设llvm没有这样做,因为这里提到的原因:为什么LLVM不通过优化浮点指令?
谢谢你的帮助Tobias
添加 - 我尝试添加instcombine via createInstructionCombiningPass(),但优化的代码看起来仍然相同:
define double @Linear0xPlus0(double …Run Code Online (Sandbox Code Playgroud)