LLVM API Documentation

ScheduleDAG.cpp

Go to the documentation of this file.
00001 //===---- ScheduleDAG.cpp - Implement the ScheduleDAG class ---------------===//
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 the ScheduleDAG class, which is a base class used by
00011 // scheduling implementation classes.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #define DEBUG_TYPE "pre-RA-sched"
00016 #include "llvm/CodeGen/ScheduleDAG.h"
00017 #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
00018 #include "llvm/Target/TargetMachine.h"
00019 #include "llvm/Target/TargetInstrInfo.h"
00020 #include "llvm/Target/TargetRegisterInfo.h"
00021 #include "llvm/Support/Debug.h"
00022 #include <climits>
00023 using namespace llvm;
00024 
00025 ScheduleDAG::ScheduleDAG(MachineFunction &mf)
00026   : DAG(0), BB(0), TM(mf.getTarget()),
00027     TII(TM.getInstrInfo()),
00028     TRI(TM.getRegisterInfo()),
00029     TLI(TM.getTargetLowering()),
00030     MF(mf), MRI(mf.getRegInfo()),
00031     ConstPool(MF.getConstantPool()) {
00032 }
00033 
00034 ScheduleDAG::~ScheduleDAG() {}
00035 
00036 /// dump - dump the schedule.
00037 void ScheduleDAG::dumpSchedule() const {
00038   for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
00039     if (SUnit *SU = Sequence[i])
00040       SU->dump(this);
00041     else
00042       cerr << "**** NOOP ****\n";
00043   }
00044 }
00045 
00046 
00047 /// Run - perform scheduling.
00048 ///
00049 void ScheduleDAG::Run(SelectionDAG *dag, MachineBasicBlock *bb,
00050                       MachineBasicBlock::iterator begin,
00051                       MachineBasicBlock::iterator end) {
00052   assert((!dag || begin == end) &&
00053          "An instruction range was given for SelectionDAG scheduling!");
00054 
00055   SUnits.clear();
00056   Sequence.clear();
00057   DAG = dag;
00058   BB = bb;
00059   Begin = begin;
00060   End = end;
00061 
00062   Schedule();
00063   
00064   DOUT << "*** Final schedule ***\n";
00065   DEBUG(dumpSchedule());
00066   DOUT << "\n";
00067 }
00068 
00069 /// addPred - This adds the specified edge as a pred of the current node if
00070 /// not already.  It also adds the current node as a successor of the
00071 /// specified node.
00072 void SUnit::addPred(const SDep &D) {
00073   // If this node already has this depenence, don't add a redundant one.
00074   for (unsigned i = 0, e = (unsigned)Preds.size(); i != e; ++i)
00075     if (Preds[i] == D)
00076       return;
00077   // Now add a corresponding succ to N.
00078   SDep P = D;
00079   P.setSUnit(this);
00080   SUnit *N = D.getSUnit();
00081   // Update the bookkeeping.
00082   if (D.getKind() == SDep::Data) {
00083     ++NumPreds;
00084     ++N->NumSuccs;
00085   }
00086   if (!N->isScheduled)
00087     ++NumPredsLeft;
00088   if (!isScheduled)
00089     ++N->NumSuccsLeft;
00090   Preds.push_back(D);
00091   N->Succs.push_back(P);
00092   if (P.getLatency() != 0) {
00093     this->setDepthDirty();
00094     N->setHeightDirty();
00095   }
00096 }
00097 
00098 /// removePred - This removes the specified edge as a pred of the current
00099 /// node if it exists.  It also removes the current node as a successor of
00100 /// the specified node.
00101 void SUnit::removePred(const SDep &D) {
00102   // Find the matching predecessor.
00103   for (SmallVector<SDep, 4>::iterator I = Preds.begin(), E = Preds.end();
00104        I != E; ++I)
00105     if (*I == D) {
00106       bool FoundSucc = false;
00107       // Find the corresponding successor in N.
00108       SDep P = D;
00109       P.setSUnit(this);
00110       SUnit *N = D.getSUnit();
00111       for (SmallVector<SDep, 4>::iterator II = N->Succs.begin(),
00112              EE = N->Succs.end(); II != EE; ++II)
00113         if (*II == P) {
00114           FoundSucc = true;
00115           N->Succs.erase(II);
00116           break;
00117         }
00118       assert(FoundSucc && "Mismatching preds / succs lists!");
00119       Preds.erase(I);
00120       // Update the bookkeeping.
00121       if (P.getKind() == SDep::Data) {
00122         --NumPreds;
00123         --N->NumSuccs;
00124       }
00125       if (!N->isScheduled)
00126         --NumPredsLeft;
00127       if (!isScheduled)
00128         --N->NumSuccsLeft;
00129       if (P.getLatency() != 0) {
00130         this->setDepthDirty();
00131         N->setHeightDirty();
00132       }
00133       return;
00134     }
00135 }
00136 
00137 void SUnit::setDepthDirty() {
00138   if (!isDepthCurrent) return;
00139   SmallVector<SUnit*, 8> WorkList;
00140   WorkList.push_back(this);
00141   do {
00142     SUnit *SU = WorkList.pop_back_val();
00143     SU->isDepthCurrent = false;
00144     for (SUnit::const_succ_iterator I = SU->Succs.begin(),
00145          E = SU->Succs.end(); I != E; ++I) {
00146       SUnit *SuccSU = I->getSUnit();
00147       if (SuccSU->isDepthCurrent)
00148         WorkList.push_back(SuccSU);
00149     }
00150   } while (!WorkList.empty());
00151 }
00152 
00153 void SUnit::setHeightDirty() {
00154   if (!isHeightCurrent) return;
00155   SmallVector<SUnit*, 8> WorkList;
00156   WorkList.push_back(this);
00157   do {
00158     SUnit *SU = WorkList.pop_back_val();
00159     SU->isHeightCurrent = false;
00160     for (SUnit::const_pred_iterator I = SU->Preds.begin(),
00161          E = SU->Preds.end(); I != E; ++I) {
00162       SUnit *PredSU = I->getSUnit();
00163       if (PredSU->isHeightCurrent)
00164         WorkList.push_back(PredSU);
00165     }
00166   } while (!WorkList.empty());
00167 }
00168 
00169 /// setDepthToAtLeast - Update this node's successors to reflect the
00170 /// fact that this node's depth just increased.
00171 ///
00172 void SUnit::setDepthToAtLeast(unsigned NewDepth) {
00173   if (NewDepth <= getDepth())
00174     return;
00175   setDepthDirty();
00176   Depth = NewDepth;
00177   isDepthCurrent = true;
00178 }
00179 
00180 /// setHeightToAtLeast - Update this node's predecessors to reflect the
00181 /// fact that this node's height just increased.
00182 ///
00183 void SUnit::setHeightToAtLeast(unsigned NewHeight) {
00184   if (NewHeight <= getHeight())
00185     return;
00186   setHeightDirty();
00187   Height = NewHeight;
00188   isHeightCurrent = true;
00189 }
00190 
00191 /// ComputeDepth - Calculate the maximal path from the node to the exit.
00192 ///
00193 void SUnit::ComputeDepth() {
00194   SmallVector<SUnit*, 8> WorkList;
00195   WorkList.push_back(this);
00196   do {
00197     SUnit *Cur = WorkList.back();
00198 
00199     bool Done = true;
00200     unsigned MaxPredDepth = 0;
00201     for (SUnit::const_pred_iterator I = Cur->Preds.begin(),
00202          E = Cur->Preds.end(); I != E; ++I) {
00203       SUnit *PredSU = I->getSUnit();
00204       if (PredSU->isDepthCurrent)
00205         MaxPredDepth = std::max(MaxPredDepth,
00206                                 PredSU->Depth + I->getLatency());
00207       else {
00208         Done = false;
00209         WorkList.push_back(PredSU);
00210       }
00211     }
00212 
00213     if (Done) {
00214       WorkList.pop_back();
00215       if (MaxPredDepth != Cur->Depth) {
00216         Cur->setDepthDirty();
00217         Cur->Depth = MaxPredDepth;
00218       }
00219       Cur->isDepthCurrent = true;
00220     }
00221   } while (!WorkList.empty());
00222 }
00223 
00224 /// ComputeHeight - Calculate the maximal path from the node to the entry.
00225 ///
00226 void SUnit::ComputeHeight() {
00227   SmallVector<SUnit*, 8> WorkList;
00228   WorkList.push_back(this);
00229   do {
00230     SUnit *Cur = WorkList.back();
00231 
00232     bool Done = true;
00233     unsigned MaxSuccHeight = 0;
00234     for (SUnit::const_succ_iterator I = Cur->Succs.begin(),
00235          E = Cur->Succs.end(); I != E; ++I) {
00236       SUnit *SuccSU = I->getSUnit();
00237       if (SuccSU->isHeightCurrent)
00238         MaxSuccHeight = std::max(MaxSuccHeight,
00239                                  SuccSU->Height + I->getLatency());
00240       else {
00241         Done = false;
00242         WorkList.push_back(SuccSU);
00243       }
00244     }
00245 
00246     if (Done) {
00247       WorkList.pop_back();
00248       if (MaxSuccHeight != Cur->Height) {
00249         Cur->setHeightDirty();
00250         Cur->Height = MaxSuccHeight;
00251       }
00252       Cur->isHeightCurrent = true;
00253     }
00254   } while (!WorkList.empty());
00255 }
00256 
00257 /// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or
00258 /// a group of nodes flagged together.
00259 void SUnit::dump(const ScheduleDAG *G) const {
00260   cerr << "SU(" << NodeNum << "): ";
00261   G->dumpNode(this);
00262 }
00263 
00264 void SUnit::dumpAll(const ScheduleDAG *G) const {
00265   dump(G);
00266 
00267   cerr << "  # preds left       : " << NumPredsLeft << "\n";
00268   cerr << "  # succs left       : " << NumSuccsLeft << "\n";
00269   cerr << "  Latency            : " << Latency << "\n";
00270   cerr << "  Depth              : " << Depth << "\n";
00271   cerr << "  Height             : " << Height << "\n";
00272 
00273   if (Preds.size() != 0) {
00274     cerr << "  Predecessors:\n";
00275     for (SUnit::const_succ_iterator I = Preds.begin(), E = Preds.end();
00276          I != E; ++I) {
00277       cerr << "   ";
00278       switch (I->getKind()) {
00279       case SDep::Data:        cerr << "val "; break;
00280       case SDep::Anti:        cerr << "anti"; break;
00281       case SDep::Output:      cerr << "out "; break;
00282       case SDep::Order:       cerr << "ch  "; break;
00283       }
00284       cerr << "#";
00285       cerr << I->getSUnit() << " - SU(" << I->getSUnit()->NodeNum << ")";
00286       if (I->isArtificial())
00287         cerr << " *";
00288       cerr << "\n";
00289     }
00290   }
00291   if (Succs.size() != 0) {
00292     cerr << "  Successors:\n";
00293     for (SUnit::const_succ_iterator I = Succs.begin(), E = Succs.end();
00294          I != E; ++I) {
00295       cerr << "   ";
00296       switch (I->getKind()) {
00297       case SDep::Data:        cerr << "val "; break;
00298       case SDep::Anti:        cerr << "anti"; break;
00299       case SDep::Output:      cerr << "out "; break;
00300       case SDep::Order:       cerr << "ch  "; break;
00301       }
00302       cerr << "#";
00303       cerr << I->getSUnit() << " - SU(" << I->getSUnit()->NodeNum << ")";
00304       if (I->isArtificial())
00305         cerr << " *";
00306       cerr << "\n";
00307     }
00308   }
00309   cerr << "\n";
00310 }
00311 
00312 #ifndef NDEBUG
00313 /// VerifySchedule - Verify that all SUnits were scheduled and that
00314 /// their state is consistent.
00315 ///
00316 void ScheduleDAG::VerifySchedule(bool isBottomUp) {
00317   bool AnyNotSched = false;
00318   unsigned DeadNodes = 0;
00319   unsigned Noops = 0;
00320   for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
00321     if (!SUnits[i].isScheduled) {
00322       if (SUnits[i].NumPreds == 0 && SUnits[i].NumSuccs == 0) {
00323         ++DeadNodes;
00324         continue;
00325       }
00326       if (!AnyNotSched)
00327         cerr << "*** Scheduling failed! ***\n";
00328       SUnits[i].dump(this);
00329       cerr << "has not been scheduled!\n";
00330       AnyNotSched = true;
00331     }
00332     if (SUnits[i].isScheduled &&
00333         (isBottomUp ? SUnits[i].getHeight() : SUnits[i].getHeight()) >
00334           unsigned(INT_MAX)) {
00335       if (!AnyNotSched)
00336         cerr << "*** Scheduling failed! ***\n";
00337       SUnits[i].dump(this);
00338       cerr << "has an unexpected "
00339            << (isBottomUp ? "Height" : "Depth") << " value!\n";
00340       AnyNotSched = true;
00341     }
00342     if (isBottomUp) {
00343       if (SUnits[i].NumSuccsLeft != 0) {
00344         if (!AnyNotSched)
00345           cerr << "*** Scheduling failed! ***\n";
00346         SUnits[i].dump(this);
00347         cerr << "has successors left!\n";
00348         AnyNotSched = true;
00349       }
00350     } else {
00351       if (SUnits[i].NumPredsLeft != 0) {
00352         if (!AnyNotSched)
00353           cerr << "*** Scheduling failed! ***\n";
00354         SUnits[i].dump(this);
00355         cerr << "has predecessors left!\n";
00356         AnyNotSched = true;
00357       }
00358     }
00359   }
00360   for (unsigned i = 0, e = Sequence.size(); i != e; ++i)
00361     if (!Sequence[i])
00362       ++Noops;
00363   assert(!AnyNotSched);
00364   assert(Sequence.size() + DeadNodes - Noops == SUnits.size() &&
00365          "The number of nodes scheduled doesn't match the expected number!");
00366 }
00367 #endif
00368 
00369 /// InitDAGTopologicalSorting - create the initial topological 
00370 /// ordering from the DAG to be scheduled.
00371 ///
00372 /// The idea of the algorithm is taken from 
00373 /// "Online algorithms for managing the topological order of
00374 /// a directed acyclic graph" by David J. Pearce and Paul H.J. Kelly
00375 /// This is the MNR algorithm, which was first introduced by 
00376 /// A. Marchetti-Spaccamela, U. Nanni and H. Rohnert in  
00377 /// "Maintaining a topological order under edge insertions".
00378 ///
00379 /// Short description of the algorithm: 
00380 ///
00381 /// Topological ordering, ord, of a DAG maps each node to a topological
00382 /// index so that for all edges X->Y it is the case that ord(X) < ord(Y).
00383 ///
00384 /// This means that if there is a path from the node X to the node Z, 
00385 /// then ord(X) < ord(Z).
00386 ///
00387 /// This property can be used to check for reachability of nodes:
00388 /// if Z is reachable from X, then an insertion of the edge Z->X would 
00389 /// create a cycle.
00390 ///
00391 /// The algorithm first computes a topological ordering for the DAG by
00392 /// initializing the Index2Node and Node2Index arrays and then tries to keep
00393 /// the ordering up-to-date after edge insertions by reordering the DAG.
00394 ///
00395 /// On insertion of the edge X->Y, the algorithm first marks by calling DFS
00396 /// the nodes reachable from Y, and then shifts them using Shift to lie
00397 /// immediately after X in Index2Node.
00398 void ScheduleDAGTopologicalSort::InitDAGTopologicalSorting() {
00399   unsigned DAGSize = SUnits.size();
00400   std::vector<SUnit*> WorkList;
00401   WorkList.reserve(DAGSize);
00402 
00403   Index2Node.resize(DAGSize);
00404   Node2Index.resize(DAGSize);
00405 
00406   // Initialize the data structures.
00407   for (unsigned i = 0, e = DAGSize; i != e; ++i) {
00408     SUnit *SU = &SUnits[i];
00409     int NodeNum = SU->NodeNum;
00410     unsigned Degree = SU->Succs.size();
00411     // Temporarily use the Node2Index array as scratch space for degree counts.
00412     Node2Index[NodeNum] = Degree;
00413 
00414     // Is it a node without dependencies?
00415     if (Degree == 0) {
00416       assert(SU->Succs.empty() && "SUnit should have no successors");
00417       // Collect leaf nodes.
00418       WorkList.push_back(SU);
00419     }
00420   }  
00421 
00422   int Id = DAGSize;
00423   while (!WorkList.empty()) {
00424     SUnit *SU = WorkList.back();
00425     WorkList.pop_back();
00426     Allocate(SU->NodeNum, --Id);
00427     for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
00428          I != E; ++I) {
00429       SUnit *SU = I->getSUnit();
00430       if (!--Node2Index[SU->NodeNum])
00431         // If all dependencies of the node are processed already,
00432         // then the node can be computed now.
00433         WorkList.push_back(SU);
00434     }
00435   }
00436 
00437   Visited.resize(DAGSize);
00438 
00439 #ifndef NDEBUG
00440   // Check correctness of the ordering
00441   for (unsigned i = 0, e = DAGSize; i != e; ++i) {
00442     SUnit *SU = &SUnits[i];
00443     for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
00444          I != E; ++I) {
00445       assert(Node2Index[SU->NodeNum] > Node2Index[I->getSUnit()->NodeNum] && 
00446       "Wrong topological sorting");
00447     }
00448   }
00449 #endif
00450 }
00451 
00452 /// AddPred - Updates the topological ordering to accomodate an edge
00453 /// to be added from SUnit X to SUnit Y.
00454 void ScheduleDAGTopologicalSort::AddPred(SUnit *Y, SUnit *X) {
00455   int UpperBound, LowerBound;
00456   LowerBound = Node2Index[Y->NodeNum];
00457   UpperBound = Node2Index[X->NodeNum];
00458   bool HasLoop = false;
00459   // Is Ord(X) < Ord(Y) ?
00460   if (LowerBound < UpperBound) {
00461     // Update the topological order.
00462     Visited.reset();
00463     DFS(Y, UpperBound, HasLoop);
00464     assert(!HasLoop && "Inserted edge creates a loop!");
00465     // Recompute topological indexes.
00466     Shift(Visited, LowerBound, UpperBound);
00467   }
00468 }
00469 
00470 /// RemovePred - Updates the topological ordering to accomodate an
00471 /// an edge to be removed from the specified node N from the predecessors
00472 /// of the current node M.
00473 void ScheduleDAGTopologicalSort::RemovePred(SUnit *M, SUnit *N) {
00474   // InitDAGTopologicalSorting();
00475 }
00476 
00477 /// DFS - Make a DFS traversal to mark all nodes reachable from SU and mark
00478 /// all nodes affected by the edge insertion. These nodes will later get new
00479 /// topological indexes by means of the Shift method.
00480 void ScheduleDAGTopologicalSort::DFS(const SUnit *SU, int UpperBound,
00481                                      bool& HasLoop) {
00482   std::vector<const SUnit*> WorkList;
00483   WorkList.reserve(SUnits.size()); 
00484 
00485   WorkList.push_back(SU);
00486   do {
00487     SU = WorkList.back();
00488     WorkList.pop_back();
00489     Visited.set(SU->NodeNum);
00490     for (int I = SU->Succs.size()-1; I >= 0; --I) {
00491       int s = SU->Succs[I].getSUnit()->NodeNum;
00492       if (Node2Index[s] == UpperBound) {
00493         HasLoop = true; 
00494         return;
00495       }
00496       // Visit successors if not already and in affected region.
00497       if (!Visited.test(s) && Node2Index[s] < UpperBound) {
00498         WorkList.push_back(SU->Succs[I].getSUnit());
00499       } 
00500     } 
00501   } while (!WorkList.empty());
00502 }
00503 
00504 /// Shift - Renumber the nodes so that the topological ordering is 
00505 /// preserved.
00506 void ScheduleDAGTopologicalSort::Shift(BitVector& Visited, int LowerBound, 
00507                                        int UpperBound) {
00508   std::vector<int> L;
00509   int shift = 0;
00510   int i;
00511 
00512   for (i = LowerBound; i <= UpperBound; ++i) {
00513     // w is node at topological index i.
00514     int w = Index2Node[i];
00515     if (Visited.test(w)) {
00516       // Unmark.
00517       Visited.reset(w);
00518       L.push_back(w);
00519       shift = shift + 1;
00520     } else {
00521       Allocate(w, i - shift);
00522     }
00523   }
00524 
00525   for (unsigned j = 0; j < L.size(); ++j) {
00526     Allocate(L[j], i - shift);
00527     i = i + 1;
00528   }
00529 }
00530 
00531 
00532 /// WillCreateCycle - Returns true if adding an edge from SU to TargetSU will
00533 /// create a cycle.
00534 bool ScheduleDAGTopologicalSort::WillCreateCycle(SUnit *SU, SUnit *TargetSU) {
00535   if (IsReachable(TargetSU, SU))
00536     return true;
00537   for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
00538        I != E; ++I)
00539     if (I->isAssignedRegDep() &&
00540         IsReachable(TargetSU, I->getSUnit()))
00541       return true;
00542   return false;
00543 }
00544 
00545 /// IsReachable - Checks if SU is reachable from TargetSU.
00546 bool ScheduleDAGTopologicalSort::IsReachable(const SUnit *SU,
00547                                              const SUnit *TargetSU) {
00548   // If insertion of the edge SU->TargetSU would create a cycle
00549   // then there is a path from TargetSU to SU.
00550   int UpperBound, LowerBound;
00551   LowerBound = Node2Index[TargetSU->NodeNum];
00552   UpperBound = Node2Index[SU->NodeNum];
00553   bool HasLoop = false;
00554   // Is Ord(TargetSU) < Ord(SU) ?
00555   if (LowerBound < UpperBound) {
00556     Visited.reset();
00557     // There may be a path from TargetSU to SU. Check for it. 
00558     DFS(TargetSU, UpperBound, HasLoop);
00559   }
00560   return HasLoop;
00561 }
00562 
00563 /// Allocate - assign the topological index to the node n.
00564 void ScheduleDAGTopologicalSort::Allocate(int n, int index) {
00565   Node2Index[n] = index;
00566   Index2Node[index] = n;
00567 }
00568 
00569 ScheduleDAGTopologicalSort::ScheduleDAGTopologicalSort(
00570                                                      std::vector<SUnit> &sunits)
00571  : SUnits(sunits) {}
00572 
00573 ScheduleHazardRecognizer::~ScheduleHazardRecognizer() {}