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