[llvm] r266767 - [ValueTracking] Improve isImpliedCondition for conditions with matching operands.

Chad Rosier via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 19 10:19:15 PDT 2016


Author: mcrosier
Date: Tue Apr 19 12:19:14 2016
New Revision: 266767

URL: http://llvm.org/viewvc/llvm-project?rev=266767&view=rev
Log:
[ValueTracking] Improve isImpliedCondition for conditions with matching operands.

This patch improves SimplifyCFG to catch cases like:

  if (a < b) {
    if (a > b) <- known to be false
      unreachable;
  }

Phabricator Revision: http://reviews.llvm.org/D18905

Added:
    llvm/trunk/test/Transforms/SimplifyCFG/implied-cond-matching.ll
Modified:
    llvm/trunk/include/llvm/Analysis/ValueTracking.h
    llvm/trunk/lib/Analysis/InstructionSimplify.cpp
    llvm/trunk/lib/Analysis/ValueTracking.cpp
    llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp
    llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
    llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll

Modified: llvm/trunk/include/llvm/Analysis/ValueTracking.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ValueTracking.h?rev=266767&r1=266766&r2=266767&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ValueTracking.h (original)
+++ llvm/trunk/include/llvm/Analysis/ValueTracking.h Tue Apr 19 12:19:14 2016
@@ -436,16 +436,18 @@ template <typename T> class ArrayRef;
   /// E.g. if RangeMD is !{i32 0, i32 10, i32 15, i32 20} then return [0, 20).
   ConstantRange getConstantRangeFromMetadata(MDNode &RangeMD);
 
-  /// Return true if RHS is known to be implied by LHS.  A & B must be i1
-  /// (boolean) values or a vector of such values. Note that the truth table for
-  /// implication is the same as <=u on i1 values (but not <=s!).  The truth
-  /// table for both is:
+  /// Return true if RHS is known to be implied by LHS.  The implication may be
+  /// either true or false depending on what is returned in ImpliedTrue.
+  /// A & B must be i1 (boolean) values or a vector of such values. Note that
+  /// the truth table for implication is the same as <=u on i1 values (but not
+  /// <=s!).  The truth table for both is:
   ///    | T | F (B)
   ///  T | T | F
   ///  F | T | T
   /// (A)
-  bool isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL,
-                          unsigned Depth = 0, AssumptionCache *AC = nullptr,
+  bool isImpliedCondition(Value *LHS, Value *RHS, bool &ImpliedTrue,
+                          const DataLayout &DL, unsigned Depth = 0,
+                          AssumptionCache *AC = nullptr,
                           const Instruction *CxtI = nullptr,
                           const DominatorTree *DT = nullptr);
 } // end namespace llvm

Modified: llvm/trunk/lib/Analysis/InstructionSimplify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InstructionSimplify.cpp?rev=266767&r1=266766&r2=266767&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InstructionSimplify.cpp (original)
+++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp Tue Apr 19 12:19:14 2016
@@ -2131,14 +2131,16 @@ static Value *SimplifyICmpInst(unsigned
       if (match(RHS, m_Zero()))
         return LHS;
       break;
-    case ICmpInst::ICMP_UGE:
+    case ICmpInst::ICMP_UGE: {
       // X >=u 1 -> X
       if (match(RHS, m_One()))
         return LHS;
-      if (isImpliedCondition(RHS, LHS, Q.DL))
+      bool ImpliedTrue;
+      if (isImpliedCondition(RHS, LHS, ImpliedTrue, Q.DL) && ImpliedTrue)
         return getTrue(ITy);
       break;
-    case ICmpInst::ICMP_SGE:
+    }
+    case ICmpInst::ICMP_SGE: {
       /// For signed comparison, the values for an i1 are 0 and -1
       /// respectively. This maps into a truth table of:
       /// LHS | RHS | LHS >=s RHS   | LHS implies RHS
@@ -2146,9 +2148,11 @@ static Value *SimplifyICmpInst(unsigned
       ///  0  |  1  |  1 (0 >= -1)  |  1
       ///  1  |  0  |  0 (-1 >= 0)  |  0
       ///  1  |  1  |  1 (-1 >= -1) |  1
-      if (isImpliedCondition(LHS, RHS, Q.DL))
+      bool ImpliedTrue;
+      if (isImpliedCondition(LHS, RHS, ImpliedTrue, Q.DL) && ImpliedTrue)
         return getTrue(ITy);
       break;
+    }
     case ICmpInst::ICMP_SLT:
       // X <s 0 -> X
       if (match(RHS, m_Zero()))
@@ -2159,11 +2163,13 @@ static Value *SimplifyICmpInst(unsigned
       if (match(RHS, m_One()))
         return LHS;
       break;
-    case ICmpInst::ICMP_ULE:
-      if (isImpliedCondition(LHS, RHS, Q.DL))
+    case ICmpInst::ICMP_ULE: {
+      bool ImpliedTrue;
+      if (isImpliedCondition(LHS, RHS, ImpliedTrue, Q.DL) && ImpliedTrue)
         return getTrue(ITy);
       break;
     }
+    }
   }
 
   // If we are comparing with zero then try hard since this is a common case.

Modified: llvm/trunk/lib/Analysis/ValueTracking.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ValueTracking.cpp?rev=266767&r1=266766&r2=266767&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ValueTracking.cpp (original)
+++ llvm/trunk/lib/Analysis/ValueTracking.cpp Tue Apr 19 12:19:14 2016
@@ -3788,16 +3788,104 @@ static bool isImpliedCondOperands(CmpIns
   }
 }
 
-bool llvm::isImpliedCondition(Value *LHS, Value *RHS, const DataLayout &DL,
-                              unsigned Depth, AssumptionCache *AC,
-                              const Instruction *CxtI,
+/// Return true if "icmp2 BPred BLHS BRHS" is known to be implied by "icmp1
+/// APred ALHS ARHS".  The implication may be either true or false depending on
+/// the return value of ImpliedTrue.
+static bool isImpliedCondMatchingOperands(CmpInst::Predicate APred, Value *ALHS,
+                                          Value *ARHS, CmpInst::Predicate BPred,
+                                          Value *BLHS, Value *BRHS,
+                                          bool &ImpliedTrue) {
+  // The operands of the two compares must match.
+  bool IsMatchingOps = (ALHS == BLHS && ARHS == BRHS);
+  bool IsSwappedOps = (ALHS == BRHS && ARHS == BLHS);
+  if (!IsMatchingOps && !IsSwappedOps)
+    return false;
+
+  // Canonicalize the operands so they're matching.
+  if (IsSwappedOps) {
+    std::swap(BLHS, BRHS);
+    BPred = ICmpInst::getSwappedPredicate(BPred);
+  }
+
+  // If the predicates match, then we know the first condition implies the
+  // second is true.
+  if (APred == BPred) {
+    ImpliedTrue = true;
+    return true;
+  }
+
+  // If an inverted APred matches BPred, we can infer the second condition is
+  // false.
+  if (CmpInst::getInversePredicate(APred) == BPred) {
+    ImpliedTrue = false;
+    return true;
+  }
+
+  // If a swapped APred matches BPred, we can infer the second condition is
+  // false in many cases.
+  if (CmpInst::getSwappedPredicate(APred) == BPred) {
+    switch (APred) {
+    default:
+      break;
+    case CmpInst::ICMP_UGT: // A >u B implies A <u B is false.
+    case CmpInst::ICMP_ULT: // A <u B implies A >u B is false.
+    case CmpInst::ICMP_SGT: // A >s B implies A <s B is false.
+    case CmpInst::ICMP_SLT: // A <s B implies A >s B is false.
+      ImpliedTrue = false;
+      return true;
+    }
+  }
+
+  // The predicates must match sign or at least one of them must be an equality
+  // comparison (which is signless).
+  if (ICmpInst::isSigned(APred) != ICmpInst::isSigned(BPred) &&
+      !ICmpInst::isEquality(APred) && !ICmpInst::isEquality(BPred))
+    return false;
+
+  switch (APred) {
+  default:
+    break;
+  case CmpInst::ICMP_EQ:
+    // A == B implies A > B and A < B are false.
+    if (CmpInst::isFalseWhenEqual(BPred)) {
+      ImpliedTrue = false;
+      return true;
+    }
+    break;
+  case CmpInst::ICMP_UGT:
+  case CmpInst::ICMP_ULT:
+  case CmpInst::ICMP_SGT:
+  case CmpInst::ICMP_SLT:
+    // A > B implies A == B is false.
+    // A < B implies A == B is false.
+    if (BPred == CmpInst::ICMP_EQ) {
+      ImpliedTrue = false;
+      return true;
+    }
+    // A > B implies A != B is true.
+    // A < B implies A != B is true.
+    if (BPred == CmpInst::ICMP_NE) {
+      ImpliedTrue = true;
+      return true;
+    }
+    break;
+  }
+  return false;
+}
+
+bool llvm::isImpliedCondition(Value *LHS, Value *RHS, bool &ImpliedTrue,
+                              const DataLayout &DL, unsigned Depth,
+                              AssumptionCache *AC, const Instruction *CxtI,
                               const DominatorTree *DT) {
   assert(LHS->getType() == RHS->getType() && "mismatched type");
   Type *OpTy = LHS->getType();
   assert(OpTy->getScalarType()->isIntegerTy(1));
 
   // LHS ==> RHS by definition
-  if (LHS == RHS) return true;
+  if (LHS == RHS) {
+    ImpliedTrue = true;
+    return true;
+  }
 
   if (OpTy->isVectorTy())
     // TODO: extending the code below to handle vectors
@@ -3812,9 +3900,15 @@ bool llvm::isImpliedCondition(Value *LHS
       !match(RHS, m_ICmp(BPred, m_Value(BLHS), m_Value(BRHS))))
     return false;
 
-  if (APred == BPred)
+  if (isImpliedCondMatchingOperands(APred, ALHS, ARHS, BPred, BLHS, BRHS,
+                                    ImpliedTrue))
+    return true;
+
+  if (APred == BPred) {
+    ImpliedTrue = true;
     return isImpliedCondOperands(APred, ALHS, ARHS, BLHS, BRHS, DL, Depth, AC,
                                  CxtI, DT);
+  }
 
   return false;
 }

Modified: llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp?rev=266767&r1=266766&r2=266767&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/JumpThreading.cpp Tue Apr 19 12:19:14 2016
@@ -928,9 +928,10 @@ bool JumpThreading::ProcessImpliedCondit
     if (!PBI || !PBI->isConditional() || PBI->getSuccessor(0) != CurrentBB)
       return false;
 
-    if (isImpliedCondition(PBI->getCondition(), Cond, DL)) {
-      BI->getSuccessor(1)->removePredecessor(BB);
-      BranchInst::Create(BI->getSuccessor(0), BI);
+    bool ImpliedTrue;
+    if (isImpliedCondition(PBI->getCondition(), Cond, ImpliedTrue, DL)) {
+      BI->getSuccessor(ImpliedTrue ? 1 : 0)->removePredecessor(BB);
+      BranchInst::Create(BI->getSuccessor(ImpliedTrue ? 0 : 1), BI);
       BI->eraseFromParent();
       return true;
     }

Modified: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp?rev=266767&r1=266766&r2=266767&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp Tue Apr 19 12:19:14 2016
@@ -2722,13 +2722,17 @@ static bool SimplifyCondBranchToCondBran
 
   // If BI is reached from the true path of PBI and PBI's condition implies
   // BI's condition, we know the direction of the BI branch.
+  bool ImpliedTrue;
   if (PBI->getSuccessor(0) == BI->getParent() &&
-      isImpliedCondition(PBI->getCondition(), BI->getCondition(), DL) &&
+      isImpliedCondition(PBI->getCondition(), BI->getCondition(), ImpliedTrue,
+                         DL) &&
       PBI->getSuccessor(0) != PBI->getSuccessor(1) &&
       BB->getSinglePredecessor()) {
     // Turn this into a branch on constant.
     auto *OldCond = BI->getCondition();
-    BI->setCondition(ConstantInt::getTrue(BB->getContext()));
+    ConstantInt *CI = ImpliedTrue ? ConstantInt::getTrue(BB->getContext())
+                                  : ConstantInt::getFalse(BB->getContext());
+    BI->setCondition(CI);
     RecursivelyDeleteTriviallyDeadInstructions(OldCond);
     return true;  // Nuke the branch on constant.
   }

Modified: llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll?rev=266767&r1=266766&r2=266767&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll (original)
+++ llvm/trunk/test/Transforms/JumpThreading/implied-cond.ll Tue Apr 19 12:19:14 2016
@@ -96,3 +96,32 @@ define void @test2(i32 %i, i32 %len, i1*
   call void @side_effect(i32 %t)
   ret void
 }
+
+; A s<= B implies A s> B is false.
+; CHECK-LABEL: @test3(
+; CHECK: entry:
+; CHECK: br i1 %cmp, label %if.end, label %if.end3
+; CHECK-NOT: br i1 %cmp1, label %if.then2, label %if.end
+; CHECK-NOT: call void @side_effect(i32 0)
+; CHECK: br label %if.end3
+; CHECK: ret void
+
+define void @test3(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp sle i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp sgt i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @side_effect(i32 0)
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}

Added: llvm/trunk/test/Transforms/SimplifyCFG/implied-cond-matching.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/implied-cond-matching.ll?rev=266767&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SimplifyCFG/implied-cond-matching.ll (added)
+++ llvm/trunk/test/Transforms/SimplifyCFG/implied-cond-matching.ll Tue Apr 19 12:19:14 2016
@@ -0,0 +1,478 @@
+; RUN: opt %s -S -simplifycfg | FileCheck %s
+
+; Test same condition with swapped operands.
+; void test_swapped_ops(unsigned a, unsigned b) {
+;   if (a > b) {
+;     if (b > a) <- always false
+;       dead();
+;     alive();
+;   }
+; }
+;
+; CHECK-LABEL: @test_swapped_ops
+; CHECK-NOT: call void @dead()
+; CHECK: call void @alive()
+; CHECK: ret
+define void @test_swapped_ops(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ugt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp ugt i32 %b, %a
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  call void @alive()
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; void test_swapped_pred(unsigned a, unsigned b) {
+;   if (a > b) {
+;     alive();
+;     if (b < a) <- always true; remove branch
+;       alive();
+;   }
+; }
+;
+; CHECK-LABEL: @test_swapped_pred
+; CHECK: call void @alive()
+; CHECK-NEXT: call void @alive()
+; CHECK: ret
+define void @test_swapped_pred(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ugt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  call void @alive()
+  %cmp1 = icmp ult i32 %b, %a
+  br i1 %cmp1, label %if.then2, label %if.end3
+
+if.then2:
+  call void @alive()
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A == B implies A >u B is false
+; A == B implies A <u B is false
+; CHECK-LABEL: @test_eq_unsigned
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_eq_unsigned(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp eq i32 %a, %b
+  br i1 %cmp, label %if.end, label %if.end9
+
+if.end:
+  %cmp3 = icmp ugt i32 %a, %b
+  br i1 %cmp3, label %if.then4, label %if.end5
+
+if.then4:
+  call void @dead()
+  br label %if.end5
+
+if.end5:
+  %cmp6 = icmp ult i32 %a, %b
+  br i1 %cmp6, label %if.then7, label %if.end8
+
+if.then7:
+  call void @dead()
+  br label %if.end8
+
+if.end8:
+  br label %if.end9
+
+if.end9:
+  ret void
+}
+
+; A == B implies A >s B is false
+; A == B implies A <s B is false
+; CHECK-LABEL: @test_eq_signed
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_eq_signed(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp eq i32 %a, %b
+  br i1 %cmp, label %if.end, label %if.end9
+
+if.end:
+  %cmp3 = icmp sgt i32 %a, %b
+  br i1 %cmp3, label %if.then4, label %if.end5
+
+if.then4:
+  call void @dead()
+  br label %if.end5
+
+if.end5:
+  %cmp6 = icmp slt i32 %a, %b
+  br i1 %cmp6, label %if.then7, label %if.end8
+
+if.then7:
+  call void @dead()
+  br label %if.end8
+
+if.end8:
+  br label %if.end9
+
+if.end9:
+  ret void
+}
+
+; A != B implies A == B is false
+; CHECK-LABEL: @test_ne
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_ne(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ne i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp eq i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A >u B implies A == B is false.
+; A >u B implies A <=u B is false.
+; A >u B implies A != B is true.
+; CHECK-LABEL: @test_ugt
+; CHECK-NOT: dead
+; CHECK: alive
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_ugt(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ugt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end9
+
+if.then:
+  %cmp1 = icmp eq i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  %cmp3 = icmp ule i32 %a, %b
+  br i1 %cmp3, label %if.then4, label %if.end5
+
+if.then4:
+  call void @dead()
+  br label %if.end5
+
+if.end5:
+  %cmp6 = icmp ne i32 %a, %b
+  br i1 %cmp6, label %if.then7, label %if.end8
+
+if.then7:
+  call void @alive()
+  br label %if.end8
+
+if.end8:
+  br label %if.end9
+
+if.end9:
+  ret void
+}
+
+; A >s B implies A == B is false.
+; A >s B implies A <=s B is false.
+; A >s B implies A != B is true.
+; CHECK-LABEL: @test_sgt
+; CHECK-NOT: dead
+; CHECK: alive
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_sgt(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp sgt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end9
+
+if.then:
+  %cmp1 = icmp eq i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  %cmp3 = icmp sle i32 %a, %b
+  br i1 %cmp3, label %if.then4, label %if.end5
+
+if.then4:
+  call void @dead()
+  br label %if.end5
+
+if.end5:
+  %cmp6 = icmp ne i32 %a, %b
+  br i1 %cmp6, label %if.then7, label %if.end8
+
+if.then7:
+  call void @alive()
+  br label %if.end8
+
+if.end8:
+  br label %if.end9
+
+if.end9:
+  ret void
+}
+
+; A <u B implies A == B is false.
+; A <u B implies A >=u B is false.
+; A <u B implies A != B is true.
+; CHECK-LABEL: @test_ult
+; CHECK-NOT: dead
+; CHECK: alive
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_ult(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ult i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end9
+
+if.then:
+  %cmp1 = icmp eq i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  %cmp3 = icmp uge i32 %a, %b
+  br i1 %cmp3, label %if.then4, label %if.end5
+
+if.then4:
+  call void @dead()
+  br label %if.end5
+
+if.end5:
+  %cmp6 = icmp eq i32 %a, %b
+  br i1 %cmp6, label %if.end8, label %if.then7
+
+if.then7:
+  call void @alive()
+  br label %if.end8
+
+if.end8:
+  br label %if.end9
+
+if.end9:
+  ret void
+}
+
+; A <s B implies A == B is false.
+; A <s B implies A >=s B is false.
+; A <s B implies A != B is true.
+; CHECK-LABEL: @test_slt
+; CHECK-NOT: dead
+; CHECK: alive
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_slt(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp slt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end9
+
+if.then:
+  %cmp1 = icmp eq i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  %cmp3 = icmp sge i32 %a, %b
+  br i1 %cmp3, label %if.then4, label %if.end5
+
+if.then4:
+  call void @dead()
+  br label %if.end5
+
+if.end5:
+  %cmp6 = icmp eq i32 %a, %b
+  br i1 %cmp6, label %if.end8, label %if.then7
+
+if.then7:
+  call void @alive()
+  br label %if.end8
+
+if.end8:
+  br label %if.end9
+
+if.end9:
+  ret void
+}
+
+; A >=u B implies A <u B is false.
+; CHECK-LABEL: @test_uge
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_uge(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp uge i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp ult i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A >=s B implies A <s B is false.
+; CHECK-LABEL: @test_sge
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_sge(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp sge i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp slt i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A <=u B implies A >u B is false.
+; CHECK-LABEL: @test_ule
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_ule(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ule i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp ugt i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A <=s B implies A >s B is false.
+; CHECK-LABEL: @test_sle
+; CHECK-NOT: dead
+; CHECK: ret void
+define void @test_sle(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp sle i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp sgt i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @dead()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A u<= B does not imply A s> B is false.
+; CHECK-LABEL: @test_ule_sgt_unsafe
+; CHECK: alive
+; CHECK: ret void
+define void @test_ule_sgt_unsafe(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ule i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp sgt i32 %a, %b
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @alive()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+; A u> B does not imply B s> A is false.
+; CHECK-LABEL: @test_ugt_sgt_unsafe
+; CHECK: alive
+; CHECK: ret void
+define void @test_ugt_sgt_unsafe(i32 %a, i32 %b) {
+entry:
+  %cmp = icmp ugt i32 %a, %b
+  br i1 %cmp, label %if.then, label %if.end3
+
+if.then:
+  %cmp1 = icmp sgt i32 %b, %a
+  br i1 %cmp1, label %if.then2, label %if.end
+
+if.then2:
+  call void @alive()
+  br label %if.end
+
+if.end:
+  br label %if.end3
+
+if.end3:
+  ret void
+}
+
+declare void @dead()
+declare void @alive()




More information about the llvm-commits mailing list