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
| ; RUN: opt < %s -loop-unroll -S | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
; This test shows how unrolling an inner loop could break LCSSA for an outer
; loop, and there is no cheap way to recover it.
;
; In this case the inner loop, L3, is being unrolled. It only runs one
; iteration, so unrolling basically means replacing
; br i1 true, label %exit, label %L3_header
; with
; br label %exit
;
; However, this change messes up the loops structure: for instance, block
; L3_body no longer belongs to L2. It becomes an exit block for L2, so LCSSA
; phis for definitions in L2 should now be placed there. In particular, we need
; to insert such a definition for %y1.
; CHECK-LABEL: @foo1
define void @foo1() {
entry:
br label %L1_header
L1_header:
br label %L2_header
L2_header:
%y1 = phi i64 [ undef, %L1_header ], [ %x.lcssa, %L2_latch ]
br label %L3_header
L3_header:
%y2 = phi i64 [ 0, %L3_latch ], [ %y1, %L2_header ]
%x = add i64 undef, -1
br i1 true, label %L2_latch, label %L3_body
L2_latch:
%x.lcssa = phi i64 [ %x, %L3_header ]
br label %L2_header
; CHECK: L3_body:
; CHECK-NEXT: %y1.lcssa = phi i64 [ %y1, %L3_header ]
L3_body:
store i64 %y1, i64* undef
br i1 false, label %L3_latch, label %L1_latch
L3_latch:
br i1 true, label %exit, label %L3_header
L1_latch:
%y.lcssa = phi i64 [ %y2, %L3_body ]
br label %L1_header
exit:
ret void
}
; Additional tests for some corner cases.
;
; CHECK-LABEL: @foo2
define void @foo2() {
entry:
br label %L1_header
L1_header:
br label %L2_header
L2_header:
%a = phi i64 [ undef, %L1_header ], [ %dec_us, %L3_header ]
br label %L3_header
L3_header:
%b = phi i64 [ 0, %L3_latch ], [ %a, %L2_header ]
%dec_us = add i64 undef, -1
br i1 true, label %L2_header, label %L3_break_to_L1
; CHECK: L3_break_to_L1:
; CHECK-NEXT: %a.lcssa = phi i64 [ %a, %L3_header ]
L3_break_to_L1:
br i1 false, label %L3_latch, label %L1_latch
L1_latch:
%b_lcssa = phi i64 [ %b, %L3_break_to_L1 ]
br label %L1_header
L3_latch:
br i1 true, label %Exit, label %L3_header
Exit:
ret void
}
; CHECK-LABEL: @foo3
define void @foo3() {
entry:
br label %L1_header
L1_header:
%a = phi i8* [ %b, %L1_latch ], [ null, %entry ]
br i1 undef, label %L2_header, label %L1_latch
L2_header:
br i1 undef, label %L2_latch, label %L1_latch
; CHECK: L2_latch:
; CHECK-NEXT: %a.lcssa = phi i8* [ %a, %L2_header ]
L2_latch:
br i1 true, label %L2_exit, label %L2_header
L1_latch:
%b = phi i8* [ undef, %L1_header ], [ null, %L2_header ]
br label %L1_header
L2_exit:
%a_lcssa1 = phi i8* [ %a, %L2_latch ]
br label %Exit
Exit:
%a_lcssa2 = phi i8* [ %a_lcssa1, %L2_exit ]
ret void
}
; PR26688
; CHECK-LABEL: @foo4
define i8 @foo4() {
entry:
br label %L1_header
L1_header:
%x = icmp eq i32 1, 0
br label %L2_header
L2_header:
br label %L3_header
L3_header:
br i1 true, label %L2_header, label %L3_exiting
L3_exiting:
br i1 true, label %L3_body, label %L1_latch
; CHECK: L3_body:
; CHECK-NEXT: %x.lcssa = phi i1
L3_body:
br i1 %x, label %L3_latch, label %L3_latch
L3_latch:
br i1 false, label %L3_header, label %exit
L1_latch:
br label %L1_header
exit:
ret i8 0
}
; CHECK-LABEL: @foo5
define void @foo5() {
entry:
br label %outer
outer:
br label %inner1
; CHECK: inner1:
; CHECK-NOT: br i1 true
; CHECK: br label %inner2_indirect_exit
inner1:
br i1 true, label %inner2_indirect_exit.preheader, label %inner1
inner2_indirect_exit.preheader:
br label %inner2_indirect_exit
inner2_indirect_exit:
%a = phi i32 [ %b, %inner2_latch ], [ undef, %inner2_indirect_exit.preheader ]
indirectbr i8* undef, [label %inner2_latch, label %inner3, label %outer_latch]
inner2_latch:
%b = load i32, i32* undef, align 8
br label %inner2_indirect_exit
inner3:
%a.lcssa = phi i32 [ %a.lcssa, %inner3 ], [ %a, %inner2_indirect_exit ]
br i1 true, label %outer_latch.loopexit, label %inner3
outer_latch.loopexit:
%a.lcssa.lcssa = phi i32 [ %a.lcssa, %inner3 ]
br label %outer_latch
outer_latch:
br label %outer
}
|