[llvm] 91836fd - [LVI][CVP] Handle (x | y) < C style conditions

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 1 11:47:46 PDT 2020


Author: Nikita Popov
Date: 2020-07-01T20:43:24+02:00
New Revision: 91836fd7f3c128b4c608bd4b389a64ff4ac1db8a

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

LOG: [LVI][CVP] Handle (x | y) < C style conditions

InstCombine may convert conditions like (x < C) && (y < C) into
(x | y) < C (for some C). This patch teaches LVI to recognize that
in this case, it can infer either x < C or y < C along the edge.

This fixes the issue reported at
https://github.com/rust-lang/rust/issues/73827.

Differential Revision: https://reviews.llvm.org/D82715

Added: 
    

Modified: 
    llvm/lib/Analysis/LazyValueInfo.cpp
    llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index a73bc4f91d10..fb14008a2b47 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1093,7 +1093,8 @@ Optional<ValueLatticeElement> LazyValueInfoImpl::solveBlockValueExtractValue(
   return ValueLatticeElement::getOverdefined();
 }
 
-static bool matchICmpOperand(const APInt *&Offset, Value *LHS, Value *Val) {
+static bool matchICmpOperand(const APInt *&Offset, Value *LHS, Value *Val,
+                             ICmpInst::Predicate Pred) {
   if (LHS == Val)
     return true;
 
@@ -1102,6 +1103,16 @@ static bool matchICmpOperand(const APInt *&Offset, Value *LHS, Value *Val) {
   if (match(LHS, m_Add(m_Specific(Val), m_APInt(Offset))))
     return true;
 
+  // If (x | y) < C, then (x < C) && (y < C).
+  if (match(LHS, m_c_Or(m_Specific(Val), m_Value())) &&
+      (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE))
+    return true;
+
+  // If (x & y) > C, then (x > C) && (y > C).
+  if (match(LHS, m_c_And(m_Specific(Val), m_Value())) &&
+      (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE))
+    return true;
+
   return false;
 }
 
@@ -1127,10 +1138,10 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
     return ValueLatticeElement::getOverdefined();
 
   const APInt *Offset = nullptr;
-  if (!matchICmpOperand(Offset, LHS, Val)) {
+  if (!matchICmpOperand(Offset, LHS, Val, EdgePred)) {
     std::swap(LHS, RHS);
     EdgePred = CmpInst::getSwappedPredicate(EdgePred);
-    if (!matchICmpOperand(Offset, LHS, Val))
+    if (!matchICmpOperand(Offset, LHS, Val, EdgePred))
       return ValueLatticeElement::getOverdefined();
   }
 

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
index 7bd997a3fefd..0eb28bdc5b44 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll
@@ -659,10 +659,8 @@ define void @test_icmp_or_ult(i32 %a, i32 %b) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[OR]], 42
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ult i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    [[CMP4:%.*]] = icmp uge i32 [[A]], 42
@@ -698,10 +696,8 @@ define void @test_icmp_or_ule(i32 %a, i32 %b) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ule i32 [[OR]], 42
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ule i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ule i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    [[CMP4:%.*]] = icmp ugt i32 [[A]], 42
@@ -743,10 +739,8 @@ define void @test_icmp_or_ugt(i32 %a, i32 %b) {
 ; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
-; CHECK-NEXT:    [[CMP4:%.*]] = icmp ule i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
-; CHECK-NEXT:    [[CMP5:%.*]] = icmp ule i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -782,10 +776,8 @@ define void @test_icmp_or_uge(i32 %a, i32 %b) {
 ; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
-; CHECK-NEXT:    [[CMP4:%.*]] = icmp ult i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
-; CHECK-NEXT:    [[CMP5:%.*]] = icmp ult i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -854,10 +846,8 @@ define void @test_icmp_and_ugt(i32 %a, i32 %b) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[AND]], 42
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ugt i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp ugt i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    [[CMP4:%.*]] = icmp ule i32 [[A]], 42
@@ -893,10 +883,8 @@ define void @test_icmp_and_uge(i32 %a, i32 %b) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i32 [[AND]], 42
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; CHECK:       if.true:
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp uge i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP2]])
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp uge i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
 ; CHECK-NEXT:    [[CMP4:%.*]] = icmp ult i32 [[A]], 42
@@ -938,10 +926,8 @@ define void @test_icmp_and_ult(i32 %a, i32 %b) {
 ; CHECK-NEXT:    call void @check1(i1 [[CMP3]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.false:
-; CHECK-NEXT:    [[CMP4:%.*]] = icmp uge i32 [[A]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP4]])
-; CHECK-NEXT:    [[CMP5:%.*]] = icmp uge i32 [[B]], 42
-; CHECK-NEXT:    call void @check1(i1 [[CMP5]])
+; CHECK-NEXT:    call void @check1(i1 true)
+; CHECK-NEXT:    call void @check1(i1 true)
 ; CHECK-NEXT:    ret void
 ;
 entry:


        


More information about the llvm-commits mailing list