Skip to content

Commit eeac6a0

Browse files
committed
* SPIRVWriter/SPIRVRegularizeLLVM: removed our own BB sorting and replaced it with stablePreDominatorTraversal() lifted from the latest Khronos SPIRV-LLVM-Translator (original: KhronosGroup@35d400e), note that this is called during translation now rather than before
1 parent cda682a commit eeac6a0

File tree

2 files changed

+106
-40
lines changed

2 files changed

+106
-40
lines changed

lib/SPIRV/SPIRVRegularizeLLVM.cpp

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343

4444
#include "llvm/ADT/StringExtras.h" // llvm::isDigit
4545
#include "llvm/Demangle/Demangle.h"
46-
#include "llvm/IR/Dominators.h"
4746
#include "llvm/IR/InstVisitor.h"
4847
#include "llvm/IR/Instructions.h"
4948
#include "llvm/IR/Operator.h"
@@ -372,35 +371,6 @@ bool SPIRVRegularizeLLVMBase::runRegularizeLLVM(Module &Module) {
372371
return true;
373372
}
374373

375-
// final cleanup: sort BBs according to the DT
376-
void sort_bbs(Function *F) {
377-
// dominator fixes: reorder blocks
378-
// NOTE: obviously only necessary when there are more than 2 blocks
379-
if (F->getBasicBlockList().size() <= 2)
380-
return;
381-
382-
DominatorTree DT;
383-
DT.recalculate(*F);
384-
385-
// use the dominator tree order to sort the bbs, i.e. with the DT we already
386-
// know the sorted order,
387-
// we just need to physically move the blocks according to it
388-
std::vector<BasicBlock *> sorted_blocks;
389-
const std::function<void(const DomTreeNodeBase<BasicBlock> &)> sort_recurse =
390-
[&sort_recurse, &sorted_blocks](const DomTreeNodeBase<BasicBlock> &node) {
391-
sorted_blocks.emplace_back(node.getBlock());
392-
for (const auto &child : node) {
393-
sort_recurse(*child);
394-
}
395-
};
396-
sort_recurse(*DT.getRootNode());
397-
398-
// move blocks in reverse order (not moving entry of course)
399-
for (size_t i = 0, count = sorted_blocks.size(); i < count - 2; ++i) {
400-
sorted_blocks[count - i - 2]->moveBefore(sorted_blocks[count - i - 1]);
401-
}
402-
}
403-
404374
/// Remove entities not representable by SPIR-V
405375
bool SPIRVRegularizeLLVMBase::regularize() {
406376
eraseUselessFunctions(M);
@@ -539,11 +509,6 @@ bool SPIRVRegularizeLLVMBase::regularize() {
539509
for (StructType *ST : M->getIdentifiedStructTypes())
540510
adaptStructTypes(ST);
541511

542-
// sort BBs according to DT
543-
for (auto &F : *M) {
544-
sort_bbs(&F);
545-
}
546-
547512
std::string Err;
548513
raw_string_ostream ErrorOS(Err);
549514
if (llvm::verifyModule(*M, &ErrorOS)) {

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
55865681
void 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

Comments
 (0)