LLVM 24.0.0git
SeedCollector.cpp
Go to the documentation of this file.
1//===- SeedCollector.cpp -------------------------------------------------===//
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
10#include "../VectorizeOptions.h"
13#include "llvm/IR/Type.h"
17#include "llvm/Support/Debug.h"
18
19using namespace llvm;
20namespace llvm::sandboxir {
21
23 unsigned MaxVecRegBits,
24 bool ForcePowerOf2) {
25 // Use uint32_t here for compatibility with IsPowerOf2_32
26
27 // BitCount tracks the size of the working slice. From that we can tell
28 // when the working slice's size is a power-of-two and when it exceeds
29 // the legal size in MaxVecBits.
30 uint32_t BitCount = 0;
31 uint32_t NumElements = 0;
32 // Tracks the most recent slice where NumElements gave a power-of-2 BitCount
33 uint32_t NumElementsPowerOfTwo = 0;
34 uint32_t BitCountPowerOfTwo = 0;
35 // Can't start a slice with a used instruction.
36 assert(!isUsed(StartIdx) && "Expected unused at StartIdx");
37 for (Instruction *S : drop_begin(Seeds, StartIdx)) {
38 // Stop if this instruction is used. This needs to be done before
39 // getNumBits() because a "used" instruction may have been erased.
40 if (isUsed(StartIdx + NumElements))
41 break;
42 uint32_t InstBits = Utils::getNumBits(S);
43 // Stop if adding it puts the slice over the limit.
44 if (BitCount + InstBits > MaxVecRegBits)
45 break;
46 NumElements++;
47 BitCount += InstBits;
48 if (ForcePowerOf2 && isPowerOf2_32(BitCount)) {
49 NumElementsPowerOfTwo = NumElements;
50 BitCountPowerOfTwo = BitCount;
51 }
52 }
53 if (ForcePowerOf2) {
54 NumElements = NumElementsPowerOfTwo;
55 BitCount = BitCountPowerOfTwo;
56 }
57
58 // Return any non-empty slice
59 if (NumElements > 1) {
60 assert((!ForcePowerOf2 || isPowerOf2_32(BitCount)) &&
61 "Must be a power of two");
62 return ArrayRef<Instruction *>(&Seeds[StartIdx], NumElements);
63 }
64 return {};
65}
66
67template <typename LoadOrStoreT>
68SeedContainer::KeyT SeedContainer::getKey(LoadOrStoreT *LSI,
69 bool AllowDiffTypes) const {
70 assert((isa<LoadInst>(LSI) || isa<StoreInst>(LSI)) &&
71 "Expected Load or Store!");
73 Instruction::Opcode Op = LSI->getOpcode();
74 Type *Ty;
75 if (AllowDiffTypes) {
76 Ty = nullptr;
77 } else {
78 Ty = Utils::getExpectedType(LSI);
79 if (auto *VTy = dyn_cast<VectorType>(Ty))
80 Ty = VTy->getElementType();
81 }
82 return {Ptr, Ty, Op};
83}
84
85// Explicit instantiations
86template SeedContainer::KeyT
87SeedContainer::getKey<LoadInst>(LoadInst *LSI, bool AllowDiffTypes) const;
88template SeedContainer::KeyT
89SeedContainer::getKey<StoreInst>(StoreInst *LSI, bool AllowDiffTypes) const;
90
92 assert((isa<LoadInst>(I) || isa<StoreInst>(I)) && "Expected Load or Store!");
93 auto It = SeedLookupMap.find(I);
94 if (It == SeedLookupMap.end())
95 return false;
96 SeedBundle *Bndl = It->second;
97 Bndl->setUsed(I);
98 return true;
99}
100
102 const VectorizeOptions &Opts = getVectorizeOptions(SE.getContext());
103 BundleSizeLimit = Opts.sbvec_seed_bundle_size_limit;
104}
105
106template <typename LoadOrStoreT>
107void SeedContainer::insert(LoadOrStoreT *LSI, bool AllowDiffTypes) {
108 // Find the bundle containing seeds for this symbol and type-of-access.
109 auto &BundleVec = Bundles[getKey(LSI, AllowDiffTypes)];
110 // Fill this vector of bundles front to back so that only the last bundle in
111 // the vector may have available space. This avoids iteration to find one with
112 // space.
113 if (BundleVec.empty() || BundleVec.back()->size() == BundleSizeLimit) {
114 BundleVec.emplace_back(std::make_unique<MemSeedBundle<LoadOrStoreT>>(LSI));
115 } else {
116 bool Inserted = BundleVec.back()->tryInsert(LSI, SE);
117 if (!Inserted)
118 BundleVec.emplace_back(
119 std::make_unique<MemSeedBundle<LoadOrStoreT>>(LSI));
120 }
121
122 SeedLookupMap[LSI] = BundleVec.back().get();
123}
124
125// Explicit instantiations
127 bool);
129 bool);
130
131#ifndef NDEBUG
133 for (const auto &Pair : Bundles) {
134 auto [I, Ty, Opc] = Pair.first;
135 const auto &SeedsVec = Pair.second;
136 std::string RefType = dyn_cast<LoadInst>(I) ? "Load"
137 : dyn_cast<StoreInst>(I) ? "Store"
138 : "Other";
139 OS << "[Inst=" << *I << " Ty=" << Ty << " " << RefType << "]\n";
140 for (const auto &SeedPtr : SeedsVec) {
141 SeedPtr->dump(OS);
142 OS << "\n";
143 }
144 }
145 OS << "\n";
146}
147
149#endif // NDEBUG
150
151template <typename LoadOrStoreT> static bool isValidMemSeed(LoadOrStoreT *LSI) {
152 if (!LSI->isSimple())
153 return false;
154 auto *Ty = Utils::getExpectedType(LSI);
155 // Omit types that are architecturally unvectorizable
156 if (Ty->isX86_FP80Ty() || Ty->isPPC_FP128Ty())
157 return false;
158 // Omit vector types without compile-time-known lane counts
160 return false;
161 if (auto *VTy = dyn_cast<FixedVectorType>(Ty))
162 return VectorType::isValidElementType(VTy->getElementType());
164}
165
168
170 bool CollectStores, bool CollectLoads,
171 bool AllowDiffTypes)
172 : StoreSeeds(SE), LoadSeeds(SE), Ctx(BB->getContext()) {
173
174 if (!CollectStores && !CollectLoads)
175 return;
176
177 EraseCallbackID = Ctx.registerEraseInstrCallback([this](Instruction *I) {
178 if (auto SI = dyn_cast<StoreInst>(I))
179 StoreSeeds.erase(SI);
180 else if (auto LI = dyn_cast<LoadInst>(I))
181 LoadSeeds.erase(LI);
182 });
183
184 // Actually collect the seeds.
185 const VectorizeOptions &Opts = getVectorizeOptions(Ctx);
186 for (auto &I : *BB) {
188 if (CollectStores && isValidMemSeed(SI))
189 StoreSeeds.insert(SI, AllowDiffTypes);
190 if (LoadInst *LI = dyn_cast<LoadInst>(&I))
191 if (CollectLoads && isValidMemSeed(LI))
192 LoadSeeds.insert(LI, AllowDiffTypes);
193 // Cap compilation time.
194 if (totalNumSeedGroups() > Opts.sbvec_seed_groups_limit)
195 break;
196 }
197}
198
200 Ctx.unregisterEraseInstrCallback(EraseCallbackID);
201}
202
203#ifndef NDEBUG
205 OS << "=== StoreSeeds ===\n";
206 StoreSeeds.print(OS);
207 OS << "=== LoadSeeds ===\n";
208 LoadSeeds.print(OS);
209}
210
211void SeedCollector::dump() const { print(dbgs()); }
212#endif
213
214} // namespace llvm::sandboxir
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:690
#define LLVM_EXPORT_TEMPLATE
Definition Compiler.h:213
#define I(x, y, z)
Definition MD5.cpp:57
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
The main scalar evolution driver.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
This is a simple bottom-up (top-down) vectorizer Region pass.
Definition BundleVec.h:43
A sandboxir::User with operands, opcode and linked with previous/next instructions in an instruction ...
Definition Instruction.h:43
Specialization of SeedBundle for memory access instructions.
A set of candidate Instructions for vectorizing together.
bool isUsed(unsigned Element) const
\Returns whether or not Element has been used.
SmallVector< Instruction * > Seeds
LLVM_ABI ArrayRef< Instruction * > getSlice(unsigned StartIdx, unsigned MaxVecRegBits, bool ForcePowOf2)
\Returns a slice of seed elements, starting at the element StartIdx, with a total size <= MaxVecRegBi...
void setUsed(Instruction *I)
Marks instruction I "used" within the bundle.
LLVM_ABI SeedCollector(BasicBlock *BB, ScalarEvolution &SE, bool CollectStores, bool CollectLoads, bool AllowDiffTypes=false)
void print(raw_ostream &OS) const
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &OS) const
void insert(LoadOrStoreT *LSI, bool AllowDiffTypes)
LLVM_ABI SeedContainer(ScalarEvolution &SE)
LLVM_DUMP_METHOD void dump() const
LLVM_ABI bool erase(Instruction *I)
Just like llvm::Type these are immutable, unique, never get freed and can only be created via static ...
Definition Type.h:49
static unsigned getNumBits(Type *Ty, const DataLayout &DL)
\Returns the number of bits of Ty.
Definition Utils.h:68
static Type * getExpectedType(const Value *V)
\Returns the expected type of Value V.
Definition Utils.h:34
static Value * getMemInstructionBase(const LoadOrStoreT *LSI)
\Returns the base Value for load or store instruction LSI.
Definition Utils.h:59
A SandboxIR Value has users. This is the base class.
Definition Value.h:72
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Definition Type.cpp:829
Context & getContext() const
Definition BasicBlock.h:99
template bool isValidMemSeed< StoreInst >(StoreInst *LSI)
static bool isValidMemSeed(LoadOrStoreT *LSI)
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
template bool isValidMemSeed< LoadInst >(LoadInst *LSI)
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
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
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
DWARFExpression::Operation Op
const VectorizeOptions & getVectorizeOptions(const LLVMContext &C)