[llvm] a5b6068 - [ValueLattice] Move intersect from LVI into ValueLattice API (NFC)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 28 06:18:44 PDT 2024


Author: Nikita Popov
Date: 2024-08-28T15:18:31+02:00
New Revision: a5b60684468ceb7d6e45e24ce94f3a49c6606b6f

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

LOG: [ValueLattice] Move intersect from LVI into ValueLattice API (NFC)

So we can reuse the logic inside IPSCCP.

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/ValueLattice.h
    llvm/lib/Analysis/LazyValueInfo.cpp
    llvm/lib/Analysis/ValueLattice.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/ValueLattice.h b/llvm/include/llvm/Analysis/ValueLattice.h
index a704cce0c082b9..9357a15f7619f1 100644
--- a/llvm/include/llvm/Analysis/ValueLattice.h
+++ b/llvm/include/llvm/Analysis/ValueLattice.h
@@ -471,6 +471,23 @@ class ValueLatticeElement {
                        const ValueLatticeElement &Other,
                        const DataLayout &DL) const;
 
+  /// Combine two sets of facts about the same value into a single set of
+  /// facts.  Note that this method is not suitable for merging facts along
+  /// 
diff erent paths in a CFG; that's what the mergeIn function is for.  This
+  /// is for merging facts gathered about the same value at the same location
+  /// through two independent means.
+  /// Notes:
+  /// * This method does not promise to return the most precise possible lattice
+  ///   value implied by A and B.  It is allowed to return any lattice element
+  ///   which is at least as strong as *either* A or B (unless our facts
+  ///   conflict, see below).
+  /// * Due to unreachable code, the intersection of two lattice values could be
+  ///   contradictory.  If this happens, we return some valid lattice value so
+  ///   as not confuse the rest of LVI.  Ideally, we'd always return Undefined,
+  ///   but we do not make this guarantee.  TODO: This would be a useful
+  ///   enhancement.
+  ValueLatticeElement intersect(const ValueLatticeElement &Other) const;
+
   unsigned getNumRangeExtensions() const { return NumRangeExtensions; }
   void setNumRangeExtensions(unsigned N) { NumRangeExtensions = N; }
 };

diff  --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 615d8b7ccd8ccf..69e0627a89cc29 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -83,57 +83,6 @@ static bool hasSingleValue(const ValueLatticeElement &Val) {
   return false;
 }
 
-/// Combine two sets of facts about the same value into a single set of
-/// facts.  Note that this method is not suitable for merging facts along
-/// 
diff erent paths in a CFG; that's what the mergeIn function is for.  This
-/// is for merging facts gathered about the same value at the same location
-/// through two independent means.
-/// Notes:
-/// * This method does not promise to return the most precise possible lattice
-///   value implied by A and B.  It is allowed to return any lattice element
-///   which is at least as strong as *either* A or B (unless our facts
-///   conflict, see below).
-/// * Due to unreachable code, the intersection of two lattice values could be
-///   contradictory.  If this happens, we return some valid lattice value so as
-///   not confuse the rest of LVI.  Ideally, we'd always return Undefined, but
-///   we do not make this guarantee.  TODO: This would be a useful enhancement.
-static ValueLatticeElement intersect(const ValueLatticeElement &A,
-                                     const ValueLatticeElement &B) {
-  // Undefined is the strongest state.  It means the value is known to be along
-  // an unreachable path.
-  if (A.isUnknown())
-    return A;
-  if (B.isUnknown())
-    return B;
-
-  // If we gave up for one, but got a useable fact from the other, use it.
-  if (A.isOverdefined())
-    return B;
-  if (B.isOverdefined())
-    return A;
-
-  // Can't get any more precise than constants.
-  if (hasSingleValue(A))
-    return A;
-  if (hasSingleValue(B))
-    return B;
-
-  // Could be either constant range or not constant here.
-  if (!A.isConstantRange() || !B.isConstantRange()) {
-    // TODO: Arbitrary choice, could be improved
-    return A;
-  }
-
-  // Intersect two constant ranges
-  ConstantRange Range =
-      A.getConstantRange().intersectWith(B.getConstantRange());
-  // Note: An empty range is implicitly converted to unknown or undef depending
-  // on MayIncludeUndef internally.
-  return ValueLatticeElement::getRange(
-      std::move(Range), /*MayIncludeUndef=*/A.isConstantRangeIncludingUndef() ||
-                            B.isConstantRangeIncludingUndef());
-}
-
 //===----------------------------------------------------------------------===//
 //                          LazyValueInfoCache Decl
 //===----------------------------------------------------------------------===//
@@ -812,9 +761,9 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
     if (I->getParent() != BB || !isValidAssumeForContext(I, BBI))
       continue;
 
-    BBLV = intersect(BBLV, *getValueFromCondition(Val, I->getArgOperand(0),
-                                                  /*IsTrueDest*/ true,
-                                                  /*UseBlockValue*/ false));
+    BBLV = BBLV.intersect(*getValueFromCondition(Val, I->getArgOperand(0),
+                                                 /*IsTrueDest*/ true,
+                                                 /*UseBlockValue*/ false));
   }
 
   // If guards are not used in the module, don't spend time looking for them
@@ -824,9 +773,9 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
          make_range(std::next(BBI->getIterator().getReverse()), BB->rend())) {
       Value *Cond = nullptr;
       if (match(&I, m_Intrinsic<Intrinsic::experimental_guard>(m_Value(Cond))))
-        BBLV = intersect(BBLV,
-                         *getValueFromCondition(Val, Cond, /*IsTrueDest*/ true,
-                                                /*UseBlockValue*/ false));
+        BBLV = BBLV.intersect(*getValueFromCondition(Val, Cond,
+                                                     /*IsTrueDest*/ true,
+                                                     /*UseBlockValue*/ false));
     }
   }
 
@@ -913,13 +862,13 @@ LazyValueInfoImpl::solveBlockValueSelect(SelectInst *SI, BasicBlock *BB) {
   // the select condition.
   if (isGuaranteedNotToBeUndef(Cond, AC)) {
     TrueVal =
-        intersect(TrueVal, *getValueFromCondition(SI->getTrueValue(), Cond,
-                                                  /*IsTrueDest*/ true,
-                                                  /*UseBlockValue*/ false));
+        TrueVal.intersect(*getValueFromCondition(SI->getTrueValue(), Cond,
+                                                 /*IsTrueDest*/ true,
+                                                 /*UseBlockValue*/ false));
     FalseVal =
-        intersect(FalseVal, *getValueFromCondition(SI->getFalseValue(), Cond,
-                                                   /*IsTrueDest*/ false,
-                                                   /*UseBlockValue*/ false));
+        FalseVal.intersect(*getValueFromCondition(SI->getFalseValue(), Cond,
+                                                  /*IsTrueDest*/ false,
+                                                  /*UseBlockValue*/ false));
   }
 
   ValueLatticeElement Result = TrueVal;
@@ -1037,9 +986,9 @@ LazyValueInfoImpl::solveBlockValueIntrinsic(IntrinsicInst *II, BasicBlock *BB) {
     OpRanges.push_back(*Range);
   }
 
-  return intersect(ValueLatticeElement::getRange(ConstantRange::intrinsic(
-                       II->getIntrinsicID(), OpRanges)),
-                   MetadataVal);
+  return ValueLatticeElement::getRange(
+             ConstantRange::intrinsic(II->getIntrinsicID(), OpRanges))
+      .intersect(MetadataVal);
 }
 
 std::optional<ValueLatticeElement>
@@ -1310,7 +1259,7 @@ LazyValueInfoImpl::getValueFromCondition(Value *Val, Value *Cond,
     return *LV;
   }
 
-  return intersect(*LV, *RV);
+  return LV->intersect(*RV);
 }
 
 // Return true if Usr has Op as an operand, otherwise false.
@@ -1522,7 +1471,7 @@ LazyValueInfoImpl::getEdgeValue(Value *Val, BasicBlock *BBFrom,
   // but then the result is not cached.
   intersectAssumeOrGuardBlockValueConstantRange(Val, InBlock, CxtI);
 
-  return intersect(*LocalResult, InBlock);
+  return LocalResult->intersect(InBlock);
 }
 
 ValueLatticeElement LazyValueInfoImpl::getValueInBlock(Value *V, BasicBlock *BB,
@@ -1612,7 +1561,7 @@ ValueLatticeElement LazyValueInfoImpl::getValueAtUse(const Use &U) {
                                    PHI->getParent(), /*UseBlockValue*/ false);
     }
     if (CondVal)
-      VL = intersect(VL, *CondVal);
+      VL = VL.intersect(*CondVal);
 
     // 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

diff  --git a/llvm/lib/Analysis/ValueLattice.cpp b/llvm/lib/Analysis/ValueLattice.cpp
index 5001fc2d310dd4..03810f1c554e5d 100644
--- a/llvm/lib/Analysis/ValueLattice.cpp
+++ b/llvm/lib/Analysis/ValueLattice.cpp
@@ -53,6 +53,62 @@ ValueLatticeElement::getCompare(CmpInst::Predicate Pred, Type *Ty,
   return nullptr;
 }
 
+static bool hasSingleValue(const ValueLatticeElement &Val) {
+  if (Val.isConstantRange() && Val.getConstantRange().isSingleElement())
+    // Integer constants are single element ranges
+    return true;
+  return Val.isConstant();
+}
+
+/// Combine two sets of facts about the same value into a single set of
+/// facts.  Note that this method is not suitable for merging facts along
+/// 
diff erent paths in a CFG; that's what the mergeIn function is for.  This
+/// is for merging facts gathered about the same value at the same location
+/// through two independent means.
+/// Notes:
+/// * This method does not promise to return the most precise possible lattice
+///   value implied by A and B.  It is allowed to return any lattice element
+///   which is at least as strong as *either* A or B (unless our facts
+///   conflict, see below).
+/// * Due to unreachable code, the intersection of two lattice values could be
+///   contradictory.  If this happens, we return some valid lattice value so as
+///   not confuse the rest of LVI.  Ideally, we'd always return Undefined, but
+///   we do not make this guarantee.  TODO: This would be a useful enhancement.
+ValueLatticeElement
+ValueLatticeElement::intersect(const ValueLatticeElement &Other) const {
+  if (isUnknown())
+    return *this;
+  if (Other.isUnknown())
+    return Other;
+
+  // If we gave up for one, but got a useable fact from the other, use it.
+  if (isOverdefined())
+    return Other;
+  if (Other.isOverdefined())
+    return *this;
+
+  // Can't get any more precise than constants.
+  if (hasSingleValue(*this))
+    return *this;
+  if (hasSingleValue(Other))
+    return Other;
+
+  // Could be either constant range or not constant here.
+  if (!isConstantRange() || !Other.isConstantRange()) {
+    // TODO: Arbitrary choice, could be improved
+    return *this;
+  }
+
+  // Intersect two constant ranges
+  ConstantRange Range =
+      getConstantRange().intersectWith(Other.getConstantRange());
+  // Note: An empty range is implicitly converted to unknown or undef depending
+  // on MayIncludeUndef internally.
+  return ValueLatticeElement::getRange(
+      std::move(Range), /*MayIncludeUndef=*/isConstantRangeIncludingUndef() ||
+                            Other.isConstantRangeIncludingUndef());
+}
+
 raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val) {
   if (Val.isUnknown())
     return OS << "unknown";


        


More information about the llvm-commits mailing list