10b57cec5SDimitry Andric //===--------------------- ResourceManager.cpp ------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// The classes here represent processor resource units and their management
110b57cec5SDimitry Andric /// strategy. These classes are managed by the Scheduler.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "llvm/MCA/HardwareUnits/ResourceManager.h"
160b57cec5SDimitry Andric #include "llvm/MCA/Support.h"
170b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
180b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric namespace llvm {
210b57cec5SDimitry Andric namespace mca {
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca"
240b57cec5SDimitry Andric ResourceStrategy::~ResourceStrategy() = default;
250b57cec5SDimitry Andric
selectImpl(uint64_t CandidateMask,uint64_t & NextInSequenceMask)260b57cec5SDimitry Andric static uint64_t selectImpl(uint64_t CandidateMask,
270b57cec5SDimitry Andric uint64_t &NextInSequenceMask) {
280b57cec5SDimitry Andric // The upper bit set in CandidateMask identifies our next candidate resource.
290b57cec5SDimitry Andric CandidateMask = 1ULL << getResourceStateIndex(CandidateMask);
300b57cec5SDimitry Andric NextInSequenceMask &= (CandidateMask | (CandidateMask - 1));
310b57cec5SDimitry Andric return CandidateMask;
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric
select(uint64_t ReadyMask)340b57cec5SDimitry Andric uint64_t DefaultResourceStrategy::select(uint64_t ReadyMask) {
350b57cec5SDimitry Andric // This method assumes that ReadyMask cannot be zero.
360b57cec5SDimitry Andric uint64_t CandidateMask = ReadyMask & NextInSequenceMask;
370b57cec5SDimitry Andric if (CandidateMask)
380b57cec5SDimitry Andric return selectImpl(CandidateMask, NextInSequenceMask);
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric NextInSequenceMask = ResourceUnitMask ^ RemovedFromNextInSequence;
410b57cec5SDimitry Andric RemovedFromNextInSequence = 0;
420b57cec5SDimitry Andric CandidateMask = ReadyMask & NextInSequenceMask;
430b57cec5SDimitry Andric if (CandidateMask)
440b57cec5SDimitry Andric return selectImpl(CandidateMask, NextInSequenceMask);
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric NextInSequenceMask = ResourceUnitMask;
470b57cec5SDimitry Andric CandidateMask = ReadyMask & NextInSequenceMask;
480b57cec5SDimitry Andric return selectImpl(CandidateMask, NextInSequenceMask);
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
used(uint64_t Mask)510b57cec5SDimitry Andric void DefaultResourceStrategy::used(uint64_t Mask) {
520b57cec5SDimitry Andric if (Mask > NextInSequenceMask) {
530b57cec5SDimitry Andric RemovedFromNextInSequence |= Mask;
540b57cec5SDimitry Andric return;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric NextInSequenceMask &= (~Mask);
580b57cec5SDimitry Andric if (NextInSequenceMask)
590b57cec5SDimitry Andric return;
600b57cec5SDimitry Andric
610b57cec5SDimitry Andric NextInSequenceMask = ResourceUnitMask ^ RemovedFromNextInSequence;
620b57cec5SDimitry Andric RemovedFromNextInSequence = 0;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
ResourceState(const MCProcResourceDesc & Desc,unsigned Index,uint64_t Mask)650b57cec5SDimitry Andric ResourceState::ResourceState(const MCProcResourceDesc &Desc, unsigned Index,
660b57cec5SDimitry Andric uint64_t Mask)
670b57cec5SDimitry Andric : ProcResourceDescIndex(Index), ResourceMask(Mask),
68bdd1243dSDimitry Andric BufferSize(Desc.BufferSize), IsAGroup(llvm::popcount(ResourceMask) > 1) {
690b57cec5SDimitry Andric if (IsAGroup) {
700b57cec5SDimitry Andric ResourceSizeMask =
710b57cec5SDimitry Andric ResourceMask ^ 1ULL << getResourceStateIndex(ResourceMask);
720b57cec5SDimitry Andric } else {
730b57cec5SDimitry Andric ResourceSizeMask = (1ULL << Desc.NumUnits) - 1;
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric ReadyMask = ResourceSizeMask;
760b57cec5SDimitry Andric AvailableSlots = BufferSize == -1 ? 0U : static_cast<unsigned>(BufferSize);
770b57cec5SDimitry Andric Unavailable = false;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric
isReady(unsigned NumUnits) const800b57cec5SDimitry Andric bool ResourceState::isReady(unsigned NumUnits) const {
810b57cec5SDimitry Andric return (!isReserved() || isADispatchHazard()) &&
82bdd1243dSDimitry Andric (unsigned)llvm::popcount(ReadyMask) >= NumUnits;
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric
isBufferAvailable() const850b57cec5SDimitry Andric ResourceStateEvent ResourceState::isBufferAvailable() const {
860b57cec5SDimitry Andric if (isADispatchHazard() && isReserved())
870b57cec5SDimitry Andric return RS_RESERVED;
880b57cec5SDimitry Andric if (!isBuffered() || AvailableSlots)
890b57cec5SDimitry Andric return RS_BUFFER_AVAILABLE;
900b57cec5SDimitry Andric return RS_BUFFER_UNAVAILABLE;
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric #ifndef NDEBUG
dump() const940b57cec5SDimitry Andric void ResourceState::dump() const {
950b57cec5SDimitry Andric dbgs() << "MASK=" << format_hex(ResourceMask, 16)
960b57cec5SDimitry Andric << ", SZMASK=" << format_hex(ResourceSizeMask, 16)
970b57cec5SDimitry Andric << ", RDYMASK=" << format_hex(ReadyMask, 16)
980b57cec5SDimitry Andric << ", BufferSize=" << BufferSize
990b57cec5SDimitry Andric << ", AvailableSlots=" << AvailableSlots
1000b57cec5SDimitry Andric << ", Reserved=" << Unavailable << '\n';
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric #endif
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric static std::unique_ptr<ResourceStrategy>
getStrategyFor(const ResourceState & RS)1050b57cec5SDimitry Andric getStrategyFor(const ResourceState &RS) {
1060b57cec5SDimitry Andric if (RS.isAResourceGroup() || RS.getNumUnits() > 1)
1078bcb0991SDimitry Andric return std::make_unique<DefaultResourceStrategy>(RS.getReadyMask());
1080b57cec5SDimitry Andric return std::unique_ptr<ResourceStrategy>(nullptr);
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric
ResourceManager(const MCSchedModel & SM)1110b57cec5SDimitry Andric ResourceManager::ResourceManager(const MCSchedModel &SM)
1120b57cec5SDimitry Andric : Resources(SM.getNumProcResourceKinds() - 1),
1130b57cec5SDimitry Andric Strategies(SM.getNumProcResourceKinds() - 1),
1140b57cec5SDimitry Andric Resource2Groups(SM.getNumProcResourceKinds() - 1, 0),
1150b57cec5SDimitry Andric ProcResID2Mask(SM.getNumProcResourceKinds(), 0),
1160b57cec5SDimitry Andric ResIndex2ProcResID(SM.getNumProcResourceKinds() - 1, 0),
117fe6060f1SDimitry Andric ProcResUnitMask(0), ReservedResourceGroups(0), AvailableBuffers(~0ULL),
118fe6060f1SDimitry Andric ReservedBuffers(0) {
1190b57cec5SDimitry Andric computeProcResourceMasks(SM, ProcResID2Mask);
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric // initialize vector ResIndex2ProcResID.
1220b57cec5SDimitry Andric for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
1230b57cec5SDimitry Andric unsigned Index = getResourceStateIndex(ProcResID2Mask[I]);
1240b57cec5SDimitry Andric ResIndex2ProcResID[Index] = I;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
1280b57cec5SDimitry Andric uint64_t Mask = ProcResID2Mask[I];
1290b57cec5SDimitry Andric unsigned Index = getResourceStateIndex(Mask);
1300b57cec5SDimitry Andric Resources[Index] =
1318bcb0991SDimitry Andric std::make_unique<ResourceState>(*SM.getProcResource(I), I, Mask);
1320b57cec5SDimitry Andric Strategies[Index] = getStrategyFor(*Resources[Index]);
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
1360b57cec5SDimitry Andric uint64_t Mask = ProcResID2Mask[I];
1370b57cec5SDimitry Andric unsigned Index = getResourceStateIndex(Mask);
1380b57cec5SDimitry Andric const ResourceState &RS = *Resources[Index];
1390b57cec5SDimitry Andric if (!RS.isAResourceGroup()) {
1400b57cec5SDimitry Andric ProcResUnitMask |= Mask;
1410b57cec5SDimitry Andric continue;
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric uint64_t GroupMaskIdx = 1ULL << Index;
1450b57cec5SDimitry Andric Mask -= GroupMaskIdx;
1460b57cec5SDimitry Andric while (Mask) {
1470b57cec5SDimitry Andric // Extract lowest set isolated bit.
1480b57cec5SDimitry Andric uint64_t Unit = Mask & (-Mask);
1490b57cec5SDimitry Andric unsigned IndexUnit = getResourceStateIndex(Unit);
1500b57cec5SDimitry Andric Resource2Groups[IndexUnit] |= GroupMaskIdx;
1510b57cec5SDimitry Andric Mask ^= Unit;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric AvailableProcResUnits = ProcResUnitMask;
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,uint64_t ResourceMask)1580b57cec5SDimitry Andric void ResourceManager::setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,
1590b57cec5SDimitry Andric uint64_t ResourceMask) {
1600b57cec5SDimitry Andric unsigned Index = getResourceStateIndex(ResourceMask);
1610b57cec5SDimitry Andric assert(Index < Resources.size() && "Invalid processor resource index!");
1620b57cec5SDimitry Andric assert(S && "Unexpected null strategy in input!");
1630b57cec5SDimitry Andric Strategies[Index] = std::move(S);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
resolveResourceMask(uint64_t Mask) const1660b57cec5SDimitry Andric unsigned ResourceManager::resolveResourceMask(uint64_t Mask) const {
1670b57cec5SDimitry Andric return ResIndex2ProcResID[getResourceStateIndex(Mask)];
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric
getNumUnits(uint64_t ResourceID) const1700b57cec5SDimitry Andric unsigned ResourceManager::getNumUnits(uint64_t ResourceID) const {
1710b57cec5SDimitry Andric return Resources[getResourceStateIndex(ResourceID)]->getNumUnits();
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andric // Returns the actual resource consumed by this Use.
1750b57cec5SDimitry Andric // First, is the primary resource ID.
1760b57cec5SDimitry Andric // Second, is the specific sub-resource ID.
selectPipe(uint64_t ResourceID)1770b57cec5SDimitry Andric ResourceRef ResourceManager::selectPipe(uint64_t ResourceID) {
1780b57cec5SDimitry Andric unsigned Index = getResourceStateIndex(ResourceID);
1790b57cec5SDimitry Andric assert(Index < Resources.size() && "Invalid resource use!");
1800b57cec5SDimitry Andric ResourceState &RS = *Resources[Index];
1810b57cec5SDimitry Andric assert(RS.isReady() && "No available units to select!");
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric // Special case where RS is not a group, and it only declares a single
1840b57cec5SDimitry Andric // resource unit.
1850b57cec5SDimitry Andric if (!RS.isAResourceGroup() && RS.getNumUnits() == 1)
1860b57cec5SDimitry Andric return std::make_pair(ResourceID, RS.getReadyMask());
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric uint64_t SubResourceID = Strategies[Index]->select(RS.getReadyMask());
1890b57cec5SDimitry Andric if (RS.isAResourceGroup())
1900b57cec5SDimitry Andric return selectPipe(SubResourceID);
1910b57cec5SDimitry Andric return std::make_pair(ResourceID, SubResourceID);
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric
use(const ResourceRef & RR)1940b57cec5SDimitry Andric void ResourceManager::use(const ResourceRef &RR) {
1950b57cec5SDimitry Andric // Mark the sub-resource referenced by RR as used.
1960b57cec5SDimitry Andric unsigned RSID = getResourceStateIndex(RR.first);
1970b57cec5SDimitry Andric ResourceState &RS = *Resources[RSID];
1980b57cec5SDimitry Andric RS.markSubResourceAsUsed(RR.second);
1990b57cec5SDimitry Andric // Remember to update the resource strategy for non-group resources with
2000b57cec5SDimitry Andric // multiple units.
2010b57cec5SDimitry Andric if (RS.getNumUnits() > 1)
2020b57cec5SDimitry Andric Strategies[RSID]->used(RR.second);
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric // If there are still available units in RR.first,
2050b57cec5SDimitry Andric // then we are done.
2060b57cec5SDimitry Andric if (RS.isReady())
2070b57cec5SDimitry Andric return;
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric AvailableProcResUnits ^= RR.first;
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric // Notify groups that RR.first is no longer available.
2120b57cec5SDimitry Andric uint64_t Users = Resource2Groups[RSID];
2130b57cec5SDimitry Andric while (Users) {
2140b57cec5SDimitry Andric // Extract lowest set isolated bit.
2150b57cec5SDimitry Andric unsigned GroupIndex = getResourceStateIndex(Users & (-Users));
2160b57cec5SDimitry Andric ResourceState &CurrentUser = *Resources[GroupIndex];
2170b57cec5SDimitry Andric CurrentUser.markSubResourceAsUsed(RR.first);
2180b57cec5SDimitry Andric Strategies[GroupIndex]->used(RR.first);
2190b57cec5SDimitry Andric // Reset lowest set bit.
2200b57cec5SDimitry Andric Users &= Users - 1;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric
release(const ResourceRef & RR)2240b57cec5SDimitry Andric void ResourceManager::release(const ResourceRef &RR) {
2250b57cec5SDimitry Andric unsigned RSID = getResourceStateIndex(RR.first);
2260b57cec5SDimitry Andric ResourceState &RS = *Resources[RSID];
2270b57cec5SDimitry Andric bool WasFullyUsed = !RS.isReady();
2280b57cec5SDimitry Andric RS.releaseSubResource(RR.second);
2290b57cec5SDimitry Andric if (!WasFullyUsed)
2300b57cec5SDimitry Andric return;
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric AvailableProcResUnits ^= RR.first;
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric // Notify groups that RR.first is now available again.
2350b57cec5SDimitry Andric uint64_t Users = Resource2Groups[RSID];
2360b57cec5SDimitry Andric while (Users) {
2370b57cec5SDimitry Andric unsigned GroupIndex = getResourceStateIndex(Users & (-Users));
2380b57cec5SDimitry Andric ResourceState &CurrentUser = *Resources[GroupIndex];
2390b57cec5SDimitry Andric CurrentUser.releaseSubResource(RR.first);
2400b57cec5SDimitry Andric Users &= Users - 1;
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric ResourceStateEvent
canBeDispatched(uint64_t ConsumedBuffers) const2458bcb0991SDimitry Andric ResourceManager::canBeDispatched(uint64_t ConsumedBuffers) const {
2468bcb0991SDimitry Andric if (ConsumedBuffers & ReservedBuffers)
2478bcb0991SDimitry Andric return ResourceStateEvent::RS_RESERVED;
2488bcb0991SDimitry Andric if (ConsumedBuffers & (~AvailableBuffers))
2498bcb0991SDimitry Andric return ResourceStateEvent::RS_BUFFER_UNAVAILABLE;
2508bcb0991SDimitry Andric return ResourceStateEvent::RS_BUFFER_AVAILABLE;
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric
reserveBuffers(uint64_t ConsumedBuffers)2538bcb0991SDimitry Andric void ResourceManager::reserveBuffers(uint64_t ConsumedBuffers) {
2548bcb0991SDimitry Andric while (ConsumedBuffers) {
2558bcb0991SDimitry Andric uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
2568bcb0991SDimitry Andric ResourceState &RS = *Resources[getResourceStateIndex(CurrentBuffer)];
2578bcb0991SDimitry Andric ConsumedBuffers ^= CurrentBuffer;
2580b57cec5SDimitry Andric assert(RS.isBufferAvailable() == ResourceStateEvent::RS_BUFFER_AVAILABLE);
2598bcb0991SDimitry Andric if (!RS.reserveBuffer())
2608bcb0991SDimitry Andric AvailableBuffers ^= CurrentBuffer;
2610b57cec5SDimitry Andric if (RS.isADispatchHazard()) {
2628bcb0991SDimitry Andric // Reserve this buffer now, and release it once pipeline resources
2638bcb0991SDimitry Andric // consumed by the instruction become available again.
2648bcb0991SDimitry Andric // We do this to simulate an in-order dispatch/issue of instructions.
2658bcb0991SDimitry Andric ReservedBuffers ^= CurrentBuffer;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric
releaseBuffers(uint64_t ConsumedBuffers)2708bcb0991SDimitry Andric void ResourceManager::releaseBuffers(uint64_t ConsumedBuffers) {
2718bcb0991SDimitry Andric AvailableBuffers |= ConsumedBuffers;
2728bcb0991SDimitry Andric while (ConsumedBuffers) {
2738bcb0991SDimitry Andric uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
2748bcb0991SDimitry Andric ResourceState &RS = *Resources[getResourceStateIndex(CurrentBuffer)];
2758bcb0991SDimitry Andric ConsumedBuffers ^= CurrentBuffer;
2768bcb0991SDimitry Andric RS.releaseBuffer();
2778bcb0991SDimitry Andric // Do not unreserve dispatch hazard resource buffers. Wait until all
2788bcb0991SDimitry Andric // pipeline resources have been freed too.
2798bcb0991SDimitry Andric }
2800b57cec5SDimitry Andric }
2810b57cec5SDimitry Andric
checkAvailability(const InstrDesc & Desc) const2820b57cec5SDimitry Andric uint64_t ResourceManager::checkAvailability(const InstrDesc &Desc) const {
2830b57cec5SDimitry Andric uint64_t BusyResourceMask = 0;
284bdd1243dSDimitry Andric uint64_t ConsumedResourceMask = 0;
285bdd1243dSDimitry Andric DenseMap<uint64_t, unsigned> AvailableUnits;
286bdd1243dSDimitry Andric
287480093f4SDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &E : Desc.Resources) {
2880b57cec5SDimitry Andric unsigned NumUnits = E.second.isReserved() ? 0U : E.second.NumUnits;
289bdd1243dSDimitry Andric const ResourceState &RS = *Resources[getResourceStateIndex(E.first)];
290bdd1243dSDimitry Andric if (!RS.isReady(NumUnits)) {
2910b57cec5SDimitry Andric BusyResourceMask |= E.first;
292bdd1243dSDimitry Andric continue;
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric
295bdd1243dSDimitry Andric if (Desc.HasPartiallyOverlappingGroups && !RS.isAResourceGroup()) {
296bdd1243dSDimitry Andric unsigned NumAvailableUnits = llvm::popcount(RS.getReadyMask());
297bdd1243dSDimitry Andric NumAvailableUnits -= NumUnits;
298bdd1243dSDimitry Andric AvailableUnits[E.first] = NumAvailableUnits;
299bdd1243dSDimitry Andric if (!NumAvailableUnits)
300bdd1243dSDimitry Andric ConsumedResourceMask |= E.first;
301bdd1243dSDimitry Andric }
302fe6060f1SDimitry Andric }
303fe6060f1SDimitry Andric
3040b57cec5SDimitry Andric BusyResourceMask &= ProcResUnitMask;
3050b57cec5SDimitry Andric if (BusyResourceMask)
3060b57cec5SDimitry Andric return BusyResourceMask;
307bdd1243dSDimitry Andric
308bdd1243dSDimitry Andric BusyResourceMask = Desc.UsedProcResGroups & ReservedResourceGroups;
309bdd1243dSDimitry Andric if (!Desc.HasPartiallyOverlappingGroups || BusyResourceMask)
310bdd1243dSDimitry Andric return BusyResourceMask;
311bdd1243dSDimitry Andric
312bdd1243dSDimitry Andric // If this instruction has overlapping groups, make sure that we can
313bdd1243dSDimitry Andric // select at least one unit per group.
314bdd1243dSDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &E : Desc.Resources) {
315bdd1243dSDimitry Andric const ResourceState &RS = *Resources[getResourceStateIndex(E.first)];
316bdd1243dSDimitry Andric if (!E.second.isReserved() && RS.isAResourceGroup()) {
317bdd1243dSDimitry Andric uint64_t ReadyMask = RS.getReadyMask() & ~ConsumedResourceMask;
318bdd1243dSDimitry Andric if (!ReadyMask) {
319bdd1243dSDimitry Andric BusyResourceMask |= RS.getReadyMask();
320bdd1243dSDimitry Andric continue;
321bdd1243dSDimitry Andric }
322bdd1243dSDimitry Andric
32306c3fb27SDimitry Andric uint64_t ResourceMask = llvm::bit_floor(ReadyMask);
324bdd1243dSDimitry Andric
325bdd1243dSDimitry Andric auto it = AvailableUnits.find(ResourceMask);
326bdd1243dSDimitry Andric if (it == AvailableUnits.end()) {
327bdd1243dSDimitry Andric unsigned Index = getResourceStateIndex(ResourceMask);
328bdd1243dSDimitry Andric unsigned NumUnits = llvm::popcount(Resources[Index]->getReadyMask());
329bdd1243dSDimitry Andric it =
330bdd1243dSDimitry Andric AvailableUnits.insert(std::make_pair(ResourceMask, NumUnits)).first;
331bdd1243dSDimitry Andric }
332bdd1243dSDimitry Andric
333bdd1243dSDimitry Andric if (!it->second) {
334bdd1243dSDimitry Andric BusyResourceMask |= it->first;
335bdd1243dSDimitry Andric continue;
336bdd1243dSDimitry Andric }
337bdd1243dSDimitry Andric
338bdd1243dSDimitry Andric it->second--;
339bdd1243dSDimitry Andric if (!it->second)
340bdd1243dSDimitry Andric ConsumedResourceMask |= it->first;
341bdd1243dSDimitry Andric }
342bdd1243dSDimitry Andric }
343bdd1243dSDimitry Andric
344bdd1243dSDimitry Andric return BusyResourceMask;
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric
issueInstruction(const InstrDesc & Desc,SmallVectorImpl<std::pair<ResourceRef,ReleaseAtCycles>> & Pipes)3470b57cec5SDimitry Andric void ResourceManager::issueInstruction(
3480b57cec5SDimitry Andric const InstrDesc &Desc,
349*5f757f3fSDimitry Andric SmallVectorImpl<std::pair<ResourceRef, ReleaseAtCycles>> &Pipes) {
3500b57cec5SDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &R : Desc.Resources) {
3510b57cec5SDimitry Andric const CycleSegment &CS = R.second.CS;
3520b57cec5SDimitry Andric if (!CS.size()) {
3530b57cec5SDimitry Andric releaseResource(R.first);
3540b57cec5SDimitry Andric continue;
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric
3570b57cec5SDimitry Andric assert(CS.begin() == 0 && "Invalid {Start, End} cycles!");
3580b57cec5SDimitry Andric if (!R.second.isReserved()) {
3590b57cec5SDimitry Andric ResourceRef Pipe = selectPipe(R.first);
3600b57cec5SDimitry Andric use(Pipe);
3610b57cec5SDimitry Andric BusyResources[Pipe] += CS.size();
362*5f757f3fSDimitry Andric Pipes.emplace_back(std::pair<ResourceRef, ReleaseAtCycles>(
363*5f757f3fSDimitry Andric Pipe, ReleaseAtCycles(CS.size())));
3640b57cec5SDimitry Andric } else {
365bdd1243dSDimitry Andric assert((llvm::popcount(R.first) > 1) && "Expected a group!");
3660b57cec5SDimitry Andric // Mark this group as reserved.
3670b57cec5SDimitry Andric assert(R.second.isReserved());
3680b57cec5SDimitry Andric reserveResource(R.first);
3690b57cec5SDimitry Andric BusyResources[ResourceRef(R.first, R.first)] += CS.size();
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric }
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric
cycleEvent(SmallVectorImpl<ResourceRef> & ResourcesFreed)3740b57cec5SDimitry Andric void ResourceManager::cycleEvent(SmallVectorImpl<ResourceRef> &ResourcesFreed) {
3750b57cec5SDimitry Andric for (std::pair<ResourceRef, unsigned> &BR : BusyResources) {
3760b57cec5SDimitry Andric if (BR.second)
3770b57cec5SDimitry Andric BR.second--;
3780b57cec5SDimitry Andric if (!BR.second) {
3790b57cec5SDimitry Andric // Release this resource.
3800b57cec5SDimitry Andric const ResourceRef &RR = BR.first;
3810b57cec5SDimitry Andric
382bdd1243dSDimitry Andric if (llvm::popcount(RR.first) == 1)
3830b57cec5SDimitry Andric release(RR);
3840b57cec5SDimitry Andric releaseResource(RR.first);
3850b57cec5SDimitry Andric ResourcesFreed.push_back(RR);
3860b57cec5SDimitry Andric }
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric for (const ResourceRef &RF : ResourcesFreed)
3900b57cec5SDimitry Andric BusyResources.erase(RF);
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric
reserveResource(uint64_t ResourceID)3930b57cec5SDimitry Andric void ResourceManager::reserveResource(uint64_t ResourceID) {
3940b57cec5SDimitry Andric const unsigned Index = getResourceStateIndex(ResourceID);
3950b57cec5SDimitry Andric ResourceState &Resource = *Resources[Index];
3960b57cec5SDimitry Andric assert(Resource.isAResourceGroup() && !Resource.isReserved() &&
3978bcb0991SDimitry Andric "Unexpected resource state found!");
3980b57cec5SDimitry Andric Resource.setReserved();
3990b57cec5SDimitry Andric ReservedResourceGroups ^= 1ULL << Index;
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric
releaseResource(uint64_t ResourceID)4020b57cec5SDimitry Andric void ResourceManager::releaseResource(uint64_t ResourceID) {
4030b57cec5SDimitry Andric const unsigned Index = getResourceStateIndex(ResourceID);
4040b57cec5SDimitry Andric ResourceState &Resource = *Resources[Index];
4050b57cec5SDimitry Andric Resource.clearReserved();
4060b57cec5SDimitry Andric if (Resource.isAResourceGroup())
4070b57cec5SDimitry Andric ReservedResourceGroups ^= 1ULL << Index;
4088bcb0991SDimitry Andric // Now it is safe to release dispatch/issue resources.
4098bcb0991SDimitry Andric if (Resource.isADispatchHazard())
4108bcb0991SDimitry Andric ReservedBuffers ^= 1ULL << Index;
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric } // namespace mca
4140b57cec5SDimitry Andric } // namespace llvm
415