LLVM API Documentation
00001 //===---- LatencyPriorityQueue.cpp - A latency-oriented priority queue ----===// 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 file implements the LatencyPriorityQueue class, which is a 00011 // SchedulingPriorityQueue that schedules using latency information to 00012 // reduce the length of the critical path through the basic block. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #define DEBUG_TYPE "scheduler" 00017 #include "llvm/CodeGen/LatencyPriorityQueue.h" 00018 #include "llvm/Support/Debug.h" 00019 using namespace llvm; 00020 00021 bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const { 00022 // The isScheduleHigh flag allows nodes with wraparound dependencies that 00023 // cannot easily be modeled as edges with latencies to be scheduled as 00024 // soon as possible in a top-down schedule. 00025 if (LHS->isScheduleHigh && !RHS->isScheduleHigh) 00026 return false; 00027 if (!LHS->isScheduleHigh && RHS->isScheduleHigh) 00028 return true; 00029 00030 unsigned LHSNum = LHS->NodeNum; 00031 unsigned RHSNum = RHS->NodeNum; 00032 00033 // The most important heuristic is scheduling the critical path. 00034 unsigned LHSLatency = PQ->getLatency(LHSNum); 00035 unsigned RHSLatency = PQ->getLatency(RHSNum); 00036 if (LHSLatency < RHSLatency) return true; 00037 if (LHSLatency > RHSLatency) return false; 00038 00039 // After that, if two nodes have identical latencies, look to see if one will 00040 // unblock more other nodes than the other. 00041 unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum); 00042 unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum); 00043 if (LHSBlocked < RHSBlocked) return true; 00044 if (LHSBlocked > RHSBlocked) return false; 00045 00046 // Finally, just to provide a stable ordering, use the node number as a 00047 // deciding factor. 00048 return LHSNum < RHSNum; 00049 } 00050 00051 00052 /// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor 00053 /// of SU, return it, otherwise return null. 00054 SUnit *LatencyPriorityQueue::getSingleUnscheduledPred(SUnit *SU) { 00055 SUnit *OnlyAvailablePred = 0; 00056 for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); 00057 I != E; ++I) { 00058 SUnit &Pred = *I->getSUnit(); 00059 if (!Pred.isScheduled) { 00060 // We found an available, but not scheduled, predecessor. If it's the 00061 // only one we have found, keep track of it... otherwise give up. 00062 if (OnlyAvailablePred && OnlyAvailablePred != &Pred) 00063 return 0; 00064 OnlyAvailablePred = &Pred; 00065 } 00066 } 00067 00068 return OnlyAvailablePred; 00069 } 00070 00071 void LatencyPriorityQueue::push_impl(SUnit *SU) { 00072 // Look at all of the successors of this node. Count the number of nodes that 00073 // this node is the sole unscheduled node for. 00074 unsigned NumNodesBlocking = 0; 00075 for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); 00076 I != E; ++I) 00077 if (getSingleUnscheduledPred(I->getSUnit()) == SU) 00078 ++NumNodesBlocking; 00079 NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking; 00080 00081 Queue.push(SU); 00082 } 00083 00084 00085 // ScheduledNode - As nodes are scheduled, we look to see if there are any 00086 // successor nodes that have a single unscheduled predecessor. If so, that 00087 // single predecessor has a higher priority, since scheduling it will make 00088 // the node available. 00089 void LatencyPriorityQueue::ScheduledNode(SUnit *SU) { 00090 for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); 00091 I != E; ++I) 00092 AdjustPriorityOfUnscheduledPreds(I->getSUnit()); 00093 } 00094 00095 /// AdjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just 00096 /// scheduled. If SU is not itself available, then there is at least one 00097 /// predecessor node that has not been scheduled yet. If SU has exactly ONE 00098 /// unscheduled predecessor, we want to increase its priority: it getting 00099 /// scheduled will make this node available, so it is better than some other 00100 /// node of the same priority that will not make a node available. 00101 void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) { 00102 if (SU->isAvailable) return; // All preds scheduled. 00103 00104 SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU); 00105 if (OnlyAvailablePred == 0 || !OnlyAvailablePred->isAvailable) return; 00106 00107 // Okay, we found a single predecessor that is available, but not scheduled. 00108 // Since it is available, it must be in the priority queue. First remove it. 00109 remove(OnlyAvailablePred); 00110 00111 // Reinsert the node into the priority queue, which recomputes its 00112 // NumNodesSolelyBlocking value. 00113 push(OnlyAvailablePred); 00114 }