DwarfEHPreparePass

注:最好对 DWARF 有了解

DwarfEHPrepare 将 LLVM IR 中==语义化的 resume 指令和清理落脚点(cleanup landing pads)转换为目标平台所需的== _Unwind_Resume(或等效)调用,并裁剪不可达的异常恢复路径,为后续代码生成做准备。

在后端最终输出 object file 时,会根据这些低级调用和 landing-pad 信息生成符合 DWARF EH ABI 的 unwind 表格,用于运行时堆栈展开和异常分派。

堆栈展开:当程序中抛出一个异常时,运行时需要“卷起”调用链上的每一层函数(就是 GDB 的 backtrace)
异常分派:在展开过程中,运行时每进入一个栈帧,就会问它的“个性化函数”:“我这个异常(携带类型信息和对象)你要处理吗?”

  • landingpad / resume:在 LLVM IR 里,landingpad 表示捕获或清理逻辑的入口,resume 用来继续传播异常
  • _Unwind_Resume:底层运行时函数,用于在目标平台上传递异常对象并恢复抛出流程。
  • 裁剪(pruning):针对优化级别非 None 的函数,移除那些从任何 cleanup landing pad 都不可到达的 resume,并用 unreachable 替换以简化控制流。
  • Dominators 更新:在修改 CFG(插入分支、合并 BasicBlock)后,通过 DomTreeUpdater 保持支配树分析的正确性。
    举个例子来看的话:
; 原始 IR(简化)
landingpad { i8*, i32 } personality i8* @__gxx_personality_v0
  cleanup
resume { i8*, i32 } %exn.aggregate

; 经过 DwarfEHPrepare 后(单个 resume)
%exn.obj = extractvalue { i8*, i32 } %exn.aggregate, 0
call void @_Unwind_Resume(i8* %exn.obj)
unreachable

如果有多个 resume,Pass 会创建一个统一的 unwind_resume BasicBlock,所有原有的 resume BasicBlock 最后都跳到这里,由一个 PHI 汇聚异常对象,再调用一次 _Unwind_Resume
源码上看:
该 Pass 依赖于:

  • DominatorTreeAnalysis
  • TargetIRAnalysis
    核心函数为:InsertUnwindResumeCalls,O (n) 复杂度。可统计信息为:
STATISTIC(NumResumesLowered, "Number of resume calls lowered");  
STATISTIC(NumCleanupLandingPadsUnreachable,  
          "Number of cleanup landing pads found unreachable");  
STATISTIC(NumCleanupLandingPadsRemaining,  
          "Number of cleanup landing pads remaining");  
STATISTIC(NumNoUnwind, "Number of functions with nounwind");  
STATISTIC(NumUnwind, "Number of functions with unwind");