Skip to content

Commit 08da343

Browse files
authored
[Convergence] allow non-convergent ops before entry and loop intrinsics (#65939)
The only real requirement is that entry and loop intrinsics should not be preceded by convergent operations in the same basic block. They do not need to be the first in the block. Relaxing the constraint on the entry and loop intrinsics avoids having to make changes in the construction of LLVM IR, such as getFirstInsertionPt(). It also avoids added complexity in the lowering to Machine IR, where COPY instructions may be added to the start of the basic block.
1 parent ad44112 commit 08da343

File tree

4 files changed

+25
-10
lines changed

4 files changed

+25
-10
lines changed

llvm/docs/ConvergentOperations.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -607,8 +607,9 @@ those in the caller.
607607
only if both threads entered the function by executing converged
608608
dynamic instances of the call-site.
609609

610-
This intrinsic can occur at most once in a function, and only at the start of
611-
the entry block of the function.
610+
This intrinsic can occur at most once in a function, and only in the the entry
611+
block of the function. If this intrinsic occurs in a basic block, then it must
612+
precede any other convergent operation in the same basic block.
612613

613614
It is an error if this intrinsic appears in a non-convergent function.
614615

@@ -669,7 +670,8 @@ threads execute converged dynamic instances of ``U`` if and only if:
669670
It is an error to omit the ``convergencectrl`` operand bundle on a
670671
call to this intrinsic.
671672

672-
This intrinsic can only occur at the start of a basic block.
673+
If this intrinsic occurs in a basic block, then it must precede any other
674+
convergent operation in the same basic block.
673675

674676
.. _convergence_cycle_heart:
675677

llvm/include/llvm/ADT/GenericConvergenceVerifier.h

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

66+
bool SeenFirstConvOp = false;
67+
6668
static bool isInsideConvergentFunction(const InstructionT &I);
6769
static bool isConvergent(const InstructionT &I);
6870
const InstructionT *findAndCheckConvergenceTokenUsed(const InstructionT &I);

llvm/include/llvm/IR/GenericConvergenceVerifierImpl.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,13 @@ template <class ContextT>
7171
void GenericConvergenceVerifier<ContextT>::visit(const InstructionT &I) {
7272
auto ID = ContextT::getIntrinsicID(I);
7373
auto *TokenDef = findAndCheckConvergenceTokenUsed(I);
74-
7574
bool IsCtrlIntrinsic = true;
7675

76+
// If this is the first instruction in the block, then we have not seen a
77+
// convergent op yet.
78+
if (!I.getPrevNode())
79+
SeenFirstConvOp = false;
80+
7781
switch (ID) {
7882
case Intrinsic::experimental_convergence_entry:
7983
Check(isInsideConvergentFunction(I),
@@ -82,8 +86,9 @@ void GenericConvergenceVerifier<ContextT>::visit(const InstructionT &I) {
8286
Check(I.getParent()->isEntryBlock(),
8387
"Entry intrinsic can occur only in the entry block.",
8488
{Context.print(&I)});
85-
Check(I.getParent()->getFirstNonPHI() == &I,
86-
"Entry intrinsic can occur only at the start of the basic block.",
89+
Check(!SeenFirstConvOp,
90+
"Entry intrinsic cannot be preceded by a convergent operation in the "
91+
"same basic block.",
8792
{Context.print(&I)});
8893
LLVM_FALLTHROUGH;
8994
case Intrinsic::experimental_convergence_anchor:
@@ -95,15 +100,19 @@ void GenericConvergenceVerifier<ContextT>::visit(const InstructionT &I) {
95100
case Intrinsic::experimental_convergence_loop:
96101
Check(TokenDef, "Loop intrinsic must have a convergencectrl token operand.",
97102
{Context.print(&I)});
98-
Check(I.getParent()->getFirstNonPHI() == &I,
99-
"Loop intrinsic can occur only at the start of the basic block.",
103+
Check(!SeenFirstConvOp,
104+
"Loop intrinsic cannot be preceded by a convergent operation in the "
105+
"same basic block.",
100106
{Context.print(&I)});
101107
break;
102108
default:
103109
IsCtrlIntrinsic = false;
104110
break;
105111
}
106112

113+
if (isConvergent(I))
114+
SeenFirstConvOp = true;
115+
107116
if (TokenDef || IsCtrlIntrinsic) {
108117
Check(isConvergent(I),
109118
"Convergence control token can only be used in a convergent call.",

llvm/test/Verifier/convergencectrl-invalid.ll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,11 @@ B:
109109
br label %B
110110
}
111111

112-
; CHECK: Entry intrinsic can occur only at the start of the basic block.
112+
; CHECK: Entry intrinsic cannot be preceded by a convergent operation in the same basic block.
113113
; CHECK: %t60_tok1
114114
define void @entry_at_start(i32 %x, i32 %y) convergent {
115115
%z = add i32 %x, %y
116+
call void @f()
116117
%t60_tok1 = call token @llvm.experimental.convergence.entry()
117118
ret void
118119
}
@@ -124,14 +125,15 @@ define void @entry_in_convergent(i32 %x, i32 %y) {
124125
ret void
125126
}
126127

127-
; CHECK: Loop intrinsic can occur only at the start of the basic block.
128+
; CHECK: Loop intrinsic cannot be preceded by a convergent operation in the same basic block.
128129
; CHECK: %t60_tok3
129130
define void @loop_at_start(i32 %x, i32 %y) convergent {
130131
A:
131132
%t60_tok3 = call token @llvm.experimental.convergence.entry()
132133
br label %B
133134
B:
134135
%z = add i32 %x, %y
136+
call void @f()
135137
%h1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t60_tok3) ]
136138
ret void
137139
}

0 commit comments

Comments
 (0)