Skip to content

Commit 0cb6d2f

Browse files
committed
[LLVM][Convergence] further refactor convergence verifier
This is in preparation for using the same convergence verifier for both LLVM IR and Machine IR. Reviewed By: yassingh Differential Revision: https://reviews.llvm.org/D158394
1 parent bcabaa5 commit 0cb6d2f

File tree

5 files changed

+53
-39
lines changed

5 files changed

+53
-39
lines changed

llvm/include/llvm/ADT/GenericConvergenceVerifier.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ template <typename ContextT> class GenericConvergenceVerifier {
6363
// and not the token values.
6464
DenseMap<const InstructionT *, const InstructionT *> Tokens;
6565

66+
static bool isInsideConvergentFunction(const InstructionT &I);
67+
static bool isConvergent(const InstructionT &I);
6668
const InstructionT *findAndCheckConvergenceTokenUsed(const InstructionT &I);
67-
bool isControlledConvergent(const InstructionT &I);
68-
bool isConvergent(const InstructionT &I) const;
6969

7070
void reportFailure(const Twine &Message, ArrayRef<Printable> Values);
7171
};

llvm/include/llvm/IR/GenericConvergenceVerifierImpl.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,44 @@ template <class ContextT> void GenericConvergenceVerifier<ContextT>::clear() {
6969

7070
template <class ContextT>
7171
void GenericConvergenceVerifier<ContextT>::visit(const InstructionT &I) {
72-
if (isControlledConvergent(I)) {
72+
auto ID = ContextT::getIntrinsicID(I);
73+
auto *TokenDef = findAndCheckConvergenceTokenUsed(I);
74+
75+
bool IsCtrlIntrinsic = true;
76+
77+
switch (ID) {
78+
case Intrinsic::experimental_convergence_entry:
79+
Check(isInsideConvergentFunction(I),
80+
"Entry intrinsic can occur only in a convergent function.",
81+
{Context.print(&I)});
82+
Check(I.getParent()->isEntryBlock(),
83+
"Entry intrinsic can occur only in the entry block.",
84+
{Context.print(&I)});
85+
Check(I.getParent()->getFirstNonPHI() == &I,
86+
"Entry intrinsic can occur only at the start of the basic block.",
87+
{Context.print(&I)});
88+
LLVM_FALLTHROUGH;
89+
case Intrinsic::experimental_convergence_anchor:
90+
Check(!TokenDef,
91+
"Entry or anchor intrinsic cannot have a convergencectrl token "
92+
"operand.",
93+
{Context.print(&I)});
94+
break;
95+
case Intrinsic::experimental_convergence_loop:
96+
Check(TokenDef, "Loop intrinsic must have a convergencectrl token operand.",
97+
{Context.print(&I)});
98+
Check(I.getParent()->getFirstNonPHI() == &I,
99+
"Loop intrinsic can occur only at the start of the basic block.",
100+
{Context.print(&I)});
101+
break;
102+
default:
103+
IsCtrlIntrinsic = false;
104+
break;
105+
}
106+
107+
if (TokenDef || IsCtrlIntrinsic) {
73108
Check(isConvergent(I),
74-
"Expected convergent attribute on a controlled convergent call.",
109+
"Convergence control token can only be used in a convergent call.",
75110
{Context.print(&I)});
76111
Check(ConvergenceKind != UncontrolledConvergence,
77112
"Cannot mix controlled and uncontrolled convergence in the same "

llvm/lib/IR/ConvergenceVerifier.cpp

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,26 +51,18 @@ GenericConvergenceVerifier<SSAContext>::findAndCheckConvergenceTokenUsed(
5151
}
5252

5353
template <>
54-
bool GenericConvergenceVerifier<SSAContext>::isConvergent(
55-
const InstructionT &I) const {
56-
if (auto *CB = dyn_cast<CallBase>(&I)) {
57-
return CB->isConvergent();
58-
}
59-
return false;
54+
bool GenericConvergenceVerifier<SSAContext>::isInsideConvergentFunction(
55+
const InstructionT &I) {
56+
auto *F = I.getFunction();
57+
return F->isConvergent();
6058
}
6159

6260
template <>
63-
bool GenericConvergenceVerifier<SSAContext>::isControlledConvergent(
61+
bool GenericConvergenceVerifier<SSAContext>::isConvergent(
6462
const InstructionT &I) {
65-
// First find a token and place it in the map.
66-
if (findAndCheckConvergenceTokenUsed(I))
67-
return true;
68-
69-
// The entry and anchor intrinsics do not use a token, so we do a broad check
70-
// here. The loop intrinsic will be checked separately for a missing token.
71-
if (isConvergenceControlIntrinsic(SSAContext::getIntrinsicID(I)))
72-
return true;
73-
63+
if (auto *CB = dyn_cast<CallBase>(&I)) {
64+
return CB->isConvergent();
65+
}
7466
return false;
7567
}
7668

llvm/lib/IR/Verifier.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5927,23 +5927,10 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
59275927
break;
59285928
}
59295929
case Intrinsic::experimental_convergence_entry:
5930-
Check(Call.getFunction()->isConvergent(),
5931-
"Entry intrinsic can occur only in a convergent function.", &Call);
5932-
Check(Call.getParent()->isEntryBlock(),
5933-
"Entry intrinsic must occur in the entry block.", &Call);
5934-
Check(Call.getParent()->getFirstNonPHI() == &Call,
5935-
"Entry intrinsic must occur at the start of the basic block.", &Call);
59365930
LLVM_FALLTHROUGH;
59375931
case Intrinsic::experimental_convergence_anchor:
5938-
Check(!Call.getOperandBundle(LLVMContext::OB_convergencectrl),
5939-
"Entry or anchor intrinsic must not have a convergencectrl bundle.",
5940-
&Call);
59415932
break;
59425933
case Intrinsic::experimental_convergence_loop:
5943-
Check(Call.getOperandBundle(LLVMContext::OB_convergencectrl),
5944-
"Loop intrinsic must have a convergencectrl bundle.", &Call);
5945-
Check(Call.getParent()->getFirstNonPHI() == &Call,
5946-
"Loop intrinsic must occur at the start of the basic block.", &Call);
59475934
break;
59485935
};
59495936

llvm/test/Verifier/convergencectrl-invalid.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
22

3-
; CHECK: Entry or anchor intrinsic must not have a convergencectrl bundle.
3+
; CHECK: Entry or anchor intrinsic cannot have a convergencectrl token operand.
44
; CHECK-NEXT: %t04_tok2 = call token
5-
; CHECK: Loop intrinsic must have a convergencectrl bundle.
5+
; CHECK: Loop intrinsic must have a convergencectrl token operand.
66
; CHECK-NEXT: %t04_tok3 = call token
77
define void @basic_syntax() {
88
%t04_tok1 = call token @llvm.experimental.convergence.anchor()
@@ -20,7 +20,7 @@ define void @wrong_token() {
2020
ret void
2121
}
2222

23-
; CHECK: Expected convergent attribute on a controlled convergent call.
23+
; CHECK: Convergence control token can only be used in a convergent call.
2424
; CHECK-NEXT call void @g(){{.*}}%t05_tok1
2525
define void @missing.attribute() {
2626
%t05_tok1 = call token @llvm.experimental.convergence.anchor()
@@ -109,7 +109,7 @@ B:
109109
br label %B
110110
}
111111

112-
; CHECK: Entry intrinsic must occur at the start of the basic block.
112+
; CHECK: Entry intrinsic can occur only at the start of the basic block.
113113
; CHECK: %t60_tok1
114114
define void @entry_at_start(i32 %x, i32 %y) convergent {
115115
%z = add i32 %x, %y
@@ -124,7 +124,7 @@ define void @entry_in_convergent(i32 %x, i32 %y) {
124124
ret void
125125
}
126126

127-
; CHECK: Loop intrinsic must occur at the start of the basic block.
127+
; CHECK: Loop intrinsic can occur only at the start of the basic block.
128128
; CHECK: %t60_tok3
129129
define void @loop_at_start(i32 %x, i32 %y) convergent {
130130
A:
@@ -136,7 +136,7 @@ B:
136136
ret void
137137
}
138138

139-
; CHECK: Entry intrinsic must occur in the entry block.
139+
; CHECK: Entry intrinsic can occur only in the entry block.
140140
; CHECK: %t60_tok4
141141
define void @entry_at_entry(i32 %x, i32 %y) convergent {
142142
A:

0 commit comments

Comments
 (0)