Skip to content

Commit 0287a3d

Browse files
committed
Verify no SIL critical edges.
There are multiple reasons this is needed. 1. Most passes do not perform CFG transformations. However, we often need to split critical edges and remember to invalidate all SIL analyses at the end of virtually every pass. This is very innefficient and highly bug prone. 2. Many SIL analysis algorithms needs to reason about CFG edges. Avoiding critical edges leads to far simpler and more efficient designs when edges can be identified by blocks. 3. Handling block arguments on conditional branches create complexity at the lowest level of the SIL interface. This complexity is difficult to abstract over and bleeds until any algorithm that needs to reason about phi operands. It's far easier to work with phis if we can easily recover the phi operand with only a reference to the predecessor block. 4. Attempting to preserve critical edges in high and mid level IR blocks optimizations that otherwise have no business optimizing branches. Branch optimization should always be defered to machine level IR where the most relevant heuristics are employed to remove unconditional branches. If code didn't need to be placed on a critical edges, then a branch optimization can easily remove that code from the critical edge.
1 parent 901bce2 commit 0287a3d

File tree

1 file changed

+18
-25
lines changed

1 file changed

+18
-25
lines changed

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5188,37 +5188,30 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
51885188

51895189
void verifyBranches(const SILFunction *F) {
51905190
// Verify no critical edge.
5191-
auto isCriticalEdgePred = [](const TermInst *T, unsigned EdgeIdx) {
5192-
assert(T->getSuccessors().size() > EdgeIdx && "Not enough successors");
5193-
5191+
auto requireNonCriticalSucc = [this](const TermInst *termInst,
5192+
const Twine &message) {
51945193
// A critical edge has more than one outgoing edges from the source
51955194
// block.
5196-
auto SrcSuccs = T->getSuccessors();
5197-
if (SrcSuccs.size() <= 1)
5198-
return false;
5199-
5200-
// And its destination block has more than one predecessor.
5201-
SILBasicBlock *DestBB = SrcSuccs[EdgeIdx];
5202-
assert(!DestBB->pred_empty() && "There should be a predecessor");
5203-
if (DestBB->getSinglePredecessorBlock())
5204-
return false;
5195+
auto succBlocks = termInst->getSuccessorBlocks();
5196+
if (succBlocks.size() <= 1)
5197+
return;
52055198

5206-
return true;
5199+
for (const SILBasicBlock *destBB : succBlocks) {
5200+
// And its destination block has more than one predecessor.
5201+
_require(destBB->getSinglePredecessorBlock(), message);
5202+
}
52075203
};
52085204

5209-
for (auto &BB : *F) {
5210-
const TermInst *TI = BB.getTerminator();
5211-
CurInstruction = TI;
5205+
for (auto &bb : *F) {
5206+
const TermInst *termInst = bb.getTerminator();
5207+
CurInstruction = termInst;
52125208

5213-
// FIXME: In OSSA, critical edges will never be allowed.
5214-
// In Lowered SIL, they are allowed on unconditional branches only.
5215-
// if (!(isSILOwnershipEnabled() && F->hasOwnership()))
5216-
if (AllowCriticalEdges && isa<CondBranchInst>(TI))
5217-
continue;
5218-
5219-
for (unsigned Idx = 0, e = BB.getSuccessors().size(); Idx != e; ++Idx) {
5220-
require(!isCriticalEdgePred(TI, Idx),
5221-
"non cond_br critical edges not allowed");
5209+
if (isSILOwnershipEnabled() && F->hasOwnership()) {
5210+
requireNonCriticalSucc(termInst, "critical edges not allowed in OSSA");
5211+
}
5212+
// In Lowered SIL, they are allowed on conditional branches only.
5213+
if (!AllowCriticalEdges && !isa<CondBranchInst>(termInst)) {
5214+
requireNonCriticalSucc(termInst, "only cond_br critical edges allowed");
52225215
}
52235216
}
52245217
}

0 commit comments

Comments
 (0)