LLVM新手编写Pass遇问题:循环内函数调用被重复打印
解决LLVM Pass中循环内函数调用重复打印的问题
嘿,作为刚踩过LLVM Pass各种坑的过来人,我太懂你这种函数调用被重复打印的烦恼了!结合你给出的代码片段来看,这个问题大概率是循环嵌套导致的BasicBlock重复遍历——LLVM里父循环的getBlocks()会包含所有子循环的BasicBlock,当你递归处理父循环和子循环时,同一个函数调用所在的块会被遍历两次,自然就打印两次了。
下面给你两个实用的解决思路,直接就能套进你的代码里:
思路1:标记已处理的BasicBlock
用一个集合记录已经检查过的块,每次处理循环时跳过已标记的块,从根源上避免重复遍历。
修改你的BlocksInLoop函数,加上LLVM自带的高效集合DenseSet作为参数:
#include "llvm/ADT/DenseSet.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Instructions.h" void BlocksInLoop(Loop *L, unsigned nlvl, DenseSet<BasicBlock*> &ProcessedBlocks) { errs() << "Loop level " << nlvl << " {\n"; BasicBlock* h = L->getHeader(); // 遍历当前循环的所有BasicBlock for (auto *BB : L->getBlocks()) { // 如果块已经被处理过,直接跳过 if (ProcessedBlocks.count(BB)) continue; ProcessedBlocks.insert(BB); // 检查当前块中的函数调用 for (auto &Inst : *BB) { if (auto *Call = dyn_cast<CallBase>(&Inst)) { errs() << "Found function call: " << Call->getCalledFunction()->getName() << " in loop level " << nlvl << "\n"; } } } // 递归处理子循环 for (auto *SubLoop : L->getSubLoops()) { BlocksInLoop(SubLoop, nlvl + 1, ProcessedBlocks); } errs() << "}\n"; }
然后在Pass的runOnFunction方法里初始化这个集合:
bool runOnFunction(Function &F) override { LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); DenseSet<BasicBlock*> ProcessedBlocks; for (auto *L : LI) { BlocksInLoop(L, 1, ProcessedBlocks); } return false; }
思路2:只处理循环独有的BasicBlock
如果你更关心函数调用所在的最内层循环,可以让父循环跳过属于子循环的块,把这些块交给子循环去处理。
修改后的BlocksInLoop函数:
void BlocksInLoop(Loop *L, unsigned nlvl) { errs() << "Loop level " << nlvl << " {\n"; LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); BasicBlock* h = L->getHeader(); // 遍历当前循环的所有BasicBlock for (auto *BB : L->getBlocks()) { // 检查当前块是否属于当前循环的子循环 bool isInSubLoop = false; for (auto *SubLoop : L->getSubLoops()) { if (SubLoop->contains(BB)) { isInSubLoop = true; break; } } // 如果属于子循环,跳过,交给子循环处理 if (isInSubLoop) continue; // 检查当前块中的函数调用 for (auto &Inst : *BB) { if (auto *Call = dyn_cast<CallBase>(&Inst)) { errs() << "Found function call: " << Call->getCalledFunction()->getName() << " in loop level " << nlvl << "\n"; } } } // 递归处理子循环 for (auto *SubLoop : L->getSubLoops()) { BlocksInLoop(SubLoop, nlvl + 1); } errs() << "}\n"; }
额外提醒
- 记得在Pass的初始化部分声明依赖,比如加上
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass),确保能正确获取LoopInfo分析结果。 - 如果你的Pass还用到了ScalarEvolution,也要记得在
getAnalysisUsage里添加对应的分析依赖:
void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<LoopInfoWrapperPass>(); AU.addRequired<ScalarEvolutionWrapperPass>(); AU.setPreservesAll(); }
内容的提问来源于stack exchange,提问作者guillau4




