25#define DEBUG_TYPE "spirv-convergence-region-analysis"
32 "SPIRV convergence regions analysis",
true,
true)
37 "convergence-region",
"SPIRV convergence regions analysis",
42template <
typename BasicBlockType,
typename IntrinsicInstType>
43std::optional<IntrinsicInstType *>
45 static_assert(std::is_const_v<IntrinsicInstType> ==
46 std::is_const_v<BasicBlockType>,
47 "Constness must match between input and output.");
48 static_assert(std::is_same_v<BasicBlock, std::remove_const_t<BasicBlockType>>,
49 "Input must be a basic block.");
51 std::is_same_v<IntrinsicInst, std::remove_const_t<IntrinsicInstType>>,
52 "Output type must be an intrinsic instruction.");
83 while (Candidate != NextCandidate && NextCandidate !=
nullptr) {
84 Candidate = NextCandidate;
85 NextCandidate =
nullptr;
91 for (
auto *Child : Candidate->
Children) {
92 if (Child->Blocks.count(Entry) != 0) {
93 NextCandidate = Child;
102std::optional<IntrinsicInst *>
104 return getConvergenceTokenInternal<BasicBlock, IntrinsicInst>(BB);
107std::optional<const IntrinsicInst *>
109 return getConvergenceTokenInternal<const BasicBlock, const IntrinsicInst>(BB);
114 : DT(DT), LI(LI),
Parent(nullptr) {
115 Entry = &
F.getEntryBlock();
130 for ([[maybe_unused]]
auto *BB : this->
Exits)
139 Child->releaseMemory();
146 const std::string Indent(IndentSize,
'\t');
147 dbgs() << Indent <<
this <<
": {\n";
148 dbgs() << Indent <<
" Parent: " <<
Parent <<
"\n";
156 if (
Entry->getName() !=
"")
157 dbgs() << Indent <<
" Entry: " <<
Entry->getName() <<
"\n";
159 dbgs() << Indent <<
" Entry: " <<
Entry <<
"\n";
161 dbgs() << Indent <<
" Exits: { ";
162 for (
const auto &Exit :
Exits) {
163 if (Exit->getName() !=
"")
164 dbgs() << Exit->getName() <<
", ";
166 dbgs() << Exit <<
", ";
170 dbgs() << Indent <<
" Blocks: { ";
172 if (
Block->getName() !=
"")
179 dbgs() << Indent <<
" Children: {\n";
181 Child->dump(IndentSize + 2);
182 dbgs() << Indent <<
" }\n";
184 dbgs() << Indent <<
"}\n";
188class ConvergenceRegionAnalyzer {
191 : DT(DT), LI(LI),
F(
F) {}
202 if (!LI.isLoopHeader(To))
205 auto *L = LI.getLoopFor(To);
206 if (L->contains(From) && L->isLoopLatch(From))
212 std::unordered_set<BasicBlock *>
214 std::function<
bool(
const BasicBlock *)> isMatch)
const {
215 std::unordered_set<BasicBlock *> Output;
221 for (
unsigned i = 0; i < Terminator->getNumSuccessors(); ++i) {
222 auto *To = Terminator->getSuccessor(i);
224 if (isBackEdge(From, To))
227 auto ChildSet = findPathsToMatch(LI, To, isMatch);
228 if (ChildSet.size() == 0)
231 Output.insert(ChildSet.begin(), ChildSet.end());
235 for (
auto *BB : L->getBlocks()) {
244 SmallPtrSet<BasicBlock *, 2>
245 findExitNodes(
const SmallPtrSetImpl<BasicBlock *> &RegionBlocks) {
246 SmallPtrSet<BasicBlock *, 2> Exits;
248 for (
auto *
B : RegionBlocks) {
250 for (
unsigned i = 0; i <
Terminator->getNumSuccessors(); ++i) {
252 if (RegionBlocks.count(Child) == 0)
261 ConvergenceRegionInfo analyze() {
262 ConvergenceRegion *TopLevelRegion =
new ConvergenceRegion(DT, LI,
F);
263 std::queue<Loop *> ToProcess;
267 while (ToProcess.size() != 0) {
268 auto *
L = ToProcess.front();
274 L->getExitingBlocks(LoopExits);
275 if (CT.has_value()) {
276 for (
auto *Exit : LoopExits) {
277 auto N = findPathsToMatch(LI, Exit, [&CT](
const BasicBlock *
block) {
279 if (Token == std::nullopt)
281 return Token.value() == CT.value();
283 RegionBlocks.insert_range(
N);
287 auto RegionExits = findExitNodes(RegionBlocks);
288 ConvergenceRegion *
Region =
new ConvergenceRegion(
289 DT, LI, CT,
L->getHeader(), std::move(RegionBlocks),
290 std::move(RegionExits));
292 assert(
Region->Parent !=
nullptr &&
"This is impossible.");
293 Region->Parent->Children.push_back(Region);
296 return ConvergenceRegionInfo(TopLevelRegion);
309 ConvergenceRegionAnalyzer Analyzer(
F, DT, LI);
310 return Analyzer.analyze();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static ConvergenceRegion * findParentRegion(ConvergenceRegion *Start, BasicBlock *Entry)
unify loop Fixup each natural loop to have a single exit block
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Analysis pass that exposes the LoopInfo for a function.
bool isLoopHeader(const BlockT *BB) const
SmallVector< LoopT *, 4 > getLoopsInPreorder() const
Return all of the loops in the function in preorder across the loop nests, with siblings in forward p...
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
The legacy pass manager's analysis pass to compute loop information.
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
SPIRVConvergenceRegionAnalysisWrapperPass()
Result run(Function &F, FunctionAnalysisManager &AM)
SPIRV::ConvergenceRegionInfo Result
SmallVector< ConvergenceRegion * > Children
ConvergenceRegion(DominatorTree &DT, LoopInfo &LI, Function &F)
void dump(const unsigned IndentSize=0) const
SmallPtrSet< BasicBlock *, 2 > Exits
std::optional< IntrinsicInst * > ConvergenceToken
ConvergenceRegion * Parent
SmallPtrSet< BasicBlock *, 8 > Blocks
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
ConvergenceRegionInfo getConvergenceRegions(Function &F, DominatorTree &DT, LoopInfo &LI)
std::optional< IntrinsicInst * > getConvergenceToken(BasicBlock *BB)
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
constexpr from_range_t from_range
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
Implement std::hash so that hash_code can be used in STL containers.
std::optional< IntrinsicInstType * > getConvergenceTokenInternal(BasicBlockType *BB)
A special type used by analysis passes to provide an address that identifies that particular analysis...