diff --git a/llvm/include/llvm/MCA/HardwareUnits/ResourceManager.h b/llvm/include/llvm/MCA/HardwareUnits/ResourceManager.h index 7ae1a218ed61..da80c984ba5e 100644 --- a/llvm/include/llvm/MCA/HardwareUnits/ResourceManager.h +++ b/llvm/include/llvm/MCA/HardwareUnits/ResourceManager.h @@ -139,7 +139,30 @@ class ResourceState { /// An index to the MCProcResourceDesc entry in the processor model. const unsigned ProcResourceDescIndex; /// A resource mask. This is generated by the tool with the help of - /// function `mca::createProcResourceMasks' (see Support.h). + /// function `mca::computeProcResourceMasks' (see Support.h). + /// + /// Field ResourceMask only has one bit set if this resource state describes a + /// processor resource unit (i.e. this is not a group). That means, we can + /// quickly check if a resource is a group by simply counting the number of + /// bits that are set in the mask. + /// + /// The most significant bit of a mask (MSB) uniquely identifies a resource. + /// Remaining bits are used to describe the composition of a group (Group). + /// + /// Example (little endian): + /// Resource | Mask | MSB | Group + /// ---------+------------+------------+------------ + /// A | 0b000001 | 0b000001 | 0b000000 + /// | | | + /// B | 0b000010 | 0b000010 | 0b000000 + /// | | | + /// C | 0b010000 | 0b010000 | 0b000000 + /// | | | + /// D | 0b110010 | 0b100000 | 0b010010 + /// + /// In this example, resources A, B and C are processor resource units. + /// Only resource D is a group resource, and it contains resources B and C. + /// That is because MSB(B) and MSB(C) are both contained within Group(D). const uint64_t ResourceMask; /// A ProcResource can have multiple units. @@ -279,10 +302,39 @@ typedef std::pair BufferUsageEntry; /// In future, it can be extended to support itineraries too through the same /// public interface. class ResourceManager { - // The resource manager owns all the ResourceState. + // Set of resources available on the subtarget. + // + // There is an instance of ResourceState for every resource declared by the + // target scheduling model. + // + // Elements of this vector are ordered by resource kind. In particular, + // resource units take precedence over resource groups. + // + // The index of a processor resource in this vector depends on the value of + // its mask (see the description of field ResourceState::ResourceMask). In + // particular, it is computed as the position of the most significant bit set + // (MSB) in the mask plus one (since we want to ignore the invalid resource + // descriptor at index zero). + // + // Example (little endian): + // + // Resource | Mask | MSB | Index + // ---------+---------+---------+------- + // A | 0b00001 | 0b00001 | 1 + // | | | + // B | 0b00100 | 0b00100 | 3 + // | | | + // C | 0b10010 | 0b10000 | 5 + // + // + // The same index is also used to address elements within vector `Strategies` + // and vector `Resource2Groups`. std::vector> Resources; std::vector> Strategies; + // Used to quickly identify groups that own a particular resource unit. + std::vector Resource2Groups; + // Keeps track of which resources are busy, and how many cycles are left // before those become usable again. SmallDenseMap BusyResources; diff --git a/llvm/lib/MCA/HardwareUnits/ResourceManager.cpp b/llvm/lib/MCA/HardwareUnits/ResourceManager.cpp index 6c21b7713307..c7f45fd95424 100644 --- a/llvm/lib/MCA/HardwareUnits/ResourceManager.cpp +++ b/llvm/lib/MCA/HardwareUnits/ResourceManager.cpp @@ -115,10 +115,11 @@ getStrategyFor(const ResourceState &RS) { return std::unique_ptr(nullptr); } -ResourceManager::ResourceManager(const MCSchedModel &SM) { +ResourceManager::ResourceManager(const MCSchedModel &SM) + : Resources(SM.getNumProcResourceKinds()), + Strategies(SM.getNumProcResourceKinds()), + Resource2Groups(SM.getNumProcResourceKinds(), 0) { computeProcResourceMasks(SM, ProcResID2Mask); - Resources.resize(SM.getNumProcResourceKinds()); - Strategies.resize(SM.getNumProcResourceKinds()); for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) { uint64_t Mask = ProcResID2Mask[I]; @@ -127,6 +128,24 @@ ResourceManager::ResourceManager(const MCSchedModel &SM) { llvm::make_unique(*SM.getProcResource(I), I, Mask); Strategies[Index] = getStrategyFor(*Resources[Index]); } + + for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) { + uint64_t Mask = ProcResID2Mask[I]; + unsigned Index = getResourceStateIndex(Mask); + const ResourceState &RS = *Resources[Index]; + if (!RS.isAResourceGroup()) + continue; + + uint64_t GroupMaskIdx = 1ULL << (Index - 1); + Mask -= GroupMaskIdx; + while (Mask) { + // Extract lowest set isolated bit. + uint64_t Unit = Mask & (-Mask); + unsigned IndexUnit = getResourceStateIndex(Unit); + Resource2Groups[IndexUnit] |= GroupMaskIdx; + Mask ^= Unit; + } + } } void ResourceManager::setCustomStrategyImpl(std::unique_ptr S, @@ -179,17 +198,16 @@ void ResourceManager::use(const ResourceRef &RR) { if (RS.isReady()) return; - // Notify to other resources that RR.first is no longer available. - for (std::unique_ptr &Res : Resources) { - ResourceState &Current = *Res; - if (!Current.isAResourceGroup() || Current.getResourceMask() == RR.first) - continue; - - if (Current.containsResource(RR.first)) { - unsigned Index = getResourceStateIndex(Current.getResourceMask()); - Current.markSubResourceAsUsed(RR.first); - Strategies[Index]->used(RR.first); - } + // Notify groups that RR.first is no longer available. + uint64_t Users = Resource2Groups[RSID]; + while (Users) { + // Extract lowest set isolated bit. + unsigned GroupIndex = getResourceStateIndex(Users & (-Users)); + ResourceState &CurrentUser = *Resources[GroupIndex]; + CurrentUser.markSubResourceAsUsed(RR.first); + Strategies[GroupIndex]->used(RR.first); + // Reset lowest set bit. + Users &= Users - 1; } }