[llvm] r196517 - MI-Sched: Model "reserved" processor resources.
Andrew Trick
atrick at apple.com
Fri Dec 6 09:27:30 PST 2013
On Dec 6, 2013, at 1:05 AM, Daniel Jasper <djasper at google.com> wrote:
> This triggered -Wparentheses and I actually think the assert was wrong. Fixed in r196567, please take a look and double-check (as I am not familiar with this part of the codebase).
Thanks, and sorry for the warning. I also fixed the grammar.
fyi: the assert was not technically wrong, just stylistically wrong. I have this problem all the time with LLVM’s silly asserts because I don’t visually parse the &&-string as an operator.
-Andy
> On Thu, Dec 5, 2013 at 6:56 PM, Andrew Trick <atrick at apple.com> wrote:
> Author: atrick
> Date: Thu Dec 5 11:56:02 2013
> New Revision: 196517
>
> URL: http://llvm.org/viewvc/llvm-project?rev=196517&view=rev
> Log:
> MI-Sched: Model "reserved" processor resources.
>
> This allows a target to use MI-Sched as an in-order scheduler that
> will model strict resource conflicts without defining a processor
> itinerary. Instead, the target can now use the new per-operand machine
> model and define in-order resources with BufferSize=0. For example,
> this would allow restricting the type of operations that can be formed
> into a dispatch group. (Normally NumMicroOps is sufficient to enforce
> dispatch groups).
>
> If the intent is to model latency in in-order pipeline, as opposed to
> resource conflicts, then a resource with BufferSize=1 should be
> defined instead.
>
> This feature is only casually tested as there are no in-tree targets
> using it yet. However, Hal will be experimenting with POWER7.
>
> Modified:
> llvm/trunk/include/llvm/CodeGen/ScheduleDAG.h
> llvm/trunk/lib/CodeGen/MachineScheduler.cpp
> llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp
>
> Modified: llvm/trunk/include/llvm/CodeGen/ScheduleDAG.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/ScheduleDAG.h?rev=196517&r1=196516&r2=196517&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/ScheduleDAG.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/ScheduleDAG.h Thu Dec 5 11:56:02 2013
> @@ -292,7 +292,8 @@ namespace llvm {
> bool isScheduleHigh : 1; // True if preferable to schedule high.
> bool isScheduleLow : 1; // True if preferable to schedule low.
> bool isCloned : 1; // True if this node has been cloned.
> - bool isUnbuffered : 1; // Reads an unbuffered resource.
> + bool isUnbuffered : 1; // Uses an unbuffered resource.
> + bool hasReservedResource : 1; // Uses a reserved resource.
> Sched::Preference SchedulingPref; // Scheduling preference.
>
> private:
> @@ -318,9 +319,9 @@ namespace llvm {
> hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false),
> isAvailable(false), isScheduled(false), isScheduleHigh(false),
> isScheduleLow(false), isCloned(false), isUnbuffered(false),
> - SchedulingPref(Sched::None), isDepthCurrent(false),
> - isHeightCurrent(false), Depth(0), Height(0), TopReadyCycle(0),
> - BotReadyCycle(0), CopyDstRC(NULL), CopySrcRC(NULL) {}
> + hasReservedResource(false), SchedulingPref(Sched::None),
> + isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0),
> + TopReadyCycle(0), BotReadyCycle(0), CopyDstRC(NULL), CopySrcRC(NULL) {}
>
> /// SUnit - Construct an SUnit for post-regalloc scheduling to represent
> /// a MachineInstr.
> @@ -333,9 +334,9 @@ namespace llvm {
> hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false),
> isAvailable(false), isScheduled(false), isScheduleHigh(false),
> isScheduleLow(false), isCloned(false), isUnbuffered(false),
> - SchedulingPref(Sched::None), isDepthCurrent(false),
> - isHeightCurrent(false), Depth(0), Height(0), TopReadyCycle(0),
> - BotReadyCycle(0), CopyDstRC(NULL), CopySrcRC(NULL) {}
> + hasReservedResource(false), SchedulingPref(Sched::None),
> + isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0),
> + TopReadyCycle(0), BotReadyCycle(0), CopyDstRC(NULL), CopySrcRC(NULL) {}
>
> /// SUnit - Construct a placeholder SUnit.
> SUnit()
> @@ -347,9 +348,9 @@ namespace llvm {
> hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false),
> isAvailable(false), isScheduled(false), isScheduleHigh(false),
> isScheduleLow(false), isCloned(false), isUnbuffered(false),
> - SchedulingPref(Sched::None), isDepthCurrent(false),
> - isHeightCurrent(false), Depth(0), Height(0), TopReadyCycle(0),
> - BotReadyCycle(0), CopyDstRC(NULL), CopySrcRC(NULL) {}
> + hasReservedResource(false), SchedulingPref(Sched::None),
> + isDepthCurrent(false), isHeightCurrent(false), Depth(0), Height(0),
> + TopReadyCycle(0), BotReadyCycle(0), CopyDstRC(NULL), CopySrcRC(NULL) {}
>
> /// \brief Boundary nodes are placeholders for the boundary of the
> /// scheduling region.
>
> Modified: llvm/trunk/lib/CodeGen/MachineScheduler.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineScheduler.cpp?rev=196517&r1=196516&r2=196517&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/MachineScheduler.cpp (original)
> +++ llvm/trunk/lib/CodeGen/MachineScheduler.cpp Thu Dec 5 11:56:02 2013
> @@ -1322,6 +1322,8 @@ void CopyConstrain::apply(ScheduleDAGMI
> // GenericScheduler - Implementation of the generic MachineSchedStrategy.
> //===----------------------------------------------------------------------===//
>
> +static const unsigned InvalidCycle = ~0U;
> +
> namespace {
> /// GenericScheduler shrinks the unscheduled zone using heuristics to balance
> /// the schedule.
> @@ -1491,6 +1493,10 @@ public:
> // Is the scheduled region resource limited vs. latency limited.
> bool IsResourceLimited;
>
> + // Record the highest cycle at which each resource has been reserved by a
> + // scheduled instruction.
> + SmallVector<unsigned, 16> ReservedCycles;
> +
> #ifndef NDEBUG
> // Remember the greatest operand latency as an upper bound on the number of
> // times we should retry the pending queue because of a hazard.
> @@ -1518,6 +1524,7 @@ public:
> MaxExecutedResCount = 0;
> ZoneCritResIdx = 0;
> IsResourceLimited = false;
> + ReservedCycles.clear();
> #ifndef NDEBUG
> MaxObservedLatency = 0;
> #endif
> @@ -1587,6 +1594,8 @@ public:
> /// cycle.
> unsigned getLatencyStallCycles(SUnit *SU);
>
> + unsigned getNextResourceCycle(unsigned PIdx, unsigned Cycles);
> +
> bool checkHazard(SUnit *SU);
>
> unsigned findMaxLatency(ArrayRef<SUnit*> ReadySUs);
> @@ -1708,8 +1717,10 @@ init(ScheduleDAGMI *dag, const TargetSch
> DAG = dag;
> SchedModel = smodel;
> Rem = rem;
> - if (SchedModel->hasInstrSchedModel())
> + if (SchedModel->hasInstrSchedModel()) {
> ExecutedResCounts.resize(SchedModel->getNumProcResourceKinds());
> + ReservedCycles.resize(SchedModel->getNumProcResourceKinds(), InvalidCycle);
> + }
> }
>
> /// Initialize the per-region scheduling policy.
> @@ -1890,6 +1901,20 @@ unsigned GenericScheduler::SchedBoundary
> return 0;
> }
>
> +/// Compute the next cycle at which the given processor resource can be
> +/// scheduled.
> +unsigned GenericScheduler::SchedBoundary::
> +getNextResourceCycle(unsigned PIdx, unsigned Cycles) {
> + unsigned NextUnreserved = ReservedCycles[PIdx];
> + // If this resource has never been used, always return cycle zero.
> + if (NextUnreserved == InvalidCycle)
> + return 0;
> + // For bottom-up scheduling add the cycles needed for the current operation.
> + if (!isTop())
> + NextUnreserved += Cycles;
> + return NextUnreserved;
> +}
> +
> /// Does this SU have a hazard within the current instruction group.
> ///
> /// The scheduler supports two modes of hazard recognition. The first is the
> @@ -1913,6 +1938,15 @@ bool GenericScheduler::SchedBoundary::ch
> << SchedModel->getNumMicroOps(SU->getInstr()) << '\n');
> return true;
> }
> + if (SchedModel->hasInstrSchedModel() && SU->hasReservedResource) {
> + const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
> + for (TargetSchedModel::ProcResIter
> + PI = SchedModel->getWriteProcResBegin(SC),
> + PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
> + if (getNextResourceCycle(PI->ProcResourceIdx, PI->Cycles) > CurrCycle)
> + return true;
> + }
> + }
> return false;
> }
>
> @@ -2097,7 +2131,7 @@ void GenericScheduler::SchedBoundary::in
> /// \return the next cycle at which the instruction may execute without
> /// oversubscribing resources.
> unsigned GenericScheduler::SchedBoundary::
> -countResource(unsigned PIdx, unsigned Cycles, unsigned ReadyCycle) {
> +countResource(unsigned PIdx, unsigned Cycles, unsigned NextCycle) {
> unsigned Factor = SchedModel->getResourceFactor(PIdx);
> unsigned Count = Factor * Cycles;
> DEBUG(dbgs() << " " << getResourceName(PIdx)
> @@ -2116,8 +2150,14 @@ countResource(unsigned PIdx, unsigned Cy
> << getResourceName(PIdx) << ": "
> << getResourceCount(PIdx) / SchedModel->getLatencyFactor() << "c\n");
> }
> - // TODO: We don't yet model reserved resources. It's not hard though.
> - return CurrCycle;
> + // For reserved resources, record the highest cycle using the resource.
> + unsigned NextAvailable = getNextResourceCycle(PIdx, Cycles);
> + if (NextAvailable > CurrCycle) {
> + DEBUG(dbgs() << " Resource conflict: "
> + << SchedModel->getProcResource(PIdx)->Name << " reserved until @"
> + << NextAvailable << "\n");
> + }
> + return NextAvailable;
> }
>
> /// Move the boundary of scheduled code by one SUnit.
> @@ -2131,25 +2171,17 @@ void GenericScheduler::SchedBoundary::bu
> }
> HazardRec->EmitInstruction(SU);
> }
> + // checkHazard should prevent scheduling multiple instructions per cycle that
> + // exceed the issue width.
> const MCSchedClassDesc *SC = DAG->getSchedClass(SU);
> unsigned IncMOps = SchedModel->getNumMicroOps(SU->getInstr());
> - CurrMOps += IncMOps;
> - // checkHazard prevents scheduling multiple instructions per cycle that exceed
> - // issue width. However, we commonly reach the maximum. In this case
> - // opportunistically bump the cycle to avoid uselessly checking everything in
> - // the readyQ. Furthermore, a single instruction may produce more than one
> - // cycle's worth of micro-ops.
> - //
> - // TODO: Also check if this SU must end a dispatch group.
> - unsigned NextCycle = CurrCycle;
> - if (CurrMOps >= SchedModel->getIssueWidth()) {
> - ++NextCycle;
> - DEBUG(dbgs() << " *** Max MOps " << CurrMOps
> - << " at cycle " << CurrCycle << '\n');
> - }
> + assert(CurrMOps == 0 || (CurrMOps + IncMOps) <= SchedModel->getIssueWidth() &&
> + "Cannot scheduling this instructions MicroOps in the current cycle.");
> +
> unsigned ReadyCycle = (isTop() ? SU->TopReadyCycle : SU->BotReadyCycle);
> DEBUG(dbgs() << " Ready @" << ReadyCycle << "c\n");
>
> + unsigned NextCycle = CurrCycle;
> switch (SchedModel->getMicroOpBufferSize()) {
> case 0:
> assert(ReadyCycle <= CurrCycle && "Broken PendingQueue");
> @@ -2194,10 +2226,23 @@ void GenericScheduler::SchedBoundary::bu
> PI = SchedModel->getWriteProcResBegin(SC),
> PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
> unsigned RCycle =
> - countResource(PI->ProcResourceIdx, PI->Cycles, ReadyCycle);
> + countResource(PI->ProcResourceIdx, PI->Cycles, NextCycle);
> if (RCycle > NextCycle)
> NextCycle = RCycle;
> }
> + if (SU->hasReservedResource) {
> + // For reserved resources, record the highest cycle using the resource.
> + // For top-down scheduling, this is the cycle in which we schedule this
> + // instruction plus the number of cycles the operations reserves the
> + // resource. For bottom-up is it simply the instruction's cycle.
> + for (TargetSchedModel::ProcResIter
> + PI = SchedModel->getWriteProcResBegin(SC),
> + PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
> + unsigned PIdx = PI->ProcResourceIdx;
> + if (SchedModel->getProcResource(PIdx)->BufferSize == 0)
> + ReservedCycles[PIdx] = isTop() ? NextCycle + PI->Cycles : NextCycle;
> + }
> + }
> }
> // Update ExpectedLatency and DependentLatency.
> unsigned &TopLatency = isTop() ? ExpectedLatency : DependentLatency;
> @@ -2224,6 +2269,16 @@ void GenericScheduler::SchedBoundary::bu
> (int)(getCriticalCount() - (getScheduledLatency() * LFactor))
> > (int)LFactor;
> }
> + // Update CurrMOps after calling bumpCycle to handle stalls, since bumpCycle
> + // resets CurrMOps. Loop to handle instructions with more MOps than issue in
> + // one cycle. Since we commonly reach the max MOps here, opportunistically
> + // bump the cycle to avoid uselessly checking everything in the readyQ.
> + CurrMOps += IncMOps;
> + while (CurrMOps >= SchedModel->getIssueWidth()) {
> + bumpCycle(++NextCycle);
> + DEBUG(dbgs() << " *** Max MOps " << CurrMOps
> + << " at cycle " << CurrCycle << '\n');
> + }
> DEBUG(dumpScheduledState());
> }
>
>
> Modified: llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp?rev=196517&r1=196516&r2=196517&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp (original)
> +++ llvm/trunk/lib/CodeGen/ScheduleDAGInstrs.cpp Thu Dec 5 11:56:02 2013
> @@ -697,9 +697,15 @@ void ScheduleDAGInstrs::initSUnits() {
> for (TargetSchedModel::ProcResIter
> PI = SchedModel.getWriteProcResBegin(SC),
> PE = SchedModel.getWriteProcResEnd(SC); PI != PE; ++PI) {
> - if (SchedModel.getProcResource(PI->ProcResourceIdx)->BufferSize == 1) {
> + switch (SchedModel.getProcResource(PI->ProcResourceIdx)->BufferSize) {
> + case 0:
> + SU->hasReservedResource = true;
> + break;
> + case 1:
> SU->isUnbuffered = true;
> break;
> + default:
> + break;
> }
> }
> }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20131206/6a5ed987/attachment.html>
More information about the llvm-commits
mailing list