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 : ProcResourceDescIndex(Index), ResourceMask(Mask),
77 BufferSize(
Desc.BufferSize) {
78 ReadyMask = ResourceSizeMask;
79 AvailableSlots = BufferSize == -1 ? 0U :
static_cast<unsigned>(BufferSize);
83bool ResourceState::isReady(
unsigned NumUnits)
const {
84 return (!isReserved() || isADispatchHazard()) &&
89 if (isADispatchHazard() && isReserved())
91 if (!isBuffered() || AvailableSlots)
97void ResourceState::dump()
const {
99 <<
", SZMASK=" <<
format_hex(ResourceSizeMask, 16)
101 <<
", BufferSize=" << BufferSize
102 <<
", AvailableSlots=" << AvailableSlots
107static std::unique_ptr<ResourceStrategy>
109 if (RS.isAResourceGroup() || RS.getNumUnits() > 1)
110 return std::make_unique<DefaultResourceStrategy>(RS.getReadyMask());
111 return std::unique_ptr<ResourceStrategy>(
nullptr);
115 : Resources(
SM.getNumProcResourceKinds() - 1),
116 Strategies(
SM.getNumProcResourceKinds() - 1),
117 Resource2Groups(
SM.getNumProcResourceKinds() - 1, 0),
118 ProcResID2Mask(
SM.getNumProcResourceKinds(), 0),
119 ResIndex2ProcResID(
SM.getNumProcResourceKinds() - 1, 0),
120 ProcResUnitMask(0), ReservedResourceGroups(0), AvailableBuffers(~0ULL),
125 for (
unsigned I = 1,
E =
SM.getNumProcResourceKinds();
I <
E; ++
I) {
127 ResIndex2ProcResID[Index] =
I;
130 for (
unsigned I = 1,
E =
SM.getNumProcResourceKinds();
I <
E; ++
I) {
134 std::make_unique<ResourceState>(*
SM.getProcResource(
I),
I, Mask);
138 for (
unsigned I = 1,
E =
SM.getNumProcResourceKinds();
I <
E; ++
I) {
139 uint64_t
Mask = ProcResID2Mask[
I];
142 if (!
RS.isAResourceGroup()) {
143 ProcResUnitMask |=
Mask;
147 uint64_t GroupMaskIdx = 1ULL <<
Index;
148 Mask -= GroupMaskIdx;
153 Resource2Groups[IndexUnit] |= GroupMaskIdx;
158 AvailableProcResUnits = ProcResUnitMask;
161void ResourceManager::setCustomStrategyImpl(std::unique_ptr<ResourceStrategy> S,
162 uint64_t ResourceMask) {
164 assert(Index < Resources.size() &&
"Invalid processor resource index!");
165 assert(S &&
"Unexpected null strategy in input!");
166 Strategies[
Index] = std::move(S);
169unsigned ResourceManager::resolveResourceMask(uint64_t Mask)
const {
173unsigned ResourceManager::getNumUnits(uint64_t ResourceID)
const {
180ResourceRef ResourceManager::selectPipe(uint64_t ResourceID) {
182 assert(Index < Resources.size() &&
"Invalid resource use!");
183 ResourceState &
RS = *Resources[
Index];
184 assert(
RS.isReady() &&
"No available units to select!");
188 if (!
RS.isAResourceGroup() &&
RS.getNumUnits() == 1)
189 return std::make_pair(ResourceID,
RS.getReadyMask());
191 uint64_t SubResourceID = Strategies[
Index]->select(
RS.getReadyMask());
192 if (
RS.isAResourceGroup())
193 return selectPipe(SubResourceID);
194 return std::make_pair(ResourceID, SubResourceID);
197void ResourceManager::use(
const ResourceRef &RR) {
200 ResourceState &
RS = *Resources[RSID];
201 RS.markSubResourceAsUsed(RR.second);
204 if (
RS.getNumUnits() > 1)
205 Strategies[RSID]->used(RR.second);
212 AvailableProcResUnits ^= RR.first;
215 uint64_t
Users = Resource2Groups[RSID];
219 ResourceState &CurrentUser = *Resources[GroupIndex];
220 CurrentUser.markSubResourceAsUsed(RR.first);
221 Strategies[GroupIndex]->used(RR.first);
227void ResourceManager::release(
const ResourceRef &RR) {
229 ResourceState &
RS = *Resources[RSID];
230 bool WasFullyUsed = !
RS.isReady();
231 RS.releaseSubResource(RR.second);
235 AvailableProcResUnits ^= RR.first;
238 uint64_t
Users = Resource2Groups[RSID];
241 ResourceState &CurrentUser = *Resources[GroupIndex];
242 CurrentUser.releaseSubResource(RR.first);
248ResourceManager::canBeDispatched(uint64_t ConsumedBuffers)
const {
249 if (ConsumedBuffers & ReservedBuffers)
250 return ResourceStateEvent::RS_RESERVED;
251 if (ConsumedBuffers & (~AvailableBuffers))
252 return ResourceStateEvent::RS_BUFFER_UNAVAILABLE;
253 return ResourceStateEvent::RS_BUFFER_AVAILABLE;
256void ResourceManager::reserveBuffers(uint64_t ConsumedBuffers) {
257 while (ConsumedBuffers) {
258 uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
260 ConsumedBuffers ^= CurrentBuffer;
261 assert(
RS.isBufferAvailable() == ResourceStateEvent::RS_BUFFER_AVAILABLE);
262 if (!
RS.reserveBuffer())
263 AvailableBuffers ^= CurrentBuffer;
264 if (
RS.isADispatchHazard()) {
268 ReservedBuffers ^= CurrentBuffer;
273void ResourceManager::releaseBuffers(uint64_t ConsumedBuffers) {
274 AvailableBuffers |= ConsumedBuffers;
275 while (ConsumedBuffers) {
276 uint64_t CurrentBuffer = ConsumedBuffers & (-ConsumedBuffers);
278 ConsumedBuffers ^= CurrentBuffer;
285uint64_t ResourceManager::checkAvailability(
const InstrDesc &
Desc)
const {
286 uint64_t BusyResourceMask = 0;
287 uint64_t ConsumedResourceMask = 0;
288 DenseMap<uint64_t, unsigned> AvailableUnits;
290 for (
const std::pair<uint64_t, ResourceUsage> &
E :
Desc.Resources) {
291 unsigned NumUnits =
E.second.isReserved() ? 0
U :
E.second.NumUnits;
293 if (!
RS.isReady(NumUnits)) {
294 BusyResourceMask |=
E.first;
298 if (
Desc.HasPartiallyOverlappingGroups && !
RS.isAResourceGroup()) {
300 NumAvailableUnits -= NumUnits;
301 AvailableUnits[
E.first] = NumAvailableUnits;
302 if (!NumAvailableUnits)
303 ConsumedResourceMask |=
E.first;
307 BusyResourceMask &= ProcResUnitMask;
308 if (BusyResourceMask)
309 return BusyResourceMask;
311 BusyResourceMask =
Desc.UsedProcResGroups & ReservedResourceGroups;
312 if (!
Desc.HasPartiallyOverlappingGroups || BusyResourceMask)
313 return BusyResourceMask;
317 for (
const std::pair<uint64_t, ResourceUsage> &
E :
Desc.Resources) {
319 if (!
E.second.isReserved() &&
RS.isAResourceGroup()) {
320 uint64_t ReadyMask =
RS.getReadyMask() & ~ConsumedResourceMask;
322 BusyResourceMask |=
RS.getReadyMask();
328 auto [it,
Inserted] = AvailableUnits.try_emplace(ResourceMask);
331 unsigned NumUnits =
llvm::popcount(Resources[Index]->getReadyMask());
332 it->second = NumUnits;
336 BusyResourceMask |= it->first;
342 ConsumedResourceMask |= it->first;
346 return BusyResourceMask;
349void ResourceManager::issueInstructionImpl(
359 using ResourceWithUsage = std::pair<uint64_t, ResourceUsage>;
361 for (
const ResourceWithUsage &R :
Desc.Resources) {
362 const CycleSegment &CS =
R.second.CS;
364 releaseResource(
R.first);
368 assert(CS.begin() == 0 &&
"Invalid {Start, End} cycles!");
369 if (
R.second.isReserved()) {
373 reserveResource(
R.first);
379 if (
RS.isAResourceGroup() &&
RS.getNumReadyUnits() > 1) {
380 Worklist.push_back(R);
386 BusyResources[
Pipe] += CS.size();
387 Pipes.emplace_back(std::make_pair(Pipe, ReleaseAtCycles(CS.size())));
397 while (!Worklist.empty()) {
398 sort(Worklist, [&](
const ResourceWithUsage &Lhs,
399 const ResourceWithUsage &Rhs) {
402 uint64_t LhsReadyUnits = LhsRS.getNumReadyUnits();
403 uint64_t RhsReadyUnits = RhsRS.getNumReadyUnits();
404 if (LhsReadyUnits == RhsReadyUnits)
405 return Lhs.first < Rhs.first;
406 return LhsReadyUnits < RhsReadyUnits;
411 for (
unsigned I = 0,
E = Worklist.size();
I <
E; ++
I) {
412 const auto &Elt = Worklist[
I];
415 if (
I == 0 ||
RS.getNumReadyUnits() == 1) {
418 const CycleSegment &CS = Elt.second.CS;
419 BusyResources[
Pipe] += CS.size();
420 Pipes.emplace_back(std::make_pair(Pipe, ReleaseAtCycles(CS.size())));
424 NewWorklist.push_back(Elt);
427 swap(NewWorklist, Worklist);
431void ResourceManager::fastIssueInstruction(
433 for (
const std::pair<uint64_t, ResourceUsage> &R :
Desc.Resources) {
434 const CycleSegment &CS =
R.second.CS;
436 releaseResource(
R.first);
440 assert(CS.begin() == 0 &&
"Invalid {Start, End} cycles!");
441 if (!
R.second.isReserved()) {
444 BusyResources[
Pipe] += CS.size();
445 Pipes.emplace_back(std::pair<ResourceRef, ReleaseAtCycles>(
446 Pipe, ReleaseAtCycles(CS.size())));
451 reserveResource(
R.first);
458 for (std::pair<ResourceRef, unsigned> &BR : BusyResources) {
467 releaseResource(RR.first);
468 ResourcesFreed.push_back(RR);
472 for (
const ResourceRef &RF : ResourcesFreed)
473 BusyResources.erase(RF);
476void ResourceManager::reserveResource(uint64_t ResourceID) {
478 ResourceState &Resource = *Resources[
Index];
479 assert(Resource.isAResourceGroup() && !Resource.isReserved() &&
480 "Unexpected resource state found!");
481 Resource.setReserved();
482 ReservedResourceGroups ^= 1ULL <<
Index;
485void ResourceManager::releaseResource(uint64_t ResourceID) {
487 ResourceState &Resource = *Resources[
Index];
488 Resource.clearReserved();
489 if (Resource.isAResourceGroup())
490 ReservedResourceGroups ^= 1ULL <<
Index;
492 if (Resource.isADispatchHazard())
493 ReservedBuffers ^= 1ULL <<
Index;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
@ 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
static constexpr unsigned SM(unsigned Version)
The classes here represent processor resource units and their management strategy.
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.
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.