xref: /llvm-project/llvm/test/Transforms/LoopSimplify/basictest.ll (revision 055fb7795aa219a3d274d280ec9129784f169f56)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -S -passes=loop-simplify | FileCheck %s
3
4; This function should get a preheader inserted before bb3, that is jumped
5; to by bb1 & bb2
6define void @test() {
7; CHECK-LABEL: @test(
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    br i1 true, label [[BB1:%.*]], label [[BB2:%.*]]
10; CHECK:       bb1:
11; CHECK-NEXT:    br label [[BB3_PREHEADER:%.*]]
12; CHECK:       bb2:
13; CHECK-NEXT:    br label [[BB3_PREHEADER]]
14; CHECK:       bb3.preheader:
15; CHECK-NEXT:    br label [[BB3:%.*]]
16; CHECK:       bb3:
17; CHECK-NEXT:    br label [[BB3]]
18;
19entry:
20  br i1 true, label %bb1, label %bb2
21
22bb1:
23  br label %bb3
24
25bb2:
26  br label %bb3
27
28bb3:
29  br label %bb3
30}
31
32; Test a case where we have multiple exit blocks as successors of a single loop
33; block that need to be made dedicated exit blocks. We also have multiple
34; exiting edges to one of the exit blocks that all should be rewritten.
35define void @test_multiple_exits_from_single_block(i8 %a, ptr %b.ptr) {
36; CHECK-LABEL: @test_multiple_exits_from_single_block(
37; CHECK-NEXT:  entry:
38; CHECK-NEXT:    switch i8 [[A:%.*]], label [[LOOP_PREHEADER:%.*]] [
39; CHECK-NEXT:    i8 0, label [[EXIT_A:%.*]]
40; CHECK-NEXT:    i8 1, label [[EXIT_B:%.*]]
41; CHECK-NEXT:    ]
42; CHECK:       loop.preheader:
43; CHECK-NEXT:    br label [[LOOP:%.*]]
44; CHECK:       loop:
45; CHECK-NEXT:    [[B:%.*]] = load volatile i8, ptr [[B_PTR:%.*]]
46; CHECK-NEXT:    switch i8 [[B]], label [[LOOP_BACKEDGE:%.*]] [
47; CHECK-NEXT:    i8 0, label [[EXIT_A_LOOPEXIT:%.*]]
48; CHECK-NEXT:    i8 1, label [[EXIT_B_LOOPEXIT:%.*]]
49; CHECK-NEXT:    i8 2, label [[LOOP_BACKEDGE]]
50; CHECK-NEXT:    i8 3, label [[EXIT_A_LOOPEXIT]]
51; CHECK-NEXT:    i8 4, label [[LOOP_BACKEDGE]]
52; CHECK-NEXT:    i8 5, label [[EXIT_A_LOOPEXIT]]
53; CHECK-NEXT:    i8 6, label [[LOOP_BACKEDGE]]
54; CHECK-NEXT:    ]
55; CHECK:       loop.backedge:
56; CHECK-NEXT:    br label [[LOOP]]
57; CHECK:       exit.a.loopexit:
58; CHECK-NEXT:    br label [[EXIT_A]]
59; CHECK:       exit.a:
60; CHECK-NEXT:    ret void
61; CHECK:       exit.b.loopexit:
62; CHECK-NEXT:    br label [[EXIT_B]]
63; CHECK:       exit.b:
64; CHECK-NEXT:    ret void
65;
66entry:
67  switch i8 %a, label %loop [
68  i8 0, label %exit.a
69  i8 1, label %exit.b
70  ]
71
72loop:
73  %b = load volatile i8, ptr %b.ptr
74  switch i8 %b, label %loop [
75  i8 0, label %exit.a
76  i8 1, label %exit.b
77  i8 2, label %loop
78  i8 3, label %exit.a
79  i8 4, label %loop
80  i8 5, label %exit.a
81  i8 6, label %loop
82  ]
83
84exit.a:
85  ret void
86
87exit.b:
88  ret void
89}
90
91; Check that we leave already dedicated exits alone when forming dedicated exit
92; blocks.
93define void @test_pre_existing_dedicated_exits(i1 %a, ptr %ptr) {
94; CHECK-LABEL: @test_pre_existing_dedicated_exits(
95; CHECK-NEXT:  entry:
96; CHECK-NEXT:    br i1 [[A:%.*]], label [[LOOP_PH:%.*]], label [[NON_DEDICATED_EXIT:%.*]]
97; CHECK:       loop.ph:
98; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
99; CHECK:       loop.header:
100; CHECK-NEXT:    [[C1:%.*]] = load volatile i1, ptr [[PTR:%.*]]
101; CHECK-NEXT:    br i1 [[C1]], label [[LOOP_BODY1:%.*]], label [[DEDICATED_EXIT1:%.*]]
102; CHECK:       loop.body1:
103; CHECK-NEXT:    [[C2:%.*]] = load volatile i1, ptr [[PTR]]
104; CHECK-NEXT:    br i1 [[C2]], label [[LOOP_BODY2:%.*]], label [[NON_DEDICATED_EXIT_LOOPEXIT:%.*]]
105; CHECK:       loop.body2:
106; CHECK-NEXT:    [[C3:%.*]] = load volatile i1, ptr [[PTR]]
107; CHECK-NEXT:    br i1 [[C3]], label [[LOOP_BACKEDGE:%.*]], label [[DEDICATED_EXIT2:%.*]]
108; CHECK:       loop.backedge:
109; CHECK-NEXT:    br label [[LOOP_HEADER]]
110; CHECK:       dedicated_exit1:
111; CHECK-NEXT:    ret void
112; CHECK:       dedicated_exit2:
113; CHECK-NEXT:    ret void
114; CHECK:       non_dedicated_exit.loopexit:
115; CHECK-NEXT:    br label [[NON_DEDICATED_EXIT]]
116; CHECK:       non_dedicated_exit:
117; CHECK-NEXT:    ret void
118;
119entry:
120  br i1 %a, label %loop.ph, label %non_dedicated_exit
121
122loop.ph:
123  br label %loop.header
124
125loop.header:
126  %c1 = load volatile i1, ptr %ptr
127  br i1 %c1, label %loop.body1, label %dedicated_exit1
128
129loop.body1:
130  %c2 = load volatile i1, ptr %ptr
131  br i1 %c2, label %loop.body2, label %non_dedicated_exit
132
133loop.body2:
134  %c3 = load volatile i1, ptr %ptr
135  br i1 %c3, label %loop.backedge, label %dedicated_exit2
136
137loop.backedge:
138  br label %loop.header
139
140dedicated_exit1:
141  ret void
142; Check that there isn't a split loop exit.
143
144dedicated_exit2:
145  ret void
146; Check that there isn't a split loop exit.
147
148non_dedicated_exit:
149  ret void
150}
151
152; Check that we form what dedicated exits we can even when some exits are
153; reached via indirectbr which precludes forming dedicated exits.
154define void @test_form_some_dedicated_exits_despite_indirectbr(i8 %a, ptr %ptr, ptr %addr.ptr) {
155; CHECK-LABEL: @test_form_some_dedicated_exits_despite_indirectbr(
156; CHECK-NEXT:  entry:
157; CHECK-NEXT:    switch i8 [[A:%.*]], label [[LOOP_PH:%.*]] [
158; CHECK-NEXT:    i8 0, label [[EXIT_A:%.*]]
159; CHECK-NEXT:    i8 1, label [[EXIT_B:%.*]]
160; CHECK-NEXT:    i8 2, label [[EXIT_C:%.*]]
161; CHECK-NEXT:    ]
162; CHECK:       loop.ph:
163; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
164; CHECK:       loop.header:
165; CHECK-NEXT:    [[ADDR1:%.*]] = load volatile ptr, ptr [[ADDR_PTR:%.*]]
166; CHECK-NEXT:    indirectbr ptr [[ADDR1]], [label [[LOOP_BODY1:%.*]], label %exit.a]
167; CHECK:       loop.body1:
168; CHECK-NEXT:    [[B:%.*]] = load volatile i8, ptr [[PTR:%.*]]
169; CHECK-NEXT:    switch i8 [[B]], label [[LOOP_BODY2:%.*]] [
170; CHECK-NEXT:    i8 0, label [[EXIT_A]]
171; CHECK-NEXT:    i8 1, label [[EXIT_B_LOOPEXIT:%.*]]
172; CHECK-NEXT:    i8 2, label [[EXIT_C]]
173; CHECK-NEXT:    ]
174; CHECK:       loop.body2:
175; CHECK-NEXT:    [[ADDR2:%.*]] = load volatile ptr, ptr [[ADDR_PTR]]
176; CHECK-NEXT:    indirectbr ptr [[ADDR2]], [label [[LOOP_BACKEDGE:%.*]], label %exit.c]
177; CHECK:       loop.backedge:
178; CHECK-NEXT:    br label [[LOOP_HEADER]]
179; CHECK:       exit.a:
180; CHECK-NEXT:    ret void
181; CHECK:       exit.b.loopexit:
182; CHECK-NEXT:    br label [[EXIT_B]]
183; CHECK:       exit.b:
184; CHECK-NEXT:    ret void
185; CHECK:       exit.c:
186; CHECK-NEXT:    ret void
187;
188entry:
189  switch i8 %a, label %loop.ph [
190  i8 0, label %exit.a
191  i8 1, label %exit.b
192  i8 2, label %exit.c
193  ]
194
195loop.ph:
196  br label %loop.header
197
198loop.header:
199  %addr1 = load volatile ptr, ptr %addr.ptr
200  indirectbr ptr %addr1, [label %loop.body1, label %exit.a]
201
202loop.body1:
203  %b = load volatile i8, ptr %ptr
204  switch i8 %b, label %loop.body2 [
205  i8 0, label %exit.a
206  i8 1, label %exit.b
207  i8 2, label %exit.c
208  ]
209
210loop.body2:
211  %addr2 = load volatile ptr, ptr %addr.ptr
212  indirectbr ptr %addr2, [label %loop.backedge, label %exit.c]
213
214loop.backedge:
215  br label %loop.header
216
217exit.a:
218  ret void
219; Check that there isn't a split loop exit.
220
221exit.b:
222  ret void
223
224exit.c:
225  ret void
226; Check that there isn't a split loop exit.
227}
228