[llvm] c259a2b - [ConstraintElimination] Add tests for transferring info between systems.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 21 14:34:17 PDT 2022


Author: Florian Hahn
Date: 2022-06-21T23:34:03+02:00
New Revision: c259a2b94f85383b5f816ecbbccdec9df8a0d735

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

LOG: [ConstraintElimination] Add tests for transferring info between systems.

Added: 
    llvm/test/Transforms/ConstraintElimination/constants-signed-predicates.ll
    llvm/test/Transforms/ConstraintElimination/constants-unsigned-predicates.ll
    llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll
    llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed.ll

Modified: 
    llvm/test/Transforms/ConstraintElimination/sge.ll

Removed: 
    llvm/test/Transforms/ConstraintElimination/constants.ll


################################################################################
diff  --git a/llvm/test/Transforms/ConstraintElimination/constants-signed-predicates.ll b/llvm/test/Transforms/ConstraintElimination/constants-signed-predicates.ll
new file mode 100644
index 0000000000000..ada29a2e7c014
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/constants-signed-predicates.ll
@@ -0,0 +1,102 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+define i1 @test_slt() {
+; CHECK-LABEL: @test_slt(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[T_0:%.*]] = icmp slt i8 10, 11
+; CHECK-NEXT:    [[F_0:%.*]] = icmp slt i8 10, 10
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, false
+; CHECK-NEXT:    [[F_1:%.*]] = icmp slt i8 10, 9
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], false
+; CHECK-NEXT:    [[F_2:%.*]] = icmp slt i8 10, -10
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], false
+; CHECK-NEXT:    [[T_1:%.*]] = icmp slt i8 10, 11
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], true
+; CHECK-NEXT:    ret i1 [[RES_4]]
+;
+entry:
+  %t.0 = icmp slt i8 10, 11
+  %f.0 = icmp slt i8 10, 10
+  %res.1 = xor i1 %t.0, %f.0
+  %f.1 = icmp slt i8 10, 9
+  %res.2 = xor i1 %res.1, %f.1
+  %f.2 = icmp slt i8 10, -10
+  %res.3 = xor i1 %res.2, %f.2
+  %t.1 = icmp slt i8 10, 11
+  %res.4 = xor i1 %res.3, %t.1
+  ret i1 %res.4
+}
+
+define i1 @test_sgt() {
+; CHECK-LABEL: @test_sgt(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[T_0:%.*]] = icmp sgt i8 11, 10
+; CHECK-NEXT:    [[F_0:%.*]] = icmp sgt i8 10, 10
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, false
+; CHECK-NEXT:    [[F_1:%.*]] = icmp sgt i8 9, 10
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], false
+; CHECK-NEXT:    [[F_2:%.*]] = icmp sgt i8 -10, 10
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], false
+; CHECK-NEXT:    [[T_1:%.*]] = icmp sgt i8 -1, -2
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], true
+; CHECK-NEXT:    ret i1 [[RES_4]]
+;
+entry:
+  %t.0 = icmp sgt i8 11, 10
+  %f.0 = icmp sgt i8 10, 10
+  %res.1 = xor i1 %t.0, %f.0
+  %f.1 = icmp sgt i8 9, 10
+  %res.2 = xor i1 %res.1, %f.1
+  %f.2 = icmp sgt i8 -10, 10
+  %res.3 = xor i1 %res.2, %f.2
+  %t.1 = icmp sgt i8 -1, -2
+  %res.4 = xor i1 %res.3, %t.1
+  ret i1 %res.4
+}
+
+; Test cases where lhs - rhs results in constant offset.
+define i1 @test_slt_gep_1(ptr %base) {
+; CHECK-LABEL: @test_slt_gep_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i8 1
+; CHECK-NEXT:    [[T_0:%.*]] = icmp slt ptr [[BASE]], [[GEP_1]]
+; CHECK-NEXT:    [[GEP_0:%.*]] = getelementptr inbounds i8, ptr [[BASE]], i8 0
+; CHECK-NEXT:    [[F_0:%.*]] = icmp slt ptr [[BASE]], [[GEP_0]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_0]], false
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt ptr [[GEP_1]], [[BASE]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+entry:
+  %gep.1 = getelementptr inbounds i8, ptr %base, i8 1
+  %t.0 = icmp slt ptr %base, %gep.1
+  %gep.0 = getelementptr inbounds i8, ptr %base, i8 0
+  %f.0 = icmp slt ptr %base, %gep.0
+  %res.1 = xor i1 %t.0, %f.0
+  %c.1 = icmp slt ptr %gep.1, %base
+  %res.2 = xor i1 %res.1, %c.1
+  ret i1 %res.2
+}
+
+define i1 @test_slt_gep_2(ptr %base) {
+; CHECK-LABEL: @test_slt_gep_2(
+; CHECK-NEXT:    [[GEP_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i8 -1
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt ptr [[BASE]], [[GEP_SUB_1]]
+; CHECK-NEXT:    ret i1 [[C_1]]
+;
+  %gep.sub.1 = getelementptr inbounds i8, ptr %base, i8 -1
+  %c.1 = icmp slt ptr %base, %gep.sub.1
+  ret i1 %c.1
+}
+
+define i1 @test_slt_gep_3(ptr %base) {
+; CHECK-LABEL: @test_slt_gep_3(
+; CHECK-NEXT:    [[GEP_1_NOINBOUNDS:%.*]] = getelementptr i8, ptr [[BASE:%.*]], i8 1
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt ptr [[BASE]], [[GEP_1_NOINBOUNDS]]
+; CHECK-NEXT:    ret i1 [[C_1]]
+;
+  %gep.1.noinbounds = getelementptr i8, ptr %base, i8 1
+  %c.1 = icmp slt ptr %base, %gep.1.noinbounds
+  ret i1 %c.1
+}

diff  --git a/llvm/test/Transforms/ConstraintElimination/constants.ll b/llvm/test/Transforms/ConstraintElimination/constants-unsigned-predicates.ll
similarity index 59%
rename from llvm/test/Transforms/ConstraintElimination/constants.ll
rename to llvm/test/Transforms/ConstraintElimination/constants-unsigned-predicates.ll
index 896eb07aff132..e6aa6f6a88bf9 100644
--- a/llvm/test/Transforms/ConstraintElimination/constants.ll
+++ b/llvm/test/Transforms/ConstraintElimination/constants-unsigned-predicates.ll
@@ -70,75 +70,6 @@ define i1 @test_ult_gep_3(ptr %base) {
   ret i1 %c.1
 }
 
-define i1 @test_slt() {
-; CHECK-LABEL: @test_slt(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[T_0:%.*]] = icmp ult i8 10, 11
-; CHECK-NEXT:    [[F_0:%.*]] = icmp ult i8 10, 10
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, false
-; CHECK-NEXT:    [[F_1:%.*]] = icmp ult i8 10, 9
-; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], false
-; CHECK-NEXT:    [[F_2:%.*]] = icmp ult i8 10, -10
-; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], true
-; CHECK-NEXT:    ret i1 [[RES_3]]
-;
-entry:
-  %t.0 = icmp ult i8 10, 11
-  %f.0 = icmp ult i8 10, 10
-  %res.1 = xor i1 %t.0, %f.0
-  %f.1 = icmp ult i8 10, 9
-  %res.2 = xor i1 %res.1, %f.1
-  %f.2 = icmp ult i8 10, -10
-  %res.3 = xor i1 %res.2, %f.2
-  ret i1 %res.3
-}
-
-; Test cases where lhs - rhs results in constant offset.
-define i1 @test_slt_gep_1(ptr %base) {
-; CHECK-LABEL: @test_slt_gep_1(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[GEP_1:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i8 1
-; CHECK-NEXT:    [[T_0:%.*]] = icmp slt ptr [[BASE]], [[GEP_1]]
-; CHECK-NEXT:    [[GEP_0:%.*]] = getelementptr inbounds i8, ptr [[BASE]], i8 0
-; CHECK-NEXT:    [[F_0:%.*]] = icmp slt ptr [[BASE]], [[GEP_0]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_0]], false
-; CHECK-NEXT:    [[C_1:%.*]] = icmp slt ptr [[GEP_1]], [[BASE]]
-; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
-; CHECK-NEXT:    ret i1 [[RES_2]]
-;
-entry:
-  %gep.1 = getelementptr inbounds i8, ptr %base, i8 1
-  %t.0 = icmp slt ptr %base, %gep.1
-  %gep.0 = getelementptr inbounds i8, ptr %base, i8 0
-  %f.0 = icmp slt ptr %base, %gep.0
-  %res.1 = xor i1 %t.0, %f.0
-  %c.1 = icmp slt ptr %gep.1, %base
-  %res.2 = xor i1 %res.1, %c.1
-  ret i1 %res.2
-}
-
-define i1 @test_slt_gep_2(ptr %base) {
-; CHECK-LABEL: @test_slt_gep_2(
-; CHECK-NEXT:    [[GEP_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i8 -1
-; CHECK-NEXT:    [[C_1:%.*]] = icmp slt ptr [[BASE]], [[GEP_SUB_1]]
-; CHECK-NEXT:    ret i1 [[C_1]]
-;
-  %gep.sub.1 = getelementptr inbounds i8, ptr %base, i8 -1
-  %c.1 = icmp slt ptr %base, %gep.sub.1
-  ret i1 %c.1
-}
-
-define i1 @test_slt_gep_3(ptr %base) {
-; CHECK-LABEL: @test_slt_gep_3(
-; CHECK-NEXT:    [[GEP_1_NOINBOUNDS:%.*]] = getelementptr i8, ptr [[BASE:%.*]], i8 1
-; CHECK-NEXT:    [[C_1:%.*]] = icmp slt ptr [[BASE]], [[GEP_1_NOINBOUNDS]]
-; CHECK-NEXT:    ret i1 [[C_1]]
-;
-  %gep.1.noinbounds = getelementptr i8, ptr %base, i8 1
-  %c.1 = icmp slt ptr %base, %gep.1.noinbounds
-  ret i1 %c.1
-}
-
 define i1 @test_eq() {
 ; CHECK-LABEL: @test_eq(
 ; CHECK-NEXT:  entry:

diff  --git a/llvm/test/Transforms/ConstraintElimination/sge.ll b/llvm/test/Transforms/ConstraintElimination/sge.ll
index 347ed41f5aa56..d3ffa2ac69046 100644
--- a/llvm/test/Transforms/ConstraintElimination/sge.ll
+++ b/llvm/test/Transforms/ConstraintElimination/sge.ll
@@ -250,3 +250,28 @@ bb2:
 exit:
   ret i32 20
 }
+
+define i1 @sge_sgt(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @sge_sgt(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sgt i32 [[X:%.*]], -1
+; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT:    ret i1 true
+; CHECK:       else:
+; CHECK-NEXT:    [[F_1:%.*]] = icmp sge i32 [[X]], 0
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %c.1 = icmp sgt i32 %x, -1
+  br i1 %c.1, label %then, label %else
+
+then:
+  %t.1 = icmp sge i32 %x, 0
+  ret i1 %t.1
+
+else:
+  %f.1 = icmp sge i32 %x, 0
+  ret i1 %f.1
+}

diff  --git a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll
new file mode 100644
index 0000000000000..8c9b374c42f81
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned.ll
@@ -0,0 +1,649 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+define i1 @len_known_positive_via_idx_1(i8 %len, i8 %idx) {
+; CHECK-LABEL: @len_known_positive_via_idx_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_POS:%.*]] = icmp sge i8 [[IDX:%.*]], 0
+; CHECK-NEXT:    [[IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX]], [[LEN:%.*]]
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[IDX_POS]], [[IDX_SLT_LEN]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], true
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[C_2]]
+; CHECK-NEXT:    ret i1 [[RES_3]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %idx.pos = icmp sge i8 %idx, 0
+  %idx.slt.len  = icmp slt i8 %idx, %len
+  %and.1 = and i1 %idx.pos, %idx.slt.len
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %t.1 = icmp ult i8 %idx, %len
+  %t.2 = icmp sge i8 %len, 0
+  %c.1 = icmp sge i8 %len, 2
+  %c.2 = icmp sge i8 %len, 2
+  %res.1 = xor i1 %t.1, %t.2
+  %res.2 = xor i1 %res.1, %c.1
+  %res.3 = xor i1 %res.2, %c.2
+  ret i1 %res.3
+
+else:
+  ret i1 0
+}
+
+; FIXME: currently adding extra facts is dependent on the visitation order of facts.
+define i1 @len_known_positive_via_idx_2(i8 %len, i8 %idx) {
+; CHECK-LABEL: @len_known_positive_via_idx_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    [[IDX_POS:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[IDX_SLT_LEN]], [[IDX_POS]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], true
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[C_2]]
+; CHECK-NEXT:    ret i1 [[RES_3]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %idx.slt.len  = icmp slt i8 %idx, %len
+  %idx.pos = icmp sge i8 %idx, 0
+  %and.1 = and i1 %idx.slt.len, %idx.pos
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %t.1 = icmp ult i8 %idx, %len
+  %t.2 = icmp sge i8 %len, 0
+  %c.1 = icmp sge i8 %len, 2
+  %c.2 = icmp sge i8 %len, 2
+  %res.1 = xor i1 %t.1, %t.2
+  %res.2 = xor i1 %res.1, %c.1
+  %res.3 = xor i1 %res.2, %c.2
+  ret i1 %res.3
+
+else:
+  ret i1 0
+}
+
+define i1 @len_not_known_positive1(i8 %len, i8 %idx) {
+; CHECK-LABEL: @len_not_known_positive1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    br i1 [[IDX_SLT_LEN]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_3]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[RES_3]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %idx.slt.len  = icmp slt i8 %idx, %len
+  br i1 %idx.slt.len, label %then.1, label %else
+
+then.1:
+  %c.1 = icmp ult i8 %idx, %len
+  %c.2 = icmp sge i8 %len, 0
+  %c.3 = icmp sge i8 %len, 2
+  %c.4 = icmp sge i8 %len, 2
+  %res.1 = xor i1 %c.1, %c.2
+  %res.2 = xor i1 %res.1, %c.3
+  %res.3 = xor i1 %res.2, %c.4
+  ret i1 %res.3
+
+else:
+  ret i1 0
+}
+
+define i1 @len_not_known_positive2(i8 %len, i8 %idx) {
+; CHECK-LABEL: @len_not_known_positive2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    [[IDX_POS:%.*]] = icmp uge i8 [[IDX]], 0
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[IDX_SLT_LEN]], [[IDX_POS]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sge i8 [[LEN]], 2
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_3]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[RES_3]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %idx.slt.len  = icmp slt i8 %idx, %len
+  %idx.pos = icmp uge i8 %idx, 0
+  %and.1 = and i1 %idx.slt.len, %idx.pos
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %c.1 = icmp ult i8 %idx, %len
+  %c.2 = icmp sge i8 %len, 0
+  %c.3 = icmp sge i8 %len, 2
+  %c.4 = icmp sge i8 %len, 2
+  %res.1 = xor i1 %c.1, %c.2
+  %res.2 = xor i1 %res.1, %c.3
+  %res.3 = xor i1 %res.2, %c.4
+  ret i1 %res.3
+
+else:
+  ret i1 0
+}
+
+declare void @sink(ptr)
+declare void @llvm.assume(i1)
+
+define i1 @cnt_positive_sgt_against_base(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_positive_sgt_against_base(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i32 [[CNT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -1
+  tail call void @llvm.assume(i1 %cmp)
+  %add.ptr = getelementptr inbounds i32, ptr %p, i32 %cnt
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+define i1 @cnt_not_known_positive_sgt_against_base(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_not_known_positive_sgt_against_base(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -2
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i32 [[CNT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -2
+  tail call void @llvm.assume(i1 %cmp)
+  %add.ptr = getelementptr inbounds i32, ptr %p, i32 %cnt
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+define i1 @cnt_not_known_positive_uge_against_base(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_not_known_positive_uge_against_base(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[CNT:%.*]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i32 [[CNT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp ugt i32 %cnt, 0
+  tail call void @llvm.assume(i1 %cmp)
+  %add.ptr = getelementptr inbounds i32, ptr %p, i32 %cnt
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+define i1 @cnt_positive_sgt_against_base_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_positive_sgt_against_base_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -1
+  tail call void @llvm.assume(i1 %cmp)
+  %ext = zext i32 %cnt to i64
+  %add.ptr = getelementptr inbounds i32, ptr %p, i64 %ext
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+define i1 @cnt_positive_sge_against_base_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_positive_sge_against_base_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[CNT:%.*]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sge i32 %cnt, 0
+  tail call void @llvm.assume(i1 %cmp)
+  %ext = zext i32 %cnt to i64
+  %add.ptr = getelementptr inbounds i32, ptr %p, i64 %ext
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+; TODO: Even though %cnt is not known signed positive %cmp can be simplified
+; because %add.ptr uses it zero-extended.
+define i1 @cnt_not_known_positive_sgt_against_base_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_not_known_positive_sgt_against_base_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -2
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -2
+  tail call void @llvm.assume(i1 %cmp)
+  %ext = zext i32 %cnt to i64
+  %add.ptr = getelementptr inbounds i32, ptr %p, i64 %ext
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+; TODO: Even though %cnt is not known signed positive %cmp can be simplified
+; because %add.ptr uses it zero-extended.
+define i1 @cnt_not_known_positive_sge_against_base_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_not_known_positive_sge_against_base_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[CNT:%.*]], -1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sge i32 %cnt, -1
+  tail call void @llvm.assume(i1 %cmp)
+  %ext = zext i32 %cnt to i64
+  %add.ptr = getelementptr inbounds i32, ptr %p, i64 %ext
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+; TODO: Even though %cnt is not known signed positive %cmp can be simplified
+; because %add.ptr uses it zero-extended.
+define i1 @cnt_not_signed_positive_uge_against_base_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_not_signed_positive_uge_against_base_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[CNT:%.*]], 0
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i32 [[CNT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp uge ptr [[ADD_PTR]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp uge i32 %cnt, 0
+  tail call void @llvm.assume(i1 %cmp)
+  %add.ptr = getelementptr inbounds i32, ptr %p, i32 %cnt
+  %cmp.1 = icmp uge ptr %add.ptr, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  ret i1 1
+}
+
+%t = type { i32, [10 x i32] }
+
+define i1 @cnt_positive_from_assume_check_against_base_struct_ugt_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_positive_from_assume_check_against_base_struct_ugt_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -1
+; CHECK-NEXT:    tail call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[GEP_EXT:%.*]] = getelementptr inbounds [[T:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ugt ptr [[GEP_EXT]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    tail call void @sink(ptr nonnull [[P]])
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -1
+  tail call void @llvm.assume(i1 %cmp)
+  %ext = zext i32 %cnt to i64
+  %gep.ext = getelementptr inbounds %t, ptr %p, i64 0, i32 1, i64 %ext
+  %cmp.1 = icmp ugt ptr %gep.ext, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  tail call void @sink(ptr nonnull %p)
+  ret i1 1
+}
+
+define i1 @cnt_positive_from_branch_check_against_base_struct_ugt_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_positive_from_branch_check_against_base_struct_ugt_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -1
+; CHECK-NEXT:    br i1 [[CMP]], label [[CHECK:%.*]], label [[ELSE:%.*]]
+; CHECK:       check:
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[GEP_EXT:%.*]] = getelementptr inbounds [[T:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ugt ptr [[GEP_EXT]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    tail call void @sink(ptr nonnull [[P]])
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -1
+  br i1 %cmp, label %check, label %else
+
+check:
+  %ext = zext i32 %cnt to i64
+  %gep.ext = getelementptr inbounds %t, ptr %p, i64 0, i32 1, i64 %ext
+  %cmp.1 = icmp ugt ptr %gep.ext, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  tail call void @sink(ptr nonnull %p)
+  ret i1 1
+}
+
+; TODO: Even though %cnt is not known signed positive %cmp can be simplified
+; because %add.ptr uses it zero-extended.
+define i1 @cnt_not_known_positive_from_branch_check_against_base_struct_ugt_with_zext(ptr %p, i32 %cnt) {
+; CHECK-LABEL: @cnt_not_known_positive_from_branch_check_against_base_struct_ugt_with_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i32 [[CNT:%.*]], -2
+; CHECK-NEXT:    br i1 [[CMP]], label [[CHECK:%.*]], label [[ELSE:%.*]]
+; CHECK:       check:
+; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[CNT]] to i64
+; CHECK-NEXT:    [[GEP_EXT:%.*]] = getelementptr inbounds [[T:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 [[EXT]]
+; CHECK-NEXT:    [[CMP_1:%.*]] = icmp ugt ptr [[GEP_EXT]], [[P]]
+; CHECK-NEXT:    br i1 [[CMP_1]], label [[THEN:%.*]], label [[ELSE]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    tail call void @sink(ptr nonnull [[P]])
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %cmp = icmp sgt i32 %cnt, -2
+  br i1 %cmp, label %check, label %else
+
+check:
+  %ext = zext i32 %cnt to i64
+  %gep.ext = getelementptr inbounds %t, ptr %p, i64 0, i32 1, i64 %ext
+  %cmp.1 = icmp ugt ptr %gep.ext, %p
+  br i1 %cmp.1, label %then, label %else
+
+then:
+  ret i1 0
+
+else:
+  tail call void @sink(ptr nonnull %p)
+  ret i1 1
+}
+
+define i1 @sge_2(i8 %idx) {
+; CHECK-LABEL: @sge_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i8 [[IDX:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i8 [[IDX]], 2
+; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i8 [[IDX]], 1
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp uge i8 [[IDX]], 3
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    [[F_1:%.*]] = icmp ult i8 [[IDX]], 2
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[F_1]]
+; CHECK-NEXT:    ret i1 [[RES_3]]
+;
+entry:
+  %cmp = icmp sge i8 %idx, 2
+  call void @llvm.assume(i1 %cmp)
+  %t.1 = icmp uge i8 %idx, 2
+  %t.2 = icmp uge i8 %idx, 1
+  %res.1 = xor i1 %t.1, %t.2
+  %c.1 = icmp uge i8 %idx, 3
+  %res.2 = xor i1 %res.1, %c.1
+  %f.1 = icmp ult i8 %idx, 2
+  %res.3 = xor i1 %res.2, %f.1
+  ret i1 %res.3
+}
+
+define i32 @sge_2_gep(i32 %idx, ptr %src, i32 %idx.2) {
+; CHECK-LABEL: @sge_2_gep(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = sext i32 [[IDX:%.*]] to i64
+; CHECK-NEXT:    [[ADD_PTR:%.*]] = getelementptr inbounds i32, ptr [[SRC:%.*]], i64 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i32 [[IDX]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[ADD_PTR_2:%.*]] = getelementptr inbounds i32, ptr [[SRC]], i32 [[IDX_2:%.*]]
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult ptr [[SRC]], [[ADD_PTR]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult ptr [[SRC]], [[ADD_PTR_2]]
+; CHECK-NEXT:    [[X_1:%.*]] = xor i1 [[T_1]], [[C_1]]
+; CHECK-NEXT:    [[F_1:%.*]] = icmp uge ptr [[SRC]], [[ADD_PTR]]
+; CHECK-NEXT:    [[X_2:%.*]] = xor i1 [[X_1]], [[F_1]]
+; CHECK-NEXT:    br i1 [[X_2]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    ret i32 0
+; CHECK:       else:
+; CHECK-NEXT:    ret i32 10
+;
+entry:
+  %idx.ext = sext i32 %idx to i64
+  %add.ptr = getelementptr inbounds i32, ptr %src, i64 %idx.ext
+  %cmp = icmp sge i32 %idx, 2
+  call void @llvm.assume(i1 %cmp)
+  %add.ptr.2 = getelementptr inbounds i32, ptr %src, i32 %idx.2
+  %t.1 = icmp ult ptr %src, %add.ptr
+  %c.1 = icmp ult ptr %src, %add.ptr.2
+  %x.1 = xor i1 %t.1, %c.1
+  %f.1 = icmp uge ptr %src, %add.ptr
+  %x.2 = xor i1 %x.1, %f.1
+  br i1 %x.2, label %then, label %else
+
+then:
+  ret i32 0
+
+else:
+  ret i32 10
+}
+
+define i1 @sgt_known_neg(i8 %idx) {
+; CHECK-LABEL: @sgt_known_neg(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[IDX:%.*]], -1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i8 [[IDX]], 0
+; CHECK-NEXT:    [[T_2:%.*]] = icmp uge i8 [[IDX]], 1
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ugt i8 [[IDX]], -1
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+entry:
+  %cmp = icmp sgt i8 %idx, -1
+  call void @llvm.assume(i1 %cmp)
+  %t.1 = icmp uge i8 %idx, 0
+  %t.2 = icmp uge i8 %idx, 1
+  %res.1 = xor i1 %t.1, %t.2
+  %c.1 = icmp ugt i8 %idx, -1
+  %res.2 = xor i1 %res.1, %c.1
+  ret i1 %res.2
+}
+
+define i1 @sgt_known_pos(i8 %idx) {
+; CHECK-LABEL: @sgt_known_pos(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[IDX:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ugt i8 [[IDX]], 2
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ugt i8 [[IDX]], 1
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ugt i8 [[IDX]], 3
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+entry:
+  %cmp = icmp sgt i8 %idx, 2
+  call void @llvm.assume(i1 %cmp)
+  %t.1 = icmp ugt i8 %idx, 2
+  %t.2 = icmp ugt i8 %idx, 1
+  %res.1 = xor i1 %t.1, %t.2
+  %c.1 = icmp ugt i8 %idx, 3
+  %res.2 = xor i1 %res.1, %c.1
+  ret i1 %res.2
+}
+
+define i1 @slt_first_op_known_pos(i8 %idx) {
+; CHECK-LABEL: @slt_first_op_known_pos(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 2, [[IDX:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 2, [[IDX]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i8 1, [[IDX]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 3, [[IDX]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+entry:
+  %cmp = icmp slt i8 2, %idx
+  call void @llvm.assume(i1 %cmp)
+  %t.1 = icmp ult i8 2, %idx
+  %t.2 = icmp ult i8 1, %idx
+  %res.1 = xor i1 %t.1, %t.2
+  %c.1 = icmp ult i8 3, %idx
+  %res.2 = xor i1 %res.1, %c.1
+  ret i1 %res.2
+}
+
+define i1 @slt_first_op_known_neg(i8 %idx) {
+; CHECK-LABEL: @slt_first_op_known_neg(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 -2, [[IDX:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 2, [[IDX]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i8 1, [[IDX]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 3, [[IDX]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_1]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+entry:
+  %cmp = icmp slt i8 -2, %idx
+  call void @llvm.assume(i1 %cmp)
+  %t.1 = icmp ult i8 2, %idx
+  %t.2 = icmp ult i8 1, %idx
+  %res.1 = xor i1 %t.1, %t.2
+  %c.1 = icmp ult i8 3, %idx
+  %res.2 = xor i1 %res.1, %c.1
+  ret i1 %res.2
+}

diff  --git a/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed.ll b/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed.ll
new file mode 100644
index 0000000000000..7365052e4b7f6
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed.ll
@@ -0,0 +1,241 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -constraint-elimination -S %s | FileCheck %s
+
+define i1 @idx_known_positive_via_len_1(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_known_positive_via_len_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN_POS:%.*]] = icmp sge i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp ult i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[LEN_POS]], [[IDX_ULT_LEN]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_1]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_2]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_3]]
+;
+entry:
+  %len.pos = icmp sge i8 %len, 0
+  %idx.ult.len  = icmp ult i8 %idx, %len
+  %and.1 = and i1 %len.pos, %idx.ult.len
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %t.1 = icmp ult i8 %idx, %len
+  %t.2 = icmp sge i8 %idx, 0
+  %r.1 = xor i1 %t.1, %t.2
+
+  %c.1 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.1
+
+  %c.2 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.2
+  ret i1 %r.3
+
+else:
+  %c.3 = icmp sge i8 %idx, 0
+  ret i1 %c.3
+}
+
+; Like @idx_known_positive_via_len_1, but with a 
diff erent order of known facts.
+define i1 @idx_known_positive_via_len_2(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_known_positive_via_len_2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp ult i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    [[LEN_POS:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[IDX_ULT_LEN]], [[LEN_POS]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, [[T_2]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_1]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_2]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_3]]
+;
+entry:
+  %idx.ult.len  = icmp ult i8 %idx, %len
+  %len.pos = icmp sge i8 %len, 0
+  %and.1 = and i1 %idx.ult.len, %len.pos
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %t.1 = icmp ult i8 %idx, %len
+  %t.2 = icmp sge i8 %idx, 0
+  %r.1 = xor i1 %t.1, %t.2
+
+  %c.1 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.1
+
+  %c.2 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.2
+  ret i1 %r.3
+
+else:
+  %c.3 = icmp sge i8 %idx, 0
+  ret i1 %c.3
+}
+
+
+; %len >=u 0 is not enough to determine idx >=s 0.
+define i1 @idx_not_known_positive_via_len_uge(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_not_known_positive_via_len_uge(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN_POS:%.*]] = icmp uge i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp ult i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[LEN_POS]], [[IDX_ULT_LEN]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, [[C_2]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_3]]
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_5:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_5]]
+;
+entry:
+  %len.pos = icmp uge i8 %len, 0
+  %idx.ult.len  = icmp ult i8 %idx, %len
+  %and.1 = and i1 %len.pos, %idx.ult.len
+  br i1 %and.1, label %then.1, label %else
+
+then.1:
+  %c.1 = icmp ult i8 %idx, %len
+  %c.2 = icmp sge i8 %idx, 0
+  %r.1 = xor i1 %c.1, %c.2
+
+  %c.3 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.3
+
+  %c.4 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.4
+  ret i1 %r.3
+
+else:
+  %c.5 = icmp sge i8 %idx, 0
+  ret i1 %c.5
+}
+
+; There's no information about %len which could be used to determine %len >=s 0.
+define i1 @idx_not_known_positive_via_len(i8 %len, i8 %idx) {
+; CHECK-LABEL: @idx_not_known_positive_via_len(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[IDX_ULT_LEN:%.*]] = icmp ult i8 [[IDX:%.*]], [[LEN:%.*]]
+; CHECK-NEXT:    br i1 [[IDX_ULT_LEN]], label [[THEN_1:%.*]], label [[ELSE:%.*]]
+; CHECK:       then.1:
+; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[IDX]], [[LEN]]
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    [[R_1:%.*]] = xor i1 true, [[C_2]]
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[IDX]], 1
+; CHECK-NEXT:    [[R_2:%.*]] = xor i1 [[R_1]], [[C_3]]
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sge i8 [[LEN]], 1
+; CHECK-NEXT:    [[R_3:%.*]] = xor i1 [[R_2]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[R_3]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_5:%.*]] = icmp sge i8 [[IDX]], 0
+; CHECK-NEXT:    ret i1 [[C_5]]
+;
+entry:
+  %idx.ult.len  = icmp ult i8 %idx, %len
+  br i1 %idx.ult.len, label %then.1, label %else
+
+then.1:
+  %c.1 = icmp ult i8 %idx, %len
+  %c.2 = icmp sge i8 %idx, 0
+  %r.1 = xor i1 %c.1, %c.2
+
+  %c.3 = icmp sge i8 %idx, 1
+  %r.2 = xor i1 %r.1, %c.3
+
+  %c.4 = icmp sge i8 %len, 1
+  %r.3 = xor i1 %r.2, %c.4
+  ret i1 %r.3
+
+else:
+  %c.5 = icmp sge i8 %idx, 0
+  ret i1 %c.5
+}
+
+define i1 @ult_signed_pos_constant(i8 %a) {
+; CHECK-LABEL: @ult_signed_pos_constant(
+; CHECK-NEXT:    [[A_ULT_4:%.*]] = icmp ult i8 [[A:%.*]], 4
+; CHECK-NEXT:    br i1 [[A_ULT_4]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[T_0:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[T_1:%.*]] = icmp slt i8 [[A]], 4
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_0]], [[T_1]]
+; CHECK-NEXT:    [[C_0:%.*]] = icmp slt i8 [[A]], 5
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[C_0]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+; CHECK:       else:
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[C_3:%.*]] = icmp slt i8 [[A]], 4
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[C_4:%.*]] = icmp slt i8 [[A]], 5
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[C_4]]
+; CHECK-NEXT:    ret i1 [[RES_4]]
+;
+  %a.ult.4 = icmp ult i8 %a, 4
+  br i1 %a.ult.4, label %then, label %else
+
+then:
+  %t.0 = icmp sge i8 %a, 0
+  %t.1 = icmp slt i8 %a, 4
+  %res.1 = xor i1 %t.0, %t.1
+
+  %c.0 = icmp slt i8 %a, 5
+  %res.2 = xor i1 %res.1, %c.0
+  ret i1 %res.2
+
+else:
+  %c.2 = icmp sge i8 %a, 0
+  %c.3 = icmp slt i8 %a, 4
+  %res.3 = xor i1 %c.2, %c.3
+
+  %c.4 = icmp slt i8 %a, 5
+  %res.4 = xor i1 %res.3, %c.4
+
+  ret i1 %res.4
+}
+
+define i1 @ult_signed_neg_constant(i8 %a) {
+; CHECK-LABEL: @ult_signed_neg_constant(
+; CHECK-NEXT:    [[A_ULT_4:%.*]] = icmp ult i8 [[A:%.*]], -2
+; CHECK-NEXT:    br i1 [[A_ULT_4]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[C_0:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i8 [[A]], -2
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[C_0]], [[C_1]]
+; CHECK-NEXT:    ret i1 [[RES_1]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+  %a.ult.4 = icmp ult i8 %a, -2
+  br i1 %a.ult.4, label %then, label %else
+
+then:
+  %c.0 = icmp sge i8 %a, 0
+  %c.1 = icmp slt i8 %a, -2
+  %res.1 = xor i1 %c.0, %c.1
+  ret i1 %res.1
+
+else:
+  ret i1 0
+}


        


More information about the llvm-commits mailing list