@@ -5583,6 +5583,101 @@ static bool is_write_only_arg(Function &F, Argument &arg) {
55835583 return user_recurse (&arg);
55845584}
55855585
5586+ // / Returns a range that traverses \p F ensuring that dominator blocks are
5587+ // / visited before the blocks they dominate.
5588+ // /
5589+ // / Compared to llvm::ReversePostOrderTraversal which also visits dominators
5590+ // / before dominated blocks, this traversal aims to be more stable and will keep
5591+ // / basic blocks in their original order as much as possible, only reordering
5592+ // / them to visit dominators ahead of their dominated blocks when needed. \p DT
5593+ // / is not copied by this function and needs to outlive any iterators created
5594+ // / from this range.
5595+ static auto stablePreDominatorTraversal (Function &F, const DominatorTree &DT) {
5596+
5597+ // A local iterator type for traversing a function in the desired order.
5598+ class StablePreDominatorIterator
5599+ : public iterator_facade_base<StablePreDominatorIterator,
5600+ std::forward_iterator_tag, BasicBlock> {
5601+
5602+ // The passed DominatorTree; may be unset for end iterators.
5603+ const DominatorTree *DT = nullptr ;
5604+
5605+ // The set of basic blocks already visited in this traversal.
5606+ SmallPtrSet<const BasicBlock *, 4 > VisitedBBs;
5607+
5608+ // The next basic block in original function order, or nullptr if the
5609+ // traversal is over.
5610+ BasicBlock *NextBB = nullptr ;
5611+
5612+ // The current basic block in the traversal, or nullptr for end iterators.
5613+ BasicBlock *CurBB = nullptr ;
5614+
5615+ // Returns the most immediate dominator of \p BB which does not have an
5616+ // unvisited dominator and so can be visited in this traversal.
5617+ BasicBlock *visitableDominator (BasicBlock *BB) const {
5618+
5619+ // Find BB's dominator; if there is none, BB can be visited immediately.
5620+ const auto *const BBNode = DT->getNode (BB);
5621+ if (!BBNode)
5622+ return BB;
5623+ const auto *const DomNode = BBNode->getIDom ();
5624+ if (!DomNode)
5625+ return BB;
5626+ BasicBlock *const Dominator = DomNode->getBlock ();
5627+
5628+ // If the dominator's been visited, BB can now be visited.
5629+ if (VisitedBBs.contains (Dominator))
5630+ return BB;
5631+
5632+ // Otherwise, find the dominator's visitable dominator instead.
5633+ return visitableDominator (Dominator);
5634+ }
5635+
5636+ // Advances the iterator and returns the next basic block to be visited in
5637+ // the traversal.
5638+ BasicBlock *next () {
5639+
5640+ // If NextBB is nullptr, the end of the traversal has been reached.
5641+ if (!NextBB)
5642+ return nullptr ;
5643+
5644+ // Check if NextBB has already been visited; if so, advance past it.
5645+ if (VisitedBBs.contains (NextBB)) {
5646+ NextBB = NextBB->getNextNode ();
5647+ return next ();
5648+ }
5649+
5650+ // If NextBB is unvisited, visit its next visitable dominator.
5651+ BasicBlock *const ToVisit = visitableDominator (NextBB);
5652+ VisitedBBs.insert (ToVisit);
5653+ return ToVisit;
5654+ }
5655+
5656+ public:
5657+ // Constructs an end iterator.
5658+ StablePreDominatorIterator () {}
5659+
5660+ // Constructs a begin iterator at the start of \p F.
5661+ StablePreDominatorIterator (Function &F, const DominatorTree &DT)
5662+ : DT(&DT), NextBB(&F.getEntryBlock()) {
5663+ ++*this ;
5664+ }
5665+
5666+ // Methods required by iterator_facade_base.
5667+ bool operator ==(const StablePreDominatorIterator &Other) const {
5668+ return CurBB == Other.CurBB ;
5669+ }
5670+ BasicBlock &operator *() const { return *CurBB; }
5671+ StablePreDominatorIterator &operator ++() {
5672+ CurBB = next ();
5673+ return *this ;
5674+ }
5675+ };
5676+
5677+ return make_range (StablePreDominatorIterator (F, DT),
5678+ StablePreDominatorIterator ());
5679+ }
5680+
55865681void LLVMToSPIRVBase::transFunction (Function *F) {
55875682 // again, ignore any floor.* functions
55885683 if (F->getName ().startswith (" floor." ))
@@ -6323,9 +6418,12 @@ void LLVMToSPIRVBase::transFunction(Function *F) {
63236418 }
63246419 }
63256420
6326- // Create all basic blocks before creating any instruction.
6327- for (Function::iterator FI = F->begin (), FE = F->end (); FI != FE; ++FI) {
6328- transValue (&*FI, nullptr );
6421+ // Create all basic blocks before creating any instruction. SPIR-V requires
6422+ // that blocks appear after their dominators, so stablePreDominatorTraversal
6423+ // is used to ensure blocks are written in the right order.
6424+ const DominatorTree DT (*F);
6425+ for (BasicBlock &FI : stablePreDominatorTraversal (*F, DT)) {
6426+ transValue (&FI, nullptr );
63296427 }
63306428
63316429 // set compute shader constant work-group size
@@ -6401,8 +6499,11 @@ void LLVMToSPIRVBase::transFunction(Function *F) {
64016499 }
64026500 }
64036501 } else if (SrcLang != SourceLanguageGLSL) {
6404- // Creating all basic blocks before creating any instruction.
6405- for (auto &FI : *F) {
6502+ // Create all basic blocks before creating any instruction. SPIR-V requires
6503+ // that blocks appear after their dominators, so stablePreDominatorTraversal
6504+ // is used to ensure blocks are written in the right order.
6505+ const DominatorTree DT (*F);
6506+ for (BasicBlock &FI : stablePreDominatorTraversal (*F, DT)) {
64066507 transValue (&FI, nullptr );
64076508 }
64086509 }
0 commit comments