LLVM 22.0.0git
SuspendCrossingInfo.h
Go to the documentation of this file.
1//===- SuspendCrossingInfo.cpp - Utility for suspend crossing values ------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8// The SuspendCrossingInfo maintains data that allows to answer a question
9// whether given two BasicBlocks A and B there is a path from A to B that
10// passes through a suspend point. Note, SuspendCrossingInfo is invalidated
11// by changes to the CFG including adding/removing BBs due to its use of BB
12// ptrs in the BlockToIndexMapping.
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_TRANSFORMS_COROUTINES_SUSPENDCROSSINGINFO_H
16#define LLVM_TRANSFORMS_COROUTINES_SUSPENDCROSSINGINFO_H
17
18#include "llvm/ADT/BitVector.h"
21#include "llvm/IR/BasicBlock.h"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/Instruction.h"
26
27namespace llvm {
28
29class ModuleSlotTracker;
30
31// Provides two way mapping between the blocks and numbers.
34
35public:
36 size_t size() const { return V.size(); }
37
39 for (BasicBlock &BB : F)
40 V.push_back(&BB);
41 llvm::sort(V);
42 }
43
44 size_t blockToIndex(BasicBlock const *BB) const {
45 auto *I = llvm::lower_bound(V, BB);
46 assert(I != V.end() && *I == BB && "BasicBlockNumberng: Unknown block");
47 return I - V.begin();
48 }
49
50 BasicBlock *indexToBlock(unsigned Index) const { return V[Index]; }
51};
52
53// The SuspendCrossingInfo maintains data that allows to answer a question
54// whether given two BasicBlocks A and B there is a path from A to B that
55// passes through a suspend point.
56//
57// For every basic block 'i' it maintains a BlockData that consists of:
58// Consumes: a bit vector which contains a set of indices of blocks that can
59// reach block 'i'. A block can trivially reach itself.
60// Kills: a bit vector which contains a set of indices of blocks that can
61// reach block 'i' but there is a path crossing a suspend point
62// not repeating 'i' (path to 'i' without cycles containing 'i').
63// Suspend: a boolean indicating whether block 'i' contains a suspend point.
64// End: a boolean indicating whether block 'i' contains a coro.end intrinsic.
65// KillLoop: There is a path from 'i' to 'i' not otherwise repeating 'i' that
66// crosses a suspend point.
67//
69 BlockToIndexMapping Mapping;
70
71 struct BlockData {
72 BitVector Consumes;
73 BitVector Kills;
74 bool Suspend = false;
75 bool End = false;
76 bool KillLoop = false;
77 bool Changed = false;
78 };
80
81 iterator_range<pred_iterator> predecessors(BlockData const &BD) const {
82 BasicBlock *BB = Mapping.indexToBlock(&BD - &Block[0]);
83 return llvm::predecessors(BB);
84 }
85
86 BlockData &getBlockData(BasicBlock *BB) {
87 return Block[Mapping.blockToIndex(BB)];
88 }
89
90 /// Compute the BlockData for the current function in one iteration.
91 /// Initialize - Whether this is the first iteration, we can optimize
92 /// the initial case a little bit by manual loop switch.
93 /// Returns whether the BlockData changes in this iteration.
94 template <bool Initialize = false>
95 bool computeBlockData(const ReversePostOrderTraversal<Function *> &RPOT);
96
97public:
98#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
99 // Print order is in RPO
100 void dump() const;
101 void dump(StringRef Label, BitVector const &BV,
103 ModuleSlotTracker &MST) const;
104#endif
105
108 const SmallVectorImpl<AnyCoroSuspendInst *> &CoroSuspends,
109 const SmallVectorImpl<AnyCoroEndInst *> &CoroEnds);
110
111 /// Returns true if there is a path from \p From to \p To crossing a suspend
112 /// point without crossing \p From a 2nd time.
114 BasicBlock *To) const;
115
116 /// Returns true if there is a path from \p From to \p To crossing a suspend
117 /// point without crossing \p From a 2nd time. If \p From is the same as \p To
118 /// this will also check if there is a looping path crossing a suspend point.
120 BasicBlock *To) const;
121
123 auto *I = cast<Instruction>(U);
124
125 // We rewrote PHINodes, so that only the ones with exactly one incoming
126 // value need to be analyzed.
127 if (auto *PN = dyn_cast<PHINode>(I))
128 if (PN->getNumIncomingValues() > 1)
129 return false;
130
131 BasicBlock *UseBB = I->getParent();
132
133 // As a special case, treat uses by an llvm.coro.suspend.retcon or an
134 // llvm.coro.suspend.async as if they were uses in the suspend's single
135 // predecessor: the uses conceptually occur before the suspend.
136 if (isa<CoroSuspendRetconInst>(I) || isa<CoroSuspendAsyncInst>(I)) {
137 UseBB = UseBB->getSinglePredecessor();
138 assert(UseBB && "should have split coro.suspend into its own block");
139 }
140
141 return hasPathCrossingSuspendPoint(DefBB, UseBB);
142 }
143
145 return isDefinitionAcrossSuspend(&A.getParent()->getEntryBlock(), U);
146 }
147
149 auto *DefBB = I.getParent();
150
151 // As a special case, treat values produced by an llvm.coro.suspend.*
152 // as if they were defined in the single successor: the uses
153 // conceptually occur after the suspend.
154 if (isa<AnyCoroSuspendInst>(I)) {
155 DefBB = DefBB->getSingleSuccessor();
156 assert(DefBB && "should have split coro.suspend into its own block");
157 }
158
159 return isDefinitionAcrossSuspend(DefBB, U);
160 }
161
163 if (auto *Arg = dyn_cast<Argument>(&V))
164 return isDefinitionAcrossSuspend(*Arg, U);
165 if (auto *Inst = dyn_cast<Instruction>(&V))
166 return isDefinitionAcrossSuspend(*Inst, U);
167
169 "Coroutine could only collect Argument and Instruction now.");
170 }
171
173 if (auto *Arg = dyn_cast<Argument>(&V)) {
174 for (User *U : Arg->users())
175 if (isDefinitionAcrossSuspend(*Arg, U))
176 return true;
177 } else if (auto *Inst = dyn_cast<Instruction>(&V)) {
178 for (User *U : Inst->users())
179 if (isDefinitionAcrossSuspend(*Inst, U))
180 return true;
181 }
182
184 "Coroutine could only collect Argument and Instruction now.");
185 }
186};
187
188} // namespace llvm
189
190#endif // LLVM_TRANSFORMS_COROUTINES_SUSPENDCROSSINGINFO_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements the BitVector class.
BlockVerifier::State From
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_ABI
Definition: Compiler.h:213
uint32_t Index
bool End
Definition: ELF_riscv.cpp:480
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
This file defines the SmallVector class.
This class represents an incoming formal argument to a Function.
Definition: Argument.h:32
LLVM Basic Block Representation.
Definition: BasicBlock.h:62
LLVM_ABI const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
Definition: BasicBlock.cpp:437
size_t blockToIndex(BasicBlock const *BB) const
BasicBlock * indexToBlock(unsigned Index) const
Manage lifetime of a slot tracker for printing IR.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
bool isDefinitionAcrossSuspend(Value &V) const
bool isDefinitionAcrossSuspend(Value &V, User *U) const
bool isDefinitionAcrossSuspend(BasicBlock *DefBB, User *U) const
LLVM_ABI bool hasPathCrossingSuspendPoint(BasicBlock *From, BasicBlock *To) const
Returns true if there is a path from From to To crossing a suspend point without crossing From a 2nd ...
bool isDefinitionAcrossSuspend(Instruction &I, User *U) const
LLVM_ABI bool hasPathOrLoopCrossingSuspendPoint(BasicBlock *From, BasicBlock *To) const
Returns true if there is a path from From to To crossing a suspend point without crossing From a 2nd ...
bool isDefinitionAcrossSuspend(Argument &A, User *U) const
LLVM Value Representation.
Definition: Value.h:75
A range adaptor for a pair of iterators.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1669
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:2013
auto predecessors(const MachineBasicBlock *BB)