[llvm] bfbfbd8 - [LVI] Fix and re-enable at-use reasoning (PR60629)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 14 06:56:49 PST 2023


Author: Nikita Popov
Date: 2023-02-14T15:56:39+01:00
New Revision: bfbfbd8b65def121ba325c6c68aca09349d119fc

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

LOG: [LVI] Fix and re-enable at-use reasoning (PR60629)

This fixes the handling of phi nodes in getConstantRangeAtUse()
and re-enables it, reverting the workaround from
c77c186a647b385c291ddabecd70a2b4f84ae342.

For phi nodes, while we can make use of the edge condition for the
incoming value, we shouldn't look past the phi node to look for
further conditions, because we might be reasoning about values
from two different cycle iterations (which will have the same
SSA value).

To handle this more specifically we would have to detect cycles,
and there doesn't seem to be any motivating case for that at this
point.

Added: 
    

Modified: 
    llvm/lib/Analysis/LazyValueInfo.cpp
    llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index efe878d987627..944b4a2938daf 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -1662,7 +1662,7 @@ ConstantRange LazyValueInfo::getConstantRangeAtUse(const Use &U,
   // position where V can be constrained by a select or branch condition.
   const Use *CurrU = &U;
   // TODO: Increase limit?
-  const unsigned MaxUsesToInspect = 0;
+  const unsigned MaxUsesToInspect = 3;
   for (unsigned I = 0; I < MaxUsesToInspect; ++I) {
     std::optional<ValueLatticeElement> CondVal;
     auto *CurrI = cast<Instruction>(CurrU->getUser());
@@ -1675,11 +1675,6 @@ ConstantRange LazyValueInfo::getConstantRangeAtUse(const Use &U,
       // TODO: Use non-local query?
       CondVal =
           getEdgeValueLocal(V, PHI->getIncomingBlock(*CurrU), PHI->getParent());
-    } else if (!isSafeToSpeculativelyExecute(CurrI)) {
-      // Stop walking if we hit a non-speculatable instruction. Even if the
-      // result is only used under a specific condition, executing the
-      // instruction itself may cause side effects or UB already.
-      break;
     }
     if (CondVal && CondVal->isConstantRange())
       CR = CR.intersectWith(CondVal->getConstantRange());
@@ -1687,7 +1682,13 @@ ConstantRange LazyValueInfo::getConstantRangeAtUse(const Use &U,
     // Only follow one-use chain, to allow direct intersection of conditions.
     // If there are multiple uses, we would have to intersect with the union of
     // all conditions at 
diff erent uses.
-    if (!CurrI->hasOneUse())
+    // Stop walking if we hit a non-speculatable instruction. Even if the
+    // result is only used under a specific condition, executing the
+    // instruction itself may cause side effects or UB already.
+    // This also disallows looking through phi nodes: If the phi node is part
+    // of a cycle, we might end up reasoning about values from 
diff erent cycle
+    // iterations (PR60629).
+    if (!CurrI->hasOneUse() || !isSafeToSpeculativelyExecute(CurrI))
       break;
     CurrU = &*CurrI->use_begin();
   }

diff  --git a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
index 1b09ca06b66fe..6270ca86bce4a 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
@@ -9,9 +9,9 @@ declare i16 @llvm.abs.i16(i16, i1)
 
 define i16 @sel_true_cond(i16 %x) {
 ; CHECK-LABEL: @sel_true_cond(
-; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
+; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SUB]], i16 42
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SUB1]], i16 42
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
@@ -76,8 +76,8 @@ define i16 @sel_true_cond_extra_use(i16 %x) {
 
 define i16 @sel_true_cond_chain_speculatable(i16 %x) {
 ; CHECK-LABEL: @sel_true_cond_chain_speculatable(
-; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[X:%.*]], i16 1)
-; CHECK-NEXT:    [[EXTRA:%.*]] = mul i16 [[SUB]], 3
+; CHECK-NEXT:    [[SUB1:%.*]] = add nuw i16 [[X:%.*]], 1
+; CHECK-NEXT:    [[EXTRA:%.*]] = mul i16 [[SUB1]], 3
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i16 [[X]], -1
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[EXTRA]], i16 42
 ; CHECK-NEXT:    ret i16 [[SEL]]
@@ -125,9 +125,9 @@ define i16 @sel_true_cond_longer_chain(i16 %x) {
 
 define i16 @sel_false_cond(i16 %x) {
 ; CHECK-LABEL: @sel_false_cond(
-; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
+; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 10
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 42, i16 [[SUB]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 42, i16 [[SUB1]]
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %sub = call i16 @llvm.usub.sat.i16(i16 %x, i16 10)
@@ -152,13 +152,13 @@ define i16 @sel_false_cond_insufficient(i16 %x) {
 define i16 @phi_true_cond(i16 %x) {
 ; CHECK-LABEL: @phi_true_cond(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
+; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i16 [[X]], 10
 ; CHECK-NEXT:    br i1 [[CMP]], label [[JOIN:%.*]], label [[SPLIT:%.*]]
 ; CHECK:       split:
 ; CHECK-NEXT:    br label [[JOIN]]
 ; CHECK:       join:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
+; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB1]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
 ; CHECK-NEXT:    ret i16 [[PHI]]
 ;
 entry:
@@ -229,13 +229,13 @@ join:
 define i16 @phi_false_cond(i16 %x) {
 ; CHECK-LABEL: @phi_false_cond(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[SUB:%.*]] = call i16 @llvm.usub.sat.i16(i16 [[X:%.*]], i16 10)
+; CHECK-NEXT:    [[SUB1:%.*]] = sub nuw i16 [[X:%.*]], 10
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 10
 ; CHECK-NEXT:    br i1 [[CMP]], label [[SPLIT:%.*]], label [[JOIN:%.*]]
 ; CHECK:       split:
 ; CHECK-NEXT:    br label [[JOIN]]
 ; CHECK:       join:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
+; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ [[SUB1]], [[ENTRY:%.*]] ], [ 42, [[SPLIT]] ]
 ; CHECK-NEXT:    ret i16 [[PHI]]
 ;
 entry:
@@ -308,10 +308,10 @@ define i16 @loop_cond() {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 1000, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[IV:%.*]] = phi i16 [ 1000, [[ENTRY:%.*]] ], [ [[IV_NEXT1:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[COUNT:%.*]] = phi i16 [ 0, [[ENTRY]] ], [ [[COUNT_NEXT:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[IV]], 0
-; CHECK-NEXT:    [[IV_NEXT]] = call i16 @llvm.usub.sat.i16(i16 [[IV]], i16 1)
+; CHECK-NEXT:    [[IV_NEXT1]] = sub nuw i16 [[IV]], 1
 ; CHECK-NEXT:    [[COUNT_NEXT]] = add i16 [[COUNT]], 1
 ; CHECK-NEXT:    br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]]
 ; CHECK:       exit:
@@ -334,9 +334,8 @@ exit:
 
 define i16 @urem_elide(i16 %x) {
 ; CHECK-LABEL: @urem_elide(
-; CHECK-NEXT:    [[UREM:%.*]] = urem i16 [[X:%.*]], 42
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 42
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM]], i16 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X:%.*]], 42
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[X]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %urem = urem i16 %x, 42
@@ -347,7 +346,10 @@ define i16 @urem_elide(i16 %x) {
 
 define i16 @urem_expand(i16 %x) {
 ; CHECK-LABEL: @urem_expand(
-; CHECK-NEXT:    [[UREM:%.*]] = urem i16 [[X:%.*]], 42
+; CHECK-NEXT:    [[X_FROZEN:%.*]] = freeze i16 [[X:%.*]]
+; CHECK-NEXT:    [[UREM_UREM:%.*]] = sub nuw i16 [[X_FROZEN]], 42
+; CHECK-NEXT:    [[UREM_CMP:%.*]] = icmp ult i16 [[X_FROZEN]], 42
+; CHECK-NEXT:    [[UREM:%.*]] = select i1 [[UREM_CMP]], i16 [[X_FROZEN]], i16 [[UREM_UREM]]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 84
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
@@ -360,9 +362,11 @@ define i16 @urem_expand(i16 %x) {
 
 define i16 @urem_narrow(i16 %x) {
 ; CHECK-LABEL: @urem_narrow(
-; CHECK-NEXT:    [[UREM:%.*]] = urem i16 [[X:%.*]], 42
+; CHECK-NEXT:    [[UREM_LHS_TRUNC:%.*]] = trunc i16 [[X:%.*]] to i8
+; CHECK-NEXT:    [[UREM1:%.*]] = urem i8 [[UREM_LHS_TRUNC]], 42
+; CHECK-NEXT:    [[UREM_ZEXT:%.*]] = zext i8 [[UREM1]] to i16
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 85
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM]], i16 24
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM_ZEXT]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %urem = urem i16 %x, 42
@@ -386,11 +390,10 @@ define i16 @urem_insufficient(i16 %x) {
 
 define i16 @srem_elide(i16 %x) {
 ; CHECK-LABEL: @srem_elide(
-; CHECK-NEXT:    [[SREM:%.*]] = srem i16 [[X:%.*]], 42
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i16 [[X]], 42
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i16 [[X:%.*]], 42
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i16 [[X]], -42
 ; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[AND]], i16 [[SREM]], i16 24
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[AND]], i16 [[X]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %srem = srem i16 %x, 42
@@ -403,11 +406,13 @@ define i16 @srem_elide(i16 %x) {
 
 define i16 @srem_narrow(i16 %x) {
 ; CHECK-LABEL: @srem_narrow(
-; CHECK-NEXT:    [[SREM:%.*]] = srem i16 [[X:%.*]], 42
+; CHECK-NEXT:    [[SREM_LHS_TRUNC:%.*]] = trunc i16 [[X:%.*]] to i8
+; CHECK-NEXT:    [[SREM1:%.*]] = srem i8 [[SREM_LHS_TRUNC]], 42
+; CHECK-NEXT:    [[SREM_SEXT:%.*]] = sext i8 [[SREM1]] to i16
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp slt i16 [[X]], 43
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp sgt i16 [[X]], -43
 ; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[AND]], i16 [[SREM]], i16 24
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[AND]], i16 [[SREM_SEXT]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %srem = srem i16 %x, 42
@@ -420,9 +425,11 @@ define i16 @srem_narrow(i16 %x) {
 
 define i16 @srem_convert(i16 %x) {
 ; CHECK-LABEL: @srem_convert(
-; CHECK-NEXT:    [[SREM:%.*]] = srem i16 [[X:%.*]], 42
+; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i16 0, [[X:%.*]]
+; CHECK-NEXT:    [[SREM1:%.*]] = urem i16 [[X_NONNEG]], 42
+; CHECK-NEXT:    [[SREM1_NEG:%.*]] = sub i16 0, [[SREM1]]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[X]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SREM]], i16 24
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SREM1_NEG]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %srem = srem i16 %x, 42
@@ -433,9 +440,11 @@ define i16 @srem_convert(i16 %x) {
 
 define i16 @sdiv_convert(i16 %x) {
 ; CHECK-LABEL: @sdiv_convert(
-; CHECK-NEXT:    [[SREM:%.*]] = sdiv i16 [[X:%.*]], 42
+; CHECK-NEXT:    [[X_NONNEG:%.*]] = sub i16 0, [[X:%.*]]
+; CHECK-NEXT:    [[SREM1:%.*]] = udiv i16 [[X_NONNEG]], 42
+; CHECK-NEXT:    [[SREM1_NEG:%.*]] = sub i16 0, [[SREM1]]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i16 [[X]], 0
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SREM]], i16 24
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[SREM1_NEG]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %srem = sdiv i16 %x, 42
@@ -498,7 +507,7 @@ define i16 @umin_elide(i16 %x) {
 
 define i16 @ashr_convert(i16 %x, i16 %y) {
 ; CHECK-LABEL: @ashr_convert(
-; CHECK-NEXT:    [[ASHR:%.*]] = ashr i16 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[ASHR:%.*]] = lshr i16 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i16 [[X]], 0
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[ASHR]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
@@ -511,7 +520,7 @@ define i16 @ashr_convert(i16 %x, i16 %y) {
 
 define i32 @sext_convert(i16 %x) {
 ; CHECK-LABEL: @sext_convert(
-; CHECK-NEXT:    [[EXT:%.*]] = sext i16 [[X:%.*]] to i32
+; CHECK-NEXT:    [[EXT:%.*]] = zext i16 [[X:%.*]] to i32
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp sge i16 [[X]], 0
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[EXT]], i32 24
 ; CHECK-NEXT:    ret i32 [[SEL]]
@@ -537,9 +546,8 @@ define i16 @infer_flags(i16 %x) {
 
 define i16 @and_elide(i16 %x) {
 ; CHECK-LABEL: @and_elide(
-; CHECK-NEXT:    [[AND:%.*]] = and i16 [[X:%.*]], 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X]], 8
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[AND]], i16 24
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i16 [[X:%.*]], 8
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i16 [[X]], i16 24
 ; CHECK-NEXT:    ret i16 [[SEL]]
 ;
   %and = and i16 %x, 7


        


More information about the llvm-commits mailing list