后端Pass简介——BranchRelaxation
BranchRelaxation
LLVM 后端的 BranchRelaxationPass 是一个专门用于处理跳转指令距离限制的 MachineFunctionPass。它的主要作用是确保生成的汇编代码中,所有的跳转指令(如 b、bl、beq 等)都能正确跳转到目标位置,避免因跳转距离超出指令编码范围而导致的错误。
原因:在某些目标架构(如 AArch64、RISC-V 等)中,跳转指令的目标地址是通过指令中的偏移量编码的,而这个偏移量有一定的范围限制。例如:
- AArch64 的 B 指令支持 ±128MB 的跳转范围。
- RISC-V 的 JAL 指令支持 ±1MB 的跳转范围。
当超出限制时,就需要进行 BranchRelaxtion 了。
其 Pass 入口在文件尾部:
PreservedAnalyses
BranchRelaxationPass::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
if (!BranchRelaxation().run(MF))
return PreservedAnalyses::all();
return getMachineFunctionPassPreservedAnalyses();
}
bool BranchRelaxation::run(MachineFunction &mf) {
MF = &mf;
LLVM_DEBUG(dbgs() << "***** BranchRelaxation *****\n");
const TargetSubtargetInfo &ST = MF->getSubtarget();
TII = ST.getInstrInfo();
TM = &MF->getTarget();
TRI = ST.getRegisterInfo();
if (TRI->trackLivenessAfterRegAlloc(*MF))
RS.reset(new RegScavenger());
// Renumber all of the machine basic blocks in the function, guaranteeing that
// the numbers agree with the position of the block in the function. MF->RenumberBlocks();
MF->RenumberBlocks();
// Do the initial scan of the function, building up information about the
// sizes of each block. scanFunction();
scanFunction();
LLVM_DEBUG(dbgs() << " Basic blocks before relaxation\n"; dumpBBs(););
bool MadeChange = false;
while (relaxBranchInstructions())
MadeChange = true;
// After a while, this might be made debug-only, but it is not expensive.
verify();
LLVM_DEBUG(dbgs() << " Basic blocks after relaxation\n\n"; dumpBBs());
BlockInfo.clear();
RelaxedUnconditionals.clear();
return MadeChange;
}
不依赖任何启发式分析因素,然后第二入口为 relaxBranchInstructions
,并且理论复杂度是 的。
我们可以看到,唯一前置工作就是需要为基本块编号,然后扫描记录他们的大小。
然后其主要处理逻辑 relaxBranchInstructions
的原理也较为简单,就是遍历所有的 MBB,然后
- 处理无条件跳转,如果跳转距离太远,且之前没处理过,则插入跳板或者间接跳转方式放宽"跳转"。
- 处理条件跳转,同上,对部分分支处理。
然后需要注意的就是每次跳转结构修改后需要重新计算偏移。
评论