[llvm] [InstCombine] Decompose an icmp into multiple ranges (PR #69855)

via llvm-commits llvm-commits at lists.llvm.org
Sat Oct 21 22:42:56 PDT 2023


================
@@ -1334,6 +1334,101 @@ Value *InstCombinerImpl::foldAndOrOfICmpsUsingRanges(ICmpInst *ICmp1,
   return Builder.CreateICmp(NewPred, NewV, ConstantInt::get(Ty, NewC));
 }
 
+/// Decompose icmp into intersection or union of ranges.
+static bool decomposeICmpIntoRangeSet(SmallVectorImpl<ConstantRange> &Set,
+                                      ICmpInst *ICmp, Value *X, bool IsAnd) {
+  // icmp eq/ne (X & mask), 0
+  ICmpInst::Predicate Pred;
+  const APInt *Mask;
+  if (match(ICmp,
+            m_ICmp(Pred, m_And(m_Specific(X), m_APInt(Mask)), m_Zero())) &&
+      ICmp->isEquality()) {
+    if (Mask->popcount() == Mask->getBitWidth() - 1) {
+      auto Zero = APInt::getZero(Mask->getBitWidth());
+      auto Val = ~*Mask;
+      if (IsAnd) {
+        if (Pred == ICmpInst::ICMP_EQ) {
+          Set.push_back(ConstantRange(Zero, Val + 1));
+          Set.push_back(ConstantRange(Val, APInt(Mask->getBitWidth(), 1)));
+        } else {
+          Set.push_back(ConstantRange(Zero).inverse());
+          Set.push_back(ConstantRange(Val).inverse());
+        }
+      } else {
+        if (Pred == ICmpInst::ICMP_EQ) {
+          Set.push_back(Val);
+          Set.push_back(Zero);
+        } else {
+          Set.push_back(ConstantRange(APInt(Mask->getBitWidth(), 1), Val));
+          Set.push_back(ConstantRange(Val + 1, Zero));
+        }
+      }
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/// Fold (icmp Pred1 V1, C1) & (icmp Pred2 V2, C2)
+/// or   (icmp Pred1 V1, C1) | (icmp Pred2 V2, C2)
+/// into a single comparison using range-based reasoning.
+/// It handles patterns which cannot be recognized by
+/// foldAndOrOfICmpsUsingRanges. Try to decompose one of icmps into two or more
+/// icmps. Example: icmp eq (X & ~signmask), 0 --> (icmp eq X, 0) | (icmp eq X,
+/// signmask)
+static Value *
+foldAndOrOfICmpsUsingDecomposedRanges(ICmpInst *ICmp1, ICmpInst *ICmp2,
+                                      bool IsAnd,
+                                      InstCombiner::BuilderTy &Builder) {
+  ICmpInst::Predicate Pred1, Pred2;
+  Value *V1, *V2;
+  const APInt *C1, *C2;
+  if (!match(ICmp1, m_ICmp(Pred1, m_Value(V1), m_APInt(C1))) ||
+      !match(ICmp2, m_ICmp(Pred2, m_Value(V2), m_APInt(C2))))
+    return nullptr;
+
+  SmallVector<ConstantRange, 3> Ranges;
+  Value *X = nullptr;
+  if (decomposeICmpIntoRangeSet(Ranges, ICmp2, V1, IsAnd)) {
+    X = V1;
+    Ranges.push_back(ConstantRange::makeExactICmpRegion(Pred1, *C1));
+  } else if (decomposeICmpIntoRangeSet(Ranges, ICmp1, V2, IsAnd)) {
+    X = V2;
+    Ranges.push_back(ConstantRange::makeExactICmpRegion(Pred2, *C2));
+  } else
+    return nullptr;
+
+  while (true) {
+    bool Merged = false;
+    for (unsigned I = 0; I < Ranges.size(); ++I) {
+      auto &CR = Ranges[I];
+      for (unsigned J = I + 1; J < Ranges.size(); ++J) {
+        if (auto NewCR = IsAnd ? CR.exactIntersectWith(Ranges[J])
+                               : CR.exactUnionWith(Ranges[J])) {
+          CR = *NewCR;
+          Ranges.erase(Ranges.begin() + J);
+          Merged = true;
+        }
+      }
+    }
+
+    if (Ranges.size() == 1)
+      break;
+
+    if (!Merged)
+      return nullptr;
+  }
----------------
goldsteinn wrote:

Not sure I understand the goal of this while loop, can you comment it a bit?
Seems you are removing duplicate ranges although your success condition seems to only be that there is at least one merge, not that it shrinks to a single range but you only reference `Ranges[0]` later, so a bit confused on the whole as to what its trying to do.

https://github.com/llvm/llvm-project/pull/69855


More information about the llvm-commits mailing list