1 //===-- HexagonMachineScheduler.h - Custom Hexagon MI scheduler. ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Custom Hexagon MI scheduler. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef HEXAGONASMPRINTER_H 15 #define HEXAGONASMPRINTER_H 16 17 #include "llvm/CodeGen/LiveIntervalAnalysis.h" 18 #include "llvm/CodeGen/MachineScheduler.h" 19 #include "llvm/CodeGen/Passes.h" 20 #include "llvm/CodeGen/RegisterClassInfo.h" 21 #include "llvm/CodeGen/RegisterPressure.h" 22 #include "llvm/CodeGen/ResourcePriorityQueue.h" 23 #include "llvm/CodeGen/ScheduleDAGInstrs.h" 24 #include "llvm/CodeGen/ScheduleHazardRecognizer.h" 25 #include "llvm/Analysis/AliasAnalysis.h" 26 #include "llvm/Target/TargetInstrInfo.h" 27 #include "llvm/Support/CommandLine.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/ErrorHandling.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include "llvm/ADT/OwningPtr.h" 32 #include "llvm/ADT/PriorityQueue.h" 33 34 using namespace llvm; 35 36 //===----------------------------------------------------------------------===// 37 // MachineSchedStrategy - Interface to a machine scheduling algorithm. 38 //===----------------------------------------------------------------------===// 39 40 namespace llvm { 41 class VLIWMachineScheduler; 42 43 /// MachineSchedStrategy - Interface used by VLIWMachineScheduler to drive 44 /// the selected scheduling algorithm. 45 /// 46 /// TODO: Move this to ScheduleDAGInstrs.h 47 class MachineSchedStrategy { 48 public: ~MachineSchedStrategy()49 virtual ~MachineSchedStrategy() {} 50 51 /// Initialize the strategy after building the DAG for a new region. 52 virtual void initialize(VLIWMachineScheduler *DAG) = 0; 53 54 /// Pick the next node to schedule, or return NULL. Set IsTopNode to true to 55 /// schedule the node at the top of the unscheduled region. Otherwise it will 56 /// be scheduled at the bottom. 57 virtual SUnit *pickNode(bool &IsTopNode) = 0; 58 59 /// Notify MachineSchedStrategy that VLIWMachineScheduler has 60 /// scheduled a node. 61 virtual void schedNode(SUnit *SU, bool IsTopNode) = 0; 62 63 /// When all predecessor dependencies have been resolved, free this node for 64 /// top-down scheduling. 65 virtual void releaseTopNode(SUnit *SU) = 0; 66 /// When all successor dependencies have been resolved, free this node for 67 /// bottom-up scheduling. 68 virtual void releaseBottomNode(SUnit *SU) = 0; 69 }; 70 71 //===----------------------------------------------------------------------===// 72 // ConvergingVLIWScheduler - Implementation of the standard 73 // MachineSchedStrategy. 74 //===----------------------------------------------------------------------===// 75 76 /// ReadyQueue encapsulates vector of "ready" SUnits with basic convenience 77 /// methods for pushing and removing nodes. ReadyQueue's are uniquely identified 78 /// by an ID. SUnit::NodeQueueId is a mask of the ReadyQueues the SUnit is in. 79 class ReadyQueue { 80 unsigned ID; 81 std::string Name; 82 std::vector<SUnit*> Queue; 83 84 public: ReadyQueue(unsigned id,const Twine & name)85 ReadyQueue(unsigned id, const Twine &name): ID(id), Name(name.str()) {} 86 getID()87 unsigned getID() const { return ID; } 88 getName()89 StringRef getName() const { return Name; } 90 91 // SU is in this queue if it's NodeQueueID is a superset of this ID. isInQueue(SUnit * SU)92 bool isInQueue(SUnit *SU) const { return (SU->NodeQueueId & ID); } 93 empty()94 bool empty() const { return Queue.empty(); } 95 size()96 unsigned size() const { return Queue.size(); } 97 98 typedef std::vector<SUnit*>::iterator iterator; 99 begin()100 iterator begin() { return Queue.begin(); } 101 end()102 iterator end() { return Queue.end(); } 103 find(SUnit * SU)104 iterator find(SUnit *SU) { 105 return std::find(Queue.begin(), Queue.end(), SU); 106 } 107 push(SUnit * SU)108 void push(SUnit *SU) { 109 Queue.push_back(SU); 110 SU->NodeQueueId |= ID; 111 } 112 remove(iterator I)113 void remove(iterator I) { 114 (*I)->NodeQueueId &= ~ID; 115 *I = Queue.back(); 116 Queue.pop_back(); 117 } 118 dump()119 void dump() { 120 dbgs() << Name << ": "; 121 for (unsigned i = 0, e = Queue.size(); i < e; ++i) 122 dbgs() << Queue[i]->NodeNum << " "; 123 dbgs() << "\n"; 124 } 125 }; 126 127 class VLIWResourceModel { 128 /// ResourcesModel - Represents VLIW state. 129 /// Not limited to VLIW targets per say, but assumes 130 /// definition of DFA by a target. 131 DFAPacketizer *ResourcesModel; 132 133 const InstrItineraryData *InstrItins; 134 135 /// Local packet/bundle model. Purely 136 /// internal to the MI schedulre at the time. 137 std::vector<SUnit*> Packet; 138 139 /// Total packets created. 140 unsigned TotalPackets; 141 142 public: VLIWResourceModel(MachineSchedContext * C,const InstrItineraryData * IID)143 VLIWResourceModel(MachineSchedContext *C, const InstrItineraryData *IID) : 144 InstrItins(IID), TotalPackets(0) { 145 const TargetMachine &TM = C->MF->getTarget(); 146 ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL); 147 148 // This hard requirement could be relaxed, 149 // but for now do not let it proceed. 150 assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); 151 152 Packet.resize(InstrItins->SchedModel->IssueWidth); 153 Packet.clear(); 154 ResourcesModel->clearResources(); 155 } 156 VLIWResourceModel(const TargetMachine & TM)157 VLIWResourceModel(const TargetMachine &TM) : 158 InstrItins(TM.getInstrItineraryData()), TotalPackets(0) { 159 ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL); 160 161 // This hard requirement could be relaxed, 162 // but for now do not let it proceed. 163 assert(ResourcesModel && "Unimplemented CreateTargetScheduleState."); 164 165 Packet.resize(InstrItins->SchedModel->IssueWidth); 166 Packet.clear(); 167 ResourcesModel->clearResources(); 168 } 169 ~VLIWResourceModel()170 ~VLIWResourceModel() { 171 delete ResourcesModel; 172 } 173 resetPacketState()174 void resetPacketState() { 175 Packet.clear(); 176 } 177 resetDFA()178 void resetDFA() { 179 ResourcesModel->clearResources(); 180 } 181 reset()182 void reset() { 183 Packet.clear(); 184 ResourcesModel->clearResources(); 185 } 186 187 bool isResourceAvailable(SUnit *SU); 188 bool reserveResources(SUnit *SU); getTotalPackets()189 unsigned getTotalPackets() const { return TotalPackets; } 190 }; 191 192 class VLIWMachineScheduler : public ScheduleDAGInstrs { 193 /// AA - AliasAnalysis for making memory reference queries. 194 AliasAnalysis *AA; 195 196 RegisterClassInfo *RegClassInfo; 197 MachineSchedStrategy *SchedImpl; 198 199 MachineBasicBlock::iterator LiveRegionEnd; 200 201 /// Register pressure in this region computed by buildSchedGraph. 202 IntervalPressure RegPressure; 203 RegPressureTracker RPTracker; 204 205 /// List of pressure sets that exceed the target's pressure limit before 206 /// scheduling, listed in increasing set ID order. Each pressure set is paired 207 /// with its max pressure in the currently scheduled regions. 208 std::vector<PressureElement> RegionCriticalPSets; 209 210 /// The top of the unscheduled zone. 211 MachineBasicBlock::iterator CurrentTop; 212 IntervalPressure TopPressure; 213 RegPressureTracker TopRPTracker; 214 215 /// The bottom of the unscheduled zone. 216 MachineBasicBlock::iterator CurrentBottom; 217 IntervalPressure BotPressure; 218 RegPressureTracker BotRPTracker; 219 220 #ifndef NDEBUG 221 /// The number of instructions scheduled so far. Used to cut off the 222 /// scheduler at the point determined by misched-cutoff. 223 unsigned NumInstrsScheduled; 224 #endif 225 226 /// Total packets in the region. 227 unsigned TotalPackets; 228 229 const MachineLoopInfo *MLI; 230 public: VLIWMachineScheduler(MachineSchedContext * C,MachineSchedStrategy * S)231 VLIWMachineScheduler(MachineSchedContext *C, MachineSchedStrategy *S): 232 ScheduleDAGInstrs(*C->MF, *C->MLI, *C->MDT, /*IsPostRA=*/false, C->LIS), 233 AA(C->AA), RegClassInfo(C->RegClassInfo), SchedImpl(S), 234 RPTracker(RegPressure), CurrentTop(), TopRPTracker(TopPressure), 235 CurrentBottom(), BotRPTracker(BotPressure), MLI(C->MLI) { 236 #ifndef NDEBUG 237 NumInstrsScheduled = 0; 238 #endif 239 TotalPackets = 0; 240 } 241 ~VLIWMachineScheduler()242 virtual ~VLIWMachineScheduler() { 243 delete SchedImpl; 244 } 245 top()246 MachineBasicBlock::iterator top() const { return CurrentTop; } bottom()247 MachineBasicBlock::iterator bottom() const { return CurrentBottom; } 248 249 /// Implement the ScheduleDAGInstrs interface for handling the next scheduling 250 /// region. This covers all instructions in a block, while schedule() may only 251 /// cover a subset. 252 void enterRegion(MachineBasicBlock *bb, 253 MachineBasicBlock::iterator begin, 254 MachineBasicBlock::iterator end, 255 unsigned endcount); 256 257 /// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's 258 /// time to do some work. 259 void schedule(); 260 261 unsigned CurCycle; 262 263 /// Get current register pressure for the top scheduled instructions. getTopPressure()264 const IntervalPressure &getTopPressure() const { return TopPressure; } getTopRPTracker()265 const RegPressureTracker &getTopRPTracker() const { return TopRPTracker; } 266 267 /// Get current register pressure for the bottom scheduled instructions. getBotPressure()268 const IntervalPressure &getBotPressure() const { return BotPressure; } getBotRPTracker()269 const RegPressureTracker &getBotRPTracker() const { return BotRPTracker; } 270 271 /// Get register pressure for the entire scheduling region before scheduling. getRegPressure()272 const IntervalPressure &getRegPressure() const { return RegPressure; } 273 getRegionCriticalPSets()274 const std::vector<PressureElement> &getRegionCriticalPSets() const { 275 return RegionCriticalPSets; 276 } 277 278 /// getIssueWidth - Return the max instructions per scheduling group. getIssueWidth()279 unsigned getIssueWidth() const { 280 return (InstrItins && InstrItins->SchedModel) 281 ? InstrItins->SchedModel->IssueWidth : 1; 282 } 283 284 /// getNumMicroOps - Return the number of issue slots required for this MI. getNumMicroOps(MachineInstr * MI)285 unsigned getNumMicroOps(MachineInstr *MI) const { 286 return 1; 287 //if (!InstrItins) return 1; 288 //int UOps = InstrItins->getNumMicroOps(MI->getDesc().getSchedClass()); 289 //return (UOps >= 0) ? UOps : TII->getNumMicroOps(InstrItins, MI); 290 } 291 292 private: 293 void scheduleNodeTopDown(SUnit *SU); 294 void listScheduleTopDown(); 295 296 void initRegPressure(); 297 void updateScheduledPressure(std::vector<unsigned> NewMaxPressure); 298 299 void moveInstruction(MachineInstr *MI, MachineBasicBlock::iterator InsertPos); 300 bool checkSchedLimit(); 301 302 void releaseRoots(); 303 304 void releaseSucc(SUnit *SU, SDep *SuccEdge); 305 void releaseSuccessors(SUnit *SU); 306 void releasePred(SUnit *SU, SDep *PredEdge); 307 void releasePredecessors(SUnit *SU); 308 309 void placeDebugValues(); 310 }; 311 312 /// ConvergingVLIWScheduler shrinks the unscheduled zone using heuristics 313 /// to balance the schedule. 314 class ConvergingVLIWScheduler : public MachineSchedStrategy { 315 316 /// Store the state used by ConvergingVLIWScheduler heuristics, required 317 /// for the lifetime of one invocation of pickNode(). 318 struct SchedCandidate { 319 // The best SUnit candidate. 320 SUnit *SU; 321 322 // Register pressure values for the best candidate. 323 RegPressureDelta RPDelta; 324 325 // Best scheduling cost. 326 int SCost; 327 SchedCandidateSchedCandidate328 SchedCandidate(): SU(NULL), SCost(0) {} 329 }; 330 /// Represent the type of SchedCandidate found within a single queue. 331 enum CandResult { 332 NoCand, NodeOrder, SingleExcess, SingleCritical, SingleMax, MultiPressure, 333 BestCost}; 334 335 /// Each Scheduling boundary is associated with ready queues. It tracks the 336 /// current cycle in whichever direction at has moved, and maintains the state 337 /// of "hazards" and other interlocks at the current cycle. 338 struct SchedBoundary { 339 VLIWMachineScheduler *DAG; 340 341 ReadyQueue Available; 342 ReadyQueue Pending; 343 bool CheckPending; 344 345 ScheduleHazardRecognizer *HazardRec; 346 VLIWResourceModel *ResourceModel; 347 348 unsigned CurrCycle; 349 unsigned IssueCount; 350 351 /// MinReadyCycle - Cycle of the soonest available instruction. 352 unsigned MinReadyCycle; 353 354 // Remember the greatest min operand latency. 355 unsigned MaxMinLatency; 356 357 /// Pending queues extend the ready queues with the same ID and the 358 /// PendingFlag set. SchedBoundarySchedBoundary359 SchedBoundary(unsigned ID, const Twine &Name): 360 DAG(0), Available(ID, Name+".A"), 361 Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"), 362 CheckPending(false), HazardRec(0), ResourceModel(0), 363 CurrCycle(0), IssueCount(0), 364 MinReadyCycle(UINT_MAX), MaxMinLatency(0) {} 365 ~SchedBoundarySchedBoundary366 ~SchedBoundary() { 367 delete ResourceModel; 368 delete HazardRec; 369 } 370 isTopSchedBoundary371 bool isTop() const { 372 return Available.getID() == ConvergingVLIWScheduler::TopQID; 373 } 374 375 bool checkHazard(SUnit *SU); 376 377 void releaseNode(SUnit *SU, unsigned ReadyCycle); 378 379 void bumpCycle(); 380 381 void bumpNode(SUnit *SU); 382 383 void releasePending(); 384 385 void removeReady(SUnit *SU); 386 387 SUnit *pickOnlyChoice(); 388 }; 389 390 VLIWMachineScheduler *DAG; 391 const TargetRegisterInfo *TRI; 392 393 // State of the top and bottom scheduled instruction boundaries. 394 SchedBoundary Top; 395 SchedBoundary Bot; 396 397 public: 398 /// SUnit::NodeQueueId: 0 (none), 1 (top), 2 (bot), 3 (both) 399 enum { 400 TopQID = 1, 401 BotQID = 2, 402 LogMaxQID = 2 403 }; 404 ConvergingVLIWScheduler()405 ConvergingVLIWScheduler(): 406 DAG(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {} 407 408 virtual void initialize(VLIWMachineScheduler *dag); 409 410 virtual SUnit *pickNode(bool &IsTopNode); 411 412 virtual void schedNode(SUnit *SU, bool IsTopNode); 413 414 virtual void releaseTopNode(SUnit *SU); 415 416 virtual void releaseBottomNode(SUnit *SU); 417 418 protected: 419 SUnit *pickNodeBidrectional(bool &IsTopNode); 420 421 int SchedulingCost(ReadyQueue &Q, 422 SUnit *SU, SchedCandidate &Candidate, 423 RegPressureDelta &Delta, bool verbose); 424 425 CandResult pickNodeFromQueue(ReadyQueue &Q, 426 const RegPressureTracker &RPTracker, 427 SchedCandidate &Candidate); 428 #ifndef NDEBUG 429 void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU, 430 PressureElement P = PressureElement()); 431 #endif 432 }; 433 434 } // namespace 435 436 437 #endif 438