[llvm] 6b1396e - [ConstraintElim] Add tests for GEPs with signed predicates.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 6 07:28:15 PST 2022


Author: Florian Hahn
Date: 2022-12-06T15:27:57Z
New Revision: 6b1396e31fb57795b3e2007a0345e0859f01fd99

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

LOG: [ConstraintElim] Add tests for GEPs with signed predicates.

Added: 
    llvm/test/Transforms/ConstraintElimination/gep-arithmetic-add-signed-predicates.ll
    llvm/test/Transforms/ConstraintElimination/gep-arithmetic-signed-predicates.ll
    llvm/test/Transforms/ConstraintElimination/gep-sub-signed-predicates.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-add-signed-predicates.ll b/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-add-signed-predicates.ll
new file mode 100644
index 0000000000000..b0a869683cc60
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-add-signed-predicates.ll
@@ -0,0 +1,488 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @llvm.assume(i1 noundef) #0
+
+define i1 @n_unknown(ptr %dst, i32 %n, i32 %i) {
+; CHECK-LABEL: @n_unknown(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[N:%.*]], -1
+; CHECK-NEXT:    [[IDXPROM:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[PTR_N_SUB_1:%.*]] = getelementptr i32, ptr [[DST:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT:    [[CMP_PTR_DST:%.*]] = icmp sge ptr [[PTR_N_SUB_1]], [[DST]]
+; CHECK-NEXT:    br i1 [[CMP_PTR_DST]], label [[PRE_BB_2:%.*]], label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       pre.bb.2:
+; CHECK-NEXT:    [[PRE_2:%.*]] = icmp sge i32 [[I:%.*]], 0
+; CHECK-NEXT:    br i1 [[PRE_2]], label [[TGT_BB:%.*]], label [[EXIT]]
+; CHECK:       tgt.bb:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[I]], [[N]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+entry:
+  %sub = add i32 %n, -1
+  %idxprom = zext i32 %sub to i64
+  %ptr.n.sub.1 = getelementptr i32, ptr %dst, i64 %idxprom
+  %cmp.ptr.dst = icmp sge ptr %ptr.n.sub.1, %dst
+  br i1 %cmp.ptr.dst, label %pre.bb.2, label %exit
+
+exit:
+  ret i1 false
+
+pre.bb.2:
+  %pre.2 = icmp sge i32 %i, 0
+  br i1 %pre.2, label %tgt.bb, label %exit
+
+tgt.bb:
+  %cmp1 = icmp slt i32 %i, %n
+  ret i1 %cmp1
+}
+
+define i1 @n_known_zero_due_to_nuw(ptr %dst, i32 %n, i32 %i) {
+; CHECK-LABEL: @n_known_zero_due_to_nuw(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[N:%.*]], -1
+; CHECK-NEXT:    [[IDXPROM:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[PTR_N_SUB_1:%.*]] = getelementptr i32, ptr [[DST:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT:    [[CMP_PTR_DST:%.*]] = icmp sge ptr [[PTR_N_SUB_1]], [[DST]]
+; CHECK-NEXT:    br i1 [[CMP_PTR_DST]], label [[PRE_BB_2:%.*]], label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       pre.bb.2:
+; CHECK-NEXT:    [[PRE_2:%.*]] = icmp sge i32 [[I:%.*]], 0
+; CHECK-NEXT:    br i1 [[PRE_2]], label [[TGT_BB:%.*]], label [[EXIT]]
+; CHECK:       tgt.bb:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i32 [[I]], [[N]]
+; CHECK-NEXT:    ret i1 [[CMP1]]
+;
+entry:
+  %sub = add i32 %n, -1
+  %idxprom = zext i32 %sub to i64
+  %ptr.n.sub.1 = getelementptr i32, ptr %dst, i64 %idxprom
+  %cmp.ptr.dst = icmp sge ptr %ptr.n.sub.1, %dst
+  br i1 %cmp.ptr.dst, label %pre.bb.2, label %exit
+
+exit:
+  ret i1 false
+
+pre.bb.2:
+  %pre.2 = icmp sge i32 %i, 0
+  br i1 %pre.2, label %tgt.bb, label %exit
+
+tgt.bb:
+  %cmp1 = icmp slt i32 %i, %n
+  ret i1 %cmp1
+}
+
+define i4 @inc_ptr_N_could_be_negative(ptr %src, ptr %lower, ptr %upper, i8 %N, i8 %step) {
+; CHECK-LABEL: @inc_ptr_N_could_be_negative(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i8 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i8 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[NEXT:%.*]] = add nuw nsw i8 [[STEP]], 2
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i8 [[NEXT]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i8 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i8 %step, 0
+  %next = add nuw nsw i8 %step, 2
+  %step.slt.N = icmp slt i8 %next, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i8 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @inc_ptr_src_sge_end(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @inc_ptr_src_sge_end(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[CMP_OVERFLOW:%.*]] = icmp sgt ptr [[SRC]], [[SRC_END]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    [[OR_PRECOND_1:%.*]] = or i1 [[OR_PRECOND_0]], [[CMP_OVERFLOW]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_1]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[NEXT:%.*]] = add nuw nsw i16 [[STEP]], 2
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 [[NEXT]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %cmp.overflow = icmp sgt ptr %src, %src.end
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  %or.precond.1 = or i1 %or.precond.0, %cmp.overflow
+  br i1 %or.precond.1, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i16 %step, 0
+  %next = add nuw nsw i16 %step, 2
+  %step.slt.N = icmp slt i16 %next, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @inc_ptr_src_sge_end_no_nsw_add(ptr %src, ptr %lower, ptr %upper, i16 %idx, i16 %N, i16 %step) {
+; CHECK-LABEL: @inc_ptr_src_sge_end_no_nsw_add(
+; CHECK-NEXT:  entry.1:
+; CHECK-NEXT:    [[IDX_POS:%.*]] = icmp sge i16 [[IDX:%.*]], 0
+; CHECK-NEXT:    br i1 [[IDX_POS]], label [[ENTRY:%.*]], label [[TRAP_BB:%.*]]
+; CHECK:       entry:
+; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[IDX]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC_IDX]], [[LOWER:%.*]]
+; CHECK-NEXT:    br i1 [[CMP_SRC_START]], label [[TRAP_BB]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[NEXT:%.*]] = add i16 [[IDX]], 2
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 [[NEXT]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry.1:
+  %idx.pos = icmp sge i16 %idx, 0
+  br i1 %idx.pos, label %entry, label %trap.bb
+
+entry:
+  %src.idx = getelementptr inbounds i8, ptr %src, i16 %idx
+  %cmp.src.start = icmp slt ptr %src.idx, %lower
+  br i1 %cmp.src.start, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %next = add i16 %idx, 2
+  %src.step = getelementptr inbounds i8, ptr %src, i16 %next
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @inc_ptr_src_sge_end_no_nsw_add_sge_0(ptr %src, ptr %lower, ptr %upper, i16 %idx, i16 %N, i16 %step) {
+; CHECK-LABEL: @inc_ptr_src_sge_end_no_nsw_add_sge_0(
+; CHECK-NEXT:  entry.1:
+; CHECK-NEXT:    [[IDX_POS:%.*]] = icmp sge i16 [[IDX:%.*]], 0
+; CHECK-NEXT:    br i1 [[IDX_POS]], label [[ENTRY:%.*]], label [[TRAP_BB:%.*]]
+; CHECK:       entry:
+; CHECK-NEXT:    [[SRC_IDX:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[IDX]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC_IDX]], [[LOWER:%.*]]
+; CHECK-NEXT:    br i1 [[CMP_SRC_START]], label [[TRAP_BB]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[NEXT:%.*]] = add i16 [[IDX]], 2
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 [[NEXT]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry.1:
+  %idx.pos = icmp sge i16 %idx, 0
+  br i1 %idx.pos, label %entry, label %trap.bb
+
+entry:
+  %src.idx = getelementptr inbounds i8, ptr %src, i16 %idx
+  %cmp.src.start = icmp slt ptr %src.idx, %lower
+  br i1 %cmp.src.start, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %next = add i16 %idx, 2
+  %src.step = getelementptr inbounds i8, ptr %src, i16 %next
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+define i4 @ptr_N_step_zext_n_zext(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_step_zext_n_zext(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N_ADD_1:%.*]] = add nuw nsw i16 [[N:%.*]], 1
+; CHECK-NEXT:    [[N_ADD_1_EXT:%.*]] = zext i16 [[N_ADD_1]] to i32
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i32 [[N_ADD_1_EXT]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_ADD_1:%.*]] = add nuw nsw i16 [[STEP:%.*]], 1
+; CHECK-NEXT:    [[STEP_ADD_1_EXT:%.*]] = zext i16 [[STEP_ADD_1]] to i32
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i32 [[STEP_ADD_1_EXT]], [[N_ADD_1_EXT]]
+; CHECK-NEXT:    br i1 [[STEP_SLT_N]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i32 [[STEP_ADD_1_EXT]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %N.add.1 = add nuw nsw i16 %N, 1
+  %N.add.1.ext = zext i16 %N.add.1 to i32
+  %src.end = getelementptr inbounds i8, ptr %src, i32 %N.add.1.ext
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.add.1 = add nuw nsw i16 %step, 1
+  %step.add.1.ext = zext i16 %step.add.1 to i32
+  %step.slt.N = icmp slt i32 %step.add.1.ext, %N.add.1.ext
+  br i1 %step.slt.N, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i32 %step.add.1.ext
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_N_step_zext_n_zext_out_of_bounds(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_step_zext_n_zext_out_of_bounds(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N_ADD_2:%.*]] = add nuw nsw i16 [[N:%.*]], 2
+; CHECK-NEXT:    [[N_ADD_2_EXT:%.*]] = zext i16 [[N_ADD_2]] to i32
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i32 [[N_ADD_2_EXT]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_ADD_2:%.*]] = add nuw nsw i16 [[STEP:%.*]], 2
+; CHECK-NEXT:    [[STEP_ADD_2_EXT:%.*]] = zext i16 [[STEP_ADD_2]] to i32
+; CHECK-NEXT:    [[STEP_EXT:%.*]] = zext i16 [[STEP]] to i32
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i32 [[STEP_EXT]], [[N_ADD_2_EXT]]
+; CHECK-NEXT:    br i1 [[STEP_SLT_N]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i32 [[STEP_ADD_2_EXT]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %N.add.2 = add nuw nsw i16 %N, 2
+  %N.add.2.ext = zext i16 %N.add.2 to i32
+  %src.end = getelementptr inbounds i8, ptr %src, i32 %N.add.2.ext
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.add.2 = add nuw nsw i16 %step, 2
+  %step.add.2.ext = zext i16 %step.add.2 to i32
+  %step.ext = zext i16 %step to i32
+  %step.slt.N = icmp slt i32 %step.ext, %N.add.2.ext
+  br i1 %step.slt.N, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i32 %step.add.2.ext
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i1 @gep_count_add_1_sge_known_slt_1(i32 %count, ptr %p) {
+; CHECK-LABEL: @gep_count_add_1_sge_known_slt_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SGE:%.*]] = icmp sge i32 [[COUNT:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGE]])
+; CHECK-NEXT:    [[COUNT_EXT:%.*]] = zext i32 [[COUNT]] to i64
+; CHECK-NEXT:    [[GEP_COUNT:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[COUNT_EXT]]
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[COUNT]], -1
+; CHECK-NEXT:    [[SUB_EXT:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[GEP_SUB:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[SUB_EXT]]
+; CHECK-NEXT:    [[C:%.*]] = icmp slt ptr [[GEP_SUB]], [[GEP_COUNT]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+entry:
+  %sge = icmp sge i32 %count, 1
+  call void @llvm.assume(i1 %sge)
+  %count.ext = zext i32 %count to i64
+  %gep.count = getelementptr inbounds i32, ptr %p, i64 %count.ext
+  %sub = add nsw i32 %count, -1
+  %sub.ext = zext i32 %sub to i64
+  %gep.sub = getelementptr inbounds i32, ptr %p, i64 %sub.ext
+  %c = icmp slt ptr %gep.sub, %gep.count
+  ;%2 = icmp sge ptr %0, %p
+  ret i1 %c
+}
+
+define i1 @gep_count_add_1_sge_known_sge_1(i32 %count, ptr %p) {
+; CHECK-LABEL: @gep_count_add_1_sge_known_sge_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SGE:%.*]] = icmp sge i32 [[COUNT:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGE]])
+; CHECK-NEXT:    [[COUNT_EXT:%.*]] = zext i32 [[COUNT]] to i64
+; CHECK-NEXT:    [[GEP_COUNT:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[COUNT_EXT]]
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[COUNT]], -1
+; CHECK-NEXT:    [[SUB_EXT:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[GEP_SUB:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[SUB_EXT]]
+; CHECK-NEXT:    [[C:%.*]] = icmp sge ptr [[GEP_SUB]], [[P]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+entry:
+  %sge = icmp sge i32 %count, 1
+  call void @llvm.assume(i1 %sge)
+  %count.ext = zext i32 %count to i64
+  %gep.count = getelementptr inbounds i32, ptr %p, i64 %count.ext
+  %sub = add nsw i32 %count, -1
+  %sub.ext = zext i32 %sub to i64
+  %gep.sub = getelementptr inbounds i32, ptr %p, i64 %sub.ext
+  %c = icmp sge ptr %gep.sub, %p
+  ret i1 %c
+}
+
+define i1 @gep_count_add_2_sge_not_known_slt_1(i32 %count, ptr %p) {
+; CHECK-LABEL: @gep_count_add_2_sge_not_known_slt_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SGE:%.*]] = icmp sge i32 [[COUNT:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGE]])
+; CHECK-NEXT:    [[COUNT_EXT:%.*]] = zext i32 [[COUNT]] to i64
+; CHECK-NEXT:    [[GEP_COUNT:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[COUNT_EXT]]
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[COUNT]], -2
+; CHECK-NEXT:    [[SUB_EXT:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[GEP_SUB:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[SUB_EXT]]
+; CHECK-NEXT:    [[C:%.*]] = icmp slt ptr [[GEP_SUB]], [[GEP_COUNT]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+entry:
+  %sge = icmp sge i32 %count, 1
+  call void @llvm.assume(i1 %sge)
+  %count.ext = zext i32 %count to i64
+  %gep.count = getelementptr inbounds i32, ptr %p, i64 %count.ext
+  %sub = add nsw i32 %count, -2
+  %sub.ext = zext i32 %sub to i64
+  %gep.sub = getelementptr inbounds i32, ptr %p, i64 %sub.ext
+  %c = icmp slt ptr %gep.sub, %gep.count
+  ret i1 %c
+}
+
+define i1 @gep_count_add_2_sge_not_known_sge_1(i32 %count, ptr %p) {
+; CHECK-LABEL: @gep_count_add_2_sge_not_known_sge_1(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SGE:%.*]] = icmp sge i32 [[COUNT:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGE]])
+; CHECK-NEXT:    [[COUNT_EXT:%.*]] = zext i32 [[COUNT]] to i64
+; CHECK-NEXT:    [[GEP_COUNT:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[COUNT_EXT]]
+; CHECK-NEXT:    [[SUB:%.*]] = add nsw i32 [[COUNT]], -2
+; CHECK-NEXT:    [[SUB_EXT:%.*]] = zext i32 [[SUB]] to i64
+; CHECK-NEXT:    [[GEP_SUB:%.*]] = getelementptr inbounds i32, ptr [[P]], i64 [[SUB_EXT]]
+; CHECK-NEXT:    [[C:%.*]] = icmp sge ptr [[GEP_SUB]], [[P]]
+; CHECK-NEXT:    ret i1 [[C]]
+;
+entry:
+  %sge = icmp sge i32 %count, 1
+  call void @llvm.assume(i1 %sge)
+  %count.ext = zext i32 %count to i64
+  %gep.count = getelementptr inbounds i32, ptr %p, i64 %count.ext
+  %sub = add nsw i32 %count, -2
+  %sub.ext = zext i32 %sub to i64
+  %gep.sub = getelementptr inbounds i32, ptr %p, i64 %sub.ext
+  %c = icmp sge ptr %gep.sub, %p
+  ret i1 %c
+}

diff  --git a/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-signed-predicates.ll b/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-signed-predicates.ll
new file mode 100644
index 0000000000000..653fe44bdcd63
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/gep-arithmetic-signed-predicates.ll
@@ -0,0 +1,657 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @llvm.assume(i1 noundef) #0
+
+define i1 @gep_constant_positive_index(ptr %dst, ptr %lower, ptr %upper) {
+; CHECK-LABEL: @gep_constant_positive_index(
+; CHECK-NEXT:    [[DST_ADD_4:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i64 4
+; CHECK-NEXT:    [[PRE_DST_LOWER:%.*]] = icmp sge ptr [[DST]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[PRE_DST_UPPER:%.*]] = icmp slt ptr [[DST_ADD_4]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[PRE_DST_LOWER]], [[PRE_DST_UPPER]]
+; CHECK-NEXT:    br i1 [[AND]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[CMP_DST_LOWER:%.*]] = icmp sge ptr [[DST]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_UPPER:%.*]] = icmp slt ptr [[DST]], [[UPPER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, [[CMP_DST_UPPER]]
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[CMP_DST_ADD_3_LOWER:%.*]] = icmp sge ptr [[DST_ADD_3]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_ADD_3_UPPER:%.*]] = icmp slt ptr [[DST_ADD_3]], [[UPPER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_DST_ADD_3_LOWER]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[CMP_DST_ADD_3_UPPER]]
+; CHECK-NEXT:    [[CMP_DST_ADD_4_LOWER:%.*]] = icmp sge ptr [[DST_ADD_4]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_ADD_4_UPPER:%.*]] = icmp slt ptr [[DST_ADD_4]], [[UPPER]]
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[CMP_DST_ADD_4_LOWER]]
+; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_4]], true
+; CHECK-NEXT:    [[DST_ADD_5:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 5
+; CHECK-NEXT:    [[CMP_DST_ADD_5_LOWER:%.*]] = icmp sge ptr [[DST_ADD_5]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_ADD_5_UPPER:%.*]] = icmp slt ptr [[DST_ADD_5]], [[UPPER]]
+; CHECK-NEXT:    [[RES_6:%.*]] = xor i1 [[RES_5]], [[CMP_DST_ADD_5_LOWER]]
+; CHECK-NEXT:    [[RES_7:%.*]] = xor i1 [[RES_6]], [[CMP_DST_ADD_5_UPPER]]
+; CHECK-NEXT:    ret i1 [[RES_7]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 false
+;
+  %dst.add.4 = getelementptr inbounds i8, ptr %dst, i64 4
+  %pre.dst.lower = icmp sge ptr %dst, %lower
+  %pre.dst.upper = icmp slt ptr %dst.add.4, %upper
+  %and = and i1 %pre.dst.lower, %pre.dst.upper
+  br i1 %and, label %then, label %else
+
+then:
+  %cmp.dst.lower = icmp sge ptr %dst, %lower
+  %cmp.dst.upper = icmp slt ptr %dst, %upper
+  %res.1 = xor i1 %cmp.dst.lower, %cmp.dst.upper
+  %dst.add.3 = getelementptr inbounds i8, ptr %dst, i64 3
+  %cmp.dst.add.3.lower = icmp sge ptr %dst.add.3, %lower
+  %cmp.dst.add.3.upper = icmp slt ptr %dst.add.3, %upper
+  %res.2 = xor i1 %res.1, %cmp.dst.add.3.lower
+  %res.3 = xor i1 %res.2, %cmp.dst.add.3.upper
+  %cmp.dst.add.4.lower = icmp sge ptr %dst.add.4, %lower
+  %cmp.dst.add.4.upper = icmp slt ptr %dst.add.4, %upper
+  %res.4 = xor i1 %res.3, %cmp.dst.add.4.lower
+  %res.5 = xor i1 %res.4, %cmp.dst.add.4.upper
+  %dst.add.5 = getelementptr inbounds i8, ptr %dst, i64 5
+  %cmp.dst.add.5.lower = icmp sge ptr %dst.add.5, %lower
+  %cmp.dst.add.5.upper = icmp slt ptr %dst.add.5, %upper
+  %res.6 = xor i1 %res.5, %cmp.dst.add.5.lower
+  %res.7 = xor i1 %res.6, %cmp.dst.add.5.upper
+  ret i1 %res.7
+
+else:
+  ret i1 false
+}
+
+define i1 @gep_constant_negative_index(ptr %dst, ptr %lower, ptr %upper) {
+; CHECK-LABEL: @gep_constant_negative_index(
+; CHECK-NEXT:    [[DST_SUB_4:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i64 -4
+; CHECK-NEXT:    [[PRE_DST_LOWER:%.*]] = icmp sge ptr [[DST]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[PRE_DST_UPPER:%.*]] = icmp slt ptr [[DST_SUB_4]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[PRE_DST_LOWER]], [[PRE_DST_UPPER]]
+; CHECK-NEXT:    br i1 [[AND]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[CMP_DST_LOWER:%.*]] = icmp sge ptr [[DST]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_UPPER:%.*]] = icmp slt ptr [[DST]], [[UPPER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, [[CMP_DST_UPPER]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 -3
+; CHECK-NEXT:    [[CMP_DST_SUB_3_LOWER:%.*]] = icmp sge ptr [[DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_SUB_3_UPPER:%.*]] = icmp slt ptr [[DST_SUB_3]], [[UPPER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_DST_SUB_3_LOWER]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[CMP_DST_SUB_3_UPPER]]
+; CHECK-NEXT:    [[CMP_DST_SUB_4_LOWER:%.*]] = icmp sge ptr [[DST_SUB_4]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_SUB_4_UPPER:%.*]] = icmp slt ptr [[DST_SUB_4]], [[UPPER]]
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[CMP_DST_SUB_4_LOWER]]
+; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_4]], true
+; CHECK-NEXT:    [[DST_SUB_5:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 -5
+; CHECK-NEXT:    [[CMP_DST_SUB_5_LOWER:%.*]] = icmp sge ptr [[DST_SUB_5]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_DST_SUB_5_UPPER:%.*]] = icmp slt ptr [[DST_SUB_5]], [[UPPER]]
+; CHECK-NEXT:    [[RES_6:%.*]] = xor i1 [[RES_5]], [[CMP_DST_SUB_5_LOWER]]
+; CHECK-NEXT:    [[RES_7:%.*]] = xor i1 [[RES_6]], [[CMP_DST_SUB_5_UPPER]]
+; CHECK-NEXT:    ret i1 [[RES_7]]
+; CHECK:       else:
+; CHECK-NEXT:    [[ELSE_CMP_DST_LOWER:%.*]] = icmp sge ptr [[DST]], [[LOWER]]
+; CHECK-NEXT:    [[ELSE_CMP_DST_UPPER:%.*]] = icmp slt ptr [[DST]], [[UPPER]]
+; CHECK-NEXT:    [[ELSE_RES_1:%.*]] = xor i1 [[ELSE_CMP_DST_LOWER]], [[ELSE_CMP_DST_UPPER]]
+; CHECK-NEXT:    [[ELSE_DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 -3
+; CHECK-NEXT:    [[ELSE_CMP_DST_SUB_3_LOWER:%.*]] = icmp sge ptr [[ELSE_DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[ELSE_CMP_DST_SUB_3_UPPER:%.*]] = icmp slt ptr [[ELSE_DST_SUB_3]], [[UPPER]]
+; CHECK-NEXT:    [[ELSE_RES_2:%.*]] = xor i1 [[ELSE_RES_1]], [[ELSE_CMP_DST_SUB_3_LOWER]]
+; CHECK-NEXT:    [[ELSE_RES_3:%.*]] = xor i1 [[ELSE_RES_2]], [[ELSE_CMP_DST_SUB_3_UPPER]]
+; CHECK-NEXT:    [[ELSE_CMP_DST_SUB_4_LOWER:%.*]] = icmp sge ptr [[DST_SUB_4]], [[LOWER]]
+; CHECK-NEXT:    [[ELSE_CMP_DST_SUB_4_UPPER:%.*]] = icmp slt ptr [[DST_SUB_4]], [[UPPER]]
+; CHECK-NEXT:    [[ELSE_RES_4:%.*]] = xor i1 [[ELSE_RES_3]], [[ELSE_CMP_DST_SUB_4_LOWER]]
+; CHECK-NEXT:    [[ELSE_RES_5:%.*]] = xor i1 [[ELSE_RES_4]], [[ELSE_CMP_DST_SUB_4_UPPER]]
+; CHECK-NEXT:    [[ELSE_DST_SUB_5:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 -5
+; CHECK-NEXT:    [[ELSE_CMP_DST_SUB_5_LOWER:%.*]] = icmp sge ptr [[ELSE_DST_SUB_5]], [[LOWER]]
+; CHECK-NEXT:    [[ELSE_CMP_DST_SUB_5_UPPER:%.*]] = icmp slt ptr [[ELSE_DST_SUB_5]], [[UPPER]]
+; CHECK-NEXT:    [[ELSE_RES_6:%.*]] = xor i1 [[ELSE_RES_5]], [[ELSE_CMP_DST_SUB_5_LOWER]]
+; CHECK-NEXT:    [[ELSE_RES_7:%.*]] = xor i1 [[ELSE_RES_6]], [[ELSE_CMP_DST_SUB_5_UPPER]]
+; CHECK-NEXT:    ret i1 [[ELSE_RES_7]]
+;
+  %dst.sub.4 = getelementptr inbounds i8, ptr %dst, i64 -4
+  %pre.dst.lower = icmp sge ptr %dst, %lower
+  %pre.dst.upper = icmp slt ptr %dst.sub.4, %upper
+  %and = and i1 %pre.dst.lower, %pre.dst.upper
+  br i1 %and, label %then, label %else
+
+then:
+  %cmp.dst.lower = icmp sge ptr %dst, %lower
+  %cmp.dst.upper = icmp slt ptr %dst, %upper
+  %res.1 = xor i1 %cmp.dst.lower, %cmp.dst.upper
+  %dst.sub.3 = getelementptr inbounds i8, ptr %dst, i64 -3
+  %cmp.dst.sub.3.lower = icmp sge ptr %dst.sub.3, %lower
+  %cmp.dst.sub.3.upper = icmp slt ptr %dst.sub.3, %upper
+  %res.2 = xor i1 %res.1, %cmp.dst.sub.3.lower
+  %res.3 = xor i1 %res.2, %cmp.dst.sub.3.upper
+  %cmp.dst.sub.4.lower = icmp sge ptr %dst.sub.4, %lower
+  %cmp.dst.sub.4.upper = icmp slt ptr %dst.sub.4, %upper
+  %res.4 = xor i1 %res.3, %cmp.dst.sub.4.lower
+  %res.5 = xor i1 %res.4, %cmp.dst.sub.4.upper
+  %dst.sub.5 = getelementptr inbounds i8, ptr %dst, i64 -5
+  %cmp.dst.sub.5.lower = icmp sge ptr %dst.sub.5, %lower
+  %cmp.dst.sub.5.upper = icmp slt ptr %dst.sub.5, %upper
+  %res.6 = xor i1 %res.5, %cmp.dst.sub.5.lower
+  %res.7 = xor i1 %res.6, %cmp.dst.sub.5.upper
+  ret i1 %res.7
+
+else:
+  %else.cmp.dst.lower = icmp sge ptr %dst, %lower
+  %else.cmp.dst.upper = icmp slt ptr %dst, %upper
+  %else.res.1 = xor i1 %else.cmp.dst.lower, %else.cmp.dst.upper
+  %else.dst.sub.3 = getelementptr inbounds i8, ptr %dst, i64 -3
+  %else.cmp.dst.sub.3.lower = icmp sge ptr %else.dst.sub.3, %lower
+  %else.cmp.dst.sub.3.upper = icmp slt ptr %else.dst.sub.3, %upper
+  %else.res.2 = xor i1 %else.res.1, %else.cmp.dst.sub.3.lower
+  %else.res.3 = xor i1 %else.res.2, %else.cmp.dst.sub.3.upper
+  %else.cmp.dst.sub.4.lower = icmp sge ptr %dst.sub.4, %lower
+  %else.cmp.dst.sub.4.upper = icmp slt ptr %dst.sub.4, %upper
+  %else.res.4 = xor i1 %else.res.3, %else.cmp.dst.sub.4.lower
+  %else.res.5 = xor i1 %else.res.4, %else.cmp.dst.sub.4.upper
+  %else.dst.sub.5 = getelementptr inbounds i8, ptr %dst, i64 -5
+  %else.cmp.dst.sub.5.lower = icmp sge ptr %else.dst.sub.5, %lower
+  %else.cmp.dst.sub.5.upper = icmp slt ptr %else.dst.sub.5, %upper
+  %else.res.6 = xor i1 %else.res.5, %else.cmp.dst.sub.5.lower
+  %else.res.7 = xor i1 %else.res.6, %else.cmp.dst.sub.5.upper
+  ret i1 %else.res.7
+}
+
+define i4 @ptr_N_signed_positive_explicit_check_constant_step(ptr %src, ptr %lower, ptr %upper, i16 %N) {
+; CHECK-LABEL: @ptr_N_signed_positive_explicit_check_constant_step(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N_POS:%.*]] = icmp sge i16 [[N:%.*]], 0
+; CHECK-NEXT:    br i1 [[N_POS]], label [[ENTRY_1:%.*]], label [[TRAP_BB:%.*]]
+; CHECK:       entry.1:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 1, [[N]]
+; CHECK-NEXT:    br i1 [[STEP_SLT_N]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 1
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %N.pos = icmp sge i16 %N, 0
+  br i1 %N.pos, label %entry.1, label %trap.bb
+
+entry.1:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.slt.N = icmp slt i16 1, %N
+  br i1 %step.slt.N, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 1
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+; Same as ptr_N_signed_positive_explicit_check_constant_step, but without inbounds.
+define i4 @ptr_N_signed_positive_explicit_check_constant_step_no_inbonds(ptr %src, ptr %lower, ptr %upper, i16 %N) {
+; CHECK-LABEL: @ptr_N_signed_positive_explicit_check_constant_step_no_inbonds(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N_POS:%.*]] = icmp sge i16 [[N:%.*]], 0
+; CHECK-NEXT:    br i1 [[N_POS]], label [[ENTRY_1:%.*]], label [[TRAP_BB:%.*]]
+; CHECK:       entry.1:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i16 [[N]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 1, [[N]]
+; CHECK-NEXT:    br i1 [[STEP_SLT_N]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr i8, ptr [[SRC]], i16 1
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %N.pos = icmp sge i16 %N, 0
+  br i1 %N.pos, label %entry.1, label %trap.bb
+
+entry.1:
+  %src.end = getelementptr i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.slt.N = icmp slt i16 1, %N
+  br i1 %step.slt.N, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr i8, ptr %src, i16 1
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_N_and_step_signed_positive_explicit_check_constant_step(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_and_step_signed_positive_explicit_check_constant_step(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[N_POS:%.*]] = icmp sge i16 [[N:%.*]], 0
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[AND_1:%.*]] = and i1 [[N_POS]], [[STEP_POS]]
+; CHECK-NEXT:    br i1 [[AND_1]], label [[ENTRY_1:%.*]], label [[TRAP_BB:%.*]]
+; CHECK:       entry.1:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_SGE_0:%.*]] = icmp sge i16 [[STEP]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_2:%.*]] = and i1 true, [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_2]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 1
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %N.pos = icmp sge i16 %N, 0
+  %step.pos = icmp sge i16 %step, 0
+  %and.1 = and i1 %N.pos, %step.pos
+  br i1 %and.1, label %entry.1, label %trap.bb
+
+entry.1:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.sge.0 = icmp sge i16 %step, 0
+  %step.slt.N = icmp slt i16 %step, %N
+  %and.2 = and i1 %step.sge.0, %step.slt.N
+  br i1 %and.2, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 1
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_N_and_step_signed_positive_unsigned_checks_only(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_and_step_signed_positive_unsigned_checks_only(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N:%.*]]
+; CHECK-NEXT:    [[NO_OVERFLOW:%.*]] = icmp sle ptr [[SRC]], [[SRC_END]]
+; CHECK-NEXT:    br i1 [[NO_OVERFLOW]], label [[ENTRY_1:%.*]], label [[TRAP_BB:%.*]]
+; CHECK:       entry.1:
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_SGE_0:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_2:%.*]] = and i1 [[STEP_SGE_0]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_2]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 1
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %no.overflow = icmp sle ptr %src, %src.end
+  br i1 %no.overflow, label %entry.1, label %trap.bb
+
+entry.1:
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.sge.0 = icmp sge i16 %step, 0
+  %step.slt.N = icmp slt i16 %step, %N
+  %and.2 = and i1 %step.sge.0, %step.slt.N
+  br i1 %and.2, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 1
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_N_signed_positive(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_signed_positive(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[N_NEG:%.*]] = icmp slt i16 [[N]], 0
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    [[OR_PRECOND_1:%.*]] = or i1 [[OR_PRECOND_0]], [[N_NEG]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_1]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %N.neg = icmp slt i16 %N, 0
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  %or.precond.1 = or i1 %or.precond.0, %N.neg
+  br i1 %or.precond.1, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i16 %step, 0
+  %step.slt.N = icmp slt i16 %step, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_N_could_be_negative(ptr %src, ptr %lower, ptr %upper, i8 %N, i8 %step) {
+; CHECK-LABEL: @ptr_N_could_be_negative(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i8 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i8 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i8 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i8 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i8 %step, 0
+  %step.slt.N = icmp slt i8 %step, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i8 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_src_sge_end(ptr %src, ptr %lower, ptr %upper, i8 %N, i8 %step) {
+; CHECK-LABEL: @ptr_src_sge_end(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i8 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[CMP_OVERFLOW:%.*]] = icmp sgt ptr [[SRC]], [[SRC_END]]
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    [[OR_PRECOND_1:%.*]] = or i1 [[OR_PRECOND_0]], [[CMP_OVERFLOW]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_1]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i8 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i8 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i8 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %cmp.overflow = icmp sgt ptr %src, %src.end
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  %or.precond.1 = or i1 %or.precond.0, %cmp.overflow
+  br i1 %or.precond.1, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i8 %step, 0
+  %step.slt.N = icmp slt i8 %step, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i8 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+; N might be negative, meaning %src.end could be < %src! Cannot remove checks!
+define i4 @ptr_N_unsigned_positive(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_unsigned_positive(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[N_NEG:%.*]] = icmp slt i16 [[N]], 0
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    [[OR_PRECOND_1:%.*]] = or i1 [[OR_PRECOND_0]], [[N_NEG]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_1]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %N.neg = icmp slt i16 %N, 0
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  %or.precond.1 = or i1 %or.precond.0, %N.neg
+  br i1 %or.precond.1, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i16 %step, 0
+  %step.slt.N = icmp slt i16 %step, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}
+
+define i4 @ptr_N_signed_positive_assume(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
+; CHECK-LABEL: @ptr_N_signed_positive_assume(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_END:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i16 [[N:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_START:%.*]] = icmp slt ptr [[SRC]], [[LOWER:%.*]]
+; CHECK-NEXT:    [[CMP_SRC_END:%.*]] = icmp sge ptr [[SRC_END]], [[UPPER:%.*]]
+; CHECK-NEXT:    [[N_NEG:%.*]] = icmp slt i16 [[N]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[N_NEG]])
+; CHECK-NEXT:    [[OR_PRECOND_0:%.*]] = or i1 [[CMP_SRC_START]], [[CMP_SRC_END]]
+; CHECK-NEXT:    br i1 [[OR_PRECOND_0]], label [[TRAP_BB:%.*]], label [[STEP_CHECK:%.*]]
+; CHECK:       trap.bb:
+; CHECK-NEXT:    ret i4 2
+; CHECK:       step.check:
+; CHECK-NEXT:    [[STEP_POS:%.*]] = icmp sge i16 [[STEP:%.*]], 0
+; CHECK-NEXT:    [[STEP_SLT_N:%.*]] = icmp slt i16 [[STEP]], [[N]]
+; CHECK-NEXT:    [[AND_STEP:%.*]] = and i1 [[STEP_POS]], [[STEP_SLT_N]]
+; CHECK-NEXT:    br i1 [[AND_STEP]], label [[PTR_CHECK:%.*]], label [[EXIT:%.*]]
+; CHECK:       ptr.check:
+; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i16 [[STEP]]
+; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp slt ptr [[SRC_STEP]], [[LOWER]]
+; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp sge ptr [[SRC_STEP]], [[UPPER]]
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
+; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i4 3
+;
+entry:
+  %src.end = getelementptr inbounds i8, ptr %src, i16 %N
+  %cmp.src.start = icmp slt ptr %src, %lower
+  %cmp.src.end = icmp sge ptr %src.end, %upper
+  %N.neg = icmp slt i16 %N, 0
+  call void @llvm.assume(i1 %N.neg)
+  %or.precond.0 = or i1 %cmp.src.start, %cmp.src.end
+  br i1 %or.precond.0, label %trap.bb, label %step.check
+
+trap.bb:
+  ret i4 2
+
+step.check:
+  %step.pos = icmp sge i16 %step, 0
+  %step.slt.N = icmp slt i16 %step, %N
+  %and.step = and i1 %step.pos, %step.slt.N
+  br i1 %and.step, label %ptr.check, label %exit
+
+ptr.check:
+  %src.step = getelementptr inbounds i8, ptr %src, i16 %step
+  %cmp.step.start = icmp slt ptr %src.step, %lower
+  %cmp.step.end = icmp sge ptr %src.step, %upper
+  %or.check = or i1 %cmp.step.start, %cmp.step.end
+  br i1 %or.check, label %trap.bb, label %exit
+
+exit:
+  ret i4 3
+}

diff  --git a/llvm/test/Transforms/ConstraintElimination/gep-sub-signed-predicates.ll b/llvm/test/Transforms/ConstraintElimination/gep-sub-signed-predicates.ll
new file mode 100644
index 0000000000000..9de9afd5ee9be
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/gep-sub-signed-predicates.ll
@@ -0,0 +1,548 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare void @llvm.assume(i1 noundef)
+
+define i1 @gep_sub_1_sge_inbounds(ptr %dst, ptr %lower) {
+; CHECK-LABEL: @gep_sub_1_sge_inbounds(
+; CHECK-NEXT:    [[PRE:%.*]] = icmp sge ptr [[DST:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp sge ptr [[DST_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp sge ptr [[DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    [[DST_SUB_4:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -4
+; CHECK-NEXT:    [[CMP_SUB_4:%.*]] = icmp sge ptr [[DST_SUB_4]], [[LOWER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_4]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %pre = icmp sge ptr %dst, %lower
+  call void @llvm.assume(i1 %pre)
+  %dst.add.3 = getelementptr inbounds i8, ptr %dst, i64 3
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.3, i64 -1
+  %cmp.sub.1 = icmp sge ptr %dst.sub.1, %lower
+  %dst.sub.3 = getelementptr inbounds i8, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp sge ptr %dst.sub.3, %lower
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.3
+  %dst.sub.4 = getelementptr inbounds i8, ptr %dst.add.3, i64 -4
+  %cmp.sub.4 = icmp sge ptr %dst.sub.4, %lower
+  %res.2 = xor i1 %res.1, %cmp.sub.4
+  ret i1 %res.2
+}
+
+define i1 @gep_sub_1_sge_only_inner_inbounds(ptr %dst, ptr %lower) {
+; CHECK-LABEL: @gep_sub_1_sge_only_inner_inbounds(
+; CHECK-NEXT:    [[PRE:%.*]] = icmp sge ptr [[DST:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr i8, ptr [[DST_ADD_3]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp sge ptr [[DST_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr i8, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp sge ptr [[DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    [[DST_SUB_4:%.*]] = getelementptr i8, ptr [[DST_ADD_3]], i64 -4
+; CHECK-NEXT:    [[CMP_SUB_4:%.*]] = icmp sge ptr [[DST_SUB_4]], [[LOWER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_4]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %pre = icmp sge ptr %dst, %lower
+  call void @llvm.assume(i1 %pre)
+  %dst.add.3 = getelementptr inbounds i8, ptr %dst, i64 3
+  %dst.sub.1 = getelementptr i8, ptr %dst.add.3, i64 -1
+  %cmp.sub.1 = icmp sge ptr %dst.sub.1, %lower
+  %dst.sub.3 = getelementptr i8, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp sge ptr %dst.sub.3, %lower
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.3
+  %dst.sub.4 = getelementptr i8, ptr %dst.add.3, i64 -4
+  %cmp.sub.4 = icmp sge ptr %dst.sub.4, %lower
+  %res.2 = xor i1 %res.1, %cmp.sub.4
+  ret i1 %res.2
+}
+
+define i1 @gep_sub_1_sge_only_outer_inbounds(ptr %dst, ptr %lower) {
+; CHECK-LABEL: @gep_sub_1_sge_only_outer_inbounds(
+; CHECK-NEXT:    [[PRE:%.*]] = icmp sge ptr [[DST:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp sge ptr [[DST_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp sge ptr [[DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    [[DST_SUB_4:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -4
+; CHECK-NEXT:    [[CMP_SUB_4:%.*]] = icmp sge ptr [[DST_SUB_4]], [[LOWER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_4]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %pre = icmp sge ptr %dst, %lower
+  call void @llvm.assume(i1 %pre)
+  %dst.add.3 = getelementptr i8, ptr %dst, i64 3
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.3, i64 -1
+  %cmp.sub.1 = icmp sge ptr %dst.sub.1, %lower
+  %dst.sub.3 = getelementptr inbounds i8, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp sge ptr %dst.sub.3, %lower
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.3
+  %dst.sub.4 = getelementptr inbounds i8, ptr %dst.add.3, i64 -4
+  %cmp.sub.4 = icmp sge ptr %dst.sub.4, %lower
+  %res.2 = xor i1 %res.1, %cmp.sub.4
+  ret i1 %res.2
+}
+
+define i1 @gep_sub_1_sge_no_inbounds(ptr %dst, ptr %lower) {
+; CHECK-LABEL: @gep_sub_1_sge_no_inbounds(
+; CHECK-NEXT:    [[PRE:%.*]] = icmp sge ptr [[DST:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr i8, ptr [[DST_ADD_3]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp sge ptr [[DST_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr i8, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp sge ptr [[DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    [[DST_SUB_4:%.*]] = getelementptr i8, ptr [[DST_ADD_3]], i64 -4
+; CHECK-NEXT:    [[CMP_SUB_4:%.*]] = icmp sge ptr [[DST_SUB_4]], [[LOWER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_4]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %pre = icmp sge ptr %dst, %lower
+  call void @llvm.assume(i1 %pre)
+  %dst.add.3 = getelementptr i8, ptr %dst, i64 3
+  %dst.sub.1 = getelementptr i8, ptr %dst.add.3, i64 -1
+  %cmp.sub.1 = icmp sge ptr %dst.sub.1, %lower
+  %dst.sub.3 = getelementptr i8, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp sge ptr %dst.sub.3, %lower
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.3
+  %dst.sub.4 = getelementptr i8, ptr %dst.add.3, i64 -4
+  %cmp.sub.4 = icmp sge ptr %dst.sub.4, %lower
+  %res.2 = xor i1 %res.1, %cmp.sub.4
+  ret i1 %res.2
+}
+
+define i1 @gep_sub_1_slt(ptr %dst, ptr %upper) {
+; CHECK-LABEL: @gep_sub_1_slt(
+; CHECK-NEXT:    [[DST_ADD_4:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i64 4
+; CHECK-NEXT:    [[PRE:%.*]] = icmp slt ptr [[DST_ADD_4]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp slt ptr [[DST_SUB_3]], [[UPPER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    ret i1 [[RES_1]]
+;
+  %dst.add.4 = getelementptr inbounds i8, ptr %dst, i64 4
+  %pre = icmp slt ptr %dst.add.4, %upper
+  call void @llvm.assume(i1 %pre)
+  %dst.add.3 = getelementptr inbounds i8, ptr %dst, i64 3
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.3, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  %dst.sub.3 = getelementptr inbounds i8, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp slt ptr %dst.sub.3, %upper
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.3
+  ret i1 %res.1
+}
+
+define i1 @gep_sub_slt_var_idx(ptr %dst, ptr %upper, i8 %idx) {
+; CHECK-LABEL: @gep_sub_slt_var_idx(
+; CHECK-NEXT:    [[NOT_ZERO:%.*]] = icmp ne i8 [[IDX:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NOT_ZERO]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER]]
+; CHECK-NEXT:    [[DST_SUB_2:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 -2
+; CHECK-NEXT:    [[CMP_SUB_2:%.*]] = icmp slt ptr [[DST_SUB_2]], [[UPPER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_2]]
+; CHECK-NEXT:    [[DST_SUB_1_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_SUB_1]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1_SUB_1]], [[UPPER]]
+; CHECK-NEXT:    [[CMP_SUB_1_SUB_1_EQ:%.*]] = icmp eq ptr [[DST_SUB_1_SUB_1]], [[DST_SUB_2]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_1_SUB_1]]
+; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[CMP_SUB_1_SUB_1_EQ]]
+; CHECK-NEXT:    ret i1 [[RES_3]]
+;
+  %not.zero = icmp ne i8 %idx, 0
+  call void @llvm.assume(i1 %not.zero)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %pre = icmp slt ptr %dst.add.idx, %upper
+  call void @llvm.assume(i1 %pre)
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.idx, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  %dst.sub.2 = getelementptr inbounds i8, ptr %dst.add.idx, i64 -2
+  %cmp.sub.2 = icmp slt ptr %dst.sub.2, %upper
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.2
+  %dst.sub.1.sub.1 = getelementptr inbounds i8, ptr %dst.sub.1, i64 -1
+  %cmp.sub.1.sub.1 = icmp slt ptr %dst.sub.1.sub.1, %upper
+  %cmp.sub.1.sub.1.eq = icmp eq ptr %dst.sub.1.sub.1, %dst.sub.2
+  %res.2 = xor i1 %res.1, %cmp.sub.1.sub.1
+  %res.3 = xor i1 %res.2, %cmp.sub.1.sub.1.eq
+  ret i1 %res.3
+}
+
+define i1 @gep_sub_slt_var_idx_sgt_1(ptr %dst, ptr %upper, i8 %idx) {
+; CHECK-LABEL: @gep_sub_slt_var_idx_sgt_1(
+; CHECK-NEXT:    [[SGT_1:%.*]] = icmp sgt i8 [[IDX:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGT_1]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[PRE:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER]]
+; CHECK-NEXT:    [[DST_SUB_2:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 -2
+; CHECK-NEXT:    [[CMP_SUB_2:%.*]] = icmp slt ptr [[DST_SUB_2]], [[UPPER]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_2]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_IDX]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp slt ptr [[DST_SUB_3]], [[UPPER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %sgt.1 = icmp sgt i8 %idx, 1
+  call void @llvm.assume(i1 %sgt.1)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %pre = icmp slt ptr %dst.add.idx, %upper
+  call void @llvm.assume(i1 %pre)
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.idx, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  %dst.sub.2 = getelementptr inbounds i8, ptr %dst.add.idx, i64 -2
+  %cmp.sub.2 = icmp slt ptr %dst.sub.2, %upper
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.2
+  %dst.sub.3 = getelementptr inbounds i8, ptr %dst.add.idx, i64 -3
+  %cmp.sub.3 = icmp slt ptr %dst.sub.3, %upper
+  %res.2 = xor i1 %res.1, %cmp.sub.3
+  ret i1 %res.2
+}
+
+define i1 @gep_sub_1_slt_var_idx_inbounds(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
+; CHECK-LABEL: @gep_sub_1_slt_var_idx_inbounds(
+; CHECK-NEXT:    [[NOT_ZERO:%.*]] = icmp ne i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NOT_ZERO]])
+; CHECK-NEXT:    [[LEN_EXT:%.*]] = zext i8 [[LEN]] to i16
+; CHECK-NEXT:    [[DST_ADD_LEN:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[LEN_EXT]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_LEN]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_SUB_1]])
+; CHECK-NEXT:    [[CMP_IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_SLT_LEN]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER]]
+; CHECK-NEXT:    ret i1 [[CMP_IDX]]
+;
+  %not.zero = icmp ne i8 %len, 0
+  call void @llvm.assume(i1 %not.zero)
+  %len.ext = zext i8 %len to i16
+  %dst.add.len = getelementptr inbounds i8, ptr %dst, i16 %len.ext
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.len, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  call void @llvm.assume(i1 %cmp.sub.1)
+  %cmp.idx.slt.len = icmp slt i8 %idx, %len
+  call void @llvm.assume(i1 %cmp.idx.slt.len)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %cmp.idx = icmp slt ptr %dst.add.idx, %upper
+  ret i1 %cmp.idx
+}
+
+define i1 @gep_sub_1_slt_var_idx_only_inner_inbounds(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
+; CHECK-LABEL: @gep_sub_1_slt_var_idx_only_inner_inbounds(
+; CHECK-NEXT:    [[NOT_ZERO:%.*]] = icmp ne i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NOT_ZERO]])
+; CHECK-NEXT:    [[LEN_EXT:%.*]] = zext i8 [[LEN]] to i16
+; CHECK-NEXT:    [[DST_ADD_LEN:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[LEN_EXT]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr i8, ptr [[DST_ADD_LEN]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_SUB_1]])
+; CHECK-NEXT:    [[CMP_IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_SLT_LEN]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER]]
+; CHECK-NEXT:    ret i1 [[CMP_IDX]]
+;
+  %not.zero = icmp ne i8 %len, 0
+  call void @llvm.assume(i1 %not.zero)
+  %len.ext = zext i8 %len to i16
+  %dst.add.len = getelementptr inbounds i8, ptr %dst, i16 %len.ext
+  %dst.sub.1 = getelementptr i8, ptr %dst.add.len, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  call void @llvm.assume(i1 %cmp.sub.1)
+  %cmp.idx.slt.len = icmp slt i8 %idx, %len
+  call void @llvm.assume(i1 %cmp.idx.slt.len)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %cmp.idx = icmp slt ptr %dst.add.idx, %upper
+  ret i1 %cmp.idx
+}
+
+define i1 @gep_sub_1_slt_var_idx_no_inbounds(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
+; CHECK-LABEL: @gep_sub_1_slt_var_idx_no_inbounds(
+; CHECK-NEXT:    [[NOT_ZERO:%.*]] = icmp ne i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NOT_ZERO]])
+; CHECK-NEXT:    [[LEN_EXT:%.*]] = zext i8 [[LEN]] to i16
+; CHECK-NEXT:    [[DST_ADD_LEN:%.*]] = getelementptr i8, ptr [[DST:%.*]], i16 [[LEN_EXT]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr i8, ptr [[DST_ADD_LEN]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_SUB_1]])
+; CHECK-NEXT:    [[CMP_IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_SLT_LEN]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr i8, ptr [[DST]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER]]
+; CHECK-NEXT:    ret i1 [[CMP_IDX]]
+;
+  %not.zero = icmp ne i8 %len, 0
+  call void @llvm.assume(i1 %not.zero)
+  %len.ext = zext i8 %len to i16
+  %dst.add.len = getelementptr i8, ptr %dst, i16 %len.ext
+  %dst.sub.1 = getelementptr i8, ptr %dst.add.len, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  call void @llvm.assume(i1 %cmp.sub.1)
+  %cmp.idx.slt.len = icmp slt i8 %idx, %len
+  call void @llvm.assume(i1 %cmp.idx.slt.len)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr i8, ptr %dst, i16 %idx.ext
+  %cmp.idx = icmp slt ptr %dst.add.idx, %upper
+  ret i1 %cmp.idx
+}
+
+define i1 @gep_sub_2_slt_var_idx(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
+; CHECK-LABEL: @gep_sub_2_slt_var_idx(
+; CHECK-NEXT:    [[NOT_ZERO:%.*]] = icmp ne i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[NOT_ZERO]])
+; CHECK-NEXT:    [[LEN_EXT:%.*]] = zext i8 [[LEN]] to i16
+; CHECK-NEXT:    [[DST_ADD_LEN:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[LEN_EXT]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_LEN]], i64 -2
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_SUB_1]])
+; CHECK-NEXT:    [[CMP_IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_SLT_LEN]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER]]
+; CHECK-NEXT:    ret i1 [[CMP_IDX]]
+;
+  %not.zero = icmp ne i8 %len, 0
+  call void @llvm.assume(i1 %not.zero)
+  %len.ext = zext i8 %len to i16
+  %dst.add.len = getelementptr inbounds i8, ptr %dst, i16 %len.ext
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.len, i64 -2
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  call void @llvm.assume(i1 %cmp.sub.1)
+  %cmp.idx.slt.len = icmp slt i8 %idx, %len
+  call void @llvm.assume(i1 %cmp.idx.slt.len)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %cmp.idx = icmp slt ptr %dst.add.idx, %upper
+  ret i1 %cmp.idx
+}
+
+define i1 @gep_sub_2_slt_var_idx_inbounds_len_sge_2(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
+; CHECK-LABEL: @gep_sub_2_slt_var_idx_inbounds_len_sge_2(
+; CHECK-NEXT:    [[SGE_2:%.*]] = icmp sge i8 [[LEN:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGE_2]])
+; CHECK-NEXT:    [[LEN_EXT:%.*]] = zext i8 [[LEN]] to i16
+; CHECK-NEXT:    [[DST_ADD_LEN:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[LEN_EXT]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_LEN]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_SUB_1]])
+; CHECK-NEXT:    [[CMP_IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_SLT_LEN]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER]]
+; CHECK-NEXT:    ret i1 [[CMP_IDX]]
+;
+  %sge.2 = icmp sge i8 %len, 2
+  call void @llvm.assume(i1 %sge.2)
+  %len.ext = zext i8 %len to i16
+  %dst.add.len = getelementptr inbounds i8, ptr %dst, i16 %len.ext
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.len, i64 -1
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  call void @llvm.assume(i1 %cmp.sub.1)
+  %cmp.idx.slt.len = icmp slt i8 %idx, %len
+  call void @llvm.assume(i1 %cmp.idx.slt.len)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %cmp.idx = icmp slt ptr %dst.add.idx, %upper
+  ret i1 %cmp.idx
+}
+
+define i1 @gep_sub_slt_var_idx_len_sgt_1(ptr %dst, ptr %upper, i8 %len, i8 %idx) {
+; CHECK-LABEL: @gep_sub_slt_var_idx_len_sgt_1(
+; CHECK-NEXT:    [[SGT_1:%.*]] = icmp sgt i8 [[LEN:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SGT_1]])
+; CHECK-NEXT:    [[LEN_EXT:%.*]] = zext i8 [[LEN]] to i16
+; CHECK-NEXT:    [[DST_ADD_LEN:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i16 [[LEN_EXT]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[DST_ADD_LEN]], i64 -2
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp slt ptr [[DST_SUB_1]], [[UPPER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_SUB_1]])
+; CHECK-NEXT:    [[CMP_IDX_SLT_LEN:%.*]] = icmp slt i8 [[IDX:%.*]], [[LEN]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_SLT_LEN]])
+; CHECK-NEXT:    [[IDX_EXT:%.*]] = zext i8 [[IDX]] to i16
+; CHECK-NEXT:    [[DST_ADD_IDX:%.*]] = getelementptr inbounds i8, ptr [[DST]], i16 [[IDX_EXT]]
+; CHECK-NEXT:    [[CMP_IDX:%.*]] = icmp slt ptr [[DST_ADD_IDX]], [[UPPER]]
+; CHECK-NEXT:    ret i1 [[CMP_IDX]]
+;
+  %sgt.1 = icmp sgt i8 %len, 1
+  call void @llvm.assume(i1 %sgt.1)
+  %len.ext = zext i8 %len to i16
+  %dst.add.len = getelementptr inbounds i8, ptr %dst, i16 %len.ext
+  %dst.sub.1 = getelementptr inbounds i8, ptr %dst.add.len, i64 -2
+  %cmp.sub.1 = icmp slt ptr %dst.sub.1, %upper
+  call void @llvm.assume(i1 %cmp.sub.1)
+  %cmp.idx.slt.len = icmp slt i8 %idx, %len
+  call void @llvm.assume(i1 %cmp.idx.slt.len)
+  %idx.ext = zext i8 %idx to i16
+  %dst.add.idx = getelementptr inbounds i8, ptr %dst, i16 %idx.ext
+  %cmp.idx = icmp slt ptr %dst.add.idx, %upper
+  ret i1 %cmp.idx
+}
+
+define i1 @gep_sub_1_slt_var_idx_lower_bound(ptr %lower, ptr %src, i8 %len) {
+; CHECK-LABEL: @gep_sub_1_slt_var_idx_lower_bound(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SRC_SGE_LOWER:%.*]] = icmp sge ptr [[SRC:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SRC_SGE_LOWER]])
+; CHECK-NEXT:    [[LEN_POS:%.*]] = icmp sge i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[LEN_POS]])
+; CHECK-NEXT:    [[GEP_LEN:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[LEN]]
+; CHECK-NEXT:    [[GEP_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[GEP_LEN]], i8 -1
+; CHECK-NEXT:    [[RES:%.*]] = icmp slt ptr [[GEP_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+entry:
+  %src.sge.lower = icmp sge ptr %src, %lower
+  call void @llvm.assume(i1 %src.sge.lower)
+
+  %len.pos = icmp sge i8 %len, 0
+  call void @llvm.assume(i1 %len.pos)
+
+  %gep.len = getelementptr inbounds i8, ptr %src, i8 %len
+  %gep.sub.1 = getelementptr inbounds i8, ptr %gep.len, i8 -1
+  %res = icmp slt ptr %gep.sub.1, %lower
+  ret i1 %res
+}
+
+define i1 @gep_sub_1_slt_var_idx_lower_bound_len_ne_0(ptr %lower, ptr %src, i8 %len) {
+; CHECK-LABEL: @gep_sub_1_slt_var_idx_lower_bound_len_ne_0(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN_NE_0:%.*]] = icmp ne i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[LEN_NE_0]])
+; CHECK-NEXT:    [[SRC_SGE_LOWER:%.*]] = icmp sge ptr [[SRC:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SRC_SGE_LOWER]])
+; CHECK-NEXT:    [[LEN_POS:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[LEN_POS]])
+; CHECK-NEXT:    [[GEP_LEN:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[LEN]]
+; CHECK-NEXT:    [[GEP_SUB_1:%.*]] = getelementptr inbounds i8, ptr [[GEP_LEN]], i8 -1
+; CHECK-NEXT:    [[RES:%.*]] = icmp slt ptr [[GEP_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+entry:
+  %len.ne.0 = icmp ne i8 %len, 0
+  call void @llvm.assume(i1 %len.ne.0)
+
+  %src.sge.lower = icmp sge ptr %src, %lower
+  call void @llvm.assume(i1 %src.sge.lower)
+
+  %len.pos = icmp sge i8 %len, 0
+  call void @llvm.assume(i1 %len.pos)
+
+  %gep.len = getelementptr inbounds i8, ptr %src, i8 %len
+  %gep.sub.1 = getelementptr inbounds i8, ptr %gep.len, i8 -1
+  %res = icmp slt ptr %gep.sub.1, %lower
+  ret i1 %res
+}
+
+define i1 @gep_sub_2_slt_var_idx_lower_bound_len_ne_0(ptr %lower, ptr %src, i8 %len) {
+; CHECK-LABEL: @gep_sub_2_slt_var_idx_lower_bound_len_ne_0(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN_NE_0:%.*]] = icmp ne i8 [[LEN:%.*]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[LEN_NE_0]])
+; CHECK-NEXT:    [[SRC_SGE_LOWER:%.*]] = icmp sge ptr [[SRC:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[SRC_SGE_LOWER]])
+; CHECK-NEXT:    [[LEN_POS:%.*]] = icmp sge i8 [[LEN]], 0
+; CHECK-NEXT:    call void @llvm.assume(i1 [[LEN_POS]])
+; CHECK-NEXT:    [[GEP_LEN:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[LEN]]
+; CHECK-NEXT:    [[GEP_SUB_2:%.*]] = getelementptr inbounds i8, ptr [[GEP_LEN]], i8 -2
+; CHECK-NEXT:    [[RES:%.*]] = icmp slt ptr [[GEP_SUB_2]], [[LOWER]]
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+entry:
+  %len.ne.0 = icmp ne i8 %len, 0
+  call void @llvm.assume(i1 %len.ne.0)
+
+  %src.sge.lower = icmp sge ptr %src, %lower
+  call void @llvm.assume(i1 %src.sge.lower)
+
+  %len.pos = icmp sge i8 %len, 0
+  call void @llvm.assume(i1 %len.pos)
+
+  %gep.len = getelementptr inbounds i8, ptr %src, i8 %len
+  %gep.sub.2 = getelementptr inbounds i8, ptr %gep.len, i8 -2
+  %res = icmp slt ptr %gep.sub.2, %lower
+  ret i1 %res
+}
+
+define i1 @gep_i16_sub_1_sge_inbounds(ptr %dst, ptr %lower) {
+; CHECK-LABEL: @gep_i16_sub_1_sge_inbounds(
+; CHECK-NEXT:    [[PRE:%.*]] = icmp sge ptr [[DST:%.*]], [[LOWER:%.*]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 3
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i16, ptr [[DST_ADD_3]], i64 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp sle ptr [[DST_SUB_1]], [[LOWER]]
+; CHECK-NEXT:    [[DST_SUB_2:%.*]] = getelementptr inbounds i16, ptr [[DST_ADD_3]], i64 -2
+; CHECK-NEXT:    [[CMP_SUB_2:%.*]] = icmp sle ptr [[DST_SUB_2]], [[DST]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_2]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i16, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp sle ptr [[DST_SUB_3]], [[LOWER]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %pre = icmp sge ptr %dst, %lower
+  call void @llvm.assume(i1 %pre)
+  %dst.add.3 = getelementptr inbounds i8, ptr %dst, i64 3
+  %dst.sub.1 = getelementptr inbounds i16, ptr %dst.add.3, i64 -1
+  %cmp.sub.1 = icmp sle ptr %dst.sub.1, %lower
+  %dst.sub.2 = getelementptr inbounds i16, ptr %dst.add.3, i64 -2
+  %cmp.sub.2 = icmp sle ptr %dst.sub.2, %dst
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.2
+  %dst.sub.3 = getelementptr inbounds i16, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp sle ptr %dst.sub.3, %lower
+  %res.2 = xor i1 %res.1, %cmp.sub.3
+  ret i1 %res.2
+}
+
+define i1 @gep_i16_sub_1_sge_inbounds_var_idx(ptr %dst, i64 %off) {
+; CHECK-LABEL: @gep_i16_sub_1_sge_inbounds_var_idx(
+; CHECK-NEXT:    [[OFF_SGE:%.*]] = icmp sge i64 [[OFF:%.*]], 1
+; CHECK-NEXT:    call void @llvm.assume(i1 [[OFF_SGE]])
+; CHECK-NEXT:    [[DST_ADD_3:%.*]] = getelementptr inbounds i8, ptr [[DST:%.*]], i64 [[OFF]]
+; CHECK-NEXT:    [[DST_SUB_1:%.*]] = getelementptr inbounds i16, ptr [[DST_ADD_3]], i32 -1
+; CHECK-NEXT:    [[CMP_SUB_1:%.*]] = icmp sle ptr [[DST_SUB_1]], [[DST]]
+; CHECK-NEXT:    [[DST_SUB_2:%.*]] = getelementptr inbounds i16, ptr [[DST_ADD_3]], i64 -2
+; CHECK-NEXT:    [[CMP_SUB_2:%.*]] = icmp sle ptr [[DST_SUB_2]], [[DST]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[CMP_SUB_1]], [[CMP_SUB_2]]
+; CHECK-NEXT:    [[DST_SUB_3:%.*]] = getelementptr inbounds i16, ptr [[DST_ADD_3]], i64 -3
+; CHECK-NEXT:    [[CMP_SUB_3:%.*]] = icmp sle ptr [[DST_SUB_3]], [[DST]]
+; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[CMP_SUB_3]]
+; CHECK-NEXT:    ret i1 [[RES_2]]
+;
+  %off.sge = icmp sge i64 %off, 1
+  call void @llvm.assume(i1 %off.sge)
+  %dst.add.3 = getelementptr inbounds i8, ptr %dst, i64 %off
+  %dst.sub.1 = getelementptr inbounds i16, ptr %dst.add.3, i32 -1
+  %cmp.sub.1 = icmp sle ptr %dst.sub.1, %dst
+  %dst.sub.2 = getelementptr inbounds i16, ptr %dst.add.3, i64 -2
+  %cmp.sub.2 = icmp sle ptr %dst.sub.2, %dst
+  %res.1 = xor i1 %cmp.sub.1, %cmp.sub.2
+  %dst.sub.3 = getelementptr inbounds i16, ptr %dst.add.3, i64 -3
+  %cmp.sub.3 = icmp sle ptr %dst.sub.3, %dst
+  %res.2 = xor i1 %res.1, %cmp.sub.3
+  ret i1 %res.2
+}


        


More information about the llvm-commits mailing list