[llvm-dev] Update control flow graph when splitting a machine basic block?
章明 via llvm-dev
llvm-dev at lists.llvm.org
Mon Nov 13 18:58:23 PST 2017
> It looks like what's happening is that IfConversion makes the return
> conditional, then that gets merged with the following block. I mean, I
> would say it's a bug in that there's a "terminator" in a position not at
> the end of the block, but a return doesn't have any CFG successors, so
> I'm not sure it has any practical effect.
>
> I think we won't merge with the following block for an indirect branch
> which is not a return.
I believe MachineBasicBlock::getFirstTerminator, MachineBasicBlock::getFirstInstrTerminator, and
Methods/functions that use these methods will break on a machine basic block like this,
although I have not tested these with such a machine basic block. I don't know whether
MachineBasicBlock::getFirstTerminator and MachineBasicBlock::getFirstInstrTerminator are
intended to be used in a late stage like just before code emission or not.
I am trying to circumvent this issue by splitting machine basic blocks, s.t. if
a machine basic block contains a terminator, only terminators or non-real instructions
like DBG_VALUE may come after the first terminator. This would probably also involve
updating the CFG. I'm trying to update the CFG by inspecting targets of terminators, but
I am not sure whether this approach is viable. My code for updating the CFG after splitting
a machine basic block is as follows. I intend to run the code before ARMConstantIslands.
Could you please give me some advice? Thank you!
// This function assumes the successors of the old machine basic
// block are correct. If the target of a terminator in a new machine basic
// block is not a successor of the old machine basic block, the target is not
// treated as a successor of the new machine basic block. If a successor of the
// old machine basic block is not the target of any of the terminators in the
// new machine basic blocks, the successor of the old machine basic block is
// conservatively treated as a common successor of all the new machine basic
// blocks.
// MBBBefore: New machine basic block before the split point.
// MBBAfter: New machine basic block after the split point.
// Successors: Successors of the old machine basic block.
// MF: Machine function that contains the new machine basic blocks and the
// successors of the old machine basic block.
void UpdateCFG(MachineBasicBlock &MBBBefore,
MachineBasicBlock &MBBAfter,
std::unordered_set<MachineBasicBlock *> &Successors,
MachineFunction &MF) {
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
assert(TII && "The target instruction information must not be a null pointer.");
const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
assert(MJTI && "The machine jump table information must not be a null pointer.");
const std::vector<MachineJumpTableEntry> &JumpTables = MJTI->getJumpTables();
SmallVector<MachineBasicBlock *, 2> MBBs = {&MBBBefore, &MBBAfter};
std::unordered_set<MachineBasicBlock *> RemainingSuccessors = Successors;
for (auto MBB : MBBs) {
assert(MBB && "A new machine basic block cannot be a null pointer.");
// Remove all successors from the new machine basic block.
for (auto SuccI = MBB->succ_begin(), SuccE = MBB->succ_end();
SuccI != SuccE;
SuccI++)
MBB->removeSuccessor(SuccI);
bool MayFallthrough = true;
// Iterate over all terminators of the new machine basic block.
// Note: MachineBasicBlock::getFirstTerminator and
// MachineBasicBlock::getFirstInstrTerminator seem to assume that every
// machine instructions after the first terminator is either a terminator or
// a debug instruction. This assumption does not always hold.
// We do not use MachineBasicBlock::terminators here, because it depends on
// MachineBasicBlock::getFirstTerminator.
for (auto MI = MBB->begin(), MIE = MBB->end(); MI != MIE; MI++) {
if (!MI->isTerminator())
continue;
// Determine the target of the terminator.
// We search for operands that are machine basic blocks or jump table
// indices.
// Returns and indirect branches are ignored, since their targets are not
// machine basic blocks.
for (auto Op = MI->operands_begin(), OpE = MI->operands_end();
Op != OpE;
Op++) {
// FIXME: Could a machine basic block operand of a terminator not be the target of the terminator?
// FIXME: Could a terminator other than jump table have more than one targets?
if (Op->isMBB()) {
// The operand is a machine basic block.
MachineBasicBlock *Target = Op->getMBB();
// If the possible target of the terminator is a successor of the old
// machine basic block, or if the terminator is in the new machine
// basic block before the split point and the operand is the new
// machine basic block after the split point, then treat the target of
// the terminator as a successor of the new basic block and remove it
// from the remaining successors.
if (Successors.count(Target) ||
(MBB == &MBBBefore && Target == &MBBAfter)) {
MBB->addSuccessor(Target);
RemainingSuccessors.erase(Target);
}
}
if (Op->isJTI()) {
// The operand is a jump table index.
unsigned JTI = Op->getIndex();
assert(JTI < JumpTables.size() &&
"The jump table index is out-of-range.");
const MachineJumpTableEntry &JT = JumpTables[JTI];
for (MachineBasicBlock *Target : JT.MBBs) {
// If the possible target of the terminator is a successor of the
// old machine basic block, then treat it as a successor of the new
// basic block and remove it from the remaining successors.
if (Successors.count(Target)) {
MBB->addSuccessor(Target);
RemainingSuccessors.erase(Target);
}
}
}
}
// If the terminator is an unconditional control flow barrier, then the
// machine basic block cannot fall through to its layout successor, and
// instructions after it cannot be executed.
// FIXME: Is this a correct way to determine whether an machine instruction may fall through?
if (MI->isBarrier() && !TII->isPredicated(*MI)) {
MayFallthrough = false;
break;
}
}
// If the new machine basic block may fall through to its layout successor,
// then treat the layout successor as a successor of the new machine basic
// block.
if (MayFallthrough) {
MachineFunction::iterator LayoutSuccessor = std::next(MBB->getIterator());
if (LayoutSuccessor != MF.end()) {
if ((MBB == &MBBBefore && &*LayoutSuccessor == &MBBAfter) ||
(MBB == &MBBAfter && Successors.count(&*LayoutSuccessor))) {
MBB->addSuccessor(&*LayoutSuccessor);
RemainingSuccessors.erase(&*LayoutSuccessor);
}
}
}
}
// Treat the remaining successors, i.e., successors of the old machine basic
// block that are not found to be targets of terminators in the new machine
// basic blocks, as common successors of all the new machine basic blocks.
for (auto MBB : MBBs) {
for (auto Succ : RemainingSuccessors)
MBB->addSuccessor(Succ);
}
}
More information about the llvm-dev
mailing list