后端Pass简介——DwarfEHPreparePass
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");
评论