1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes='lower-switch,unify-loop-exits' -S | FileCheck %s
4 ; Loop consists of A and B:
6 ; - A and B are exiting blocks
7 ; - C and return are exit blocks.
8 ; Pattern: Value (%mytmp42) defined in exiting block (A) and used in
10 ; The relevant code uses DT::dominates(Value,
11 ; BasicBlock). This is misnamed because it actually checks
12 ; strict dominance, causing the pattern to be miscompiled
13 ; (the use receives an undef value).
14 define i32 @exiting-used-in-exit(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 {
15 ; CHECK-LABEL: @exiting-used-in-exit(
17 ; CHECK-NEXT: br label [[A:%.*]]
19 ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
20 ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
21 ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
23 ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
24 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP41]], 0
25 ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
27 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
28 ; CHECK-NEXT: br label [[RETURN:%.*]]
30 ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[INC]], [[C:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD]] ]
31 ; CHECK-NEXT: ret i32 [[PHI]]
32 ; CHECK: loop.exit.guard:
33 ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ poison, [[A]] ], [ [[MYTMP41]], [[B]] ]
34 ; CHECK-NEXT: [[PHI_MOVED]] = phi i32 [ [[MYTMP42]], [[A]] ], [ undef, [[B]] ]
35 ; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[B]] ]
36 ; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[C]]
42 %mytmp42 = load i32, ptr %arg1, align 4
43 %cmp1 = icmp slt i32 %mytmp42, 0
44 br i1 %cmp1, label %B, label %return
47 %mytmp41 = load i32, ptr %arg2, align 4
48 %cmp = icmp slt i32 %mytmp41, 0
49 br i1 %cmp, label %A, label %C
52 %inc = add i32 %mytmp41, 1
56 %phi = phi i32 [ %inc, %C ], [ %mytmp42, %A ]
60 ; Loop consists of A, B and C:
62 ; - A and C are exiting blocks
63 ; - B is an "internal" block that dominates exiting block C
64 ; - D and return are exit blocks.
65 ; Pattern: Value (%mytmp41) defined in internal block (B) and used in an
67 define i32 @internal-used-in-exit(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 {
68 ; CHECK-LABEL: @internal-used-in-exit(
70 ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
71 ; CHECK-NEXT: br label [[A:%.*]]
73 ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
74 ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
76 ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
77 ; CHECK-NEXT: br label [[C:%.*]]
79 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
80 ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
82 ; CHECK-NEXT: [[INC:%.*]] = add i32 [[MYTMP41_MOVED:%.*]], 1
83 ; CHECK-NEXT: br label [[RETURN:%.*]]
85 ; CHECK-NEXT: ret i32 0
86 ; CHECK: loop.exit.guard:
87 ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ poison, [[A]] ], [ [[MYTMP41]], [[C]] ]
88 ; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
89 ; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D:%.*]]
92 %mytmp42 = load i32, ptr %arg1, align 4
96 %cmp1 = icmp slt i32 %mytmp42, 0
97 br i1 %cmp1, label %B, label %return
100 %mytmp41 = load i32, ptr %arg2, align 4
104 %cmp = icmp slt i32 %mytmp42, 0
105 br i1 %cmp, label %A, label %D
108 %inc = add i32 %mytmp41, 1
115 ; Loop consists of A, B and C:
117 ; - A and C are exiting blocks
118 ; - B is an "internal" block that dominates exiting block C
119 ; - D and return are exit blocks.
120 ; Pattern: %return contains a phi node that receives values from
121 ; %entry, %A and %D. This mixes all the special cases in a single phi.
122 define i32 @mixed-use-in-exit(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 {
123 ; CHECK-LABEL: @mixed-use-in-exit(
125 ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
126 ; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[MYTMP42]], 0
127 ; CHECK-NEXT: br i1 [[CMP2]], label [[A:%.*]], label [[RETURN:%.*]]
129 ; CHECK-NEXT: [[MYTMP43:%.*]] = add i32 [[MYTMP42]], 1
130 ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
131 ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
133 ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
134 ; CHECK-NEXT: br label [[C:%.*]]
136 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
137 ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
139 ; CHECK-NEXT: br label [[RETURN]]
141 ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[ENTRY:%.*]] ], [ [[PHI_MOVED:%.*]], [[LOOP_EXIT_GUARD]] ]
142 ; CHECK-NEXT: ret i32 [[PHI]]
143 ; CHECK: loop.exit.guard:
144 ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ poison, [[A]] ], [ [[MYTMP41]], [[C]] ]
145 ; CHECK-NEXT: [[PHI_MOVED]] = phi i32 [ [[MYTMP43]], [[A]] ], [ undef, [[C]] ]
146 ; CHECK-NEXT: [[GUARD_RETURN:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
147 ; CHECK-NEXT: br i1 [[GUARD_RETURN]], label [[RETURN]], label [[D]]
150 %mytmp42 = load i32, ptr %arg1, align 4
151 %cmp2 = icmp slt i32 %mytmp42, 0
152 br i1 %cmp2, label %A, label %return
155 %mytmp43 = add i32 %mytmp42, 1
156 %cmp1 = icmp slt i32 %mytmp42, 0
157 br i1 %cmp1, label %B, label %return
160 %mytmp41 = load i32, ptr %arg2, align 4
164 %cmp = icmp slt i32 %mytmp42, 0
165 br i1 %cmp, label %A, label %D
171 %phi = phi i32 [ %mytmp41, %D ], [ %mytmp43, %A ], [%mytmp42, %entry]
175 ; Loop consists of A, B and C:
177 ; - A and C are exiting blocks
178 ; - B is an "internal" block that dominates exiting block C
179 ; - D and E are exit blocks.
180 ; Pattern: Value (%mytmp41) defined in internal block (B) and used in a
181 ; downstream block not related to the loop (return). The use
182 ; is a phi where the incoming block for %mytmp41 is not related
184 ; This pattern does not involve either the exiting blocks or
185 ; the exit blocks, which catches any such assumptions built
186 ; into the SSA reconstruction phase.
187 define i32 @phi-via-external-block(ptr %arg1, ptr %arg2) local_unnamed_addr align 2 {
188 ; CHECK-LABEL: @phi-via-external-block(
190 ; CHECK-NEXT: [[MYTMP42:%.*]] = load i32, ptr [[ARG1:%.*]], align 4
191 ; CHECK-NEXT: br label [[A:%.*]]
193 ; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[MYTMP42]], 0
194 ; CHECK-NEXT: br i1 [[CMP1]], label [[B:%.*]], label [[LOOP_EXIT_GUARD:%.*]]
196 ; CHECK-NEXT: [[MYTMP41:%.*]] = load i32, ptr [[ARG2:%.*]], align 4
197 ; CHECK-NEXT: br label [[C:%.*]]
199 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[MYTMP42]], 0
200 ; CHECK-NEXT: br i1 [[CMP]], label [[A]], label [[LOOP_EXIT_GUARD]]
202 ; CHECK-NEXT: br label [[RETURN:%.*]]
204 ; CHECK-NEXT: br label [[RETURN]]
206 ; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[MYTMP41_MOVED:%.*]], [[D:%.*]] ], [ [[MYTMP42]], [[E:%.*]] ]
207 ; CHECK-NEXT: ret i32 [[PHI]]
208 ; CHECK: loop.exit.guard:
209 ; CHECK-NEXT: [[MYTMP41_MOVED]] = phi i32 [ poison, [[A]] ], [ [[MYTMP41]], [[C]] ]
210 ; CHECK-NEXT: [[GUARD_E:%.*]] = phi i1 [ true, [[A]] ], [ false, [[C]] ]
211 ; CHECK-NEXT: br i1 [[GUARD_E]], label [[E]], label [[D]]
214 %mytmp42 = load i32, ptr %arg1, align 4
218 %cmp1 = icmp slt i32 %mytmp42, 0
219 br i1 %cmp1, label %B, label %E
222 %mytmp41 = load i32, ptr %arg2, align 4
226 %cmp = icmp slt i32 %mytmp42, 0
227 br i1 %cmp, label %A, label %D
236 %phi = phi i32 [ %mytmp41, %D ], [ %mytmp42, %E ]