LLVM 22.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
12#include "llvm/IR/Type.h"
16#include "llvm/Support/Debug.h"
17
18using namespace llvm;
19namespace llvm::sandboxir {
20
22 "sbvec-seed-bundle-size-limit", cl::init(32), cl::Hidden,
23 cl::desc("Limit the size of the seed bundle to cap compilation time."));
24
26 "sbvec-seed-groups-limit", cl::init(256), cl::Hidden,
27 cl::desc("Limit the number of collected seeds groups in a BB to "
28 "cap compilation time."));
29
31 unsigned MaxVecRegBits,
32 bool ForcePowerOf2) {
33 // Use uint32_t here for compatibility with IsPowerOf2_32
34
35 // BitCount tracks the size of the working slice. From that we can tell
36 // when the working slice's size is a power-of-two and when it exceeds
37 // the legal size in MaxVecBits.
38 uint32_t BitCount = 0;
39 uint32_t NumElements = 0;
40 // Tracks the most recent slice where NumElements gave a power-of-2 BitCount
41 uint32_t NumElementsPowerOfTwo = 0;
42 uint32_t BitCountPowerOfTwo = 0;
43 // Can't start a slice with a used instruction.
44 assert(!isUsed(StartIdx) && "Expected unused at StartIdx");
45 for (Instruction *S : drop_begin(Seeds, StartIdx)) {
46 // Stop if this instruction is used. This needs to be done before
47 // getNumBits() because a "used" instruction may have been erased.
48 if (isUsed(StartIdx + NumElements))
49 break;
50 uint32_t InstBits = Utils::getNumBits(S);
51 // Stop if adding it puts the slice over the limit.
52 if (BitCount + InstBits > MaxVecRegBits)
53 break;
54 NumElements++;
55 BitCount += InstBits;
56 if (ForcePowerOf2 && isPowerOf2_32(BitCount)) {
57 NumElementsPowerOfTwo = NumElements;
58 BitCountPowerOfTwo = BitCount;
59 }
60 }
61 if (ForcePowerOf2) {
62 NumElements = NumElementsPowerOfTwo;
63 BitCount = BitCountPowerOfTwo;
64 }
65
66 // Return any non-empty slice
67 if (NumElements > 1) {
68 assert((!ForcePowerOf2 || isPowerOf2_32(BitCount)) &&
69 "Must be a power of two");
70 return ArrayRef<Instruction *>(&Seeds[StartIdx], NumElements);
71 }
72 return {};
73}
74
75template <typename LoadOrStoreT>
76SeedContainer::KeyT SeedContainer::getKey(LoadOrStoreT *LSI,
77 bool AllowDiffTypes) const {
78 assert((isa<LoadInst>(LSI) || isa<StoreInst>(LSI)) &&
79 "Expected Load or Store!");
81 Instruction::Opcode Op = LSI->getOpcode();
82 Type *Ty;
83 if (AllowDiffTypes) {
84 Ty = nullptr;
85 } else {
86 Ty = Utils::getExpectedType(LSI);
87 if (auto *VTy = dyn_cast<VectorType>(Ty))
88 Ty = VTy->getElementType();
89 }
90 return {Ptr, Ty, Op};
91}
92
93// Explicit instantiations
94template SeedContainer::KeyT
95SeedContainer::getKey<LoadInst>(LoadInst *LSI, bool AllowDiffTypes) const;
96template SeedContainer::KeyT
97SeedContainer::getKey<StoreInst>(StoreInst *LSI, bool AllowDiffTypes) const;
98
100 assert((isa<LoadInst>(I) || isa<StoreInst>(I)) && "Expected Load or Store!");
101 auto It = SeedLookupMap.find(I);
102 if (It == SeedLookupMap.end())
103 return false;
104 SeedBundle *Bndl = It->second;
105 Bndl->setUsed(I);
106 return true;
107}
108
109template <typename LoadOrStoreT>
110void SeedContainer::insert(LoadOrStoreT *LSI, bool AllowDiffTypes) {
111 // Find the bundle containing seeds for this symbol and type-of-access.
112 auto &BundleVec = Bundles[getKey(LSI, AllowDiffTypes)];
113 // Fill this vector of bundles front to back so that only the last bundle in
114 // the vector may have available space. This avoids iteration to find one with
115 // space.
116 if (BundleVec.empty() || BundleVec.back()->size() == SeedBundleSizeLimit)
117 BundleVec.emplace_back(std::make_unique<MemSeedBundle<LoadOrStoreT>>(LSI));
118 else
119 BundleVec.back()->insert(LSI, SE);
120
121 SeedLookupMap[LSI] = BundleVec.back().get();
122}
123
124// Explicit instantiations
125template LLVM_EXPORT_TEMPLATE void SeedContainer::insert<LoadInst>(LoadInst *,
126 bool);
127template LLVM_EXPORT_TEMPLATE void SeedContainer::insert<StoreInst>(StoreInst *,
128 bool);
129
130#ifndef NDEBUG
132 for (const auto &Pair : Bundles) {
133 auto [I, Ty, Opc] = Pair.first;
134 const auto &SeedsVec = Pair.second;
135 std::string RefType = dyn_cast<LoadInst>(I) ? "Load"
136 : dyn_cast<StoreInst>(I) ? "Store"
137 : "Other";
138 OS << "[Inst=" << *I << " Ty=" << Ty << " " << RefType << "]\n";
139 for (const auto &SeedPtr : SeedsVec) {
140 SeedPtr->dump(OS);
141 OS << "\n";
142 }
143 }
144 OS << "\n";
145}
146
148#endif // NDEBUG
149
150template <typename LoadOrStoreT> static bool isValidMemSeed(LoadOrStoreT *LSI) {
151 if (!LSI->isSimple())
152 return false;
153 auto *Ty = Utils::getExpectedType(LSI);
154 // Omit types that are architecturally unvectorizable
155 if (Ty->isX86_FP80Ty() || Ty->isPPC_FP128Ty())
156 return false;
157 // Omit vector types without compile-time-known lane counts
158 if (isa<ScalableVectorType>(Ty))
159 return false;
160 if (auto *VTy = dyn_cast<FixedVectorType>(Ty))
161 return VectorType::isValidElementType(VTy->getElementType());
163}
164
167
169 bool CollectStores, bool CollectLoads,
170 bool AllowDiffTypes)
171 : StoreSeeds(SE), LoadSeeds(SE), Ctx(BB->getContext()) {
172
173 if (!CollectStores && !CollectLoads)
174 return;
175
176 EraseCallbackID = Ctx.registerEraseInstrCallback([this](Instruction *I) {
177 if (auto SI = dyn_cast<StoreInst>(I))
178 StoreSeeds.erase(SI);
179 else if (auto LI = dyn_cast<LoadInst>(I))
180 LoadSeeds.erase(LI);
181 });
182
183 // Actually collect the seeds.
184 for (auto &I : *BB) {
185 if (StoreInst *SI = dyn_cast<StoreInst>(&I))
186 if (CollectStores && isValidMemSeed(SI))
187 StoreSeeds.insert(SI, AllowDiffTypes);
188 if (LoadInst *LI = dyn_cast<LoadInst>(&I))
189 if (CollectLoads && isValidMemSeed(LI))
190 LoadSeeds.insert(LI, AllowDiffTypes);
191 // Cap compilation time.
192 if (totalNumSeedGroups() > SeedGroupsLimit)
193 break;
194 }
195}
196
198 Ctx.unregisterEraseInstrCallback(EraseCallbackID);
199}
200
201#ifndef NDEBUG
203 OS << "=== StoreSeeds ===\n";
204 StoreSeeds.print(OS);
205 OS << "=== LoadSeeds ===\n";
206 LoadSeeds.print(OS);
207}
208
209void SeedCollector::dump() const { print(dbgs()); }
210#endif
211
212} // 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:638
#define LLVM_EXPORT_TEMPLATE
Definition: Compiler.h:215
#define I(x, y, z)
Definition: MD5.cpp:58
if(PassOpts->AAPipeline)
raw_pwrite_stream & OS
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
This class represents an Operation in the Expression.
An instruction for reading from memory.
Definition: Instructions.h:180
std::pair< KeyT, ValueT > & back()
Definition: MapVector.h:81
The main scalar evolution driver.
An instruction for storing to memory.
Definition: Instructions.h:296
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
Contains a list of sandboxir::Instruction's.
Definition: BasicBlock.h:68
LLVM_ABI void unregisterEraseInstrCallback(CallbackID ID)
Definition: Context.cpp:735
LLVM_ABI CallbackID registerEraseInstrCallback(EraseInstrCallback CB)
Register a callback that gets called when a SandboxIR instruction is about to be removed from its par...
Definition: Context.cpp:728
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.
Definition: SeedCollector.h:28
bool isUsed(unsigned Element) const
\Returns whether or not Element has been used.
Definition: SeedCollector.h:89
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.
Definition: SeedCollector.h:70
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_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:47
bool isX86_FP80Ty() const
Return true if this is x86 long double.
Definition: Type.h:115
bool isPPC_FP128Ty() const
Return true if this is powerpc long double.
Definition: Type.h:121
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
static Value * getMemInstructionBase(const LoadOrStoreT *LSI)
\Returns the base Value for load or store instruction LSI.
Definition: Utils.h:57
A SandboxIR Value has users. This is the base class.
Definition: Value.h:66
static LLVM_ABI bool isValidElementType(Type *ElemTy)
Definition: Type.cpp:790
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
template bool isValidMemSeed< StoreInst >(StoreInst *LSI)
static bool isValidMemSeed(LoadOrStoreT *LSI)
template bool isValidMemSeed< LoadInst >(LoadInst *LSI)
static cl::opt< unsigned > SeedGroupsLimit("sbvec-seed-groups-limit", cl::init(256), cl::Hidden, cl::desc("Limit the number of collected seeds groups in a BB to " "cap compilation time."))
static cl::opt< unsigned > SeedBundleSizeLimit("sbvec-seed-bundle-size-limit", cl::init(32), cl::Hidden, cl::desc("Limit the size of the seed bundle to cap compilation time."))
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
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition: MathExtras.h:288
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207