Skip to content

Commit afe4a60

Browse files
committed
[SPIR-V] Fix block sorting with irreducible CFG
Block sorting was assuming reducible CFG. Meaning we always had a best node to continue with. Irreducible CFG makes breaks this assumption, so the algorithm looped indefinitely because no node was a valid candidate. Fixes #116692 Signed-off-by: Nathan Gauër <[email protected]>
1 parent dddeec4 commit afe4a60

File tree

6 files changed

+592
-214
lines changed

6 files changed

+592
-214
lines changed

llvm/lib/Target/SPIRV/SPIRVUtils.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -519,14 +519,18 @@ bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const {
519519
}
520520

521521
size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const {
522-
size_t result = 0;
522+
auto It = BlockToOrder.find(BB);
523+
if (It != BlockToOrder.end())
524+
return It->second.Rank;
523525

526+
size_t result = 0;
524527
for (BasicBlock *P : predecessors(BB)) {
525528
// Ignore back-edges.
526529
if (DT.dominates(BB, P))
527530
continue;
528531

529532
auto Iterator = BlockToOrder.end();
533+
530534
Loop *L = LI.getLoopFor(P);
531535
BasicBlock *Latch = L ? L->getLoopLatch() : nullptr;
532536

@@ -541,7 +545,11 @@ size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const {
541545
Iterator = BlockToOrder.find(Latch);
542546
}
543547

544-
assert(Iterator != BlockToOrder.end());
548+
// This block hasn't been ranked yet. Ignoring.
549+
// This doesn't happen often, but when dealing with irreducible CFG, we have
550+
// to rank nodes without knowing the rank of all their predecessors.
551+
if (Iterator == BlockToOrder.end())
552+
continue;
545553
result = std::max(result, Iterator->second.Rank + 1);
546554
}
547555

@@ -552,15 +560,27 @@ size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
552560
ToVisit.push(BB);
553561
Queued.insert(BB);
554562

563+
// When the graph is irreducible, we can end up in a case where each
564+
// node has a predecessor we haven't ranked yet.
565+
// When such case arise, we have to pick a node to continue.
566+
// This index is used to determine when we looped through all candidates.
567+
// Each time a candidate is processed, this counter is reset.
568+
// If the index is larger than the queue size, it means we looped.
569+
size_t QueueIndex = 0;
570+
555571
while (ToVisit.size() != 0) {
556572
BasicBlock *BB = ToVisit.front();
557573
ToVisit.pop();
558574

559-
if (!CanBeVisited(BB)) {
575+
// Either the node is a candidate, or we looped already, and this is
576+
// the first node we tried.
577+
if (!CanBeVisited(BB) && QueueIndex <= ToVisit.size()) {
560578
ToVisit.push(BB);
579+
QueueIndex++;
561580
continue;
562581
}
563582

583+
QueueIndex = 0;
564584
size_t Rank = GetNodeRank(BB);
565585
OrderInfo Info = {Rank, BlockToOrder.size()};
566586
BlockToOrder.emplace(BB, Info);

llvm/lib/Target/SPIRV/SPIRVUtils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,11 @@ class PartialOrderingVisitor {
8484
// Visits |BB| with the current rank being |Rank|.
8585
size_t visit(BasicBlock *BB, size_t Rank);
8686

87-
size_t GetNodeRank(BasicBlock *BB) const;
8887
bool CanBeVisited(BasicBlock *BB) const;
8988

9089
public:
90+
size_t GetNodeRank(BasicBlock *BB) const;
91+
9192
// Build the visitor to operate on the function F.
9293
PartialOrderingVisitor(Function &F);
9394

llvm/test/CodeGen/SPIRV/structurizer/cf.if.nested.ll

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,28 @@
3434
; CHECK: %[[#bb30:]] = OpLabel
3535
; CHECK: OpSelectionMerge %[[#bb31:]] None
3636
; CHECK: OpBranchConditional %[[#]] %[[#bb32:]] %[[#bb33:]]
37-
; CHECK: %[[#bb32:]] = OpLabel
37+
; CHECK: %[[#bb32]] = OpLabel
3838
; CHECK: OpSelectionMerge %[[#bb34:]] None
39-
; CHECK: OpBranchConditional %[[#]] %[[#bb35:]] %[[#bb34:]]
40-
; CHECK: %[[#bb33:]] = OpLabel
39+
; CHECK: OpBranchConditional %[[#]] %[[#bb35:]] %[[#bb34]]
40+
; CHECK: %[[#bb33]] = OpLabel
4141
; CHECK: OpSelectionMerge %[[#bb36:]] None
4242
; CHECK: OpBranchConditional %[[#]] %[[#bb37:]] %[[#bb38:]]
43-
; CHECK: %[[#bb35:]] = OpLabel
44-
; CHECK: OpBranch %[[#bb34:]]
45-
; CHECK: %[[#bb37:]] = OpLabel
46-
; CHECK: OpBranch %[[#bb36:]]
47-
; CHECK: %[[#bb38:]] = OpLabel
43+
; CHECK: %[[#bb35]] = OpLabel
44+
; CHECK: OpBranch %[[#bb34]]
45+
; CHECK: %[[#bb37]] = OpLabel
46+
; CHECK: OpBranch %[[#bb36]]
47+
; CHECK: %[[#bb38]] = OpLabel
4848
; CHECK: OpSelectionMerge %[[#bb39:]] None
49-
; CHECK: OpBranchConditional %[[#]] %[[#bb40:]] %[[#bb39:]]
50-
; CHECK: %[[#bb34:]] = OpLabel
51-
; CHECK: OpBranch %[[#bb31:]]
52-
; CHECK: %[[#bb40:]] = OpLabel
53-
; CHECK: OpBranch %[[#bb39:]]
54-
; CHECK: %[[#bb39:]] = OpLabel
55-
; CHECK: OpBranch %[[#bb36:]]
56-
; CHECK: %[[#bb36:]] = OpLabel
57-
; CHECK: OpBranch %[[#bb31:]]
58-
; CHECK: %[[#bb31:]] = OpLabel
49+
; CHECK: OpBranchConditional %[[#]] %[[#bb40:]] %[[#bb39]]
50+
; CHECK: %[[#bb34]] = OpLabel
51+
; CHECK: OpBranch %[[#bb31]]
52+
; CHECK: %[[#bb40]] = OpLabel
53+
; CHECK: OpBranch %[[#bb39]]
54+
; CHECK: %[[#bb39]] = OpLabel
55+
; CHECK: OpBranch %[[#bb36]]
56+
; CHECK: %[[#bb36]] = OpLabel
57+
; CHECK: OpBranch %[[#bb31]]
58+
; CHECK: %[[#bb31]] = OpLabel
5959
; CHECK: OpReturnValue %[[#]]
6060
; CHECK: OpFunctionEnd
6161
; CHECK: %[[#func_26:]] = OpFunction %[[#void:]] DontInline %[[#]]

0 commit comments

Comments
 (0)