xref: /llvm-project/llvm/test/Verifier/convergencectrl-invalid.ll (revision ee4945329f8d90ba4fda2e3b740f40b4958721c8)
1; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
2
3; CHECK: Entry or anchor intrinsic cannot have a convergencectrl token operand.
4; CHECK-NEXT: %t04_tok2 = call token
5; CHECK: Loop intrinsic must have a convergencectrl token operand.
6; CHECK-NEXT: %t04_tok3 = call token
7define void @basic_syntax() {
8  %t04_tok1 = call token @llvm.experimental.convergence.anchor()
9  %t04_tok2 = call token @llvm.experimental.convergence.anchor() [ "convergencectrl"(token %t04_tok1) ]
10  %t04_tok3 = call token @llvm.experimental.convergence.loop()
11  ret void
12}
13
14; CHECK: Convergence control tokens can only be produced by calls to the convergence control intrinsics.
15; CHECK-NEXT:  %t04_tok1 = call token @produce_token()
16; CHECK-NEXT:  call void @f() [ "convergencectrl"(token %t04_tok1) ]
17define void @wrong_token() {
18  %t04_tok1 = call token @produce_token()
19  call void @f() [ "convergencectrl"(token %t04_tok1) ]
20  ret void
21}
22
23; CHECK: Convergence control token can only be used in a convergent call.
24; CHECK-NEXT  call void @g(){{.*}}%t05_tok1
25define void @missing.attribute() {
26  %t05_tok1 = call token @llvm.experimental.convergence.anchor()
27  call void @g() [ "convergencectrl"(token %t05_tok1) ]
28  ret void
29}
30
31; CHECK: The 'convergencectrl' bundle requires exactly one token use.
32; CHECK-NEXT:  call void @g()
33define void @multiple_tokens() {
34  %t06_tok1 = call token @llvm.experimental.convergence.anchor()
35  %t06_tok2 = call token @llvm.experimental.convergence.anchor()
36  call void @g() [ "convergencectrl"(token %t06_tok2, token %t06_tok1) ]
37  ret void
38}
39
40; CHECK: The 'convergencectrl' bundle can occur at most once on a call
41; CHECK-NEXT:  call void @g()
42define void @multiple_bundles() {
43  %t07_tok1 = call token @llvm.experimental.convergence.anchor()
44  %t07_tok2 = call token @llvm.experimental.convergence.anchor()
45  call void @g() [ "convergencectrl"(token %t07_tok2), "convergencectrl"(token %t07_tok1) ]
46  ret void
47}
48
49; CHECK: Cannot mix controlled and uncontrolled convergence in the same function
50; CHECK-NEXT  call void @f()
51define void @mixed1() {
52  call void @g() ; not convergent
53  %t10_tok1 = call token @llvm.experimental.convergence.anchor()
54  call void @f() [ "convergencectrl"(token %t10_tok1) ]
55  call void @g()
56  call void @f() ; uncontrolled convergent
57  ret void
58}
59
60; CHECK: Cannot mix controlled and uncontrolled convergence in the same function
61; CHECK:  %t20_tok1 = call token @llvm.experimental.convergence.anchor()
62; CHECK: Cannot mix controlled and uncontrolled convergence in the same function
63; CHECK:  call void @f() [ "convergencectrl"(token %t20_tok1) ]
64define void @mixed2() {
65  call void @g() ; not convergent
66  call void @f() ; uncontrolled convergent
67  call void @g()
68  %t20_tok1 = call token @llvm.experimental.convergence.anchor()
69  call void @f() [ "convergencectrl"(token %t20_tok1) ]
70  ret void
71}
72
73; CHECK: Convergence region is not well-nested.
74; CHECK:   %t30_tok2
75define void @region_nesting1() {
76  %t30_tok1 = call token @llvm.experimental.convergence.anchor()
77  %t30_tok2 = call token @llvm.experimental.convergence.anchor()
78  call void @f() [ "convergencectrl"(token %t30_tok1) ]
79  call void @f() [ "convergencectrl"(token %t30_tok2) ]
80  ret void
81}
82
83; CHECK: Convergence region is not well-nested.
84; CHECK:   %t40_tok2
85define void @region_nesting2(i1 %cond) {
86A:
87  %t40_tok1 = call token @llvm.experimental.convergence.anchor()
88  %t40_tok2 = call token @llvm.experimental.convergence.anchor()
89  br i1 %cond, label %B, label %C
90
91B:
92  call void @f() [ "convergencectrl"(token %t40_tok1) ]
93  br label %C
94
95C:
96  call void @f() [ "convergencectrl"(token %t40_tok2) ]
97  ret void
98}
99
100; CHECK: Convergence token used by an instruction other than llvm.experimental.convergence.loop in a cycle that does not contain the token's definition.
101; CHECK:   token %t50_tok1
102define void @use_in_cycle() {
103A:
104  %t50_tok1 = call token @llvm.experimental.convergence.anchor()
105  br label %B
106
107B:
108  call void @f() [ "convergencectrl"(token %t50_tok1) ]
109  br label %B
110}
111
112; CHECK: Entry intrinsic cannot be preceded by a convergent operation in the same basic block.
113; CHECK:   %t60_tok1
114define void @entry_at_start(i32 %x, i32 %y) convergent {
115  %z = add i32 %x, %y
116  call void @f()
117  %t60_tok1 = call token @llvm.experimental.convergence.entry()
118  ret void
119}
120
121; CHECK: Entry intrinsic can occur only in a convergent function.
122; CHECK:   %t60_tok2
123define void @entry_in_convergent(i32 %x, i32 %y) {
124  %t60_tok2 = call token @llvm.experimental.convergence.entry()
125  ret void
126}
127
128; CHECK: Loop intrinsic cannot be preceded by a convergent operation in the same basic block.
129; CHECK-NEXT: %h1
130; CHECK-SAME: %t60_tok3
131define void @loop_at_start(i32 %x, i32 %y) convergent {
132A:
133  %t60_tok3 = call token @llvm.experimental.convergence.entry()
134  br label %B
135B:
136  %z = add i32 %x, %y
137  ; This is not an error
138  %h2 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t60_tok3) ]
139  br label %C
140C:
141  call void @f()
142  %h1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t60_tok3) ]
143  ret void
144}
145
146; CHECK: Entry intrinsic can occur only in the entry block.
147; CHECK:   %t60_tok4
148define void @entry_at_entry(i32 %x, i32 %y) convergent {
149A:
150  %z = add i32 %x, %y
151  br label %B
152B:
153  %t60_tok4 = call token @llvm.experimental.convergence.entry()
154  ret void
155}
156
157; CHECK: Two static convergence token uses in a cycle that does not contain either token's definition.
158; CHECK:   token %t70_tok1
159; CHECK:   token %t70_tok2
160define void @multiple_hearts() {
161A:
162  %t70_tok1 = call token @llvm.experimental.convergence.anchor()
163  %t70_tok2 = call token @llvm.experimental.convergence.anchor()
164  br label %B
165
166B:
167  %h2 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t70_tok2) ]
168  %h1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t70_tok1) ]
169  br label %B
170}
171
172; CHECK: Two static convergence token uses in a cycle that does not contain either token's definition.
173; CHECK:   token %h0
174; CHECK:   token %h0
175define void @multiple_hearts_nested(i1 %cond1, i1 %cond2) {
176A:
177  %t70_tok3 = call token @llvm.experimental.convergence.anchor()
178  br label %B
179
180B:
181  %h0 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t70_tok3) ]
182  br i1 %cond1, label %C, label %B
183
184C:
185  %h1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %h0) ]
186  %h2 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %h0) ]
187  br i1 %cond2, label %C, label %B
188}
189
190; CHECK: Cycle heart must dominate all blocks in the cycle.
191; CHECK: %h3 = call token
192; CHECK:   label %C
193define void @invalid_heart_nested(i1 %cond1, i1 %cond2) {
194A:
195  %t70_tok4 = call token @llvm.experimental.convergence.anchor()
196  br label %B
197
198B:
199  br i1 %cond1, label %C, label %B
200
201C:
202  %h3 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %t70_tok4) ]
203  br i1 %cond2, label %C, label %B
204}
205
206; CHECK: Cycle heart must dominate all blocks in the cycle.
207; CHECK: %h4 = call token
208; CHECK: label %C
209define void @irreducible1(i1 %cond) {
210A:
211  %a = call token @llvm.experimental.convergence.anchor()
212  br i1 %cond, label %B, label %C
213
214B:
215  %b = call token @llvm.experimental.convergence.anchor()
216  br i1 %cond, label %C, label %D
217
218C:
219  %h4 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %a) ]
220  br i1 %cond, label %B, label %E
221
222D:
223  call void @f() [ "convergencectrl"(token %b) ]
224  br i1 %cond, label %B, label %F
225
226E:
227  call void @f() [ "convergencectrl"(token %h4) ]
228  br i1 %cond, label %C, label %F
229
230F:
231  call void @f() [ "convergencectrl"(token %a) ]
232  ret void
233}
234
235; Mirror image of @irreducible1
236; CHECK: Cycle heart must dominate all blocks in the cycle.
237; CHECK: %h5 = call token
238; CHECK: label %B
239define void @irreducible2(i1 %cond) {
240A:
241  %a = call token @llvm.experimental.convergence.anchor()
242  br i1 %cond, label %B, label %C
243
244B:
245  %h5 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %a) ]
246  br i1 %cond, label %C, label %D
247
248C:
249  %c = call token @llvm.experimental.convergence.anchor()
250  br i1 %cond, label %B, label %E
251
252D:
253  call void @f() [ "convergencectrl"(token %h5) ]
254  br i1 %cond, label %B, label %F
255
256E:
257  call void @f() [ "convergencectrl"(token %c) ]
258  br i1 %cond, label %C, label %F
259
260F:
261  call void @f() [ "convergencectrl"(token %a) ]
262  ret void
263}
264
265declare token @produce_token()
266
267declare void @f() convergent
268declare void @g()
269
270declare token @llvm.experimental.convergence.entry()
271declare token @llvm.experimental.convergence.anchor()
272declare token @llvm.experimental.convergence.loop()
273