LLVM 22.0.0git
VecUtils.h
Go to the documentation of this file.
1//===- VecUtils.h -----------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Collector for SandboxVectorizer related convenience functions that don't
10// belong in other classes.
11
12#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_VECUTILS_H
13#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_VECUTILS_H
14
16#include "llvm/IR/DataLayout.h"
17#include "llvm/SandboxIR/Type.h"
20
21namespace llvm {
22/// Traits for DenseMap.
23template <> struct DenseMapInfo<SmallVector<sandboxir::Value *>> {
26 }
29 }
30 static unsigned getHashValue(const SmallVector<sandboxir::Value *> &Vec) {
31 return hash_combine_range(Vec);
32 }
35 return Vec1 == Vec2;
36 }
37};
38
39namespace sandboxir {
40
41class VecUtils {
42public:
43 /// \Returns the number of elements in \p Ty. That is the number of lanes if a
44 /// fixed vector or 1 if scalar. ScalableVectors have unknown size and
45 /// therefore are unsupported.
46 static int getNumElements(Type *Ty) {
47 assert(!isa<ScalableVectorType>(Ty));
48 return Ty->isVectorTy() ? cast<FixedVectorType>(Ty)->getNumElements() : 1;
49 }
50 /// Returns \p Ty if scalar or its element type if vector.
51 static Type *getElementType(Type *Ty) {
52 return Ty->isVectorTy() ? cast<FixedVectorType>(Ty)->getElementType() : Ty;
53 }
54
55 /// \Returns true if \p I1 and \p I2 are load/stores accessing consecutive
56 /// memory addresses.
57 template <typename LoadOrStoreT>
58 static bool areConsecutive(LoadOrStoreT *I1, LoadOrStoreT *I2,
59 ScalarEvolution &SE, const DataLayout &DL) {
60 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
61 std::is_same<LoadOrStoreT, StoreInst>::value,
62 "Expected Load or Store!");
63 auto Diff = Utils::getPointerDiffInBytes(I1, I2, SE);
64 if (!Diff)
65 return false;
66 int ElmBytes = Utils::getNumBits(I1) / 8;
67 return *Diff == ElmBytes;
68 }
69
70 template <typename LoadOrStoreT>
72 const DataLayout &DL) {
73 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
74 std::is_same<LoadOrStoreT, StoreInst>::value,
75 "Expected Load or Store!");
76 assert(isa<LoadOrStoreT>(Bndl[0]) && "Expected Load or Store!");
77 auto *LastLS = cast<LoadOrStoreT>(Bndl[0]);
78 for (Value *V : drop_begin(Bndl)) {
79 assert(isa<LoadOrStoreT>(V) &&
80 "Unimplemented: we only support StoreInst!");
81 auto *LS = cast<LoadOrStoreT>(V);
82 if (!VecUtils::areConsecutive(LastLS, LS, SE, DL))
83 return false;
84 LastLS = LS;
85 }
86 return true;
87 }
88
89 /// \Returns the number of vector lanes of \p Ty or 1 if not a vector.
90 /// NOTE: It asserts that \p Ty is a fixed vector type.
91 static unsigned getNumLanes(Type *Ty) {
92 assert(!isa<ScalableVectorType>(Ty) && "Expect scalar or fixed vector");
93 if (auto *FixedVecTy = dyn_cast<FixedVectorType>(Ty))
94 return FixedVecTy->getNumElements();
95 return 1u;
96 }
97
98 /// \Returns the expected vector lanes of \p V or 1 if not a vector.
99 /// NOTE: It asserts that \p V is a fixed vector.
100 static unsigned getNumLanes(Value *V) {
102 }
103
104 /// \Returns the total number of lanes across all values in \p Bndl.
105 static unsigned getNumLanes(ArrayRef<Value *> Bndl) {
106 unsigned Lanes = 0;
107 for (Value *V : Bndl)
108 Lanes += getNumLanes(V);
109 return Lanes;
110 }
111
112 /// \Returns <NumElts x ElemTy>.
113 /// It works for both scalar and vector \p ElemTy.
114 static Type *getWideType(Type *ElemTy, unsigned NumElts) {
115 if (ElemTy->isVectorTy()) {
116 auto *VecTy = cast<FixedVectorType>(ElemTy);
117 ElemTy = VecTy->getElementType();
118 NumElts = VecTy->getNumElements() * NumElts;
119 }
120 return FixedVectorType::get(ElemTy, NumElts);
121 }
122 /// \Returns the instruction in \p Instrs that is lowest in the BB. Expects
123 /// that all instructions are in the same BB.
125 Instruction *LowestI = Instrs.front();
126 for (auto *I : drop_begin(Instrs)) {
127 if (LowestI->comesBefore(I))
128 LowestI = I;
129 }
130 return LowestI;
131 }
132 /// \Returns the lowest instruction in \p Vals, or nullptr if no instructions
133 /// are found. Skips instructions not in \p BB.
135 // Find the first Instruction in Vals that is also in `BB`.
136 auto It = find_if(Vals, [BB](Value *V) {
137 return isa<Instruction>(V) && cast<Instruction>(V)->getParent() == BB;
138 });
139 // If we couldn't find an instruction return nullptr.
140 if (It == Vals.end())
141 return nullptr;
142 Instruction *FirstI = cast<Instruction>(*It);
143 // Now look for the lowest instruction in Vals starting from one position
144 // after FirstI.
145 Instruction *LowestI = FirstI;
146 for (auto *V : make_range(std::next(It), Vals.end())) {
147 auto *I = dyn_cast<Instruction>(V);
148 // Skip non-instructions.
149 if (I == nullptr)
150 continue;
151 // Skips instructions not in \p BB.
152 if (I->getParent() != BB)
153 continue;
154 // If `LowestI` comes before `I` then `I` is the new lowest.
155 if (LowestI->comesBefore(I))
156 LowestI = I;
157 }
158 return LowestI;
159 }
160
161 /// If \p I is not a PHI it returns it. Else it walks down the instruction
162 /// chain looking for the last PHI and returns it. \Returns nullptr if \p I is
163 /// nullptr.
165 Instruction *LastI = I;
166 while (I != nullptr && isa<PHINode>(I)) {
167 LastI = I;
168 I = I->getNextNode();
169 }
170 return LastI;
171 }
172
173 /// If all values in \p Bndl are of the same scalar type then return it,
174 /// otherwise return nullptr.
176 Value *V0 = Bndl[0];
177 Type *Ty0 = Utils::getExpectedType(V0);
178 Type *ScalarTy = VecUtils::getElementType(Ty0);
179 for (auto *V : drop_begin(Bndl)) {
181 Type *NScalarTy = VecUtils::getElementType(NTy);
182 if (NScalarTy != ScalarTy)
183 return nullptr;
184 }
185 return ScalarTy;
186 }
187
188 /// Similar to tryGetCommonScalarType() but will assert that there is a common
189 /// type. So this is faster in release builds as it won't iterate through the
190 /// values.
192 Value *V0 = Bndl[0];
193 Type *Ty0 = Utils::getExpectedType(V0);
194 Type *ScalarTy = VecUtils::getElementType(Ty0);
195 assert(tryGetCommonScalarType(Bndl) && "Expected common scalar type!");
196 return ScalarTy;
197 }
198 /// \Returns the first integer power of 2 that is <= Num.
199 LLVM_ABI static unsigned getFloorPowerOf2(unsigned Num);
200
201 /// Helper struct for `matchPack()`. Describes the instructions and operands
202 /// of a pack pattern.
203 struct PackPattern {
204 /// The insertelement instructions that form the pack pattern in bottom-up
205 /// order, i.e., the first instruction in `Instrs` is the bottom-most
206 /// InsertElement instruction of the pack pattern.
207 /// For example in this simple pack pattern:
208 /// %Pack0 = insertelement <2 x i8> poison, i8 %v0, i64 0
209 /// %Pack1 = insertelement <2 x i8> %Pack0, i8 %v1, i64 1
210 /// this is [ %Pack1, %Pack0 ].
212 /// The "external" operands of the pack pattern, i.e., the values that get
213 /// packed into a vector, skipping the ones in `Instrs`. The operands are in
214 /// bottom-up order, starting from the operands of the bottom-most insert.
215 /// So in our example this would be [ %v1, %v0 ].
217 };
218
219 /// If \p I is the last instruction of a pack pattern (i.e., an InsertElement
220 /// into a vector), then this function returns the instructions in the pack
221 /// and the operands in the pack, else returns nullopt.
222 /// Here is an example of a matched pattern:
223 /// %PackA0 = insertelement <2 x i8> poison, i8 %v0, i64 0
224 /// %PackA1 = insertelement <2 x i8> %PackA0, i8 %v1, i64 1
225 /// TODO: this currently detects only simple canonicalized patterns.
226 static std::optional<PackPattern> matchPack(Instruction *I) {
227 // TODO: Support vector pack patterns.
228 // TODO: Support out-of-order inserts.
229
230 // Early return if `I` is not an Insert.
231 if (!isa<InsertElementInst>(I))
232 return std::nullopt;
233 auto *BB0 = I->getParent();
234 // The pack contains as many instrs as the lanes of the bottom-most Insert
235 unsigned ExpectedNumInserts = VecUtils::getNumLanes(I);
236 assert(ExpectedNumInserts >= 2 && "Expected at least 2 inserts!");
238 Pack.Operands.resize(ExpectedNumInserts);
239 // Collect the inserts by walking up the use-def chain.
240 Instruction *InsertI = I;
241 for (auto ExpectedLane : reverse(seq<unsigned>(ExpectedNumInserts))) {
242 if (InsertI == nullptr)
243 return std::nullopt;
244 if (InsertI->getParent() != BB0)
245 return std::nullopt;
246 // Check the lane.
247 auto *LaneC = dyn_cast<ConstantInt>(InsertI->getOperand(2));
248 if (LaneC == nullptr || LaneC->getSExtValue() != ExpectedLane)
249 return std::nullopt;
250 Pack.Instrs.push_back(InsertI);
251 Pack.Operands[ExpectedLane] = InsertI->getOperand(1);
252
253 Value *Op = InsertI->getOperand(0);
254 if (ExpectedLane == 0) {
255 // Check the topmost insert. The operand should be a Poison.
256 if (!isa<PoisonValue>(Op))
257 return std::nullopt;
258 } else {
259 InsertI = dyn_cast<InsertElementInst>(Op);
260 }
261 }
262 return Pack;
263 }
264
265#ifndef NDEBUG
266 /// Helper dump function for debugging.
267 LLVM_DUMP_METHOD static void dump(ArrayRef<Value *> Bndl);
269#endif // NDEBUG
270};
271
272} // namespace sandboxir
273
274} // namespace llvm
275
276#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_VECUTILS_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_ABI
Definition: Compiler.h:213
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:638
#define I(x, y, z)
Definition: MD5.cpp:58
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
const T & front() const
front - Get the first element.
Definition: ArrayRef.h:150
iterator end() const
Definition: ArrayRef.h:136
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
The main scalar evolution driver.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
LLVM Value Representation.
Definition: Value.h:75
Contains a list of sandboxir::Instruction's.
Definition: BasicBlock.h:68
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition: Instruction.h:43
bool comesBefore(const Instruction *Other) const
Given an instruction Other in the same basic block as this instruction, return true if this instructi...
Definition: Instruction.h:215
LLVM_ABI BasicBlock * getParent() const
\Returns the BasicBlock containing this Instruction, or null if it is detached.
Just like llvm::Type these are immutable, unique, never get freed and can only be created via static ...
Definition: Type.h:47
bool isVectorTy() const
True if this is an instance of VectorType.
Definition: Type.h:201
Value * getOperand(unsigned OpIdx) const
Definition: User.h:123
static std::optional< int > getPointerDiffInBytes(LoadOrStoreT *I0, LoadOrStoreT *I1, ScalarEvolution &SE)
\Returns the gap between the memory locations accessed by I0 and I1 in bytes.
Definition: Utils.h:92
static unsigned getNumBits(Type *Ty, const DataLayout &DL)
\Returns the number of bits of Ty.
Definition: Utils.h:66
static Type * getExpectedType(const Value *V)
\Returns the expected type of Value V.
Definition: Utils.h:32
A SandboxIR Value has users. This is the base class.
Definition: Value.h:66
static Type * tryGetCommonScalarType(ArrayRef< Value * > Bndl)
If all values in Bndl are of the same scalar type then return it, otherwise return nullptr.
Definition: VecUtils.h:175
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition: VecUtils.h:124
static Type * getCommonScalarType(ArrayRef< Value * > Bndl)
Similar to tryGetCommonScalarType() but will assert that there is a common type.
Definition: VecUtils.h:191
static int getNumElements(Type *Ty)
\Returns the number of elements in Ty.
Definition: VecUtils.h:46
static std::optional< PackPattern > matchPack(Instruction *I)
If I is the last instruction of a pack pattern (i.e., an InsertElement into a vector),...
Definition: VecUtils.h:226
static Instruction * getLastPHIOrSelf(Instruction *I)
If I is not a PHI it returns it.
Definition: VecUtils.h:164
static unsigned getNumLanes(Type *Ty)
\Returns the number of vector lanes of Ty or 1 if not a vector.
Definition: VecUtils.h:91
static Instruction * getLowest(ArrayRef< Value * > Vals, BasicBlock *BB)
\Returns the lowest instruction in Vals, or nullptr if no instructions are found.
Definition: VecUtils.h:134
static LLVM_DUMP_METHOD void dump(ArrayRef< Value * > Bndl)
Helper dump function for debugging.
Definition: VecUtils.cpp:28
static Type * getWideType(Type *ElemTy, unsigned NumElts)
\Returns <NumElts x ElemTy>.
Definition: VecUtils.h:114
static bool areConsecutive(LoadOrStoreT *I1, LoadOrStoreT *I2, ScalarEvolution &SE, const DataLayout &DL)
\Returns true if I1 and I2 are load/stores accessing consecutive memory addresses.
Definition: VecUtils.h:58
static Type * getElementType(Type *Ty)
Returns Ty if scalar or its element type if vector.
Definition: VecUtils.h:51
static bool areConsecutive(ArrayRef< Value * > &Bndl, ScalarEvolution &SE, const DataLayout &DL)
Definition: VecUtils.h:71
static unsigned getNumLanes(Value *V)
\Returns the expected vector lanes of V or 1 if not a vector.
Definition: VecUtils.h:100
static unsigned getNumLanes(ArrayRef< Value * > Bndl)
\Returns the total number of lanes across all values in Bndl.
Definition: VecUtils.h:105
static LLVM_ABI unsigned getFloorPowerOf2(unsigned Num)
\Returns the first integer power of 2 that is <= Num.
Definition: VecUtils.cpp:13
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition: STLExtras.h:338
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1777
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition: Hashing.h:469
static bool isEqual(const SmallVector< sandboxir::Value * > &Vec1, const SmallVector< sandboxir::Value * > &Vec2)
Definition: VecUtils.h:33
static SmallVector< sandboxir::Value * > getEmptyKey()
Definition: VecUtils.h:24
static unsigned getHashValue(const SmallVector< sandboxir::Value * > &Vec)
Definition: VecUtils.h:30
static SmallVector< sandboxir::Value * > getTombstoneKey()
Definition: VecUtils.h:27
An information struct used to provide DenseMap with the various necessary components for a given valu...
Definition: DenseMapInfo.h:54
Helper struct for matchPack().
Definition: VecUtils.h:203
SmallVector< Value * > Operands
The "external" operands of the pack pattern, i.e., the values that get packed into a vector,...
Definition: VecUtils.h:216
SmallVector< Instruction * > Instrs
The insertelement instructions that form the pack pattern in bottom-up order, i.e....
Definition: VecUtils.h:211