LLVM API Documentation

HexagonMachineScheduler.h
Go to the documentation of this file.
00001 //===-- HexagonMachineScheduler.h - Custom Hexagon MI scheduler.      ----===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // Custom Hexagon MI scheduler.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONMACHINESCHEDULER_H
00015 #define LLVM_LIB_TARGET_HEXAGON_HEXAGONMACHINESCHEDULER_H
00016 
00017 #include "llvm/ADT/PriorityQueue.h"
00018 #include "llvm/Analysis/AliasAnalysis.h"
00019 #include "llvm/CodeGen/LiveIntervalAnalysis.h"
00020 #include "llvm/CodeGen/MachineScheduler.h"
00021 #include "llvm/CodeGen/Passes.h"
00022 #include "llvm/CodeGen/RegisterClassInfo.h"
00023 #include "llvm/CodeGen/RegisterPressure.h"
00024 #include "llvm/CodeGen/ResourcePriorityQueue.h"
00025 #include "llvm/CodeGen/ScheduleDAGInstrs.h"
00026 #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
00027 #include "llvm/Support/CommandLine.h"
00028 #include "llvm/Support/Debug.h"
00029 #include "llvm/Support/ErrorHandling.h"
00030 #include "llvm/Support/raw_ostream.h"
00031 #include "llvm/Target/TargetInstrInfo.h"
00032 
00033 using namespace llvm;
00034 
00035 namespace llvm {
00036 //===----------------------------------------------------------------------===//
00037 // ConvergingVLIWScheduler - Implementation of the standard
00038 // MachineSchedStrategy.
00039 //===----------------------------------------------------------------------===//
00040 
00041 class VLIWResourceModel {
00042   /// ResourcesModel - Represents VLIW state.
00043   /// Not limited to VLIW targets per say, but assumes
00044   /// definition of DFA by a target.
00045   DFAPacketizer *ResourcesModel;
00046 
00047   const TargetSchedModel *SchedModel;
00048 
00049   /// Local packet/bundle model. Purely
00050   /// internal to the MI schedulre at the time.
00051   std::vector<SUnit*> Packet;
00052 
00053   /// Total packets created.
00054   unsigned TotalPackets;
00055 
00056 public:
00057 VLIWResourceModel(const TargetMachine &TM, const TargetSchedModel *SM) :
00058     SchedModel(SM), TotalPackets(0) {
00059   ResourcesModel =
00060       TM.getSubtargetImpl()->getInstrInfo()->CreateTargetScheduleState(&TM,
00061                                                                        nullptr);
00062 
00063     // This hard requirement could be relaxed,
00064     // but for now do not let it proceed.
00065     assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
00066 
00067     Packet.resize(SchedModel->getIssueWidth());
00068     Packet.clear();
00069     ResourcesModel->clearResources();
00070   }
00071 
00072   ~VLIWResourceModel() {
00073     delete ResourcesModel;
00074   }
00075 
00076   void resetPacketState() {
00077     Packet.clear();
00078   }
00079 
00080   void resetDFA() {
00081     ResourcesModel->clearResources();
00082   }
00083 
00084   void reset() {
00085     Packet.clear();
00086     ResourcesModel->clearResources();
00087   }
00088 
00089   bool isResourceAvailable(SUnit *SU);
00090   bool reserveResources(SUnit *SU);
00091   unsigned getTotalPackets() const { return TotalPackets; }
00092 };
00093 
00094 /// Extend the standard ScheduleDAGMI to provide more context and override the
00095 /// top-level schedule() driver.
00096 class VLIWMachineScheduler : public ScheduleDAGMILive {
00097 public:
00098   VLIWMachineScheduler(MachineSchedContext *C,
00099                        std::unique_ptr<MachineSchedStrategy> S)
00100       : ScheduleDAGMILive(C, std::move(S)) {}
00101 
00102   /// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's
00103   /// time to do some work.
00104   void schedule() override;
00105   /// Perform platform-specific DAG postprocessing.
00106   void postprocessDAG();
00107 };
00108 
00109 /// ConvergingVLIWScheduler shrinks the unscheduled zone using heuristics
00110 /// to balance the schedule.
00111 class ConvergingVLIWScheduler : public MachineSchedStrategy {
00112 
00113   /// Store the state used by ConvergingVLIWScheduler heuristics, required
00114   ///  for the lifetime of one invocation of pickNode().
00115   struct SchedCandidate {
00116     // The best SUnit candidate.
00117     SUnit *SU;
00118 
00119     // Register pressure values for the best candidate.
00120     RegPressureDelta RPDelta;
00121 
00122     // Best scheduling cost.
00123     int SCost;
00124 
00125     SchedCandidate(): SU(nullptr), SCost(0) {}
00126   };
00127   /// Represent the type of SchedCandidate found within a single queue.
00128   enum CandResult {
00129     NoCand, NodeOrder, SingleExcess, SingleCritical, SingleMax, MultiPressure,
00130     BestCost};
00131 
00132   /// Each Scheduling boundary is associated with ready queues. It tracks the
00133   /// current cycle in whichever direction at has moved, and maintains the state
00134   /// of "hazards" and other interlocks at the current cycle.
00135   struct VLIWSchedBoundary {
00136     VLIWMachineScheduler *DAG;
00137     const TargetSchedModel *SchedModel;
00138 
00139     ReadyQueue Available;
00140     ReadyQueue Pending;
00141     bool CheckPending;
00142 
00143     ScheduleHazardRecognizer *HazardRec;
00144     VLIWResourceModel *ResourceModel;
00145 
00146     unsigned CurrCycle;
00147     unsigned IssueCount;
00148 
00149     /// MinReadyCycle - Cycle of the soonest available instruction.
00150     unsigned MinReadyCycle;
00151 
00152     // Remember the greatest min operand latency.
00153     unsigned MaxMinLatency;
00154 
00155     /// Pending queues extend the ready queues with the same ID and the
00156     /// PendingFlag set.
00157     VLIWSchedBoundary(unsigned ID, const Twine &Name):
00158       DAG(nullptr), SchedModel(nullptr), Available(ID, Name+".A"),
00159       Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"),
00160       CheckPending(false), HazardRec(nullptr), ResourceModel(nullptr),
00161       CurrCycle(0), IssueCount(0),
00162       MinReadyCycle(UINT_MAX), MaxMinLatency(0) {}
00163 
00164     ~VLIWSchedBoundary() {
00165       delete ResourceModel;
00166       delete HazardRec;
00167     }
00168 
00169     void init(VLIWMachineScheduler *dag, const TargetSchedModel *smodel) {
00170       DAG = dag;
00171       SchedModel = smodel;
00172     }
00173 
00174     bool isTop() const {
00175       return Available.getID() == ConvergingVLIWScheduler::TopQID;
00176     }
00177 
00178     bool checkHazard(SUnit *SU);
00179 
00180     void releaseNode(SUnit *SU, unsigned ReadyCycle);
00181 
00182     void bumpCycle();
00183 
00184     void bumpNode(SUnit *SU);
00185 
00186     void releasePending();
00187 
00188     void removeReady(SUnit *SU);
00189 
00190     SUnit *pickOnlyChoice();
00191   };
00192 
00193   VLIWMachineScheduler *DAG;
00194   const TargetSchedModel *SchedModel;
00195 
00196   // State of the top and bottom scheduled instruction boundaries.
00197   VLIWSchedBoundary Top;
00198   VLIWSchedBoundary Bot;
00199 
00200 public:
00201   /// SUnit::NodeQueueId: 0 (none), 1 (top), 2 (bot), 3 (both)
00202   enum {
00203     TopQID = 1,
00204     BotQID = 2,
00205     LogMaxQID = 2
00206   };
00207 
00208   ConvergingVLIWScheduler()
00209     : DAG(nullptr), SchedModel(nullptr), Top(TopQID, "TopQ"),
00210       Bot(BotQID, "BotQ") {}
00211 
00212   void initialize(ScheduleDAGMI *dag) override;
00213 
00214   SUnit *pickNode(bool &IsTopNode) override;
00215 
00216   void schedNode(SUnit *SU, bool IsTopNode) override;
00217 
00218   void releaseTopNode(SUnit *SU) override;
00219 
00220   void releaseBottomNode(SUnit *SU) override;
00221 
00222   unsigned ReportPackets() {
00223     return Top.ResourceModel->getTotalPackets() +
00224            Bot.ResourceModel->getTotalPackets();
00225   }
00226 
00227 protected:
00228   SUnit *pickNodeBidrectional(bool &IsTopNode);
00229 
00230   int SchedulingCost(ReadyQueue &Q,
00231                      SUnit *SU, SchedCandidate &Candidate,
00232                      RegPressureDelta &Delta, bool verbose);
00233 
00234   CandResult pickNodeFromQueue(ReadyQueue &Q,
00235                                const RegPressureTracker &RPTracker,
00236                                SchedCandidate &Candidate);
00237 #ifndef NDEBUG
00238   void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU,
00239                       PressureChange P = PressureChange());
00240 #endif
00241 };
00242 
00243 } // namespace
00244 
00245 
00246 #endif