Changes to build successfully with GCC 3.02
[oota-llvm.git] / lib / Target / SparcV9 / InstrSched / SchedPriorities.cpp
1 // $Id$ -*-C++-*-
2 //***************************************************************************
3 // File:
4 //      SchedPriorities.h
5 // 
6 // Purpose:
7 //      Encapsulate heuristics for instruction scheduling.
8 // 
9 // Strategy:
10 //    Priority ordering rules:
11 //    (1) Max delay, which is the order of the heap S.candsAsHeap.
12 //    (2) Instruction that frees up a register.
13 //    (3) Instruction that has the maximum number of dependent instructions.
14 //    Note that rules 2 and 3 are only used if issue conflicts prevent
15 //    choosing a higher priority instruction by rule 1.
16 // 
17 // History:
18 //      7/30/01  -  Vikram Adve  -  Created
19 //**************************************************************************/
20
21 #include "SchedPriorities.h"
22 #include "Support/PostOrderIterator.h"
23 #include <iostream>
24 using std::cerr;
25
26 SchedPriorities::SchedPriorities(const Method* method,
27                                  const SchedGraph* _graph)
28   : curTime(0),
29     graph(_graph),
30     methodLiveVarInfo(method),                            // expensive!
31     nodeDelayVec(_graph->getNumNodes(), INVALID_LATENCY), // make errors obvious
32     earliestForNode(_graph->getNumNodes(), 0),
33     earliestReadyTime(0),
34     nextToTry(candsAsHeap.begin())
35 {
36   methodLiveVarInfo.analyze();
37   computeDelays(graph);
38 }
39
40
41 void
42 SchedPriorities::initialize()
43 {
44   initializeReadyHeap(graph);
45 }
46
47
48 void
49 SchedPriorities::computeDelays(const SchedGraph* graph)
50 {
51   po_iterator<const SchedGraph*> poIter = po_begin(graph), poEnd =po_end(graph);
52   for ( ; poIter != poEnd; ++poIter)
53     {
54       const SchedGraphNode* node = *poIter;
55       cycles_t nodeDelay;
56       if (node->beginOutEdges() == node->endOutEdges())
57         nodeDelay = node->getLatency();
58       else
59         {
60           // Iterate over the out-edges of the node to compute delay
61           nodeDelay = 0;
62           for (SchedGraphNode::const_iterator E=node->beginOutEdges();
63                E != node->endOutEdges(); ++E)
64             {
65               cycles_t sinkDelay = getNodeDelayRef((*E)->getSink());
66               nodeDelay = std::max(nodeDelay, sinkDelay + (*E)->getMinDelay());
67             }
68         }
69       getNodeDelayRef(node) = nodeDelay;
70     }
71 }
72
73
74 void
75 SchedPriorities::initializeReadyHeap(const SchedGraph* graph)
76 {
77   const SchedGraphNode* graphRoot = graph->getRoot();
78   assert(graphRoot->getMachineInstr() == NULL && "Expect dummy root");
79   
80   // Insert immediate successors of dummy root, which are the actual roots
81   sg_succ_const_iterator SEnd = succ_end(graphRoot);
82   for (sg_succ_const_iterator S = succ_begin(graphRoot); S != SEnd; ++S)
83     this->insertReady(*S);
84   
85 #undef TEST_HEAP_CONVERSION
86 #ifdef TEST_HEAP_CONVERSION
87   cerr << "Before heap conversion:\n";
88   copy(candsAsHeap.begin(), candsAsHeap.end(),
89        ostream_iterator<NodeDelayPair*>(cerr,"\n"));
90 #endif
91   
92   candsAsHeap.makeHeap();
93   
94 #ifdef TEST_HEAP_CONVERSION
95   cerr << "After heap conversion:\n";
96   copy(candsAsHeap.begin(), candsAsHeap.end(),
97        ostream_iterator<NodeDelayPair*>(cerr,"\n"));
98 #endif
99 }
100
101 void
102 SchedPriorities::insertReady(const SchedGraphNode* node)
103 {
104   candsAsHeap.insert(node, nodeDelayVec[node->getNodeId()]);
105   candsAsSet.insert(node);
106   mcands.clear(); // ensure reset choices is called before any more choices
107   earliestReadyTime = std::min(earliestReadyTime,
108                                earliestForNode[node->getNodeId()]);
109   
110   if (SchedDebugLevel >= Sched_PrintSchedTrace)
111     {
112       cerr << "    Cycle " << (long)getTime() << ": "
113            << " Node " << node->getNodeId() << " is ready; "
114            << " Delay = " << (long)getNodeDelayRef(node) << "; Instruction: \n";
115       cerr << "        " << *node->getMachineInstr() << "\n";
116     }
117 }
118
119 void
120 SchedPriorities::issuedReadyNodeAt(cycles_t curTime,
121                                    const SchedGraphNode* node)
122 {
123   candsAsHeap.removeNode(node);
124   candsAsSet.erase(node);
125   mcands.clear(); // ensure reset choices is called before any more choices
126   
127   if (earliestReadyTime == getEarliestForNodeRef(node))
128     {// earliestReadyTime may have been due to this node, so recompute it
129       earliestReadyTime = HUGE_LATENCY;
130       for (NodeHeap::const_iterator I=candsAsHeap.begin();
131            I != candsAsHeap.end(); ++I)
132         if (candsAsHeap.getNode(I))
133           earliestReadyTime = std::min(earliestReadyTime, 
134                                 getEarliestForNodeRef(candsAsHeap.getNode(I)));
135     }
136   
137   // Now update ready times for successors
138   for (SchedGraphNode::const_iterator E=node->beginOutEdges();
139        E != node->endOutEdges(); ++E)
140     {
141       cycles_t& etime = getEarliestForNodeRef((*E)->getSink());
142       etime = std::max(etime, curTime + (*E)->getMinDelay());
143     }    
144 }
145
146
147 //----------------------------------------------------------------------
148 // Priority ordering rules:
149 // (1) Max delay, which is the order of the heap S.candsAsHeap.
150 // (2) Instruction that frees up a register.
151 // (3) Instruction that has the maximum number of dependent instructions.
152 // Note that rules 2 and 3 are only used if issue conflicts prevent
153 // choosing a higher priority instruction by rule 1.
154 //----------------------------------------------------------------------
155
156 inline int
157 SchedPriorities::chooseByRule1(std::vector<candIndex>& mcands)
158 {
159   return (mcands.size() == 1)? 0        // only one choice exists so take it
160                              : -1;      // -1 indicates multiple choices
161 }
162
163 inline int
164 SchedPriorities::chooseByRule2(std::vector<candIndex>& mcands)
165 {
166   assert(mcands.size() >= 1 && "Should have at least one candidate here.");
167   for (unsigned i=0, N = mcands.size(); i < N; i++)
168     if (instructionHasLastUse(methodLiveVarInfo,
169                               candsAsHeap.getNode(mcands[i])))
170       return i;
171   return -1;
172 }
173
174 inline int
175 SchedPriorities::chooseByRule3(std::vector<candIndex>& mcands)
176 {
177   assert(mcands.size() >= 1 && "Should have at least one candidate here.");
178   int maxUses = candsAsHeap.getNode(mcands[0])->getNumOutEdges();       
179   int indexWithMaxUses = 0;
180   for (unsigned i=1, N = mcands.size(); i < N; i++)
181     {
182       int numUses = candsAsHeap.getNode(mcands[i])->getNumOutEdges();
183       if (numUses > maxUses)
184         {
185           maxUses = numUses;
186           indexWithMaxUses = i;
187         }
188     }
189   return indexWithMaxUses; 
190 }
191
192 const SchedGraphNode*
193 SchedPriorities::getNextHighest(const SchedulingManager& S,
194                                 cycles_t curTime)
195 {
196   int nextIdx = -1;
197   const SchedGraphNode* nextChoice = NULL;
198   
199   if (mcands.size() == 0)
200     findSetWithMaxDelay(mcands, S);
201   
202   while (nextIdx < 0 && mcands.size() > 0)
203     {
204       nextIdx = chooseByRule1(mcands);   // rule 1
205       
206       if (nextIdx == -1)
207         nextIdx = chooseByRule2(mcands); // rule 2
208       
209       if (nextIdx == -1)
210         nextIdx = chooseByRule3(mcands); // rule 3
211       
212       if (nextIdx == -1)
213         nextIdx = 0;                     // default to first choice by delays
214       
215       // We have found the next best candidate.  Check if it ready in
216       // the current cycle, and if it is feasible.
217       // If not, remove it from mcands and continue.  Refill mcands if
218       // it becomes empty.
219       nextChoice = candsAsHeap.getNode(mcands[nextIdx]);
220       if (getEarliestForNodeRef(nextChoice) > curTime
221           || ! instrIsFeasible(S, nextChoice->getMachineInstr()->getOpCode()))
222         {
223           mcands.erase(mcands.begin() + nextIdx);
224           nextIdx = -1;
225           if (mcands.size() == 0)
226             findSetWithMaxDelay(mcands, S);
227         }
228     }
229   
230   if (nextIdx >= 0)
231     {
232       mcands.erase(mcands.begin() + nextIdx);
233       return nextChoice;
234     }
235   else
236     return NULL;
237 }
238
239
240 void
241 SchedPriorities::findSetWithMaxDelay(std::vector<candIndex>& mcands,
242                                      const SchedulingManager& S)
243 {
244   if (mcands.size() == 0 && nextToTry != candsAsHeap.end())
245     { // out of choices at current maximum delay;
246       // put nodes with next highest delay in mcands
247       candIndex next = nextToTry;
248       cycles_t maxDelay = candsAsHeap.getDelay(next);
249       for (; next != candsAsHeap.end()
250              && candsAsHeap.getDelay(next) == maxDelay; ++next)
251         mcands.push_back(next);
252       
253       nextToTry = next;
254       
255       if (SchedDebugLevel >= Sched_PrintSchedTrace)
256         {
257           cerr << "    Cycle " << (long)getTime() << ": "
258                << "Next highest delay = " << (long)maxDelay << " : "
259                << mcands.size() << " Nodes with this delay: ";
260           for (unsigned i=0; i < mcands.size(); i++)
261             cerr << candsAsHeap.getNode(mcands[i])->getNodeId() << ", ";
262           cerr << "\n";
263         }
264     }
265 }
266
267
268 bool
269 SchedPriorities::instructionHasLastUse(MethodLiveVarInfo& methodLiveVarInfo,
270                                        const SchedGraphNode* graphNode)
271 {
272   const MachineInstr* minstr = graphNode->getMachineInstr();
273   
274   std::hash_map<const MachineInstr*, bool>::const_iterator
275     ui = lastUseMap.find(minstr);
276   if (ui != lastUseMap.end())
277     return ui->second;
278   
279   // else check if instruction is a last use and save it in the hash_map
280   bool hasLastUse = false;
281   const BasicBlock* bb = graphNode->getBB();
282   const LiveVarSet* liveVars =
283     methodLiveVarInfo.getLiveVarSetBeforeMInst(minstr, bb);
284   
285   for (MachineInstr::val_const_op_iterator vo(minstr); ! vo.done(); ++vo)
286     if (liveVars->find(*vo) == liveVars->end())
287       {
288         hasLastUse = true;
289         break;
290       }
291   
292   lastUseMap[minstr] = hasLastUse;
293   return hasLastUse;
294 }
295