X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FHexagon%2FHexagonMachineScheduler.cpp;h=35f732cd6207fbaa40cef53cf6daf820df29ad01;hb=c413998d28c4e201e265b0bdbe90ddc2747856c4;hp=838f7b5ed77ab28b3d6c50cd54476d11841acca5;hpb=78e5efe1b202f71975ad93f33b1fda21d83fd1fb;p=oota-llvm.git diff --git a/lib/Target/Hexagon/HexagonMachineScheduler.cpp b/lib/Target/Hexagon/HexagonMachineScheduler.cpp index 838f7b5ed77..35f732cd620 100644 --- a/lib/Target/Hexagon/HexagonMachineScheduler.cpp +++ b/lib/Target/Hexagon/HexagonMachineScheduler.cpp @@ -12,14 +12,29 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "misched" - #include "HexagonMachineScheduler.h" - -#include +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/IR/Function.h" using namespace llvm; +#define DEBUG_TYPE "misched" + +/// Platform-specific modifications to DAG. +void VLIWMachineScheduler::postprocessDAG() { + SUnit* LastSequentialCall = nullptr; + // Currently we only catch the situation when compare gets scheduled + // before preceding call. + for (unsigned su = 0, e = SUnits.size(); su != e; ++su) { + // Remember the call. + if (SUnits[su].getInstr()->isCall()) + LastSequentialCall = &(SUnits[su]); + // Look for a compare that defines a predicate. + else if (SUnits[su].getInstr()->isCompare() && LastSequentialCall) + SUnits[su].addPred(SDep(LastSequentialCall, SDep::Barrier)); + } +} + /// Check if scheduling of this SU is possible /// in the current packet. /// It is _not_ precise (statefull), it is more like @@ -67,6 +82,13 @@ bool VLIWResourceModel::isResourceAvailable(SUnit *SU) { /// Keep track of available resources. bool VLIWResourceModel::reserveResources(SUnit *SU) { bool startNewCycle = false; + // Artificially reset state. + if (!SU) { + ResourcesModel->clearResources(); + Packet.clear(); + TotalPackets++; + return false; + } // If this SU does not fit in the packet // start a new one. if (!isResourceAvailable(SU)) { @@ -86,7 +108,7 @@ bool VLIWResourceModel::reserveResources(SUnit *SU) { case TargetOpcode::REG_SEQUENCE: case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: - case TargetOpcode::PROLOG_LABEL: + case TargetOpcode::CFI_INSTRUCTION: case TargetOpcode::EH_LABEL: case TargetOpcode::COPY: case TargetOpcode::INLINEASM: @@ -105,7 +127,7 @@ bool VLIWResourceModel::reserveResources(SUnit *SU) { // If packet is now full, reset the state so in the next cycle // we start fresh. - if (Packet.size() >= InstrItins->SchedModel->IssueWidth) { + if (Packet.size() >= SchedModel->getIssueWidth()) { ResourcesModel->clearResources(); Packet.clear(); TotalPackets++; @@ -128,7 +150,19 @@ void VLIWMachineScheduler::schedule() { buildDAGWithRegPressure(); + // Postprocess the DAG to add platform-specific artificial dependencies. + postprocessDAG(); + + SmallVector TopRoots, BotRoots; + findRootsAndBiasEdges(TopRoots, BotRoots); + + // Initialize the strategy before modifying the DAG. + SchedImpl->initialize(this); + // To view Height/Depth correctly, they should be accessed at least once. + // + // FIXME: SUnit::dumpAll always recompute depth and height now. The max + // depth/height could be computed directly from the roots and leaves. DEBUG(unsigned maxH = 0; for (unsigned su = 0, e = SUnits.size(); su != e; ++su) if (SUnits[su].getHeight() > maxH) @@ -142,7 +176,7 @@ void VLIWMachineScheduler::schedule() { DEBUG(for (unsigned su = 0, e = SUnits.size(); su != e; ++su) SUnits[su].dumpAll(this)); - initQueues(); + initQueues(TopRoots, BotRoots); bool IsTopNode = false; while (SUnit *SU = SchedImpl->pickNode(IsTopNode)) { @@ -152,6 +186,9 @@ void VLIWMachineScheduler::schedule() { scheduleMI(SU, IsTopNode); updateQueues(SU, IsTopNode); + + // Notify the scheduling strategy after updating the DAG. + SchedImpl->schedNode(SU, IsTopNode); } assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); @@ -160,18 +197,25 @@ void VLIWMachineScheduler::schedule() { void ConvergingVLIWScheduler::initialize(ScheduleDAGMI *dag) { DAG = static_cast(dag); - TRI = DAG->TRI; - Top.DAG = DAG; - Bot.DAG = DAG; - - // Initialize the HazardRecognizers. - const TargetMachine &TM = DAG->MF.getTarget(); - const InstrItineraryData *Itin = TM.getInstrItineraryData(); - Top.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG); - Bot.HazardRec = TM.getInstrInfo()->CreateTargetMIHazardRecognizer(Itin, DAG); - - Top.ResourceModel = new VLIWResourceModel(TM); - Bot.ResourceModel = new VLIWResourceModel(TM); + SchedModel = DAG->getSchedModel(); + + Top.init(DAG, SchedModel); + Bot.init(DAG, SchedModel); + + // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or + // are disabled, then these HazardRecs will be disabled. + const InstrItineraryData *Itin = DAG->getSchedModel()->getInstrItineraries(); + const TargetSubtargetInfo &STI = DAG->MF.getSubtarget(); + const TargetInstrInfo *TII = STI.getInstrInfo(); + delete Top.HazardRec; + delete Bot.HazardRec; + Top.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG); + Bot.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG); + + delete Top.ResourceModel; + delete Bot.ResourceModel; + Top.ResourceModel = new VLIWResourceModel(STI, DAG->getSchedModel()); + Bot.ResourceModel = new VLIWResourceModel(STI, DAG->getSchedModel()); assert((!llvm::ForceTopDown || !llvm::ForceBottomUp) && "-misched-topdown incompatible with -misched-bottomup"); @@ -184,7 +228,7 @@ void ConvergingVLIWScheduler::releaseTopNode(SUnit *SU) { for (SUnit::succ_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { unsigned PredReadyCycle = I->getSUnit()->TopReadyCycle; - unsigned MinLatency = I->getMinLatency(); + unsigned MinLatency = I->getLatency(); #ifndef NDEBUG Top.MaxMinLatency = std::max(MinLatency, Top.MaxMinLatency); #endif @@ -203,7 +247,7 @@ void ConvergingVLIWScheduler::releaseBottomNode(SUnit *SU) { for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); I != E; ++I) { unsigned SuccReadyCycle = I->getSUnit()->BotReadyCycle; - unsigned MinLatency = I->getMinLatency(); + unsigned MinLatency = I->getLatency(); #ifndef NDEBUG Bot.MaxMinLatency = std::max(MinLatency, Bot.MaxMinLatency); #endif @@ -226,17 +270,18 @@ void ConvergingVLIWScheduler::releaseBottomNode(SUnit *SU) { /// can dispatch per cycle. /// /// TODO: Also check whether the SU must start a new group. -bool ConvergingVLIWScheduler::SchedBoundary::checkHazard(SUnit *SU) { +bool ConvergingVLIWScheduler::VLIWSchedBoundary::checkHazard(SUnit *SU) { if (HazardRec->isEnabled()) return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard; - if (IssueCount + DAG->getNumMicroOps(SU->getInstr()) > DAG->getIssueWidth()) + unsigned uops = SchedModel->getNumMicroOps(SU->getInstr()); + if (IssueCount + uops > SchedModel->getIssueWidth()) return true; return false; } -void ConvergingVLIWScheduler::SchedBoundary::releaseNode(SUnit *SU, +void ConvergingVLIWScheduler::VLIWSchedBoundary::releaseNode(SUnit *SU, unsigned ReadyCycle) { if (ReadyCycle < MinReadyCycle) MinReadyCycle = ReadyCycle; @@ -251,8 +296,8 @@ void ConvergingVLIWScheduler::SchedBoundary::releaseNode(SUnit *SU, } /// Move the boundary of scheduled code by one cycle. -void ConvergingVLIWScheduler::SchedBoundary::bumpCycle() { - unsigned Width = DAG->getIssueWidth(); +void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpCycle() { + unsigned Width = SchedModel->getIssueWidth(); IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width; assert(MinReadyCycle < UINT_MAX && "MinReadyCycle uninitialized"); @@ -277,7 +322,7 @@ void ConvergingVLIWScheduler::SchedBoundary::bumpCycle() { } /// Move the boundary of scheduled code by one SUnit. -void ConvergingVLIWScheduler::SchedBoundary::bumpNode(SUnit *SU) { +void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpNode(SUnit *SU) { bool startNewCycle = false; // Update the reservation table. @@ -295,7 +340,7 @@ void ConvergingVLIWScheduler::SchedBoundary::bumpNode(SUnit *SU) { // Check the instruction group dispatch limit. // TODO: Check if this SU must end a dispatch group. - IssueCount += DAG->getNumMicroOps(SU->getInstr()); + IssueCount += SchedModel->getNumMicroOps(SU->getInstr()); if (startNewCycle) { DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n'); bumpCycle(); @@ -307,7 +352,7 @@ void ConvergingVLIWScheduler::SchedBoundary::bumpNode(SUnit *SU) { /// Release pending ready nodes in to the available queue. This makes them /// visible to heuristics. -void ConvergingVLIWScheduler::SchedBoundary::releasePending() { +void ConvergingVLIWScheduler::VLIWSchedBoundary::releasePending() { // If the available queue is empty, it is safe to reset MinReadyCycle. if (Available.empty()) MinReadyCycle = UINT_MAX; @@ -335,7 +380,7 @@ void ConvergingVLIWScheduler::SchedBoundary::releasePending() { } /// Remove SU from the ready set for this boundary. -void ConvergingVLIWScheduler::SchedBoundary::removeReady(SUnit *SU) { +void ConvergingVLIWScheduler::VLIWSchedBoundary::removeReady(SUnit *SU) { if (Available.isInQueue(SU)) Available.remove(Available.find(SU)); else { @@ -347,29 +392,30 @@ void ConvergingVLIWScheduler::SchedBoundary::removeReady(SUnit *SU) { /// If this queue only has one ready candidate, return it. As a side effect, /// advance the cycle until at least one node is ready. If multiple instructions /// are ready, return NULL. -SUnit *ConvergingVLIWScheduler::SchedBoundary::pickOnlyChoice() { +SUnit *ConvergingVLIWScheduler::VLIWSchedBoundary::pickOnlyChoice() { if (CheckPending) releasePending(); for (unsigned i = 0; Available.empty(); ++i) { assert(i <= (HazardRec->getMaxLookAhead() + MaxMinLatency) && "permanent hazard"); (void)i; + ResourceModel->reserveResources(nullptr); bumpCycle(); releasePending(); } if (Available.size() == 1) return *Available.begin(); - return NULL; + return nullptr; } #ifndef NDEBUG void ConvergingVLIWScheduler::traceCandidate(const char *Label, const ReadyQueue &Q, - SUnit *SU, PressureElement P) { + SUnit *SU, PressureChange P) { dbgs() << Label << " " << Q.getName() << " "; if (P.isValid()) - dbgs() << TRI->getRegPressureSetName(P.PSetID) << ":" << P.UnitIncrease - << " "; + dbgs() << DAG->TRI->getRegPressureSetName(P.getPSet()) << ":" + << P.getUnitInc() << " "; else dbgs() << " "; SU->dump(DAG); @@ -379,7 +425,7 @@ void ConvergingVLIWScheduler::traceCandidate(const char *Label, /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor /// of SU, return it, otherwise return null. static SUnit *getSingleUnscheduledPred(SUnit *SU) { - SUnit *OnlyAvailablePred = 0; + SUnit *OnlyAvailablePred = nullptr; for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { SUnit &Pred = *I->getSUnit(); @@ -387,7 +433,7 @@ static SUnit *getSingleUnscheduledPred(SUnit *SU) { // We found an available, but not scheduled, predecessor. If it's the // only one we have found, keep track of it... otherwise give up. if (OnlyAvailablePred && OnlyAvailablePred != &Pred) - return 0; + return nullptr; OnlyAvailablePred = &Pred; } } @@ -397,7 +443,7 @@ static SUnit *getSingleUnscheduledPred(SUnit *SU) { /// getSingleUnscheduledSucc - If there is exactly one unscheduled successor /// of SU, return it, otherwise return null. static SUnit *getSingleUnscheduledSucc(SUnit *SU) { - SUnit *OnlyAvailableSucc = 0; + SUnit *OnlyAvailableSucc = nullptr; for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); I != E; ++I) { SUnit &Succ = *I->getSUnit(); @@ -405,7 +451,7 @@ static SUnit *getSingleUnscheduledSucc(SUnit *SU) { // We found an available, but not scheduled, successor. If it's the // only one we have found, keep track of it... otherwise give up. if (OnlyAvailableSucc && OnlyAvailableSucc != &Succ) - return 0; + return nullptr; OnlyAvailableSucc = &Succ; } } @@ -415,9 +461,7 @@ static SUnit *getSingleUnscheduledSucc(SUnit *SU) { // Constants used to denote relative importance of // heuristic components for cost computation. static const unsigned PriorityOne = 200; -static const unsigned PriorityTwo = 100; -static const unsigned PriorityThree = 50; -static const unsigned PriorityFour = 20; +static const unsigned PriorityTwo = 50; static const unsigned ScaleTwo = 10; static const unsigned FactorOne = 2; @@ -475,8 +519,8 @@ int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU, ResCount += (NumNodesBlocking * ScaleTwo); // Factor in reg pressure as a heuristic. - ResCount -= (Delta.Excess.UnitIncrease*PriorityThree); - ResCount -= (Delta.CriticalMax.UnitIncrease*PriorityThree); + ResCount -= (Delta.Excess.getUnitInc()*PriorityTwo); + ResCount -= (Delta.CriticalMax.getUnitInc()*PriorityTwo); DEBUG(if (verbose) dbgs() << " Total(" << ResCount << ")"); @@ -596,7 +640,7 @@ SUnit *ConvergingVLIWScheduler::pickNode(bool &IsTopNode) { if (DAG->top() == DAG->bottom()) { assert(Top.Available.empty() && Top.Pending.empty() && Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage"); - return NULL; + return nullptr; } SUnit *SU; if (llvm::ForceTopDown) { @@ -649,4 +693,3 @@ void ConvergingVLIWScheduler::schedNode(SUnit *SU, bool IsTopNode) { Bot.bumpNode(SU); } } -