[llvm] [VectorCombine] Fold compare chains to experimental.vector.match (PR #212456)

Graham Hunter via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 29 06:08:40 PDT 2026


================
@@ -578,6 +579,123 @@ bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0,
   return OldCost < NewCost;
 }
 
+/// Attempts to fold chains of `eq` comparisons to `vector.match`. For example:
+///
+/// ```
+/// %c0 = icmp eq <vscale x 4 x i16> %vec, splat (i16 100)
+/// %c1 = icmp eq <vscale x 4 x i16> %vec, splat (i16 32)
+/// %c2 = icmp eq <vscale x 4 x i16> %vec, splat (i16 10)
+/// %or = or <vscale x 4 x i1> %c0, %c1
+/// %r = or <vscale x 4 x i1> %or, %c2
+/// ```
+/// folds to:
+/// ```
+/// %r = call <vscale x 4 x i1> @llvm.experimental.vector.match.nxv8i16.v8i16(
+///        <vscale x 4 x i16> %vec, <i16 100, i16 32, i16 10, i16 100>,
+///        splat (i1 true))
+/// ```
+bool VectorCombine::foldDisjunctionToConstantMatch(Instruction &I) {
+  auto *BinOp = dyn_cast<BinaryOperator>(&I);
+  if (!BinOp || BinOp->getOpcode() != Instruction::Or)
+    return false;
+
+  // The vector being checked (%vec in the example).
+  Value *CompareSource = nullptr;
+  // The values being searched for (e.g, 100, 32, 10).
+  SmallSetVector<Constant *, 16> SearchValues;
+
+  SmallPtrSet<Value *, 4> Visited;
+  SmallVector<Value *> Worklist = {BinOp->getOperand(0), BinOp->getOperand(1)};
+  unsigned NumVisited = 0;
+  while (!Worklist.empty()) {
+    auto *Op = dyn_cast<Instruction>(Worklist.pop_back_val());
+    if (++NumVisited >= MaxInstrsToScan || !Op || !Op->hasOneUse())
+      return false;
+
+    if (!Visited.insert(Op).second)
+      continue;
+
+    Constant *C;
+    Value *Source = nullptr;
+    // TODO: Extend to "not equals" compares.
+    if (match(Op, m_c_SpecificICmp(CmpInst::ICMP_EQ, m_Value(Source),
+                                   m_ConstantSplat(m_Constant(C)))) &&
+        !C->getType()->isPointerTy()) {
+      SearchValues.insert(C);
+    } else if (match(Op, m_Intrinsic<Intrinsic::experimental_vector_match>(
+                             m_Value(Source), m_Constant(C),
+                             m_ConstantSplat(m_SpecificInt(1))))) {
+      // Merge with any previous vector match. This ensures the combine always
+      // creates the largest possible match (even if the combine applies to an
+      // `or` earlier in the chain).
+      unsigned NumElts = cast<FixedVectorType>(C->getType())->getNumElements();
+      for (unsigned I = 0; I < NumElts; ++I)
+        if (Constant *Elt = C->getAggregateElement(I))
+          SearchValues.insert(Elt);
+    } else if (Op->getOpcode() == Instruction::Or) {
+      Worklist.append({Op->getOperand(0), Op->getOperand(1)});
+    } else {
+      // InstCombine can fold compares with nearby values to check ranges, which
+      // means this combine does not match. TODO: Extend this fold to cover
+      // these cases too?
+      return false;
+    }
+
+    // Ensure all comparisons are against the same vector.
+    if (!CompareSource)
+      CompareSource = Source;
+    else if (Source && CompareSource != Source)
+      return false;
+  }
+
+  if (SearchValues.size() <= 1)
+    return false;
+
+  auto *ResultTy = cast<VectorType>(BinOp->getType());
+  auto *SrcType = cast<VectorType>(CompareSource->getType());
+
+  // Cost the old code as-if it were all a chain of compares. It could include
+  // a match, but that will always be replaced with another match (with a
+  // needle size >= to the current match).
+  InstructionCost OldCost =
+      TTI.getCmpSelInstrCost(Instruction::ICmp, SrcType, ResultTy,
+                             CmpInst::ICMP_EQ, CostKind) *
+      SearchValues.size();
+  OldCost += TTI.getArithmeticInstrCost(Instruction::Or, ResultTy, CostKind) *
+             (SearchValues.size() - 1);
+
+  ElementCount SrcElts = SrcType->getElementCount();
+
+  InstructionCost NewCost;
+  Constant *NeedleVector;
+  SmallVector<Constant *> MatchValues(SearchValues.getArrayRef());
+
+  // Look for a match needle size (up to the size of SrcType) that's profitable.
+  do {
+    NeedleVector = ConstantVector::get(MatchValues);
+    IntrinsicCostAttributes ICA(Intrinsic::experimental_vector_match, ResultTy,
+                                {SrcType, NeedleVector->getType(), ResultTy});
+    NewCost = TTI.getIntrinsicInstrCost(ICA, CostKind);
+    if (NewCost < OldCost)
+      break;
+
+    // Pad the needle by duplicating the first element.
+    unsigned PadValues = NextPowerOf2(MatchValues.size()) - MatchValues.size();
+    MatchValues.append(SmallVector<Constant *>(PadValues, MatchValues[0]));
----------------
huntergr-arm wrote:

```suggestion
    MatchValues.resize(NextPowerOf2(MatchValues.size()), MatchValues.front());
```

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


More information about the llvm-commits mailing list