[llvm] cd84cab - [LVI] Support urem in implied conditions

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 20 12:01:43 PST 2021


Author: Nikita Popov
Date: 2021-11-20T21:01:26+01:00
New Revision: cd84cab6b37f615d0babd0b1c7b9e3acef5586c2

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

LOG: [LVI] Support urem in implied conditions

If (X urem M) >= C we know that X >= C. Make use of this fact
when computing the implied condition range.

In some cases we could also establish an upper bound, but that's
both tricker and not interesting in practice.

Alive: https://alive2.llvm.org/ce/z/R5ZGSW

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 50fa169c20815..4d7a009402ecb 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1095,7 +1095,8 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
   if (!Ty->isIntegerTy())
     return ValueLatticeElement::getOverdefined();
 
-  APInt Offset(Ty->getScalarSizeInBits(), 0);
+  unsigned BitWidth = Ty->getScalarSizeInBits();
+  APInt Offset(BitWidth, 0);
   if (matchICmpOperand(Offset, LHS, Val, EdgePred))
     return getValueFromSimpleICmpCondition(EdgePred, RHS, Offset);
 
@@ -1118,13 +1119,24 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
     // If (Val & Mask) != 0 then the value must be larger than the lowest set
     // bit of Mask.
     if (EdgePred == ICmpInst::ICMP_NE && !Mask->isZero() && C->isZero()) {
-      unsigned BitWidth = Ty->getIntegerBitWidth();
       return ValueLatticeElement::getRange(ConstantRange::getNonEmpty(
           APInt::getOneBitSet(BitWidth, Mask->countTrailingZeros()),
           APInt::getZero(BitWidth)));
     }
   }
 
+  // If (X urem Modulus) >= C, then X >= C.
+  // TODO: An upper bound could be computed as well.
+  const APInt *Modulus;
+  if (match(LHS, m_URem(m_Specific(Val), m_APInt(Modulus))) &&
+      match(RHS, m_APInt(C))) {
+    // Use the icmp region so we don't have to deal with 
diff erent predicates.
+    ConstantRange CR = ConstantRange::makeExactICmpRegion(EdgePred, *C);
+    if (!CR.isEmptySet())
+      return ValueLatticeElement::getRange(ConstantRange::getNonEmpty(
+          CR.getUnsignedMin(), APInt(BitWidth, 0)));
+  }
+
   return ValueLatticeElement::getOverdefined();
 }
 

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll
index 56f556363e16d..0aa0971cad9d1 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll
@@ -161,18 +161,18 @@ define void @non_power_of_2(i24 %n) {
   ret void
 }
 
+; (x urem 5) uge 2 implies x uge 2 on the true branch.
+; We don't know anything about the lower bound on the false branch.
 define void @urem_implied_cond_uge(i8 %x) {
 ; CHECK-LABEL: @urem_implied_cond_uge(
 ; CHECK-NEXT:    [[U:%.*]] = urem i8 [[X:%.*]], 5
 ; CHECK-NEXT:    [[C1:%.*]] = icmp uge i8 [[U]], 2
 ; CHECK-NEXT:    br i1 [[C1]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
-; CHECK-NEXT:    [[C2:%.*]] = icmp ult i8 [[X]], 2
-; CHECK-NEXT:    call void @use(i1 [[C2]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[C3:%.*]] = icmp ule i8 [[X]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C3]])
-; CHECK-NEXT:    [[C4:%.*]] = icmp uge i8 [[X]], 2
-; CHECK-NEXT:    call void @use(i1 [[C4]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C5:%.*]] = icmp ugt i8 [[X]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C5]])
 ; CHECK-NEXT:    ret void
@@ -214,6 +214,8 @@ else:
   ret void
 }
 
+; (x urem 5) uge 5 is always false. It ends up being folded first, but if it
+; weren't, we should handle that gracefully.
 define void @urem_implied_cond_uge_out_of_range(i8 %x) {
 ; CHECK-LABEL: @urem_implied_cond_uge_out_of_range(
 ; CHECK-NEXT:    [[U:%.*]] = urem i8 [[X:%.*]], 5
@@ -266,18 +268,17 @@ else:
   ret void
 }
 
+; (x urem 5) != 0 is the same as (x urem 5) >= 1 and implies x >= 1.
 define void @urem_implied_cond_ne_zero(i8 %x) {
 ; CHECK-LABEL: @urem_implied_cond_ne_zero(
 ; CHECK-NEXT:    [[U:%.*]] = urem i8 [[X:%.*]], 5
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[U]], 0
 ; CHECK-NEXT:    br i1 [[C1]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
-; CHECK-NEXT:    [[C2:%.*]] = icmp ult i8 [[X]], 1
-; CHECK-NEXT:    call void @use(i1 [[C2]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[C3:%.*]] = icmp ule i8 [[X]], 1
 ; CHECK-NEXT:    call void @use(i1 [[C3]])
-; CHECK-NEXT:    [[C4:%.*]] = icmp uge i8 [[X]], 1
-; CHECK-NEXT:    call void @use(i1 [[C4]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C5:%.*]] = icmp ugt i8 [[X]], 1
 ; CHECK-NEXT:    call void @use(i1 [[C5]])
 ; CHECK-NEXT:    ret void
@@ -319,6 +320,8 @@ else:
   ret void
 }
 
+; (x urem 5) != 1 doesn't imply anything on the true branch. However, on the
+; false branch (x urem 5) == 1 implies x >= 1.
 define void @urem_implied_cond_ne_non_zero(i8 %x) {
 ; CHECK-LABEL: @urem_implied_cond_ne_non_zero(
 ; CHECK-NEXT:    [[U:%.*]] = urem i8 [[X:%.*]], 5
@@ -335,12 +338,10 @@ define void @urem_implied_cond_ne_non_zero(i8 %x) {
 ; CHECK-NEXT:    call void @use(i1 [[C5]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
-; CHECK-NEXT:    [[C2_2:%.*]] = icmp ult i8 [[X]], 1
-; CHECK-NEXT:    call void @use(i1 [[C2_2]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[C3_2:%.*]] = icmp ule i8 [[X]], 1
 ; CHECK-NEXT:    call void @use(i1 [[C3_2]])
-; CHECK-NEXT:    [[C4_2:%.*]] = icmp uge i8 [[X]], 1
-; CHECK-NEXT:    call void @use(i1 [[C4_2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C5_2:%.*]] = icmp ugt i8 [[X]], 1
 ; CHECK-NEXT:    call void @use(i1 [[C5_2]])
 ; CHECK-NEXT:    ret void


        


More information about the llvm-commits mailing list