26#ifndef LLVM_IR_GENERICCONVERGENCEVERIFIERIMPL_H
27#define LLVM_IR_GENERICCONVERGENCEVERIFIERIMPL_H
34#define Check(C, ...) \
37 reportFailure(__VA_ARGS__); \
42#define CheckOrNull(C, ...) \
45 reportFailure(__VA_ARGS__); \
57template <
class ContextT>
59 SeenFirstConvOp =
false;
62template <
class ContextT>
64 ConvOpKind ConvOp = getConvOp(
I);
66 auto *TokenDef = findAndCheckConvergenceTokenUsed(
I);
69 Check(isInsideConvergentFunction(
I),
70 "Entry intrinsic can occur only in a convergent function.",
72 Check(
I.getParent()->isEntryBlock(),
73 "Entry intrinsic can occur only in the entry block.",
75 Check(!SeenFirstConvOp,
76 "Entry intrinsic cannot be preceded by a convergent operation in the "
82 "Entry or anchor intrinsic cannot have a convergencectrl token "
87 Check(TokenDef,
"Loop intrinsic must have a convergencectrl token operand.",
89 Check(!SeenFirstConvOp,
90 "Loop intrinsic cannot be preceded by a convergent operation in the "
98 if (ConvOp != CONV_NONE)
99 checkConvergenceTokenProduced(
I);
102 SeenFirstConvOp =
true;
104 if (TokenDef || ConvOp != CONV_NONE) {
106 "Convergence control token can only be used in a convergent call.",
107 {Context.print(&
I)});
109 "Cannot mix controlled and uncontrolled convergence in the same "
111 {Context.print(&
I)});
113 }
else if (isConvergent(
I)) {
115 "Cannot mix controlled and uncontrolled convergence in the same "
117 {Context.print(&
I)});
122template <
class ContextT>
127 for (
auto V : DumpedValues)
132template <
class ContextT>
134 assert(Context.getFunction());
135 const auto &
F = *Context.getFunction();
148 "Convergence control token must dominate all its uses.",
149 {Context.print(Token), Context.print(User)});
152 "Convergence region is not well-nested.",
153 {Context.print(Token), Context.print(
User)});
154 while (LiveTokens.back() != Token)
155 LiveTokens.pop_back();
158 auto *BB =
User->getParent();
159 auto *BBCycle = CI.getCycle(BB);
163 auto *DefBB = Token->getParent();
164 if (DefBB == BB || BBCycle->contains(DefBB)) {
170 "Convergence token used by an instruction other than "
171 "llvm.experimental.convergence.loop in a cycle that does "
172 "not contain the token's definition.",
173 {Context.print(
User), CI.print(BBCycle)});
176 auto *Parent = BBCycle->getParentCycle();
177 if (!Parent || Parent->contains(DefBB))
182 Check(BBCycle->isReducible() && BB == BBCycle->getHeader(),
183 "Cycle heart must dominate all blocks in the cycle.",
184 {Context.print(User), Context.printAsOperand(BB), CI.print(BBCycle)});
186 "Two static convergence token uses in a cycle that does "
187 "not contain either token's definition.",
188 {Context.print(User), Context.print(CycleHearts[BBCycle]),
190 CycleHearts[BBCycle] =
User;
195 for (
auto *BB : RPOT) {
197 auto LTIt = LiveTokenMap.
find(BB);
198 if (LTIt != LiveTokenMap.
end()) {
199 LiveTokens = std::move(LTIt->second);
200 LiveTokenMap.
erase(LTIt);
203 for (
auto &
I : *BB) {
204 if (
auto *Token = Tokens.lookup(&
I))
205 checkToken(Token, &
I, LiveTokens);
206 if (getConvOp(
I) != CONV_NONE)
212 auto *SuccNode = DT.
getNode(Succ);
213 auto [LTIt, Inserted] = LiveTokenMap.
try_emplace(Succ);
217 for (
auto LiveToken : LiveTokens) {
220 LTIt->second.push_back(LiveToken);
225 LTIt->second, [&LiveTokens](
const InstructionT *Token) {
226 return llvm::is_contained(LiveTokens, Token);
228 LTIt->second.erase(It, LTIt->second.end());
A verifier for the static rules of convergence control tokens that works with both LLVM IR and MIR.
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool erase(const KeyT &Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
DomTreeNodeBase< NodeT > * getNode(const NodeT *BB) const
getNode - return the (Post)DominatorTree node for the specified basic block.
bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
typename ContextT::InstructionT InstructionT
typename ContextT::DominatorTreeT DominatorTreeT
typename ContextT::BlockT BlockT
typename ContextT::FunctionT FunctionT
void verify(const DominatorTreeT &DT)
void visit(const BlockT &BB)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This is an optimization pass for GlobalISel generic memory operations.
auto successors(const MachineBasicBlock *BB)
auto partition(R &&Range, UnaryPredicate P)
Provide wrappers to std::partition which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.