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 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 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 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 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 800b57cec5SDimitry Andric bool ResourceState::isReady(unsigned NumUnits) const { 810b57cec5SDimitry Andric return (!isReserved() || isADispatchHazard()) && 82bdd1243dSDimitry Andric (unsigned)llvm::popcount(ReadyMask) >= NumUnits; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry 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 940b57cec5SDimitry 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> 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 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 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 1660b57cec5SDimitry Andric unsigned ResourceManager::resolveResourceMask(uint64_t Mask) const { 1670b57cec5SDimitry Andric return ResIndex2ProcResID[getResourceStateIndex(Mask)]; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry 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. 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 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 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 2458bcb0991SDimitry 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 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 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 2820b57cec5SDimitry 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 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 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 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 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