[llvm] [SLP][Modularization][NFC] Extract type and constant helpers into SLPUtils (1/3) (PR #206881)
Madhur Amilkanthwar via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 6 23:10:50 PDT 2026
https://github.com/madhur13490 updated https://github.com/llvm/llvm-project/pull/206881
>From e9f27139306798bd2c651af1fd288f6bb5660d89 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Thu, 28 May 2026 04:58:40 -0700
Subject: [PATCH 1/4] [SLP][NFC] Extract type and constant helpers into
SLPUtils (1/3)
As we discussed on RFC:
https://discourse.llvm.org/t/modularizing-slpvectorizer-cpp/90922
This patch introduces the SLPVectorizer/ subdirectory and adds
SLPUtils.{h,cpp} under namespace llvm::slpvectorizer, then moves the
type and constant query helpers into it:
- isConstant
- isVectorLikeInstWithConstOps
- isSplat
- allConstant
- allSameBlock
- allSameType
- allSameOpcode
- getNumElements
- getPartNumElems
- getNumElems
- getInsertExtractIndex
- getExtractIndex
---
llvm/lib/Transforms/Vectorize/CMakeLists.txt | 1 +
.../Transforms/Vectorize/SLPVectorizer.cpp | 177 +-----------------
.../Vectorize/SLPVectorizer/SLPUtils.cpp | 154 +++++++++++++++
.../Vectorize/SLPVectorizer/SLPUtils.h | 117 ++++++++++++
4 files changed, 273 insertions(+), 176 deletions(-)
create mode 100644 llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
create mode 100644 llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
diff --git a/llvm/lib/Transforms/Vectorize/CMakeLists.txt b/llvm/lib/Transforms/Vectorize/CMakeLists.txt
index d081747b821a4..6e26203d957cb 100644
--- a/llvm/lib/Transforms/Vectorize/CMakeLists.txt
+++ b/llvm/lib/Transforms/Vectorize/CMakeLists.txt
@@ -23,6 +23,7 @@ add_llvm_component_library(LLVMVectorize
SandboxVectorizer/Scheduler.cpp
SandboxVectorizer/SeedCollector.cpp
SandboxVectorizer/VecUtils.cpp
+ SLPVectorizer/SLPUtils.cpp
SLPVectorizer.cpp
Vectorize.cpp
VectorCombine.cpp
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index ea97a18403dc8..58de3e8c82c2a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -17,6 +17,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Vectorize/SLPVectorizer.h"
+#include "SLPVectorizer/SLPUtils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/PriorityQueue.h"
@@ -338,15 +339,6 @@ static Type *getValueType(Value *V, bool LookThroughCmp = false) {
return V->getType();
}
-/// \returns the number of elements for Ty.
-static unsigned getNumElements(Type *Ty) {
- assert(!isa<ScalableVectorType>(Ty) &&
- "ScalableVectorType is not supported.");
- if (isVectorizedTy(Ty))
- return getVectorizedTypeVF(Ty).getFixedValue();
- return 1;
-}
-
/// \returns the vector type of ScalarTy based on vectorization factor.
static Type *getWidenedType(Type *ScalarTy, unsigned VF) {
if (VF == 1 && !isVectorizedTy(ScalarTy)) {
@@ -511,47 +503,6 @@ static SmallVector<int> calculateShufflevectorMask(ArrayRef<Value *> VL) {
return Mask;
}
-/// \returns True if the value is a constant (but not globals/constant
-/// expressions).
-static bool isConstant(Value *V) {
- return isa<Constant>(V) && !isa<ConstantExpr, GlobalValue>(V);
-}
-
-/// Checks if \p V is one of vector-like instructions, i.e. undef,
-/// insertelement/extractelement with constant indices for fixed vector type or
-/// extractvalue instruction.
-static bool isVectorLikeInstWithConstOps(Value *V) {
- if (!isa<InsertElementInst, InsertValueInst, ExtractElementInst>(V) &&
- !isa<ExtractValueInst, UndefValue>(V))
- return false;
- auto *I = dyn_cast<Instruction>(V);
- if (!I || isa<ExtractValueInst>(I))
- return true;
- if (isa<ExtractElementInst>(I))
- return isa<FixedVectorType>(I->getOperand(0)->getType()) &&
- isConstant(I->getOperand(1));
- if (isa<InsertElementInst>(I))
- return isa<FixedVectorType>(I->getOperand(0)->getType()) &&
- isConstant(I->getOperand(2));
- assert(isa<InsertValueInst>(I) && "Expected InsertValueInst");
- return true;
-}
-
-/// Returns power-of-2 number of elements in a single register (part), given the
-/// total number of elements \p Size and number of registers (parts) \p
-/// NumParts.
-static unsigned getPartNumElems(unsigned Size, unsigned NumParts) {
- return std::min<unsigned>(Size, bit_ceil(divideCeil(Size, NumParts)));
-}
-
-/// Returns correct remaining number of elements, considering total amount \p
-/// Size, (power-of-2 number) of elements in a single register \p PartNumElems
-/// and current register (part) \p Part.
-static unsigned getNumElems(unsigned Size, unsigned PartNumElems,
- unsigned Part) {
- return std::min<unsigned>(PartNumElems, Size - Part * PartNumElems);
-}
-
#if !defined(NDEBUG)
/// Print a short descriptor of the instruction bundle suitable for debug output.
static std::string shortBundleName(ArrayRef<Value *> VL, int Idx = -1) {
@@ -564,55 +515,6 @@ static std::string shortBundleName(ArrayRef<Value *> VL, int Idx = -1) {
}
#endif
-/// \returns true if all of the instructions in \p VL are in the same block or
-/// false otherwise.
-static bool allSameBlock(ArrayRef<Value *> VL) {
- auto *It = find_if(VL, IsaPred<Instruction>);
- if (It == VL.end())
- return false;
- Instruction *I0 = cast<Instruction>(*It);
- if (all_of(VL, isVectorLikeInstWithConstOps))
- return true;
-
- BasicBlock *BB = I0->getParent();
- for (Value *V : iterator_range(It, VL.end())) {
- if (isa<PoisonValue>(V))
- continue;
- auto *II = dyn_cast<Instruction>(V);
- if (!II)
- return false;
-
- if (BB != II->getParent())
- return false;
- }
- return true;
-}
-
-/// \returns True if all of the values in \p VL are constants (but not
-/// globals/constant expressions).
-static bool allConstant(ArrayRef<Value *> VL) {
- // Constant expressions and globals can't be vectorized like normal integer/FP
- // constants.
- return all_of(VL, isConstant);
-}
-
-/// \returns True if all of the values in \p VL are identical or some of them
-/// are UndefValue.
-static bool isSplat(ArrayRef<Value *> VL) {
- Value *FirstNonUndef = nullptr;
- for (Value *V : VL) {
- if (isa<UndefValue>(V))
- continue;
- if (!FirstNonUndef) {
- FirstNonUndef = V;
- continue;
- }
- if (V != FirstNonUndef)
- return false;
- }
- return FirstNonUndef != nullptr;
-}
-
/// \returns True if \p I is commutative, handles CmpInst and BinaryOperator.
/// For BinaryOperator, it also checks if \p InstWithUses is used in specific
/// patterns that make it effectively commutative (like equality comparisons
@@ -705,29 +607,6 @@ static unsigned getNumberOfPotentiallyCommutativeOps(Instruction *I) {
return I->getNumOperands();
}
-template <typename T>
-static std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
- unsigned Offset) {
- static_assert(std::is_same_v<T, InsertElementInst> ||
- std::is_same_v<T, ExtractElementInst>,
- "unsupported T");
- int Index = Offset;
- if (const auto *IE = dyn_cast<T>(Inst)) {
- const auto *VT = dyn_cast<FixedVectorType>(IE->getType());
- if (!VT)
- return std::nullopt;
- const auto *CI = dyn_cast<ConstantInt>(IE->getOperand(2));
- if (!CI)
- return std::nullopt;
- if (CI->getValue().uge(VT->getNumElements()))
- return std::nullopt;
- Index *= VT->getNumElements();
- Index += CI->getZExtValue();
- return Index;
- }
- return std::nullopt;
-}
-
/// \returns inserting or extracting index of InsertElement, ExtractElement or
/// InsertValue instruction, using Offset as base offset for index.
/// \returns std::nullopt if the index is not an immediate.
@@ -760,28 +639,6 @@ static std::optional<unsigned> getElementIndex(const Value *Inst,
return Index;
}
-/// \returns true if all of the values in \p VL use the same opcode.
-/// For comparison instructions, also checks if predicates match.
-/// PoisonValues are considered matching.
-/// Interchangeable instructions are not considered.
-static bool allSameOpcode(ArrayRef<Value *> VL) {
- auto *It = find_if(VL, IsaPred<Instruction>);
- if (It == VL.end())
- return true;
- Instruction *MainOp = cast<Instruction>(*It);
- unsigned Opcode = MainOp->getOpcode();
- bool IsCmpOp = isa<CmpInst>(MainOp);
- CmpInst::Predicate BasePred = IsCmpOp ? cast<CmpInst>(MainOp)->getPredicate()
- : CmpInst::BAD_ICMP_PREDICATE;
- return std::all_of(It, VL.end(), [&](Value *V) {
- if (auto *CI = dyn_cast<CmpInst>(V))
- return BasePred == CI->getPredicate();
- if (auto *I = dyn_cast<Instruction>(V))
- return I->getOpcode() == Opcode;
- return isa<PoisonValue>(V);
- });
-}
-
namespace {
/// Specifies the way the mask should be analyzed for undefs/poisonous elements
/// in the shuffle mask.
@@ -977,31 +834,6 @@ isFixedVectorShuffle(ArrayRef<Value *> VL, SmallVectorImpl<int> &Mask,
: TargetTransformInfo::SK_PermuteSingleSrc;
}
-/// \returns True if Extract{Value,Element} instruction extracts element Idx.
-static std::optional<unsigned> getExtractIndex(const Instruction *E) {
- unsigned Opcode = E->getOpcode();
- assert((Opcode == Instruction::ExtractElement ||
- Opcode == Instruction::ExtractValue) &&
- "Expected extractelement or extractvalue instruction.");
- if (Opcode == Instruction::ExtractElement) {
- auto *CI = dyn_cast<ConstantInt>(E->getOperand(1));
- if (!CI)
- return std::nullopt;
- // Check if the index is out of bound - we can get the source vector from
- // operand 0
- unsigned Idx = CI->getZExtValue();
- auto *EE = cast<ExtractElementInst>(E);
- const unsigned VF = ::getNumElements(EE->getVectorOperandType());
- if (Idx >= VF)
- return std::nullopt;
- return Idx;
- }
- auto *EI = cast<ExtractValueInst>(E);
- if (EI->getNumIndices() != 1)
- return std::nullopt;
- return *EI->idx_begin();
-}
-
/// Checks if the provided value does not require scheduling. It does not
/// require scheduling if this is not an instruction or it is an instruction
/// that does not read/write memory and all operands are either not instructions
@@ -1844,13 +1676,6 @@ static InstructionsState getSameOpcode(ArrayRef<Value *> VL,
return S;
}
-/// \returns true if all of the values in \p VL have the same type or false
-/// otherwise.
-static bool allSameType(ArrayRef<Value *> VL) {
- Type *Ty = VL.consume_front()->getType();
- return all_of(VL, [&](Value *V) { return V->getType() == Ty; });
-}
-
/// \returns True if in-tree use also needs extract. This refers to
/// possible scalar operand in vectorized instruction.
static bool doesInTreeUserNeedToExtract(Value *Scalar, Instruction *UserInst,
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
new file mode 100644
index 0000000000000..477250c93b06f
--- /dev/null
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
@@ -0,0 +1,154 @@
+//===- SLPUtils.cpp - SLP Vectorizer free utility helpers -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SLPUtils.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Analysis/VectorUtils.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <bit>
+
+using namespace llvm;
+using namespace llvm::PatternMatch;
+
+namespace llvm::slpvectorizer {
+
+bool isConstant(Value *V) {
+ return isa<Constant>(V) && !isa<ConstantExpr, GlobalValue>(V);
+}
+
+bool isVectorLikeInstWithConstOps(Value *V) {
+ if (!isa<InsertElementInst, InsertValueInst, ExtractElementInst>(V) &&
+ !isa<ExtractValueInst, UndefValue>(V))
+ return false;
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I || isa<ExtractValueInst>(I))
+ return true;
+ if (isa<ExtractElementInst>(I))
+ return isa<FixedVectorType>(I->getOperand(0)->getType()) &&
+ isConstant(I->getOperand(1));
+ if (isa<InsertElementInst>(I))
+ return isa<FixedVectorType>(I->getOperand(0)->getType()) &&
+ isConstant(I->getOperand(2));
+ assert(isa<InsertValueInst>(I) && "Expected InsertValueInst");
+ return true;
+}
+
+unsigned getNumElements(Type *Ty) {
+ assert(!isa<ScalableVectorType>(Ty) &&
+ "ScalableVectorType is not supported.");
+ if (isVectorizedTy(Ty))
+ return getVectorizedTypeVF(Ty).getFixedValue();
+ return 1;
+}
+
+unsigned getPartNumElems(unsigned Size, unsigned NumParts) {
+ return std::min<unsigned>(Size, bit_ceil(divideCeil(Size, NumParts)));
+}
+
+unsigned getNumElems(unsigned Size, unsigned PartNumElems, unsigned Part) {
+ return std::min<unsigned>(PartNumElems, Size - Part * PartNumElems);
+}
+
+bool allSameBlock(ArrayRef<Value *> VL) {
+ auto *It = find_if(VL, IsaPred<Instruction>);
+ if (It == VL.end())
+ return false;
+ Instruction *I0 = cast<Instruction>(*It);
+ if (all_of(VL, isVectorLikeInstWithConstOps))
+ return true;
+
+ BasicBlock *BB = I0->getParent();
+ for (Value *V : iterator_range(It, VL.end())) {
+ if (isa<PoisonValue>(V))
+ continue;
+ auto *II = dyn_cast<Instruction>(V);
+ if (!II)
+ return false;
+
+ if (BB != II->getParent())
+ return false;
+ }
+ return true;
+}
+
+bool allConstant(ArrayRef<Value *> VL) {
+ // Constant expressions and globals can't be vectorized like normal integer/FP
+ // constants.
+ return all_of(VL, isConstant);
+}
+
+bool isSplat(ArrayRef<Value *> VL) {
+ Value *FirstNonUndef = nullptr;
+ for (Value *V : VL) {
+ if (isa<UndefValue>(V))
+ continue;
+ if (!FirstNonUndef) {
+ FirstNonUndef = V;
+ continue;
+ }
+ if (V != FirstNonUndef)
+ return false;
+ }
+ return FirstNonUndef != nullptr;
+}
+
+bool allSameOpcode(ArrayRef<Value *> VL) {
+ auto *It = find_if(VL, IsaPred<Instruction>);
+ if (It == VL.end())
+ return true;
+ Instruction *MainOp = cast<Instruction>(*It);
+ unsigned Opcode = MainOp->getOpcode();
+ bool IsCmpOp = isa<CmpInst>(MainOp);
+ CmpInst::Predicate BasePred = IsCmpOp ? cast<CmpInst>(MainOp)->getPredicate()
+ : CmpInst::BAD_ICMP_PREDICATE;
+ return std::all_of(It, VL.end(), [&](Value *V) {
+ if (auto *CI = dyn_cast<CmpInst>(V))
+ return BasePred == CI->getPredicate();
+ if (auto *I = dyn_cast<Instruction>(V))
+ return I->getOpcode() == Opcode;
+ return isa<PoisonValue>(V);
+ });
+}
+
+std::optional<unsigned> getExtractIndex(const Instruction *E) {
+ unsigned Opcode = E->getOpcode();
+ assert((Opcode == Instruction::ExtractElement ||
+ Opcode == Instruction::ExtractValue) &&
+ "Expected extractelement or extractvalue instruction.");
+ if (Opcode == Instruction::ExtractElement) {
+ auto *CI = dyn_cast<ConstantInt>(E->getOperand(1));
+ if (!CI)
+ return std::nullopt;
+ // Check if the index is out of bound - we can get the source vector from
+ // operand 0
+ unsigned Idx = CI->getZExtValue();
+ auto *EE = cast<ExtractElementInst>(E);
+ const unsigned VF = getNumElements(EE->getVectorOperandType());
+ if (Idx >= VF)
+ return std::nullopt;
+ return Idx;
+ }
+ auto *EI = cast<ExtractValueInst>(E);
+ if (EI->getNumIndices() != 1)
+ return std::nullopt;
+ return *EI->idx_begin();
+}
+
+bool allSameType(ArrayRef<Value *> VL) {
+ Type *Ty = VL.consume_front()->getType();
+ return all_of(VL, [&](Value *V) { return V->getType() == Ty; });
+}
+
+} // namespace llvm::slpvectorizer
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
new file mode 100644
index 0000000000000..385946bda6c6f
--- /dev/null
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
@@ -0,0 +1,117 @@
+//===- SLPUtils.h - SLP Vectorizer free utility helpers --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Internal header used by SLPVectorizer.cpp. It declares free helper
+// functions that do not depend on BoUpSLP, InstructionsState, or any other
+// SLP-private type. Splitting them out keeps SLPVectorizer.cpp focused on
+// the build / legality / cost / codegen pipeline.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
+#define LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Analysis/MemoryLocation.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Value.h"
+
+#include <optional>
+#include <string>
+#include <type_traits>
+
+namespace llvm {
+
+class Constant;
+class Instruction;
+class TargetLibraryInfo;
+class TargetTransformInfo;
+class Type;
+class Value;
+
+namespace slpvectorizer {
+
+/// \returns True if the value is a constant (but not globals/constant
+/// expressions).
+bool isConstant(Value *V);
+
+/// Checks if \p V is one of vector-like instructions, i.e. undef,
+/// insertelement/extractelement with constant indices for fixed vector type
+/// or extractvalue instruction.
+bool isVectorLikeInstWithConstOps(Value *V);
+
+/// \returns the number of elements for Ty.
+unsigned getNumElements(Type *Ty);
+
+/// Returns power-of-2 number of elements in a single register (part), given
+/// the total number of elements \p Size and number of registers (parts) \p
+/// NumParts.
+unsigned getPartNumElems(unsigned Size, unsigned NumParts);
+
+/// Returns correct remaining number of elements, considering total amount
+/// \p Size, (power-of-2 number) of elements in a single register
+/// \p PartNumElems and current register (part) \p Part.
+unsigned getNumElems(unsigned Size, unsigned PartNumElems, unsigned Part);
+
+/// \returns true if all of the instructions in \p VL are in the same block
+/// or false otherwise.
+bool allSameBlock(ArrayRef<Value *> VL);
+
+/// \returns True if all of the values in \p VL are constants (but not
+/// globals/constant expressions).
+bool allConstant(ArrayRef<Value *> VL);
+
+/// \returns True if all of the values in \p VL are identical or some of them
+/// are UndefValue.
+bool isSplat(ArrayRef<Value *> VL);
+
+/// \returns true if all of the values in \p VL use the same opcode.
+/// For comparison instructions, also checks if predicates match.
+/// PoisonValues are considered matching. Interchangeable instructions are
+/// not considered.
+bool allSameOpcode(ArrayRef<Value *> VL);
+
+/// \returns True if Extract{Value,Element} instruction extracts element Idx.
+std::optional<unsigned> getExtractIndex(const Instruction *E);
+
+/// \returns true iff every value in \p VL has the same Type as the first.
+bool allSameType(ArrayRef<Value *> VL);
+
+/// \returns inserting or extracting index of InsertElement / ExtractElement
+/// instruction, using \p Offset as base offset for index.
+template <typename T>
+std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
+ unsigned Offset) {
+ static_assert(std::is_same_v<T, InsertElementInst> ||
+ std::is_same_v<T, ExtractElementInst>,
+ "unsupported T");
+ int Index = Offset;
+ if (const auto *IE = dyn_cast<T>(Inst)) {
+ const auto *VT = dyn_cast<FixedVectorType>(IE->getType());
+ if (!VT)
+ return std::nullopt;
+ const auto *CI = dyn_cast<ConstantInt>(IE->getOperand(2));
+ if (!CI)
+ return std::nullopt;
+ if (CI->getValue().uge(VT->getNumElements()))
+ return std::nullopt;
+ Index *= VT->getNumElements();
+ Index += CI->getZExtValue();
+ return Index;
+ }
+ return std::nullopt;
+}
+
+} // end namespace slpvectorizer
+} // end namespace llvm
+
+#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
>From 7f65ec3eb88225160d72cc6a26af6005f1d2039a Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Wed, 1 Jul 2026 22:13:03 -0700
Subject: [PATCH 2/4] fixup! address comments
---
.../Vectorize/SLPVectorizer/SLPUtils.cpp | 2 --
.../Transforms/Vectorize/SLPVectorizer/SLPUtils.h | 14 +++-----------
2 files changed, 3 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
index 477250c93b06f..2ad4cbbe3ae29 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
@@ -17,8 +17,6 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include <bit>
-
using namespace llvm;
using namespace llvm::PatternMatch;
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
index 385946bda6c6f..54ac6c4c41ac3 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
@@ -17,28 +17,21 @@
#define LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallBitVector.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Value.h"
#include <optional>
-#include <string>
#include <type_traits>
namespace llvm {
-
-class Constant;
class Instruction;
-class TargetLibraryInfo;
-class TargetTransformInfo;
class Type;
class Value;
+} // namespace llvm
-namespace slpvectorizer {
+namespace llvm::slpvectorizer {
/// \returns True if the value is a constant (but not globals/constant
/// expressions).
@@ -111,7 +104,6 @@ std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
return std::nullopt;
}
-} // end namespace slpvectorizer
-} // end namespace llvm
+} // namespace llvm::slpvectorizer
#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
>From 206eac9319c8d2368e7ba1d57ac37b47fe065e7c Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Thu, 2 Jul 2026 09:10:11 -0700
Subject: [PATCH 3/4] fixup! address comments
---
.../Vectorize/SLPVectorizer/SLPUtils.cpp | 44 ++++++++++++++++---
.../Vectorize/SLPVectorizer/SLPUtils.h | 36 +++------------
2 files changed, 43 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
index 2ad4cbbe3ae29..a33fd20b44b9c 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
@@ -9,16 +9,16 @@
#include "SLPUtils.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/VectorUtils.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/PatternMatch.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/raw_ostream.h"
+
+#include <type_traits>
using namespace llvm;
-using namespace llvm::PatternMatch;
namespace llvm::slpvectorizer {
@@ -129,8 +129,8 @@ std::optional<unsigned> getExtractIndex(const Instruction *E) {
auto *CI = dyn_cast<ConstantInt>(E->getOperand(1));
if (!CI)
return std::nullopt;
- // Check if the index is out of bound - we can get the source vector from
- // operand 0
+ // Check if the index is out of bound. We can get the source vector from
+ // operand 0.
unsigned Idx = CI->getZExtValue();
auto *EE = cast<ExtractElementInst>(E);
const unsigned VF = getNumElements(EE->getVectorOperandType());
@@ -149,4 +149,34 @@ bool allSameType(ArrayRef<Value *> VL) {
return all_of(VL, [&](Value *V) { return V->getType() == Ty; });
}
+template <typename T>
+std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
+ unsigned Offset) {
+ static_assert(std::is_same_v<T, InsertElementInst> ||
+ std::is_same_v<T, ExtractElementInst>,
+ "unsupported T");
+ int Index = Offset;
+ if (const auto *IE = dyn_cast<T>(Inst)) {
+ const auto *VT = dyn_cast<FixedVectorType>(IE->getType());
+ if (!VT)
+ return std::nullopt;
+ const auto *CI = dyn_cast<ConstantInt>(IE->getOperand(2));
+ if (!CI)
+ return std::nullopt;
+ if (CI->getValue().uge(VT->getNumElements()))
+ return std::nullopt;
+ Index *= VT->getNumElements();
+ Index += CI->getZExtValue();
+ return Index;
+ }
+ return std::nullopt;
+}
+
+// Only these two specializations are used; instantiate them here so the
+// definition can stay out of the header.
+template std::optional<unsigned>
+getInsertExtractIndex<InsertElementInst>(const Value *, unsigned);
+template std::optional<unsigned>
+getInsertExtractIndex<ExtractElementInst>(const Value *, unsigned);
+
} // namespace llvm::slpvectorizer
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
index 54ac6c4c41ac3..a7a23fb172a59 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.h
@@ -17,13 +17,8 @@
#define LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPUTILS_H
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Value.h"
#include <optional>
-#include <type_traits>
namespace llvm {
class Instruction;
@@ -55,8 +50,7 @@ unsigned getPartNumElems(unsigned Size, unsigned NumParts);
/// \p PartNumElems and current register (part) \p Part.
unsigned getNumElems(unsigned Size, unsigned PartNumElems, unsigned Part);
-/// \returns true if all of the instructions in \p VL are in the same block
-/// or false otherwise.
+/// \returns True if all of the instructions in \p VL are in the same block.
bool allSameBlock(ArrayRef<Value *> VL);
/// \returns True if all of the values in \p VL are constants (but not
@@ -67,7 +61,7 @@ bool allConstant(ArrayRef<Value *> VL);
/// are UndefValue.
bool isSplat(ArrayRef<Value *> VL);
-/// \returns true if all of the values in \p VL use the same opcode.
+/// \returns True if all of the values in \p VL use the same opcode.
/// For comparison instructions, also checks if predicates match.
/// PoisonValues are considered matching. Interchangeable instructions are
/// not considered.
@@ -76,33 +70,15 @@ bool allSameOpcode(ArrayRef<Value *> VL);
/// \returns True if Extract{Value,Element} instruction extracts element Idx.
std::optional<unsigned> getExtractIndex(const Instruction *E);
-/// \returns true iff every value in \p VL has the same Type as the first.
+/// \returns True iff every value in \p VL has the same Type as the first.
bool allSameType(ArrayRef<Value *> VL);
/// \returns inserting or extracting index of InsertElement / ExtractElement
-/// instruction, using \p Offset as base offset for index.
+/// instruction, using \p Offset as base offset for index. Only instantiated
+/// for InsertElementInst and ExtractElementInst (see SLPUtils.cpp).
template <typename T>
std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
- unsigned Offset) {
- static_assert(std::is_same_v<T, InsertElementInst> ||
- std::is_same_v<T, ExtractElementInst>,
- "unsupported T");
- int Index = Offset;
- if (const auto *IE = dyn_cast<T>(Inst)) {
- const auto *VT = dyn_cast<FixedVectorType>(IE->getType());
- if (!VT)
- return std::nullopt;
- const auto *CI = dyn_cast<ConstantInt>(IE->getOperand(2));
- if (!CI)
- return std::nullopt;
- if (CI->getValue().uge(VT->getNumElements()))
- return std::nullopt;
- Index *= VT->getNumElements();
- Index += CI->getZExtValue();
- return Index;
- }
- return std::nullopt;
-}
+ unsigned Offset);
} // namespace llvm::slpvectorizer
>From f608043b522d09539538397f36309c90059d46d7 Mon Sep 17 00:00:00 2001
From: Madhur Amilkanthwar <madhura at nvidia.com>
Date: Mon, 6 Jul 2026 23:09:36 -0700
Subject: [PATCH 4/4] fixup! address comments int ->unsigned
---
llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
index a33fd20b44b9c..8dc46631549d7 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPUtils.cpp
@@ -155,7 +155,7 @@ std::optional<unsigned> getInsertExtractIndex(const Value *Inst,
static_assert(std::is_same_v<T, InsertElementInst> ||
std::is_same_v<T, ExtractElementInst>,
"unsupported T");
- int Index = Offset;
+ unsigned Index = Offset;
if (const auto *IE = dyn_cast<T>(Inst)) {
const auto *VT = dyn_cast<FixedVectorType>(IE->getType());
if (!VT)
More information about the llvm-commits
mailing list