xref: /llvm-project/llvm/test/CodeGen/AArch64/callbr-prepare.ll (revision e390c229a438ed1eb3396df8fbeeda89c49474e6)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt %s -callbrprepare -S -o - | FileCheck %s
3; RUN: opt %s -passes=callbr-prepare -S -o - | FileCheck %s
4
5define i32 @test0() {
6; CHECK-LABEL: @test0(
7; CHECK-NEXT:  entry:
8; CHECK-NEXT:    [[OUT:%.*]] = callbr i32 asm "# $0", "=r,!i"()
9; CHECK-NEXT:    to label [[DIRECT:%.*]] [label %entry.indirect_crit_edge]
10; CHECK:       entry.indirect_crit_edge:
11; CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[OUT]])
12; CHECK-NEXT:    br label [[INDIRECT:%.*]]
13; CHECK:       direct:
14; CHECK-NEXT:    [[OUT2:%.*]] = callbr i32 asm "# $0", "=r,!i"()
15; CHECK-NEXT:    to label [[DIRECT2:%.*]] [label %direct.indirect_crit_edge]
16; CHECK:       direct.indirect_crit_edge:
17; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[OUT2]])
18; CHECK-NEXT:    br label [[INDIRECT]]
19; CHECK:       direct2:
20; CHECK-NEXT:    ret i32 0
21; CHECK:       indirect:
22; CHECK-NEXT:    [[OUT3:%.*]] = phi i32 [ [[TMP0]], [[ENTRY_INDIRECT_CRIT_EDGE:%.*]] ], [ [[TMP1]], [[DIRECT_INDIRECT_CRIT_EDGE:%.*]] ]
23; CHECK-NEXT:    ret i32 [[OUT3]]
24;
25entry:
26  %out = callbr i32 asm "# $0", "=r,!i"()
27  to label %direct [label %indirect]
28direct:
29  %out2 = callbr i32 asm "# $0", "=r,!i"()
30  to label %direct2 [label %indirect]
31direct2:
32  ret i32 0
33indirect:
34  %out3 = phi i32 [%out, %entry], [%out2, %direct]
35  ret i32 %out3
36}
37
38; Don't split edges unless they are critical, and callbr produces output, and
39; that output is used.
40; Here we have none of the above.
41define i32 @dont_split0() {
42; CHECK-LABEL: @dont_split0(
43; CHECK-NEXT:  entry:
44; CHECK-NEXT:    callbr void asm "", "!i"()
45; CHECK-NEXT:    to label [[X:%.*]] [label %y]
46; CHECK:       x:
47; CHECK-NEXT:    ret i32 42
48; CHECK:       y:
49; CHECK-NEXT:    ret i32 0
50;
51entry:
52  callbr void asm "", "!i"()
53  to label %x [label %y]
54
55x:
56  ret i32 42
57
58y:
59  ret i32 0
60}
61
62; Don't split edges unless they are critical, and callbr produces output, and
63; that output is used.
64; Here we have output, but no critical edge.
65; That said, we ought to insert a callbr landing pad intrinsic call and update
66; to use the correct SSA value.
67define i32 @dont_split1() {
68; CHECK-LABEL: @dont_split1(
69; CHECK-NEXT:  entry:
70; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
71; CHECK-NEXT:    to label [[X:%.*]] [label %y]
72; CHECK:       x:
73; CHECK-NEXT:    ret i32 42
74; CHECK:       y:
75; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
76; CHECK-NEXT:    ret i32 [[TMP1]]
77;
78entry:
79  %0 = callbr i32 asm "", "=r,!i"()
80  to label %x [label %y]
81
82x:
83  ret i32 42
84
85y:
86  ret i32 %0
87}
88
89; Don't split edges unless they are critical, and callbr produces output, and
90; that output is used.
91; Here we have a critical edge along an indirect branch, but no output.
92define i32 @dont_split2() {
93; CHECK-LABEL: @dont_split2(
94; CHECK-NEXT:  entry:
95; CHECK-NEXT:    callbr void asm "", "!i"()
96; CHECK-NEXT:    to label [[X:%.*]] [label %y]
97; CHECK:       x:
98; CHECK-NEXT:    br label [[Y:%.*]]
99; CHECK:       y:
100; CHECK-NEXT:    [[TMP0:%.*]] = phi i32 [ 0, [[X]] ], [ 42, [[ENTRY:%.*]] ]
101; CHECK-NEXT:    ret i32 [[TMP0]]
102;
103entry:
104  callbr void asm "", "!i"()
105  to label %x [label %y]
106
107x:
108  br label %y
109
110y:
111  %0 = phi i32 [ 0, %x ], [ 42, %entry ]
112  ret i32 %0
113}
114
115; Don't split edges unless they are critical, and callbr produces output, and
116; that output is used.
117; Here we're missing a use.
118define i32 @dont_split3() {
119; CHECK-LABEL: @dont_split3(
120; CHECK-NEXT:  entry:
121; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
122; CHECK-NEXT:    to label [[X:%.*]] [label %v]
123; CHECK:       x:
124; CHECK-NEXT:    br label [[V:%.*]]
125; CHECK:       v:
126; CHECK-NEXT:    ret i32 42
127;
128entry:
129  %0 = callbr i32 asm "", "=r,!i"() to label %x [label %v]
130
131x:
132  br label %v
133
134v:
135  ret i32 42
136}
137
138; Don't split edges unless they are critical, and callbr produces output, and
139; that output is used.
140; Here we have output and a critical edge along an indirect branch.
141define i32 @split_me0() {
142; CHECK-LABEL: @split_me0(
143; CHECK-NEXT:  entry:
144; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
145; CHECK-NEXT:    to label [[X:%.*]] [label %entry.y_crit_edge]
146; CHECK:       entry.y_crit_edge:
147; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
148; CHECK-NEXT:    br label [[Y:%.*]]
149; CHECK:       x:
150; CHECK-NEXT:    br label [[Y]]
151; CHECK:       y:
152; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_Y_CRIT_EDGE:%.*]] ], [ 42, [[X]] ]
153; CHECK-NEXT:    ret i32 [[TMP2]]
154;
155entry:
156  %0 = callbr i32 asm "", "=r,!i"()
157  to label %x [label %y]
158
159x:
160  br label %y
161
162y:
163  %1 = phi i32 [ %0, %entry ], [ 42, %x ]
164  ret i32 %1
165}
166
167; Here we have output and a critical edge along an indirect branch.
168; Ensure that if we repeat the indirect destination, that we only split it
169; once.
170define i32 @split_me1(i1 %z) {
171; CHECK-LABEL: @split_me1(
172; CHECK-NEXT:  entry:
173; CHECK-NEXT:    br i1 [[Z:%.*]], label [[W:%.*]], label [[V:%.*]]
174; CHECK:       w:
175; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,!i"()
176; CHECK-NEXT:    to label [[X:%.*]] [label [[W_V_CRIT_EDGE:%.*]], label %w.v_crit_edge]
177; CHECK:       w.v_crit_edge:
178; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
179; CHECK-NEXT:    br label [[V]]
180; CHECK:       x:
181; CHECK-NEXT:    ret i32 42
182; CHECK:       v:
183; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[W_V_CRIT_EDGE]] ], [ undef, [[ENTRY:%.*]] ]
184; CHECK-NEXT:    ret i32 [[TMP2]]
185;
186entry:
187  br i1 %z, label %w, label %v
188
189w:
190  %0 = callbr i32 asm "", "=r,!i,!i"()
191  to label %x [label %v, label %v]
192
193x:
194  ret i32 42
195
196v:
197  %1 = phi i32 [%0, %w], [%0, %w], [undef, %entry]
198  ret i32 %1
199}
200
201; A more interessting case of @split_me1. Check that we still only split the
202; critical edge from w to v once.
203define i32 @split_me2(i1 %z) {
204; CHECK-LABEL: @split_me2(
205; CHECK-NEXT:  entry:
206; CHECK-NEXT:    br i1 [[Z:%.*]], label [[W:%.*]], label [[V:%.*]]
207; CHECK:       w:
208; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i,!i"()
209; CHECK-NEXT:    to label [[X:%.*]] [label [[W_V_CRIT_EDGE:%.*]], label %w.v_crit_edge]
210; CHECK:       w.v_crit_edge:
211; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
212; CHECK-NEXT:    br label [[V]]
213; CHECK:       x:
214; CHECK-NEXT:    ret i32 42
215; CHECK:       v:
216; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[W_V_CRIT_EDGE]] ], [ 42, [[ENTRY:%.*]] ]
217; CHECK-NEXT:    ret i32 [[TMP2]]
218;
219entry:
220  br i1 %z, label %w, label %v
221
222w:
223  %0 = callbr i32 asm "", "=r,!i,!i"()
224  to label %x [label %v, label %v]
225
226x:
227  ret i32 42
228
229v:
230  %1 = phi i32 [ %0, %w ], [ 42, %entry ], [ %0, %w ]
231  ret i32 %1
232}
233
234; Here we have a diamond with no phi.
235define i32 @dont_split4() {
236; CHECK-LABEL: @dont_split4(
237; CHECK-NEXT:  entry:
238; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
239; CHECK-NEXT:    to label [[X:%.*]] [label %y]
240; CHECK:       x:
241; CHECK-NEXT:    br label [[OUT:%.*]]
242; CHECK:       y:
243; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
244; CHECK-NEXT:    br label [[OUT]]
245; CHECK:       out:
246; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[Y:%.*]] ], [ [[TMP0]], [[X]] ]
247; CHECK-NEXT:    ret i32 [[TMP2]]
248;
249entry:
250  %0 = callbr i32 asm "", "=r,!i"()
251  to label %x [label %y]
252
253x:
254  br label %out
255
256y:
257  br label %out
258
259out:
260  ret i32 %0
261}
262
263; Triangle with no phi.
264define i32 @dont_split5() {
265; CHECK-LABEL: @dont_split5(
266; CHECK-NEXT:  entry:
267; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
268; CHECK-NEXT:    to label [[OUT:%.*]] [label %y]
269; CHECK:       y:
270; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
271; CHECK-NEXT:    br label [[OUT]]
272; CHECK:       out:
273; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[Y:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]
274; CHECK-NEXT:    ret i32 [[TMP2]]
275;
276entry:
277  %0 = callbr i32 asm "", "=r,!i"()
278  to label %out [label %y]
279
280y:
281  br label %out
282
283out:
284  ret i32 %0
285}
286
287; Triangle the other way with no phi.
288define i32 @split_me3() {
289; CHECK-LABEL: @split_me3(
290; CHECK-NEXT:  entry:
291; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
292; CHECK-NEXT:    to label [[Y:%.*]] [label %entry.out_crit_edge]
293; CHECK:       entry.out_crit_edge:
294; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
295; CHECK-NEXT:    br label [[OUT:%.*]]
296; CHECK:       y:
297; CHECK-NEXT:    br label [[OUT]]
298; CHECK:       out:
299; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_OUT_CRIT_EDGE:%.*]] ], [ [[TMP0]], [[Y]] ]
300; CHECK-NEXT:    ret i32 [[TMP2]]
301;
302entry:
303  %0 = callbr i32 asm "", "=r,!i"()
304  to label %y [label %out]
305
306y:
307  br label %out
308
309out:
310  ret i32 %0
311}
312
313; Test callbr looping back on itself.
314define i32 @dont_split6(i32 %0) {
315; CHECK-LABEL: @dont_split6(
316; CHECK-NEXT:  entry:
317; CHECK-NEXT:    br label [[LOOP:%.*]]
318; CHECK:       loop:
319; CHECK-NEXT:    [[TMP1:%.*]] = phi i32 [ [[TMP0:%.*]], [[ENTRY:%.*]] ], [ [[TMP3:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ]
320; CHECK-NEXT:    [[TMP2:%.*]] = callbr i32 asm "", "=r,0,!i"(i32 [[TMP1]])
321; CHECK-NEXT:    to label [[EXIT:%.*]] [label %loop.loop_crit_edge]
322; CHECK:       loop.loop_crit_edge:
323; CHECK-NEXT:    [[TMP3]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP2]])
324; CHECK-NEXT:    br label [[LOOP]]
325; CHECK:       exit:
326; CHECK-NEXT:    ret i32 0
327;
328entry:
329  br label %loop
330loop:
331  %1 = phi i32 [%0, %entry], [%2, %loop]
332  %2 = callbr i32 asm "", "=r,0,!i"(i32 %1) to label %exit [label %loop]
333exit:
334  ret i32 0
335}
336
337; Test same direct+indirect dest no phi.
338define i32 @split_me4() {
339; CHECK-LABEL: @split_me4(
340; CHECK-NEXT:  entry:
341; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
342; CHECK-NEXT:    to label [[SAME:%.*]] [label %entry.same_crit_edge]
343; CHECK:       entry.same_crit_edge:
344; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
345; CHECK-NEXT:    br label [[SAME]]
346; CHECK:       same:
347; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_SAME_CRIT_EDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]
348; CHECK-NEXT:    ret i32 [[TMP2]]
349;
350entry:
351  %0 = callbr i32 asm "", "=r,!i"() to label %same [label %same]
352same:
353  ret i32 %0
354}
355
356; Test same direct+indirect dest w/ phi.
357define i32 @split_me5() {
358; CHECK-LABEL: @split_me5(
359; CHECK-NEXT:  entry:
360; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
361; CHECK-NEXT:    to label [[SAME:%.*]] [label %entry.same_crit_edge]
362; CHECK:       entry.same_crit_edge:
363; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
364; CHECK-NEXT:    br label [[SAME]]
365; CHECK:       same:
366; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[TMP1]], [[ENTRY_SAME_CRIT_EDGE:%.*]] ], [ [[TMP0]], [[ENTRY:%.*]] ]
367; CHECK-NEXT:    ret i32 [[TMP2]]
368;
369entry:
370  %0 = callbr i32 asm "", "=r,!i"() to label %same [label %same]
371same:
372  %1 = phi i32 [%0, %entry], [%0, %entry]
373  ret i32 %1
374}
375
376; "The Devil's cross" (i.e. two asm goto with conflicting physreg constraints
377; going to the same destination).
378define i64 @split_me6() {
379; CHECK-LABEL: @split_me6(
380; CHECK-NEXT:  entry:
381; CHECK-NEXT:    [[TMP0:%.*]] = callbr i64 asm "# $0 $1", "={dx},!i"()
382; CHECK-NEXT:    to label [[ASM_FALLTHROUGH:%.*]] [label %entry.foo_crit_edge]
383; CHECK:       entry.foo_crit_edge:
384; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.callbr.landingpad.i64(i64 [[TMP0]])
385; CHECK-NEXT:    br label [[FOO:%.*]]
386; CHECK:       asm.fallthrough:
387; CHECK-NEXT:    [[TMP2:%.*]] = callbr i64 asm "# $0 $1", "={bx},!i"()
388; CHECK-NEXT:    to label [[FOO]] [label %asm.fallthrough.foo_crit_edge]
389; CHECK:       asm.fallthrough.foo_crit_edge:
390; CHECK-NEXT:    [[TMP3:%.*]] = call i64 @llvm.callbr.landingpad.i64(i64 [[TMP2]])
391; CHECK-NEXT:    br label [[FOO]]
392; CHECK:       foo:
393; CHECK-NEXT:    [[X_0:%.*]] = phi i64 [ [[TMP1]], [[ENTRY_FOO_CRIT_EDGE:%.*]] ], [ [[TMP3]], [[ASM_FALLTHROUGH_FOO_CRIT_EDGE:%.*]] ], [ [[TMP2]], [[ASM_FALLTHROUGH]] ]
394; CHECK-NEXT:    ret i64 [[X_0]]
395;
396entry:
397  %0 = callbr i64 asm "# $0 $1", "={dx},!i"()
398  to label %asm.fallthrough [label %foo]
399
400asm.fallthrough:
401  %1 = callbr i64 asm "# $0 $1", "={bx},!i"()
402  to label %foo [label %foo]
403
404foo:
405  %x.0 = phi i64 [ %0, %entry ], [ %1, %asm.fallthrough ], [ %1, %asm.fallthrough ]
406  ret i64 %x.0
407}
408
409; Test the result of the callbr having multiple uses to avoid iterator
410; invalidation bugs in CallBrPrepare::UpdateSSA.
411define i32 @multiple_split() {
412; CHECK-LABEL: @multiple_split(
413; CHECK-NEXT:  entry:
414; CHECK-NEXT:    [[TMP0:%.*]] = callbr i32 asm "", "=r,!i"()
415; CHECK-NEXT:    to label [[X:%.*]] [label %y]
416; CHECK:       x:
417; CHECK-NEXT:    ret i32 42
418; CHECK:       y:
419; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.callbr.landingpad.i32(i32 [[TMP0]])
420; CHECK-NEXT:    [[TMP2:%.*]] = add nsw i32 [[TMP1]], [[TMP1]]
421; CHECK-NEXT:    ret i32 [[TMP2]]
422;
423entry:
424  %0 = callbr i32 asm "", "=r,!i"()
425  to label %x [label %y]
426
427x:
428  ret i32 42
429
430y:
431  %1 = add nsw i32 %0, %0
432  ret i32 %1
433}
434