Bug type: miscompilation
Component: ConstraintElimination
Bug location: llvm/lib/Transforms/Scalar/ConstraintElimination.cpp: checkOrAndOpImpliedByOther
eliminateConstraints
Issue title: [ConstraintElim] `checkOrAndOpImpliedByOther` should drop `disjoint` flag
Labels: miscompilation
llvm:transforms
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/pUvC88
```
----------------------------------------
define i1 @src(i8 %b) {
entry:
  %c.1 = icmp slt i8 %b, 1
  %c.2 = icmp ne i8 %b, 0
  %or = or disjoint i1 %c.2, %c.1
  ret i1 %or
}
=>
define i1 @src(i8 %b) {
entry:
  %c.2 = icmp ne i8 %b, 0
  %or = or disjoint i1 %c.2, 1
  ret i1 %or
}
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i8 %b = #x01 (1)

Source:
i1 %c.1 = #x0 (0)
i1 %c.2 = #x1 (1)
i1 %or = #x1 (1)

Target:
i1 %c.2 = #x1 (1)
i1 %or = poison
Source value: #x1 (1)
Target value: poison

Summary:
  0 correct transformations
  1 incorrect transformations
  0 failed-to-prove transformations
  0 Alive2 errors
```
Triggered by pre-commit fuzzing for https://github.com/llvm/llvm-project/pull/135784.



Fix patch:
commit aa054c681059257d371857945c08840f69f68379
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed May 14 23:37:41 2025 +0800

    [ConstraintElim] Simplify and/or instead of replacing its operand (#139874)
    
    In `checkOrAndOpImpliedByOther`, replacing an operand of a disjoint or
    is unsafe: https://alive2.llvm.org/ce/z/4R4hxN
    This patch performs the simplification directly, to avoid miscompilation
    and unnecessary canonicalization.
    
    Closes https://github.com/llvm/llvm-project/issues/137937.

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index f2d6e268743e..da5be383df15 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1563,8 +1563,12 @@ removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
 static bool checkOrAndOpImpliedByOther(
     FactOrCheck &CB, ConstraintInfo &Info, Module *ReproducerModule,
     SmallVectorImpl<ReproducerEntry> &ReproducerCondStack,
-    SmallVectorImpl<StackEntry> &DFSInStack) {
+    SmallVectorImpl<StackEntry> &DFSInStack,
+    SmallVectorImpl<Instruction *> &ToRemove) {
   Instruction *JoinOp = CB.getContextInst();
+  if (JoinOp->use_empty())
+    return false;
+
   CmpInst *CmpToCheck = cast<CmpInst>(CB.getInstructionToSimplify());
   unsigned OtherOpIdx = JoinOp->getOperand(0) == CmpToCheck ? 1 : 0;
 
@@ -1611,15 +1615,12 @@ static bool checkOrAndOpImpliedByOther(
   if (auto ImpliedCondition =
           checkCondition(CmpToCheck->getPredicate(), CmpToCheck->getOperand(0),
                          CmpToCheck->getOperand(1), CmpToCheck, Info)) {
-    if (IsOr && isa<SelectInst>(JoinOp)) {
-      JoinOp->setOperand(
-          OtherOpIdx == 0 ? 2 : 0,
+    if (IsOr == *ImpliedCondition)
+      JoinOp->replaceAllUsesWith(
           ConstantInt::getBool(JoinOp->getType(), *ImpliedCondition));
-    } else
-      JoinOp->setOperand(
-          1 - OtherOpIdx,
-          ConstantInt::getBool(JoinOp->getType(), *ImpliedCondition));
-
+    else
+      JoinOp->replaceAllUsesWith(JoinOp->getOperand(OtherOpIdx));
+    ToRemove.push_back(JoinOp);
     return true;
   }
 
@@ -1852,9 +1853,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
             ReproducerModule.get(), ReproducerCondStack, S.DT, ToRemove);
         if (!Simplified &&
             match(CB.getContextInst(), m_LogicalOp(m_Value(), m_Value()))) {
-          Simplified =
-              checkOrAndOpImpliedByOther(CB, Info, ReproducerModule.get(),
-                                         ReproducerCondStack, DFSInStack);
+          Simplified = checkOrAndOpImpliedByOther(
+              CB, Info, ReproducerModule.get(), ReproducerCondStack, DFSInStack,
+              ToRemove);
         }
         Changed |= Simplified;
       } else if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(Inst)) {


Regression tests:
file: llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: and_tree_second_implies_first_perm1
test_body: define void @and_tree_second_implies_first_perm1(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) {
entry:
  %cmp0 = icmp sge i32 %v0, %v1
  %cmp1 = icmp sge i32 %v1, %v2
  %cmp2 = icmp slt i32 %v0, %v2
  %and1 = and i1 %cmp2, %cmp1
  %and2 = and i1 %cmp0, %and1
  br i1 %and2, label %if.then, label %return

if.then:                                          ; preds = %entry
  call void @side_effect()
  br label %return

return:                                           ; preds = %if.then, %entry
  ret void
}

declare void @side_effect()

test_name: test_second_and_condition_implied_by_first
test_body: define i1 @test_second_and_condition_implied_by_first(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %and = and i1 %c.1, %t.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_or_used_in_false_branch2
test_body: define i1 @test_or_used_in_false_branch2(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %and = or i1 %c.1, %t.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 %t.1

else:                                             ; preds = %entry
  ret i1 %t.1
}

test_name: test_and_used_in_false_branch
test_body: define i1 @test_and_used_in_false_branch(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %and = and i1 %c.1, %t.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 %t.1

else:                                             ; preds = %entry
  ret i1 %t.1
}

test_name: and_tree_second_implies_first_perm2
test_body: define void @and_tree_second_implies_first_perm2(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) {
entry:
  %cmp0 = icmp sge i32 %v0, %v1
  %cmp1 = icmp sge i32 %v1, %v2
  %cmp2 = icmp slt i32 %v0, %v2
  %and1 = and i1 %cmp0, %cmp2
  %and2 = and i1 %cmp1, %and1
  br i1 %and2, label %if.then, label %return

if.then:                                          ; preds = %entry
  call void @side_effect()
  br label %return

return:                                           ; preds = %if.then, %entry
  ret void
}

declare void @side_effect()

test_name: or_tree_second_implies_first_with_unknown_cond
test_body: define void @or_tree_second_implies_first_with_unknown_cond(i64 %x, i1 %cond) {
entry:
  %cmp1 = icmp ugt i64 %x, 1
  %or1 = select i1 %cmp1, i1 %cond, i1 false
  %cmp2 = icmp ult i64 %x, 2
  %or2 = select i1 %or1, i1 %cmp2, i1 false
  br i1 %or2, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  call void @side_effect()
  br label %if.end

if.end:                                           ; preds = %if.then, %entry
  ret void
}

declare void @side_effect()

test_name: test_or_used_in_false_branch
test_body: define i1 @test_or_used_in_false_branch(i8 %x) {
entry:
  %c.1 = icmp ule i8 %x, 10
  %t.1 = icmp ule i8 %x, 5
  %and = or i1 %c.1, %t.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 %t.1

else:                                             ; preds = %entry
  ret i1 %t.1
}

test_name: or_tree_second_implies_first
test_body: define void @or_tree_second_implies_first(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) {
entry:
  %cmp0 = icmp sge i32 %v0, %v1
  %cmp1 = icmp sge i32 %v1, %v2
  %and1 = or i1 %cmp0, %cmp1
  %cmp2 = icmp slt i32 %v0, %v2
  %and2 = or i1 %cmp2, %and1
  br i1 %and2, label %if.then, label %return

if.then:                                          ; preds = %entry
  call void @side_effect()
  br label %return

return:                                           ; preds = %if.then, %entry
  ret void
}

declare void @side_effect()

test_name: and_tree_second_implies_first
test_body: define void @and_tree_second_implies_first(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) {
entry:
  %cmp0 = icmp sge i32 %v0, %v1
  %cmp1 = icmp sge i32 %v1, %v2
  %and1 = and i1 %cmp0, %cmp1
  %cmp2 = icmp slt i32 %v0, %v2
  %and2 = and i1 %cmp2, %and1
  br i1 %and2, label %if.then, label %return

if.then:                                          ; preds = %entry
  call void @side_effect()
  br label %return

return:                                           ; preds = %if.then, %entry
  ret void
}

declare void @side_effect()

test_name: and_select_first_implies_second_may_be_poison
test_body: define i1 @and_select_first_implies_second_may_be_poison(ptr noundef %A, ptr noundef %B) {
entry:
  %c.1 = icmp ne ptr %A, %B
  %gep = getelementptr inbounds ptr, ptr %B, i64 -1
  %c.2 = icmp ugt ptr %gep, %A
  %and = select i1 %c.2, i1 %c.1, i1 false
  ret i1 %and
}

test_name: test_second_and_condition_not_implied_by_first
test_body: define i1 @test_second_and_condition_not_implied_by_first(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %c.2 = icmp ugt i8 %x, 5
  %and = and i1 %c.2, %c.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_same_cond_for_and
test_body: define i1 @test_same_cond_for_and(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %and = and i1 %c.1, %c.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_second_and_condition_implied_by_first_select_form
test_body: define i1 @test_second_and_condition_implied_by_first_select_form(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %and = select i1 %c.1, i1 %t.1, i1 false
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_first_and_condition_implied_by_second_ops
test_body: define i1 @test_first_and_condition_implied_by_second_ops(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %and = and i1 %t.1, %c.1
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

file: llvm/test/Transforms/ConstraintElimination/eq.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: test_eq_for_signed_cmp_with_decompsition
test_body: define i1 @test_eq_for_signed_cmp_with_decompsition(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2, i32 noundef %addend0, i32 noundef %addend1) {
entry:
  %v0add = add nsw i32 %v0, %addend0
  %v1add = add nsw i32 %v1, %addend1
  %cmp = icmp eq i32 %v2, %v0add
  %cmp1 = icmp sge i32 %v0add, %v1add
  %cmp2 = icmp sge i32 %addend0, 0
  %cmp3 = icmp slt i32 %addend0, %addend1
  %and0 = and i1 %cmp1, %cmp
  %and1 = and i1 %and0, %cmp2
  %and2 = and i1 %and1, %cmp3
  %cmp4 = icmp sgt i32 %v1, %v2
  %and3 = and i1 %cmp4, %and2
  ret i1 %and3
}

test_name: test_eq_for_signed_cmp
test_body: define i1 @test_eq_for_signed_cmp(i32 noundef %v0, i32 noundef %v1, i32 noundef %v2) {
entry:
  %cmp = icmp eq i32 %v2, %v0
  %cmp1 = icmp sge i32 %v0, %v1
  %and0 = and i1 %cmp1, %cmp
  %cmp4 = icmp sgt i32 %v1, %v2
  %and1 = and i1 %cmp4, %and0
  ret i1 %and1
}

file: llvm/test/Transforms/ConstraintElimination/gep-arithmetic-signed-predicates.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: ptr_N_signed_positive_assume
test_body: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write)
declare void @llvm.assume(i1 noundef) #0

define i4 @ptr_N_signed_positive_assume(ptr %src, ptr %lower, ptr %upper, i16 %N, i16 %step) {
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:                                          ; preds = %ptr.check, %entry
  ret i4 2

step.check:                                       ; preds = %entry
  %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:                                        ; preds = %step.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:                                             ; preds = %ptr.check, %step.check
  ret i4 3
}

attributes #0 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) }

file: llvm/test/Transforms/ConstraintElimination/geps-precondition-overflow-check.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: overflow_check_4_and
test_body: define i1 @overflow_check_4_and(ptr %dst) {
entry:
  %dst.5 = getelementptr i32, ptr %dst, i64 5
  %dst.5.uge = icmp uge ptr %dst.5, %dst
  %and = and i1 %dst.5.uge, %dst.5.uge
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  %dst.4 = getelementptr i32, ptr %dst, i64 4
  %true.dst.4.uge = icmp uge ptr %dst.4, %dst
  %dst.5.2 = getelementptr i32, ptr %dst, i64 5
  %true.dst.5.uge = icmp uge ptr %dst.5.2, %dst
  %res.0 = xor i1 %true.dst.4.uge, %true.dst.5.uge
  %dst.6 = getelementptr i32, ptr %dst, i64 6
  %c.dst.6.uge = icmp uge ptr %dst.6, %dst
  %res.1 = xor i1 %res.0, %c.dst.6.uge
  ret i1 %res.1

else:                                             ; preds = %entry
  %else.dst.4 = getelementptr i32, ptr %dst, i64 4
  %else.dst.4.uge = icmp uge ptr %else.dst.4, %dst
  %else.dst.6 = getelementptr i32, ptr %dst, i64 6
  %else.dst.6.uge = icmp uge ptr %else.dst.6, %dst
  %else.res.0 = xor i1 %else.dst.4.uge, %else.dst.6.uge
  ret i1 %else.res.0
}

test_name: overflow_check_3_or
test_body: define i1 @overflow_check_3_or(ptr %dst) {
entry:
  %dst.5 = getelementptr i32, ptr %dst, i64 5
  %dst.5.uge = icmp uge ptr %dst.5, %dst
  %or = or i1 %dst.5.uge, %dst.5.uge
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  %dst.4 = getelementptr i32, ptr %dst, i64 4
  %true.dst.4.uge = icmp uge ptr %dst.4, %dst
  ret i1 %true.dst.4.uge

else:                                             ; preds = %entry
  ret i1 false
}

test_name: overflow_check_3_and
test_body: define i1 @overflow_check_3_and(ptr %dst) {
entry:
  %dst.5 = getelementptr i32, ptr %dst, i64 5
  %dst.5.uge = icmp uge ptr %dst.5, %dst
  %and = and i1 %dst.5.uge, %dst.5.uge
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  %dst.4 = getelementptr i32, ptr %dst, i64 4
  %dst.4.uge = icmp uge ptr %dst.4, %dst
  ret i1 %dst.4.uge

else:                                             ; preds = %entry
  %else.dst.4 = getelementptr i32, ptr %dst, i64 4
  %else.dst.4.uge = icmp uge ptr %else.dst.4, %dst
  ret i1 %else.dst.4.uge
}

test_name: overflow_check_2_and
test_body: define i1 @overflow_check_2_and(ptr %dst) {
entry:
  %dst.5 = getelementptr i32, ptr %dst, i64 5
  %dst.5.uge = icmp uge ptr %dst.5, %dst
  %and = and i1 %dst.5.uge, %dst.5.uge
  br i1 %and, label %then, label %else

then:                                             ; preds = %entry
  %dst.4 = getelementptr i32, ptr %dst, i64 4
  %true.dst.4.uge = icmp uge ptr %dst.4, %dst
  ret i1 %true.dst.4.uge

else:                                             ; preds = %entry
  ret i1 true
}

file: llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: checks_in_loops_removable
test_body: define void @checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n) {
entry:
  %cmp.ptr.lower = icmp ult ptr %ptr, %lower
  br i1 %cmp.ptr.lower, label %trap, label %pre.1

pre.1:                                            ; preds = %entry
  %idx.ext = zext i8 %n to i16
  %ptr.n = getelementptr inbounds i8, ptr %ptr, i16 %idx.ext
  %cmp.ptr.n.upper = icmp ult ptr %ptr.n, %upper
  br i1 %cmp.ptr.n.upper, label %pre.2, label %trap

pre.2:                                            ; preds = %pre.1
  %cmp.n.not.zero = icmp eq i8 %n, 0
  br i1 %cmp.n.not.zero, label %exit, label %loop.header

trap:                                             ; preds = %loop.header, %pre.1, %entry
  ret void

loop.header:                                      ; preds = %loop.latch, %pre.2
  %iv = phi i16 [ 0, %pre.2 ], [ %iv.next, %loop.latch ]
  %ptr.iv = getelementptr inbounds i8, ptr %ptr, i16 %iv
  %cmp.ptr.iv.lower = icmp ugt ptr %lower, %ptr.iv
  %cmp.ptr.iv.upper = icmp ule ptr %upper, %ptr.iv
  %or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
  br i1 %or, label %trap, label %loop.latch

loop.latch:                                       ; preds = %loop.header
  store i8 0, ptr %ptr.iv, align 4
  %iv.next = add nuw nsw i16 %iv, 1
  %exitcond = icmp ne i16 %iv.next, %idx.ext
  br i1 %exitcond, label %loop.header, label %exit

exit:                                             ; preds = %loop.latch, %pre.2
  ret void
}

test_name: some_checks_in_loops_removable
test_body: define void @some_checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n) {
entry:
  %cmp.ptr.lower = icmp ult ptr %ptr, %lower
  br i1 %cmp.ptr.lower, label %trap, label %pre.1

pre.1:                                            ; preds = %entry
  %idx.ext = zext i8 %n to i16
  %ptr.n = getelementptr inbounds i8, ptr %ptr, i16 %idx.ext
  %cmp.ptr.n.upper = icmp ult ptr %ptr.n, %upper
  br i1 %cmp.ptr.n.upper, label %pre.2, label %trap

pre.2:                                            ; preds = %pre.1
  %cmp.n.not.zero = icmp eq i8 %n, 0
  br i1 %cmp.n.not.zero, label %exit, label %loop.header

trap:                                             ; preds = %loop.body, %loop.header, %pre.1, %entry
  ret void

loop.header:                                      ; preds = %loop.latch, %pre.2
  %iv = phi i16 [ 0, %pre.2 ], [ %iv.next, %loop.latch ]
  %ptr.iv = getelementptr inbounds i8, ptr %ptr, i16 %iv
  %cmp.ptr.iv.lower = icmp ugt ptr %lower, %ptr.iv
  %cmp.ptr.iv.upper = icmp ule ptr %upper, %ptr.iv
  %or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
  br i1 %or, label %trap, label %loop.body

loop.body:                                        ; preds = %loop.header
  %iv.1 = add nuw nsw i16 %iv, 1
  %ptr.iv.1 = getelementptr inbounds i8, ptr %ptr, i16 %iv.1
  %cmp.ptr.iv.1.lower = icmp ugt ptr %lower, %ptr.iv.1
  %cmp.ptr.iv.1.upper = icmp ule ptr %upper, %ptr.iv.1
  %or.1 = or i1 %cmp.ptr.iv.1.lower, %cmp.ptr.iv.1.upper
  br i1 %or, label %trap, label %loop.latch

loop.latch:                                       ; preds = %loop.body
  store i8 0, ptr %ptr.iv, align 4
  %iv.next = add nuw nsw i16 %iv, 1
  %exitcond = icmp ne i16 %iv.next, %idx.ext
  br i1 %exitcond, label %loop.header, label %exit

exit:                                             ; preds = %loop.latch, %pre.2
  ret void
}

test_name: no_checks_in_loops_removable
test_body: define void @no_checks_in_loops_removable(ptr %ptr, ptr %lower, ptr %upper, i8 %n) {
entry:
  %cmp.ptr.lower = icmp ult ptr %ptr, %lower
  br i1 %cmp.ptr.lower, label %trap, label %pre.1

pre.1:                                            ; preds = %entry
  %idx.ext = zext i8 %n to i16
  %ptr.n = getelementptr inbounds i8, ptr %ptr, i16 %idx.ext
  %cmp.ptr.n.upper = icmp ult ptr %ptr.n, %upper
  br i1 %cmp.ptr.n.upper, label %loop.header, label %trap

trap:                                             ; preds = %loop.body, %loop.header, %pre.1, %entry
  ret void

loop.header:                                      ; preds = %loop.latch, %pre.1
  %iv = phi i16 [ 0, %pre.1 ], [ %iv.next, %loop.latch ]
  %ptr.iv = getelementptr inbounds i8, ptr %ptr, i16 %iv
  %cmp.ptr.iv.lower = icmp ugt ptr %lower, %ptr.iv
  %cmp.ptr.iv.upper = icmp ule ptr %upper, %ptr.iv
  %or = or i1 %cmp.ptr.iv.lower, %cmp.ptr.iv.upper
  br i1 %or, label %trap, label %loop.body

loop.body:                                        ; preds = %loop.header
  %iv.1 = add nuw nsw i16 %iv, 1
  %ptr.iv.1 = getelementptr inbounds i8, ptr %ptr, i16 %iv.1
  %cmp.ptr.iv.1.lower = icmp ugt ptr %lower, %ptr.iv.1
  %cmp.ptr.iv.1.upper = icmp ule ptr %upper, %ptr.iv.1
  %or.1 = or i1 %cmp.ptr.iv.1.lower, %cmp.ptr.iv.1.upper
  br i1 %or, label %trap, label %loop.latch

loop.latch:                                       ; preds = %loop.body
  store i8 0, ptr %ptr.iv, align 4
  %iv.next = add nuw nsw i16 %iv, 1
  %exitcond = icmp ne i16 %iv.next, %idx.ext
  br i1 %exitcond, label %loop.header, label %exit

exit:                                             ; preds = %loop.latch
  ret void
}

file: llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: test3
test_body: define void @test3(ptr %src, ptr %lower, ptr %upper, i8 %N) {
entry:
  %src.end = getelementptr inbounds i8, ptr %src, i8 %N
  %cmp.src.start = icmp ult ptr %src, %lower
  %cmp.src.end = icmp uge ptr %src.end, %upper
  %cmp.overflow = icmp ugt ptr %src, %src.end
  %or.0 = or i1 %cmp.src.start, %cmp.src.end
  %or.11 = or i1 %or.0, %cmp.overflow
  br i1 %or.11, label %trap.bb, label %loop.header

trap.bb:                                          ; preds = %loop.body.2, %loop.body.1, %loop.body, %entry
  ret void

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i8 [ %iv.next, %loop.latch ], [ 1, %entry ]
  %next = or i8 %iv, 1
  %ec = icmp ult i8 %next, %N
  br i1 %ec, label %loop.body, label %exit

loop.body:                                        ; preds = %loop.header
  %src.iv = getelementptr inbounds i8, ptr %src, i8 %iv
  %cmp.iv.start = icmp ult ptr %src.iv, %lower
  %cmp.iv.end = icmp uge ptr %src.iv, %upper
  %or.1 = or i1 %cmp.iv.start, %cmp.iv.end
  br i1 %or.1, label %trap.bb, label %loop.body.1

loop.body.1:                                      ; preds = %loop.body
  %src.iv.1 = getelementptr inbounds i8, ptr %src, i8 %next
  %cmp.iv.1.start = icmp ult ptr %src.iv.1, %lower
  %cmp.iv.1.end = icmp uge ptr %src.iv.1, %upper
  %or.2 = or i1 %cmp.iv.1.start, %cmp.iv.1.end
  br i1 %or.2, label %trap.bb, label %loop.body.2

loop.body.2:                                      ; preds = %loop.body.1
  %add.2 = add nuw nsw i8 %iv, 2
  %src.iv.2 = getelementptr inbounds i8, ptr %src, i8 %add.2
  %cmp.iv.2.start = icmp ult ptr %src.iv.2, %lower
  %cmp.iv.2.end = icmp uge ptr %src.iv.2, %upper
  %or.3 = or i1 %cmp.iv.2.start, %cmp.iv.2.end
  br i1 %or.3, label %trap.bb, label %loop.latch

loop.latch:                                       ; preds = %loop.body.2
  %ptr = bitcast ptr %src.iv to ptr
  store i32 0, ptr %ptr, align 4
  %iv.next = add nuw nsw i8 %iv, 1
  br label %loop.header

exit:                                             ; preds = %loop.header
  ret void
}

test_name: test2_with_ne
test_body: define void @test2_with_ne(ptr %src, ptr %lower, ptr %upper, i8 %N) {
entry:
  %src.end = getelementptr inbounds i8, ptr %src, i8 %N
  %cmp.src.start = icmp ult ptr %src, %lower
  %cmp.src.end = icmp uge ptr %src.end, %upper
  %cmp.overflow = icmp ugt ptr %src, %src.end
  %or.0 = or i1 %cmp.src.start, %cmp.src.end
  %or.11 = or i1 %or.0, %cmp.overflow
  br i1 %or.11, label %trap.bb, label %loop.header

trap.bb:                                          ; preds = %loop.body.2, %loop.body.1, %loop.body, %entry
  ret void

loop.header:                                      ; preds = %loop.latch, %entry
  %iv = phi i8 [ %iv.next, %loop.latch ], [ 1, %entry ]
  %next = add nuw nsw i8 %iv, 1
  %ec = icmp eq i8 %next, %N
  br i1 %ec, label %exit, label %loop.body

loop.body:                                        ; preds = %loop.header
  %src.iv = getelementptr inbounds i8, ptr %src, i8 %iv
  %cmp.iv.start = icmp ult ptr %src.iv, %lower
  %cmp.iv.end = icmp uge ptr %src.iv, %upper
  %or.1 = or i1 %cmp.iv.start, %cmp.iv.end
  br i1 %or.1, label %trap.bb, label %loop.body.1

loop.body.1:                                      ; preds = %loop.body
  %add.1 = add nuw nsw i8 %iv, 1
  %src.iv.1 = getelementptr inbounds i8, ptr %src, i8 %add.1
  %cmp.iv.1.start = icmp ult ptr %src.iv.1, %lower
  %cmp.iv.1.end = icmp uge ptr %src.iv.1, %upper
  %or.2 = or i1 %cmp.iv.1.start, %cmp.iv.1.end
  br i1 %or.2, label %trap.bb, label %loop.body.2

loop.body.2:                                      ; preds = %loop.body.1
  %add.2 = add nuw nsw i8 %iv, 2
  %src.iv.2 = getelementptr inbounds i8, ptr %src, i8 %add.2
  %cmp.iv.2.start = icmp ult ptr %src.iv.2, %lower
  %cmp.iv.2.end = icmp uge ptr %src.iv.2, %upper
  %or.3 = or i1 %cmp.iv.2.start, %cmp.iv.2.end
  br i1 %or.3, label %trap.bb, label %loop.latch

loop.latch:                                       ; preds = %loop.body.2
  %ptr = bitcast ptr %src.iv to ptr
  store i32 0, ptr %ptr, align 4
  %iv.next = add nuw nsw i8 %iv, 1
  br label %loop.header

exit:                                             ; preds = %loop.header
  ret void
}

file: llvm/test/Transforms/ConstraintElimination/or-implied-by-operands.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: test_or_used_in_false_branch2
test_body: define i1 @test_or_used_in_false_branch2(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %or = or i1 %c.1, %t.1
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  ret i1 %t.1

else:                                             ; preds = %entry
  ret i1 %t.1
}

test_name: test_same_cond_for_or
test_body: define i1 @test_same_cond_for_or(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %or = or i1 %c.1, %c.1
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_or_disjoint_set_operand
test_body: define i1 @test_or_disjoint_set_operand(i8 %x) {
entry:
  %cmp1 = icmp slt i8 %x, 1
  %cmp2 = icmp ne i8 %x, 0
  %or = or disjoint i1 %cmp2, %cmp1
  ret i1 %or
}

test_name: test_or_used_in_false_branch
test_body: define i1 @test_or_used_in_false_branch(i8 %x) {
entry:
  %c.1 = icmp ule i8 %x, 10
  %t.1 = icmp ule i8 %x, 5
  %or = or i1 %c.1, %t.1
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  ret i1 %t.1

else:                                             ; preds = %entry
  ret i1 %t.1
}

test_name: test_first_or_condition_implied_by_second_ops
test_body: define i1 @test_first_or_condition_implied_by_second_ops(i8 %x) {
entry:
  %c.1 = icmp ule i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %or = or i1 %t.1, %c.1
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_second_or_condition_implied_by_first
test_body: define i1 @test_second_or_condition_implied_by_first(i8 %x) {
entry:
  %c.1 = icmp ule i8 %x, 10
  %t.1 = icmp ugt i8 %x, 5
  %or = or i1 %c.1, %t.1
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

test_name: test_second_or_condition_not_implied_by_first
test_body: define i1 @test_second_or_condition_not_implied_by_first(i8 %x) {
entry:
  %c.1 = icmp ugt i8 %x, 10
  %c.2 = icmp ugt i8 %x, 5
  %or = or i1 %c.2, %c.1
  br i1 %or, label %then, label %else

then:                                             ; preds = %entry
  ret i1 false

else:                                             ; preds = %entry
  ret i1 true
}

file: llvm/test/Transforms/ConstraintElimination/or.ll
commands: opt -passes=constraint-elimination -S %s
tests: test_name: test_or_chain_ule_1
test_body: define i1 @test_or_chain_ule_1(i4 %x, i4 %y, i4 %z, i4 %a, i4 %b) {
entry:
  %c.1 = icmp ule i4 %x, %y
  %c.2 = icmp ule i4 %y, %z
  %c.3 = icmp ule i4 2, %x
  %c.4 = icmp ule i4 2, %a
  %or.1 = or i1 %c.1, %c.2
  %or.2 = or i1 %or.1, %c.3
  %or.3 = or i1 %c.4, %or.2
  br i1 %or.3, label %bb1, label %exit

bb1:                                              ; preds = %entry
  %c.5 = icmp ule i4 %x, %z
  %c.6 = icmp ule i4 %x, %a
  %res.1 = xor i1 %c.5, %c.6
  %c.7 = icmp ule i4 2, %x
  %res.2 = xor i1 %res.1, %c.7
  ret i1 %res.2

exit:                                             ; preds = %entry
  %f.1 = icmp ule i4 %x, %z
  %f.2 = icmp ule i4 2, %x
  %res.3 = xor i1 %f.1, %f.2
  %t.1 = icmp ugt i4 %y, %z
  %res.4 = xor i1 %res.3, %t.1
  %t.2 = icmp ugt i4 %x, %y
  %res.5 = xor i1 %res.4, %t.2
  %t.3 = icmp ugt i4 %x, %z
  %res.6 = xor i1 %res.5, %t.3
  %t.4 = icmp ugt i4 2, %a
  %res.7 = xor i1 %res.6, %t.4
  %c.8 = icmp ule i4 %x, %a
  %res.8 = xor i1 %res.7, %c.8
  %c.9 = icmp ule i4 %x, %b
  %res.9 = xor i1 %res.8, %c.9
  ret i1 %res.9
}