1 ; Specifically exercise the cost modeling for non-trivial loop unswitching.
3 ; RUN: opt -passes='loop(simple-loop-unswitch<nontrivial>),verify<loops>' -unswitch-threshold=5 -S < %s | FileCheck %s
4 ; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>),verify<loops>' -unswitch-threshold=5 -S < %s | FileCheck %s
5 ; RUN: opt -passes='simple-loop-unswitch<nontrivial>' -unswitch-threshold=5 -verify-memoryssa -S < %s | FileCheck %s
11 ; First establish enough code size in the duplicated 'loop_begin' block to
12 ; suppress unswitching.
13 define void @test_no_unswitch(ptr %ptr, i1 %cond) {
14 ; CHECK-LABEL: @test_no_unswitch(
18 ; CHECK-NEXT: br label %loop_begin
20 ; We shouldn't have unswitched into any other block either.
21 ; CHECK-NOT: br i1 %cond
28 br i1 %cond, label %loop_a, label %loop_b
30 ; CHECK-NEXT: call void @x()
31 ; CHECK-NEXT: call void @x()
32 ; CHECK-NEXT: call void @x()
33 ; CHECK-NEXT: call void @x()
34 ; CHECK-NEXT: br i1 %cond, label %loop_a, label %loop_b
45 %v = load i1, ptr %ptr
46 br i1 %v, label %loop_begin, label %loop_exit
52 ; Now check that the smaller formulation of 'loop_begin' does in fact unswitch
53 ; with our low threshold.
54 define void @test_unswitch(ptr %ptr, i1 %cond) {
55 ; CHECK-LABEL: @test_unswitch(
59 ; CHECK-NEXT: [[FROZEN:%.+]] = freeze i1 %cond
60 ; CHECK-NEXT: br i1 [[FROZEN]], label %entry.split.us, label %entry.split
64 br i1 %cond, label %loop_a, label %loop_b
69 ; The 'loop_a' unswitched loop.
71 ; CHECK: entry.split.us:
72 ; CHECK-NEXT: br label %loop_begin.us
74 ; CHECK: loop_begin.us:
75 ; CHECK-NEXT: call void @x()
76 ; CHECK-NEXT: br label %loop_a.us
79 ; CHECK-NEXT: call void @a()
80 ; CHECK-NEXT: br label %loop_latch.us
82 ; CHECK: loop_latch.us:
83 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
84 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin.us, label %loop_exit.split.us
86 ; CHECK: loop_exit.split.us:
87 ; CHECK-NEXT: br label %loop_exit
92 ; The 'loop_b' unswitched loop.
95 ; CHECK-NEXT: br label %loop_begin
98 ; CHECK-NEXT: call void @x()
99 ; CHECK-NEXT: br label %loop_b
102 ; CHECK-NEXT: call void @b()
103 ; CHECK-NEXT: br label %loop_latch
106 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
107 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin, label %loop_exit.split
109 ; CHECK: loop_exit.split:
110 ; CHECK-NEXT: br label %loop_exit
113 %v = load i1, ptr %ptr
114 br i1 %v, label %loop_begin, label %loop_exit
119 ; CHECK-NEXT: ret void
122 ; Check that even with large amounts of code on either side of the unswitched
123 ; branch, if that code would be kept in only one of the unswitched clones it
124 ; doesn't contribute to the cost.
125 define void @test_unswitch_non_dup_code(ptr %ptr, i1 %cond) {
126 ; CHECK-LABEL: @test_unswitch_non_dup_code(
130 ; CHECK-NEXT: [[FROZEN:%.+]] = freeze i1 %cond
131 ; CHECK-NEXT: br i1 [[FROZEN]], label %entry.split.us, label %entry.split
135 br i1 %cond, label %loop_a, label %loop_b
143 ; The 'loop_a' unswitched loop.
145 ; CHECK: entry.split.us:
146 ; CHECK-NEXT: br label %loop_begin.us
148 ; CHECK: loop_begin.us:
149 ; CHECK-NEXT: call void @x()
150 ; CHECK-NEXT: br label %loop_a.us
153 ; CHECK-NEXT: call void @a()
154 ; CHECK-NEXT: call void @a()
155 ; CHECK-NEXT: call void @a()
156 ; CHECK-NEXT: call void @a()
157 ; CHECK-NEXT: br label %loop_latch.us
159 ; CHECK: loop_latch.us:
160 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
161 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin.us, label %loop_exit.split.us
163 ; CHECK: loop_exit.split.us:
164 ; CHECK-NEXT: br label %loop_exit
172 ; The 'loop_b' unswitched loop.
174 ; CHECK: entry.split:
175 ; CHECK-NEXT: br label %loop_begin
178 ; CHECK-NEXT: call void @x()
179 ; CHECK-NEXT: br label %loop_b
182 ; CHECK-NEXT: call void @b()
183 ; CHECK-NEXT: call void @b()
184 ; CHECK-NEXT: call void @b()
185 ; CHECK-NEXT: call void @b()
186 ; CHECK-NEXT: br label %loop_latch
189 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
190 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin, label %loop_exit.split
192 ; CHECK: loop_exit.split:
193 ; CHECK-NEXT: br label %loop_exit
196 %v = load i1, ptr %ptr
197 br i1 %v, label %loop_begin, label %loop_exit
202 ; CHECK-NEXT: ret void
205 ; Much like with non-duplicated code directly in the successor, we also won't
206 ; duplicate even interesting CFGs.
207 define void @test_unswitch_non_dup_code_in_cfg(ptr %ptr, i1 %cond) {
208 ; CHECK-LABEL: @test_unswitch_non_dup_code_in_cfg(
212 ; CHECK-NEXT: [[FROZEN:%.+]] = freeze i1 %cond
213 ; CHECK-NEXT: br i1 [[FROZEN]], label %entry.split.us, label %entry.split
217 br i1 %cond, label %loop_a, label %loop_b
220 %v1 = load i1, ptr %ptr
221 br i1 %v1, label %loop_a_a, label %loop_a_b
230 ; The 'loop_a' unswitched loop.
232 ; CHECK: entry.split.us:
233 ; CHECK-NEXT: br label %loop_begin.us
235 ; CHECK: loop_begin.us:
236 ; CHECK-NEXT: call void @x()
237 ; CHECK-NEXT: br label %loop_a.us
240 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
241 ; CHECK-NEXT: br i1 %[[V]], label %loop_a_a.us, label %loop_a_b.us
243 ; CHECK: loop_a_b.us:
244 ; CHECK-NEXT: call void @a()
245 ; CHECK-NEXT: br label %loop_latch.us
247 ; CHECK: loop_a_a.us:
248 ; CHECK-NEXT: call void @a()
249 ; CHECK-NEXT: br label %loop_latch.us
251 ; CHECK: loop_latch.us:
252 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
253 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin.us, label %loop_exit.split.us
255 ; CHECK: loop_exit.split.us:
256 ; CHECK-NEXT: br label %loop_exit
259 %v2 = load i1, ptr %ptr
260 br i1 %v2, label %loop_b_a, label %loop_b_b
269 ; The 'loop_b' unswitched loop.
271 ; CHECK: entry.split:
272 ; CHECK-NEXT: br label %loop_begin
275 ; CHECK-NEXT: call void @x()
276 ; CHECK-NEXT: br label %loop_b
279 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
280 ; CHECK-NEXT: br i1 %[[V]], label %loop_b_a, label %loop_b_b
283 ; CHECK-NEXT: call void @b()
284 ; CHECK-NEXT: br label %loop_latch
287 ; CHECK-NEXT: call void @b()
288 ; CHECK-NEXT: br label %loop_latch
291 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
292 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin, label %loop_exit.split
294 ; CHECK: loop_exit.split:
295 ; CHECK-NEXT: br label %loop_exit
298 %v3 = load i1, ptr %ptr
299 br i1 %v3, label %loop_begin, label %loop_exit
304 ; CHECK-NEXT: ret void
307 ; Check that even if there is *some* non-duplicated code on one side of an
308 ; unswitch, we don't count any other code in the loop that will in fact have to
310 define void @test_no_unswitch_non_dup_code(ptr %ptr, i1 %cond) {
311 ; CHECK-LABEL: @test_no_unswitch_non_dup_code(
315 ; CHECK-NEXT: br label %loop_begin
317 ; We shouldn't have unswitched into any other block either.
318 ; CHECK-NOT: br i1 %cond
322 br i1 %cond, label %loop_a, label %loop_b
324 ; CHECK-NEXT: call void @x()
325 ; CHECK-NEXT: br i1 %cond, label %loop_a, label %loop_b
328 %v1 = load i1, ptr %ptr
329 br i1 %v1, label %loop_a_a, label %loop_a_b
340 %v2 = load i1, ptr %ptr
341 br i1 %v2, label %loop_b_a, label %loop_b_b
354 %v = load i1, ptr %ptr
355 br i1 %v, label %loop_begin, label %loop_exit
361 ; Check that we still unswitch when the exit block contains lots of code, even
362 ; though we do clone the exit block as part of unswitching. This should work
363 ; because we should split the exit block before anything inside it.
364 define void @test_unswitch_large_exit(ptr %ptr, i1 %cond) {
365 ; CHECK-LABEL: @test_unswitch_large_exit(
369 ; CHECK-NEXT: [[FROZEN:%.+]] = freeze i1 %cond
370 ; CHECK-NEXT: br i1 [[FROZEN]], label %entry.split.us, label %entry.split
374 br i1 %cond, label %loop_a, label %loop_b
379 ; The 'loop_a' unswitched loop.
381 ; CHECK: entry.split.us:
382 ; CHECK-NEXT: br label %loop_begin.us
384 ; CHECK: loop_begin.us:
385 ; CHECK-NEXT: call void @x()
386 ; CHECK-NEXT: br label %loop_a.us
389 ; CHECK-NEXT: call void @a()
390 ; CHECK-NEXT: br label %loop_latch.us
392 ; CHECK: loop_latch.us:
393 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
394 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin.us, label %loop_exit.split.us
396 ; CHECK: loop_exit.split.us:
397 ; CHECK-NEXT: br label %loop_exit
402 ; The 'loop_b' unswitched loop.
404 ; CHECK: entry.split:
405 ; CHECK-NEXT: br label %loop_begin
408 ; CHECK-NEXT: call void @x()
409 ; CHECK-NEXT: br label %loop_b
412 ; CHECK-NEXT: call void @b()
413 ; CHECK-NEXT: br label %loop_latch
416 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
417 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin, label %loop_exit.split
419 ; CHECK: loop_exit.split:
420 ; CHECK-NEXT: br label %loop_exit
423 %v = load i1, ptr %ptr
424 br i1 %v, label %loop_begin, label %loop_exit
433 ; CHECK-NEXT: call void @x()
434 ; CHECK-NEXT: call void @x()
435 ; CHECK-NEXT: call void @x()
436 ; CHECK-NEXT: call void @x()
437 ; CHECK-NEXT: ret void
440 ; Check that we handle a dedicated exit edge unswitch which is still
441 ; non-trivial and has lots of code in the exit.
442 define void @test_unswitch_dedicated_exiting(ptr %ptr, i1 %cond) {
443 ; CHECK-LABEL: @test_unswitch_dedicated_exiting(
447 ; CHECK-NEXT: [[FROZEN:%.+]] = freeze i1 %cond
448 ; CHECK-NEXT: br i1 [[FROZEN]], label %entry.split.us, label %entry.split
452 br i1 %cond, label %loop_a, label %loop_b_exit
457 ; The 'loop_a' unswitched loop.
459 ; CHECK: entry.split.us:
460 ; CHECK-NEXT: br label %loop_begin.us
462 ; CHECK: loop_begin.us:
463 ; CHECK-NEXT: call void @x()
464 ; CHECK-NEXT: br label %loop_a.us
467 ; CHECK-NEXT: call void @a()
468 ; CHECK-NEXT: br label %loop_latch.us
470 ; CHECK: loop_latch.us:
471 ; CHECK-NEXT: %[[V:.*]] = load i1, ptr %ptr
472 ; CHECK-NEXT: br i1 %[[V]], label %loop_begin.us, label %loop_exit.split.us
474 ; CHECK: loop_exit.split.us:
475 ; CHECK-NEXT: br label %loop_exit
483 ; The 'loop_b_exit' unswitched exit path.
485 ; CHECK: entry.split:
486 ; CHECK-NEXT: br label %loop_begin
489 ; CHECK-NEXT: call void @x()
490 ; CHECK-NEXT: br label %loop_b_exit
492 ; CHECK: loop_b_exit:
493 ; CHECK-NEXT: call void @b()
494 ; CHECK-NEXT: call void @b()
495 ; CHECK-NEXT: call void @b()
496 ; CHECK-NEXT: call void @b()
497 ; CHECK-NEXT: ret void
500 %v = load i1, ptr %ptr
501 br i1 %v, label %loop_begin, label %loop_exit
506 ; CHECK-NEXT: ret void