必须改用 basicblock::iterator 插入指令,因 llvm 15+ 中 instruction* 插入会静默丢弃 #dbg_value 调试信息并可能触发断言失败;正确做法包括用 i->getiterator()、bb->getfirstinsertionpt() 或 bb->end()。

旧教程里用 Instruction * 直接插入指令、用 BasicBlock::getFirstInsertionPt() 返回 Instruction * 再传给 InsertBefore 的写法,在 LLVM 15+(尤其是启用调试记录后)会静默丢弃调试信息,甚至触发断言失败。必须改用 BasicBlock::iterator。
为什么不能继续用 Instruction * 插入位置
新调试信息以 #dbg_value 记录形式存在,不参与指令链表,但绑定在 BasicBlock::iterator 的底层比特位上。一旦你把 Instruction * 强转成迭代器(比如调用 I->getIterator()),LLVM 会尝试从该指令向前扫描找最近的 dbg record —— 但如果插入点是基本块开头且没有前置指令,这个扫描会失败或返回错误位置。更糟的是,InsertBefore(Inst*) 内部会无条件丢弃所有关联的调试记录。
常见错误现象包括:
- IR 中
#dbg_value行消失,但opt -S输出看起来“正常” - 调试器无法停在某行,或变量显示为
<optimized out></optimized> - 启用
-g编译后lldb显示源码行号错位
正确插入位置的三类写法
所有插入操作必须使用 BasicBlock::iterator 类型的位置标记,而不是 Instruction *:
- 插到某条指令前:用
I->getIterator(),不是I - 插到基本块开头(如 PHIs 后):用
BB->getFirstInsertionPt()—— 它返回的就是iterator,别再解引用或强转 - 插到基本块末尾:用
BB->end(),不是BB->getTerminator()
示例对比:
/* 错误:传 Instruction*,调试记录丢失 */ Builder.Insert(BB->getTerminator(), NewInst); // 不要这样 <p>/<em> 正确:用 iterator </em>/ Builder.Insert(BB->getTerminator()->getIterator(), NewInst);</p><p>/<em> 正确:插到开头(PHIs 之后) </em>/ auto InsertPt = BB->getFirstInsertionPt(); Builder.Insert(InsertPt, NewInst);</p>
批量移动指令时必须用 moveBeforePreserving
如果你在 Pass 中做指令重排(比如把一组计算提前到入口基本块),旧写法 Inst->moveBefore(OtherInst) 会切断调试记录绑定。新版本必须用 moveBeforePreserving:
-
Inst->moveBefore(OtherInst)→ 仅移动指令,丢弃所有#dbg_value -
Inst->moveBeforePreserving(OtherInst)→ 指令 + 关联调试记录一起移动
注意:这个函数只存在于 Instruction 类中,BasicBlock::splice 等批量操作默认已支持保留,但手动逐条调用 moveBefore 是高频出错点。
最易被忽略的是:即使你不显式操作调试信息,只要用了旧插入模式,生成的 bitcode 就可能在后续优化中因缺失调试上下文而触发未定义行为 —— 比如 LoopInfo 分析错判循环边界,或 GVN 错误合并等价表达式。别等调试器报错才回头查。











