FinalizeISel

这个 Pass 只有一百多行。

这个 Pass 的作用,通俗地说,就是在指令选择(ISel)之后,把那些「伪指令」(pseudo‐instructions)真正展开成目标架构能识别的真实指令,并在此过程中修正一些寄存器/栈帧的预约信息。具体流程可以分为三个阶段:

  1. 调用目标侧的 finalizeLowering
    每个目标(TargetLowering)在 ISel 完成后,可能还需要做一些机器无关/机器相关的收尾工作,比如插入特殊指令、准备寄存器掩码等,这一步交给 TLI->finalizeLowering(MF)。
  2. 扫描所有 MachineInstr,展开伪指令
    指令选择器往往会产生一些「便于生成控制流或原子操作」的伪指令,比如用一个伪指令表示“条件移动”、或是“原子加锁-放锁”循环。它们本身不是最终的机器指令。这个 Pass 会遍历每个基本块、每条指令:
  • 如果某条指令 usesCustomInsertionHook()(即伪指令),就调用 TLI->EmitInstrWithCustomInserter(MI, MBB),由目标后端自己把它拆成若干条真正的指令/基本块(可能带分支、phi、循环等)。
  • 如果拆分出新基本块,就更新 CFG,并标记不再保留旧的 CFG 分析结果。
  1. 捕捉栈帧调整指令
    在展开过程中,如果遇到真正的「栈帧创建/销毁指令」(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 其实就是流控制里合并的结果