00001 // 00002 // File: 00003 // 00004 // op_scheduler.H 00005 // 00006 // Purpose: 00007 // 00008 // Defines class structure for an implementation of 00009 // operation scheduling. 00010 // 00011 // Author: 00012 // 00013 // Mark C. Toburen 00014 // 00015 // History: 00016 // 00017 // 02/15/02 - Created. 00018 // 00019 00020 #ifndef _OP_SCHEDULER_H_ 00021 #define _OP_SCHEDULER_H_ 00022 00023 #include <stl.h> 00024 #include "TinkerKnobs.H" 00025 #include "dag.H" 00026 #include "machine.h" 00027 #include "chains.H" 00028 #include "opList.H" 00029 #include "rdef.H" 00030 00031 #define UNSCHEDULED -1 // Marks an Op as unscheduled 00032 #define RENAMING_CONFLICT 1 // Marks Ops that can't be renamed 00033 #define NO_RENAMING_CONFLICT 0 // Marks Ops that can be renamed 00034 00035 class op_scheduler { 00036 00037 protected: 00038 00039 // Pointers, etc to hold the prioritized op list of the current region being scheduled 00040 typedef vector <BigListElement>::iterator ListIterator; 00041 vector <BigListElement> *List; 00042 ListIterator ListHead, ListTail, ListPtr, Op; 00043 int ListCount; 00044 00045 // Miscellaneous global variables used during scheduling 00046 int *operand_ready_times, current_block_int; 00047 legoOp *current_before_op; 00048 regionList *Children; 00049 vector <legoRegion *> ScheduleList; 00050 map <int, int> ScheduleTimes; 00051 00052 // Pointers to the current region being scheduled, its DDG, the Machine model, and knobs 00053 legoRegion *Region; 00054 dag *DDG; 00055 machine *Machine; 00056 knobs *Knobs; 00057 00058 // OpSched Knobs 00059 char *TreeTraversal; 00060 int PlayDoh, 00061 BypassLatency, 00062 CodeGen, 00063 NoSpeculation, 00064 AllowPBRSpeculation, 00065 AllowLoadSpeculation, 00066 AllowOnlySafeSpeculation, 00067 AllowDownwardCodeMotion, 00068 AllowMultiWayBR; 00069 00070 // ********************************************************************************************* 00071 // Renaming Functions 00072 // - taken from list scheduler 00073 // ********************************************************************************************* 00074 00075 // HZ: Rename the dst reg of the op. 00076 // Based on the following conditions to decide which renaming scheme will be 00077 // used: 00078 // whether there are any uses of the dsts of the op that are outside 00079 // of treegion, or there are any uses that are not descedant of the 00080 // BB where the op resides in. => variable UseOutsideTreeOrNotDom 00081 // If UseOutsideTreeOrNotDom is false, the SimpleRename is used. 00082 // If UseOutsideTreeOrNotDom is true, more conditions need to be checked to 00083 // determine either SimpleRenameWithCopy or GlobalRename to be used: 00084 // -Check whether Merge problem exists. If not, the global rename is 00085 // used. 00086 // -If there is Merge Problem, add a copy op if the op 00087 // has at least one use that it dominates and there is no use preceeds 00088 // the op. 00089 // -Otherwise, return RENAMING_CONFLICT. 00090 // For the input Hazardous, if set, the Merge problem is assumed to exist. So 00091 // the SimpleRenameWithCopy is favored. 00092 // 00093 // Doubtful point: (future work on DDG & scheduler) DDG analysis of FICT 00094 int Rename(legoOp *op, int RegNum, legoRegion *proc_ptr, int Final_Pass, 00095 int IncMaxRegNum, int Hazardous); 00096 00097 // HZ: Simple rename of the dsts of the op 00098 // If IncMaxRegNum == 1, rename the dsts of the op starting from reg no (++MaxRegNum) 00099 // If IncMaxRegNum == 0, rename the dsts of the op starting from RegNum. 00100 // Simple rename works by setting just the reg no of the dsts of the op and 00101 // update the DAG by remove the Output and Anti(def) dep. 00102 void SimpleRename(legoOp *op, int RegNum, int IncMaxRegNum); 00103 00104 // HZ: Rename the uses of the def. 00105 // For each use of the def (obtained by GetDUChain), set the oprdRegNum to 00106 // RegNum , also call the function ReverseGlobalRename(use, RegNum, orig_def) 00107 // to rename the defs of the use. 00108 void ForwardGlobalRename(legoOprd *def, int RegNum, legoOprd *orig_def); 00109 00110 // HZ: Rename the defs of the use 00111 // For each def of the use (obtained by GetUDChain), set the oprdRegNum to 00112 // RegNum, also call the function ForwardGlobalRename(def, RegNum, orig_def) 00113 // to rename the uses of the def. 00114 // 00115 // Doubtful point: the setting of the ReDoLiveVarsAfterGlobal 00116 void ReverseGlobalRename(legoOprd *use, int RegNum, legoOprd *orig_def); 00117 00118 // HZ: Rename the dsts of the op. 00119 // If IncMaxRegNum == 1, rename the dsts of the op starting from reg no (++MaxRegNum) 00120 // If IncMaxRegNum == 0, rename the dsts of the op starting from RegNum. 00121 // For each dst of the op, after change the reg no, call 00122 // ForwardGlobalRename(def, localRegNum, def) to rename the reg no globally 00123 // Then remove the output deps on its predecessors and the antidep based on 00124 // the renamed def. 00125 void GlobalRename(legoOp *op, int RegNum, int IncMaxRegNum); 00126 00127 // HZ: AddCopyOps: add the copy (move) ops of the op. 00128 // There are two scenarios considered in this function: 00129 // (1) If the op is scheduled, we are dealing with the dominate parallelism 00130 // (Doubtful point for me at this time) 00131 // (2) If the op is unscheduled, we are doing the first step of 00132 // renamewithcopy. 00133 // For each dst reg of the op, a copy (move) inst is created with the 00134 // consideration of the predicate register.(e.g., mov r1, 00135 // r1 (p1) ). Then the related DU, UD chains, and the copy ops are appended 00136 // at the end of the List. Also the predecessor & successor 00137 // dependency relationships in DAG are updated. 00138 int AddCopyOps(legoOp *op); 00139 00140 // HZ: Return true if orig_def is descendant of the BB that the def resides in. 00141 // This happens when a use has two reaching defs. In the renaming process, 00142 // just rename one of them is not enough. Matt called this 'Merge Problem' as 00143 // two defs merge at the same use. 00144 // Because of the nature of treegion, this mergeing use should not be in the 00145 // same treegion as the two defs. 00146 int IsRemoteMergeProblem(legoOprd *def, legoOprd *orig_def); 00147 00148 // HZ: Check whether a merge problem exist for the orig_def. 00149 // For each use of the orig_def (obtained by GetDUChain()), if the use is 00150 // preceeds the def (due to the loop back), or the use is not descendant of 00151 // the def, or the use is in different treegions, check the defs of this use 00152 // to see whether there is a merge problem between the orig_def and any of the 00153 // defs. Also checks whether the dst of the orig_def are among the live-ins 00154 // of the treegion. If so, return YES to show that there is merge problem. 00155 int IsMergeProblem(legoOprd *orig_def); 00156 00157 // HZ: Check whether there are any dsts of the op that are live along the edge. 00158 int anyliveout(legoOp *op, opEdges *edge); 00159 00160 // HZ: The define (renamed_def) has been renamed. So we need to remove the output 00161 // dep caused by this define. The function does so by checking both its 00162 // successors and predecessors. Then remove the corresponding dependence edge 00163 // in the DAG. 00164 void RemoveOutputDepsAfterRename(legoOprd *renamed_def); 00165 00166 // HZ: Same as the one above except that it just checks predecessors. 00167 void RemoveOutputDepsAfterRenameUp(legoOprd *renamed_def); 00168 00169 // HZ: Anti Dep removal after renaming the use. 00170 // In the following scenario: 00171 // Inst. a <- r1, r2 ( use of r1 has been renamed) 00172 // ... (other instructions) 00173 // Inst. b r1 <- (define of r1) 00174 // Looking through the successors of instruction a, remove the anti 00175 // dep if the reg no, reg type, Oprd File Type, etc. match. Remove the 00176 // dep edge by removing the successor from instr a and removing predecessor 00177 // from instr. b. Also it is noted that for brl op, when reg no is INTP1 ~ 00178 // DBL_P2. This dep edge is not removed. 00179 void RemoveAntiDepsAfterUseRename(legoOprd *renamed_use); 00180 00181 // HZ: Anti Dep removal after renaming the def. 00182 // In the following scenario: 00183 // Inst. a <- r1, r2 ( use of r1) 00184 // ... (other instructions) 00185 // Inst. b r1 <- (define of r1 has been renamed) 00186 // Looking through the predecessors of instruction b, remove the anti 00187 // dep if the reg no, reg type, Oprd File Type, etc. match. Remove the 00188 // dep edge by removing the successor from instr a and removing predecessor 00189 // from instr. b. Also it is noted that for brl op, when reg no is INTP1 ~ 00190 // DBL_P2. This dep edge is not removed. 00191 void RemoveAntiDepsAfterDefRename(legoOprd *renamed_def); 00192 00193 00194 // copy_operand 00195 // Src = source operand 00196 // Target = target operand 00197 // 00198 // Copies fields from Src to Target, assuming a register-type operand. 00199 // Does NOT copy next and prev pointers. 00200 void copy_operand(legoOprd *Src, legoOprd *Target); 00201 00202 // add_to_existing_attr 00203 // Attr = existing live attribute 00204 // NewOprd = new operand to add to attribute 00205 // 00206 // Adds a copy of the operand NewOprd to attribute Attr. If a copy 00207 // already resides in Attr, no action is taken. 00208 void add_to_existing_attr(attrs *Attr, legoOprd *NewOprd); 00209 00210 // create_new_attr 00211 // Edge = edge on which to add live attribute 00212 // Oprd = operand to add to attribute 00213 // Proc = proc to whose dictionary to add edge 00214 // 00215 // Creates a new live attribute for Edge containing a copy of Oprd. 00216 void create_new_attr(opEdges *Edge, legoOprd *Oprd, legoProc *Proc); 00217 00218 // HZ: Fix the liveness after we move the op sepculatively up to a different 00219 // block from its orginal block (where before_op resides in). 00220 // Add the dsts of the op to live attr of the edges along the path from its 00221 // original block to its current block. 00222 int FixLiveVarsUp(legoOp *op, legoOp *before_op, legoProc *proc_ptr); 00223 00224 // HZ: Fix the liveness after we move the op sepculatively down to a different 00225 // block from its orginal block. 00226 // Add the srcs of the op to live attr of the edge. 00227 // Note: if op is a brl instr, the src oprds are MACRO REGS (from INT_P1 to 00228 // DBL_P2) 00229 int FixLiveVarsDown(legoOp *op, opEdges *edge, legoProc *proc_ptr); 00230 00231 // HZ: Add use to the live attr of the edges along the path from the BB where 00232 // before_op resides in to the BB where the use is. 00233 int FixLiveVarsFromUses(legoOprd *use, legoOp *before_op, legoProc *proc_ptr); 00234 00235 // HZ: Determine whether there is any instruction in the path from op to 00236 // before op that uses the same dst reg as compare_dest. 00237 // (the path is obtained using GetPrevLink or GetInList()->GetOp) 00238 int AnyOutputDepsBetween(legoOp *op, legoOp *op_in_multiop, legoOprd *compare_dest); 00239 00240 // DoTheMessyStuff: This code allows branches to be scheduled above other 00241 // operations (or allows ops to move below branches) during scheduling. 00242 // This usually results in copy of ops (depending on liveness out of the 00243 // branches. Priority lists, liveness, and reaching definitions are updated 00244 // incrementally. 00245 // HZ: As it is said by Matt, this function moves the br op upwards. So the input 00246 // op is a br instr. The other input proc_ptr is used for updating the 00247 // liveness attr. 00248 // This is how it is done: 00249 // 1. Process the case that the op is the exit op of the treegion or the op 00250 // is either BRU or DUMMY BR. (return RENAMING CONFLICT) 00251 // 2. If the op is either BRCT or BRCF, then there are two exit edges, 00252 // called first edge and second edge of 00253 // the op (not the treegion). Processing each instruction that 00254 // is above the op but not scheduled yet (variable above_op): 00255 // a. If above_op is brl or store, set the attribute 00256 // "no_longer_speculative". 00257 // b. Check the control dep between above_op and op using 00258 // DPG->AreOpsDependent(above_op, op) (Doubtful point for me, 00259 // ambiguous in what the function does exactly) 00260 // c. If above_op has control dep on op, then if the above_op is live on 00261 // second edge or the above_op is either store/brl, a duplicate of 00262 // the above op will be created (duplicate the predicate needs more 00263 // work). Then the duplicate will be placed after the C_MERGE op 00264 // along the second edge. Also the related DU, UD chain and DDG will 00265 // be updated to reflect the correct dep info and the liveness on the 00266 // second edge need to be fixed by calling FixLiveVarsDown. 00267 // d. If above_op has control dep on op, then if the above_op is live on 00268 // first edge or the above_op is either store/brl, the above op 00269 // will be moved after the C_MERGE op along the first edge (there is 00270 // no needs to duplicate the above op as it is processed along the 00271 // second edge already). Also the related DU, UD chain and DDG will 00272 // be updated to reflect the correct dep info and the liveness on the 00273 // first edge need to be fixed by calling FixLiveVarsDown. 00274 // e. Processing the dead ops by adding the DPRemoveAttribute and remove 00275 // the dep with its successors and predecessors. 00276 int DoTheMessyStuff(legoOp *op, legoRegion *proc_ptr); 00277 00278 // This routine returns the second, complementary destination for a CMPP op. 00279 // If the second predicate dest is OT_UNDEFINED, one will be created. 00280 // if the CMPP opcode does not produce a complementary second dest, the 00281 // opcode will be updated. The second destination oprd is returned. 00282 legoOprd* GetComplementaryDestOprd(legoOp *cmppop); 00283 00284 // This routine cleans up ops and adds a dp_remove attr so that they 00285 // can be remove after procedure is scheduled. Removing them earlier fucks 00286 // up priority lists and RDefs() 00287 // HZ: This is the way how to do it: 00288 // 1. RemoveOp and AddOp such that the infor in priority list & RDefs are 00289 // not disturbed. 00290 // 2. Set the schedule time as zero for the op and add DPRemoveAttribute 00291 // 3. Remove the dep between the op and its successors & predecessors. 00292 void PrepareToDie(legoOp *op); 00293 00294 // As a result of control flow changes during the forming of Multi-Way 00295 // branches, some ops get re-targeted. Need to update the dag to reflect 00296 // new predecessor ops for control deps in these cases. 00297 //HZ: This is the way it works: (the op is branch op ??) 00298 // 1. Find the C_MERGE op preceeding the op and set the inlist of the 00299 // C_MERGE op to include the new_predecessor_op. 00300 // 2. Remove old predecessor/successor pair (CONT Dep) between the op and 00301 // the old_predecessor_op. 00302 // 3. Add control dep between op & new_predecessor_op. 00303 // 4. Repeat step 2,3 for the C_MERGE op. 00304 void UpdatePredecessorBranch(legoOp *op, legoOp *old_predecessor_op, legoOp *new_predecessor_op); 00305 00306 // Allowing Multi-Way branches to be formed during list scheduling requires 00307 // even MoreMessyStuff. 00308 // Here I DoMoreMessyStuff. 00309 // HZ: DoMoreMessy stuff happens when we are trying to schedule the branch op 00310 // (op) speculatively (i.e., the current_before_op is in a different BB from 00311 // the BB where the op resides in.) After calling the function 00312 // DoTheMessyStuff to move its above ops into its descendant BBs, the op and 00313 // the CMERGE_op are the instructions left in the BB. The function 00314 // DoMoreMessyStuff moves such a br upwards to its parentBB to form a 00315 // multiway br. (the resulted empty BB is removed ??) 00316 // This is the way how to do it: 00317 // If Final_Pass is not set, return RENAMING_CONFLICT. 00318 // 1. Find the related pointers, including predecessor_branch_op, 00319 // original_block, c_merge_op 00320 // 2. Find the last op in the predecessor_branc_op's multiop, since we 00321 // will move the op just before this last op. 00322 // 3. Since we currently can not handle the jump table, check the 00323 // attributes of the op and predecessor_branch_op. If ATTR_TBLNAME is 00324 // found, return RENAMING_CONFLICT. (Jump table is a doubtful point 00325 // for me) 00326 // 4. If the op is either an DUMMY_BR or an BRU instr: 00327 // a. Update the inlist of the C_MERGE op following the op so that 00328 // the predecessor_branch_op is in the inlist. Also adjust the 00329 // edge from op to its following C_MERGE so that the edge starts 00330 // from predecessor_branch_op to the C_MERGE. Delete the edge from 00331 // the predecessor to the C_MERGE which is just before the op. 00332 // Update the outlist of the predecessor_branch_op. 00333 // b. Retarget PBR of predecessor_branch_op to the target of the op 00334 // if the predecessor is a BRU instr or the op is in the taken 00335 // path of the predecssor_branch_op. (Doubtful point: what if the 00336 // op is on the fall-through path of the predecessor_branch_op?) 00337 // c. PrepareToDie the op and its pbrrop (probably already scheduled) 00338 // 5. If the op is a RTS instr: 00339 // a. If the predecessor_branch_op is either an BRU or an DUMMY_BR, 00340 // replace the predecessor_branch_op with this RTS by: 00341 // Move the RTS to the last op found in step 2; Remove the control 00342 // dep of the predecessor and its following C_MERGE and set the 00343 // predicate of the predecessor_branch_op as the predicate of the 00344 // RTS; PrepareToDie the predecessor_branch_op & its pbrr and free 00345 // the resources that scheduled to the predecessor_branch_op (PBRR 00346 // op takes no resources ?). 00347 // b. If the predecessor_branch_op is cond br, change the 00348 // predecessor_branch_op to an BRU instr and move the RTS up. 00349 // Implementing this involves the following steps: 00350 // b1. check whether the op is in the taken path of the 00351 // predecessor_branch_op 00352 // b2. create a predicate for the RTS op that will be moved up. 00353 // Based on the CMPP op / orig_fall_through attribute of the 00354 // predecessor_branch_op, a predicate orpd is constructed. 00355 // b3. Adjust the UD, DU chains to include the new predicate 00356 // oprd. 00357 // b4. If the op is in the taken path of the 00358 // predecessor_branch_op and the predecessor_branch_op is 00359 // BRCF, set the predicate value of the RTS as the 00360 // complementary of what cmpp set. Also set the predicate 00361 // value of the predecessor_branch_op as what cmpp set. 00362 // b5. If the op is in the taken path of the 00363 // predecessor_branch_op and the predecessor_branch_op is 00364 // BRCT, set the predicate value of the RTS as what cmpp set 00365 // and set the predicate value of the predecessor_branch_op 00366 // as the complementary of what cmpp set. 00367 // b6. Process the other two cases of the RTS is in the fall 00368 // through path of the predecessor_branch_op which is either 00369 // BRCT or BRCF. 00370 // b7. move up the RTS op, change the predecessor_branch_op 00371 // (BRCT/BRCF) to BRU and update the the target of the 00372 // pbrr to point to the right CB. 00373 // 6. If the op is a BRCT or BRCF instr: 00374 // a. If the predecessor_branch_op is a BRU instr, we will retarget 00375 // this predecessor_branch_op to the op's fall through block and 00376 // change the the op to a BRU instr. Then mode the op upwards, 00377 // update the control edges, UD DU chain for the predicates, 00378 // update the predecessor/successor relationship, etc. 00379 // b. If the predecessor_branch_op is a BRCT/BRCF instr, we will 00380 // combine the op and predecessor_branch_op into a BRU and a BRC. 00381 // b1. If the op is in the taken path of the 00382 // predecessor_branch_op, make the op a predicated BRU and 00383 // retarget the predecessor_branch_op to the fall-through 00384 // path of the op. Also do the related book-keeping 00385 // including: creating the new predicate, update the in/out 00386 // edges, in/out lists, DU/UD chain, predecessor/successor 00387 // dep relationship, change the op to BRU, etc. 00388 // b2. If the op is in the fall-through path of the 00389 // predecessor_branch_op, change the predecessor_branch_op 00390 // to a BRU targeting at its orginal taken path. Change the 00391 // position of the op and predecessor_branch_op such that 00392 // the brc* happens at the end of the multiway branch. (o.w., 00393 // yula may take the fall-thru path of the brc* 00394 // incorrectly.) 00395 // 7. If the original block only has c_merge op left, destroy the 00396 // cmerge_op and the BB. (actually, it is not deleted here, but the 00397 // edge info. is updated. The actual removal happened after the 00398 // procedure is scheduled (in Function ScheduleProc in schedule.C)). 00399 // 00400 int DoMoreMessyStuff(legoOp *op, int Final_Pass); 00401 00402 // HZ: Scan the current region under scheduling. For each br instr, if it is 00403 // not DUMMY_BR or dp_removed, find the the corresponding PBR and move the 00404 // PBR just before the br inst. If the need_duplicate attribute is set for 00405 // the PBR, duplicate the PBR and move the duplicated pbrr just before the 00406 // br. 00407 void PlacePBRsJustBeforeBranches(); 00408 00409 // HZ: Scan through the current region. Put the br to the end of the BB that 00410 // it resides in. 00411 void PlaceBranchesLast(); 00412 00413 00414 // ********************************************************************************************* 00415 // Scheduling Functions 00416 // ********************************************************************************************* 00417 00418 // MCT: ScheduleOp moves ops and sets schedule times once they can be scheduled. An 00419 // integer flag is returned indicating whether a renaming conflict was encountered. 00420 int ScheduleOp(legoOp *op, int cycle); 00421 00422 // MCT: These functions traverse a treegion and schedule its constituent basic-blocks in 00423 // either a depth-first or breadth-first manner. One of these two functions is called from 00424 // ScheduleTree based on the "op-scheduler:tree-traversal" knob. 00425 void ScheduleTreeBreadthFirst(); 00426 void ScheduleTreeDepthFirst(legoRegion *Block, int StartCycle); 00427 00428 // ********************************************************************************************* 00429 // Utility Functions 00430 // ********************************************************************************************* 00431 00432 //HZ: Note: 00433 // Matt used the word 'attribute' to describe the private/public variables of 00434 // the class. Also the word is used in the description of the Rebel code. 00435 // The meaning of the word in the comments should be clear from the context. 00436 00437 // DescendantofBlock: Returns YES if this operation 00438 // belongs to a block which is a descendant of the 00439 // block identified by a pointer of value input_block_int. 00440 int DescendantofBlock(int input_block_int, legoOp *op); 00441 00442 // DescendantofCurBlockPtr: Returns YES if this operation 00443 // belongs to a block which is a descendant of the 00444 // block identified by the current_block_int attribute. 00445 // It can be seen as a special case of the previous function with 00446 // the input_block_int is current_block_int and op as Node->GetOp(). 00447 int DescendantofCurBlockPtr(ListIterator Node); 00448 00449 // MCT: BuildList builds a valid sequential order of LegoOps for the op scheduler to consume. 00450 // At inception, BuildList will basically just spit out the list generated by the 00451 // DAG builder. 00452 // void BuildList(); 00453 00454 // MCT: BuildReadyTimes finds the ready times for each operand of the next unscheduled 00455 // candidate op 00456 void BuildReadyTimes(ListIterator Node, int IssueCycle); 00457 00458 // MCT: PredecessorsScheduled determines whether all of a candidate's predecessor ops have 00459 // been scheduled. Returns YES is all predecessors have been scheduled, NO otherwise. 00460 int PredecessorsScheduled(ListIterator Node); 00461 00462 // MCT: SortRegionListByWeight takes a LEGO regionList, converts it into a vector of legoRegions, 00463 // then calls BubbleSortRegionList to sort the vector. This allows us to schedule child 00464 // basic-blocks in order of profile weight. 00465 vector <legoRegion *> SortRegionListByWeight(regionList *rlist); 00466 00467 // MCT: Performs a bubble sort of a vector of legoRegions based on the Compare function passed. 00468 void BubbleSortRegionList(vector <legoRegion *> Vector, int (*Compare)(legoRegion *, legoRegion *)); 00469 00470 // MCT: Tells the scheduler if this region has already been scheduled. I use this to avoid spinning 00471 // trying to schedule a child block that is a child of itself (i.e. has a back edge to itself). 00472 int HasBlockBeenScheduled(legoRegion *Block); 00473 00474 // MCT: PrintBlockSchedule is used for debug purposes only. 00475 void PrintSchedule(); 00476 00477 public: 00478 00479 // constructors and destructors 00480 op_scheduler() {} 00481 op_scheduler(legoRegion *, machine *, knobs *); 00482 ~op_scheduler() {} 00483 00484 // Set knobs specific for operation scheduling 00485 virtual void SetKnobs(); 00486 00487 // Operation schedule a basic-block. 00488 int ScheduleBlock(legoRegion *Block, int StartCycle); 00489 00490 // Operation schedule a treegion. 00491 void ScheduleTree(); 00492 }; 00493 00494 00495 #endif // _OP_SCHEDULER_H_
1.3.2