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__); \
52 switch (IntrinsicID) {
55 case Intrinsic::experimental_convergence_anchor:
56 case Intrinsic::experimental_convergence_entry:
57 case Intrinsic::experimental_convergence_loop:
65 ConvergenceKind = NoConvergence;
68template <
class ContextT>
70 SeenFirstConvOp =
false;
73template <
class ContextT>
75 auto ID = ContextT::getIntrinsicID(
I);
76 auto *TokenDef = findAndCheckConvergenceTokenUsed(
I);
77 bool IsCtrlIntrinsic =
true;
80 case Intrinsic::experimental_convergence_entry:
81 Check(isInsideConvergentFunction(
I),
82 "Entry intrinsic can occur only in a convergent function.",
84 Check(
I.getParent()->isEntryBlock(),
85 "Entry intrinsic can occur only in the entry block.",
87 Check(!SeenFirstConvOp,
88 "Entry intrinsic cannot be preceded by a convergent operation in the "
92 case Intrinsic::experimental_convergence_anchor:
94 "Entry or anchor intrinsic cannot have a convergencectrl token "
98 case Intrinsic::experimental_convergence_loop:
99 Check(TokenDef,
"Loop intrinsic must have a convergencectrl token operand.",
101 Check(!SeenFirstConvOp,
102 "Loop intrinsic cannot be preceded by a convergent operation in the "
107 IsCtrlIntrinsic =
false;
112 SeenFirstConvOp =
true;
114 if (TokenDef || IsCtrlIntrinsic) {
116 "Convergence control token can only be used in a convergent call.",
118 Check(ConvergenceKind != UncontrolledConvergence,
119 "Cannot mix controlled and uncontrolled convergence in the same "
122 ConvergenceKind = ControlledConvergence;
123 }
else if (isConvergent(
I)) {
124 Check(ConvergenceKind != ControlledConvergence,
125 "Cannot mix controlled and uncontrolled convergence in the same "
128 ConvergenceKind = UncontrolledConvergence;
132template <
class ContextT>
137 for (
auto V : DumpedValues)
142template <
class ContextT>
145 const auto &
F = *
Context.getFunction();
158 "Convergence region is not well-nested.",
160 while (LiveTokens.back() != Token)
161 LiveTokens.pop_back();
164 auto *BB =
User->getParent();
165 auto *BBCycle = CI.getCycle(BB);
169 auto *DefBB = Token->getParent();
170 if (DefBB == BB || BBCycle->contains(DefBB)) {
176 Intrinsic::experimental_convergence_loop,
177 "Convergence token used by an instruction other than "
178 "llvm.experimental.convergence.loop in a cycle that does "
179 "not contain the token's definition.",
183 auto *Parent = BBCycle->getParentCycle();
184 if (!Parent || Parent->contains(DefBB))
189 Check(BBCycle->isReducible() && BB == BBCycle->getHeader(),
190 "Cycle heart must dominate all blocks in the cycle.",
191 {Context.print(User), Context.printAsOperand(BB), CI.print(BBCycle)});
193 "Two static convergence token uses in a cycle that does "
194 "not contain either token's definition.",
195 {Context.print(User), Context.print(CycleHearts[BBCycle]),
197 CycleHearts[BBCycle] =
User;
202 for (
auto *BB : RPOT) {
204 auto LTIt = LiveTokenMap.
find(BB);
205 if (LTIt != LiveTokenMap.
end()) {
206 LiveTokens = std::move(LTIt->second);
207 LiveTokenMap.
erase(LTIt);
210 for (
auto &
I : *BB) {
211 if (
auto *Token = Tokens.lookup(&
I))
212 checkToken(Token, &
I, LiveTokens);
219 auto *SuccNode = DT.getNode(Succ);
220 auto LTIt = LiveTokenMap.
find(Succ);
221 if (LTIt == LiveTokenMap.
end()) {
225 for (
auto LiveToken : LiveTokens) {
226 if (!DT.dominates(DT.getNode(LiveToken->getParent()), SuccNode))
228 LTIt->second.push_back(LiveToken);
233 LTIt->second, [&LiveTokens](
const InstructionT *Token) {
234 return llvm::is_contained(LiveTokens, Token);
236 LTIt->second.erase(It, LTIt->second.end());
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
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.
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.
static bool isConvergenceControlIntrinsic(unsigned IntrinsicID)