1. 简介
indirect-call 对后端芯片来说,是一件非常伤害性能的行为,它让分支预测单元更难处理,它常出现在C++虚函数调用,GPU的subroutine. Compiler有一些算法就是想要减少indirect-call,具体可见参考文献1,AMD使用了下图第二种:Indirect Call Promotion.
2. 源码跟踪&学习
llc 命令:
llc.exe -mtriple=amdgcn G:\Mesa3D_ws\llvm-11.0.0.src\llvm-11.0.0.src\test\CodeGen\AMDGPU\promote-alloca-bitcast-function.ll
AMDGPUFixFunctionBitcasts
class AMDGPUFixFunctionBitcasts final
: public ModulePass,
public InstVisitor<AMDGPUFixFunctionBitcasts> {
bool runOnModule(Module &M) override;
bool Modified;
public:
void visitCallBase(CallBase &CB) {
if (CB.getCalledFunction())
return;
auto *Callee =
dyn_cast<Function>(CB.getCalledOperand()->stripPointerCasts());
if (Callee && isLegalToPromote(CB, Callee)) {
promoteCall(CB, Callee);
Modified = true;
}
}
static char ID;
AMDGPUFixFunctionBitcasts() : ModulePass(ID) {}
};
AMDGPUFixFunctionBitcasts::runOnModule
bool AMDGPUFixFunctionBitcasts::runOnModule(Module &M) {
Modified = false;
visit(M);
return Modified;
}
2.1 InstVisitor
当某个LLVM Pass想要对Module Unit 遍历,同时对不同类型的指令做不同的工作时,可以使用这个接口,只需要继承这个模板类,同时重载各指令类型接口即可,最后在runOnModule , 调用visit(M) . 它可以减少代码中大量的casts和if-else代码,同时它故意使用了C++模板技术,减少了虚函数调用开销,性能上会更好。
参考写法:
struct CountAllocaVisitor : public InstVisitor<CountAllocaVisitor> {
unsigned Count;
CountAllocaVisitor() : Count(0) {}
void visitAllocaInst(AllocaInst &AI) { ++Count; }
....
};
2.2 CallPromotionUtils
这个工具类定义了一些转换indirect-call的接口:
- isLegalToPromote : 返回值类型,参数个数,参数类型相同或者可bitcast即为合法
- promoteCall : 具体的处理逻辑
- promoteCallWithIfThenElse : 提升为条件Call
- tryPromoteCall :
3. 总结
- indirect-call
- InstVisitor 的使用,这个工具接口可以替换大量’For遍历式’代码的,主体非常干净整洁.
- CallPromotionUtils
4. 参考资料
- https://llvm.org/devmtg/2015-10/slides/Baev-IndirectCallPromotion.pdf
- https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.75.5105&rep=rep1&type=pdf