; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 ; RUN: opt -passes=flattencfg -S < %s | FileCheck %s ; This test checks whether the pass completes without a crash. ; The code is not transformed in any way define void @test_not_crash(i32 %in_a) #0 { ; CHECK-LABEL: define void @test_not_crash ; CHECK-SAME: (i32 [[IN_A:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP0:%.*]] = icmp eq i32 [[IN_A]], -1 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[IN_A]], 0 ; CHECK-NEXT: [[COND0:%.*]] = and i1 [[CMP0]], [[CMP1]] ; CHECK-NEXT: br i1 [[COND0]], label [[B0:%.*]], label [[B1:%.*]] ; CHECK: b0: ; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[IN_A]], 0 ; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i32 [[IN_A]], 1 ; CHECK-NEXT: [[COND1:%.*]] = or i1 [[CMP2]], [[CMP3]] ; CHECK-NEXT: br i1 [[COND1]], label [[EXIT:%.*]], label [[B1]] ; CHECK: b1: ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry: %cmp0 = icmp eq i32 %in_a, -1 %cmp1 = icmp ne i32 %in_a, 0 %cond0 = and i1 %cmp0, %cmp1 br i1 %cond0, label %b0, label %b1 b0: ; preds = %entry %cmp2 = icmp eq i32 %in_a, 0 %cmp3 = icmp ne i32 %in_a, 1 %cond1 = or i1 %cmp2, %cmp3 br i1 %cond1, label %exit, label %b1 b1: ; preds = %entry, %b0 br label %exit exit: ; preds = %entry, %b0, %b1 ret void } define void @test_not_crash2(float %a, float %b) #0 { ; CHECK-LABEL: define void @test_not_crash2 ; CHECK-SAME: (float [[A:%.*]], float [[B:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = fcmp ult float [[A]], 1.000000e+00 ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult float [[B]], 1.000000e+00 ; CHECK-NEXT: [[TMP2:%.*]] = and i1 [[TMP0]], [[TMP1]] ; CHECK-NEXT: br i1 [[TMP2]], label [[BB4:%.*]], label [[BB3:%.*]] ; CHECK: bb3: ; CHECK-NEXT: br label [[BB4]] ; CHECK: bb4: ; CHECK-NEXT: ret void ; entry: %0 = fcmp ult float %a, 1.000000e+00 br i1 %0, label %bb0, label %bb1 bb3: ; preds = %bb0 br label %bb4 bb4: ; preds = %bb0, %bb3 ret void bb1: ; preds = %entry br label %bb0 bb0: ; preds = %bb1, %entry %1 = fcmp ult float %b, 1.000000e+00 br i1 %1, label %bb4, label %bb3 } define void @test_not_crash3(i32 %a) #0 { ; CHECK-LABEL: define void @test_not_crash3 ; CHECK-SAME: (i32 [[A:%.*]]) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A_EQ_0:%.*]] = icmp eq i32 [[A]], 0 ; CHECK-NEXT: br i1 [[A_EQ_0]], label [[BB0:%.*]], label [[BB1:%.*]] ; CHECK: bb0: ; CHECK-NEXT: br label [[BB1]] ; CHECK: bb1: ; CHECK-NEXT: [[A_EQ_1:%.*]] = icmp eq i32 [[A]], 1 ; CHECK-NEXT: br i1 [[A_EQ_1]], label [[BB2:%.*]], label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: ; CHECK-NEXT: [[CHECK_BADREF:%.*]] = phi i32 [ 17, [[BB1]] ], [ 11, [[BB2]] ] ; CHECK-NEXT: ret void ; entry: %a_eq_0 = icmp eq i32 %a, 0 br i1 %a_eq_0, label %bb0, label %bb1 bb0: ; preds = %entry br label %bb1 bb1: ; preds = %bb0, %entry %a_eq_1 = icmp eq i32 %a, 1 br i1 %a_eq_1, label %bb2, label %bb3 bb2: ; preds = %bb1 br label %bb3 bb3: ; preds = %bb2, %bb1 %check_badref = phi i32 [ 17, %bb1 ], [ 11, %bb2 ] ret void } @g = global i32 0, align 4 define void @test_then(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: define void @test_then ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { ; CHECK-NEXT: entry.x: ; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp ne i32 [[Y]], 0 ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y]] ; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN_Y:%.*]], label [[EXIT:%.*]] ; CHECK: if.then.y: ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry.x: %cmp.x = icmp ne i32 %x, 0 br i1 %cmp.x, label %if.then.x, label %entry.y if.then.x: store i32 %z, ptr @g, align 4 br label %entry.y entry.y: %cmp.y = icmp ne i32 %y, 0 br i1 %cmp.y, label %if.then.y, label %exit if.then.y: store i32 %z, ptr @g, align 4 br label %exit exit: ret void } define void @test_else(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: define void @test_else ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { ; CHECK-NEXT: entry.x: ; CHECK-NEXT: [[CMP_X:%.*]] = icmp eq i32 [[X]], 0 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0 ; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP_X]], [[CMP_Y]] ; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT:%.*]], label [[IF_ELSE_Y:%.*]] ; CHECK: if.else.y: ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry.x: %cmp.x = icmp eq i32 %x, 0 br i1 %cmp.x, label %entry.y, label %if.else.x if.else.x: store i32 %z, ptr @g, align 4 br label %entry.y entry.y: %cmp.y = icmp eq i32 %y, 0 br i1 %cmp.y, label %exit, label %if.else.y if.else.y: store i32 %z, ptr @g, align 4 br label %exit exit: ret void } define void @test_combine_and(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: define void @test_combine_and ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { ; CHECK-NEXT: entry.x: ; CHECK-NEXT: [[CMP_X:%.*]] = icmp eq i32 [[X]], 0 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0 ; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP_X]], [[CMP_Y]] ; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT:%.*]], label [[IF_THEN_Y:%.*]] ; CHECK: if.then.y: ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry.x: %cmp.x = icmp eq i32 %x, 0 br i1 %cmp.x, label %entry.y, label %if.else.x if.else.x: store i32 %z, ptr @g, align 4 br label %entry.y entry.y: %cmp.y = icmp ne i32 %y, 0 br i1 %cmp.y, label %if.then.y, label %exit if.then.y: store i32 %z, ptr @g, align 4 br label %exit exit: ret void } define void @test_combine_or(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: define void @test_combine_or ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { ; CHECK-NEXT: entry.x: ; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp ne i32 [[Y]], 0 ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y]] ; CHECK-NEXT: br i1 [[TMP0]], label [[IF_ELSE_Y:%.*]], label [[EXIT:%.*]] ; CHECK: if.else.y: ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; entry.x: %cmp.x = icmp ne i32 %x, 0 br i1 %cmp.x, label %if.then.x, label %entry.y if.then.x: store i32 %z, ptr @g, align 4 br label %entry.y entry.y: %cmp.y = icmp eq i32 %y, 0 br i1 %cmp.y, label %exit, label %if.else.y if.else.y: store i32 %z, ptr @g, align 4 br label %exit exit: ret void } declare i1 @llvm.smax.i1(i1, i1) #0 define void @PR56875(i1 %val_i1_5) { ; CHECK-LABEL: define void @PR56875 ; CHECK-SAME: (i1 [[VAL_I1_5:%.*]]) { ; CHECK-NEXT: entry_1: ; CHECK-NEXT: ret void ; CHECK: bb_2: ; CHECK-NEXT: br label [[BB_4:%.*]] ; CHECK: bb_4: ; CHECK-NEXT: [[VAL_I1_46:%.*]] = call i1 @llvm.smax.i1(i1 [[VAL_I1_5]], i1 [[VAL_I1_5]]) ; CHECK-NEXT: br i1 [[VAL_I1_46]], label [[BB_4]], label [[BB_2:%.*]] ; entry_1: ret void bb_2: ; preds = %bb_4 br label %bb_4 bb_4: ; preds = %bb_4, %bb_2 %val_i1_46 = call i1 @llvm.smax.i1(i1 %val_i1_5, i1 %val_i1_5) br i1 %val_i1_46, label %bb_4, label %bb_2 } ; cmp.y has 2 users, but should be inverted. So that a new one cmp is created instead. ; Branch condition must be replaced with a new created combined condition ; Proof of bug: https://alive2.llvm.org/ce/z/L4ps9v ; Proof of fix: https://alive2.llvm.org/ce/z/QdrG5U define i1 @test_cond_multi_use(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: define i1 @test_cond_multi_use ; CHECK-SAME: (i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) { ; CHECK-NEXT: entry.x: ; CHECK-NEXT: [[CMP_X:%.*]] = icmp ne i32 [[X]], 0 ; CHECK-NEXT: [[CMP_Y:%.*]] = icmp eq i32 [[Y]], 0 ; CHECK-NEXT: [[CMP_Y_NOT:%.*]] = xor i1 [[CMP_Y]], true ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP_X]], [[CMP_Y_NOT]] ; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN_Y:%.*]], label [[EXIT:%.*]] ; CHECK: if.then.y: ; CHECK-NEXT: store i32 [[Z]], ptr @g, align 4 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret i1 [[CMP_Y]] ; entry.x: %cmp.x = icmp ne i32 %x, 0 br i1 %cmp.x, label %if.then.x, label %entry.y if.then.x: store i32 %z, ptr @g, align 4 br label %entry.y entry.y: %cmp.y = icmp eq i32 %y, 0 br i1 %cmp.y, label %exit, label %if.then.y if.then.y: store i32 %z, ptr @g, align 4 br label %exit exit: ret i1 %cmp.y }