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 float ReservationStationScaleFactor)
75 : ProcResourceDescIndex(Index), ResourceMask(Mask),
79 SM.getResourceBufferSize(Index, ReservationStationScaleFactor)) {
80 ReadyMask = ResourceSizeMask;
81 AvailableSlots = BufferSize == -1 ? 0U :
static_cast<unsigned>(BufferSize);
85bool ResourceState::isReady(
unsigned NumUnits)
const {
86 return (!isReserved() || isADispatchHazard()) &&
91 if (isADispatchHazard() && isReserved())
93 if (!isBuffered() || AvailableSlots)
99void ResourceState::dump()
const {
101 <<
", SZMASK=" <<
format_hex(ResourceSizeMask, 16)
103 <<
", BufferSize=" << BufferSize
104 <<
", AvailableSlots=" << AvailableSlots
109static std::unique_ptr<ResourceStrategy>
111 if (RS.isAResourceGroup() || RS.getNumUnits() > 1)
112 return std::make_unique<DefaultResourceStrategy>(RS.getReadyMask());
113 return std::unique_ptr<ResourceStrategy>(
nullptr);
117 float ReservationStationScaleFactor)
118 :
Resources(SM.getNumProcResourceKinds() - 1),
119 Strategies(SM.getNumProcResourceKinds() - 1),
120 Resource2Groups(SM.getNumProcResourceKinds() - 1, 0),
121 ProcResID2Mask(SM.getNumProcResourceKinds(), 0),
122 ResIndex2ProcResID(SM.getNumProcResourceKinds() - 1, 0),
123 ProcResUnitMask(0), ReservedResourceGroups(0), AvailableBuffers(~0ULL),
130 ResIndex2ProcResID[Index] =
I;
136 Resources[Index] = std::make_unique<ResourceState>(
143 dbgs() <<
"\nProcessor resources:\n";
148 << InvalidUnit.Name <<
"\n";
151 const unsigned ProcResID =
RS.getProcResourceID();
154 <<
" - " <<
format_hex(
RS.getResourceMask(), 16) <<
" - "
155 <<
Desc.Name <<
" (BufferSize=" <<
RS.getBufferSize() <<
")\n";
163 if (!
RS.isAResourceGroup()) {
164 ProcResUnitMask |=
Mask;
169 Mask -= GroupMaskIdx;
174 Resource2Groups[IndexUnit] |= GroupMaskIdx;
179 AvailableProcResUnits = ProcResUnitMask;
182void ResourceManager::setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,
185 assert(Index <
Resources.size() &&
"Invalid processor resource index!");
186 assert(S &&
"Unexpected null strategy in input!");
187 Strategies[
Index] = std::move(S);
190unsigned ResourceManager::resolveResourceMask(
uint64_t Mask)
const {
194unsigned ResourceManager::getNumUnits(
uint64_t ResourceID)
const {
205 assert(
RS.isReady() &&
"No available units to select!");
209 if (!
RS.isAResourceGroup() &&
RS.getNumUnits() == 1)
210 return std::make_pair(ResourceID,
RS.getReadyMask());
213 if (
RS.isAResourceGroup())
214 return selectPipe(SubResourceID);
215 return std::make_pair(ResourceID, SubResourceID);
218void ResourceManager::use(
const ResourceRef &RR) {
222 RS.markSubResourceAsUsed(RR.second);
225 if (
RS.getNumUnits() > 1)
226 Strategies[RSID]->used(RR.second);
233 AvailableProcResUnits ^= RR.first;
240 ResourceState &CurrentUser = *
Resources[GroupIndex];
241 CurrentUser.markSubResourceAsUsed(RR.first);
242 Strategies[GroupIndex]->used(RR.first);
248void ResourceManager::release(
const ResourceRef &RR) {
251 bool WasFullyUsed = !
RS.isReady();
252 RS.releaseSubResource(RR.second);
256 AvailableProcResUnits ^= RR.first;
262 ResourceState &CurrentUser = *
Resources[GroupIndex];
263 CurrentUser.releaseSubResource(RR.first);
269ResourceManager::canBeDispatched(
uint64_t ConsumedBuffers)
const {
270 if (ConsumedBuffers & ReservedBuffers)
271 return ResourceStateEvent::RS_RESERVED;
272 if (ConsumedBuffers & (~AvailableBuffers))
273 return ResourceStateEvent::RS_BUFFER_UNAVAILABLE;
274 return ResourceStateEvent::RS_BUFFER_AVAILABLE;
277void ResourceManager::reserveBuffers(
uint64_t ConsumedBuffers) {
278 while (ConsumedBuffers) {
279 uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
281 ConsumedBuffers ^= CurrentBuffer;
282 assert(
RS.isBufferAvailable() == ResourceStateEvent::RS_BUFFER_AVAILABLE);
283 if (!
RS.reserveBuffer())
284 AvailableBuffers ^= CurrentBuffer;
285 if (
RS.isADispatchHazard()) {
289 ReservedBuffers ^= CurrentBuffer;
294void ResourceManager::releaseBuffers(
uint64_t ConsumedBuffers) {
295 AvailableBuffers |= ConsumedBuffers;
296 while (ConsumedBuffers) {
297 uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
299 ConsumedBuffers ^= CurrentBuffer;
306uint64_t ResourceManager::checkAvailability(
const InstrDesc &
Desc)
const {
309 DenseMap<uint64_t, unsigned> AvailableUnits;
311 for (
const std::pair<uint64_t, ResourceUsage> &
E :
Desc.Resources) {
312 unsigned NumUnits =
E.second.isReserved() ? 0
U :
E.second.NumUnits;
314 if (!
RS.isReady(NumUnits)) {
315 BusyResourceMask |=
E.first;
319 if (
Desc.HasPartiallyOverlappingGroups && !
RS.isAResourceGroup()) {
321 NumAvailableUnits -= NumUnits;
322 AvailableUnits[
E.first] = NumAvailableUnits;
323 if (!NumAvailableUnits)
324 ConsumedResourceMask |=
E.first;
328 BusyResourceMask &= ProcResUnitMask;
329 if (BusyResourceMask)
330 return BusyResourceMask;
332 BusyResourceMask =
Desc.UsedProcResGroups & ReservedResourceGroups;
333 if (!
Desc.HasPartiallyOverlappingGroups || BusyResourceMask)
334 return BusyResourceMask;
338 for (
const std::pair<uint64_t, ResourceUsage> &
E :
Desc.Resources) {
340 if (!
E.second.isReserved() &&
RS.isAResourceGroup()) {
341 uint64_t ReadyMask =
RS.getReadyMask() & ~ConsumedResourceMask;
343 BusyResourceMask |=
RS.getReadyMask();
349 auto [it,
Inserted] = AvailableUnits.try_emplace(ResourceMask);
353 it->second = NumUnits;
357 BusyResourceMask |= it->first;
363 ConsumedResourceMask |= it->first;
367 return BusyResourceMask;
370void ResourceManager::issueInstructionImpl(
380 using ResourceWithUsage = std::pair<uint64_t, ResourceUsage>;
382 for (
const ResourceWithUsage &R :
Desc.Resources) {
383 const CycleSegment &CS =
R.second.CS;
385 releaseResource(
R.first);
389 assert(CS.begin() == 0 &&
"Invalid {Start, End} cycles!");
390 if (
R.second.isReserved()) {
394 reserveResource(
R.first);
400 if (
RS.isAResourceGroup() &&
RS.getNumReadyUnits() > 1) {
401 Worklist.push_back(R);
407 BusyResources[
Pipe] += CS.size();
408 Pipes.emplace_back(std::make_pair(Pipe, ReleaseAtCycles(CS.size())));
418 while (!Worklist.empty()) {
419 sort(Worklist, [&](
const ResourceWithUsage &Lhs,
420 const ResourceWithUsage &Rhs) {
423 uint64_t LhsReadyUnits = LhsRS.getNumReadyUnits();
424 uint64_t RhsReadyUnits = RhsRS.getNumReadyUnits();
425 if (LhsReadyUnits == RhsReadyUnits)
426 return Lhs.first < Rhs.first;
427 return LhsReadyUnits < RhsReadyUnits;
432 for (
unsigned I = 0,
E = Worklist.size();
I <
E; ++
I) {
433 const auto &Elt = Worklist[
I];
436 if (
I == 0 ||
RS.getNumReadyUnits() == 1) {
439 const CycleSegment &CS = Elt.second.CS;
440 BusyResources[
Pipe] += CS.size();
441 Pipes.emplace_back(std::make_pair(Pipe, ReleaseAtCycles(CS.size())));
445 NewWorklist.push_back(Elt);
448 swap(NewWorklist, Worklist);
452void ResourceManager::fastIssueInstruction(
454 for (
const std::pair<uint64_t, ResourceUsage> &R :
Desc.Resources) {
455 const CycleSegment &CS =
R.second.CS;
457 releaseResource(
R.first);
461 assert(CS.begin() == 0 &&
"Invalid {Start, End} cycles!");
462 if (!
R.second.isReserved()) {
465 BusyResources[
Pipe] += CS.size();
466 Pipes.emplace_back(std::pair<ResourceRef, ReleaseAtCycles>(
467 Pipe, ReleaseAtCycles(CS.size())));
472 reserveResource(
R.first);
479 for (
auto &BR : BusyResources) {
488 releaseResource(RR.first);
489 ResourcesFreed.push_back(RR);
493 for (
const ResourceRef &RF : ResourcesFreed)
494 BusyResources.erase(RF);
497void ResourceManager::reserveResource(
uint64_t ResourceID) {
500 assert(Resource.isAResourceGroup() && !Resource.isReserved() &&
501 "Unexpected resource state found!");
502 Resource.setReserved();
503 ReservedResourceGroups ^= 1ULL <<
Index;
506void ResourceManager::releaseResource(
uint64_t ResourceID) {
509 Resource.clearReserved();
510 if (Resource.isAResourceGroup())
511 ReservedResourceGroups ^= 1ULL <<
Index;
513 if (Resource.isADispatchHazard())
514 ReservedBuffers ^= 1ULL <<
Index;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
DXIL Remove Unused Resources
@ 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
The classes here represent processor resource units and their management strategy.
LLVM_ABI 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.
unsigned getNumProcResourceKinds() const
const MCProcResourceDesc * getProcResource(unsigned ProcResourceIdx) const