1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2 ; RUN: opt -passes=flattencfg -S < %s | FileCheck %s
5 ; This test checks whether the pass completes without a crash.
6 ; The code is not transformed in any way
7 define void @test_not_crash(i32 %in_a) #0 {
8 ; CHECK-LABEL: define void @test_not_crash
9 ; CHECK-SAME: (i32 [[IN_A:%.*]]) {
11 ; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i32 [[IN_A]], -1
12 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[IN_A]], 0
13 ; CHECK-NEXT: [[COND0:%.*]] = and i1 [[CMP0]], [[CMP1]]
14 ; CHECK-NEXT: br i1 [[COND0]], label [[B0:%.*]], label [[B1:%.*]]
16 ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[IN_A]], 0
17 ; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i32 [[IN_A]], 1
18 ; CHECK-NEXT: [[COND1:%.*]] = or i1 [[CMP2]], [[CMP3]]
19 ; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[B1]]
21 ; CHECK-NEXT: br label [[EXIT]]
23 ; CHECK-NEXT: ret void
26 %cmp0 = icmp eq i32 %in_a, -1
27 %cmp1 = icmp ne i32 %in_a, 0
28 %cond0 = and i1 %cmp0, %cmp1
29 br i1 %cond0, label %b0, label %b1
32 %cmp2 = icmp eq i32 %in_a, 0
33 %cmp3 = icmp ne i32 %in_a, 1
34 %cond1 = or i1 %cmp2, %cmp3
35 br i1 %cond1, label %exit, label %b1
37 b1: ; preds = %entry, %b0
40 exit: ; preds = %entry, %b0, %b1
44 define void @test_not_crash2(float %a, float %b) #0 {
45 ; CHECK-LABEL: define void @test_not_crash2
46 ; CHECK-SAME: (float [[A:%.*]], float [[B:%.*]]) {
48 ; CHECK-NEXT: [[TMP0:%.*]] = fcmp ult float [[A]], 1.000000e+00
49 ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult float [[B]], 1.000000e+00
50 ; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP0]], [[TMP1]]
51 ; CHECK-NEXT: br i1 [[TMP2]], label [[BB4:%.*]], label [[BB3:%.*]]
53 ; CHECK-NEXT: br label [[BB4]]
55 ; CHECK-NEXT: ret void
58 %0 = fcmp ult float %a, 1.000000e+00
59 br i1 %0, label %bb0, label %bb1
64 bb4: ; preds = %bb0, %bb3
70 bb0: ; preds = %bb1, %entry
71 %1 = fcmp ult float %b, 1.000000e+00
72 br i1 %1, label %bb4, label %bb3
75 define void @test_not_crash3(i32 %a) #0 {
76 ; CHECK-LABEL: define void @test_not_crash3
77 ; CHECK-SAME: (i32 [[A:%.*]]) {
79 ; CHECK-NEXT: [[A_EQ_0:%.*]] = icmp eq i32 [[A]], 0
80 ; CHECK-NEXT: [[A_EQ_1:%.*]] = icmp eq i32 [[A]], 1
81 ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[A_EQ_0]], [[A_EQ_1]]
82 ; CHECK-NEXT: br i1 [[TMP0]], label [[BB2:%.*]], label [[BB3:%.*]]
84 ; CHECK-NEXT: br label [[BB3]]
86 ; CHECK-NEXT: [[CHECK_BADREF:%.*]] = phi i32 [ 17, [[ENTRY:%.*]] ], [ 11, [[BB2]] ]
87 ; CHECK-NEXT: ret void
90 %a_eq_0 = icmp eq i32 %a, 0
91 br i1 %a_eq_0, label %bb0, label %bb1
96 bb1: ; preds = %bb0, %entry
97 %a_eq_1 = icmp eq i32 %a, 1
98 br i1 %a_eq_1, label %bb2, label %bb3
103 bb3: ; preds = %bb2, %bb1
104 %check_badref = phi i32 [ 17, %bb1 ], [ 11, %bb2 ]
109 @g = global i32 0, align 4
111 define void @test_then(i32 %x, i32 %y, i32 %z) {
112 ; CHECK-LABEL: define void @test_then
113 ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
114 ; CHECK-NEXT: entry.x:
115 ; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0
116 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp ne i32 [[Y]], 0
117 ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y]]
118 ; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN_Y:%.*]], label [[EXIT:%.*]]
120 ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4
121 ; CHECK-NEXT: br label [[EXIT]]
123 ; CHECK-NEXT: ret void
126 %cmp.x = icmp ne i32 %x, 0
127 br i1 %cmp.x, label %if.then.x, label %entry.y
130 store i32 %z, ptr @g, align 4
134 %cmp.y = icmp ne i32 %y, 0
135 br i1 %cmp.y, label %if.then.y, label %exit
138 store i32 %z, ptr @g, align 4
145 define void @test_else(i32 %x, i32 %y, i32 %z) {
146 ; CHECK-LABEL: define void @test_else
147 ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
148 ; CHECK-NEXT: entry.x:
149 ; CHECK-NEXT: [[CMP_X:%.*]] = icmp eq i32 [[X]], 0
150 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0
151 ; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP_X]], [[CMP_Y]]
152 ; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT:%.*]], label [[IF_ELSE_Y:%.*]]
154 ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4
155 ; CHECK-NEXT: br label [[EXIT]]
157 ; CHECK-NEXT: ret void
160 %cmp.x = icmp eq i32 %x, 0
161 br i1 %cmp.x, label %entry.y, label %if.else.x
164 store i32 %z, ptr @g, align 4
168 %cmp.y = icmp eq i32 %y, 0
169 br i1 %cmp.y, label %exit, label %if.else.y
172 store i32 %z, ptr @g, align 4
179 define void @test_combine_and(i32 %x, i32 %y, i32 %z) {
180 ; CHECK-LABEL: define void @test_combine_and
181 ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
182 ; CHECK-NEXT: entry.x:
183 ; CHECK-NEXT: [[CMP_X:%.*]] = icmp eq i32 [[X]], 0
184 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0
185 ; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP_X]], [[CMP_Y]]
186 ; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT:%.*]], label [[IF_THEN_Y:%.*]]
188 ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4
189 ; CHECK-NEXT: br label [[EXIT]]
191 ; CHECK-NEXT: ret void
194 %cmp.x = icmp eq i32 %x, 0
195 br i1 %cmp.x, label %entry.y, label %if.else.x
198 store i32 %z, ptr @g, align 4
202 %cmp.y = icmp ne i32 %y, 0
203 br i1 %cmp.y, label %if.then.y, label %exit
206 store i32 %z, ptr @g, align 4
213 define void @test_combine_or(i32 %x, i32 %y, i32 %z) {
214 ; CHECK-LABEL: define void @test_combine_or
215 ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
216 ; CHECK-NEXT: entry.x:
217 ; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0
218 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp ne i32 [[Y]], 0
219 ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y]]
220 ; CHECK-NEXT: br i1 [[TMP0]], label [[IF_ELSE_Y:%.*]], label [[EXIT:%.*]]
222 ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4
223 ; CHECK-NEXT: br label [[EXIT]]
225 ; CHECK-NEXT: ret void
228 %cmp.x = icmp ne i32 %x, 0
229 br i1 %cmp.x, label %if.then.x, label %entry.y
232 store i32 %z, ptr @g, align 4
236 %cmp.y = icmp eq i32 %y, 0
237 br i1 %cmp.y, label %exit, label %if.else.y
240 store i32 %z, ptr @g, align 4
247 declare i1 @llvm.smax.i1(i1, i1) #0
249 define void @PR56875(i1 %val_i1_5) {
250 ; CHECK-LABEL: define void @PR56875
251 ; CHECK-SAME: (i1 [[VAL_I1_5:%.*]]) {
252 ; CHECK-NEXT: entry_1:
253 ; CHECK-NEXT: ret void
255 ; CHECK-NEXT: br label [[BB_4:%.*]]
257 ; CHECK-NEXT: [[VAL_I1_46:%.*]] = call i1 @llvm.smax.i1(i1 [[VAL_I1_5]], i1 [[VAL_I1_5]])
258 ; CHECK-NEXT: br i1 [[VAL_I1_46]], label [[BB_4]], label [[BB_2:%.*]]
263 bb_2: ; preds = %bb_4
266 bb_4: ; preds = %bb_4, %bb_2
267 %val_i1_46 = call i1 @llvm.smax.i1(i1 %val_i1_5, i1 %val_i1_5)
268 br i1 %val_i1_46, label %bb_4, label %bb_2
271 ; cmp.y has 2 users, but should be inverted. So that a new one cmp is created instead.
272 ; Branch condition must be replaced with a new created combined condition
273 ; Proof of bug: https://alive2.llvm.org/ce/z/L4ps9v
274 ; Proof of fix: https://alive2.llvm.org/ce/z/QdrG5U
275 define i1 @test_cond_multi_use(i32 %x, i32 %y, i32 %z) {
276 ; CHECK-LABEL: define i1 @test_cond_multi_use
277 ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
278 ; CHECK-NEXT: entry.x:
279 ; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0
280 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0
281 ; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[CMP_Y]], true
282 ; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[CMP_X]], [[TMP0]]
283 ; CHECK-NEXT: br i1 [[TMP1]], label [[IF_THEN_Y:%.*]], label [[EXIT:%.*]]
285 ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4
286 ; CHECK-NEXT: br label [[EXIT]]
288 ; CHECK-NEXT: ret i1 [[CMP_Y]]
291 %cmp.x = icmp ne i32 %x, 0
292 br i1 %cmp.x, label %if.then.x, label %entry.y
295 store i32 %z, ptr @g, align 4
299 %cmp.y = icmp eq i32 %y, 0
300 br i1 %cmp.y, label %exit, label %if.then.y
303 store i32 %z, ptr @g, align 4