TCE  1.20
BypassingBUBasicBlockScheduler.cc
Go to the documentation of this file.
1 /*
2  Copyright (c) 2002-2011 Tampere University.
3 
4  This file is part of TTA-Based Codesign Environment (TCE).
5 
6  Permission is hereby granted, free of charge, to any person obtaining a
7  copy of this software and associated documentation files (the "Software"),
8  to deal in the Software without restriction, including without limitation
9  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  and/or sell copies of the Software, and to permit persons to whom the
11  Software is furnished to do so, subject to the following conditions:
12 
13  The above copyright notice and this permission notice shall be included in
14  all copies or substantial portions of the Software.
15 
16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23  */
24 /**
25  * @file BypassingBUBasicBlockScheduler.cc
26  *
27  * Implementation of BypassingBUBasicBlockScheduler class.
28  *
29  * This scheduler first schedules result reads of an operation, then
30  * it tries to bypass the operands, and recursively schedule the
31  * operations which produce the result, bypassing the operands while
32  * bypassing the results of the other operation. If it cannot schedule the
33  * operation producing the value of the operand, it reverts the bypass,
34  * and schedules operands from registers.
35  *
36  * When the original/first scheduleOperation() call finishes,
37  * all operations and
38  * moves scheduled directly by it or recursively by it are "fixed in place",
39  * and can no longer be reverted. Then selector gives another operation or
40  * individual move to be scheduled.
41  *
42  * The basic principle of this scheduler is greediness:
43  * "try the fastest way of doing things first, and if it succeeds, good,
44  * it not, revert to slower way of doing things.
45  * so 1) bypass 2) rename 3) add regcopies
46  *
47  * The old BB scheduler does these in exactly opposite order(
48  * first addregcopies, then rename, then bypass).
49  *
50  * @author Heikki Kultala 2011-2012 (hkultala-no.spam-tut.fi)
51  * @note rating: red
52  */
53 
54 /*
55  TODO:
56 
57  * Allow reverting of regcopyadding
58  * Allow bypassing also when not scheduling recursively
59  * switch from DFS to BFS
60  * Bypass and schedule top-down other results?
61  * Allow bypassing when scheduling reg-reg moves
62  * Allow bypassing over multiple nodes
63  * Smarter logic for selecting registers when 1) renaming 2)tempregadding
64  * switch operands on commutative operations.
65  */
66 
67 #include <set>
68 #include <string>
69 
71 #include "DataDependenceGraph.hh"
72 #include "SimpleResourceManager.hh"
73 #include "BUMoveNodeSelector.hh"
74 #include "ProgramOperation.hh"
75 #include "ControlUnit.hh"
76 #include "Machine.hh"
77 #include "BasicBlock.hh"
78 #include "LLVMTCECmdLineOptions.hh"
79 #include "InterPassData.hh"
80 #include "MoveNodeSet.hh"
81 #include "Terminal.hh"
82 #include "RegisterRenamer.hh"
83 #include "HWOperation.hh"
85 #include "Operation.hh"
86 #include "TerminalRegister.hh"
87 #include "Move.hh"
88 #include "RegisterCopyAdder.hh"
89 #include "MoveGuard.hh"
90 #include "DisassemblyRegister.hh"
91 
92 //#define DEBUG_OUTPUT
93 //#define DEBUG_REG_COPY_ADDER
94 //#define CFG_SNAPSHOTS
95 //#define BIG_DDG_SNAPSHOTS
96 //#define DDG_SNAPSHOTS
97 //#define SW_BYPASSING_STATISTICS
98 
100 class RegisterRenamer;
101 
102 /**
103  * Constructs the basic block scheduler.
104  *
105  * @param data Interpass data
106  * @param bypasser Helper module implementing software bypassing. Not used.
107  * @param delaySlotFiller Helper module implementing jump delay slot filling
108  * @param registerRenamer Helper module implementing register renaming
109  */
111  InterPassData& data,
112  SoftwareBypasser* bypasser,
113  CopyingDelaySlotFiller* delaySlotFiller,
114  RegisterRenamer* renamer) :
115  BasicBlockScheduler(data, bypasser, delaySlotFiller, renamer),
116  killDeadResults_(false), renameRegisters_(false) {
117 
118  CmdLineOptions *cmdLineOptions = Application::cmdLineOptions();
119  options_ = dynamic_cast<LLVMTCECmdLineOptions*>(cmdLineOptions);
120  if (options_ != NULL) {
123  }
124 }
125 
126 /**
127  * Destructor.
128  */
130 }
131 
132 /**
133  * Schedules a piece of code in a DDG
134  * @param ddg The ddg containing the code
135  * @param rm Resource manager that is to be used.
136  * @param targetMachine The target machine.
137  * @exception Exception several TCE exceptions can be thrown in case of
138  * a scheduling error.
139  */
140 void
143  const TTAMachine::Machine& targetMachine) {
144  if (!BasicBlockPass::interPassData().hasDatum("SCRATCH_REGISTERS")) {
146  targetMachine, BasicBlockPass::interPassData());
147  }
148 
149  ddg_ = &ddg;
150  targetMachine_ = &targetMachine;
151 
152  if (renamer_ != NULL) {
153  renamer_->initialize(ddg);
154  }
155 
156  if (options_ != NULL && options_->dumpDDGsDot()) {
157  ddgSnapshot(
158  ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false);
159  }
160 
161  if (options_ != NULL && options_->dumpDDGsXML()) {
162  ddgSnapshot(
163  ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false);
164  }
165 
166  // empty need not to be scheduled
167  if (ddg.nodeCount() == 0 ||
168  (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
169  return;
170  }
171  // TODO: Magic number! Provide better heuristics.
172  // INT_MAX/2 won't work on trunk due to multithreading injecting empty
173  // instructions into the beginning of basic block.
174  // Remove magic 1000 once the sparse implementation of RM vectors works.
175 //endCycle_ = (ddg.nodeCount() < 1000) ? ddg.nodeCount() + 200 : 1000;
176  endCycle_ = (int)(ddg.nodeCount()*1.3 + 150);
177  BUMoveNodeSelector selector(ddg, targetMachine);
178 
179  // scheduling pipeline resources after last cycle may cause problems.
180  // make RM to check for those
182 
183 
184  // register selector to renamer for notfications.
185  if (renamer_ != NULL) {
186  renamer_->setSelector(&selector);
187  }
188 
189  rm_ = &rm;
190 
191  MoveNodeGroup moves = selector.candidates();
192  while (moves.nodeCount() > 0) {
193  MoveNode& firstMove = moves.node(0);
194  if (firstMove.isOperationMove()) {
195  scheduleOperation(moves, selector);
196  } else {
197  std::cerr << "Individual move: " << firstMove.toString()
198  << std::endl;
199  scheduleMoveBU(firstMove, 0, endCycle_, TempRegBefore);
200  finalizeOperation(selector);
201  }
202  if (!moves.isScheduled()) {
203  std::string message = " Move(s) did not get scheduled: ";
204  for (int i = 0; i < moves.nodeCount(); i++) {
205  message += moves.node(i).toString() + " ";
206  }
207  ddg.writeToDotFile("failed_bb.dot");
208  throw ModuleRunTimeError(__FILE__,__LINE__,__func__, message);
209  }
210  moves = selector.candidates();
211  }
212 
213  clearCaches();
214 
215  if (ddg.nodeCount() != ddg.scheduledNodeCount()) {
216  debugLog("All moves in the DDG didn't get scheduled.");
217  ddg.writeToDotFile("failed_bb.dot");
218  abortWithError("Should not happen!");
219  }
220 
221  if (options_ != NULL && options_->dumpDDGsDot()) {
222  std::string wtf = "0";
223  ddgSnapshot(
224  ddg, wtf, DataDependenceGraph::DUMP_DOT, true);
225  }
226 
227  if (options_ != NULL && options_->dumpDDGsXML()) {
228  ddgSnapshot(
229  ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
230  }
231 }
232 
233 #ifdef DEBUG_REG_COPY_ADDER
234 static int graphCount = 0;
235 #endif
236 
237 /**
238  * Schedules moves in a single operation execution.
239  *
240  * Assumes the given MoveNodeGroup contains all moves in the operation
241  * execution. Also assumes that all outputs of the MoveNodeGroup have
242  * been scheduled.
243  *
244  * @param moves Moves of the operation execution.
245  */
246 void
248  MoveNodeGroup& moves, MoveNodeSelector& selector) {
249 
250  std::cerr << "ScheduleOperation from selector: " << moves.toString()
251  << std::endl;
252 
253  for (int i = 0; i < moves.nodeCount(); i++) {
254  if (moves.node(0).isScheduled()) {
255  ddg_->writeToDotFile("op_already_sched.dot");
256  throw Exception(__FILE__,__LINE__,__func__,
257  "Scheduling failed for opsched, operation: "
258  + moves.toString());
259  }
260  }
261  ProgramOperation& po =
262  (moves.node(0).isSourceOperation())?
263  (moves.node(0).sourceOperation()):
264  (moves.node(0).destinationOperation());
265 
266  for (int lastCycle = endCycle_; lastCycle > 0; lastCycle--) {
267  if (scheduleOperation(po, lastCycle , true)) {
268 // ddg_->writeToDotFile("op_schedok.dot");
269 
270  finalizeOperation(selector);
271  return;
272  }
273  std::cerr << "Trying to schedule op again with smaller cycle"
274  << std::endl;
275  }
276 
277  ddg_->writeToDotFile("fail.dot");
278  ddg_->writeToXMLFile("fail.xml");
279 
280  throw Exception(__FILE__,__LINE__,__func__,
281  "Scheduling failed for unknown reason!, operation: "
282  + po.toString());
283 }
284 
285 /**
286  * A short description of the pass, usually the optimization name,
287  * such as "basic block scheduler".
288  *
289  * @return The description as a string.
290  */
291 std::string
293  return "Bypassing recursive Bottom-up list scheduler with a basic block scope.";
294 }
295 
296 /**
297  * Optional longer description of the pass.
298  *
299  * This description can include usage instructions, details of choice of
300  * algorithmic details, etc.
301  *
302  * @return The description as a string.
303  */
304 std::string
306  return
307  "Bottom-up list basic block scheduler that first tries to bypass"
308  " and only then assign moves,and recursively schedules bypass sources";
309 }
310 
311 void
313 
314  for (std::map<MoveNode*, MoveNode*, MoveNode::Comparator>::iterator i =
315  bypassSources_.begin(); i != bypassSources_.end(); i++) {
316  // only notify if no DRE'd
317  if (i->second != NULL && pendingBypassSources_.find(i->second)
318  == pendingBypassSources_.end()) {
319  selector.mightBeReady(*i->second);
320  }
321  }
322 
323  bypassSources_.clear();
324 
325  for (std::set<MoveNode*, MoveNode::Comparator>::iterator i =
326  pendingBypassSources_.begin(); i != pendingBypassSources_.end();
327  i++) {
328  MoveNode* node = *i;
329 
330  // this may lead to extra raw edges.
331  static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
332  copyDepsOver(*node, true, true);
333 
334  std::cerr << "DRE killing node: " << (**i).toString() << std::endl;
336  ddg_->dropNode(*node);
337  removedNodes_.insert(node);
338  for (DataDependenceGraph::NodeSet::iterator i =
339  preds.begin(); i != preds.end(); i++) {
340  selector.mightBeReady(**i);
341  }
342  }
343  pendingBypassSources_.clear();
344 
345  for (std::set<MoveNode*, MoveNode::Comparator>::iterator i =
346  scheduledMoves_.begin(); i != scheduledMoves_.end();
347  i++) {
348  assert((**i).isScheduled());
349  selector.notifyScheduled(**i);
350  }
351  scheduledMoves_.clear();
352 
353  regCopiesBefore_.clear();
354  regCopiesAfter_.clear();
355 }
356 
357 /**
358  * Tries to schedule an operation.
359  *
360  * This function is called recursively, when bypassing.
361  *
362  */
363 bool
365  ProgramOperation& po, int& latestCycle, bool allowRegCopies) {
366 
367  int lc = latestCycle;
368  std::cerr << "Scheduling operation: " << po.toString()
369  << " lc: " << latestCycle << std::endl;
370  if (po.isAnyNodeAssigned()) {
371  ddg_->writeToDotFile("po_already_assigned.dot");
372  throw Exception(__FILE__,__LINE__,__func__,
373  "po already scheduled!" +
374  po.toString());
375  }
376  if (!scheduleResults(po, latestCycle, allowRegCopies)) {
377  std::cerr << "results fail for: " << po.toString() << std::endl;
378  return false;
379  }
380 
381  // update latestcycle
382  int lastRes = -1;
383  for (int i = 0; i < po.outputMoveCount(); i++) {
384  MoveNode& mn = po.outputMove(i);
385  if (mn.isScheduled()) {
386  if (mn.cycle() > lastRes) {
387  lastRes = mn.cycle();
388  }
389  lc = endCycle_;
390  // TODO: why does this make the schedule worse?
391 // if (mn.cycle() < lc) {
392 // lc = mn.cycle() -1;
393 // }
394  }
395  }
396  if (lastRes > -1) {
397  std::cerr << "Last result cycle: " << lastRes << std::endl;
398  assert(lastRes <= latestCycle);
399  latestCycle = lastRes;
400 
401  }
402 
403  MoveNode* trigger = findTrigger(po);
404 
405  // this occurs if operation without retvals
406  // has different trigger selections?
407  if (trigger == NULL) {
408  std::cerr << "Trigger was null for: " << po.toString() << std::endl;
409  return false;
410  }
411 
412  if (!bypassAndScheduleNode(*trigger, trigger, lc, allowRegCopies)) {
413  unscheduleResults(po);
414  std::cerr << "trigger bypass or shed fail for: " <<
415  po.toString() << std::endl;
416  return false;
417  }
418 
419  // if trigger bypass jamms fu, this may fail.
420  if (!bypassAndScheduleOperands(po, trigger, lc, allowRegCopies)) {
421  unscheduleOperands(po);
422 
423  // try to remove bypass of trigger and then re-schedule this
424  if (!scheduleMoveBU(*trigger, 0, latestCycle,
425  allowRegCopies ?
426  TempRegBefore :
428  unscheduleResults(po);
429  std::cerr << "Unscheduled trigger fail:" << trigger->toString()
430  << std::endl;
431  return false;
432  }
433 
434  // try now operands, with bypass.
435  if (!bypassAndScheduleOperands(po, trigger, lc, allowRegCopies)) {
436  // advance latest cycle retry counter
437  if (po.outputMoveCount() == 0) {
438  latestCycle = trigger->cycle();
439  }
440  unscheduleOperands(po);
441  unscheduleResults(po);
442 
443  std::cerr << "Operands scheduling fail for: " <<
444  po.toString()<< std::endl;
445  return false;
446  }
447  }
448  std::cerr << "Operation scheduled ok!" << po.toString() << std::endl;
449 // ddg_->writeToDotFile("op_schedok.dot");
450 // if (!po.isScheduled()) {
451 
452  return true;
453 }
454 
455 /**
456  * Schedules result writes to an operation.
457  *
458  * There result writes may be bypasses.
459  */
460 bool
462  ProgramOperation& po, int latestCycle, bool allowRegCopies) {
463 
464  TTAMachine::HWOperation* hwop = NULL;
465  int ectrig = -1;
466  // TODO: do bypasses first? then put other close to them?
467  for (int i = 0; i < po.outputMoveCount(); i++) {
468  MoveNode& mn = po.outputMove(i);
469  if (mn.isDestinationOperation()) {
470  std::pair<int,int> cycleLimits = operandCycleLimits(mn, NULL);
471  if (!scheduleMoveBU(
472  mn, cycleLimits.first, std::min(
473  cycleLimits.second, latestCycle),
474  allowRegCopies ? TempRegAfter : TempRegNotAllowed)) {
475  unscheduleResults(po);
476  return false;
477  } else {
478  // bypassed move is now scheduled.
479  TTAProgram::Terminal& src = mn.move().source();
481  dynamic_cast<TTAMachine::FunctionUnit*>(
482  src.port().parentUnit());
483  assert(fu != NULL);
484  hwop = fu->operation(po.operation().name());
485  ectrig = mn.cycle() - hwop->latency(src.operationIndex());
486  }
487  }
488  }
489 
490  // then non-bypasseds.
491  for (int i = 0; i < po.outputMoveCount(); i++) {
492  MoveNode& mn = po.outputMove(i);
493  if (!mn.isDestinationOperation()) {
494  // if this is
495  if (pendingBypassSources_.find(&mn) !=
496  pendingBypassSources_.end()) {
497  std::cerr << "This node is to be DRE'd: " << mn.toString()
498  << std::endl;
499  continue;
500  }
501  // is some bypassed move already scheduled?
502  if (hwop != NULL) {
503  TTAProgram::Terminal& src = mn.move().source();
504 
505  // try to put as close to other results as possible.
506  // so use top-down-scheduling here.
507 
508  // todo: make sure successors not scheduled?
509  if (ddg_->successorsReady(mn)) {
510  if (scheduleMoveUB(
511  mn, ectrig + hwop->latency(src.operationIndex()),
512  latestCycle)) {
513  return true;
514  }
515  } else {
516  unscheduleResults(po);
517  return false;
518  }
519  }
520 
521  // old regcopy may mess up scheduling result
522  // TODO: remove those regcopies?
523  if (!scheduleMoveBU(
524  mn, 0, latestCycle,
525  allowRegCopies?
526  TempRegAfter :
528  unscheduleResults(po);
529  return false;
530  }
531  }
532  }
533 
534 
535  return true;
536 }
537 
538 /**
539  * Schedule a single move with up-down scheduling.
540  *
541  * Currently used only for results which also have bypassed read of the
542  * result, to get this as close to the bypassed one as possible.
543  */
544 bool
546  MoveNode& mn, int earliestCycle, int latestCycle) {
547  std::cerr << "\t\tSchedulign moveUB: " << mn.toString() <<
548  " Cycle limits: " << earliestCycle << " , " << latestCycle
549  << std::endl;
550  // TODO: unscheduld ones
551 
552  // Does not try to rename as this ub is mostly used with non-dre'd result
553  // when bypassing
555  return false;
556  }
557 /*
558  MoveNode* reg2RegCopy = createTempRegCopy(mn, true);
559  // recursively call this first, then the generated copy.
560 
561  if (reg2RegCopy == NULL) {
562  return false;
563  }
564  std::cerr << "Created regcopy: " << reg2RegCopy->toString();
565 
566  if (!scheduleMoveUB(mn, earliestCycle, latestCycle)) {
567  return false;
568  }
569 
570  if (!scheduleMoveUB(*reg2RegCopy, 0, endCycle_)) {
571  unschedule(mn);
572  return false;
573  }
574  }
575 */
576 
577  latestCycle = std::min(latestCycle, (int)endCycle_);
578  std::cerr << "\t\tlc: " << latestCycle << std::endl;
579  int ddgLC = ddg_->latestCycle(mn);
580  latestCycle = std::min(latestCycle, ddgLC);
581  std::cerr << "\t\tddglc: " << latestCycle << std::endl;
582  int ddgEC = ddg_->earliestCycle(mn);
583  std::cerr << "\t\tddgec: " << ddgEC << std::endl;
584  if (ddgEC == -1 || ddgEC == INT_MAX) {
585  return false;
586  }
587  int minCycle = std::max(earliestCycle, ddgEC);
588  std::cerr << "\t\tmincycle: " << minCycle << std::endl;
589  int rmCycle = rm_->earliestCycle(minCycle, mn);
590  std::cerr << "\t\trmcycle: " << rmCycle << std::endl;
591  if (rmCycle != -1 && rmCycle <= latestCycle) {
592  rm_->assign(rmCycle, mn);
593  scheduledMoves_.insert(&mn);
594 
595  std::cerr << "\t\tScheduled to cycle: " << rmCycle << std::endl;
596  return true;
597  } else {
598  return false;
599  }
600 }
601 
602 /**
603  * Schedule a single move with bottom-up-scheduling.
604  *
605  * If the machine does not have sufficient connectivity,
606  * tries to rename the source register or add regcopies.
607  *
608  * @param mn MoveNode to be scheduled
609  * @param earliestCycle earliestCycle allowed.
610  * @param latestCycle latest allowed cycle. Tries to schedule close to this.
611  * @param t whether temp register copies are allowed, and whether they
612  are added after or before this move.
613  */
614 bool
616  MoveNode& mn, int earliestCycle, int latestCycle,
618  int endCycle = endCycle_;
619 
620  std::cerr << "\t\tSchedulign moveBU: " << mn.toString() <<
621  " Cycle limits: " << earliestCycle << " , " << latestCycle
622  << std::endl;
623 
624  // if control flow move, limit delay slots before end
625  if (mn.move().isControlFlowMove()) {
626  endCycle -= targetMachine_->controlUnit()->delaySlots();
627  }
628 
629  // if regcpy is unscheudled it must be rescheduled
630  if (t == TempRegAfter) {
631  MoveNode* regCopyAfter = regCopiesAfter_[&mn];
632  if (regCopyAfter != NULL &&
633  pendingBypassSources_.find(regCopyAfter) ==
634  pendingBypassSources_.end()) {
635  if (!regCopyAfter->isScheduled()) {
636  std::cerr << "\t\t\tScheduling regcopyafter: " <<
637  regCopyAfter->toString() << std::endl;
638  if (!(scheduleMoveBU(
639  *regCopyAfter, 0, latestCycle, t))) {
640  std::cerr << "\t\t\t\tRegcopyafter scheduling failed" << std::endl;
641  return false;
642  }
643  }
644  }
645  }
646 
648  mn, *targetMachine_)) {
649  std::cerr << "\t\t\tSchedulemoveBU cannot transport move" << std::endl;
650 
651  if (t == TempRegNotAllowed) {
652  return false;
653  }
654 
655  if (!renameSourceIfNotConnected(mn, latestCycle)) {
656 
657  MoveNode* reg2RegCopy =
659  // recursively call this first, then the generated copy.
660 
661  if (reg2RegCopy == NULL) {
662  return false;
663  }
664  std::cerr << "\t\t\tCreated regcopy: " << reg2RegCopy->toString()
665  << std::endl;
666  if (t == TempRegBefore) {
667  MoveNode* oldRC = regCopiesBefore_[&mn];
668  if (oldRC != NULL) {
669  std::cerr << "Existing regcopy before: " << oldRC->toString()
670  << " setting it as regcopy of regcopy"
671  << std::endl;
672  regCopiesBefore_[reg2RegCopy] = oldRC;
673  }
674  regCopiesBefore_[&mn] = reg2RegCopy;
675  std::cerr << "\t\t\t\tRegcopybefore added." << std::endl;
676 
677  return scheduleMoveBU(
678  mn, earliestCycle, latestCycle, TempRegBefore);
679 
680  } else {
681  MoveNode* oldRC = regCopiesAfter_[&mn];
682  if (oldRC != NULL) {
683  std::cerr << "Existing regcopy after: "<<oldRC->toString()
684  << " setting it as regcopy of regcopy"
685  << std::endl;
686  regCopiesAfter_[reg2RegCopy] = oldRC;
687  }
688 
689  regCopiesAfter_[&mn] = reg2RegCopy;
690  if (!scheduleMoveBU(
691  *reg2RegCopy, 0, endCycle_, TempRegAfter)) {
692  return false;
693  }
694 
695  if (!scheduleMoveBU(
696  mn, earliestCycle, latestCycle, TempRegAfter)) {
697  unschedule(*reg2RegCopy);
698  return false;
699  } else {
700  return true;
701  }
702  }
703  } else {
704  std::cerr << "\t\t\tRenamed source to get connectivity: " <<
705  mn.toString() << std::endl;
706  }
707  } else {
708  std::cerr << "\t\t\tCantransportmove ok for: " << mn.toString() << std::endl;
709  }
710 
711  latestCycle = std::min(latestCycle, endCycle);
712  int ddgCycle = ddg_->latestCycle(mn,UINT_MAX,false, false);
713  if (ddgCycle == -1) {
714  std::cerr << "ddg cycle -1, ddg prevents scheduling!" << std::endl;
715  return false;
716  }
717  int maxCycle = std::min(latestCycle, ddgCycle);
718  std::cerr << "\t\t\tmaxCycle after ddg: " << maxCycle << std::endl;
719  int rmCycle = rm_->latestCycle(maxCycle, mn);
720  std::cerr << "\t\t\trmCycle: " << rmCycle << std::endl;
721  if (rmCycle != -1 && rmCycle >= earliestCycle) {
722  rm_->assign(rmCycle, mn);
723  scheduledMoves_.insert(&mn);
724  std::cerr << "\t\tScheduled to cycle: " << rmCycle << std::endl;
725 
726  // if regcpy is unscheudled it must be rescheduled
727  if (t == TempRegBefore) {
728  MoveNode* regCopyBefore = regCopiesBefore_[&mn];
729  if (regCopyBefore != NULL &&
730  pendingBypassSources_.find(regCopyBefore) ==
731  pendingBypassSources_.end()) {
732  if (!regCopyBefore->isScheduled()) {
733  std::cerr << "scheduling regcopybefore: " <<
734  regCopyBefore->toString() << std::endl;
735  if (!(scheduleMoveBU(
736  *regCopyBefore, 0, rmCycle-1, t))) {
737  std::cerr << "regcopybefore scheduling failed" <<
738  std::endl;
739  unschedule(mn);
740  return false;
741  }
742  }
743  }
744  }
745  return true;
746  } else {
747  std::cerr << "\t\t\trmcycle is -1, cannot schedule move" << std::endl;
748  return false;
749  }
750 }
751 
752 /**
753  * Bypasses a node.
754  *
755  * @param maxHopCount maximum amount or registers to skip while bypassing.
756  * 1 == bypass from move which produced the value, 0 == do not bypass.
757  *
758  * @return the amount of moves saved by this bypass
759  */
760 int
762  std::cerr << "\t\tIncoming hopcount: " << maxHopCount << std::endl;
763  std::pair<MoveNode*,int> bypassSource =
764  findBypassSource(node, maxHopCount);
765  if (bypassSource.second == 0) {
766  std::cerr << "\t\thopcount 0" << std::endl;
767  return 0;
768  }
769 
770  // do not bypass from already scheduled moves.
771  if (bypassSource.first->isScheduled()) {
772  std::cerr << "\t\tbypassource scheduled" << std::endl;
773  return 0;
774  }
775 /*
776  ddg_->writeToDotFile("bypass_source_scheduled.dot");
777  throw Exception(__FILE__, __LINE__,__func__,
778  "Bypass souce already scheduled! " +
779  bypassSource.first->toString());
780  }
781 */
782 
783  if (!ddg_->guardsAllowBypass(*bypassSource.first, node)) {
784  std::cerr << "\t\tguardsnotallowbypass" << std::endl;
785  return 0;
786  }
787 
788 // std::cerr << "\t\tMerging." << std::endl;
789 // ddg_->writeToDotFile("merging.dot");
790  if (!ddg_->mergeAndKeep(*bypassSource.first,node)) {
791 
792  std::cerr << "Merge fail." << std::endl;
793  return 0;
794  }
795 
796  std::cerr << "Merged." << std::endl;
797 
798  bypassSources_[&node] = bypassSource.first;
799 
800  // TODO: DRE seems to slow things down!
801  if (killDeadResults_) {
802  if (!ddg_->resultUsed(*bypassSource.first)) {
803  std::cerr << "Could remove source:" <<
804  bypassSource.first->toString() << std::endl;
805  pendingBypassSources_.insert(bypassSource.first);
806  }
807  // bypassing own regcopy away? what if 2?
808  if (regCopiesBefore_[&node] == bypassSource.first) {
809  MoveNode* rgBefore = regCopiesBefore_[bypassSource.first];
810  if (rgBefore != NULL) {
811  regCopiesBefore_[&node] = rgBefore;
812  }
813  }
814  }
815 
816  return bypassSource.second;
817 }
818 
819 /**
820  * Finds a source where from to bypass.
821  *
822  * Goes ddg backwards and checks for connectivity.
823  *
824  * @return pair of source of bypass and amount of regs skipped by the bypass.
825  */
826 std::pair<MoveNode*, int>
828  MoveNode& node, int maxHopCount) {
829  std::set<const TTAMachine::Port*>
830  destinationPorts =
832  *targetMachine_, node);
833 
834  MoveNode* n = &node;
835  MoveNode* okSource = NULL;
836  int hops = 0;
837  for (int i = 0; i < maxHopCount; i++) {
838  MoveNode* rrSource = ddg_->onlyRegisterRawSource(*n);
839  if (rrSource == NULL) {
840  break;
841  }
842  n = rrSource;
844  *n, destinationPorts)) {
845  okSource = n;
846  hops = i+1;
847  }
848  }
849  return std::pair<MoveNode*,int>(okSource, hops);
850 }
851 
852 /**
853  * Tries to schedule an (input) node, bypassing if possible
854  */
855 bool
857  MoveNode& node, MoveNode* trigger, int latestCycle, bool allowRegCopies) {
858  // TODO: DDG does not yet support bypass over multiply nodes
859  int bypassHopCount = 1; //INT_MAX;
860  while (bypassHopCount >= 0) {
861  bypassHopCount = bypassNode(node, bypassHopCount);
862  if (bypassHopCount > 0) {
863  std::cerr << "\tBypassed node: " << node.toString() << std::endl;
864  if (node.isSourceOperation()) {
865  // take a copy of latestCycle because scheduleOperation
866  // may modify it
867  int lc = latestCycle;
868  if (scheduleOperation(node.sourceOperation(), lc, false)) {
869  return true;
870  } else {
871  // scheduling bypassed op failed.
872  // revert bypass, and try with smaller bypass ho count.
873  undoBypass(node);
874  bypassHopCount--;
875  continue;
876  }
877  } else {
878  // schedule individual input, not bypassed from op.
879  // bypassed from reg write?
881  node, trigger, latestCycle, allowRegCopies)) {
882  return true;
883  } else {
884  std::cerr << "Bypassed operand failed.. trying smaller "
885  << " hop count." <<
886  node.toString() << std::endl;
887 
888  // scheduling bypassed op failed.
889  // revert bypass, and try with smaller bypass ho count.
890  undoBypass(node);
891  bypassHopCount--;
892  continue;
893  }
894  }
895  }
896  // not bypassed.
897  std::cerr << "\tDid not bypass: " << node.toString() << std::endl;
899  node, trigger, latestCycle, allowRegCopies)) {
900  return true;
901  } else {
902  return false;
903  }
904  }
905  // for some reason went out from the loop. fail
906  return false;
907 }
908 
909 /**
910  * Schedule all operands of an operation, (but no trigger), trying t
911  * bypass them.
912  */
913 bool
915  ProgramOperation& po, MoveNode* trigger, int latestCycle,
916  bool allowRegCopies) {
917 
918  for (int i = 0; i < po.inputMoveCount(); i++) {
919  MoveNode& operand = po.inputMove(i);
920  if (trigger != &operand) {
922  operand, trigger, latestCycle, allowRegCopies)) {
923  for (; i >= 0; i++) {
925  return false;
926  }
927  }
928  } else {
929  assert(operand.isScheduled());
930  }
931  }
932  return true;
933 }
934 
935 /**
936  * Tries to schedue operand or trigger, but not trying to bypass
937  */
938 bool
940  MoveNode& operand, MoveNode* trigger, int latestCycle,
941  bool allowRegCopies) {
942  std::pair<int,int> cycleLimits =
943  operandCycleLimits(operand, trigger);
944 
945  return scheduleMoveBU(operand, cycleLimits.first,
946  std::min(latestCycle,cycleLimits.second),
947  allowRegCopies ?
948  TempRegBefore :
950 }
951 
952 /**
953  * Calculates the range where operand can be scheduled, based on
954  * results and other operands.
955  */
956 std::pair<int,int>
958  MoveNode& mn, MoveNode* trigger) {
959  int minn = 0;
960  int maxx = endCycle_;
963  if (po.areOutputsAssigned()) {
964  maxx = std::min(mn.latestTriggerWriteCycle(), (int)endCycle_);
965  } else {
966  maxx = -1;
967  }
968  if (po.isAnyInputAssigned()) {
969  // if trigger now known, find it.
970  if (trigger == NULL) {
971  trigger = findTrigger(po);
972  }
973  if (trigger != NULL) {
974  if (trigger == &mn) {
975  // this is trigger. limit min to last operand.
976  minn = std::max(lastOperandCycle(po), 0);
977  } else {
978  // this is not trigger.
979  if (trigger->isScheduled()) {
980  maxx = trigger->cycle();
981  }
982  }
983  } else {
984  // TODO: what to do if cannot find trigger? fail?
985  return std::pair<int,int>(INT_MAX, -1);
986  }
987  }
988  return std::pair<int,int>(minn, maxx);
989 }
990 
991 /**
992  * find the highest cycle some operand of an operation is scheduled.
993  *
994  * @TODO: move this to ProgramOperation class?
995  */
996 int
998  const ProgramOperation& po) {
999  int res = -1;
1000  for (int i = 0; i < po.inputMoveCount(); i++) {
1001  const MoveNode& mn = po.inputMove(i);
1002  if (mn.isScheduled()) {
1003  if (mn.cycle() > res) {
1004  res = mn.cycle();
1005  }
1006  }
1007  }
1008  return res;
1009 }
1010 
1011 /**
1012  * undoes a bypass.
1013  */
1014 void
1016  std::cerr << "\tundoing bypass: " << mn.toString() << std::endl;
1017  MoveNode* source = bypassSources_[&mn];
1018  if (source != NULL) {
1019  if (pendingBypassSources_.erase(source)) {
1020  std::cerr << "undid dre: " << source->toString()
1021  << std::endl;
1022  if (regCopiesBefore_[source] != NULL) {
1023  assert(regCopiesBefore_[source] == regCopiesBefore_[&mn]);
1024  regCopiesBefore_[&mn] = source;
1025  // TODO: what if bypassed over 2 moves?
1026  // ddg does not support it anyway, not yet a problem
1027  }
1028  }
1029  ddg_->unMerge(*source, mn);
1030  bypassSources_[&mn] = NULL;
1031  }
1032  std::cerr << "\tundid bypass: " << mn.toString() << std::endl;
1033 }
1034 
1035 /**
1036  * Undoes bypass and unschedules a move.
1037  *
1038  * This also recursively unschedules the source operation of the bypass.
1039  */
1040 void
1042  if (mn.isBypass()) {
1044  }
1045  unschedule(mn);
1046  undoBypass(mn);
1047 }
1048 
1049 /*
1050 void
1051 BypassingBUBasicBlockScheduler::revertRegCopyBefore(
1052  MoveNode& regCopy, MoveNode& mn) {
1053  ddg->mergeAndKeep(regCopy, mn);
1054 }
1055 
1056 void
1057 BypassingBUBasicBlockScheduler::revertRegCopyAfter(
1058  MoveNode& mn, MoveNode& regCopy) {
1059  ddg->mergeAndKeep(regCopy, mn);
1060 }
1061 */
1062 
1063 /**
1064  * Unschedule a move
1065  *
1066  * Also unschedules the tempregcopies of that move.
1067  */
1068 void
1070  std::cerr << "UnScheduling: " << mn.toString() << std::endl;
1071  MoveNode* regcopy = regCopiesBefore_[&mn];
1072  if (regcopy != NULL) {
1073  unschedule(*regcopy);
1074  }
1075  if (mn.isScheduled()) {
1076  rm_->unassign(mn);
1077  }
1078 /*
1079  if (regcopy != NULL) {
1080  revertRegCopyBefore(mn);
1081  }
1082 */
1083  scheduledMoves_.erase(&mn);
1084  regcopy = regCopiesAfter_[&mn];
1085  if (regcopy != NULL) {
1086  unschedule(*regcopy);
1087 // revertRegCopyAfter(mn);
1088  }
1089 
1090 
1091 }
1092 
1093 /**
1094  * Unschedule all result moves of an operation.
1095  */
1096 void
1098  std::cerr << "\tUnschedulign results" << std::endl;
1099  for (int i = 0; i < po.outputMoveCount(); i++) {
1100  MoveNode& mn = po.outputMove(i);
1101  if (mn.isScheduled()) {
1102  unschedule(mn);
1103  }
1104  }
1105 }
1106 
1107 /**
1108  * Unschedules all operands of an operation.
1109  * Also reverts bypasses and unschedules the bypass sources.
1110  */
1111 void
1113  ProgramOperation& po) {
1114  for (int i = 0; i < po.inputMoveCount(); i++) {
1116  }
1117 }
1118 
1119 /**
1120  * Unschedules an operation (and recursively the bypass sources
1121  */
1122 void
1124  unscheduleOperands(po);
1125  unscheduleResults(po);
1126 }
1127 
1128 /**
1129  * Cleanups some bookkeeping. This should not be needed
1130  */
1131 void
1133  bypassSources_.clear();
1134  for (DataDependenceGraph::NodeSet::iterator i = removedNodes_.begin();
1135  i != removedNodes_.end(); i++) {
1136  if (ddg_->rootGraph() != ddg_) {
1137  if ((**i).isScheduled()) {
1138  std::cerr << "DRE'd move: " << (**i).toString() <<
1139  " is Scheduled! " << std::endl;
1140  }
1141  assert(!(**i).isScheduled());
1142  ddg_->rootGraph()->removeNode(**i);
1143  }
1144  delete *i;
1145  }
1146  removedNodes_.clear();
1147  pendingBypassSources_.clear();
1148 
1149  regCopiesBefore_.clear();
1150  regCopiesAfter_.clear();
1151 }
1152 
1153 /**
1154  * Tries to rename source register of unconnected move to make it connected.
1155  */
1157  MoveNode& moveNode, int latestCycle) {
1158 
1159  if (!renameRegisters_) {
1160  return false;
1161  }
1162 
1164  moveNode, false, false, false, latestCycle)) {
1165  return false;
1166  }
1167 
1169  moveNode, *targetMachine_)) {
1170  return true;
1171  } else {
1172  return false;
1173  }
1174 
1175 
1176 
1177 #if 0
1178  LiveRange* lr = ddg_->findLiveRange(moveNode, false);
1179  // todo: should rename here
1180  if (lr == NULL) {
1181  std::cerr << "Could not find liverange for:" << moveNode.toString() << std::endl;
1182  return false;
1183  }
1184 
1185  // for now limit to simple cases.
1186  if (!(lr->writes.size() == 1 && lr->reads.size() > 0)) {
1187  std::cerr << "Liverange too complex to rename: " << lr->toString()
1188  <<" for: " << moveNode.toString() << std::endl;
1189  return false;
1190  }
1191 
1192  std::cerr << "(Not really yeat)Trying to rename lr: " << lr->toString() << std::endl;
1193 
1194  // TODO: find the register.
1195 
1196  return renamer_->renameLiveRange(*lr, "", false, false, false);
1197 #endif
1198 }
1199 
1200 /**
1201  * Creates a temp reg copy for given move.
1202  *
1203  * Does not necessarily create all required temp reg copies,
1204  * so this may be needed to be called recursively to get all required copies.
1205  *
1206  * @TODO: Smarted logic to select the register to use
1207  *
1208  * @param mn movenode to be splitted
1209  * @param after set to true if temp reg is the last of the nodes, false if first
1210  * @return the created tempregcopy
1211  */
1212 MoveNode*
1214 
1215  // before splitting, annotate the possible return move so we can still
1216  // detect a procedure return in simulator
1217  if (mn.move().isReturn()) {
1218  TTAProgram::ProgramAnnotation annotation(
1220  mn.move().setAnnotation(annotation);
1221  }
1222 
1223  std::set<TTAMachine::RegisterFile*, TTAMachine::MachinePart::Comparator>
1224  rfs = possibleTempRegRFs(mn, after);
1225 
1226  TTAMachine::RegisterFile* rf = *rfs.rbegin();
1227 
1228  int lastRegisterIndex = rf->size()-1;
1229  TTAMachine::Port* dstRFPort = rf->firstWritePort();
1230  TTAMachine::Port* srcRFPort = rf->firstReadPort();
1231 
1232  TTAProgram::TerminalRegister* tempWrite =
1233  new TTAProgram::TerminalRegister(*dstRFPort, lastRegisterIndex);
1234 
1235  TTAProgram::TerminalRegister* tempRead =
1236  new TTAProgram::TerminalRegister(*srcRFPort, lastRegisterIndex);
1237 
1238  TTAProgram::ProgramAnnotation connMoveAnnotation(
1240 
1241  TTAProgram::Move* copyMove = mn.move().copy();
1242  MoveNode* copyNode = new MoveNode(copyMove);
1244  ddg_->addNode(*copyNode,bbn);
1245  copyMove->addAnnotation(connMoveAnnotation);
1246 
1247  if (after) {
1248  std::cerr << "Creating temp move after: " << mn.toString() << " ";
1249  copyMove->setSource(tempRead);
1250  mn.move().setDestination(tempWrite);
1252  *ddg_, mn, &mn, copyNode, rf, lastRegisterIndex, bbn, true);
1253  std::cerr << " Moves after split: " << mn.toString() << " and " <<
1254  copyMove->toString() << std::endl;
1255 
1256 
1257  } else {
1258  std::cerr << "Creating temp move before: " << mn.toString();
1259  copyMove->setDestination(tempWrite);
1260  mn.move().setSource(tempRead);
1261 
1263  *ddg_, mn, copyNode, &mn, rf, lastRegisterIndex, bbn, true);
1264 
1265  std::cerr << "Moves after split: " << copyMove->toString()
1266  << " and "<< mn.toString() << std::endl;
1267 
1268  createAntidepsFromUnscheduledRegCopies(*copyNode, mn, *tempWrite);
1269  }
1270 
1271  return copyNode;
1272 }
1273 
1274 /**
1275  * Creste register antideps from unscheduled temp reg copies
1276  * to the just created one.
1277  *
1278  * This is needed when temp reg copies are "created on wrong order",
1279  * for example if some operation is attempted to first schedule some FU,
1280  * later to some another
1281  */
1283  MoveNode& copyNode, MoveNode& mn,
1284  TTAProgram::Terminal& terminalRegister) {
1285  TCEString reg = DisassemblyRegister::registerName(terminalRegister);
1286 
1287  for (std::map<MoveNode*, MoveNode*, MoveNode::Comparator>::iterator i =
1288  regCopiesBefore_.begin(); i != regCopiesBefore_.end(); i++) {
1289  // found non-scheduled move having regcopies..
1290  if (!i->first->isScheduled() && i->first != &mn) {
1291  if (i->first->isSourceVariable()) {
1293  i->first->move().source());
1294  if (reg1 == reg) {
1295  DataDependenceEdge* edgeWar =
1296  new DataDependenceEdge(
1299  ddg_->connectOrDeleteEdge(*i->first, copyNode, edgeWar);
1300 
1301  DataDependenceEdge* edgeWaw =
1302  new DataDependenceEdge(
1305  ddg_->connectOrDeleteEdge(*i->second, copyNode, edgeWaw);
1306  }
1307  }
1308  }
1309  }
1310 }
1311 
1312 /**
1313  * Find possible temp reg RF's for connectivity of given register.
1314  *
1315  * This only gives the register files that for the "next register in the
1316  * temp reg chain", not the whole chain
1317  */
1318 std::set<TTAMachine::RegisterFile*, TTAMachine::MachinePart::Comparator>
1320  const MoveNode& mn, bool tempRegAfter) {
1321 
1322  std::set<TTAMachine::RegisterFile*, TTAMachine::MachinePart::Comparator>
1323  result;
1324 
1325  std::map<int, int> rfDistanceFromSource;
1326  std::map<int, int> rfDistanceFromDestination;
1327 
1328  typedef SimpleInterPassDatum<
1329  std::vector<std::pair<TTAMachine::RegisterFile*, int> > >
1330  TempRegData;
1331 
1332  std::string srDatumName = "SCRATCH_REGISTERS";
1333  if (!BasicBlockPass::interPassData().hasDatum(srDatumName) ||
1334  (dynamic_cast<TempRegData&>(
1335  BasicBlockPass::interPassData().datum(srDatumName))).size() == 0)
1336  throw IllegalProgram(
1337  __FILE__, __LINE__, __func__,
1338  "No scratch registers available for temporary moves.");
1339 
1340  const TempRegData& tempRegs =
1341  dynamic_cast<TempRegData&>(
1342  BasicBlockPass::interPassData().datum(srDatumName));
1343 
1344 
1345  for (unsigned int i = 0; i < tempRegs.size(); i++) {
1346  rfDistanceFromSource[i] = INT_MAX;
1347  rfDistanceFromDestination[i] = INT_MAX;
1348  }
1349 
1350 
1351  for (unsigned int i = 0; i < tempRegs.size(); i++) {
1352  TTAMachine::RegisterFile* rf = tempRegs[i].first;
1353  std::set<const TTAMachine::Port*> readPorts =
1355  std::set<const TTAMachine::Port*> writePorts =
1357  bool srcOk = false;
1359  mn, writePorts)) {
1360  rfDistanceFromSource[i] = 1;
1361  srcOk = true;
1362  }
1363 
1365  readPorts, mn)) {
1366  rfDistanceFromDestination[i] = 1;
1367  if (srcOk) {
1368  // this RF does it!
1369  result.insert(rf);
1370  }
1371  }
1372  }
1373 
1374  // modified check to avoid 4ever loop in case of broken machine
1375  bool modified = true;
1376  if (!tempRegAfter) {
1377  while (result.empty() && modified) {
1378  int shortest = INT_MAX;
1379  modified = false;
1380  for (unsigned int i = 0; i < tempRegs.size(); i++) {
1381  int srcDist = rfDistanceFromSource[i];
1382  if (srcDist != INT_MAX) {
1383  TTAMachine::RegisterFile* rfSrc = tempRegs[i].first;
1384  for (unsigned int j = 0; j < tempRegs.size(); j++) {
1385  if (rfDistanceFromSource[j] > srcDist + 1) {
1386  TTAMachine::RegisterFile* rfDest = tempRegs[j].first;
1387  // ignore rf's which are not wide enough
1389  *rfSrc, *rfDest,
1390  (mn.move().isUnconditional() ? NULL :
1391  &mn.move().guard().guard()))) {
1392  rfDistanceFromSource[j] = srcDist + 1;
1393  modified = true;
1394  if (rfDistanceFromDestination[j] == 1) {
1395  int dist = srcDist + 2;
1396  if (dist < shortest) {
1397  result.clear();
1398  shortest = dist;
1399  }
1400  if (dist == shortest) {
1401  result.insert(rfDest);
1402  }
1403  }
1404  }
1405  }
1406  }
1407  }
1408  }
1409  }
1410  return result;
1411  } else {
1412  while (result.empty() && modified) {
1413  int shortest = INT_MAX;
1414  modified = false;
1415  for (unsigned int i = 0; i < tempRegs.size(); i++) {
1416  int dstDist = rfDistanceFromDestination[i];
1417  if (dstDist != INT_MAX) {
1418  TTAMachine::RegisterFile* rfDst = tempRegs[i].first;
1419  for (unsigned int j = 0; j < tempRegs.size(); j++) {
1420  if (rfDistanceFromDestination[j] > dstDist + 1) {
1421  TTAMachine::RegisterFile* rfSrc = tempRegs[j].first;
1423  *rfDst, *rfSrc,
1424  (mn.move().isUnconditional() ? NULL :
1425  &mn.move().guard().guard()))) {
1426  rfDistanceFromDestination[j] = dstDist + 1;
1427  modified = true;
1428  if (rfDistanceFromSource[j] == 1) {
1429  int dst = dstDist + 2;
1430  if (dst < shortest) {
1431  result.clear();
1432  shortest = dst;
1433  }
1434  if (dst == shortest) {
1435  result.insert(rfSrc);
1436  }
1437  }
1438  }
1439  }
1440  }
1441  }
1442  }
1443  }
1444  return result;
1445  }
1446 }
bool successorsReady(MoveNode &node) const
DataDependenceGraph * ddg_
DDG of the currently scheduled BB.
void setAnnotation(const ProgramAnnotation &annotation)
bool scheduleOperandOrTrigger(MoveNode &operand, MoveNode *trigger, int latestCycle, bool allowRegCopies)
RegisterRenamer * renamer_
bool scheduleResults(ProgramOperation &po, int latestCycle, bool allowTempRegCopies)
void scheduleOperation(MoveNodeGroup &mng, MoveNodeSelector &selector)
int lastOperandCycle(const ProgramOperation &po)
bool guardsAllowBypass(const MoveNode &defNode, const MoveNode &useNode)
void setDestination(Terminal *dst)
Definition: Move.cc:319
void setMaxCycle(unsigned int maxCycle)
bool isOperationMove() const
Definition: MoveNode.cc:214
#define __func__
Definition: Application.hh:67
static bool isConnected(const TTAMachine::Port &sourcePort, const TTAMachine::Port &destinationPort, TTAMachine::Guard *guard=NULL)
const TTAMachine::Machine * targetMachine_
The target machine we are scheduling the program against.
virtual void handleDDG(DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine)
InterPassDatum & datum(const std::string &key)
void finalizeOperation(MoveNodeSelector &selector)
int inputMoveCount() const
bool isUnconditional() const
Definition: Move.cc:156
int outputMoveCount() const
TCEString toString() const
Definition: LiveRange.cc:53
bool isScheduled() const
int latestTriggerWriteCycle() const
Definition: MoveNode.cc:593
std::string toString() const
bool scheduleMoveUB(MoveNode &mn, int earlistCycle, int latestCycle)
Terminal & source() const
Definition: Move.cc:288
void createAntidepsFromUnscheduledRegCopies(MoveNode &copyNode, MoveNode &mn, TTAProgram::Terminal &terminalRegister)
virtual bool dumpDDGsXML() const
bool isReturn() const
Definition: Move.cc:245
bool connectOrDeleteEdge(const MoveNode &tailNode, const MoveNode &headNode, DataDependenceEdge *edge)
bool isSourceOperation() const
Definition: MoveNode.cc:157
int nodeCount() const
MoveNode * onlyRegisterRawSource(const MoveNode &mn) const
int bypassNode(MoveNode &node, int maxHopCount)
virtual bool killDeadResults() const
Move * copy() const
Definition: Move.cc:399
std::pair< int, int > operandCycleLimits(MoveNode &mn, MoveNode *trigger)
static std::set< const TTAMachine::Port * > findReadPorts(TTAMachine::Unit &rf)
bool isBypass() const
Definition: MoveNode.cc:241
virtual bool dumpDDGsDot() const
#define debugLog(text)
Definition: Application.hh:87
void writeToXMLFile(std::string fileName) const
const BasicBlockNode & getBasicBlockNode(const MoveNode &mn) const
bool mergeAndKeep(MoveNode &resultNode, MoveNode &userNode)
Node & node(const int index) const
virtual void assign(int cycle, MoveNode &node)
virtual TCEString name() const
Definition: Operation.cc:88
static std::set< const TTAMachine::Port * > findWritePorts(TTAMachine::Unit &rf)
virtual void writeToDotFile(const TCEString &fileName) const
void addNode(MoveNode &moveNode)
virtual int latestCycle(MoveNode &node) const
virtual ControlUnit * controlUnit() const
Definition: Machine.cc:331
static CmdLineOptions * cmdLineOptions()
Definition: Application.cc:346
ProgramOperation & destinationOperation(unsigned int index=0) const
std::string toString() const
Definition: MoveNode.cc:492
virtual int operationIndex() const
Definition: Terminal.cc:352
MoveNode & outputMove(int index) const
BypassingBUBasicBlockScheduler(InterPassData &data, SoftwareBypasser *bypasser=NULL, CopyingDelaySlotFiller *delaySlotFiller=NULL, RegisterRenamer *registerRenamer=NULL)
bool isControlFlowMove() const
Definition: Move.cc:219
bool renameLiveRange(LiveRange &liveRange, const TCEString &newReg, bool usedBefore, bool usedAfter, bool loopScheduling)
std::set< MoveNode *, MoveNode::Comparator > removedNodes_
static bool canAnyPortWriteToDestination(std::set< const TTAMachine::Port *> &ports, const MoveNode &dest)
static int canSourceWriteToAnyDestinationPort(const MoveNode &src, std::set< const TTAMachine::Port *> &ports)
InterPassData & interPassData()
virtual int size() const
const Operation & operation() const
Unit * parentUnit() const
virtual void notifyScheduled(MoveNode &node)=0
static void fixDDGEdgesInTempReg(DataDependenceGraph &ddg, MoveNode &originalMove, MoveNode *firstMove, MoveNode *lastMove, const TTAMachine::RegisterFile *lastRF, int lastRegisterIndex, BasicBlockNode &currentBBNode, bool bottomUpScheduling)
MoveNode & inputMove(int index) const
TTAMachine::Guard & guard() const
Definition: MoveGuard.cc:86
int nodeCount() const
bool isDestinationOperation() const
virtual void unassign(MoveNode &node)
DataDependenceGraph::NodeSet writes
Definition: LiveRange.hh:39
std::string toString() const
virtual void removeNode(Node &node)
std::pair< MoveNode *, int > findBypassSource(MoveNode &node, int maxHopCount)
virtual HWOperation * operation(const std::string &name) const
std::set< MoveNode *, typename MoveNode ::Comparator > NodeSet
Definition: BoostGraph.hh:86
bool bypassAndScheduleNode(MoveNode &node, MoveNode *trigger, int latestCycle, bool allowRegCopies)
void ddgSnapshot(DataDependenceGraph &ddg, const std::string &name, DataDependenceGraph::DumpFileFormat format, bool final, bool resetCounter=false) const
static void findTempRegisters(const TTAMachine::Machine &machine, InterPassData &ipd)
std::map< MoveNode *, MoveNode *, MoveNode::Comparator > bypassSources_
bool bypassAndScheduleOperands(ProgramOperation &po, MoveNode *trigger, int latestCycle, bool allowRegCopies)
bool renameSourceRegister(MoveNode &node, bool loopScheduling, bool allowSameRf, bool differentRfOnlyDirectlyReachable, int latestCycle=INT_MAX)
bool isMove() const
ProgramOperation & sourceOperation() const
Definition: MoveNode.cc:402
SimpleResourceManager * rm_
Resource Manager of the currently scheduled BB.
void setSelector(MoveNodeSelector *selector)
LiveRange * findLiveRange(MoveNode &lrNode, bool writingNode=true) const
LLVMTCECmdLineOptions * options_
virtual MoveNodeGroup candidates()
std::map< MoveNode *, MoveNode *, MoveNode::Comparator > regCopiesAfter_
virtual int earliestCycle(MoveNode &node) const
BoostGraph * rootGraph()
static std::set< const TTAMachine::Port * > findPossibleDestinationPorts(const TTAMachine::Machine &mach, const MoveNode &node)
int cycle() const
Definition: MoveNode.cc:365
int earliestCycle(const MoveNode &moveNode, unsigned int ii=UINT_MAX, bool ignoreRegWaRs=false, bool ignoreRegWaWs=false, bool ignoreGuards=false, bool ignoreFUDeps=false, bool ignoreSameOperationEdges=false) const
void initialize(DataDependenceGraph &ddg)
MoveNode * createTempRegCopy(MoveNode &mn, bool after)
MoveGuard & guard() const
Definition: Move.cc:331
static bool canTransportMove(MoveNode &moveNode, const TTAMachine::Machine &machine)
virtual void dropNode(Node &node)
MoveNode * findTrigger(ProgramOperation &po)
std::set< MoveNode *, MoveNode::Comparator > scheduledMoves_
#define abortWithError(message)
Definition: Application.hh:72
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
MoveNode & node(int index) const
void addAnnotation(const ProgramAnnotation &annotation)
void unMerge(MoveNode &resultNode, MoveNode &mergedNode)
A reg to reg move that was added because of missing connectivity between the original target and dest...
std::string toString() const
Definition: Move.cc:422
virtual const TTAMachine::Port & port() const
Definition: Terminal.cc:366
bool renameSourceIfNotConnected(MoveNode &moveNode, int latestCycle)
DataDependenceGraph::NodeSet reads
Definition: LiveRange.hh:40
std::map< MoveNode *, MoveNode *, MoveNode::Comparator > regCopiesBefore_
int latestCycle(const MoveNode &moveNode, unsigned int ii=UINT_MAX, bool ignoreRegAntideps=false, bool ignoreUnscheduledSuccessors=true) const
#define assert(condition)
Definition: Application.hh:80
TTAProgram::Move & move()
bool scheduleMoveBU(MoveNode &mn, int earlistCycle, int latestCycle, TempRegCopyLocation t)
std::set< MoveNode *, MoveNode::Comparator > pendingBypassSources_
std::set< TTAMachine::RegisterFile *, TTAMachine::MachinePart::Comparator > possibleTempRegRFs(const MoveNode &mn, bool tempRegAfter)
void setSource(Terminal *src)
Definition: Move.cc:298
virtual void mightBeReady(MoveNode &node)=0
bool isScheduled() const
Definition: MoveNode.cc:353
static TCEString registerName(const TTAMachine::RegisterFile &rf, int index, char delim='.')
bool resultUsed(MoveNode &resultNode)