[llvm] r358597 - [LVI][CVP] Constrain values in with.overflow branches

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 17 09:57:42 PDT 2019


Author: nikic
Date: Wed Apr 17 09:57:42 2019
New Revision: 358597

URL: http://llvm.org/viewvc/llvm-project?rev=358597&view=rev
Log:
[LVI][CVP] Constrain values in with.overflow branches

If a branch is conditional on extractvalue(op.with.overflow(%x, C), 1)
then we can constrain the value of %x inside the branch based on
makeGuaranteedNoWrapRegion(). We do this by extending the edge-value
handling in LVI. This allows CVP to then fold comparisons against %x,
as illustrated in the tests.

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

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

Modified: llvm/trunk/lib/Analysis/LazyValueInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyValueInfo.cpp?rev=358597&r1=358596&r2=358597&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/LazyValueInfo.cpp (original)
+++ llvm/trunk/lib/Analysis/LazyValueInfo.cpp Wed Apr 17 09:57:42 2019
@@ -1134,6 +1134,28 @@ static ValueLatticeElement getValueFromI
   return ValueLatticeElement::getOverdefined();
 }
 
+// Handle conditions of the form
+// extractvalue(op.with.overflow(%x, C), 1).
+static ValueLatticeElement getValueFromOverflowCondition(
+    Value *Val, WithOverflowInst *WO, bool IsTrueDest) {
+  // TODO: This only works with a constant RHS for now. We could also compute
+  // the range of the RHS, but this doesn't fit into the current structure of
+  // the edge value calculation.
+  const APInt *C;
+  if (WO->getLHS() != Val || !match(WO->getRHS(), m_APInt(C)))
+    return ValueLatticeElement::getOverdefined();
+
+  // Calculate the possible values of %x for which no overflow occurs.
+  ConstantRange NWR = ConstantRange::makeGuaranteedNoWrapRegion(
+      WO->getBinaryOp(), ConstantRange(*C), WO->getNoWrapKind());
+
+  // If overflow is false, %x is constrained to NWR. If overflow is true, %x is
+  // constrained to it's inverse (all values that might cause overflow).
+  if (IsTrueDest)
+    NWR = NWR.inverse();
+  return ValueLatticeElement::getRange(NWR);
+}
+
 static ValueLatticeElement
 getValueFromCondition(Value *Val, Value *Cond, bool isTrueDest,
                       DenseMap<Value*, ValueLatticeElement> &Visited);
@@ -1144,6 +1166,11 @@ getValueFromConditionImpl(Value *Val, Va
   if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
     return getValueFromICmpCondition(Val, ICI, isTrueDest);
 
+  if (auto *EVI = dyn_cast<ExtractValueInst>(Cond))
+    if (auto *WO = dyn_cast<WithOverflowInst>(EVI->getAggregateOperand()))
+      if (EVI->getNumIndices() == 1 && *EVI->idx_begin() == 1)
+        return getValueFromOverflowCondition(Val, WO, isTrueDest);
+
   // Handle conditions in the form of (cond1 && cond2), we know that on the
   // true dest path both of the conditions hold. Similarly for conditions of
   // the form (cond1 || cond2), we know that on the false dest path neither

Modified: llvm/trunk/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll?rev=358597&r1=358596&r2=358597&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll (original)
+++ llvm/trunk/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll Wed Apr 17 09:57:42 2019
@@ -19,8 +19,7 @@ define i1 @uadd_ov_false(i8 %x, i8* %px,
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], -102
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i8 [[X]], -101
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -52,8 +51,7 @@ define i1 @uadd_ov_true(i8 %x, i8* %px,
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], -100
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i8 [[X]], -101
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -85,8 +83,7 @@ define i1 @sadd_ov_false(i8 %x, i8* %px,
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[X]], 26
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp sgt i8 [[X]], 27
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -118,8 +115,7 @@ define i1 @sadd_ov_true(i8 %x, i8* %px,
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[X]], 28
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp sgt i8 [[X]], 27
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -151,8 +147,7 @@ define i1 @usub_ov_false(i8 %x, i8* %px,
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X]], 101
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp ult i8 [[X]], 100
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -184,8 +179,7 @@ define i1 @usub_ov_true(i8 %x, i8* %px,
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ult i8 [[X]], 99
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp ult i8 [[X]], 100
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -217,8 +211,7 @@ define i1 @ssub_ov_false(i8 %x, i8* %px,
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[X]], -27
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp slt i8 [[X]], -28
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -250,8 +243,7 @@ define i1 @ssub_ov_true(i8 %x, i8* %px,
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[X]], -29
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp slt i8 [[X]], -28
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -283,8 +275,7 @@ define i1 @umul_ov_false(i8 %x, i8* %px,
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], 24
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i8 [[X]], 25
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -316,8 +307,7 @@ define i1 @umul_ov_true(i8 %x, i8* %px,
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp ugt i8 [[X]], 26
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i8 [[X]], 25
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -350,8 +340,7 @@ define i1 @smul_ov_false_bound1(i8 %x, i
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp slt i8 [[X]], -11
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp slt i8 [[X]], -12
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -383,8 +372,7 @@ define i1 @smul_ov_false_bound2(i8 %x, i
 ; CHECK:       no_overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp sgt i8 [[X]], 11
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp sgt i8 [[X]], 12
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -417,8 +405,7 @@ define i1 @smul_ov_true_bound1(i8 %x, i8
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], -13
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[X]], -12
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable
@@ -450,8 +437,7 @@ define i1 @smul_ov_true_bound2(i8 %x, i8
 ; CHECK:       overflow:
 ; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], 13
 ; CHECK-NEXT:    store i1 [[C1]], i1* [[PC:%.*]]
-; CHECK-NEXT:    [[C2:%.*]] = icmp eq i8 [[X]], 12
-; CHECK-NEXT:    ret i1 [[C2]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       trap:
 ; CHECK-NEXT:    call void @llvm.trap()
 ; CHECK-NEXT:    unreachable




More information about the llvm-commits mailing list