diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll new file mode 100644 index 0000000000000..b14ea94f0d71c --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll @@ -0,0 +1,75 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s + +define i1 @test_second_and_condition_implied_by_first(i8 %x) { +; CHECK-LABEL: @test_second_and_condition_implied_by_first( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8 [[X:%.*]], 10 +; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i8 [[X]], 5 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_1]], [[T_1]] +; CHECK-NEXT: br i1 [[AND]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: ret i1 false +; CHECK: else: +; CHECK-NEXT: ret i1 true +; +entry: + %c.1 = icmp ugt i8 %x, 10 + %t.1 = icmp ugt i8 %x, 5 + %and = and i1 %c.1, %t.1 + br i1 %and, label %then, label %else + +then: + ret i1 0 + +else: + ret i1 1 +} + +define i1 @test_same_cond_for_and(i8 %x) { +; CHECK-LABEL: @test_same_cond_for_and( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8 [[X:%.*]], 10 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_1]], [[C_1]] +; CHECK-NEXT: br i1 [[AND]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: ret i1 false +; CHECK: else: +; CHECK-NEXT: ret i1 true +; +entry: + %c.1 = icmp ugt i8 %x, 10 + %and = and i1 %c.1, %c.1 + br i1 %and, label %then, label %else + +then: + ret i1 0 + +else: + ret i1 1 +} + +define i1 @test_second_and_condition_not_implied_by_first(i8 %x) { +; CHECK-LABEL: @test_second_and_condition_not_implied_by_first( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8 [[X:%.*]], 10 +; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i8 [[X]], 5 +; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] +; CHECK-NEXT: br i1 [[AND]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: ret i1 false +; CHECK: else: +; CHECK-NEXT: ret i1 true +; +entry: + %c.1 = icmp ugt i8 %x, 10 + %c.2 = icmp ugt i8 %x, 5 + %and = and i1 %c.2, %c.1 + br i1 %and, label %then, label %else + +then: + ret i1 0 + +else: + ret i1 1 +} diff --git a/llvm/test/Transforms/ConstraintElimination/geps-inbounds-precondition-ub-in-use-blocks.ll b/llvm/test/Transforms/ConstraintElimination/geps-inbounds-precondition-ub-in-use-blocks.ll new file mode 100644 index 0000000000000..7d4a941e36547 --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/geps-inbounds-precondition-ub-in-use-blocks.ll @@ -0,0 +1,281 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -constraint-elimination -S %s | FileCheck %s + +; Tests for using inbounds information from GEPs where the GEP only causes UB in the use blocks. + +declare void @noundef(i32* noundef) willreturn nounwind +declare void @noundef2(i32* noundef) + +declare void @use(i1) + +; %start + %n.ext is guaranteed to not overflow (due to inbounds). +; %start + %idx.ext does not overflow if %idx.ext <= %n.ext. +define i1 @inbounds_poison_is_ub_in_use_block_1(i32* %src, i32 %n, i32 %idx) { +; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @noundef(i32* [[UPPER]]) +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + call void @noundef(i32* %upper) + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.1 + +else: + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 +} + +define i1 @inbounds_poison_is_ub_in_use_block_2(i32* %src, i32 %n, i32 %idx, i1 %c) { +; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: call void @noundef(i32* [[UPPER]]) +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + call void @noundef(i32* %upper) + ret i1 %cmp.upper.1 + +else: + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 +} + +declare void @llvm.assume(i1) + +; %start + %n.ext is guaranteed to not overflow (due to inbounds). +; %start + %idx.ext does not overflow if %idx.ext <= %n.ext. +define i1 @inbounds_poison_is_ub_in_use_block_by_assume(i32* %src, i32 %n, i32 %idx) { +; CHECK-LABEL: @inbounds_poison_is_ub_in_use_block_by_assume( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[CMP_NE:%.*]] = icmp ule i32* null, [[UPPER]] +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_NE]]) +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + %cmp.ne = icmp ule i32* null, %upper + call void @llvm.assume(i1 %cmp.ne) + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.1 + +else: + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 +} + + +; %start + %n.ext is guaranteed to not overflow (due to inbounds). +; %start + %idx.ext does not overflow if %idx.ext <= %n.ext. +define i1 @inbounds_poison_is_ub_in_in_multiple_use_blocks_1(i32* %src, i32 %n, i32 %idx, i1 %c) { +; CHECK-LABEL: @inbounds_poison_is_ub_in_in_multiple_use_blocks_1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: br i1 [[C:%.*]], label [[CHECK_BB:%.*]], label [[EXIT:%.*]] +; CHECK: check.bb: +; CHECK-NEXT: call void @noundef(i32* [[UPPER]]) +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @noundef(i32* [[UPPER]]) +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; CHECK: exit: +; CHECK-NEXT: ret i1 false +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + br i1 %c, label %check.bb, label %exit + +check.bb: + call void @noundef(i32* %upper) + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + call void @noundef(i32* %upper) + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.1 + +else: + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 + +exit: + ret i1 false +} + +define i1 @may_exit_before_ub_is_caused(i32* %src, i32 %n, i32 %idx) { +; CHECK-LABEL: @may_exit_before_ub_is_caused( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: call void @use(i1 [[CMP_UPPER_1]]) +; CHECK-NEXT: call void @noundef(i32* [[UPPER]]) +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + call void @use(i1 %cmp.upper.1); + call void @noundef(i32* %upper) + ret i1 %cmp.upper.1 + +else: + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 +} + +define i1 @only_UB_in_false_block(i32* %src, i32 %n, i32 %idx) { +; CHECK-LABEL: @only_UB_in_false_block( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: call void @noundef(i32* [[UPPER]]) +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.1 + +else: + call void @noundef(i32* %upper) + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 +} + +define i1 @only_ub_by_assume_in_false_block(i32* %src, i32 %n, i32 %idx) { +; CHECK-LABEL: @only_ub_by_assume_in_false_block( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N_EXT:%.*]] = zext i32 [[N:%.*]] to i64 +; CHECK-NEXT: [[UPPER:%.*]] = getelementptr inbounds i32, i32* [[SRC:%.*]], i64 [[N_EXT]] +; CHECK-NEXT: [[CMP_IDX:%.*]] = icmp ult i32 [[IDX:%.*]], [[N]] +; CHECK-NEXT: [[IDX_EXT:%.*]] = zext i32 [[IDX]] to i64 +; CHECK-NEXT: [[SRC_IDX:%.*]] = getelementptr i32, i32* [[SRC]], i64 [[IDX_EXT]] +; CHECK-NEXT: br i1 [[CMP_IDX]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[CMP_UPPER_1:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_1]] +; CHECK: else: +; CHECK-NEXT: [[CMP_NE:%.*]] = icmp ule i32* null, [[UPPER]] +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_NE]]) +; CHECK-NEXT: [[CMP_UPPER_2:%.*]] = icmp ule i32* [[SRC_IDX]], [[UPPER]] +; CHECK-NEXT: ret i1 [[CMP_UPPER_2]] +; +entry: + %n.ext = zext i32 %n to i64 + %upper = getelementptr inbounds i32, i32* %src, i64 %n.ext + %cmp.idx = icmp ult i32 %idx, %n + %idx.ext = zext i32 %idx to i64 + %src.idx = getelementptr i32, i32* %src, i64 %idx.ext + br i1 %cmp.idx, label %then, label %else + +then: + %cmp.upper.1 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.1 + +else: + %cmp.ne = icmp ule i32* null, %upper + call void @llvm.assume(i1 %cmp.ne) + %cmp.upper.2 = icmp ule i32* %src.idx, %upper + ret i1 %cmp.upper.2 +} diff --git a/llvm/test/Transforms/ConstraintElimination/uses-in-different-blocks.ll b/llvm/test/Transforms/ConstraintElimination/uses-in-different-blocks.ll new file mode 100644 index 0000000000000..e77fe44d380d8 --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/uses-in-different-blocks.ll @@ -0,0 +1,98 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s + +define i1 @test_conds_single_use_in_different_blocks(i8 %x) { +; CHECK-LABEL: @test_conds_single_use_in_different_blocks( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8 [[X:%.*]], 10 +; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i8 [[X]], 5 +; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i8 [[X]], 5 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: ret i1 [[T_1]] +; CHECK: else: +; CHECK-NEXT: ret i1 [[C_2]] +; +entry: + %c.1 = icmp ugt i8 %x, 10 + %t.1 = icmp ugt i8 %x, 5 + %c.2 = icmp ugt i8 %x, 5 + br i1 %c.1, label %then, label %else + +then: + ret i1 %t.1 + +else: + ret i1 %c.2 +} + + +define i1 @test_conds_single_use_in_different_blocks_2(i8 %x, i8 %y) { +; CHECK-LABEL: @test_conds_single_use_in_different_blocks_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8 [[X:%.*]], 10 +; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i8 [[Y:%.*]], 5 +; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i8 [[Y]], [[X]] +; CHECK-NEXT: [[C_3:%.*]] = icmp ugt i8 [[Y]], 5 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]] +; CHECK: then.1: +; CHECK-NEXT: br i1 [[C_2]], label [[THEN_2:%.*]], label [[ELSE]] +; CHECK: then.2: +; CHECK-NEXT: ret i1 [[T_1]] +; CHECK: else: +; CHECK-NEXT: ret i1 [[C_3]] +; +entry: + %c.1 = icmp ugt i8 %x, 10 + %t.1 = icmp ugt i8 %y, 5 + %c.2 = icmp ugt i8 %y, %x + %c.3 = icmp ugt i8 %y, 5 + br i1 %c.1, label %then.1, label %else + +then.1: + br i1 %c.2, label %then.2, label %else + +then.2: + ret i1 %t.1 + +else: + ret i1 %c.3 +} + +declare void @llvm.assume(i1) + +; Only the use of %t.1 in %then.2 could be simplified, but not the one in +; %entry. +define i1 @test_conds_multiple_uses_in_different_blocks_2(i8 %x, i8 %y) { +; CHECK-LABEL: @test_conds_multiple_uses_in_different_blocks_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[C_1:%.*]] = icmp ugt i8 [[X:%.*]], 10 +; CHECK-NEXT: [[T_1:%.*]] = icmp ugt i8 [[Y:%.*]], 5 +; CHECK-NEXT: call void @llvm.assume(i1 [[T_1]]) +; CHECK-NEXT: [[C_2:%.*]] = icmp ugt i8 [[Y]], [[X]] +; CHECK-NEXT: [[C_3:%.*]] = icmp ugt i8 [[Y]], 5 +; CHECK-NEXT: br i1 [[C_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]] +; CHECK: then.1: +; CHECK-NEXT: br i1 [[C_2]], label [[THEN_2:%.*]], label [[ELSE]] +; CHECK: then.2: +; CHECK-NEXT: ret i1 true +; CHECK: else: +; CHECK-NEXT: ret i1 true +; +entry: + %c.1 = icmp ugt i8 %x, 10 + %t.1 = icmp ugt i8 %y, 5 + call void @llvm.assume(i1 %t.1) + %c.2 = icmp ugt i8 %y, %x + %c.3 = icmp ugt i8 %y, 5 + br i1 %c.1, label %then.1, label %else + +then.1: + br i1 %c.2, label %then.2, label %else + +then.2: + ret i1 %t.1 + +else: + ret i1 %c.3 +}