LLVM 23.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#include <iterator>
21
22namespace llvm {
23/// Traits for DenseMap.
24template <> struct DenseMapInfo<SmallVector<sandboxir::Value *>> {
31 static unsigned getHashValue(const SmallVector<sandboxir::Value *> &Vec) {
32 return hash_combine_range(Vec);
33 }
36 return Vec1 == Vec2;
37 }
38};
39
40namespace sandboxir {
41
42class VecUtils {
43public:
44 /// \Returns the number of elements in \p Ty. That is the number of lanes if a
45 /// fixed vector or 1 if scalar. ScalableVectors have unknown size and
46 /// therefore are unsupported.
47 static int getNumElements(Type *Ty) {
49 return Ty->isVectorTy() ? cast<FixedVectorType>(Ty)->getNumElements() : 1;
50 }
51 /// Returns \p Ty if scalar or its element type if vector.
52 static Type *getElementType(Type *Ty) {
53 return Ty->isVectorTy() ? cast<FixedVectorType>(Ty)->getElementType() : Ty;
54 }
55
56 /// \Returns true if \p I1 and \p I2 are load/stores accessing consecutive
57 /// memory addresses.
58 template <typename LoadOrStoreT>
59 static bool areConsecutive(LoadOrStoreT *I1, LoadOrStoreT *I2,
60 ScalarEvolution &SE, const DataLayout &DL) {
61 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
62 std::is_same<LoadOrStoreT, StoreInst>::value,
63 "Expected Load or Store!");
64 auto Diff = Utils::getPointerDiffInBytes(I1, I2, SE);
65 if (!Diff)
66 return false;
67 int ElmBytes = Utils::getNumBits(I1) / 8;
68 return *Diff == ElmBytes;
69 }
70
71 template <typename LoadOrStoreT>
73 const DataLayout &DL) {
74 static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
75 std::is_same<LoadOrStoreT, StoreInst>::value,
76 "Expected Load or Store!");
77 assert(isa<LoadOrStoreT>(Bndl[0]) && "Expected Load or Store!");
78 auto *LastLS = cast<LoadOrStoreT>(Bndl[0]);
79 for (Value *V : drop_begin(Bndl)) {
81 "Unimplemented: we only support StoreInst!");
82 auto *LS = cast<LoadOrStoreT>(V);
83 if (!VecUtils::areConsecutive(LastLS, LS, SE, DL))
84 return false;
85 LastLS = LS;
86 }
87 return true;
88 }
89
90 /// \Returns the number of vector lanes of \p Ty or 1 if not a vector.
91 /// NOTE: It asserts that \p Ty is a fixed vector type.
92 static unsigned getNumLanes(Type *Ty) {
93 assert(!isa<ScalableVectorType>(Ty) && "Expect scalar or fixed vector");
94 if (auto *FixedVecTy = dyn_cast<FixedVectorType>(Ty))
95 return FixedVecTy->getNumElements();
96 return 1u;
97 }
98
99 /// \Returns the expected vector lanes of \p V or 1 if not a vector.
100 /// NOTE: It asserts that \p V is a fixed vector.
101 static unsigned getNumLanes(Value *V) {
103 }
104
105 /// \Returns the total number of lanes across all values in \p Bndl.
106 static unsigned getNumLanes(ArrayRef<Value *> Bndl) {
107 unsigned Lanes = 0;
108 for (Value *V : Bndl)
109 Lanes += getNumLanes(V);
110 return Lanes;
111 }
112
113 /// \Returns <NumElts x ElemTy>.
114 /// It works for both scalar and vector \p ElemTy.
115 static Type *getWideType(Type *ElemTy, unsigned NumElts) {
116 if (ElemTy->isVectorTy()) {
117 auto *VecTy = cast<FixedVectorType>(ElemTy);
118 ElemTy = VecTy->getElementType();
119 NumElts = VecTy->getNumElements() * NumElts;
120 }
121 return FixedVectorType::get(ElemTy, NumElts);
122 }
123 /// \Returns the instruction in \p Instrs that is lowest in the BB. Expects
124 /// that all instructions are in the same BB.
126 Instruction *LowestI = Instrs.front();
127 for (auto *I : drop_begin(Instrs)) {
128 if (LowestI->comesBefore(I))
129 LowestI = I;
130 }
131 return LowestI;
132 }
133 /// \Returns the lowest instruction in \p Vals, or nullptr if no instructions
134 /// are found. Skips instructions not in \p BB.
136 // Find the first Instruction in Vals that is also in `BB`.
137 auto It = find_if(Vals, [BB](Value *V) {
138 return isa<Instruction>(V) && cast<Instruction>(V)->getParent() == BB;
139 });
140 // If we couldn't find an instruction return nullptr.
141 if (It == Vals.end())
142 return nullptr;
143 Instruction *FirstI = cast<Instruction>(*It);
144 // Now look for the lowest instruction in Vals starting from one position
145 // after FirstI.
146 Instruction *LowestI = FirstI;
147 for (auto *V : make_range(std::next(It), Vals.end())) {
148 auto *I = dyn_cast<Instruction>(V);
149 // Skip non-instructions.
150 if (I == nullptr)
151 continue;
152 // Skips instructions not in \p BB.
153 if (I->getParent() != BB)
154 continue;
155 // If `LowestI` comes before `I` then `I` is the new lowest.
156 if (LowestI->comesBefore(I))
157 LowestI = I;
158 }
159 return LowestI;
160 }
161
162 /// If \p I is not a PHI it returns it. Else it walks down the instruction
163 /// chain looking for the last PHI and returns it. \Returns nullptr if \p I is
164 /// nullptr.
166 Instruction *LastI = I;
167 while (I != nullptr && isa<PHINode>(I)) {
168 LastI = I;
169 I = I->getNextNode();
170 }
171 return LastI;
172 }
173
174 /// If all values in \p Bndl are of the same scalar type then return it,
175 /// otherwise return nullptr.
177 Value *V0 = Bndl[0];
178 Type *Ty0 = Utils::getExpectedType(V0);
179 Type *ScalarTy = VecUtils::getElementType(Ty0);
180 for (auto *V : drop_begin(Bndl)) {
182 Type *NScalarTy = VecUtils::getElementType(NTy);
183 if (NScalarTy != ScalarTy)
184 return nullptr;
185 }
186 return ScalarTy;
187 }
188
189 /// Similar to tryGetCommonScalarType() but will assert that there is a common
190 /// type. So this is faster in release builds as it won't iterate through the
191 /// values.
193 Value *V0 = Bndl[0];
194 Type *Ty0 = Utils::getExpectedType(V0);
195 Type *ScalarTy = VecUtils::getElementType(Ty0);
196 assert(tryGetCommonScalarType(Bndl) && "Expected common scalar type!");
197 return ScalarTy;
198 }
199 /// \Returns the first integer power of 2 that is <= Num.
200 LLVM_ABI static unsigned getFloorPowerOf2(unsigned Num);
201
202 /// Helper struct for `matchPack()`. Describes the instructions and operands
203 /// of a pack pattern.
204 struct PackPattern {
205 /// The insertelement instructions that form the pack pattern in bottom-up
206 /// order, i.e., the first instruction in `Instrs` is the bottom-most
207 /// InsertElement instruction of the pack pattern.
208 /// For example in this simple pack pattern:
209 /// %Pack0 = insertelement <2 x i8> poison, i8 %v0, i64 0
210 /// %Pack1 = insertelement <2 x i8> %Pack0, i8 %v1, i64 1
211 /// this is [ %Pack1, %Pack0 ].
213 /// The "external" operands of the pack pattern, i.e., the values that get
214 /// packed into a vector, skipping the ones in `Instrs`. The operands are in
215 /// bottom-up order, starting from the operands of the bottom-most insert.
216 /// So in our example this would be [ %v1, %v0 ].
218 };
219
220 /// If \p I is the last instruction of a pack pattern (i.e., an InsertElement
221 /// into a vector), then this function returns the instructions in the pack
222 /// and the operands in the pack, else returns nullopt.
223 /// Here is an example of a matched pattern:
224 /// %PackA0 = insertelement <2 x i8> poison, i8 %v0, i64 0
225 /// %PackA1 = insertelement <2 x i8> %PackA0, i8 %v1, i64 1
226 /// TODO: this currently detects only simple canonicalized patterns.
227 static std::optional<PackPattern> matchPack(Instruction *I) {
228 // TODO: Support vector pack patterns.
229 // TODO: Support out-of-order inserts.
230
231 // Early return if `I` is not an Insert.
233 return std::nullopt;
234 auto *BB0 = I->getParent();
235 // The pack contains as many instrs as the lanes of the bottom-most Insert
236 unsigned ExpectedNumInserts = VecUtils::getNumLanes(I);
237 assert(ExpectedNumInserts >= 2 && "Expected at least 2 inserts!");
239 Pack.Operands.resize(ExpectedNumInserts);
240 // Collect the inserts by walking up the use-def chain.
241 Instruction *InsertI = I;
242 for (auto ExpectedLane : reverse(seq<unsigned>(ExpectedNumInserts))) {
243 if (InsertI == nullptr)
244 return std::nullopt;
245 if (InsertI->getParent() != BB0)
246 return std::nullopt;
247 // Check the lane.
248 auto *LaneC = dyn_cast<ConstantInt>(InsertI->getOperand(2));
249 if (LaneC == nullptr || LaneC->getSExtValue() != ExpectedLane)
250 return std::nullopt;
251 Pack.Instrs.push_back(InsertI);
252 Pack.Operands[ExpectedLane] = InsertI->getOperand(1);
253
254 Value *Op = InsertI->getOperand(0);
255 if (ExpectedLane == 0) {
256 // Check the topmost insert. The operand should be a Poison.
257 if (!isa<PoisonValue>(Op))
258 return std::nullopt;
259 } else {
261 }
262 }
263 return Pack;
264 }
265
266 /// Emits the necessary instruction sequence to extract element of type \p
267 /// ExtrTy at \p Lane from \p FromVec. Emits instructions before \p WhereIt.
268 /// Returns the extracted value.
269 /// Note: This handles both vectors and scalars. In the vector case it
270 /// extracts an N-wide element (with N dictated by \p ExtrTy).
271 static Value *unpack(Value *FromVec, Type *ExtrTy, unsigned Lane,
272 BasicBlock::iterator WhereIt) {
273 assert(isa<FixedVectorType>(FromVec->getType()) && "Expected vector!");
274 auto &Ctx = FromVec->getContext();
275 if (!ExtrTy->isVectorTy()) {
276 // For scalar elements we emit a single ExtractElementInst.
277 assert(Lane <
278 cast<FixedVectorType>(FromVec->getType())->getNumElements() &&
279 "Out of bounds!");
280 assert(ExtrTy ==
281 cast<FixedVectorType>(FromVec->getType())->getElementType() &&
282 "Expected same element type!");
283 Constant *ExtractLaneC =
285 // Note: This may be folded into a Constant if FromVec is a Constant.
286 return ExtractElementInst::create(FromVec, ExtractLaneC, WhereIt, Ctx,
287 "Unpack");
288 }
289 // For vector elements we emit a shuffle.
290 // For example, extracting lanes 2 and 3 of a <4 x i32> vector %vec:
291 // shufflevector <4 x i32> %vec, <4 x i32> poison, <2 x i32> <i32 2, i32 3>
292 auto *VecTy = cast<FixedVectorType>(FromVec->getType());
293 auto *ExtrVecTy = cast<FixedVectorType>(ExtrTy);
294 assert(ExtrVecTy->getElementType() == VecTy->getElementType() &&
295 "Expected same element type!");
297 for (unsigned Idx = 0, E = ExtrVecTy->getNumElements(); Idx != E; ++Idx) {
298 int MaskLane = Lane + Idx;
299 assert((unsigned)MaskLane <
300 cast<FixedVectorType>(FromVec->getType())->getNumElements() &&
301 "Out of bounds!");
302 Mask.push_back(MaskLane);
303 }
304 return ShuffleVectorInst::create(FromVec, PoisonValue::get(VecTy), Mask,
305 WhereIt, Ctx, "Unpack");
306 }
307
308 /// Iterate over all lanes and Value pairs.
309 // For example, given a range: {i32 %v0, <2 x i32> %v1, i32 %v2} we get:
310 // Lane Elm
311 // 0 %v0
312 // 1 %v1
313 // 3 %v2
314 template <typename RangeIteratorT> class LaneValueEnumerator {
315 /// Points to current element.
316 RangeIteratorT It;
317 RangeIteratorT ItE;
318 /// Accumulator of lanes.
319 unsigned Lane;
320
321 public:
322 // Note that We can start counting from a non-zero BeginLane, though the
323 // user must make sure it corresponds to the correct lane matching Begin.
324 LaneValueEnumerator(RangeIteratorT Begin, RangeIteratorT End,
325 unsigned BeginLane)
326 : It(Begin), ItE(End), Lane(BeginLane) {}
327 using iterator_catecotry = std::input_iterator_tag;
328 // NOTE: dereference returns by value instead of by reference.
329 using value_type = std::pair<unsigned, Value *>;
330 using difference_type = std::ptrdiff_t;
331 using pointer = std::pair<unsigned, Value *> *;
332 using reference = std::pair<unsigned, Value *> &;
334 assert(It != ItE && "Already at end!");
335 auto *Ty = Utils::getExpectedType(*It);
336 if (auto *VecTy = dyn_cast<FixedVectorType>(Ty)) {
337 Lane += VecTy->getNumElements();
338 } else {
339 assert(!isa<VectorType>(Ty) && "Expected scalar type!");
340 Lane += 1;
341 }
342 ++It;
343 return *this;
344 }
345 value_type operator*() const { return {Lane, *It}; }
347 return It == Other.It;
348 }
350 return !(*this == Other);
351 }
352 };
353
354 /// Helper for creating LaneValueEnumerator ranges. Can be used in for loops
355 /// like: `for (auto [Lane, V] : enumerateLanes(Range))`
356 template <typename ValueContainerT>
357 static auto enumerateLanes(const ValueContainerT &Range) {
358 auto Begin = LaneValueEnumerator<decltype(Range.begin())>(Range.begin(),
359 Range.end(), 0);
360 auto End = LaneValueEnumerator<decltype(Range.begin())>(Range.end(),
361 Range.end(), 0);
362 return make_range(Begin, End);
363 }
364
365#ifndef NDEBUG
366 /// Helper dump function for debugging.
367 LLVM_DUMP_METHOD static void dump(ArrayRef<Value *> Bndl);
369#endif // NDEBUG
370};
371
372} // namespace sandboxir
373
374} // namespace llvm
375
376#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_VECUTILS_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#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:661
#define I(x, y, z)
Definition MD5.cpp:57
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
front - Get the first element.
Definition ArrayRef.h:145
iterator end() const
Definition ArrayRef.h:131
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
The main scalar evolution driver.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM Value Representation.
Definition Value.h:75
static LLVM_ABI ConstantInt * getSigned(IntegerType *Ty, int64_t V)
Return a ConstantInt with the specified value for the specified type.
Definition Constant.cpp:56
static LLVM_ABI Value * create(Value *Vec, Value *Idx, InsertPosition Pos, Context &Ctx, const Twine &Name="")
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...
LLVM_ABI BasicBlock * getParent() const
\Returns the BasicBlock containing this Instruction, or null if it is detached.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Definition Constant.cpp:259
static LLVM_ABI Value * create(Value *V1, Value *V2, Value *Mask, InsertPosition Pos, Context &Ctx, const Twine &Name="")
Just like llvm::Type these are immutable, unique, never get freed and can only be created via static ...
Definition Type.h:47
static LLVM_ABI IntegerType * getInt32Ty(Context &Ctx)
Definition Type.cpp:21
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:68
LLVM_ABI Type * getType() const
Definition Value.cpp:46
Context & getContext() const
Definition Value.h:266
Iterate over all lanes and Value pairs.
Definition VecUtils.h:314
bool operator==(const LaneValueEnumerator &Other) const
Definition VecUtils.h:346
bool operator!=(const LaneValueEnumerator &Other) const
Definition VecUtils.h:349
std::pair< unsigned, Value * > value_type
Definition VecUtils.h:329
std::pair< unsigned, Value * > & reference
Definition VecUtils.h:332
LaneValueEnumerator(RangeIteratorT Begin, RangeIteratorT End, unsigned BeginLane)
Definition VecUtils.h:324
std::pair< unsigned, Value * > * pointer
Definition VecUtils.h:331
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:176
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition VecUtils.h:125
static Type * getCommonScalarType(ArrayRef< Value * > Bndl)
Similar to tryGetCommonScalarType() but will assert that there is a common type.
Definition VecUtils.h:192
static int getNumElements(Type *Ty)
\Returns the number of elements in Ty.
Definition VecUtils.h:47
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:227
static Instruction * getLastPHIOrSelf(Instruction *I)
If I is not a PHI it returns it.
Definition VecUtils.h:165
static unsigned getNumLanes(Type *Ty)
\Returns the number of vector lanes of Ty or 1 if not a vector.
Definition VecUtils.h:92
static Instruction * getLowest(ArrayRef< Value * > Vals, BasicBlock *BB)
\Returns the lowest instruction in Vals, or nullptr if no instructions are found.
Definition VecUtils.h:135
static Value * unpack(Value *FromVec, Type *ExtrTy, unsigned Lane, BasicBlock::iterator WhereIt)
Emits the necessary instruction sequence to extract element of type ExtrTy at Lane from FromVec.
Definition VecUtils.h:271
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:115
static auto enumerateLanes(const ValueContainerT &Range)
Helper for creating LaneValueEnumerator ranges.
Definition VecUtils.h:357
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:59
static Type * getElementType(Type *Ty)
Returns Ty if scalar or its element type if vector.
Definition VecUtils.h:52
static bool areConsecutive(ArrayRef< Value * > &Bndl, ScalarEvolution &SE, const DataLayout &DL)
Definition VecUtils.h:72
static unsigned getNumLanes(Value *V)
\Returns the expected vector lanes of V or 1 if not a vector.
Definition VecUtils.h:101
static unsigned getNumLanes(ArrayRef< Value * > Bndl)
\Returns the total number of lanes across all values in Bndl.
Definition VecUtils.h:106
static LLVM_ABI unsigned getFloorPowerOf2(unsigned Num)
\Returns the first integer power of 2 that is <= Num.
Definition VecUtils.cpp:13
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ Other
Any other memory.
Definition ModRef.h:68
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
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:1772
auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:305
hash_code hash_combine_range(InputIteratorT first, InputIteratorT last)
Compute a hash_code for a sequence of values.
Definition Hashing.h:466
static bool isEqual(const SmallVector< sandboxir::Value * > &Vec1, const SmallVector< sandboxir::Value * > &Vec2)
Definition VecUtils.h:34
static SmallVector< sandboxir::Value * > getEmptyKey()
Definition VecUtils.h:25
static unsigned getHashValue(const SmallVector< sandboxir::Value * > &Vec)
Definition VecUtils.h:31
static SmallVector< sandboxir::Value * > getTombstoneKey()
Definition VecUtils.h:28
An information struct used to provide DenseMap with the various necessary components for a given valu...
Helper struct for matchPack().
Definition VecUtils.h:204
SmallVector< Value * > Operands
The "external" operands of the pack pattern, i.e., the values that get packed into a vector,...
Definition VecUtils.h:217
SmallVector< Instruction * > Instrs
The insertelement instructions that form the pack pattern in bottom-up order, i.e....
Definition VecUtils.h:212