Use alloca instead of a C99 style array. This should fix the
[oota-llvm.git] / lib / Target / TargetSchedInfo.cpp
1 //===-- SchedInfo.cpp - Generic code to support target schedulers ----------==//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the generic part of a Scheduler description for a
11 // target.  This functionality is defined in the llvm/Target/SchedInfo.h file.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/Target/TargetSchedInfo.h"
16 #include "llvm/Target/TargetMachine.h"
17 #include <algorithm>
18 #include <iostream>
19 using namespace llvm;
20
21 resourceId_t llvm::CPUResource::nextId = 0;
22 static std::vector<CPUResource*> *CPUResourceMap = 0;
23   
24 CPUResource::CPUResource(const std::string& resourceName, int maxUsers)
25     : rname(resourceName), rid(nextId++), maxNumUsers(maxUsers) {
26   if(!CPUResourceMap)
27     CPUResourceMap = new std::vector<CPUResource*>;
28
29   //Put Resource in the map
30   CPUResourceMap->push_back(this);
31 }
32
33 ///Get CPUResource if you only have the resource ID
34 CPUResource* CPUResource::getCPUResource(resourceId_t id) {
35   return (*CPUResourceMap)[id];
36 }
37
38 // Check if fromRVec and toRVec have *any* common entries.
39 // Assume the vectors are sorted in increasing order.
40 // Algorithm copied from function set_intersection() for sorted ranges
41 // (stl_algo.h).
42 //
43 inline static bool
44 RUConflict(const std::vector<resourceId_t>& fromRVec,
45            const std::vector<resourceId_t>& toRVec)
46 {
47   
48   unsigned fN = fromRVec.size(), tN = toRVec.size(); 
49   unsigned fi = 0, ti = 0;
50
51   while (fi < fN && ti < tN) {
52     if (fromRVec[fi] < toRVec[ti])
53       ++fi;
54     else if (toRVec[ti] < fromRVec[fi])
55       ++ti;
56     else
57       return true;
58   }
59   return false;
60 }
61
62
63 static cycles_t
64 ComputeMinGap(const InstrRUsage &fromRU, 
65               const InstrRUsage &toRU)
66 {
67   cycles_t minGap = 0;
68   
69   if (fromRU.numBubbles > 0)
70     minGap = fromRU.numBubbles;
71   
72   if (minGap < fromRU.numCycles) {
73     // only need to check from cycle `minGap' onwards
74     for (cycles_t gap=minGap; gap <= fromRU.numCycles-1; gap++) {
75       // check if instr. #2 can start executing `gap' cycles after #1
76       // by checking for resource conflicts in each overlapping cycle
77       cycles_t numOverlap =std::min(fromRU.numCycles - gap, toRU.numCycles);
78       for (cycles_t c = 0; c <= numOverlap-1; c++)
79         if (RUConflict(fromRU.resourcesByCycle[gap + c],
80                        toRU.resourcesByCycle[c])) {
81           // conflict found so minGap must be more than `gap'
82           minGap = gap+1;
83           break;
84         }
85     }
86   }
87   
88   return minGap;
89 }
90
91
92 //---------------------------------------------------------------------------
93 // class TargetSchedInfo
94 //      Interface to machine description for instruction scheduling
95 //---------------------------------------------------------------------------
96
97 TargetSchedInfo::TargetSchedInfo(const TargetMachine&    tgt,
98                                  int                     NumSchedClasses,
99                                  const InstrClassRUsage* ClassRUsages,
100                                  const InstrRUsageDelta* UsageDeltas,
101                                  const InstrIssueDelta*  IssueDeltas,
102                                  unsigned NumUsageDeltas,
103                                  unsigned NumIssueDeltas)
104   : target(tgt),
105     numSchedClasses(NumSchedClasses), mii(tgt.getInstrInfo()),
106     classRUsages(ClassRUsages), usageDeltas(UsageDeltas),
107     issueDeltas(IssueDeltas), numUsageDeltas(NumUsageDeltas),
108     numIssueDeltas(NumIssueDeltas)
109 {}
110
111 void
112 TargetSchedInfo::initializeResources()
113 {
114   assert(MAX_NUM_SLOTS >= (int)getMaxNumIssueTotal()
115          && "Insufficient slots for static data! Increase MAX_NUM_SLOTS");
116   
117   // First, compute common resource usage info for each class because
118   // most instructions will probably behave the same as their class.
119   // Cannot allocate a vector of InstrRUsage so new each one.
120   // 
121   std::vector<InstrRUsage> instrRUForClasses;
122   instrRUForClasses.resize(numSchedClasses);
123   for (InstrSchedClass sc = 0; sc < numSchedClasses; sc++) {
124     // instrRUForClasses.push_back(new InstrRUsage);
125     instrRUForClasses[sc].setMaxSlots(getMaxNumIssueTotal());
126     instrRUForClasses[sc].setTo(classRUsages[sc]);
127   }
128   
129   computeInstrResources(instrRUForClasses);
130   computeIssueGaps(instrRUForClasses);
131 }
132
133
134 void
135 TargetSchedInfo::computeInstrResources(const std::vector<InstrRUsage>&
136                                         instrRUForClasses)
137 {
138   int numOpCodes =  mii->getNumOpcodes();
139   instrRUsages.resize(numOpCodes);
140   
141   // First get the resource usage information from the class resource usages.
142   for (MachineOpCode op = 0; op < numOpCodes; ++op) {
143     InstrSchedClass sc = getSchedClass(op);
144     assert(sc < numSchedClasses);
145     instrRUsages[op] = instrRUForClasses[sc];
146   }
147   
148   // Now, modify the resource usages as specified in the deltas.
149   for (unsigned i = 0; i < numUsageDeltas; ++i) {
150     MachineOpCode op = usageDeltas[i].opCode;
151     assert(op < numOpCodes);
152     instrRUsages[op].addUsageDelta(usageDeltas[i]);
153   }
154   
155   // Then modify the issue restrictions as specified in the deltas.
156   for (unsigned i = 0; i < numIssueDeltas; ++i) {
157     MachineOpCode op = issueDeltas[i].opCode;
158     assert(op < numOpCodes);
159     instrRUsages[issueDeltas[i].opCode].addIssueDelta(issueDeltas[i]);
160   }
161 }
162
163
164 void
165 TargetSchedInfo::computeIssueGaps(const std::vector<InstrRUsage>&
166                                    instrRUForClasses)
167 {
168   int numOpCodes =  mii->getNumOpcodes();
169   issueGaps.resize(numOpCodes);
170   conflictLists.resize(numOpCodes);
171
172   assert(numOpCodes < (1 << MAX_OPCODE_SIZE) - 1
173          && "numOpCodes invalid for implementation of class OpCodePair!");
174
175   // First, compute issue gaps between pairs of classes based on common
176   // resources usages for each class, because most instruction pairs will
177   // usually behave the same as their class.
178   // 
179   int* classPairGaps =
180     static_cast<int*>(alloca(sizeof(int) * numSchedClasses * numSchedClasses));
181   for (InstrSchedClass fromSC=0; fromSC < numSchedClasses; fromSC++)
182     for (InstrSchedClass toSC=0; toSC < numSchedClasses; toSC++) {
183       int classPairGap = ComputeMinGap(instrRUForClasses[fromSC],
184                                        instrRUForClasses[toSC]);
185       classPairGaps[fromSC*numSchedClasses + toSC] = classPairGap; 
186     }
187
188   // Now, for each pair of instructions, use the class pair gap if both
189   // instructions have identical resource usage as their respective classes.
190   // If not, recompute the gap for the pair from scratch.
191
192   longestIssueConflict = 0;
193
194   for (MachineOpCode fromOp=0; fromOp < numOpCodes; fromOp++)
195     for (MachineOpCode toOp=0; toOp < numOpCodes; toOp++) {
196       int instrPairGap = 
197         (instrRUsages[fromOp].sameAsClass && instrRUsages[toOp].sameAsClass)
198         ? classPairGaps[getSchedClass(fromOp)*numSchedClasses + getSchedClass(toOp)]
199         : ComputeMinGap(instrRUsages[fromOp], instrRUsages[toOp]);
200
201       if (instrPairGap > 0) {
202         this->setGap(instrPairGap, fromOp, toOp);
203         conflictLists[fromOp].push_back(toOp);
204         longestIssueConflict=std::max(longestIssueConflict, instrPairGap);
205       }
206     }
207 }
208
209
210 void InstrRUsage::setTo(const InstrClassRUsage& classRU) {
211   sameAsClass   = true;
212   isSingleIssue = classRU.isSingleIssue;
213   breaksGroup   = classRU.breaksGroup; 
214   numBubbles    = classRU.numBubbles;
215   
216   for (unsigned i=0; i < classRU.numSlots; i++) {
217     unsigned slot = classRU.feasibleSlots[i];
218     assert(slot < feasibleSlots.size() && "Invalid slot specified!");
219     this->feasibleSlots[slot] = true;
220   }
221   
222   numCycles   = classRU.totCycles;
223   resourcesByCycle.resize(this->numCycles);
224   
225   for (unsigned i=0; i < classRU.numRUEntries; i++)
226     for (unsigned c=classRU.V[i].startCycle, NC = c + classRU.V[i].numCycles;
227          c < NC; c++)
228       this->resourcesByCycle[c].push_back(classRU.V[i].resourceId);
229   
230   // Sort each resource usage vector by resourceId_t to speed up conflict
231   // checking
232   for (unsigned i=0; i < this->resourcesByCycle.size(); i++)
233     std::sort(resourcesByCycle[i].begin(), resourcesByCycle[i].end());
234 }
235
236 // Add the extra resource usage requirements specified in the delta.
237 // Note that a negative value of `numCycles' means one entry for that
238 // resource should be deleted for each cycle.
239 // 
240 void InstrRUsage::addUsageDelta(const InstrRUsageDelta &delta) {
241   int NC = delta.numCycles;
242   sameAsClass = false;
243   
244   // resize the resources vector if more cycles are specified
245   unsigned maxCycles = this->numCycles;
246   maxCycles = std::max(maxCycles, delta.startCycle + abs(NC) - 1);
247   if (maxCycles > this->numCycles) {
248     this->resourcesByCycle.resize(maxCycles);
249     this->numCycles = maxCycles;
250   }
251     
252   if (NC >= 0)
253     for (unsigned c=delta.startCycle, last=c+NC-1; c <= last; c++)
254       this->resourcesByCycle[c].push_back(delta.resourceId);
255   else
256     // Remove the resource from all NC cycles.
257     for (unsigned c=delta.startCycle, last=(c-NC)-1; c <= last; c++) {
258       // Look for the resource backwards so we remove the last entry
259       // for that resource in each cycle.
260       std::vector<resourceId_t>& rvec = this->resourcesByCycle[c];
261       int r;
262       for (r = rvec.size() - 1; r >= 0; r--)
263         if (rvec[r] == delta.resourceId) {
264           // found last entry for the resource
265           rvec.erase(rvec.begin() + r);
266           break;
267         }
268       assert(r >= 0 && "Resource to remove was unused in cycle c!");
269     }
270 }