DroppedVariableStatsMIR

这个 Pass 比较简单但重要!是 LLVM 后端的一个统计工具,它在每个机器级优化或代码生成阶段前后对比收集到的调试变量信息,记录因各类转换或优化而被丢弃(Dropped)的 DBG_VALUE 指令数量,并将这些丢失统计结果输出。
为什么要这么做

  • 确保调试质量:优化虽能提升性能,却往往会重排或删除部分中间变量的映射指令,导致调试器无法正确显示源代码中的变量值
  • 回归检测通过自动化统计,可以在引入新优化 Pass 时,及时发现是否有过多的调试信息丢失,避免影响调试体验
  • 定位问题:统计结果帮助后端开发者快速定位是哪个 Pass、哪个函数或哪个变量出了问题,从而有针对性地修改代码生成或优化策略。
    举例
    假设函数中有一个局部变量 foo,编译器在某次寄存器分配优化中,为了更好地利用寄存器,移除了或合并了原先用于跟踪 fooDBG_VALUE 指令。调试时便无法再观察到 foo 的值。使用 DroppedVariableStatsMIR
  1. 在“寄存器分配” Pass 之前,它记录下所有与 foo 相关的 DBG_VALUE
  2. Pass 执行后再次统计,发现 fooDBG_VALUE 数量从 3 条降到了 1 条,就会报告“寄存器分配”阶段丢弃了 2 条 DBG_VALUE
  3. 开发者据此可以深入分析:是分配算法的问题,还是后续的代码合并导致的指令删除,并进行修复或调整。

源码解读

  1. 钩子注册与前后比较
    • runBeforePass(PassID, MF):在每个 Pass 之前(除 “Debug Variable Analysis”)执行 setup() 初始化,并调用 runOnMachineFunction(MF, true) 记录“Before”状态。
    • runAfterPass(PassID, MF):在每个 Pass 之后执行 runOnMachineFunction(MF, false) 记录“After”状态,随后调用 calculateDroppedVarStatsOnMachineFunction 对比并输出差异,最后 cleanup() 清理本次数据。
  2. 数据收集
    • visitEveryDebugRecord:遍历当前 MachineFunction 中所有基本块和指令,收集所有 DBG_VALUE(和相关内联信息),构建要跟踪的变量集合 VarIDSet 及其 inlined-at 映射。
    • visitEveryInstruction:对于非调试指令,检查其附带的 DebugLoc,将指令作用域与每个目标变量的作用域匹配,一旦检测到某个变量的调试映射不再更新,即视为“丢弃”,并更新计数。
  3. 结果计算与输出
    • calculateDroppedVarStatsOnMachineFunction:读取“Before”与“After”两个阶段的丢弃计数差值,调用基类的 calculateDroppedStatsAndPrint,按 Pass 名称、函数名和模块名等信息格式化输出统计报告。
  4. 辅助流程
    • 内部通过一个栈状结构 DebugVariablesStack 保存各函数在不同 Pass 前后的调试变量快照;
    • setup()/cleanup() 分别初始化和清理该栈,以保证每次统计都是独立且完整的。
      整体来看,DroppedVariableStatsMIR.cpp 通过 “前——后” 对比的方式,自动化地在编译后端各阶段监控调试信息的完整性,为维护高质量的调试支持提供了重要手段。