1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00

[MCA] Slightly refactor the logic in ResourceManager. NFCI

This patch slightly changes the API in the attempt to simplify resource buffer
queries. It is done in preparation for a patch that will enable support for
macro fusion.

llvm-svn: 368994
This commit is contained in:
Andrea Di Biagio 2019-08-15 12:39:55 +00:00
parent aa6d87ddfb
commit 278dc66e41
7 changed files with 102 additions and 68 deletions

View File

@ -33,8 +33,7 @@ namespace mca {
/// with a buffer size of -1 is always available if it is not reserved.
///
/// Values of type ResourceStateEvent are returned by method
/// ResourceState::isBufferAvailable(), which is used to query the internal
/// state of a resource.
/// ResourceManager::canBeDispatched()
///
/// The naming convention for resource state events is:
/// * Event names start with prefix RS_
@ -263,16 +262,26 @@ public:
/// Returns RS_BUFFER_UNAVAILABLE if there are no available slots.
ResourceStateEvent isBufferAvailable() const;
/// Reserve a slot in the buffer.
void reserveBuffer() {
if (AvailableSlots)
AvailableSlots--;
/// Reserve a buffer slot.
///
/// Returns true if the buffer is not full.
/// It always returns true if BufferSize is set to zero.
bool reserveBuffer() {
if (BufferSize <= 0)
return true;
--AvailableSlots;
assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
return AvailableSlots;
}
/// Release a slot in the buffer.
/// Releases a slot in the buffer.
void releaseBuffer() {
if (BufferSize > 0)
AvailableSlots++;
// Ignore dispatch hazards or invalid buffer sizes.
if (BufferSize <= 0)
return;
++AvailableSlots;
assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
}
@ -351,9 +360,16 @@ class ResourceManager {
// Set of processor resource units that are available during this cycle.
uint64_t AvailableProcResUnits;
// Set of processor resource groups that are currently reserved.
// Set of processor resources that are currently reserved.
uint64_t ReservedResourceGroups;
// Set of unavailable scheduler buffer resources. This is used internally to
// speedup `canBeDispatched()` queries.
uint64_t AvailableBuffers;
// Set of dispatch hazard buffer resources that are currently unavailable.
uint64_t ReservedBuffers;
// Returns the actual resource unit that will be used.
ResourceRef selectPipe(uint64_t ResourceID);
@ -382,17 +398,20 @@ public:
// Returns RS_BUFFER_AVAILABLE if buffered resources are not reserved, and if
// there are enough available slots in the buffers.
ResourceStateEvent canBeDispatched(ArrayRef<uint64_t> Buffers) const;
ResourceStateEvent canBeDispatched(uint64_t ConsumedBuffers) const;
// Return the processor resource identifier associated to this Mask.
unsigned resolveResourceMask(uint64_t Mask) const;
// Consume a slot in every buffered resource from array 'Buffers'. Resource
// units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
void reserveBuffers(ArrayRef<uint64_t> Buffers);
// Acquires a slot from every buffered resource in mask `ConsumedBuffers`.
// Units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
void reserveBuffers(uint64_t ConsumedBuffers);
// Release buffer entries previously allocated by method reserveBuffers.
void releaseBuffers(ArrayRef<uint64_t> Buffers);
// Releases a slot from every buffered resource in mask `ConsumedBuffers`.
// ConsumedBuffers is a bitmask of previously acquired buffers (using method
// `reserveBuffers`). Units that are dispatch hazards (i.e. BufferSize=0) are
// not automatically unreserved by this method.
void releaseBuffers(uint64_t ConsumedBuffers);
// Reserve a processor resource. A reserved resource is not available for
// instruction issue until it is released.

View File

@ -228,6 +228,9 @@ public:
SmallVectorImpl<InstRef> &Ready);
/// Convert a resource mask into a valid llvm processor resource identifier.
///
/// Only the most significant bit of the Mask is used by this method to
/// identify the processor resource.
unsigned getResourceID(uint64_t Mask) const {
return Resources->resolveResourceMask(Mask);
}

View File

@ -352,11 +352,14 @@ struct InstrDesc {
// reports the number of "consumed cycles".
SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
// A list of buffered resources consumed by this instruction.
SmallVector<uint64_t, 4> Buffers;
// A bitmask of used hardware buffers.
uint64_t UsedBuffers;
unsigned UsedProcResUnits;
unsigned UsedProcResGroups;
// A bitmask of used processor resource units.
uint64_t UsedProcResUnits;
// A bitmask of used processor resource groups.
uint64_t UsedProcResGroups;
unsigned MaxLatency;
// Number of MicroOps for this instruction.

View File

@ -114,7 +114,8 @@ ResourceManager::ResourceManager(const MCSchedModel &SM)
Resource2Groups(SM.getNumProcResourceKinds() - 1, 0),
ProcResID2Mask(SM.getNumProcResourceKinds(), 0),
ResIndex2ProcResID(SM.getNumProcResourceKinds() - 1, 0),
ProcResUnitMask(0), ReservedResourceGroups(0) {
ProcResUnitMask(0), ReservedResourceGroups(0),
AvailableBuffers(~0ULL), ReservedBuffers(0) {
computeProcResourceMasks(SM, ProcResID2Mask);
// initialize vector ResIndex2ProcResID.
@ -241,33 +242,41 @@ void ResourceManager::release(const ResourceRef &RR) {
}
ResourceStateEvent
ResourceManager::canBeDispatched(ArrayRef<uint64_t> Buffers) const {
ResourceStateEvent Result = ResourceStateEvent::RS_BUFFER_AVAILABLE;
for (uint64_t Buffer : Buffers) {
ResourceState &RS = *Resources[getResourceStateIndex(Buffer)];
Result = RS.isBufferAvailable();
if (Result != ResourceStateEvent::RS_BUFFER_AVAILABLE)
break;
}
return Result;
ResourceManager::canBeDispatched(uint64_t ConsumedBuffers) const {
if (ConsumedBuffers & ReservedBuffers)
return ResourceStateEvent::RS_RESERVED;
if (ConsumedBuffers & (~AvailableBuffers))
return ResourceStateEvent::RS_BUFFER_UNAVAILABLE;
return ResourceStateEvent::RS_BUFFER_AVAILABLE;
}
void ResourceManager::reserveBuffers(ArrayRef<uint64_t> Buffers) {
for (const uint64_t Buffer : Buffers) {
ResourceState &RS = *Resources[getResourceStateIndex(Buffer)];
void ResourceManager::reserveBuffers(uint64_t ConsumedBuffers) {
while (ConsumedBuffers) {
uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
ResourceState &RS = *Resources[getResourceStateIndex(CurrentBuffer)];
ConsumedBuffers ^= CurrentBuffer;
assert(RS.isBufferAvailable() == ResourceStateEvent::RS_BUFFER_AVAILABLE);
RS.reserveBuffer();
if (!RS.reserveBuffer())
AvailableBuffers ^= CurrentBuffer;
if (RS.isADispatchHazard()) {
assert(!RS.isReserved());
RS.setReserved();
// Reserve this buffer now, and release it once pipeline resources
// consumed by the instruction become available again.
// We do this to simulate an in-order dispatch/issue of instructions.
ReservedBuffers ^= CurrentBuffer;
}
}
}
void ResourceManager::releaseBuffers(ArrayRef<uint64_t> Buffers) {
for (const uint64_t R : Buffers)
Resources[getResourceStateIndex(R)]->releaseBuffer();
void ResourceManager::releaseBuffers(uint64_t ConsumedBuffers) {
AvailableBuffers |= ConsumedBuffers;
while (ConsumedBuffers) {
uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
ResourceState &RS = *Resources[getResourceStateIndex(CurrentBuffer)];
ConsumedBuffers ^= CurrentBuffer;
RS.releaseBuffer();
// Do not unreserve dispatch hazard resource buffers. Wait until all
// pipeline resources have been freed too.
}
}
uint64_t ResourceManager::checkAvailability(const InstrDesc &Desc) const {
@ -322,7 +331,6 @@ void ResourceManager::cycleEvent(SmallVectorImpl<ResourceRef> &ResourcesFreed) {
if (countPopulation(RR.first) == 1)
release(RR);
releaseResource(RR.first);
ResourcesFreed.push_back(RR);
}
@ -336,7 +344,7 @@ void ResourceManager::reserveResource(uint64_t ResourceID) {
const unsigned Index = getResourceStateIndex(ResourceID);
ResourceState &Resource = *Resources[Index];
assert(Resource.isAResourceGroup() && !Resource.isReserved() &&
"Unexpected resource found!");
"Unexpected resource state found!");
Resource.setReserved();
ReservedResourceGroups ^= 1ULL << Index;
}
@ -347,6 +355,9 @@ void ResourceManager::releaseResource(uint64_t ResourceID) {
Resource.clearReserved();
if (Resource.isAResourceGroup())
ReservedResourceGroups ^= 1ULL << Index;
// Now it is safe to release dispatch/issue resources.
if (Resource.isADispatchHazard())
ReservedBuffers ^= 1ULL << Index;
}
} // namespace mca

View File

@ -40,7 +40,7 @@ void Scheduler::dump() const {
Scheduler::Status Scheduler::isAvailable(const InstRef &IR) {
const InstrDesc &Desc = IR.getInstruction()->getDesc();
ResourceStateEvent RSE = Resources->canBeDispatched(Desc.Buffers);
ResourceStateEvent RSE = Resources->canBeDispatched(Desc.UsedBuffers);
HadTokenStall = RSE != RS_BUFFER_AVAILABLE;
switch (RSE) {
@ -106,7 +106,7 @@ void Scheduler::issueInstruction(
bool HasDependentUsers = Inst.hasDependentUsers();
HasDependentUsers |= Inst.isMemOp() && LSU.hasDependentUsers(IR);
Resources->releaseBuffers(Inst.getDesc().Buffers);
Resources->releaseBuffers(Inst.getDesc().UsedBuffers);
issueInstructionImpl(IR, UsedResources);
// Instructions that have been issued during this cycle might have unblocked
// other dependent instructions. Dependent instructions may be issued during
@ -301,7 +301,7 @@ bool Scheduler::mustIssueImmediately(const InstRef &IR) const {
bool Scheduler::dispatch(InstRef &IR) {
Instruction &IS = *IR.getInstruction();
const InstrDesc &Desc = IS.getDesc();
Resources->reserveBuffers(Desc.Buffers);
Resources->reserveBuffers(Desc.UsedBuffers);
// If necessary, reserve queue entries in the load-store unit (LSU).
if (IS.isMemOp())

View File

@ -80,7 +80,7 @@ static void initializeUsedResources(InstrDesc &ID,
if (PR.BufferSize < 0) {
AllInOrderResources = false;
} else {
Buffers.setBit(PRE->ProcResourceIdx);
Buffers.setBit(getResourceStateIndex(Mask));
AnyDispatchHazards |= (PR.BufferSize == 0);
AllInOrderResources &= (PR.BufferSize <= 1);
}
@ -139,9 +139,6 @@ static void initializeUsedResources(InstrDesc &ID,
}
}
ID.UsedProcResUnits = UsedResourceUnits;
ID.UsedProcResGroups = UsedResourceGroups;
// A SchedWrite may specify a number of cycles in which a resource group
// is reserved. For example (on target x86; cpu Haswell):
//
@ -177,20 +174,13 @@ static void initializeUsedResources(InstrDesc &ID,
uint64_t Mask = ProcResourceMasks[I];
if (Mask != SR.first && ((Mask & SR.first) == SR.first))
Buffers.setBit(I);
Buffers.setBit(getResourceStateIndex(Mask));
}
}
// Now set the buffers.
if (unsigned NumBuffers = Buffers.countPopulation()) {
ID.Buffers.resize(NumBuffers);
for (unsigned I = 0, E = NumProcResources; I < E && NumBuffers; ++I) {
if (Buffers[I]) {
--NumBuffers;
ID.Buffers[NumBuffers] = ProcResourceMasks[I];
}
}
}
ID.UsedBuffers = Buffers.getZExtValue();
ID.UsedProcResUnits = UsedResourceUnits;
ID.UsedProcResGroups = UsedResourceGroups;
LLVM_DEBUG({
for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
@ -198,8 +188,12 @@ static void initializeUsedResources(InstrDesc &ID,
<< "Reserved=" << R.second.isReserved() << ", "
<< "#Units=" << R.second.NumUnits << ", "
<< "cy=" << R.second.size() << '\n';
for (const uint64_t R : ID.Buffers)
dbgs() << "\t\tBuffer Mask=" << format_hex(R, 16) << '\n';
uint64_t BufferIDs = ID.UsedBuffers;
while (BufferIDs) {
uint64_t Current = BufferIDs & (-BufferIDs);
dbgs() << "\t\tBuffer Mask=" << format_hex(Current, 16) << '\n';
BufferIDs ^= Current;
}
dbgs() << "\t\t Used Units=" << format_hex(ID.UsedProcResUnits, 16) << '\n';
dbgs() << "\t\tUsed Groups=" << format_hex(ID.UsedProcResGroups, 16)
<< '\n';
@ -493,7 +487,7 @@ Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
return ErrorSuccess();
bool UsesMemory = ID.MayLoad || ID.MayStore;
bool UsesBuffers = !ID.Buffers.empty();
bool UsesBuffers = ID.UsedBuffers;
bool UsesResources = !ID.Resources.empty();
if (!UsesMemory && !UsesBuffers && !UsesResources)
return ErrorSuccess();

View File

@ -269,13 +269,17 @@ void ExecuteStage::notifyInstructionIssued(
void ExecuteStage::notifyReservedOrReleasedBuffers(const InstRef &IR,
bool Reserved) const {
const InstrDesc &Desc = IR.getInstruction()->getDesc();
if (Desc.Buffers.empty())
uint64_t UsedBuffers = IR.getInstruction()->getDesc().UsedBuffers;
if (!UsedBuffers)
return;
SmallVector<unsigned, 4> BufferIDs(Desc.Buffers.begin(), Desc.Buffers.end());
std::transform(Desc.Buffers.begin(), Desc.Buffers.end(), BufferIDs.begin(),
[&](uint64_t Op) { return HWS.getResourceID(Op); });
SmallVector<unsigned, 4> BufferIDs(countPopulation(UsedBuffers), 0);
for (unsigned I = 0, E = BufferIDs.size(); I < E; ++I) {
uint64_t CurrentBufferMask = UsedBuffers & (-UsedBuffers);
BufferIDs[I] = HWS.getResourceID(CurrentBufferMask);
UsedBuffers ^= CurrentBufferMask;
}
if (Reserved) {
for (HWEventListener *Listener : getListeners())
Listener->onReservedBuffers(IR, BufferIDs);