1; RUN: llc < %s -march=x86-64 -mtriple=x86_64-unknown-linux-gnu -asm-verbose=false | FileCheck %s
2
3; These tests check for loop branching structure, and that the loop align
4; directive is placed in the expected place.
5
6; CodeGen should insert a branch into the middle of the loop in
7; order to avoid a branch within the loop.
8
9; CHECK-LABEL: simple:
10;      CHECK:   jmp   .LBB0_1
11; CHECK-NEXT:   align
12; CHECK-NEXT: .LBB0_2:
13; CHECK-NEXT:   callq loop_latch
14; CHECK-NEXT: .LBB0_1:
15; CHECK-NEXT:   callq loop_header
16
17define void @simple() nounwind {
18entry:
19  br label %loop
20
21loop:
22  call void @loop_header()
23  %t0 = tail call i32 @get()
24  %t1 = icmp slt i32 %t0, 0
25  br i1 %t1, label %done, label %bb
26
27bb:
28  call void @loop_latch()
29  br label %loop
30
31done:
32  call void @exit()
33  ret void
34}
35
36; CodeGen should move block_a to the top of the loop so that it
37; falls through into the loop, avoiding a branch within the loop.
38
39; CHECK-LABEL: slightly_more_involved:
40;      CHECK:   jmp .LBB1_1
41; CHECK-NEXT:   align
42; CHECK-NEXT: .LBB1_4:
43; CHECK-NEXT:   callq bar99
44; CHECK-NEXT: .LBB1_1:
45; CHECK-NEXT:   callq body
46
47define void @slightly_more_involved() nounwind {
48entry:
49  br label %loop
50
51loop:
52  call void @body()
53  %t0 = call i32 @get()
54  %t1 = icmp slt i32 %t0, 2
55  br i1 %t1, label %block_a, label %bb
56
57bb:
58  %t2 = call i32 @get()
59  %t3 = icmp slt i32 %t2, 99
60  br i1 %t3, label %exit, label %loop
61
62block_a:
63  call void @bar99()
64  br label %loop
65
66exit:
67  call void @exit()
68  ret void
69}
70
71; Same as slightly_more_involved, but block_a is now a CFG diamond with
72; fallthrough edges which should be preserved.
73; "callq block_a_merge_func" is tail duped.
74
75; CHECK-LABEL: yet_more_involved:
76;      CHECK:   jmp .LBB2_1
77; CHECK-NEXT:   align
78; CHECK-NEXT: .LBB2_5:
79; CHECK-NEXT:   callq block_a_true_func
80; CHECK-NEXT:   callq block_a_merge_func
81; CHECK-NEXT: .LBB2_1:
82; CHECK-NEXT:   callq body
83;
84; LBB2_4
85;      CHECK:   callq bar99
86; CHECK-NEXT:   callq get
87; CHECK-NEXT:   cmpl $2999, %eax
88; CHECK-NEXT:   jle .LBB2_5
89; CHECK-NEXT:   callq block_a_false_func
90; CHECK-NEXT:   callq block_a_merge_func
91; CHECK-NEXT:   jmp .LBB2_1
92
93define void @yet_more_involved() nounwind {
94entry:
95  br label %loop
96
97loop:
98  call void @body()
99  %t0 = call i32 @get()
100  %t1 = icmp slt i32 %t0, 2
101  br i1 %t1, label %block_a, label %bb
102
103bb:
104  %t2 = call i32 @get()
105  %t3 = icmp slt i32 %t2, 99
106  br i1 %t3, label %exit, label %loop
107
108block_a:
109  call void @bar99()
110  %z0 = call i32 @get()
111  %z1 = icmp slt i32 %z0, 3000
112  br i1 %z1, label %block_a_true, label %block_a_false
113
114block_a_true:
115  call void @block_a_true_func()
116  br label %block_a_merge
117
118block_a_false:
119  call void @block_a_false_func()
120  br label %block_a_merge
121
122block_a_merge:
123  call void @block_a_merge_func()
124  br label %loop
125
126exit:
127  call void @exit()
128  ret void
129}
130
131; CodeGen should move the CFG islands that are part of the loop but don't
132; conveniently fit anywhere so that they are at least contiguous with the
133; loop.
134
135; CHECK-LABEL: cfg_islands:
136;      CHECK:   jmp     .LBB3_1
137; CHECK-NEXT:   align
138; CHECK-NEXT: .LBB3_7:
139; CHECK-NEXT:   callq   bar100
140; CHECK-NEXT: .LBB3_1:
141; CHECK-NEXT:   callq   loop_header
142;      CHECK:   jl .LBB3_7
143;      CHECK:   jge .LBB3_3
144; CHECK-NEXT:   callq   bar101
145; CHECK-NEXT:   jmp     .LBB3_1
146; CHECK-NEXT:   align
147; CHECK-NEXT: .LBB3_3:
148;      CHECK:   jge .LBB3_4
149; CHECK-NEXT:   callq   bar102
150; CHECK-NEXT:   jmp     .LBB3_1
151; CHECK-NEXT: .LBB3_4:
152;      CHECK:   jl .LBB3_6
153; CHECK-NEXT:   callq   loop_latch
154; CHECK-NEXT:   jmp     .LBB3_1
155; CHECK-NEXT: .LBB3_6:
156
157define void @cfg_islands() nounwind {
158entry:
159  br label %loop
160
161loop:
162  call void @loop_header()
163  %t0 = call i32 @get()
164  %t1 = icmp slt i32 %t0, 100
165  br i1 %t1, label %block100, label %bb
166
167bb:
168  %t2 = call i32 @get()
169  %t3 = icmp slt i32 %t2, 101
170  br i1 %t3, label %block101, label %bb1
171
172bb1:
173  %t4 = call i32 @get()
174  %t5 = icmp slt i32 %t4, 102
175  br i1 %t5, label %block102, label %bb2
176
177bb2:
178  %t6 = call i32 @get()
179  %t7 = icmp slt i32 %t6, 103
180  br i1 %t7, label %exit, label %bb3
181
182bb3:
183  call void @loop_latch()
184  br label %loop
185
186exit:
187  call void @exit()
188  ret void
189
190block100:
191  call void @bar100()
192  br label %loop
193
194block101:
195  call void @bar101()
196  br label %loop
197
198block102:
199  call void @bar102()
200  br label %loop
201}
202
203; CHECK-LABEL: check_minsize:
204;      CHECK:   jmp   .LBB4_1
205; CHECK-NOT:   align
206; CHECK-NEXT: .LBB4_2:
207; CHECK-NEXT:   callq loop_latch
208; CHECK-NEXT: .LBB4_1:
209; CHECK-NEXT:   callq loop_header
210
211
212define void @check_minsize() minsize nounwind {
213entry:
214  br label %loop
215
216loop:
217  call void @loop_header()
218  %t0 = tail call i32 @get()
219  %t1 = icmp slt i32 %t0, 0
220  br i1 %t1, label %done, label %bb
221
222bb:
223  call void @loop_latch()
224  br label %loop
225
226done:
227  call void @exit()
228  ret void
229}
230
231declare void @bar99() nounwind
232declare void @bar100() nounwind
233declare void @bar101() nounwind
234declare void @bar102() nounwind
235declare void @body() nounwind
236declare void @exit() nounwind
237declare void @loop_header() nounwind
238declare void @loop_latch() nounwind
239declare i32 @get() nounwind
240declare void @block_a_true_func() nounwind
241declare void @block_a_false_func() nounwind
242declare void @block_a_merge_func() nounwind
243