[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