23#define DEBUG_TYPE "llvm-mca"
30 NextInSequenceMask &= (CandidateMask | (CandidateMask - 1));
36 uint64_t CandidateMask = ReadyMask & NextInSequenceMask;
38 return selectImpl(CandidateMask, NextInSequenceMask);
40 NextInSequenceMask = ResourceUnitMask ^ RemovedFromNextInSequence;
41 RemovedFromNextInSequence = 0;
42 CandidateMask = ReadyMask & NextInSequenceMask;
44 return selectImpl(CandidateMask, NextInSequenceMask);
46 NextInSequenceMask = ResourceUnitMask;
47 CandidateMask = ReadyMask & NextInSequenceMask;
48 return selectImpl(CandidateMask, NextInSequenceMask);
52 if (Mask > NextInSequenceMask) {
53 RemovedFromNextInSequence |= Mask;
57 NextInSequenceMask &= (~Mask);
58 if (NextInSequenceMask)
61 NextInSequenceMask = ResourceUnitMask ^ RemovedFromNextInSequence;
62 RemovedFromNextInSequence = 0;
69 return (1ULL << NumUnits) - 1;
74 : ProcResourceDescIndex(Index), ResourceMask(Mask),
77 BufferSize(
Desc.BufferSize) {
78 ReadyMask = ResourceSizeMask;
79 AvailableSlots = BufferSize == -1 ? 0U :
static_cast<unsigned>(BufferSize);
83bool ResourceState::isReady(
unsigned NumUnits)
const {
84 return (!isReserved() || isADispatchHazard()) &&
89 if (isADispatchHazard() && isReserved())
91 if (!isBuffered() || AvailableSlots)
97void ResourceState::dump()
const {
99 <<
", SZMASK=" <<
format_hex(ResourceSizeMask, 16)
101 <<
", BufferSize=" << BufferSize
102 <<
", AvailableSlots=" << AvailableSlots
107static std::unique_ptr<ResourceStrategy>
109 if (RS.isAResourceGroup() || RS.getNumUnits() > 1)
110 return std::make_unique<DefaultResourceStrategy>(RS.getReadyMask());
111 return std::unique_ptr<ResourceStrategy>(
nullptr);
115 : Resources(
SM.getNumProcResourceKinds() - 1),
116 Strategies(
SM.getNumProcResourceKinds() - 1),
117 Resource2Groups(
SM.getNumProcResourceKinds() - 1, 0),
118 ProcResID2Mask(
SM.getNumProcResourceKinds(), 0),
119 ResIndex2ProcResID(
SM.getNumProcResourceKinds() - 1, 0),
120 ProcResUnitMask(0), ReservedResourceGroups(0), AvailableBuffers(~0ULL),
125 for (
unsigned I = 1,
E =
SM.getNumProcResourceKinds();
I <
E; ++
I) {
127 ResIndex2ProcResID[Index] =
I;
130 for (
unsigned I = 1,
E =
SM.getNumProcResourceKinds();
I <
E; ++
I) {
134 std::make_unique<ResourceState>(*
SM.getProcResource(
I),
I, Mask);
140 dbgs() <<
"\nProcessor resources:\n";
143 const MCProcResourceDesc &InvalidUnit = *
SM.getProcResource(0);
145 << InvalidUnit.Name <<
"\n";
146 for (
unsigned I = 0,
E = Resources.size();
I <
E; ++
I) {
148 const unsigned ProcResID =
RS.getProcResourceID();
149 const MCProcResourceDesc &
Desc = *
SM.getProcResource(ProcResID);
151 <<
" - " <<
format_hex(
RS.getResourceMask(), 16) <<
" - "
152 <<
Desc.Name <<
" (BufferSize=" <<
RS.getBufferSize() <<
")\n";
156 for (
unsigned I = 1,
E =
SM.getNumProcResourceKinds();
I <
E; ++
I) {
157 uint64_t
Mask = ProcResID2Mask[
I];
160 if (!
RS.isAResourceGroup()) {
161 ProcResUnitMask |=
Mask;
165 uint64_t GroupMaskIdx = 1ULL <<
Index;
166 Mask -= GroupMaskIdx;
171 Resource2Groups[IndexUnit] |= GroupMaskIdx;
176 AvailableProcResUnits = ProcResUnitMask;
179void ResourceManager::setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,
180 uint64_t ResourceMask) {
182 assert(Index < Resources.size() &&
"Invalid processor resource index!");
183 assert(S &&
"Unexpected null strategy in input!");
184 Strategies[
Index] = std::move(S);
187unsigned ResourceManager::resolveResourceMask(uint64_t Mask)
const {
191unsigned ResourceManager::getNumUnits(uint64_t ResourceID)
const {
198ResourceRef ResourceManager::selectPipe(uint64_t ResourceID) {
200 assert(Index < Resources.size() &&
"Invalid resource use!");
201 ResourceState &
RS = *Resources[
Index];
202 assert(
RS.isReady() &&
"No available units to select!");
206 if (!
RS.isAResourceGroup() &&
RS.getNumUnits() == 1)
207 return std::make_pair(ResourceID,
RS.getReadyMask());
209 uint64_t SubResourceID = Strategies[
Index]->select(
RS.getReadyMask());
210 if (
RS.isAResourceGroup())
211 return selectPipe(SubResourceID);
212 return std::make_pair(ResourceID, SubResourceID);
215void ResourceManager::use(
const ResourceRef &RR) {
218 ResourceState &
RS = *Resources[RSID];
219 RS.markSubResourceAsUsed(RR.second);
222 if (
RS.getNumUnits() > 1)
223 Strategies[RSID]->used(RR.second);
230 AvailableProcResUnits ^= RR.first;
233 uint64_t
Users = Resource2Groups[RSID];
237 ResourceState &CurrentUser = *Resources[GroupIndex];
238 CurrentUser.markSubResourceAsUsed(RR.first);
239 Strategies[GroupIndex]->used(RR.first);
245void ResourceManager::release(
const ResourceRef &RR) {
247 ResourceState &
RS = *Resources[RSID];
248 bool WasFullyUsed = !
RS.isReady();
249 RS.releaseSubResource(RR.second);
253 AvailableProcResUnits ^= RR.first;
256 uint64_t
Users = Resource2Groups[RSID];
259 ResourceState &CurrentUser = *Resources[GroupIndex];
260 CurrentUser.releaseSubResource(RR.first);
266ResourceManager::canBeDispatched(uint64_t ConsumedBuffers)
const {
267 if (ConsumedBuffers & ReservedBuffers)
268 return ResourceStateEvent::RS_RESERVED;
269 if (ConsumedBuffers & (~AvailableBuffers))
270 return ResourceStateEvent::RS_BUFFER_UNAVAILABLE;
271 return ResourceStateEvent::RS_BUFFER_AVAILABLE;
274void ResourceManager::reserveBuffers(uint64_t ConsumedBuffers) {
275 while (ConsumedBuffers) {
276 uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
278 ConsumedBuffers ^= CurrentBuffer;
279 assert(
RS.isBufferAvailable() == ResourceStateEvent::RS_BUFFER_AVAILABLE);
280 if (!
RS.reserveBuffer())
281 AvailableBuffers ^= CurrentBuffer;
282 if (
RS.isADispatchHazard()) {
286 ReservedBuffers ^= CurrentBuffer;
291void ResourceManager::releaseBuffers(uint64_t ConsumedBuffers) {
292 AvailableBuffers |= ConsumedBuffers;
293 while (ConsumedBuffers) {
294 uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
296 ConsumedBuffers ^= CurrentBuffer;
303uint64_t ResourceManager::checkAvailability(
const InstrDesc &
Desc)
const {
304 uint64_t BusyResourceMask = 0;
305 uint64_t ConsumedResourceMask = 0;
306 DenseMap<uint64_t, unsigned> AvailableUnits;
308 for (
const std::pair<uint64_t, ResourceUsage> &
E :
Desc.Resources) {
309 unsigned NumUnits =
E.second.isReserved() ? 0
U :
E.second.NumUnits;
311 if (!
RS.isReady(NumUnits)) {
312 BusyResourceMask |=
E.first;
316 if (
Desc.HasPartiallyOverlappingGroups && !
RS.isAResourceGroup()) {
318 NumAvailableUnits -= NumUnits;
319 AvailableUnits[
E.first] = NumAvailableUnits;
320 if (!NumAvailableUnits)
321 ConsumedResourceMask |=
E.first;
325 BusyResourceMask &= ProcResUnitMask;
326 if (BusyResourceMask)
327 return BusyResourceMask;
329 BusyResourceMask =
Desc.UsedProcResGroups & ReservedResourceGroups;
330 if (!
Desc.HasPartiallyOverlappingGroups || BusyResourceMask)
331 return BusyResourceMask;
335 for (
const std::pair<uint64_t, ResourceUsage> &
E :
Desc.Resources) {
337 if (!
E.second.isReserved() &&
RS.isAResourceGroup()) {
338 uint64_t ReadyMask =
RS.getReadyMask() & ~ConsumedResourceMask;
340 BusyResourceMask |=
RS.getReadyMask();
346 auto [it,
Inserted] = AvailableUnits.try_emplace(ResourceMask);
349 unsigned NumUnits =
llvm::popcount(Resources[Index]->getReadyMask());
350 it->second = NumUnits;
354 BusyResourceMask |= it->first;
360 ConsumedResourceMask |= it->first;
364 return BusyResourceMask;
367void ResourceManager::issueInstructionImpl(
377 using ResourceWithUsage = std::pair<uint64_t, ResourceUsage>;
379 for (
const ResourceWithUsage &R :
Desc.Resources) {
380 const CycleSegment &CS =
R.second.CS;
382 releaseResource(
R.first);
386 assert(CS.begin() == 0 &&
"Invalid {Start, End} cycles!");
387 if (
R.second.isReserved()) {
391 reserveResource(
R.first);
397 if (
RS.isAResourceGroup() &&
RS.getNumReadyUnits() > 1) {
398 Worklist.push_back(R);
404 BusyResources[
Pipe] += CS.size();
405 Pipes.emplace_back(std::make_pair(Pipe, ReleaseAtCycles(CS.size())));
415 while (!Worklist.empty()) {
416 sort(Worklist, [&](
const ResourceWithUsage &Lhs,
417 const ResourceWithUsage &Rhs) {
420 uint64_t LhsReadyUnits = LhsRS.getNumReadyUnits();
421 uint64_t RhsReadyUnits = RhsRS.getNumReadyUnits();
422 if (LhsReadyUnits == RhsReadyUnits)
423 return Lhs.first < Rhs.first;
424 return LhsReadyUnits < RhsReadyUnits;
429 for (
unsigned I = 0,
E = Worklist.size();
I <
E; ++
I) {
430 const auto &Elt = Worklist[
I];
433 if (
I == 0 ||
RS.getNumReadyUnits() == 1) {
436 const CycleSegment &CS = Elt.second.CS;
437 BusyResources[
Pipe] += CS.size();
438 Pipes.emplace_back(std::make_pair(Pipe, ReleaseAtCycles(CS.size())));
442 NewWorklist.push_back(Elt);
445 swap(NewWorklist, Worklist);
449void ResourceManager::fastIssueInstruction(
451 for (
const std::pair<uint64_t, ResourceUsage> &R :
Desc.Resources) {
452 const CycleSegment &CS =
R.second.CS;
454 releaseResource(
R.first);
458 assert(CS.begin() == 0 &&
"Invalid {Start, End} cycles!");
459 if (!
R.second.isReserved()) {
462 BusyResources[
Pipe] += CS.size();
463 Pipes.emplace_back(std::pair<ResourceRef, ReleaseAtCycles>(
464 Pipe, ReleaseAtCycles(CS.size())));
469 reserveResource(
R.first);
476 for (std::pair<ResourceRef, unsigned> &BR : BusyResources) {
485 releaseResource(RR.first);
486 ResourcesFreed.push_back(RR);
490 for (
const ResourceRef &RF : ResourcesFreed)
491 BusyResources.erase(RF);
494void ResourceManager::reserveResource(uint64_t ResourceID) {
496 ResourceState &Resource = *Resources[
Index];
497 assert(Resource.isAResourceGroup() && !Resource.isReserved() &&
498 "Unexpected resource state found!");
499 Resource.setReserved();
500 ReservedResourceGroups ^= 1ULL <<
Index;
503void ResourceManager::releaseResource(uint64_t ResourceID) {
505 ResourceState &Resource = *Resources[
Index];
506 Resource.clearReserved();
507 if (Resource.isAResourceGroup())
508 ReservedResourceGroups ^= 1ULL <<
Index;
510 if (Resource.isADispatchHazard())
511 ReservedBuffers ^= 1ULL <<
Index;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
@ Unavailable
We know the block is not fully available. This is a fixpoint.
iv Induction Variable Users
Move duplicate certain instructions close to their use
static constexpr unsigned SM(unsigned Version)
The classes here represent processor resource units and their management strategy.
ResourceManager(const TargetSubtargetInfo *ST, ScheduleDAGInstrs *DAG)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void used(uint64_t Mask) override
Called by the ResourceManager when a processor resource group, or a processor resource with multiple ...
uint64_t select(uint64_t ReadyMask) override
Selects a processor resource unit from a ReadyMask.
A processor resource descriptor.
virtual ~ResourceStrategy()
Helper functions used by various pipeline components.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ BR
Control flow instructions. These all have token chains.
static uint64_t computeResourceSizeMask(uint64_t Mask, bool IsAGroup, unsigned NumUnits)
static std::unique_ptr< ResourceStrategy > getStrategyFor(const ResourceState &RS)
ResourceStateEvent
Used to notify the internal state of a processor resource.
std::pair< uint64_t, uint64_t > ResourceRef
static uint64_t selectImpl(uint64_t CandidateMask, uint64_t &NextInSequenceMask)
LLVM_ABI void computeProcResourceMasks(const MCSchedModel &SM, MutableArrayRef< uint64_t > Masks)
Populates vector Masks with processor resource masks.
unsigned getResourceStateIndex(uint64_t Mask)
This is an optimization pass for GlobalISel generic memory operations.
FormattedNumber format_decimal(int64_t N, unsigned Width)
format_decimal - Output N as a right justified, fixed-width decimal.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Define a kind of processor resource that will be modeled by the scheduler.
Machine model for scheduling, bundling, and heuristics.