[llvm] [SLP][modularisation][NFC] Extract InstructionsState (2/3) (PR #211461)

Madhur Amilkanthwar via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 22 21:52:15 PDT 2026


https://github.com/madhur13490 created https://github.com/llvm/llvm-project/pull/211461

Move the InstructionsState class out of SLPVectorizer.cpp into the existing private module SLPVectorizer/SLPCompatibilityAnalysis.{h,cpp}. The class declaration (with trivial accessors) lives in the header; the non-trivial method bodies are defined out-of-line in the .cpp:

  isSameOperation
  getMatchingMainOpOrAltOp
  isMulDivLikeOp
  isAddSubLikeOp
  isCopyableElement
  isExpandedBinOp
  isExpandedOperand
  isNonSchedulable

Part of the effort to modularize SLPVectorizer.cpp. See the RFC: https://discourse.llvm.org/t/modularizing-slpvectorizer-cpp/90922

>From 0fb1c2ffaae858a0ad2986766267cfe38e3cf2e6 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Wed, 22 Jul 2026 09:12:47 -0700
Subject: [PATCH] [SLP][modularisation][NFC] Extract InstructionsState (2/3)

Move the InstructionsState class out of SLPVectorizer.cpp into the
existing private module SLPVectorizer/SLPCompatibilityAnalysis.{h,cpp}.
The class declaration (with trivial accessors) lives in the header; the
non-trivial method bodies are defined out-of-line in the .cpp:

  isSameOperation
  getMatchingMainOpOrAltOp
  isMulDivLikeOp
  isAddSubLikeOp
  isCopyableElement
  isExpandedBinOp
  isExpandedOperand
  isNonSchedulable

InstructionsState depends only on BinOpSameOpcodeHelper (already in this
module) and helpers in SLPUtils.h; it does not depend on BoUpSLP. This
is a pure code move with no functional change.

Part of the effort to modularize SLPVectorizer.cpp. See the RFC:
https://discourse.llvm.org/t/modularizing-slpvectorizer-cpp/90922
---
 .../Transforms/Vectorize/SLPVectorizer.cpp    | 248 ------------------
 .../SLPCompatibilityAnalysis.cpp              | 153 +++++++++++
 .../SLPVectorizer/SLPCompatibilityAnalysis.h  | 116 ++++++++
 3 files changed, 269 insertions(+), 248 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index 209954aebeb2c..e096d6f3c08a1 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -534,254 +534,6 @@ isFixedVectorShuffle(ArrayRef<Value *> VL, SmallVectorImpl<int> &Mask,
 
 namespace {
 
-/// Main data required for vectorization of instructions.
-class InstructionsState {
-  /// MainOp and AltOp are primarily determined by getSameOpcode. Currently,
-  /// only BinaryOperator, CastInst, and CmpInst support alternate instructions
-  /// (i.e., AltOp is not equal to MainOp; this can be checked using
-  /// isAltShuffle).
-  /// A rare exception is TrySplitNode, where the InstructionsState is derived
-  /// from getMainAltOpsNoStateVL.
-  /// For those InstructionsState that use alternate instructions, the resulting
-  /// vectorized output ultimately comes from a shufflevector. For example,
-  /// given a vector list (VL):
-  /// VL[0] = add i32 a, e
-  /// VL[1] = sub i32 b, f
-  /// VL[2] = add i32 c, g
-  /// VL[3] = sub i32 d, h
-  /// The vectorized result would be:
-  /// intermediated_0 = add <4 x i32> <a, b, c, d>, <e, f, g, h>
-  /// intermediated_1 = sub <4 x i32> <a, b, c, d>, <e, f, g, h>
-  /// result = shufflevector <4 x i32> intermediated_0,
-  ///                        <4 x i32> intermediated_1,
-  ///                        <4 x i32> <i32 0, i32 5, i32 2, i32 7>
-  /// Since shufflevector is used in the final result, when calculating the cost
-  /// (getEntryCost), we must account for the usage of shufflevector in
-  /// GetVectorCost.
-  Instruction *MainOp = nullptr;
-  Instruction *AltOp = nullptr;
-  /// Wether the instruction state represents copyable instructions.
-  bool HasCopyables = false;
-
-public:
-  Instruction *getMainOp() const {
-    assert(valid() && "InstructionsState is invalid.");
-    return MainOp;
-  }
-
-  Instruction *getAltOp() const {
-    assert(valid() && "InstructionsState is invalid.");
-    return AltOp;
-  }
-
-  /// The main/alternate opcodes for the list of instructions.
-  unsigned getOpcode() const { return getMainOp()->getOpcode(); }
-
-  unsigned getAltOpcode() const { return getAltOp()->getOpcode(); }
-
-  /// Some of the instructions in the list have alternate opcodes.
-  bool isAltShuffle() const { return getMainOp() != getAltOp(); }
-
-  /// Checks if \p I is the same operation as \p Op, distinguishing calls by
-  /// intrinsic ID (all calls share the Call opcode, so e.g. umax != smax).
-  static bool isSameOperation(const Instruction *I, const Instruction *Op) {
-    if (I->getOpcode() != Op->getOpcode())
-      return false;
-    const auto *II = dyn_cast<IntrinsicInst>(I);
-    const auto *IOp = dyn_cast<IntrinsicInst>(Op);
-    if (II || IOp)
-      return II && IOp && II->getIntrinsicID() == IOp->getIntrinsicID();
-    return true;
-  }
-
-  /// Checks if the instruction matches either the main or alternate opcode.
-  /// \returns
-  /// - MainOp if \param I matches MainOp's opcode directly or can be converted
-  /// to it
-  /// - AltOp if \param I matches AltOp's opcode directly or can be converted to
-  /// it
-  /// - nullptr if \param I cannot be matched or converted to either opcode
-  Instruction *getMatchingMainOpOrAltOp(Instruction *I) const {
-    assert(MainOp && "MainOp cannot be nullptr.");
-    if (isSameOperation(I, MainOp))
-      return MainOp;
-    if (MainOp->getOpcode() == Instruction::Select &&
-        I->getOpcode() == Instruction::ZExt && !isAltShuffle())
-      return MainOp;
-    // Prefer AltOp instead of interchangeable instruction of MainOp.
-    assert(AltOp && "AltOp cannot be nullptr.");
-    if (isSameOperation(I, AltOp))
-      return AltOp;
-    // BinOpSameOpcodeHelper handles only BinaryOperators; a call cannot match.
-    if (!I->isBinaryOp() || !MainOp->isBinaryOp())
-      return nullptr;
-    BinOpSameOpcodeHelper Converter(MainOp);
-    if (!Converter.add(I) || !Converter.add(MainOp))
-      return nullptr;
-    if (isAltShuffle() && !Converter.hasCandidateOpcode(MainOp->getOpcode())) {
-      BinOpSameOpcodeHelper AltConverter(AltOp);
-      if (AltConverter.add(I) && AltConverter.add(AltOp) &&
-          AltConverter.hasCandidateOpcode(AltOp->getOpcode()))
-        return AltOp;
-    }
-    if (Converter.hasAltOp() && !isAltShuffle())
-      return nullptr;
-    return Converter.hasAltOp() ? AltOp : MainOp;
-  }
-
-  /// Checks if main/alt instructions are shift operations.
-  bool isShiftOp() const {
-    return getMainOp()->isShift() && getAltOp()->isShift();
-  }
-
-  /// Checks if main/alt instructions are bitwise logic operations.
-  bool isBitwiseLogicOp() const {
-    return getMainOp()->isBitwiseLogicOp() && getAltOp()->isBitwiseLogicOp();
-  }
-
-  /// Checks if main/alt instructions are mul/div/rem/fmul/fdiv/frem operations.
-  bool isMulDivLikeOp() const {
-    constexpr std::array<unsigned, 8> MulDiv = {
-        Instruction::Mul,  Instruction::FMul, Instruction::SDiv,
-        Instruction::UDiv, Instruction::FDiv, Instruction::SRem,
-        Instruction::URem, Instruction::FRem};
-    return is_contained(MulDiv, getOpcode()) &&
-           is_contained(MulDiv, getAltOpcode());
-  }
-
-  /// Checks if main/alt instructions are add/sub/fadd/fsub operations.
-  bool isAddSubLikeOp() const {
-    constexpr std::array<unsigned, 4> AddSub = {
-        Instruction::Add, Instruction::Sub, Instruction::FAdd,
-        Instruction::FSub};
-    return is_contained(AddSub, getOpcode()) &&
-           is_contained(AddSub, getAltOpcode());
-  }
-
-  /// Checks if main/alt instructions are cmp operations.
-  bool isCmpOp() const {
-    return (getOpcode() == Instruction::ICmp ||
-            getOpcode() == Instruction::FCmp) &&
-           getAltOpcode() == getOpcode();
-  }
-
-  /// Checks if the current state is valid, i.e. has non-null MainOp
-  bool valid() const { return MainOp && AltOp; }
-
-  explicit operator bool() const { return valid(); }
-
-  InstructionsState() = delete;
-  InstructionsState(Instruction *MainOp, Instruction *AltOp,
-                    bool HasCopyables = false)
-      : MainOp(MainOp), AltOp(AltOp), HasCopyables(HasCopyables) {}
-  static InstructionsState invalid() { return {nullptr, nullptr}; }
-
-  /// Checks if the value is a copyable element.
-  bool isCopyableElement(Value *V) const {
-    assert(valid() && "InstructionsState is invalid.");
-    if (!HasCopyables)
-      return false;
-    if (isAltShuffle() || getOpcode() == Instruction::GetElementPtr)
-      return false;
-    auto *I = dyn_cast<Instruction>(V);
-    if (!I)
-      return !isa<PoisonValue>(V);
-    if (I->getParent() != MainOp->getParent() &&
-        (!isVectorLikeInstWithConstOps(I) ||
-         !isVectorLikeInstWithConstOps(MainOp)))
-      return true;
-    if (isSameOperation(I, MainOp))
-      return false;
-    // BinOpSameOpcodeHelper handles only BinaryOperators; a call is copyable.
-    if (!I->isBinaryOp() || !MainOp->isBinaryOp())
-      return true;
-    BinOpSameOpcodeHelper Converter(MainOp);
-    return !Converter.add(I) || !Converter.add(MainOp) ||
-           Converter.hasAltOp() || !Converter.hasCandidateOpcode(getOpcode());
-  }
-
-  /// Checks if the value \p V is a transformed instruction, compatible either
-  /// with main or alternate ops.
-  bool isExpandedBinOp(Value *V) const {
-    assert(valid() && "InstructionsState is invalid.");
-    if (isCopyableElement(V))
-      return false;
-    auto *ExpandingOp = dyn_cast<Instruction>(V);
-    if (!ExpandingOp)
-      return false;
-    auto CheckForTransformedOpcode = [](const Instruction *RefOp,
-                                        const Instruction *ExpandingOp) {
-      switch (RefOp->getOpcode()) {
-      case Instruction::Add:
-        switch (ExpandingOp->getOpcode()) {
-        case Instruction::Shl:
-          return match(ExpandingOp, m_Shl(m_Value(), m_One()));
-        default:
-          break;
-        }
-        break;
-      default:
-        break;
-      }
-      return false;
-    };
-    // getMatchingMainOpOrAltOp() may legitimately return nullptr, e.g. for a
-    // split node, whose Scalars combine two unrelated operations (main/alt
-    // ops of the split state), so V is not required to match either of them.
-    Instruction *MainOp = getMatchingMainOpOrAltOp(ExpandingOp);
-    if (!MainOp)
-      return false;
-    return CheckForTransformedOpcode(MainOp, ExpandingOp);
-  }
-
-  /// Checks if the operand at index \p Idx of instruction \p I is an expanded
-  /// operand.
-  bool isExpandedOperand(Instruction *I, unsigned Idx) const {
-    assert(isExpandedBinOp(I) && "Expected an expanded binop.");
-    switch (I->getOpcode()) {
-    case Instruction::Shl:
-      assert(match(I, m_Shl(m_Value(), m_One())) && "Expected shl x, 1 only.");
-      return Idx == 1;
-    default:
-      llvm_unreachable("Unexpected opcode for an expanded operand.");
-    }
-  }
-
-  /// Checks if the value is non-schedulable.
-  bool isNonSchedulable(Value *V) const {
-    assert(valid() && "InstructionsState is invalid.");
-    auto *I = dyn_cast<Instruction>(V);
-    if (!HasCopyables)
-      return !I || isa<PHINode>(I) || isVectorLikeInstWithConstOps(I) ||
-             doesNotNeedToBeScheduled(V);
-    // MainOp for copyables always schedulable to correctly identify
-    // non-schedulable copyables.
-    if (getMainOp() == V)
-      return false;
-    if (isCopyableElement(V)) {
-      auto IsNonSchedulableCopyableElement = [this](Value *V) {
-        auto *I = dyn_cast<Instruction>(V);
-        return !I || isa<PHINode>(I) || I->getParent() != MainOp->getParent() ||
-               (doesNotNeedToBeScheduled(I) &&
-                // If the copyable instructions comes after MainOp
-                // (non-schedulable, but used in the block) - cannot vectorize
-                // it, will possibly generate use before def.
-                !MainOp->comesBefore(I));
-      };
-
-      return IsNonSchedulableCopyableElement(V);
-    }
-    return !I || isa<PHINode>(I) || isVectorLikeInstWithConstOps(I) ||
-           doesNotNeedToBeScheduled(V);
-  }
-
-  /// Checks if the state represents copyable instructions.
-  bool areInstructionsWithCopyableElements() const {
-    assert(valid() && "InstructionsState is invalid.");
-    return HasCopyables;
-  }
-};
-
 std::pair<Instruction *, SmallVector<Value *>>
 convertTo(Instruction *I, const InstructionsState &S) {
   Instruction *SelectedOp = S.getMatchingMainOpOrAltOp(I);
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp
index 565e2436096a9..28b31934fc6cd 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp
@@ -15,13 +15,18 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/PatternMatch.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 
+#include <array>
 #include <utility>
 
 using namespace llvm;
+using namespace llvm::PatternMatch;
 
 namespace llvm::slpvectorizer {
 
@@ -312,4 +317,152 @@ bool BinOpSameOpcodeHelper::add(const Instruction *I) {
           AltOp.trySet(OpcodeInMaskForm, InterchangeableMask));
 }
 
+bool InstructionsState::isSameOperation(const Instruction *I,
+                                        const Instruction *Op) {
+  if (I->getOpcode() != Op->getOpcode())
+    return false;
+  const auto *II = dyn_cast<IntrinsicInst>(I);
+  const auto *IOp = dyn_cast<IntrinsicInst>(Op);
+  if (II || IOp)
+    return II && IOp && II->getIntrinsicID() == IOp->getIntrinsicID();
+  return true;
+}
+
+Instruction *InstructionsState::getMatchingMainOpOrAltOp(Instruction *I) const {
+  assert(MainOp && "MainOp cannot be nullptr.");
+  if (isSameOperation(I, MainOp))
+    return MainOp;
+  if (MainOp->getOpcode() == Instruction::Select &&
+      I->getOpcode() == Instruction::ZExt && !isAltShuffle())
+    return MainOp;
+  // Prefer AltOp instead of interchangeable instruction of MainOp.
+  assert(AltOp && "AltOp cannot be nullptr.");
+  if (isSameOperation(I, AltOp))
+    return AltOp;
+  // BinOpSameOpcodeHelper handles only BinaryOperators; a call cannot match.
+  if (!I->isBinaryOp() || !MainOp->isBinaryOp())
+    return nullptr;
+  BinOpSameOpcodeHelper Converter(MainOp);
+  if (!Converter.add(I) || !Converter.add(MainOp))
+    return nullptr;
+  if (isAltShuffle() && !Converter.hasCandidateOpcode(MainOp->getOpcode())) {
+    BinOpSameOpcodeHelper AltConverter(AltOp);
+    if (AltConverter.add(I) && AltConverter.add(AltOp) &&
+        AltConverter.hasCandidateOpcode(AltOp->getOpcode()))
+      return AltOp;
+  }
+  if (Converter.hasAltOp() && !isAltShuffle())
+    return nullptr;
+  return Converter.hasAltOp() ? AltOp : MainOp;
+}
+
+bool InstructionsState::isMulDivLikeOp() const {
+  constexpr std::array<unsigned, 8> MulDiv = {
+      Instruction::Mul,  Instruction::FMul, Instruction::SDiv,
+      Instruction::UDiv, Instruction::FDiv, Instruction::SRem,
+      Instruction::URem, Instruction::FRem};
+  return is_contained(MulDiv, getOpcode()) &&
+         is_contained(MulDiv, getAltOpcode());
+}
+
+bool InstructionsState::isAddSubLikeOp() const {
+  constexpr std::array<unsigned, 4> AddSub = {
+      Instruction::Add, Instruction::Sub, Instruction::FAdd, Instruction::FSub};
+  return is_contained(AddSub, getOpcode()) &&
+         is_contained(AddSub, getAltOpcode());
+}
+
+bool InstructionsState::isCopyableElement(Value *V) const {
+  assert(valid() && "InstructionsState is invalid.");
+  if (!HasCopyables)
+    return false;
+  if (isAltShuffle() || getOpcode() == Instruction::GetElementPtr)
+    return false;
+  auto *I = dyn_cast<Instruction>(V);
+  if (!I)
+    return !isa<PoisonValue>(V);
+  if (I->getParent() != MainOp->getParent() &&
+      (!isVectorLikeInstWithConstOps(I) ||
+       !isVectorLikeInstWithConstOps(MainOp)))
+    return true;
+  if (isSameOperation(I, MainOp))
+    return false;
+  // BinOpSameOpcodeHelper handles only BinaryOperators; a call is copyable.
+  if (!I->isBinaryOp() || !MainOp->isBinaryOp())
+    return true;
+  BinOpSameOpcodeHelper Converter(MainOp);
+  return !Converter.add(I) || !Converter.add(MainOp) || Converter.hasAltOp() ||
+         !Converter.hasCandidateOpcode(getOpcode());
+}
+
+bool InstructionsState::isExpandedBinOp(Value *V) const {
+  assert(valid() && "InstructionsState is invalid.");
+  if (isCopyableElement(V))
+    return false;
+  auto *ExpandingOp = dyn_cast<Instruction>(V);
+  if (!ExpandingOp)
+    return false;
+  auto CheckForTransformedOpcode = [](const Instruction *RefOp,
+                                      const Instruction *ExpandingOp) {
+    switch (RefOp->getOpcode()) {
+    case Instruction::Add:
+      switch (ExpandingOp->getOpcode()) {
+      case Instruction::Shl:
+        return match(ExpandingOp, m_Shl(m_Value(), m_One()));
+      default:
+        break;
+      }
+      break;
+    default:
+      break;
+    }
+    return false;
+  };
+  // getMatchingMainOpOrAltOp() may legitimately return nullptr, e.g. for a
+  // split node, whose Scalars combine two unrelated operations (main/alt
+  // ops of the split state), so V is not required to match either of them.
+  Instruction *MainOp = getMatchingMainOpOrAltOp(ExpandingOp);
+  if (!MainOp)
+    return false;
+  return CheckForTransformedOpcode(MainOp, ExpandingOp);
+}
+
+bool InstructionsState::isExpandedOperand(Instruction *I, unsigned Idx) const {
+  assert(isExpandedBinOp(I) && "Expected an expanded binop.");
+  switch (I->getOpcode()) {
+  case Instruction::Shl:
+    assert(match(I, m_Shl(m_Value(), m_One())) && "Expected shl x, 1 only.");
+    return Idx == 1;
+  default:
+    llvm_unreachable("Unexpected opcode for an expanded operand.");
+  }
+}
+
+bool InstructionsState::isNonSchedulable(Value *V) const {
+  assert(valid() && "InstructionsState is invalid.");
+  auto *I = dyn_cast<Instruction>(V);
+  if (!HasCopyables)
+    return !I || isa<PHINode>(I) || isVectorLikeInstWithConstOps(I) ||
+           doesNotNeedToBeScheduled(V);
+  // MainOp for copyables always schedulable to correctly identify
+  // non-schedulable copyables.
+  if (getMainOp() == V)
+    return false;
+  if (isCopyableElement(V)) {
+    auto IsNonSchedulableCopyableElement = [this](Value *V) {
+      auto *I = dyn_cast<Instruction>(V);
+      return !I || isa<PHINode>(I) || I->getParent() != MainOp->getParent() ||
+             (doesNotNeedToBeScheduled(I) &&
+              // If the copyable instructions comes after MainOp
+              // (non-schedulable, but used in the block) - cannot vectorize
+              // it, will possibly generate use before def.
+              !MainOp->comesBefore(I));
+    };
+
+    return IsNonSchedulableCopyableElement(V);
+  }
+  return !I || isa<PHINode>(I) || isVectorLikeInstWithConstOps(I) ||
+         doesNotNeedToBeScheduled(V);
+}
+
 } // namespace llvm::slpvectorizer
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h
index 156418fe39c44..b8aa59ff0a22d 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h
@@ -126,6 +126,122 @@ class BinOpSameOpcodeHelper {
   }
 };
 
+/// Main data required for vectorization of instructions.
+class InstructionsState {
+  /// MainOp and AltOp are primarily determined by getSameOpcode. Currently,
+  /// only BinaryOperator, CastInst, and CmpInst support alternate instructions
+  /// (i.e., AltOp is not equal to MainOp; this can be checked using
+  /// isAltShuffle).
+  /// A rare exception is TrySplitNode, where the InstructionsState is derived
+  /// from getMainAltOpsNoStateVL.
+  /// For those InstructionsState that use alternate instructions, the resulting
+  /// vectorized output ultimately comes from a shufflevector. For example,
+  /// given a vector list (VL):
+  /// VL[0] = add i32 a, e
+  /// VL[1] = sub i32 b, f
+  /// VL[2] = add i32 c, g
+  /// VL[3] = sub i32 d, h
+  /// The vectorized result would be:
+  /// intermediated_0 = add <4 x i32> <a, b, c, d>, <e, f, g, h>
+  /// intermediated_1 = sub <4 x i32> <a, b, c, d>, <e, f, g, h>
+  /// result = shufflevector <4 x i32> intermediated_0,
+  ///                        <4 x i32> intermediated_1,
+  ///                        <4 x i32> <i32 0, i32 5, i32 2, i32 7>
+  /// Since shufflevector is used in the final result, when calculating the cost
+  /// (getEntryCost), we must account for the usage of shufflevector in
+  /// GetVectorCost.
+  Instruction *MainOp = nullptr;
+  Instruction *AltOp = nullptr;
+  /// Wether the instruction state represents copyable instructions.
+  bool HasCopyables = false;
+
+public:
+  Instruction *getMainOp() const {
+    assert(valid() && "InstructionsState is invalid.");
+    return MainOp;
+  }
+
+  Instruction *getAltOp() const {
+    assert(valid() && "InstructionsState is invalid.");
+    return AltOp;
+  }
+
+  /// The main/alternate opcodes for the list of instructions.
+  unsigned getOpcode() const { return getMainOp()->getOpcode(); }
+
+  unsigned getAltOpcode() const { return getAltOp()->getOpcode(); }
+
+  /// Some of the instructions in the list have alternate opcodes.
+  bool isAltShuffle() const { return getMainOp() != getAltOp(); }
+
+  /// Checks if \p I is the same operation as \p Op, distinguishing calls by
+  /// intrinsic ID (all calls share the Call opcode, so e.g. umax != smax).
+  static bool isSameOperation(const Instruction *I, const Instruction *Op);
+
+  /// Checks if the instruction matches either the main or alternate opcode.
+  /// \returns
+  /// - MainOp if \param I matches MainOp's opcode directly or can be converted
+  /// to it
+  /// - AltOp if \param I matches AltOp's opcode directly or can be converted to
+  /// it
+  /// - nullptr if \param I cannot be matched or converted to either opcode
+  Instruction *getMatchingMainOpOrAltOp(Instruction *I) const;
+
+  /// Checks if main/alt instructions are shift operations.
+  bool isShiftOp() const {
+    return getMainOp()->isShift() && getAltOp()->isShift();
+  }
+
+  /// Checks if main/alt instructions are bitwise logic operations.
+  bool isBitwiseLogicOp() const {
+    return getMainOp()->isBitwiseLogicOp() && getAltOp()->isBitwiseLogicOp();
+  }
+
+  /// Checks if main/alt instructions are mul/div/rem/fmul/fdiv/frem operations.
+  bool isMulDivLikeOp() const;
+
+  /// Checks if main/alt instructions are add/sub/fadd/fsub operations.
+  bool isAddSubLikeOp() const;
+
+  /// Checks if main/alt instructions are cmp operations.
+  bool isCmpOp() const {
+    return (getOpcode() == Instruction::ICmp ||
+            getOpcode() == Instruction::FCmp) &&
+           getAltOpcode() == getOpcode();
+  }
+
+  /// Checks if the current state is valid, i.e. has non-null MainOp
+  bool valid() const { return MainOp && AltOp; }
+
+  explicit operator bool() const { return valid(); }
+
+  InstructionsState() = delete;
+  InstructionsState(Instruction *MainOp, Instruction *AltOp,
+                    bool HasCopyables = false)
+      : MainOp(MainOp), AltOp(AltOp), HasCopyables(HasCopyables) {}
+  static InstructionsState invalid() { return {nullptr, nullptr}; }
+
+  /// Checks if the value is a copyable element.
+  bool isCopyableElement(Value *V) const;
+
+  /// Checks if the value \p V is a transformed instruction, compatible either
+  /// with main or alternate ops.
+  bool isExpandedBinOp(Value *V) const;
+
+  /// Checks if the operand at index \p Idx of instruction \p I is an expanded
+  /// operand.
+  bool isExpandedOperand(Instruction *I, unsigned Idx) const;
+
+  /// Checks if the value is non-schedulable.
+  bool isNonSchedulable(Value *V) const;
+
+  /// Checks if the state represents copyable instructions.
+  bool areInstructionsWithCopyableElements() const {
+    assert(valid() && "InstructionsState is invalid.");
+    return HasCopyables;
+  }
+};
+
 } // namespace llvm::slpvectorizer
 
 #endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H



More information about the llvm-commits mailing list