Basic
这是一个analysis pass, 在程序的编译器静态分析每个函数的调用次数。
与之前一样,为了输出 analysis pass 的结果, 我们需要一个专门输出结果的 printing pass。
由于 printing pass 和 pass manger 注册和之前类似, 本文不再描述。
struct StaticCallCounter : public llvm::AnalysisInfoMixin<StaticCallCounter>
因为要统计各个函数之间的相互调用, 这次选用了 moudle 粒度的 pass
runOnModule
主要逻辑是一步步地从 Module 遍历到每一条指令, 再检查每条指令是否是函数调用,统计函数调用的信息。
在判断一个指令是否是 call 指令时, 使用了动态分派的技巧。
如果分派后的结果为 nullptr 则说明该指令不是 call 类指令。
StaticCallCounter::Result StaticCallCounter::runOnModule(llvm::Module &M) {
llvm::MapVector<const llvm::Function *, unsigned> Res;
for (auto &Func : M) {
for (auto &BB : Func) {
for (auto &Ins : BB) {
auto *CB = dyn_cast<CallBase>(&Ins);
if (nullptr == CB) {
continue;
}
auto DirectInvoc = CB->getCalledFunction();
if (nullptr == DirectInvoc) {
continue;
}
auto CallCount = Res.find(DirectInvoc);
if (Res.end() == CallCount) {
CallCount = Res.insert(std::make_pair(DirectInvoc, 0)).first;
}
++CallCount->second;
}
}
}
return Res;
}
总结
一个 analysis pass (假设名为 foo)
- 要继承 AnalysisInfoMixin<foo>。
- 它的分析结果的类型总是 foo::Result。
- 它的分析方法的入口函数总是 run
- run 的第一个参数是对应粒度的 IR, 第二个参数是对应粒度的 analysis manger。
- 总有一个类型为 llvm::AnalysisKey 的私有变量 Key 用于 analysis manger 对 analysis 的定位和管理