后端Pass简介——FinalizeISel
FinalizeISel
这个 Pass 只有一百多行。
这个 Pass 的作用,通俗地说,就是在指令选择(ISel)之后,把那些「伪指令」(pseudo‐instructions)真正展开成目标架构能识别的真实指令,并在此过程中修正一些寄存器/栈帧的预约信息。具体流程可以分为三个阶段:
- 调用目标侧的 finalizeLowering
每个目标(TargetLowering)在 ISel 完成后,可能还需要做一些机器无关/机器相关的收尾工作,比如插入特殊指令、准备寄存器掩码等,这一步交给 TLI->finalizeLowering(MF)。 - 扫描所有 MachineInstr,展开伪指令
指令选择器往往会产生一些「便于生成控制流或原子操作」的伪指令,比如用一个伪指令表示“条件移动”、或是“原子加锁-放锁”循环。它们本身不是最终的机器指令。这个 Pass 会遍历每个基本块、每条指令:
- 如果某条指令 usesCustomInsertionHook()(即伪指令),就调用 TLI->EmitInstrWithCustomInserter(MI, MBB),由目标后端自己把它拆成若干条真正的指令/基本块(可能带分支、phi、循环等)。
- 如果拆分出新基本块,就更新 CFG,并标记不再保留旧的 CFG 分析结果。
- 捕捉栈帧调整指令
在展开过程中,如果遇到真正的「栈帧创建/销毁指令」(isFrameInstr)或是内联汇编里调整对齐的代码,也会通知 MachineFrameInfo,标记本函数需要在入口/出口生成相应的栈操作。
由以上内容可以看出这是在指令选择之后调度之前的一个 Lowering Pass
伪指令只是 MIR 里的一类特殊 MachineInstr——它们并不是 CPU/ISA 能真正执行的指令,而是 ISel 阶段为了简化模式匹配、表达复杂控制流或原子操作而插入的“占位符”。也就是说,他们没有和后端指令一一对应,没法在之前被指令选择而遗留下来
// 原始伪指令
SELECTCC %dst, EQ, %a, %b
// FinalizeISel 调用 TLI->EmitInstrWithCustomInserter 后等价于:
cmp %a, #%0 // 比较操作,设置 CPU flags
b.ne L_else // 条件分支
mov %dst, %a // then 分支:dst = a
b L_done
L_else:
mov %dst, %b // else 分支:dst = b
L_done:
; phi/dst 其实就是流控制里合并的结果
评论