[llvm] 175d68d - [ConstraintElimination] Add additional tests.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 24 13:33:06 PST 2021


Author: Florian Hahn
Date: 2021-11-24T21:32:49Z
New Revision: 175d68dd8db5fd9d892be3db46c9a8dc601ed968

URL: https://github.com/llvm/llvm-project/commit/175d68dd8db5fd9d892be3db46c9a8dc601ed968
DIFF: https://github.com/llvm/llvm-project/commit/175d68dd8db5fd9d892be3db46c9a8dc601ed968.diff

LOG: [ConstraintElimination] Add additional tests.

Added: 
    llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
    llvm/test/Transforms/ConstraintElimination/geps-inbounds-precondition-ub-in-use-blocks.ll
    llvm/test/Transforms/ConstraintElimination/uses-in-different-blocks.ll

Modified: 
    

Removed: 
    


################################################################################
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-
diff erent-blocks.ll b/llvm/test/Transforms/ConstraintElimination/uses-in-
diff erent-blocks.ll
new file mode 100644
index 0000000000000..e77fe44d380d8
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/uses-in-
diff erent-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_
diff erent_blocks(i8 %x) {
+; CHECK-LABEL: @test_conds_single_use_in_
diff erent_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_
diff erent_blocks_2(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_conds_single_use_in_
diff erent_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_
diff erent_blocks_2(i8 %x, i8 %y) {
+; CHECK-LABEL: @test_conds_multiple_uses_in_
diff erent_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
+}


        


More information about the llvm-commits mailing list