blob: d06437ec5e0aeef572a0351641a81ea04a054439 [file] [log] [blame]
Sameer Sahasrabuddhe3cbbded2020-03-28 07:13:35 -04001; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
Arthur Eubanks89df0fd2020-09-21 16:52:07 -07002; RUN: opt < %s -unify-loop-exits -enable-new-pm=0 -S | FileCheck %s
Ta-Wei Tu529ecd12020-10-20 10:41:38 -07003; RUN: opt < %s -passes='lowerswitch,unify-loop-exits' -S | FileCheck %s
Sameer Sahasrabuddhe3cbbded2020-03-28 07:13:35 -04004
5; Loop consists of A and B:
6; - A is the header
7; - A and B are exiting blocks
8; - C and return are exit blocks.
9; Pattern: Value (%mytmp42) defined in exiting block (A) and used in
10; exit block (return).
11; The relevant code uses DT::dominates(Value,
12; BasicBlock). This is misnamed because it actually checks
13; strict dominance, causing the pattern to be miscompiled
14; (the use receives an undef value).
15define i32 @exiting-used-in-exit(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 {
16; CHECK-LABEL: @exiting-used-in-exit(
17; CHECK-NEXT: entry:
18; CHECK-NEXT: br label [[A:%.*]]
19; CHECK: A:
20; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4
21; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
22; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
23; CHECK: B:
24; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4
25; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP41]], 0
26; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
27; CHECK: C:
28; CHECK-NEXT: [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
29; CHECK-NEXT: br label [[RETURN:%.*]]
30; CHECK: return:
31; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[INC]], [[C:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD]] ]
32; CHECK-NEXT: ret i32 [[PHI]]
33; CHECK: loop.exit.guard:
34; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[B]] ]
35; CHECK-NEXT: [[PHI_MOVED]] = phi i32 [ [[MYTMP42]], [[A]] ], [ undef, [[B]] ]
36; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[B]] ]
37; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[C]]
38;
39entry:
40 br label %A
41
42A:
43 %mytmp42 = load i32, i32* %arg1, align 4
44 %cmp1 = icmp slt i32 %mytmp42, 0
45 br i1 %cmp1, label %B, label %return
46
47B:
48 %mytmp41 = load i32, i32* %arg2, align 4
49 %cmp = icmp slt i32 %mytmp41, 0
50 br i1 %cmp, label %A, label %C
51
52C:
53 %inc = add i32 %mytmp41, 1
54 br label %return
55
56return:
57 %phi = phi i32 [ %inc, %C ], [ %mytmp42, %A ]
58 ret i32 %phi
59}
60
61; Loop consists of A, B and C:
62; - A is the header
63; - A and C are exiting blocks
64; - B is an "internal" block that dominates exiting block C
65; - D and return are exit blocks.
66; Pattern: Value (%mytmp41) defined in internal block (B) and used in an
67; exit block (D).
68define i32 @internal-used-in-exit(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 {
69; CHECK-LABEL: @internal-used-in-exit(
70; CHECK-NEXT: entry:
71; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4
72; CHECK-NEXT: br label [[A:%.*]]
73; CHECK: A:
74; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
75; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
76; CHECK: B:
77; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4
78; CHECK-NEXT: br label [[C:%.*]]
79; CHECK: C:
80; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
81; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
82; CHECK: D:
83; CHECK-NEXT: [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
84; CHECK-NEXT: br label [[RETURN:%.*]]
85; CHECK: return:
86; CHECK-NEXT: ret i32 0
87; CHECK: loop.exit.guard:
88; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
89; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[C]] ]
90; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D:%.*]]
91;
92entry:
93 %mytmp42 = load i32, i32* %arg1, align 4
94 br label %A
95
96A:
97 %cmp1 = icmp slt i32 %mytmp42, 0
98 br i1 %cmp1, label %B, label %return
99
100B:
101 %mytmp41 = load i32, i32* %arg2, align 4
102 br label %C
103
104C:
105 %cmp = icmp slt i32 %mytmp42, 0
106 br i1 %cmp, label %A, label %D
107
108D:
109 %inc = add i32 %mytmp41, 1
110 br label %return
111
112return:
113 ret i32 0
114}
115
116; Loop consists of A, B and C:
117; - A is the header
118; - A and C are exiting blocks
119; - B is an "internal" block that dominates exiting block C
120; - D and return are exit blocks.
121; Pattern: %return contains a phi node that receives values from
122; %entry, %A and %D. This mixes all the special cases in a single phi.
123define i32 @mixed-use-in-exit(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 {
124; CHECK-LABEL: @mixed-use-in-exit(
125; CHECK-NEXT: entry:
126; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4
127; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[MYTMP42]], 0
128; CHECK-NEXT: br i1 [[CMP2]], label [[A:%.*]], label [[RETURN:%.*]]
129; CHECK: A:
130; CHECK-NEXT: [[MYTMP43:%.*]] = add i32 [[MYTMP42]], 1
131; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
132; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
133; CHECK: B:
134; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4
135; CHECK-NEXT: br label [[C:%.*]]
136; CHECK: C:
137; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
138; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
139; CHECK: D:
140; CHECK-NEXT: br label [[RETURN]]
141; CHECK: return:
142; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[ENTRY:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD]] ]
143; CHECK-NEXT: ret i32 [[PHI]]
144; CHECK: loop.exit.guard:
145; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
146; CHECK-NEXT: [[PHI_MOVED]] = phi i32 [ [[MYTMP43]], [[A]] ], [ undef, [[C]] ]
147; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[C]] ]
148; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D]]
149;
150entry:
151 %mytmp42 = load i32, i32* %arg1, align 4
152 %cmp2 = icmp slt i32 %mytmp42, 0
153 br i1 %cmp2, label %A, label %return
154
155A:
156 %mytmp43 = add i32 %mytmp42, 1
157 %cmp1 = icmp slt i32 %mytmp42, 0
158 br i1 %cmp1, label %B, label %return
159
160B:
161 %mytmp41 = load i32, i32* %arg2, align 4
162 br label %C
163
164C:
165 %cmp = icmp slt i32 %mytmp42, 0
166 br i1 %cmp, label %A, label %D
167
168D:
169 br label %return
170
171return:
172 %phi = phi i32 [ %mytmp41, %D ], [ %mytmp43, %A ], [%mytmp42, %entry]
173 ret i32 %phi
174}
175
176; Loop consists of A, B and C:
177; - A is the header
178; - A and C are exiting blocks
179; - B is an "internal" block that dominates exiting block C
180; - D and E are exit blocks.
181; Pattern: Value (%mytmp41) defined in internal block (B) and used in a
182; downstream block not related to the loop (return). The use
183; is a phi where the incoming block for %mytmp41 is not related
184; to the loop (D).
185; This pattern does not involve either the exiting blocks or
186; the exit blocks, which catches any such assumptions built
187; into the SSA reconstruction phase.
188define i32 @phi-via-external-block(i32* %arg1, i32* %arg2) local_unnamed_addr align 2 {
189; CHECK-LABEL: @phi-via-external-block(
190; CHECK-NEXT: entry:
191; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, i32* [[ARG1:%.*]], align 4
192; CHECK-NEXT: br label [[A:%.*]]
193; CHECK: A:
194; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
195; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
196; CHECK: B:
197; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, i32* [[ARG2:%.*]], align 4
198; CHECK-NEXT: br label [[C:%.*]]
199; CHECK: C:
200; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
201; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
202; CHECK: D:
203; CHECK-NEXT: br label [[RETURN:%.*]]
204; CHECK: E:
205; CHECK-NEXT: br label [[RETURN]]
206; CHECK: return:
207; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[E:%.*]] ]
208; CHECK-NEXT: ret i32 [[PHI]]
209; CHECK: loop.exit.guard:
210; CHECK-NEXT: [[GUARD_E:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
211; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ undef, [[A]] ], [ [[MYTMP41]], [[C]] ]
212; CHECK-NEXT: br i1 [[GUARD_E]], label [[E]], label [[D]]
213;
214entry:
215 %mytmp42 = load i32, i32* %arg1, align 4
216 br label %A
217
218A:
219 %cmp1 = icmp slt i32 %mytmp42, 0
220 br i1 %cmp1, label %B, label %E
221
222B:
223 %mytmp41 = load i32, i32* %arg2, align 4
224 br label %C
225
226C:
227 %cmp = icmp slt i32 %mytmp42, 0
228 br i1 %cmp, label %A, label %D
229
230D:
231 br label %return
232
233E:
234 br label %return
235
236return:
237 %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ]
238 ret i32 %phi
239}