LLVM API Documentation
00001 //===---- ScheduleDAGList.cpp - Implement a list scheduler for isel DAG ---===// 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 // This implements a top-down list scheduler, using standard algorithms. 00011 // The basic approach uses a priority queue of available nodes to schedule. 00012 // One at a time, nodes are taken from the priority queue (thus in priority 00013 // order), checked for legality to schedule, and emitted if legal. 00014 // 00015 // Nodes may not be legal to schedule either due to structural hazards (e.g. 00016 // pipeline or resource constraints) or because an input to the instruction has 00017 // not completed execution. 00018 // 00019 //===----------------------------------------------------------------------===// 00020 00021 #define DEBUG_TYPE "pre-RA-sched" 00022 #include "llvm/CodeGen/LatencyPriorityQueue.h" 00023 #include "llvm/CodeGen/ScheduleDAGSDNodes.h" 00024 #include "llvm/CodeGen/ScheduleHazardRecognizer.h" 00025 #include "llvm/CodeGen/SchedulerRegistry.h" 00026 #include "llvm/CodeGen/SelectionDAGISel.h" 00027 #include "llvm/Target/TargetRegisterInfo.h" 00028 #include "llvm/Target/TargetData.h" 00029 #include "llvm/Target/TargetInstrInfo.h" 00030 #include "llvm/Support/Debug.h" 00031 #include "llvm/Support/Compiler.h" 00032 #include "llvm/ADT/PriorityQueue.h" 00033 #include "llvm/ADT/Statistic.h" 00034 #include <climits> 00035 using namespace llvm; 00036 00037 STATISTIC(NumNoops , "Number of noops inserted"); 00038 STATISTIC(NumStalls, "Number of pipeline stalls"); 00039 00040 static RegisterScheduler 00041 tdListDAGScheduler("list-td", "Top-down list scheduler", 00042 createTDListDAGScheduler); 00043 00044 namespace { 00045 //===----------------------------------------------------------------------===// 00046 /// ScheduleDAGList - The actual list scheduler implementation. This supports 00047 /// top-down scheduling. 00048 /// 00049 class VISIBILITY_HIDDEN ScheduleDAGList : public ScheduleDAGSDNodes { 00050 private: 00051 /// AvailableQueue - The priority queue to use for the available SUnits. 00052 /// 00053 SchedulingPriorityQueue *AvailableQueue; 00054 00055 /// PendingQueue - This contains all of the instructions whose operands have 00056 /// been issued, but their results are not ready yet (due to the latency of 00057 /// the operation). Once the operands become available, the instruction is 00058 /// added to the AvailableQueue. 00059 std::vector<SUnit*> PendingQueue; 00060 00061 /// HazardRec - The hazard recognizer to use. 00062 ScheduleHazardRecognizer *HazardRec; 00063 00064 public: 00065 ScheduleDAGList(MachineFunction &mf, 00066 SchedulingPriorityQueue *availqueue, 00067 ScheduleHazardRecognizer *HR) 00068 : ScheduleDAGSDNodes(mf), 00069 AvailableQueue(availqueue), HazardRec(HR) { 00070 } 00071 00072 ~ScheduleDAGList() { 00073 delete HazardRec; 00074 delete AvailableQueue; 00075 } 00076 00077 void Schedule(); 00078 00079 private: 00080 void ReleaseSucc(SUnit *SU, const SDep &D); 00081 void ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle); 00082 void ListScheduleTopDown(); 00083 }; 00084 } // end anonymous namespace 00085 00086 /// Schedule - Schedule the DAG using list scheduling. 00087 void ScheduleDAGList::Schedule() { 00088 DOUT << "********** List Scheduling **********\n"; 00089 00090 // Build the scheduling graph. 00091 BuildSchedGraph(); 00092 00093 AvailableQueue->initNodes(SUnits); 00094 00095 ListScheduleTopDown(); 00096 00097 AvailableQueue->releaseState(); 00098 } 00099 00100 //===----------------------------------------------------------------------===// 00101 // Top-Down Scheduling 00102 //===----------------------------------------------------------------------===// 00103 00104 /// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to 00105 /// the PendingQueue if the count reaches zero. Also update its cycle bound. 00106 void ScheduleDAGList::ReleaseSucc(SUnit *SU, const SDep &D) { 00107 SUnit *SuccSU = D.getSUnit(); 00108 --SuccSU->NumPredsLeft; 00109 00110 #ifndef NDEBUG 00111 if (SuccSU->NumPredsLeft < 0) { 00112 cerr << "*** Scheduling failed! ***\n"; 00113 SuccSU->dump(this); 00114 cerr << " has been released too many times!\n"; 00115 assert(0); 00116 } 00117 #endif 00118 00119 SuccSU->setDepthToAtLeast(SU->getDepth() + D.getLatency()); 00120 00121 if (SuccSU->NumPredsLeft == 0) { 00122 PendingQueue.push_back(SuccSU); 00123 } 00124 } 00125 00126 /// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending 00127 /// count of its successors. If a successor pending count is zero, add it to 00128 /// the Available queue. 00129 void ScheduleDAGList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) { 00130 DOUT << "*** Scheduling [" << CurCycle << "]: "; 00131 DEBUG(SU->dump(this)); 00132 00133 Sequence.push_back(SU); 00134 assert(CurCycle >= SU->getDepth() && "Node scheduled above its depth!"); 00135 SU->setDepthToAtLeast(CurCycle); 00136 00137 // Top down: release successors. 00138 for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); 00139 I != E; ++I) { 00140 assert(!I->isAssignedRegDep() && 00141 "The list-td scheduler doesn't yet support physreg dependencies!"); 00142 00143 ReleaseSucc(SU, *I); 00144 } 00145 00146 SU->isScheduled = true; 00147 AvailableQueue->ScheduledNode(SU); 00148 } 00149 00150 /// ListScheduleTopDown - The main loop of list scheduling for top-down 00151 /// schedulers. 00152 void ScheduleDAGList::ListScheduleTopDown() { 00153 unsigned CurCycle = 0; 00154 00155 // All leaves to Available queue. 00156 for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { 00157 // It is available if it has no predecessors. 00158 if (SUnits[i].Preds.empty()) { 00159 AvailableQueue->push(&SUnits[i]); 00160 SUnits[i].isAvailable = true; 00161 } 00162 } 00163 00164 // While Available queue is not empty, grab the node with the highest 00165 // priority. If it is not ready put it back. Schedule the node. 00166 std::vector<SUnit*> NotReady; 00167 Sequence.reserve(SUnits.size()); 00168 while (!AvailableQueue->empty() || !PendingQueue.empty()) { 00169 // Check to see if any of the pending instructions are ready to issue. If 00170 // so, add them to the available queue. 00171 for (unsigned i = 0, e = PendingQueue.size(); i != e; ++i) { 00172 if (PendingQueue[i]->getDepth() == CurCycle) { 00173 AvailableQueue->push(PendingQueue[i]); 00174 PendingQueue[i]->isAvailable = true; 00175 PendingQueue[i] = PendingQueue.back(); 00176 PendingQueue.pop_back(); 00177 --i; --e; 00178 } else { 00179 assert(PendingQueue[i]->getDepth() > CurCycle && "Negative latency?"); 00180 } 00181 } 00182 00183 // If there are no instructions available, don't try to issue anything, and 00184 // don't advance the hazard recognizer. 00185 if (AvailableQueue->empty()) { 00186 ++CurCycle; 00187 continue; 00188 } 00189 00190 SUnit *FoundSUnit = 0; 00191 00192 bool HasNoopHazards = false; 00193 while (!AvailableQueue->empty()) { 00194 SUnit *CurSUnit = AvailableQueue->pop(); 00195 00196 ScheduleHazardRecognizer::HazardType HT = 00197 HazardRec->getHazardType(CurSUnit); 00198 if (HT == ScheduleHazardRecognizer::NoHazard) { 00199 FoundSUnit = CurSUnit; 00200 break; 00201 } 00202 00203 // Remember if this is a noop hazard. 00204 HasNoopHazards |= HT == ScheduleHazardRecognizer::NoopHazard; 00205 00206 NotReady.push_back(CurSUnit); 00207 } 00208 00209 // Add the nodes that aren't ready back onto the available list. 00210 if (!NotReady.empty()) { 00211 AvailableQueue->push_all(NotReady); 00212 NotReady.clear(); 00213 } 00214 00215 // If we found a node to schedule, do it now. 00216 if (FoundSUnit) { 00217 ScheduleNodeTopDown(FoundSUnit, CurCycle); 00218 HazardRec->EmitInstruction(FoundSUnit); 00219 00220 // If this is a pseudo-op node, we don't want to increment the current 00221 // cycle. 00222 if (FoundSUnit->Latency) // Don't increment CurCycle for pseudo-ops! 00223 ++CurCycle; 00224 } else if (!HasNoopHazards) { 00225 // Otherwise, we have a pipeline stall, but no other problem, just advance 00226 // the current cycle and try again. 00227 DOUT << "*** Advancing cycle, no work to do\n"; 00228 HazardRec->AdvanceCycle(); 00229 ++NumStalls; 00230 ++CurCycle; 00231 } else { 00232 // Otherwise, we have no instructions to issue and we have instructions 00233 // that will fault if we don't do this right. This is the case for 00234 // processors without pipeline interlocks and other cases. 00235 DOUT << "*** Emitting noop\n"; 00236 HazardRec->EmitNoop(); 00237 Sequence.push_back(0); // NULL here means noop 00238 ++NumNoops; 00239 ++CurCycle; 00240 } 00241 } 00242 00243 #ifndef NDEBUG 00244 VerifySchedule(/*isBottomUp=*/false); 00245 #endif 00246 } 00247 00248 //===----------------------------------------------------------------------===// 00249 // Public Constructor Functions 00250 //===----------------------------------------------------------------------===// 00251 00252 /// createTDListDAGScheduler - This creates a top-down list scheduler with a 00253 /// new hazard recognizer. This scheduler takes ownership of the hazard 00254 /// recognizer and deletes it when done. 00255 ScheduleDAG* llvm::createTDListDAGScheduler(SelectionDAGISel *IS, 00256 bool Fast) { 00257 return new ScheduleDAGList(*IS->MF, 00258 new LatencyPriorityQueue(), 00259 IS->CreateTargetHazardRecognizer()); 00260 }