Skip to content

Commit cb13282

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 8a6a76b commit cb13282

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
@@ -517,14 +517,18 @@ bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const {
517517
}
518518

519519
size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const {
520-
size_t result = 0;
520+
auto It = BlockToOrder.find(BB);
521+
if (It != BlockToOrder.end())
522+
return It->second.Rank;
521523

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

527530
auto Iterator = BlockToOrder.end();
531+
528532
Loop *L = LI.getLoopFor(P);
529533
BasicBlock *Latch = L ? L->getLoopLatch() : nullptr;
530534

@@ -539,7 +543,11 @@ size_t PartialOrderingVisitor::GetNodeRank(BasicBlock *BB) const {
539543
Iterator = BlockToOrder.find(Latch);
540544
}
541545

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

@@ -550,15 +558,27 @@ size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
550558
ToVisit.push(BB);
551559
Queued.insert(BB);
552560

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

557-
if (!CanBeVisited(BB)) {
573+
// Either the node is a candidate, or we looped already, and this is
574+
// the first node we tried.
575+
if (!CanBeVisited(BB) && QueueIndex <= ToVisit.size()) {
558576
ToVisit.push(BB);
577+
QueueIndex++;
559578
continue;
560579
}
561580

581+
QueueIndex = 0;
562582
size_t Rank = GetNodeRank(BB);
563583
OrderInfo Info = {Rank, BlockToOrder.size()};
564584
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)