mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 05:46:06 +00:00
Revert "[MISched] Introduce and use ResourceSegments."
Reverted because it produces the following builbot failure at https://lab.llvm.org/buildbot#builders/9/builds/27319: /b/ml-opt-rel-x86-64-b1/llvm-project/llvm/unittests/CodeGen/SchedBoundary.cpp: In member function ‘virtual void ResourceSegments_getFirstAvailableAtFromBottom_empty_Test::TestBody()’: /b/ml-opt-rel-x86-64-b1/llvm-project/llvm/unittests/CodeGen/SchedBoundary.cpp:395:31: error: call of overloaded ‘ResourceSegments(<brace-enclosed initializer list>)’ is ambiguous 395 | auto X = ResourceSegments({}); | ^ This reverts commit dc312f0331309692e8d6e06e93b3492b6a40989f.
This commit is contained in:
parent
6680d60dd6
commit
f1d1ca3d74
@ -92,7 +92,6 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -611,222 +610,6 @@ struct SchedRemainder {
|
||||
void init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel);
|
||||
};
|
||||
|
||||
/// ResourceSegments are a collection of intervals closed on the
|
||||
/// left and opened on the right:
|
||||
///
|
||||
/// list{ [a1, b1), [a2, b2), ..., [a_N, b_N) }
|
||||
///
|
||||
/// The collection has the following properties:
|
||||
///
|
||||
/// 1. The list is ordered: a_i < b_i and b_i < a_(i+1)
|
||||
///
|
||||
/// 2. The intervals in the collection do not intersect each other.
|
||||
///
|
||||
/// A \ref ResourceSegments instance represents the cycle
|
||||
/// reservation history of the instance of and individual resource.
|
||||
class ResourceSegments {
|
||||
public:
|
||||
/// Represents an interval of discrete integer values closed on
|
||||
/// the left and open on the right: [a, b).
|
||||
typedef std::pair<int64_t, int64_t> IntervalTy;
|
||||
|
||||
/// Adds an interval [a, b) to the collection of the instance.
|
||||
///
|
||||
/// When adding [a, b[ to the collection, the operation merges the
|
||||
/// adjacent intervals. For example
|
||||
///
|
||||
/// 0 1 2 3 4 5 6 7 8 9 10
|
||||
/// [-----) [--) [--)
|
||||
/// + [--)
|
||||
/// = [-----------) [--)
|
||||
///
|
||||
/// To be able to debug duplicate resource usage, the function has
|
||||
/// assertion that checks that no interval should be added if it
|
||||
/// overlaps any of the intervals in the collection. We can
|
||||
/// require this because by definition a \ref ResourceSegments is
|
||||
/// attached only to an individual resource instance.
|
||||
void add(IntervalTy A, const unsigned CutOff = 10);
|
||||
|
||||
public:
|
||||
/// Checks whether intervals intersect.
|
||||
static bool intersects(IntervalTy A, IntervalTy B);
|
||||
|
||||
/// These function return the interval used by a resource in bottom and top
|
||||
/// scheduling.
|
||||
///
|
||||
/// Consider an instruction that uses resources X0, X1 and X2 as follows:
|
||||
///
|
||||
/// X0 X1 X1 X2 +--------+------------+------+
|
||||
/// |Resource|StartAtCycle|Cycles|
|
||||
/// +--------+------------+------+
|
||||
/// | X0 | 0 | 1 |
|
||||
/// +--------+------------+------+
|
||||
/// | X1 | 1 | 3 |
|
||||
/// +--------+------------+------+
|
||||
/// | X2 | 3 | 4 |
|
||||
/// +--------+------------+------+
|
||||
///
|
||||
/// If we can schedule the instruction at cycle C, we need to
|
||||
/// compute the interval of the resource as follows:
|
||||
///
|
||||
/// # TOP DOWN SCHEDULING
|
||||
///
|
||||
/// Cycles scheduling flows to the _right_, in the same direction
|
||||
/// of time.
|
||||
///
|
||||
/// C 1 2 3 4 5 ...
|
||||
/// ------|------|------|------|------|------|----->
|
||||
/// X0 X1 X1 X2 ---> direction of time
|
||||
/// X0 [C, C+1)
|
||||
/// X1 [C+1, C+3)
|
||||
/// X2 [C+3, C+4)
|
||||
///
|
||||
/// Therefore, the formula to compute the interval for a resource
|
||||
/// of an instruction that can be scheduled at cycle C in top-down
|
||||
/// scheduling is:
|
||||
///
|
||||
/// [C+StartAtCycle, C+Cycles)
|
||||
///
|
||||
///
|
||||
/// # BOTTOM UP SCHEDULING
|
||||
///
|
||||
/// Cycles scheduling flows to the _left_, in opposite direction
|
||||
/// of time.
|
||||
///
|
||||
/// In bottom up scheduling, the scheduling happens in opposite
|
||||
/// direction to the execution of the cycles of the
|
||||
/// instruction. When the instruction is scheduled at cycle `C`,
|
||||
/// the resources are allocated in the past relative to `C`:
|
||||
///
|
||||
/// 2 1 C -1 -2 -3 -4 -5 ...
|
||||
/// <-----|------|------|------|------|------|------|------|---
|
||||
/// X0 X1 X1 X2 ---> direction of time
|
||||
/// X0 (C+1, C]
|
||||
/// X1 (C, C-2]
|
||||
/// X2 (C-2, C-3]
|
||||
///
|
||||
/// Therefore, the formula to compute the interval for a resource
|
||||
/// of an instruction that can be scheduled at cycle C in bottom-up
|
||||
/// scheduling is:
|
||||
///
|
||||
/// [C-Cycle+1, C-StartAtCycle+1)
|
||||
///
|
||||
///
|
||||
/// NOTE: In both cases, the number of cycles booked by a
|
||||
/// resources is the value (Cycle - StartAtCycles).
|
||||
static IntervalTy getResourceIntervalBottom(unsigned C, unsigned StartAtCycle,
|
||||
unsigned Cycle) {
|
||||
return std::make_pair<long, long>((long)C - (long)Cycle + 1L,
|
||||
(long)C - (long)StartAtCycle + 1L);
|
||||
}
|
||||
static IntervalTy getResourceIntervalTop(unsigned C, unsigned StartAtCycle,
|
||||
unsigned Cycle) {
|
||||
return std::make_pair<long, long>((long)C + (long)StartAtCycle,
|
||||
(long)C + (long)Cycle);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Finds the first cycle in which a resource can be allocated.
|
||||
///
|
||||
/// The function uses the \param IntervalBuider [*] to build a
|
||||
/// resource interval [a, b[ out of the input parameters \param
|
||||
/// CurrCycle, \param StartAtCycle and \param Cycle.
|
||||
///
|
||||
/// The function then loops through the intervals in the ResourceSegments
|
||||
/// and shifts the interval [a, b[ and the ReturnCycle to the
|
||||
/// right until there is no intersection between the intervals of
|
||||
/// the \ref ResourceSegments instance and the new shifted [a, b[. When
|
||||
/// this condition is met, the ReturnCycle (which
|
||||
/// correspond to the cycle in which the resource can be
|
||||
/// allocated) is returned.
|
||||
///
|
||||
/// c = CurrCycle in input
|
||||
/// c 1 2 3 4 5 6 7 8 9 10 ... ---> (time
|
||||
/// flow)
|
||||
/// ResourceSegments... [---) [-------) [-----------)
|
||||
/// c [1 3[ -> StartAtCycle=1, Cycles=3
|
||||
/// ++c [1 3)
|
||||
/// ++c [1 3)
|
||||
/// ++c [1 3)
|
||||
/// ++c [1 3)
|
||||
/// ++c [1 3) ---> returns c
|
||||
/// incremented by 5 (c+5)
|
||||
///
|
||||
///
|
||||
/// Notice that for bottom-up scheduling the diagram is slightly
|
||||
/// different because the current cycle c is always on the right
|
||||
/// of the interval [a, b) (see \ref
|
||||
/// `getResourceIntervalBottom`). This is because the cycle
|
||||
/// increments for bottom-up scheduling moved in the direction
|
||||
/// opposite to the direction of time:
|
||||
///
|
||||
/// --------> direction of time.
|
||||
/// XXYZZZ (resource usage)
|
||||
/// --------> direction of top-down execution cycles.
|
||||
/// <-------- direction of bottom-up execution cycles.
|
||||
///
|
||||
/// Even though bottom-up scheduling moves against the flow of
|
||||
/// time, the algorithm used to find the first free slot in between
|
||||
/// intervals is the same as for top-down scheduling.
|
||||
///
|
||||
/// [*] See \ref `getResourceIntervalTop` and
|
||||
/// \ref `getResourceIntervalBottom` to see how such resource intervals
|
||||
/// are built.
|
||||
unsigned
|
||||
getFirstAvailableAt(unsigned CurrCycle, unsigned StartAtCycle, unsigned Cycle,
|
||||
std::function<IntervalTy(unsigned, unsigned, unsigned)>
|
||||
IntervalBuilder) const;
|
||||
|
||||
public:
|
||||
/// getFirstAvailableAtFromBottom and getFirstAvailableAtFromTop
|
||||
/// should be merged in a single function in which a function that
|
||||
/// creates the `NewInterval` is passed as a parameter.
|
||||
unsigned getFirstAvailableAtFromBottom(unsigned CurrCycle,
|
||||
unsigned StartAtCycle,
|
||||
unsigned Cycle) const {
|
||||
return getFirstAvailableAt(CurrCycle, StartAtCycle, Cycle,
|
||||
getResourceIntervalBottom);
|
||||
}
|
||||
unsigned getFirstAvailableAtFromTop(unsigned CurrCycle, unsigned StartAtCycle,
|
||||
unsigned Cycle) const {
|
||||
return getFirstAvailableAt(CurrCycle, StartAtCycle, Cycle,
|
||||
getResourceIntervalTop);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<IntervalTy> _Intervals;
|
||||
/// Merge all adjacent intervals in the collection. For all pairs
|
||||
/// of adjacient intervals, it performs [a, b) + [b, c) -> [a, c).
|
||||
///
|
||||
/// Before performing the merge operation, the intervals are
|
||||
/// sorted with \ref sort_predicate.
|
||||
void sortAndMerge();
|
||||
|
||||
public:
|
||||
// constructor for empty set
|
||||
explicit ResourceSegments(){};
|
||||
bool empty() const { return _Intervals.empty(); }
|
||||
explicit ResourceSegments(std::list<IntervalTy> Intervals)
|
||||
: _Intervals(Intervals) {
|
||||
sortAndMerge();
|
||||
}
|
||||
|
||||
friend bool operator==(const ResourceSegments &c1,
|
||||
const ResourceSegments &c2) {
|
||||
return c1._Intervals == c2._Intervals;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
|
||||
const ResourceSegments &Segments) {
|
||||
os << "{ ";
|
||||
for (auto p : Segments._Intervals)
|
||||
os << "[" << p.first << ", " << p.second << "), ";
|
||||
os << "}\n";
|
||||
return os;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Each Scheduling boundary is associated with ready queues. It tracks the
|
||||
/// current cycle in the direction of movement, and maintains the state
|
||||
/// of "hazards" and other interlocks at the current cycle.
|
||||
@ -892,14 +675,12 @@ private:
|
||||
// Is the scheduled region resource limited vs. latency limited.
|
||||
bool IsResourceLimited;
|
||||
|
||||
public:
|
||||
private:
|
||||
/// Record how resources have been allocated across the cycles of
|
||||
/// the execution.
|
||||
std::map<unsigned, ResourceSegments> ReservedResourceSegments;
|
||||
std::vector<unsigned> ReservedCycles;
|
||||
/// For each PIdx, stores first index into ReservedResourceSegments that
|
||||
/// corresponds to it.
|
||||
// Record the highest cycle at which each resource has been reserved by a
|
||||
// scheduled instruction.
|
||||
SmallVector<unsigned, 16> ReservedCycles;
|
||||
|
||||
/// For each PIdx, stores first index into ReservedCycles that corresponds to
|
||||
/// it.
|
||||
///
|
||||
/// For example, consider the following 3 resources (ResourceCount =
|
||||
/// 3):
|
||||
@ -915,14 +696,12 @@ private:
|
||||
/// +------------+--------+
|
||||
///
|
||||
/// In this case, the total number of resource instances is 6. The
|
||||
/// vector \ref ReservedResourceSegments will have a slot for each instance.
|
||||
/// The vector \ref ReservedCyclesIndex will track at what index the first
|
||||
/// vector \ref ReservedCycles will have a slot for each instance. The
|
||||
/// vector \ref ReservedCyclesIndex will track at what index the first
|
||||
/// instance of the resource is found in the vector of \ref
|
||||
/// ReservedResourceSegments:
|
||||
///
|
||||
/// Indexes of instances in
|
||||
/// ReservedResourceSegments
|
||||
/// ReservedCycles:
|
||||
///
|
||||
/// Indexes of instances in ReservedCycles
|
||||
/// 0 1 2 3 4 5
|
||||
/// ReservedCyclesIndex[0] = 0; [X0, X1,
|
||||
/// ReservedCyclesIndex[1] = 2; Y0, Y1, Y2
|
||||
@ -1008,13 +787,11 @@ public:
|
||||
unsigned getLatencyStallCycles(SUnit *SU);
|
||||
|
||||
unsigned getNextResourceCycleByInstance(unsigned InstanceIndex,
|
||||
unsigned Cycles,
|
||||
unsigned StartAtCycle);
|
||||
unsigned Cycles);
|
||||
|
||||
std::pair<unsigned, unsigned> getNextResourceCycle(const MCSchedClassDesc *SC,
|
||||
unsigned PIdx,
|
||||
unsigned Cycles,
|
||||
unsigned StartAtCycle);
|
||||
unsigned Cycles);
|
||||
|
||||
bool isUnbufferedGroup(unsigned PIdx) const {
|
||||
return SchedModel->getProcResource(PIdx)->SubUnitsIdxBegin &&
|
||||
@ -1043,8 +820,7 @@ public:
|
||||
void incExecutedResources(unsigned PIdx, unsigned Count);
|
||||
|
||||
unsigned countResource(const MCSchedClassDesc *SC, unsigned PIdx,
|
||||
unsigned Cycles, unsigned ReadyCycle,
|
||||
unsigned StartAtCycle);
|
||||
unsigned Cycles, unsigned ReadyCycle);
|
||||
|
||||
void bumpNode(SUnit *SU);
|
||||
|
||||
|
@ -90,7 +90,7 @@ public:
|
||||
bool hasInstrSchedModelOrItineraries() const {
|
||||
return hasInstrSchedModel() || hasInstrItineraries();
|
||||
}
|
||||
bool enableIntervals() const { return SchedModel.EnableIntervals; }
|
||||
|
||||
/// Identify the processor corresponding to the current subtarget.
|
||||
unsigned getProcessorID() const { return SchedModel.getProcessorID(); }
|
||||
|
||||
|
@ -58,17 +58,10 @@ struct MCProcResourceDesc {
|
||||
}
|
||||
};
|
||||
|
||||
/// Identify one of the processor resource kinds consumed by a
|
||||
/// particular scheduling class for the specified number of cycles.
|
||||
/// TODO: consider renaming the field `StartAtCycle` and `Cycles` to
|
||||
/// `AcquireAtCycle` and `ReleaseAtCycle` respectively, to stress the
|
||||
/// fact that resource allocation is now represented as an interval,
|
||||
/// relatively to the issue cycle of the instruction.
|
||||
/// Identify one of the processor resource kinds consumed by a particular
|
||||
/// scheduling class for the specified number of cycles.
|
||||
struct MCWriteProcResEntry {
|
||||
uint16_t ProcResourceIdx;
|
||||
/// Cycle at which the resource will be released by an instruction,
|
||||
/// relatively to the cycle in which the instruction is issued
|
||||
/// (assuming no stalls inbetween).
|
||||
uint16_t Cycles;
|
||||
/// Cycle at which the resource will be grabbed by an instruction,
|
||||
/// relatively to the cycle in which the instruction is issued
|
||||
@ -313,11 +306,6 @@ struct MCSchedModel {
|
||||
|
||||
bool CompleteModel;
|
||||
|
||||
// Tells the MachineScheduler whether or not to track resource usage
|
||||
// using intervals via ResourceSegments (see
|
||||
// llvm/include/llvm/CodeGen/MachineScheduler.h).
|
||||
bool EnableIntervals;
|
||||
|
||||
unsigned ProcID;
|
||||
const MCProcResourceDesc *ProcResourceTable;
|
||||
const MCSchedClassDesc *SchedClassTable;
|
||||
|
@ -117,11 +117,6 @@ class SchedMachineModel {
|
||||
list<Predicate> UnsupportedFeatures = [];
|
||||
|
||||
bit NoModel = false; // Special tag to indicate missing machine model.
|
||||
|
||||
// Tells the MachineScheduler whether or not to track resource usage
|
||||
// using intervals via ResourceSegments (see
|
||||
// llvm/include/llvm/CodeGen/MachineScheduler.h).
|
||||
bit EnableIntervals = false;
|
||||
}
|
||||
|
||||
def NoSchedModel : SchedMachineModel {
|
||||
|
@ -162,10 +162,6 @@ static cl::opt<unsigned>
|
||||
cl::init(5));
|
||||
#endif
|
||||
|
||||
static cl::opt<unsigned>
|
||||
MIResourceCutOff("misched-resource-cutoff", cl::Hidden,
|
||||
cl::desc("Number of intervals to track"), cl::init(10));
|
||||
|
||||
// DAG subtrees must have at least this many nodes.
|
||||
static const unsigned MinSubtreeSize = 8;
|
||||
|
||||
@ -2172,7 +2168,6 @@ void SchedBoundary::reset() {
|
||||
ZoneCritResIdx = 0;
|
||||
IsResourceLimited = false;
|
||||
ReservedCycles.clear();
|
||||
ReservedResourceSegments.clear();
|
||||
ReservedCyclesIndex.clear();
|
||||
ResourceGroupSubUnitMasks.clear();
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
@ -2201,8 +2196,7 @@ init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) {
|
||||
PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
|
||||
unsigned PIdx = PI->ProcResourceIdx;
|
||||
unsigned Factor = SchedModel->getResourceFactor(PIdx);
|
||||
assert(PI->Cycles >= PI->StartAtCycle);
|
||||
RemainingCounts[PIdx] += (Factor * (PI->Cycles - PI->StartAtCycle));
|
||||
RemainingCounts[PIdx] += (Factor * PI->Cycles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2255,17 +2249,7 @@ unsigned SchedBoundary::getLatencyStallCycles(SUnit *SU) {
|
||||
/// Compute the next cycle at which the given processor resource unit
|
||||
/// can be scheduled.
|
||||
unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx,
|
||||
unsigned Cycles,
|
||||
unsigned StartAtCycle) {
|
||||
if (SchedModel && SchedModel->enableIntervals()) {
|
||||
if (isTop())
|
||||
return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromTop(
|
||||
CurrCycle, StartAtCycle, Cycles);
|
||||
|
||||
return ReservedResourceSegments[InstanceIdx].getFirstAvailableAtFromBottom(
|
||||
CurrCycle, StartAtCycle, Cycles);
|
||||
}
|
||||
|
||||
unsigned Cycles) {
|
||||
unsigned NextUnreserved = ReservedCycles[InstanceIdx];
|
||||
// If this resource has never been used, always return cycle zero.
|
||||
if (NextUnreserved == InvalidCycle)
|
||||
@ -2281,7 +2265,7 @@ unsigned SchedBoundary::getNextResourceCycleByInstance(unsigned InstanceIdx,
|
||||
/// instance in the reserved cycles vector.
|
||||
std::pair<unsigned, unsigned>
|
||||
SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
|
||||
unsigned Cycles, unsigned StartAtCycle) {
|
||||
unsigned Cycles) {
|
||||
|
||||
unsigned MinNextUnreserved = InvalidCycle;
|
||||
unsigned InstanceIdx = 0;
|
||||
@ -2310,7 +2294,7 @@ SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
|
||||
for (unsigned I = 0, End = NumberOfInstances; I < End; ++I) {
|
||||
unsigned NextUnreserved, NextInstanceIdx;
|
||||
std::tie(NextUnreserved, NextInstanceIdx) =
|
||||
getNextResourceCycle(SC, SubUnits[I], Cycles, StartAtCycle);
|
||||
getNextResourceCycle(SC, SubUnits[I], Cycles);
|
||||
if (MinNextUnreserved > NextUnreserved) {
|
||||
InstanceIdx = NextInstanceIdx;
|
||||
MinNextUnreserved = NextUnreserved;
|
||||
@ -2321,8 +2305,7 @@ SchedBoundary::getNextResourceCycle(const MCSchedClassDesc *SC, unsigned PIdx,
|
||||
|
||||
for (unsigned I = StartIndex, End = StartIndex + NumberOfInstances; I < End;
|
||||
++I) {
|
||||
unsigned NextUnreserved =
|
||||
getNextResourceCycleByInstance(I, Cycles, StartAtCycle);
|
||||
unsigned NextUnreserved = getNextResourceCycleByInstance(I, Cycles);
|
||||
if (MinNextUnreserved > NextUnreserved) {
|
||||
InstanceIdx = I;
|
||||
MinNextUnreserved = NextUnreserved;
|
||||
@ -2372,10 +2355,8 @@ bool SchedBoundary::checkHazard(SUnit *SU) {
|
||||
SchedModel->getWriteProcResEnd(SC))) {
|
||||
unsigned ResIdx = PE.ProcResourceIdx;
|
||||
unsigned Cycles = PE.Cycles;
|
||||
unsigned StartAtCycle = PE.StartAtCycle;
|
||||
unsigned NRCycle, InstanceIdx;
|
||||
std::tie(NRCycle, InstanceIdx) =
|
||||
getNextResourceCycle(SC, ResIdx, Cycles, StartAtCycle);
|
||||
std::tie(NRCycle, InstanceIdx) = getNextResourceCycle(SC, ResIdx, Cycles);
|
||||
if (NRCycle > CurrCycle) {
|
||||
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
|
||||
MaxObservedStall = std::max(Cycles, MaxObservedStall);
|
||||
@ -2526,10 +2507,9 @@ void SchedBoundary::incExecutedResources(unsigned PIdx, unsigned Count) {
|
||||
/// \return the next cycle at which the instruction may execute without
|
||||
/// oversubscribing resources.
|
||||
unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx,
|
||||
unsigned Cycles, unsigned NextCycle,
|
||||
unsigned StartAtCycle) {
|
||||
unsigned Cycles, unsigned NextCycle) {
|
||||
unsigned Factor = SchedModel->getResourceFactor(PIdx);
|
||||
unsigned Count = Factor * (Cycles - StartAtCycle);
|
||||
unsigned Count = Factor * Cycles;
|
||||
LLVM_DEBUG(dbgs() << " " << SchedModel->getResourceName(PIdx) << " +"
|
||||
<< Cycles << "x" << Factor << "u\n");
|
||||
|
||||
@ -2549,8 +2529,7 @@ unsigned SchedBoundary::countResource(const MCSchedClassDesc *SC, unsigned PIdx,
|
||||
}
|
||||
// For reserved resources, record the highest cycle using the resource.
|
||||
unsigned NextAvailable, InstanceIdx;
|
||||
std::tie(NextAvailable, InstanceIdx) =
|
||||
getNextResourceCycle(SC, PIdx, Cycles, StartAtCycle);
|
||||
std::tie(NextAvailable, InstanceIdx) = getNextResourceCycle(SC, PIdx, Cycles);
|
||||
if (NextAvailable > CurrCycle) {
|
||||
LLVM_DEBUG(dbgs() << " Resource conflict: "
|
||||
<< SchedModel->getResourceName(PIdx)
|
||||
@ -2629,8 +2608,8 @@ void SchedBoundary::bumpNode(SUnit *SU) {
|
||||
for (TargetSchedModel::ProcResIter
|
||||
PI = SchedModel->getWriteProcResBegin(SC),
|
||||
PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
|
||||
unsigned RCycle = countResource(SC, PI->ProcResourceIdx, PI->Cycles,
|
||||
NextCycle, PI->StartAtCycle);
|
||||
unsigned RCycle =
|
||||
countResource(SC, PI->ProcResourceIdx, PI->Cycles, NextCycle);
|
||||
if (RCycle > NextCycle)
|
||||
NextCycle = RCycle;
|
||||
}
|
||||
@ -2644,33 +2623,14 @@ void SchedBoundary::bumpNode(SUnit *SU) {
|
||||
PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
|
||||
unsigned PIdx = PI->ProcResourceIdx;
|
||||
if (SchedModel->getProcResource(PIdx)->BufferSize == 0) {
|
||||
|
||||
if (SchedModel && SchedModel->enableIntervals()) {
|
||||
unsigned ReservedUntil, InstanceIdx;
|
||||
std::tie(ReservedUntil, InstanceIdx) =
|
||||
getNextResourceCycle(SC, PIdx, PI->Cycles, PI->StartAtCycle);
|
||||
if (isTop()) {
|
||||
ReservedResourceSegments[InstanceIdx].add(
|
||||
ResourceSegments::getResourceIntervalTop(
|
||||
NextCycle, PI->StartAtCycle, PI->Cycles),
|
||||
MIResourceCutOff);
|
||||
} else {
|
||||
ReservedResourceSegments[InstanceIdx].add(
|
||||
ResourceSegments::getResourceIntervalBottom(
|
||||
NextCycle, PI->StartAtCycle, PI->Cycles),
|
||||
MIResourceCutOff);
|
||||
}
|
||||
} else {
|
||||
|
||||
unsigned ReservedUntil, InstanceIdx;
|
||||
std::tie(ReservedUntil, InstanceIdx) =
|
||||
getNextResourceCycle(SC, PIdx, 0, PI->StartAtCycle);
|
||||
if (isTop()) {
|
||||
ReservedCycles[InstanceIdx] =
|
||||
std::max(ReservedUntil, NextCycle + PI->Cycles);
|
||||
} else
|
||||
ReservedCycles[InstanceIdx] = NextCycle;
|
||||
}
|
||||
unsigned ReservedUntil, InstanceIdx;
|
||||
std::tie(ReservedUntil, InstanceIdx) =
|
||||
getNextResourceCycle(SC, PIdx, 0);
|
||||
if (isTop()) {
|
||||
ReservedCycles[InstanceIdx] =
|
||||
std::max(ReservedUntil, NextCycle + PI->Cycles);
|
||||
} else
|
||||
ReservedCycles[InstanceIdx] = NextCycle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2810,14 +2770,8 @@ LLVM_DUMP_METHOD void SchedBoundary::dumpReservedCycles() const {
|
||||
const unsigned NumUnits = SchedModel->getProcResource(ResIdx)->NumUnits;
|
||||
std::string ResName = SchedModel->getResourceName(ResIdx);
|
||||
for (unsigned UnitIdx = 0; UnitIdx < NumUnits; ++UnitIdx) {
|
||||
dbgs() << ResName << "(" << UnitIdx << ") = ";
|
||||
if (SchedModel && SchedModel->enableIntervals()) {
|
||||
if (ReservedResourceSegments.count(StartIdx + UnitIdx))
|
||||
dbgs() << ReservedResourceSegments.at(StartIdx + UnitIdx);
|
||||
else
|
||||
dbgs() << "{ }\n";
|
||||
} else
|
||||
dbgs() << ReservedCycles[StartIdx + UnitIdx] << "\n";
|
||||
dbgs() << ResName << "(" << UnitIdx
|
||||
<< ") = " << ReservedCycles[StartIdx + UnitIdx] << "\n";
|
||||
}
|
||||
StartIdx += NumUnits;
|
||||
}
|
||||
@ -4184,102 +4138,3 @@ void ScheduleDAGMI::viewGraph(const Twine &Name, const Twine &Title) {
|
||||
void ScheduleDAGMI::viewGraph() {
|
||||
viewGraph(getDAGName(), "Scheduling-Units Graph for " + getDAGName());
|
||||
}
|
||||
|
||||
/// Sort predicate for the intervals stored in an instance of
|
||||
/// ResourceSegments. Intervals are always disjoint (no intersection
|
||||
/// for any pairs of intervals), therefore we can sort the totality of
|
||||
/// the intervals by looking only at the left boundary.
|
||||
static bool sortIntervals(const ResourceSegments::IntervalTy &A,
|
||||
const ResourceSegments::IntervalTy &B) {
|
||||
return A.first < B.first;
|
||||
}
|
||||
|
||||
unsigned ResourceSegments::getFirstAvailableAt(
|
||||
unsigned CurrCycle, unsigned StartAtCycle, unsigned Cycle,
|
||||
std::function<ResourceSegments::IntervalTy(unsigned, unsigned, unsigned)>
|
||||
IntervalBuilder) const {
|
||||
assert(std::is_sorted(std::begin(_Intervals), std::end(_Intervals),
|
||||
sortIntervals) &&
|
||||
"Cannot execute on an un-sorted set of intervals.");
|
||||
unsigned RetCycle = CurrCycle;
|
||||
ResourceSegments::IntervalTy NewInterval =
|
||||
IntervalBuilder(RetCycle, StartAtCycle, Cycle);
|
||||
for (auto &Interval : _Intervals) {
|
||||
if (!intersects(NewInterval, Interval))
|
||||
continue;
|
||||
|
||||
// Move the interval right next to the top of the one it
|
||||
// intersects.
|
||||
assert(Interval.second > NewInterval.first &&
|
||||
"Invalid intervals configuration.");
|
||||
RetCycle += (unsigned)Interval.second - (unsigned)NewInterval.first;
|
||||
NewInterval = IntervalBuilder(RetCycle, StartAtCycle, Cycle);
|
||||
}
|
||||
return RetCycle;
|
||||
}
|
||||
|
||||
void ResourceSegments::add(ResourceSegments::IntervalTy A,
|
||||
const unsigned CutOff) {
|
||||
using IntervalTy = ResourceSegments::IntervalTy;
|
||||
assert(A.first < A.second && "Cannot add empty resource usage");
|
||||
assert(CutOff > 0 && "0-size interval history has no use.");
|
||||
assert(all_of(_Intervals,
|
||||
[&A](const IntervalTy &Interval) -> bool {
|
||||
return !intersects(A, Interval);
|
||||
}) &&
|
||||
"A resource is being overwritten");
|
||||
_Intervals.push_back(A);
|
||||
|
||||
sortAndMerge();
|
||||
|
||||
// Do not keep the full history of the intervals, just the
|
||||
// latest #CutOff.
|
||||
while (_Intervals.size() > CutOff)
|
||||
_Intervals.pop_front();
|
||||
}
|
||||
|
||||
bool ResourceSegments::intersects(ResourceSegments::IntervalTy A,
|
||||
ResourceSegments::IntervalTy B) {
|
||||
assert(A.first <= A.second && "Invalid interval");
|
||||
assert(B.first <= B.second && "Invalid interval");
|
||||
|
||||
// Share one boundary.
|
||||
if ((A.first == B.first) || (A.second == B.second))
|
||||
return true;
|
||||
|
||||
// full intersersect: [ *** ) B
|
||||
// [***) A
|
||||
if ((A.first > B.first) && (A.second < B.second))
|
||||
return true;
|
||||
|
||||
// right intersect: [ ***) B
|
||||
// [*** ) A
|
||||
if ((A.first > B.first) && (A.first < B.second) && (A.second > B.second))
|
||||
return true;
|
||||
|
||||
// left intersect: [*** ) B
|
||||
// [ ***) A
|
||||
if ((A.first < B.first) && (B.first < A.second) && (B.second > B.first))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ResourceSegments::sortAndMerge() {
|
||||
if (_Intervals.size() <= 1)
|
||||
return;
|
||||
|
||||
// First sort the collection.
|
||||
_Intervals.sort(sortIntervals);
|
||||
|
||||
// can use next because I have at least 2 elements in the list
|
||||
auto next = std::next(std::begin(_Intervals));
|
||||
auto E = std::end(_Intervals);
|
||||
for (; next != E; ++next) {
|
||||
if (std::prev(next)->second >= next->first) {
|
||||
next->first = std::prev(next)->first;
|
||||
_Intervals.erase(std::prev(next));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,
|
||||
DefaultMispredictPenalty,
|
||||
false,
|
||||
true,
|
||||
false /*EnableIntervals*/,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@ -35,7 +35,6 @@ add_llvm_unittest(CodeGenTests
|
||||
RegAllocScoreTest.cpp
|
||||
PassManagerTest.cpp
|
||||
ScalableVectorMVTsTest.cpp
|
||||
SchedBoundary.cpp
|
||||
SelectionDAGAddressAnalysisTest.cpp
|
||||
TypeTraitsTest.cpp
|
||||
TargetOptionsTest.cpp
|
||||
|
@ -1,398 +0,0 @@
|
||||
#include "llvm/CodeGen/MachineScheduler.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#ifndef NDEBUG
|
||||
TEST(ResourceSegmentsDeath, OverwriteOnRight) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
EXPECT_DEATH(X.add({15, 30}), "A resource is being overwritten");
|
||||
}
|
||||
|
||||
TEST(ResourceSegmentsDeath, OverwriteOnLeft) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
EXPECT_DEATH(X.add({5, 11}), "A resource is being overwritten");
|
||||
;
|
||||
}
|
||||
|
||||
TEST(ResourceSegmentsDeath, FullOverwrite) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
EXPECT_DEATH(X.add({15, 18}), "A resource is being overwritten");
|
||||
}
|
||||
|
||||
TEST(ResourceSegmentsDeath, ZeroSizeIntervalsNotAllowed) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
EXPECT_DEATH(X.add({20, 30}, 0), "0-size interval history has no use.");
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
TEST(ResourceSegments, ConsecutiveLeftNoOverlap) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
X.add({7, 9});
|
||||
EXPECT_EQ(X, ResourceSegments({{7, 9}, {10, 20}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, ConsecutiveLeftWithOverlap) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
X.add({7, 10});
|
||||
EXPECT_EQ(X, ResourceSegments({{7, 20}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, ConsecutiveRightNoOverlap) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
X.add({21, 22});
|
||||
EXPECT_EQ(X, ResourceSegments({{10, 20}, {21, 22}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, ConsecutiveRightWithOverlap) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
X.add({20, 22});
|
||||
EXPECT_EQ(X, ResourceSegments({{10, 22}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, Disjoint) {
|
||||
auto X = ResourceSegments({{10, 20}});
|
||||
X.add({22, 23});
|
||||
EXPECT_EQ(X, ResourceSegments({{10, 20}, {22, 23}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, SortAfterAdd) {
|
||||
auto X = ResourceSegments({{10, 20}, {3, 4}});
|
||||
X.add({6, 8});
|
||||
EXPECT_EQ(X, ResourceSegments({{3, 4}, {6, 8}, {10, 20}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, AddWithCutOff) {
|
||||
auto X = ResourceSegments({{1, 2}, {3, 4}});
|
||||
X.add({6, 8}, 2);
|
||||
EXPECT_EQ(X, ResourceSegments({{3, 4}, {6, 8}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, add_01) {
|
||||
auto X = ResourceSegments({{10, 20}, {30, 40}});
|
||||
X.add({21, 29});
|
||||
EXPECT_EQ(X, ResourceSegments({{10, 20}, {21, 29}, {30, 40}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, add_02) {
|
||||
auto X = ResourceSegments({{10, 20}, {30, 40}});
|
||||
X.add({22, 29});
|
||||
EXPECT_EQ(X, ResourceSegments({{10, 20}, {22, 29}, {30, 40}}));
|
||||
X.add({29, 30});
|
||||
EXPECT_EQ(X, ResourceSegments({{10, 20}, {22, 40}}));
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
TEST(ResourceSegmentsDeath, add_empty) {
|
||||
auto X = ResourceSegments({{10, 20}, {30, 40}});
|
||||
EXPECT_DEATH(X.add({22, 22}), "Cannot add empty resource usage");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(ResourceSegments, sort_two) {
|
||||
EXPECT_EQ(ResourceSegments({{30, 40}, {10, 28}}),
|
||||
ResourceSegments({{10, 28}, {30, 40}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, sort_three) {
|
||||
EXPECT_EQ(ResourceSegments({{30, 40}, {71, 200}, {10, 29}}),
|
||||
ResourceSegments({{10, 29}, {30, 40}, {71, 200}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, merge_two) {
|
||||
EXPECT_EQ(ResourceSegments({{10, 33}, {30, 40}}),
|
||||
ResourceSegments({{10, 40}}));
|
||||
EXPECT_EQ(ResourceSegments({{10, 30}, {30, 40}}),
|
||||
ResourceSegments({{10, 40}}));
|
||||
// Cycle 29 is resource free, so the interval is disjoint.
|
||||
EXPECT_EQ(ResourceSegments({{10, 29}, {30, 40}}),
|
||||
ResourceSegments({{10, 29}, {30, 40}}));
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, merge_three) {
|
||||
EXPECT_EQ(ResourceSegments({{10, 29}, {30, 40}, {71, 200}}),
|
||||
ResourceSegments({{10, 29}, {30, 40}, {71, 200}}));
|
||||
EXPECT_EQ(ResourceSegments({{10, 29}, {30, 40}, {41, 200}}),
|
||||
ResourceSegments({{10, 29}, {30, 40}, {41, 200}}));
|
||||
EXPECT_EQ(ResourceSegments({{10, 30}, {30, 40}, {40, 200}}),
|
||||
ResourceSegments({{10, 200}}));
|
||||
EXPECT_EQ(ResourceSegments({{10, 28}, {30, 71}, {71, 200}}),
|
||||
ResourceSegments({{10, 28}, {30, 200}}));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Intersection
|
||||
TEST(ResourceSegments, intersects) {
|
||||
// no intersect
|
||||
EXPECT_FALSE(ResourceSegments::intersects({0, 1}, {3, 4}));
|
||||
EXPECT_FALSE(ResourceSegments::intersects({3, 4}, {0, 1}));
|
||||
EXPECT_FALSE(ResourceSegments::intersects({0, 3}, {3, 4}));
|
||||
EXPECT_FALSE(ResourceSegments::intersects({3, 4}, {0, 3}));
|
||||
|
||||
// Share one boundary
|
||||
EXPECT_TRUE(ResourceSegments::intersects({5, 6}, {5, 10}));
|
||||
EXPECT_TRUE(ResourceSegments::intersects({5, 10}, {5, 6}));
|
||||
|
||||
// full intersect
|
||||
EXPECT_TRUE(ResourceSegments::intersects({1, 2}, {0, 3}));
|
||||
EXPECT_TRUE(ResourceSegments::intersects({1, 2}, {0, 2}));
|
||||
EXPECT_TRUE(ResourceSegments::intersects({0, 3}, {1, 2}));
|
||||
EXPECT_TRUE(ResourceSegments::intersects({0, 2}, {1, 2}));
|
||||
|
||||
// right intersect
|
||||
EXPECT_TRUE(ResourceSegments::intersects({2, 4}, {0, 3}));
|
||||
EXPECT_TRUE(ResourceSegments::intersects({0, 3}, {2, 4}));
|
||||
|
||||
// left intersect
|
||||
EXPECT_TRUE(ResourceSegments::intersects({2, 4}, {3, 5}));
|
||||
EXPECT_TRUE(ResourceSegments::intersects({3, 5}, {2, 4}));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TOP-DOWN getFirstAvailableAt
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromTop_oneCycle) {
|
||||
auto X = ResourceSegments({{2, 5}});
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// Res X X X
|
||||
// ...X...
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(0, 0, 1), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(1, 0, 1), 1U);
|
||||
// Skip to five when hitting cycle 2
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 0, 1), 5U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromTop_twoCycles) {
|
||||
auto X = ResourceSegments({{4, 5}});
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// Res X
|
||||
// ...X X....
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(0, 0, 2), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(1, 0, 2), 1U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 0, 2), 2U);
|
||||
// Skip to cycle 5
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(3, 0, 2), 5U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromTop_twoCycles_Shifted) {
|
||||
auto X = ResourceSegments({{4, 5}});
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// Res X
|
||||
// ...c X X...
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(0, 1, 3), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(1, 1, 3), 1U);
|
||||
// Skip to cycle 4
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 1, 3), 4U);
|
||||
// Stay con cycle 4
|
||||
// 0 1 2 3 4 5 6 7
|
||||
// Res X
|
||||
// ...c X X...
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(3, 1, 3), 4U);
|
||||
//
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(4, 1, 3), 4U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(5, 1, 3), 5U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromTop_twoCycles_Shifted_withGap) {
|
||||
auto X = ResourceSegments({{4, 5}, {7, 9}});
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// Res X X X
|
||||
// c X X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(1, 1, 3), 1U);
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// Res X X X
|
||||
// c X X --> moves to 4
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 1, 3), 4U);
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// Res X X X
|
||||
// c X X --> moves to 4
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(3, 1, 3), 4U);
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// Res X X X
|
||||
// c X X --> stays on 4
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(4, 1, 3), 4U);
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
// Res X X X
|
||||
// c X X --> skips to 8
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(5, 1, 3), 8U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromTop_basic) {
|
||||
auto X = ResourceSegments({{5, 10}, {30, 40}});
|
||||
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(0, 3, 4), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(1, 3, 4), 1U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 3, 4), 7U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(3, 3, 4), 7U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(4, 3, 4), 7U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(5, 3, 4), 7U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(6, 3, 4), 7U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(7, 3, 4), 7U);
|
||||
// Check the empty range between the two intervals of X.
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(15, 3, 4), 15U);
|
||||
// Overlap the second interval.
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(28, 3, 4), 37U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromTop_advanced) {
|
||||
auto X = ResourceSegments({{3, 6}, {7, 9}, {11, 14}, {30, 33}});
|
||||
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 4, 5), 2U);
|
||||
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(2, 3, 4), 3U);
|
||||
// Can schedule at 7U because the interval [14, 19[ does not
|
||||
// overlap any of the intervals in X.
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromTop(1, 7, 12), 7U);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// BOTTOM-UP getFirstAvailableAt
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom) {
|
||||
// Scheduling cycles move to the left...
|
||||
//
|
||||
// 41 40 39 ... 31 30 29 ... 21 20 19 ... 11 10 9 8 7 6 ... 1 0
|
||||
// Res X X X X X X X X
|
||||
// X X X X X X
|
||||
// Time (relative to instruction execution) 0 1 2 3 4 5
|
||||
auto X = ResourceSegments({{10, 20}, {30, 40}});
|
||||
// .. but time (instruction cycle) moves to the right. Therefore, it
|
||||
// is always possible to llocate a resource to the right of 0 if 0
|
||||
// is not taken, because the right side of the scheduling cycles is
|
||||
// empty.
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 1), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 9), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 10), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 20), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 21), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 22), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 29), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 30), 0U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom_01) {
|
||||
auto X = ResourceSegments({{3, 7}});
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// ...X... <- one cycle resource placement
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 1), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(1, 0, 1), 1U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(2, 0, 1), 2U);
|
||||
// Skip to 7
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(3, 0, 1), 7U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom_02) {
|
||||
auto X = ResourceSegments({{3, 7}});
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// ...X X... <- two cycles resource placement
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 2), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(1, 0, 2), 1U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(2, 0, 2), 2U);
|
||||
// skip to 8
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(3, 0, 2), 8U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom_02_shifted) {
|
||||
auto X = ResourceSegments({{3, 7}});
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// c X X <- two cycles resource placement but shifted by 1
|
||||
// 0 1 2 <- cycles relative to the execution of the
|
||||
// instruction
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 1, 3), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(1, 1, 3), 1U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(2, 1, 3), 2U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(3, 1, 3), 3U);
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// c X X -> skip to 9
|
||||
// 0 1 2
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(4, 1, 3), 9U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(5, 1, 3), 9U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(6, 1, 3), 9U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(7, 1, 3), 9U);
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// c X X <- skip to 9
|
||||
// 0 1 2
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(8, 1, 3), 9U);
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// c X X
|
||||
// 0 1 2
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(9, 1, 3), 9U);
|
||||
// 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X
|
||||
// c X X
|
||||
// 0 1 2
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(10, 1, 3), 10U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom_03) {
|
||||
auto X = ResourceSegments({{1, 2}, {3, 7}});
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X X
|
||||
// X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 1), 0U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X X
|
||||
// X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(1, 0, 1), 2U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X X
|
||||
// X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(2, 0, 1), 2U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X X
|
||||
// X X X X X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(2, 0, 5), 11U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(3, 0, 5), 11U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(5, 0, 5), 11U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(11, 0, 5), 11U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
// X X X X X
|
||||
// X X X X X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(12, 0, 5), 12U);
|
||||
}
|
||||
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom_03_shifted) {
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
auto X = ResourceSegments({{-3, -1}, {1, 2}, {3, 7}, {9, 10}});
|
||||
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 1, 2), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 2), 0U);
|
||||
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
// X X X -> skip to cycle 12
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 3), 12U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
// X X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 1, 3), 1U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 1, 4), 13U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(12, 1, 4), 13U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
// c X X X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(13, 1, 4), 13U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
// X X
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(1, 1, 3), 1U);
|
||||
// 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
// C X X 0 -> skip to cycle 9
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(2, 1, 3), 9U);
|
||||
// 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3
|
||||
// X X X X X X X X
|
||||
// C C X X X X X -> skip to cycle 16
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(3, 2, 7), 16U);
|
||||
}
|
||||
TEST(ResourceSegments, getFirstAvailableAtFromBottom_empty) {
|
||||
// Empty resource usage can accept schediling at any cycle
|
||||
auto X = ResourceSegments({});
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(0, 0, 1), 0U);
|
||||
EXPECT_EQ(X.getFirstAvailableAtFromBottom(17, 1, 22), 17U);
|
||||
}
|
@ -1453,12 +1453,6 @@ void SubtargetEmitter::EmitProcessorModels(raw_ostream &OS) {
|
||||
OS << " " << (CompleteModel ? "true" : "false") << ", // "
|
||||
<< "CompleteModel\n";
|
||||
|
||||
bool EnableIntervals =
|
||||
(PM.ModelDef ? PM.ModelDef->getValueAsBit("EnableIntervals") : false);
|
||||
|
||||
OS << " " << (EnableIntervals ? "true" : "false") << ", // "
|
||||
<< "EnableIntervals\n";
|
||||
|
||||
OS << " " << PM.Index << ", // Processor ID\n";
|
||||
if (PM.hasInstrSchedModel())
|
||||
OS << " " << PM.ModelName << "ProcResources" << ",\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user