llvm pass遍历ir必须严格按module→function→basicblock→instruction层级进行,不可跳过;需用module->begin()/end()遍历所有function,跳过isdeclaration()为true的声明,用for(auto &bb : *f)遍历basicblock,用for(auto &i : bb)遍历instruction,调用识别用isa或isa。

LLVM Pass 遍历 IR 的核心路径是 Module → Function → BasicBlock → Instruction,没有捷径,也不能跳过层级。如果你在写一个自定义 Pass 时发现没遍历到某条指令,大概率是漏了某一层的循环嵌套,或者用了错误的迭代器范围(比如用 front() 取单个基本块而不是遍历全部)。
怎么从 Module 开始拿到所有 Function
Module 是整个编译单元的顶层容器,所有函数都挂在它下面。直接用 module->begin() 和 module->end() 迭代即可,但要注意:某些 Pass(比如 ModulePass)接收的是 Module&,而 FunctionPass 接收的是单个 Function&,别混淆作用域。
- 必须检查
!F->isDeclaration(),否则会把外部声明(如printf)也当成本地函数处理 - 如果只关心定义过的函数(即有函数体的),跳过
isDeclaration() == true的Function -
Module::getFunction(StringRef)是按名查找,适合调试时定位,但不用于遍历主逻辑
怎么安全遍历一个 Function 内的所有 BasicBlock
BasicBlock 是函数内不可分割的线性指令序列,遍历顺序默认是插入顺序(Function::begin() 到 end()),但某些优化 Pass(如 Reassociate)会先构造 ReversePostOrderTraversal 来保证数据流正确性。日常分析类 Pass 用默认顺序足够。
- 不要用
F->getEntryBlock()作为唯一入口——它只返回第一个基本块,而函数可能有多个入口(如异常分发块) - 用
for (auto &BB : *F)或for (auto BB = F->begin(); BB != F->end(); ++BB)才能覆盖全部 - 如果需要前驱/后继信息(比如做 CFG 分析),调用
BB.getPredecessors()或BB.getSuccessors(),注意它们返回的是SmallVector,不是迭代器
怎么逐条访问 BasicBlock 中的 Instruction 并识别调用
每条 Instruction 都是 SSA 形式,其操作数可通过 I.getOperand(i) 访问,类型判断靠 isa<callinst>(&I)</callinst> 这类模板谓词。直接 cast 有风险,必须先 dyn_cast 或 isa 检查。
- 遍历指令必须用
for (auto &I : BB),不能用BB.begin()+++手动推进——IR 指令可能被中途删除,迭代器失效 - 识别函数调用:优先用
isa<callinst>(&I) || isa<invokeinst>(&I)</invokeinst></callinst>,因为invoke也属于调用指令,但带异常路径 - 获取被调用函数名:对
CallInst*调用CI->getCalledFunction(),若返回nullptr,说明是间接调用(如函数指针),需进一步查CI->getCalledValue() - 想统计指令频次?别只数
Instruction类型,注意PHINode、AllocaInst等都继承自Instruction,但语义完全不同
最容易被忽略的一点:LLVM IR 是模块化的,但遍历本身不自动处理跨函数引用。比如你在函数 A 里看到一条 call @foo,@foo 的定义可能在另一个 Translation Unit 里——此时 getCalledFunction() 返回 nullptr,你得决定是跳过、报错,还是加载对应 Module。真实项目中,这往往是静态分析准确率的分水岭。











