后端Pass简介——MachineCSE
MachineCSE
MachineCSE 是 LLVM 后端用于在 SSA 机器指令级别进行 公共子表达式消除(CSE) 的优化 Pass,旨在通过识别重复的计算并替换为已有结果,从而减少指令数、降低寄存器/内存压力。
这个 Pass 的概念也非常简单,对应到中端,就是普通CSE。
该 Pass 将近 1000 行,可以使用 -aggressive-machine-cse
强制忽略收益判断,直接执行 CSE 操作。
该 Pass 依赖:
- MachineDominatorTreeAnalysis
- MachineBlockFrequencyAnalysis
主处理函数为:
bool MachineCSEImpl::run(MachineFunction &MF) {
TII = MF.getSubtarget().getInstrInfo();
TRI = MF.getSubtarget().getRegisterInfo();
MRI = &MF.getRegInfo();
LookAheadLimit = TII->getMachineCSELookAheadLimit();
bool ChangedPRE, ChangedCSE;
ChangedPRE = PerformSimplePRE(DT); // 尝试将部分冗余表达式提前提升为全冗余,从而可以被后续的 CSE 消除。
ChangedCSE = PerformCSE(DT->getRootNode()); // 真正公共子表达式消除
releaseMemory();
return ChangedPRE || ChangedCSE;
}
下面讲一下他的代价函数 isProfitableToCSE
:
寄存器压力判断(主要):
- 如果 CSReg 的使用完全包含 Reg 的使用,不会增加寄存器活跃区间。
- 但如果使用数量过多(大于 csuses-threshold),为保守起见,放弃优化。
**启发式 #1 :对“便宜”指令(如 mov),如果其定义不在当前 BB 或直接前驱,不要做 CSE(担心跨块延长 live range):
if (TII->isAsCheapAsAMove(*MI)) {
if (CSBB != BB && !CSBB->isSuccessor(BB))
return false;
}
启发式 #2 :如果表达式无虚拟寄存器使用,且其使用只是复制(copy), 不要做 CSE:
if (!HasVRegUse && all uses are copies)
return false;
启发式 #3:如果 CSReg 的使用出现在 PHI 节点中,且不在当前 BB,不做 CSE,防止值在不同路径被滥用。
评论