OpenASIP 2.2
Loading...
Searching...
No Matches
BUBasicBlockScheduler.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2012 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 BUBasicBlockScheduler.cc
26 *
27 * Definition of BUBasicBlockScheduler class.
28 *
29 * @author Vladimir Guzma 2011 (vladimir.guzma-no.spam-tut.fi)
30 * @note rating: red
31 */
32
33#include <set>
34#include <string>
35
37#include "ControlFlowGraph.hh"
41#include "BUMoveNodeSelector.hh"
42#include "POMDisassembler.hh"
43#include "Procedure.hh"
44#include "ProgramOperation.hh"
45#include "ControlUnit.hh"
46#include "Machine.hh"
47#include "UniversalMachine.hh"
48#include "Guard.hh"
49#include "MapTools.hh"
50#include "Instruction.hh"
52#include "BasicBlock.hh"
54#include "RegisterCopyAdder.hh"
55#include "SchedulerPass.hh"
58#include "InterPassData.hh"
59#include "MoveNodeSet.hh"
60#include "Terminal.hh"
61#include "RegisterRenamer.hh"
62#include "HWOperation.hh"
64#include "Operation.hh"
65#include "TerminalImmediate.hh"
66#include "TerminalRegister.hh"
67
68//#define DEBUG_OUTPUT
69//#define DEBUG_REG_COPY_ADDER
70//#define CFG_SNAPSHOTS
71//#define BIG_DDG_SNAPSHOTS
72//#define DDG_SNAPSHOTS
73//#define SW_BYPASSING_STATISTICS
74//#define DEBUG_BYPASS
75
77
78/**
79 * Constructs the basic block scheduler.
80 *
81 * @param data Interpass data
82 * @param bypasser Helper module implementing software bypassing
83 * @param delaySlotFiller Helper module implementing jump delay slot filling
84 * @param registerRenamer Helper module implementing register renaming
85 */
87 InterPassData& data,
88 SoftwareBypasser* bypasser,
89 RegisterRenamer* renamer) :
90 BasicBlockScheduler(data, bypasser, renamer),
91 endCycle_(INT_MAX), bypass_(true), dre_(true), bypassDistance_(3) {
92
94 options_ = dynamic_cast<LLVMTCECmdLineOptions*>(cmdLineOptions);
95 jumpMove_ = NULL;
96}
97
98/**
99 * Destructor.
100 */
103
104/**
105 * Schedules a piece of code in a DDG
106 * @param ddg The ddg containing the code
107 * @param rm Resource manager that is to be used.
108 * @param targetMachine The target machine.
109 * @exception Exception several TCE exceptions can be thrown in case of
110 * a scheduling error.
111 */
112int
115 const TTAMachine::Machine& targetMachine, int /*minCycle*/, bool test) {
116 ddg_ = &ddg;
117 targetMachine_ = &targetMachine;
118
119 if (renamer_ != NULL) {
120 renamer_->initialize(ddg);
121 }
122
123 if (options_ != NULL && options_->dumpDDGsDot()) {
125 ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false);
126 }
127
128 if (options_ != NULL && options_->dumpDDGsXML()) {
130 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false);
131 }
132
133 if (options_ != NULL && options_->bypassDistance() > -1) {
135 }
136
137 if (options_ != NULL && options_->bypassDistance() == 0) {
138 bypass_ = false;
139 }
140
141 if (options_ != NULL && !options_->killDeadResults()) {
142 dre_ = false;
143 }
144
145 // empty need not to be scheduled
146 if (ddg.nodeCount() == 0 ||
147 (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
148 return 0;
149 }
150
151 // INT_MAX/2 won't work on trunk due to multithreading injecting empty
152 // instructions into the beginning of basic block.
153 endCycle_ = INT_MAX/1000;
154
155 // scheduling pipeline resources after last cycle may cause problems.
156 // make RM to check for those
158
159 BUMoveNodeSelector selector(ddg, targetMachine);
160 selector_ = &selector;
161 // register selector to renamer for notfications.
162 if (renamer_ != NULL) {
163 renamer_->setSelector(&selector);
164 }
165
166 rm_ = &rm;
167
168 MoveNodeGroup moves = selector.candidates();
169 while (moves.nodeCount() > 0) {
170 bool movesRemoved = false;
171 MoveNode& firstMove = moves.node(0);
172 if (firstMove.isOperationMove()) {
173 scheduleOperation(moves, selector);
174 movesRemoved = true;
175 } else {
176 if (firstMove.move().destination().isRA()) {
177 scheduleMove(firstMove, endCycle_, true);
178 finalizeSchedule(firstMove, selector);
179 } else {
180 int tmp = endCycle_;
181 if (bypassNode(firstMove,tmp) && dre_
182 &&!ddg_->resultUsed(firstMove)) {
183 // No need to schedule original move any more
184 movesRemoved = true;
185 } else {
186 // schedule original move
187 scheduleRRMove(firstMove);
188 // If move was register copy to self, it could have been
189 // just dropped.
190 movesRemoved = true;
191 if (!firstMove.isScheduled()) {
192 undoBypass(firstMove);
193 scheduleRRMove(firstMove);
194 }
195 }
196 if (bypass_) {
197 bypassNode(firstMove, tmp);
198 }
199 finalizeSchedule(firstMove, selector);
200 }
201 }
202 if (!movesRemoved) {
203 if (!moves.isScheduled()) {
204 std::string message = " Move(s) did not get scheduled: ";
205 for (int i = 0; i < moves.nodeCount(); i++) {
206 message += moves.node(i).toString() + " ";
207 }
208 ddg.writeToDotFile("failed_bb.dot");
209 throw ModuleRunTimeError(__FILE__,__LINE__,__func__, message);
210 }
211 }
212 moves = selector.candidates();
213 if (!test)
215 }
216
217 if (ddg.nodeCount() != ddg.scheduledNodeCount()) {
218 debugLog("All moves in the DDG didn't get scheduled.");
219 ddg.writeToDotFile("failed_bb.dot");
220 abortWithError("Should not happen!");
221 }
222
223 if (options_ != NULL && options_->dumpDDGsDot()) {
224 std::string wtf = "0";
226 ddg, wtf, DataDependenceGraph::DUMP_DOT, true);
227 }
228
229 if (options_ != NULL && options_->dumpDDGsXML()) {
231 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
232 }
233 if (rm_->largestCycle() > (int)endCycle_) {
234 ddg.writeToDotFile("largest_bigger_than_endcycle.dot");
235 std::cerr << "rm largest cycle bigger than endCycle_!" <<
236 std::endl << "This may break delay slot filler!" <<
237 std::endl << " rm largest: " << rm_->largestCycle() <<
238 " end cycle: " << endCycle_ << std::endl;
239
240 abortWithError("Should not happen!");
241 }
242 int size = rm_->largestCycle() - rm_->smallestCycle();
243 if (test) {
245 }
246 return size;
247}
248
249/**
250 * Schedules loop in a DDG
251 *
252 * @param ddg The ddg containing the loop
253 * @param rm Resource manager that is to be used.
254 * @param targetMachine The target machine.
255 * @exception Exception several TCE exceptions can be thrown in case of
256 * a scheduling error.
257 * @return negative if failed, else overlapcount.
258 */
259int
262 const TTAMachine::Machine& targetMachine, int tripCount,
263 SimpleResourceManager*, bool testOnly) {
264 tripCount_ = tripCount;
265 ddg_ = &ddg;
266 targetMachine_ = &targetMachine;
267 minCycle_ = 0;
268
269 if (renamer_ != NULL) {
270 renamer_->initialize(ddg);
271 }
272
273 if (options_ != NULL && options_->dumpDDGsDot()) {
275 ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false, true);
276 }
277
278 if (options_ != NULL && options_->dumpDDGsXML()) {
280 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false, true);
281 }
282
283 if (options_ != NULL && options_->bypassDistance() > -1) {
285 }
286
287 if (options_ != NULL && options_->bypassDistance() == 0) {
288 bypass_ = false;
289 }
290
291 if (options_ != NULL && !options_->killDeadResults()) {
292 dre_ = false;
293 }
294
295 scheduledTempMoves_.clear();
296
297 // empty DDGs can be ignored
298 if (ddg.nodeCount() == 0 ||
299 (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
300 return 0;
301 }
302 endCycle_ = 2 * rm.initiationInterval() - 1;
303 BUMoveNodeSelector selector(ddg, targetMachine);
304
305 rm_ = &rm;
306
307 if (renamer_ != NULL) {
308 renamer_->setSelector(&selector);
309 }
310 MoveNodeGroup moves = selector.candidates();
311 while (moves.nodeCount() > 0) {
312 bool movesRemoved = false;
313 MoveNode& firstMove = moves.node(0);
314 if (firstMove.isOperationMove()) {
315 scheduleOperation(moves, selector);
316 movesRemoved = true;
317 } else {
318 if (firstMove.move().destination().isRA()) {
319 scheduleMove(firstMove, endCycle_, true);
320 notifyScheduled(moves, selector);
321 } else {
322 int tmp = endCycle_;
323 if (bypassNode(firstMove,tmp) && dre_
324 &&!ddg_->resultUsed(firstMove)) {
325 // No need to schedule original move any more
326 movesRemoved = true;
327 } else {
328 // schedule original move
329 scheduleRRMove(firstMove);
330 // If move was register copy to self, it could have been
331 // just dropped.
332 movesRemoved = true;
333 }
334 if (bypass_) {
335 bypassNode(firstMove, tmp);
336 }
337 finalizeSchedule(firstMove, selector);
338 }
339 }
340
341 if (!movesRemoved && !moves.isScheduled()) {
343 std::string("ii_") +
345 std::string("_dag.dot"));
346
348 return -1;
349 }
350
351 moves = selector.candidates();
352 }
353
354 if (ddg.nodeCount() !=
355 ddg.scheduledNodeCount()) {
356 debugLog("All moves in the DDG didn't get scheduled.");
357// debugLog("Disassembly of the situation:");
358// Application::logStream() << bb.disassemble() << std::endl;
359 ddg.writeToDotFile("failed_bb.dot");
360 abortWithError("Should not happen!");
361 }
362
363 // loop scheduling did not help
364 if (static_cast<unsigned>(ddg.largestCycle() - ddg.smallestCycle()) < rm.initiationInterval()
365 || testOnly) {
366 if (static_cast<unsigned>(ddg.largestCycle() - ddg.smallestCycle()) <
367 rm.initiationInterval()) {
369 << "No overlapping instructions."
370 << "Should Revert to ordinary scheduler."
371 << " ii = " << rm.initiationInterval()
372 << " size = " << ddg.largestCycle() - ddg.smallestCycle()
373 << std::endl;
374 }
375 // this have to be calculated before unscheduling.
376 int rv = (ddg.largestCycle() - ddg.smallestCycle()) / rm.initiationInterval();
378 return rv;
379 }
380
381 // test that ext-cond jump not in prolog (where it is skipped)
382 int overlap_count = (ddg.largestCycle() - ddg.smallestCycle()) / rm.initiationInterval();
383 if (overlap_count >= tripCount) {
385 return -1;
386 }
387
388 if (options_ != NULL && options_->dumpDDGsDot()) {
389 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, true);
390 }
391
392 if (options_ != NULL && options_->dumpDDGsXML()) {
393 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
394 }
395
396 if (jumpMove_ != NULL) {
397 MoveNode* jumpLimit = ddg_->findLoopLimitAndIndex(*jumpMove_).first;
398 if (jumpLimit != NULL) {
399 int jumpOverlapCount = (endCycle_ - rm.smallestCycle())
400 / rm.initiationInterval();
401 TTAProgram::TerminalImmediate& ti = dynamic_cast<
402 TTAProgram::TerminalImmediate&>(jumpLimit->move().source());
403 int jumpLimitValue = ti.value().unsignedValue();
404 int loopCounterStep = 1;
405 if (jumpLimitValue != tripCount_) {
406 if (jumpLimitValue == 2 * tripCount_) {
407 loopCounterStep = 2;
408 } else {
409 if (jumpLimitValue == 4 * tripCount_) {
410 loopCounterStep = 4;
411 } else {
412 // don't know how much to decr. counter.
414 return -1;
415 }
416 }
417 }
418 if (tripCount_ > jumpOverlapCount) {
419 jumpLimit->move().setSource(
421 SimValue(
422 jumpLimitValue -
423 (jumpOverlapCount * loopCounterStep),
424 ti.value().width())));
425 } else {
426 // loop limit is too short.
427 // would be always executed too many times.
428 jumpLimit->move().setSource(
429 new TTAProgram::TerminalImmediate(SimValue(jumpLimitValue)));
431 return -1;
432 }
433
434 }
435 }
437 return (ddg.largestCycle() - ddg.smallestCycle()) / rm.initiationInterval();
438}
439
440#ifdef DEBUG_REG_COPY_ADDER
441static int graphCount = 0;
442#endif
443
444/**
445 * Schedules moves in a single operation execution.
446 *
447 * Assumes the given MoveNodeGroup contains all moves in the operation
448 * execution. Also assumes that all outputs of the MoveNodeGroup have
449 * been scheduled.
450 *
451 * @param moves Moves of the operation execution.
452 */
453void
455 MoveNodeGroup& moves, BUMoveNodeSelector& selector) {
456 ProgramOperation& po =
457 (moves.node(0).isSourceOperation())?
458 (moves.node(0).sourceOperation()):
459 (moves.node(0).destinationOperation());
461 bool operandsFailed = true;
462 bool resultsFailed = true;
463 int resultsStartCycle = endCycle_;
464 int maxResult = resultsStartCycle;
465
466#ifdef DEBUG_REG_COPY_ADDER
467 ddg_->setCycleGrouping(true);
469 (boost::format("%s_before_ddg.dot") % ddg_->name()).str());
470#endif
471 RegisterCopyAdder regCopyAdder(
474 regCopyAdder.addMinimumRegisterCopies(po, *targetMachine_, ddg_);
475
476#ifdef DEBUG_REG_COPY_ADDER
477 const int tempsAdded = copies.count_;
478#endif
479 ;
480#ifdef DEBUG_REG_COPY_ADDER
481 if (tempsAdded > 0) {
483 (boost::format("%s_after_regcopy_ddg.dot") % ddg_->name()).str());
484 }
485// ddg_->sanityCheck();
486#endif
487
488 bool bypass = bypass_;
489 bool bypassLate = bypass_;
490 int ii = rm_->initiationInterval();
491 // Find smallest cycle from RM is known, otherwise 1
492 int rmSmallest = (rm_->smallestCycle() < INT_MAX) ? rm_->smallestCycle() : 1;
493 // rmSmallest is cycle where there is nothing scheduled, and nothing
494 // is scheduled before it, so it the schedule of result fails there
495 // there is no point decreasing the schedule any more.
496 int stopingPoint = (ii == 0) ?
497 rmSmallest - 1 :
498 endCycle_ - ii -1;
499 while ((operandsFailed || resultsFailed) &&
500 resultsStartCycle >= stopingPoint) {
501 maxResult = scheduleResultReads(
502 moves, resultsStartCycle, bypass, bypassLate);
503 if (maxResult != -1) {
504 resultsFailed = false;
505 } else {
506 // At least one of the results did not get scheduled correctly,
507 // We try with earlier starting cycle.
508 // Drawback, in case of 3 results, 1 could be scheduled very late,
509 // second bit earlier and third failing because of location of
510 // second scheduled result, not first.
511 // Better solution would be to try to push scheduled results up
512 // individually, but that would be rather slow process.
513 for (int i = 0; i < moves.nodeCount(); i++){
514 MoveNode& moveNode = moves.node(i);
515 if (moveNode.isScheduled() &&
516 moveNode.isSourceOperation()) {
517 unschedule(moveNode);
519 undoBypass(moveNode);
520 }
521 }
522 resultsFailed = true;
523 if (bypass && bypassLate) {
524 bypass = true;
525 bypassLate = false;
526 } else if (bypass && !bypassLate) {
527 bypass = false;
528 bypassLate = true;
529 } else if (!bypass && bypassLate) {
530 bypassLate = false;
531 } else {
532 // We will try to schedule results in earlier cycle
533 resultsStartCycle--;
534 bypass = bypass_;
535 bypassLate = bypass_;
536 }
537 continue;
538 }
539 regCopyAdder.resultsScheduled(copies, *ddg_);
540 if (scheduleOperandWrites(moves, resultsStartCycle)) {
541 operandsFailed = false;
542 } else {
543 // Scheduling some operand failed, unschedule all moves, try earlier
544 for (int i = 0;i < po.inputMoveCount(); i++) {
545 MoveNode& moveNode = po.inputMove(i);//moves.node(i);
546 if (moveNode.isScheduled()) {
547 unschedule(moveNode);
548 if (moveNode.isDestinationOperation()) {
550 }
551
552 if (moveNode.isSourceOperation()) {
554 }
555 }
556 }
557
558 for (int i = 0;i < po.outputMoveCount(); i++) {
559 MoveNode& moveNode = po.outputMove(i);//moves.node(i);
560 if (moveNode.isScheduled()) {
561 unschedule(moveNode);
562 if (moveNode.isDestinationOperation()) {
564 }
565
566 if (moveNode.isSourceOperation()) {
568 }
569 }
570 }
571
572 std::vector<MoveNode*> outputMoves;
573 for (int i = 0; i < po.outputMoveCount(); i++) {
574 outputMoves.push_back(&po.outputMove(i));
575 }
576
577 for (unsigned int i = 0; i < outputMoves.size(); i++) {
578 // then undo the bypass etc.
579 MoveNode& moveNode = *outputMoves[i]; //moves.node(i);
580 if (moveNode.isSourceOperation()) {
581 undoBypass(moveNode);
582 }
583 }
584
585 operandsFailed = true;
586 if (bypass && bypassLate) {
587 bypass = true;
588 bypassLate = false;
589 } else if (bypass && !bypassLate) {
590 bypass = false;
591 bypassLate = true;
592 } else if (!bypass && bypassLate) {
593 bypassLate = false;
594 } else {
595 resultsStartCycle--;
596 maxResult--;
597 resultsStartCycle = std::min(maxResult, resultsStartCycle);
598 bypass = bypass_;
599 bypassLate = bypass_;
600 }
601 }
602 }
603 // This fails if we reach 0 cycle.
604 if (resultsFailed) {
605 if (ii == 0) {
606 // This is only problem with regular scheduling, with loop schedule
607 // this is expected for too small II.
609 (boost::format("bb_%s_2_failed_scheduling.dot")
610 % ddg_->name()).str());
611 }
613 throw ModuleRunTimeError(
614 __FILE__, __LINE__, __func__,
615 "Results scheduling failed for \'" + moves.toString());
616 }
617
618 if (operandsFailed) {
619 if (ii == 0) {
620 // This is only problem with regular scheduling, with loop schedule
621 // this is expected for too small II.
623 (boost::format("bb_%s_2_scheduling.dot")
624 % ddg_->name()).str());
625 }
627 throw ModuleRunTimeError(
628 __FILE__, __LINE__, __func__,
629 "Operands scheduling failed for \'" + moves.toString());
630 }
631
632 for (int i = 0; i < moves.nodeCount(); i++) {
633 finalizeSchedule(moves.node(i), selector);
634 }
635 regCopyAdder.operandsScheduled(copies,*ddg_);
636#ifdef DEBUG_REG_COPY_ADDER
637 if (tempsAdded > 0) {
639 (boost::format("%s_after_scheduler_ddg.dot") %
640 ddg_->name()).str());
642 << "(operation fix #" << ddg_->name() << ")" << std::endl
643 << std::endl;
644 ++graphCount;
645 }
646
647#endif
648}
649
650/**
651 * Schedules operand moves of an operation execution.
652 *
653 * Assumes the given MoveNodeGroup contains all moves in the operation
654 * execution. Also assumes that all result moves of the MoveNodeGroup have
655 * been scheduled.
656 * Assumes bottom up scheduling.
657 *
658 * @param moves Moves of the operation execution.
659 * @param cycle latest cycle for starting scheduling of operands
660 * @return True if all operands got scheduled
661 */
662bool
664 ProgramOperation& po =
665 (moves.node(0).isSourceOperation())?
666 (moves.node(0).sourceOperation()):
667 (moves.node(0).destinationOperation());
668
669 int unscheduledMoves = 0;
670 int scheduledMoves = 0;
671 MoveNode* trigger = NULL;
672
673 for (int i = 0; i < moves.nodeCount(); i++) {
674 if (!moves.node(i).isDestinationOperation()) {
675 continue;
676 }
677 // count how many operand moves will need to be scheduled
678 unscheduledMoves++;
679 if (moves.node(i).move().destination().isTriggering()) {
680 int limit = moves.node(i).latestTriggerWriteCycle();
681 // update starting cycle based on scheduled results
682 // if necessary.
683 cycle = (limit < cycle) ? limit : cycle;
684 }
685 }
686 int counter = 0;
687
688 while (unscheduledMoves != scheduledMoves && counter < 5 && cycle >=0) {
689 // try to schedule all input moveNodes, also find trigger
690 // Try to schedule trigger first, otherwise the operand
691 // may get scheduled in cycle where trigger does not fit and
692 // later cycle will not be possible for trigger.
693 trigger = findTrigger(po, *targetMachine_);
694 if (trigger != NULL && !trigger->isScheduled()) {
695 if (scheduleOperand(*trigger, cycle) == false) {
696 cycle--;
697 counter++;
698 continue;
699 }
700 assert(trigger->isScheduled());
701 cycle = trigger->cycle();
702
703 if (trigger->move().destination().isTriggering()) {
704 // We schedulled trigger, this will give us latest possible cycle
705 // in order not to have operands later then trigger.
706 if (ddg_->hasNode(*trigger)) {
707 // handle moving fu deps.
708 // they may move trigger to later time.
710 int triggerLatest =
711 std::min(ddg_->latestCycle(*trigger,
713 cycle);
714 triggerLatest = rm_->latestCycle(triggerLatest, *trigger);
715 if (triggerLatest != INT_MAX &&
716 triggerLatest > trigger->cycle()) {
717 unschedule(*trigger);
719 if (scheduleOperand(*trigger, triggerLatest) == false) {
720 // reschedule with new dependencies failed,
721 // bringing back originaly scheduled trigger
722 scheduleOperand(*trigger, cycle);
723 }
724 assert(trigger->isScheduled());
725 cycle = trigger->cycle();
726 }
727 }
728 }
729 }
730
731 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
732 MoveNode& moveNode = moves.node(moveIndex);
733 // skip the result reads
734 if (!moveNode.isDestinationOperation()) {
735 continue;
736 }
737
738 if (moveNode.isScheduled()) {
739 continue;
740 }
741 if (scheduleOperand(moveNode, cycle) == false) {
743 break;
744 }
745
746 }
747 // Tests if all input moveNodes were scheduled, if so check if trigger
748 // is latest
749 scheduledMoves = 0;
750 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
751 MoveNode& moveNode = moves.node(moveIndex);
752 // skip the result reads
753 if (!moveNode.isDestinationOperation()) {
754 continue;
755 }
756 if (moveNode.isScheduled()) {
757 scheduledMoves++;
758 if (moveNode.cycle() > cycle) {
759 // moveNode is operand and it is scheduled after the
760 // trigger! This is wrong!
761 std::cerr << "Move " << moveNode.toString()
762 << " is scheduled after the trigger!" << std::endl;
763 scheduledMoves--;
764 }
765 }
766 }
767
768 // Some moveNodes were not scheduled
769 // unschedule all and try with higher start cycle
770 if (scheduledMoves != unscheduledMoves) {
771 for (int i = 0; i < moves.nodeCount(); i++){
772 MoveNode& moveNode = moves.node(i);
773 if (moveNode.isScheduled() &&
774 moveNode.isDestinationOperation()) {
775 unschedule(moveNode);
777 }
778 }
779 scheduledMoves = 0;
780 } else {
781 // every operand is scheduled, we can return quickly
782 return true;
783 }
784 cycle--;
785 counter++;
786 }
787 // If loop timeouts we get here
788 if (scheduledMoves != unscheduledMoves) {
789 return false;
790 }
791 return true;
792}
793
794/**
795 * Schedules the result read moves of an operation execution.
796 *
797 * Assumes the given MoveNodeGroup contains all moves in the operation
798 * execution.
799 *
800 * @param moves Moves of the operation execution.
801 * @return Last cycle in which any of the results was scheduled
802 */
803int
805 MoveNodeGroup& moves, int cycle, bool bypass, bool bypassLate) {
806 int maxResultCycle = cycle;
807 int tempRegLimitCycle = cycle;
808 int localMaximum = 0;
809 bool resultScheduled = false;
810 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
811 if (!moves.node(moveIndex).isSourceOperation()) {
812 continue;
813 }
814 MoveNode& moveNode = moves.node(moveIndex);
815 bool bypassSuccess = false;
816 if (!moveNode.isScheduled()) {
817 if (!moveNode.isSourceOperation()) {
818 throw InvalidData(
819 __FILE__, __LINE__, __func__,
820 (boost::format("Move to schedule '%s' is not "
821 "result move!") % moveNode.toString()).str());
822 }
823 if (bypass) {
824 int newMaximum = maxResultCycle + bypassDistance_;
825 bypassSuccess = bypassNode(moveNode, newMaximum);
826 localMaximum =
827 (newMaximum > localMaximum) ? newMaximum : localMaximum;
828 if (dre_ && bypassSuccess &&
829 !ddg_->resultUsed(moveNode)) {
830 // All uses of result were bypassed, result will be removed
831 // after whole operation is scheduled.
832 //tempRegLimitCycle = std::max(tempRegLimitCycle, maxResultCycle);
833 resultScheduled = true;
834 continue;
835 }
836 }
837
838 // Find out if RegCopyAdded create temporary copy for output move
839 MoveNode* test = succeedingTempMove(moveNode);
840 if (test != NULL) {
841 // Output temp move exists. Check where the original move
842 // will be writing, that is the temporary register.
843 MoveNode* firstWrite =
845 moveNode.move().destination().registerFile(),
846 moveNode.move().destination().index());
847 if (firstWrite != NULL) {
848 assert(firstWrite->isScheduled());
849 tempRegLimitCycle = firstWrite->cycle();
850 }
851 // Schedule temporary move first.
853 moveNode, moveNode, tempRegLimitCycle);
854 // If there was temporary result read scheduled, write needs
855 // to be at least one cycle earlier.
856 if (test != NULL && test->isScheduled())
857 tempRegLimitCycle = std::min(test->cycle() -1, cycle);
858 }
859 tempRegLimitCycle =
860 (localMaximum != 0)
861 ? std::min(localMaximum +1, tempRegLimitCycle)
862 : tempRegLimitCycle;
863
864 scheduleMove(moveNode, tempRegLimitCycle, true);
865 if (!moveNode.isScheduled()) {
866 // Scheduling result failed due to some of the bypassed moves
867 // will try again without bypassing anything.
868 undoBypass(moveNode);
869 return -1;
870 }
871 if (bypassLate) {
872 int newMaximum = moveNode.cycle() + bypassDistance_;
873 if (bypassNode(moveNode, newMaximum)) {
874 localMaximum =
875 (localMaximum < newMaximum) ? newMaximum : localMaximum;
876 localMaximum = (localMaximum > cycle) ? localMaximum : cycle;
877 int originalCycle = moveNode.cycle();
878 unschedule(moveNode);
879 scheduleMove(moveNode, localMaximum, true);
880 if (!moveNode.isScheduled()) {
881 scheduleMove(moveNode, originalCycle, false);
882 }
883 }
884 assert(moveNode.isScheduled());
885 }
886 resultScheduled = true;
887 // Find latest schedule result cycle
888 localMaximum =
889 (localMaximum < moveNode.cycle())
890 ? moveNode.cycle() : localMaximum;
891
892 maxResultCycle =
893 (moveNode.cycle() > maxResultCycle) ?
894 moveNode.cycle() : maxResultCycle;
895 }
896
897 }
898 return (resultScheduled) ? localMaximum : maxResultCycle;
899}
900
901/**
902 * Schedules moves in a single operation execution.
903 *
904 * Assumes the given MoveNodeGroup contains all moves in the operation
905 * execution. Also assumes that all inputs to the MoveNodeGroup have
906 * been scheduled.
907 *
908 * @param moveNode R-R Move to schedule.
909 */
910void
912#ifdef DEBUG_REG_COPY_ADDER
913 ddg_->setCycleGrouping(true);
915 (boost::format("%s_before_ddg.dot") % ddg_->name()).str());
916#endif
917
918 if (moveNode.move().source().equals(
919 moveNode.move().destination())) {
920 return;
921 }
922
923 RegisterCopyAdder regCopyAdder(
925
926#ifdef DEBUG_REG_COPY_ADDER
927 const int tempsAdded =
928#endif
929
930 regCopyAdder.addRegisterCopiesToRRMove(moveNode, ddg_)
931#ifdef DEBUG_REG_COPY_ADDER
932 .count_
933#endif
934 ;
935#ifdef DEBUG_REG_COPY_ADDER
936 if (tempsAdded > 0) {
938 (boost::format("%s_after_regcopy_ddg.dot") % ddg_->name()).str());
939 }
940// ddg_->sanityCheck();
941#endif
942 scheduleResultReadTempMoves(moveNode, moveNode, endCycle_);
943 scheduleMove(moveNode, endCycle_, true);
944}
945
946/**
947 * Schedules a single move to the earliest possible cycle, taking in
948 * account the DDG, resource constraints, and latencies in producing
949 * source values.
950 *
951 * This method assumes the move is possible to schedule with regards to
952 * connectivity and resources. Short immediates are converted to long
953 * immediates when needed.
954 *
955 * @param move The move to schedule.
956 * @param earliestCycle The earliest cycle to try.
957 */
958void
960 MoveNode& moveNode, int latestCycle, bool allowPredicationAndRenaming) {
961 if (moveNode.isScheduled()) {
962 ddg_->writeToDotFile("already_sched.dot");
963 throw InvalidData(
964 __FILE__, __LINE__, __func__,
965 (boost::format("Move '%s' is already scheduled!")
966 % moveNode.toString()).str());
967 }
968 int ii = rm_->initiationInterval();
969 int ddgCycle = endCycle_;
970 if (moveNode.move().isControlFlowMove()) {
972 if (ddg_->latestCycle(moveNode, ii) < ddgCycle) {
973 // Trying to schedule CFG move but data dependence does not
974 // allow it to schedule in correct place
975 throw InvalidData(
976 __FILE__, __LINE__, __func__,
977 (boost::format("Move '%s' needs to be scheduled in %d,"
978 " but data dependence does not allow it!")
979 % moveNode.toString() % ddgCycle).str());
980 }
981 jumpMove_ = &moveNode;
982 } else { // not a control flow move:
983 ddgCycle = ddg_->latestCycle(moveNode, ii);
984 if (renamer_ != NULL && allowPredicationAndRenaming) {
985 int latestFromTrigger =
986 (moveNode.isDestinationOperation()) ?
987 moveNode.latestTriggerWriteCycle() : latestCycle;
988 int minRenamedEC = std::min(
989 latestFromTrigger, ddg_->latestCycle(
990 moveNode, ii, true)); // TODO: 0 or INT_MAX
991
992 // rename if can and may alow scheuduling later.
993 if (minRenamedEC > ddgCycle) {
994 minRenamedEC = rm_->latestCycle(minRenamedEC, moveNode);
995 if (minRenamedEC > ddgCycle) {
997 moveNode, ii != 0, true, true, minRenamedEC)) {
998 ddgCycle = ddg_->latestCycle(moveNode, ii);
999 }
1000#ifdef THIS_IS_BUGGY_WITH_REGCOPY_ADDER
1001 else {
1002 MoveNode *limitingAdep =
1004 moveNode);
1005 if (limitingAdep != NULL) {
1006 // don't try to rename is same operation.
1007 // as it would not help at all.
1008 if (!moveNode.isDestinationOperation() ||
1009 !limitingAdep->isSourceOperation() ||
1010 &moveNode.destinationOperation() !=
1011 &limitingAdep->sourceOperation()) {
1013 *limitingAdep, false, true, true)) {
1014 ddgCycle =
1015 ddg_->latestCycle(moveNode, ii);
1016 }
1017 }
1018 }
1019 }
1020#endif
1021 }
1022 }
1023 }
1024 }
1025 // if it's a conditional move then we have to be sure that the guard
1026 // is defined before executing the move.
1027 // this is already handled by DDGs earliestCycle, except cases
1028 // where the guard is defined in a previous BB.
1029 // So this prevents scheduling unconditional moves at the beginning
1030 // of a BB.
1031
1032 if (!moveNode.move().isUnconditional()) {
1033
1034 if (allowPredicationAndRenaming) {
1035 // try to get rid of the guard if it gives earlier earliestcycle.
1036 if (ddg_->latestCycle(moveNode, ii, false, true, true)
1037 > ddgCycle) {
1038 bool guardNeeded = false;
1039 if (moveNode.move().destination().isGPR() ||
1040 moveNode.move().isControlFlowMove()) {
1041 guardNeeded = true;
1042 } else {
1043 // this would be needed only for trigger,
1044 // but trigger may change during scheduling.
1045 // so lets just limit all operands, it seems
1046 // this does not make the schedule any worse.
1047 if (moveNode.isDestinationOperation()) {
1048 const Operation& o =
1049 moveNode.destinationOperation().operation();
1050 if (o.writesMemory() || o.hasSideEffects() ||
1051 o.affectsCount() != 0) {
1052 guardNeeded = true;
1053 }
1054 }
1055 }
1056 if (!guardNeeded) {
1057 moveNode.move().setGuard(NULL);
1058 ddg_->removeIncomingGuardEdges(moveNode);
1059 ddgCycle = ddg_->latestCycle(moveNode, ii);
1060 assert(moveNode.move().isUnconditional());
1061 }
1062 }
1063
1064 if (ii == 0 && tryToOptimizeWaw(moveNode)) {
1065 ddgCycle = std::max(ddg_->latestCycle(moveNode, ii),
1066 moveNode.guardLatency()-1);
1067 }
1068
1069 }
1070 }
1071
1072 ddgCycle = (ddgCycle == INT_MAX) ? endCycle_ : ddgCycle;
1073 assert(ddgCycle != -1);
1074 // Earliest cycle from which to start, could depend on result ready
1075 // for result moves.
1076 int minCycle = std::min(latestCycle, ddgCycle);
1077 if (moveNode.isSourceConstant() &&
1078 !moveNode.move().hasAnnotations(
1080 // If source is constant and node does not have annotation already,
1081 // we add it if constant can not be transported so IU broker and
1082 // OutputPSocket brokers will add Immediate
1083 // Example : 999999 -> integer0.2
1084 if (!rm_->canTransportImmediate(moveNode)){
1087 moveNode.move().setAnnotation(annotation);
1088
1089 } else if (!moveNode.isDestinationOperation() &&
1090 rm_->latestCycle(endCycle_, moveNode) == -1 && ii == 0) {
1091 // If source is constant and node does not have annotation already,
1092 // we add it if node has no connection, so IU broker and
1093 // OutputPSocket brokers will add Immediate
1094 // Example: 27 -> integer0.2
1095 // With bus capable of transporting 27 as short immediate but
1096 // no connection from that bus to integer0 unit
1099 moveNode.move().setAnnotation(annotation);
1100 }
1101 }
1102 // annotate the return move otherwise it might get undetected in the
1103 // simulator after the short to long immediate conversion and thus
1104 // stopping simulation automatically might not work
1105 if (moveNode.isSourceConstant() &&
1106 moveNode.move().isReturn() &&
1107 !rm_->canTransportImmediate(moveNode)) {
1110 moveNode.move().setAnnotation(annotation);
1111 }
1112 int earliestDDG = ddg_->earliestCycle(moveNode, ii);
1113 minCycle = rm_->latestCycle(minCycle, moveNode);
1114 if (minCycle < earliestDDG) {
1115 // Bypassed move could get scheduld too early, this should prevent it
1116 return ;
1117 }
1118 if (minCycle == -1 || minCycle == INT_MAX) {
1119 if (moveNode.isSourceConstant() &&
1120 !moveNode.isDestinationOperation() &&
1121 moveNode.move().hasAnnotations(
1123 // If earliest cycle returns -1 and source is constant and moveNode
1124 // needs long immediate there is most likely missing long immediate
1125 // unit
1126 std::string msg = "Assignment of MoveNode " + moveNode.toString();
1127 msg += " failed! Most likely missing Long Immediate Unit";
1128 msg += " or Instruction Template!";
1129 throw IllegalMachine(
1130 __FILE__, __LINE__, __func__, msg);
1131 }
1132 return;
1133 }
1134 if (moveNode.isSourceOperation() && !moveNode.isDestinationOperation()) {
1135 ProgramOperation& po = moveNode.sourceOperation();
1136 if (po.isAnyOutputAssigned()) {
1137 // Some of the output moves are already assigned, we try to
1138 // put this as close to them as possible
1139 int localMaximum = 0;
1140 for (int i = 0; i < po.outputMoveCount(); i++) {
1141 MoveNode& temp = po.outputMove(i);
1142 if (temp.isScheduled()) {
1143 localMaximum = std::max(temp.cycle(), localMaximum);
1144 }
1145 }
1146 if (localMaximum != 0 && localMaximum < minCycle) {
1147 // Bypassed moves are earlier then this one can be scheduled
1148 // scheduling it too late won't help since operands are limited
1149 // with already scheduled result move
1150
1151 // if ddg requires move to be later then the bypassed
1152 // versions, we have to obey that
1153 localMaximum = std::max(earliestDDG, localMaximum);
1154 int rmEarliest =
1155 rm_->earliestCycle((localMaximum + minCycle)/2, moveNode);
1156 if (rmEarliest != -1 &&
1157 rmEarliest != INT_MAX &&
1158 rmEarliest < minCycle) {
1159 minCycle = rmEarliest;
1160 }
1161 }
1162 }
1163 }
1164 rm_->assign(minCycle, moveNode);
1165 if (!moveNode.isScheduled()) {
1166 throw ModuleRunTimeError(
1167 __FILE__, __LINE__, __func__,
1168 (boost::format("Assignment of MoveNode '%s' failed!")
1169 % moveNode.toString()).str());
1170 }
1171 // Find out the cycle when execution of operation actually ends.
1172 // Only use for operations that uses internal pipeline after the result read.
1173 if (moveNode.isDestinationOperation()) {
1174
1175 const Operation& op = moveNode.destinationOperation().operation();
1176 const TTAMachine::HWOperation& hwop =
1177 *moveNode.move().destination().functionUnit().operation(op.name());
1178
1179 unsigned int epEndCycle = moveNode.cycle() + hwop.latency();
1180 // The pipeline will end after current the final cycle,
1181 // have to scheduler earlier.
1182 if (epEndCycle > endCycle_ &&
1183 moveNode.destinationOperation().outputMoveCount() > 0) {
1184 rm_->unassign(moveNode);
1185 }
1186 }
1187}
1188
1189/**
1190 * A short description of the pass, usually the optimization name,
1191 * such as "basic block scheduler".
1192 *
1193 * @return The description as a string.
1194 */
1195std::string
1197 return "Bottom-up list scheduler with a basic block scope.";
1198}
1199
1200/**
1201 * Optional longer description of the pass.
1202 *
1203 * This description can include usage instructions, details of choice of
1204 * algorithmic details, etc.
1205 *
1206 * @return The description as a string.
1207 */
1208std::string
1210 return
1211 "Bottom-up list basic block scheduler that uses the longest path "
1212 "information of data dependency graph to prioritize the ready list."
1213 "Assumes that the input has registers allocated and no connectivity "
1214 "missing.";
1215}
1216/**
1217 * Schedules the (possible) temporary register copy moves (due to missing
1218 * connectivity) preceeding the given result read move.
1219 *
1220 * The function recursively goes through all the temporary moves added to
1221 * the given result move.
1222 *
1223 * @param resultMove A temp move whose predecessor has to be scheduled.
1224 * @param resultRead The original move of which temp moves to schedule.
1225 * @param firstWriteCycle Recursive function parameter.
1226 */
1227void
1229 MoveNode& resultMove, MoveNode& resultRead, int firstWriteCycle) {
1230 /* Because temporary register moves do not have WaR/WaW dependency edges
1231 between the other possible uses of the same temp register in
1232 the same operation, we have to limit the scheduling of the new
1233 temp reg move to the last use of the same temp register so
1234 we don't overwrite the temp registers of the other operands. */
1235
1236
1237 // find all unscheduled succeeding moves of the result read move
1238 // there should be only only one with the only dependence edge (RaW) to
1239 // the result move
1240
1241 MoveNode* tempMove1 = succeedingTempMove(resultMove);
1242 if (tempMove1 == NULL)
1243 return; // no temp moves found
1244
1245 MoveNode* tempMove2 = succeedingTempMove(*tempMove1);
1246 if (tempMove2 != NULL) {
1247 // Found second temp move. First temp move will write register
1248 // which second will read.
1249 MoveNode* firstWrite =
1251 tempMove1->move().destination().registerFile(),
1252 tempMove1->move().destination().index());
1253 if (firstWrite != NULL && firstWrite->isScheduled())
1254 firstWriteCycle = firstWrite->cycle();
1255 scheduleResultReadTempMoves(*tempMove1, resultRead, firstWriteCycle);
1256 if (tempMove2 != NULL && tempMove2->isScheduled()){ // TODO: maybe there is scheduled is missing
1257 firstWriteCycle = tempMove2->cycle() -1;
1258 }
1259 }
1260 bool bypassSuccess = false;
1261 if (bypass_) {
1262 int tmp = endCycle_;
1263 bypassSuccess = bypassNode(*tempMove1, tmp);
1264 }
1265 if (!bypassSuccess || !dre_ || ddg_->resultUsed(*tempMove1)) {
1266 scheduleMove(*tempMove1, firstWriteCycle, true);
1267 assert(tempMove1->isScheduled());
1268 if (bypass_) {
1269 int tmp = endCycle_;
1270 bypassSuccess = bypassNode(*tempMove1, tmp);
1271 }
1272 scheduledTempMoves_[&resultRead].insert(tempMove1);
1273 } else if (dre_ && !ddg_->resultUsed(*tempMove1)) {
1274 finalizeSchedule(*tempMove1, dynamic_cast<BUMoveNodeSelector&>(*selector_));
1275 }
1276}
1277
1278/**
1279 * Schedules the (possible) temporary register copy moves (due to missing
1280 * connectivity) preceeding the given input move.
1281 *
1282 * The function recursively goes through all the temporary moves added to
1283 * the given input move.
1284 *
1285 * @param operandMove A temp move whose predecessor has to be scheduled.
1286 * @param operandWrite The original move of which temp moves to schedule.
1287 */
1288void
1290 MoveNode& operandMove, MoveNode& operandWrite) {
1291 /* Because temporary register moves do not have WaR dependency edges
1292 between the other possible uses of the same temp register in
1293 the same operation, we have to limit the scheduling of the new
1294 temp reg move to the last use of the same temp register so
1295 we don't overwrite the temp registers of other operands. */
1296 int lastUse = endCycle_;
1297
1298 // find all unscheduled preceeding temp moves of the operand move
1299 DataDependenceGraph::EdgeSet inEdges = ddg_->inEdges(operandMove);
1300 MoveNode* tempMove = NULL;
1301 for (DataDependenceGraph::EdgeSet::iterator i = inEdges.begin();
1302 i != inEdges.end(); ++i) {
1303
1304 if ((**i).edgeReason() != DataDependenceEdge::EDGE_REGISTER ||
1305 (**i).guardUse() ||
1306 (**i).dependenceType() != DataDependenceEdge::DEP_RAW) {
1307 continue;
1308 }
1309
1310 MoveNode& m = ddg_->tailNode(**i);
1311 if (m.isScheduled() ||
1312 !m.move().hasAnnotations(
1314 continue;
1315 }
1316
1317 assert(tempMove == NULL &&
1318 "Multiple unscheduled moves for the operand move, should have "
1319 "max. one (the temporary move)!");
1320 tempMove = &m;
1321 // First cycle where temporary register will be read, this should
1322 // be actuall operand move cycle!
1323 MoveNode* firstRead =
1325 tempMove->move().destination().registerFile(),
1326 tempMove->move().destination().index());
1327 if (firstRead != NULL) {
1328 assert(firstRead->isScheduled());
1329 lastUse = firstRead->cycle();
1330 if (operandMove.isScheduled() && lastUse != operandMove.cycle()) {
1331 Application::logStream() << "\tFirst register read problem "
1332 << operandMove.toString() << " temp " << firstRead->toString()
1333 << std::endl;
1334 }
1335 }
1336 }
1337
1338 if (tempMove == NULL)
1339 return; // no temp moves found
1340
1341 scheduleMove(*tempMove, lastUse - 1, true);
1342 if (!tempMove->isScheduled()) {
1343 std::cerr << "temp move: " << tempMove->toString()
1344 << "not scheduled."
1345 << std::endl;
1346 ddg_->writeToDotFile("failTempNotSched.dot");
1347 }
1348 assert(tempMove->isScheduled());
1349 scheduledTempMoves_[&operandWrite].insert(tempMove);
1350 scheduleInputOperandTempMoves(*tempMove, operandWrite);
1351}
1352/**
1353 * Schedules the (possible) temporary register copy moves (due to missing
1354 * connectivity) succeeding the given RR move.
1355 *
1356 * The function recursively goes through all the temporary moves added to
1357 * the given RR move.
1358 *
1359 * @param regToRegMove A temp move whose successor has to be scheduled.
1360 * @param firstMove The original move of which temp moves to schedule.
1361 * @param lastUse Recursive function parameter, it should be set as 0
1362 * for the first function call.
1363 */
1364void
1366 MoveNode& regToRegMove, MoveNode& firstMove, int lastUse) {
1367 /* Because temporary register moves do not have WaR/WaW dependency edges
1368 between the other possible uses of the same temp register in
1369 the same operation, we have to limit the scheduling of the new
1370 temp reg move to the last use of the same temp register so
1371 we don't overwrite the temp registers of the other operands. */
1372
1373 // find all unscheduled succeeding moves of the result read move
1374 // there should be only only one with the only dependence edge (RaW) to
1375 // the result move
1376
1377 MoveNode* tempMove1 = succeedingTempMove(regToRegMove);
1378 if (tempMove1 == NULL)
1379 return; // no temp moves found
1380
1381 MoveNode* tempMove2 = succeedingTempMove(*tempMove1);
1382 if (tempMove2 != NULL) {
1383 MoveNode* firstWrite =
1385 tempMove1->move().destination().registerFile(),
1386 tempMove1->move().destination().index());
1387 if (firstWrite != NULL) {
1388 assert(firstWrite->isScheduled());
1389 lastUse = firstWrite->cycle();
1390 }
1391 }
1392 scheduleResultReadTempMoves(*tempMove1, firstMove, lastUse);
1393 bool bypassSuccess = false;
1394 if (bypass_) {
1395 int tmp = endCycle_;
1396 bypassSuccess = bypassNode(*tempMove1, tmp);
1397 }
1398 if (!bypassSuccess || !dre_ || ddg_->resultUsed(*tempMove1)) {
1399 scheduleMove(*tempMove1, lastUse - 1, true);
1400 if (!tempMove1->isScheduled()) {
1401 std::cerr << "not scheduled: " << tempMove1->toString() << std::endl;
1402 ddg_->writeToDotFile("tempNotSched.dot");
1403 }
1404 if (bypass_) {
1405 int tmp = endCycle_;
1406 bypassSuccess = bypassNode(*tempMove1, tmp);
1407 }
1408 assert(tempMove1->isScheduled());
1409 scheduledTempMoves_[&firstMove].insert(tempMove1);
1410 } else if (dre_ && !ddg_->resultUsed(*tempMove1)) {
1411 finalizeSchedule(*tempMove1, dynamic_cast<BUMoveNodeSelector&>(*selector_));
1412 }
1413}
1414
1415/**
1416 * Finds the temp move preceding the given movenode.
1417 *
1418 * If it does not have one, returns null.
1419 *
1420 * @param current MoveNode whose tempmoves we are searching
1421 * @return tempMove preceding given node, or null if does not exist.
1422 */
1423MoveNode*
1425
1427 MoveNode* result = NULL;
1428 for (DataDependenceGraph::NodeSet::iterator i = pred.begin();
1429 i != pred.end(); ++i) {
1430 MoveNode& m = **i;
1431 if (m.isScheduled() ||
1432 !m.move().hasAnnotations(
1434 continue;
1435
1436 assert(result == NULL &&
1437 "Multiple candidates for the temp move of result read.");
1438 result = &m;
1439 }
1440 return result;
1441}
1442
1443/**
1444 * Checks existence of temporary moves and schedules operand according
1445 * to discovered dependencies.
1446 */
1447bool
1449 int tempRegLimitCycle = cycle;
1450 // Find out if RegCopyAdded create temporary move for input.
1451 // If so, the operand has to be scheduled before the other use
1452 // of same temporary register.
1453 MoveNode* test = precedingTempMove(node);
1454 if (test != NULL) {
1455 // Input temp move exists. Check where the move is reading data
1456 // from, so operand move can be scheduled earlier then
1457 // the already scheduled overwriting cycle.
1458 MoveNode* firstWrite =
1460 node.move().source().registerFile(),
1461 node.move().source().index());
1462 if (firstWrite != NULL) {
1463 assert(firstWrite->isScheduled());
1464 tempRegLimitCycle = firstWrite->cycle();
1465 }
1466 }
1467 cycle = std::min(cycle, tempRegLimitCycle);
1468 // This must pass, since we got latest cycle from RM.
1469 scheduleMove(node, cycle, true);
1470 if (node.isScheduled() == false) {
1471 // the latest cycle may change because scheduleMove may do things like
1472 // register renaming, so this may fail.
1473 return false;
1474 }
1476 return true;
1477}
1478
1479/**
1480 * Finds a destination where to bypass.
1481 *
1482 * Goes through ddg and checks for connectivity.
1483 *
1484 * @return pair of destination of bypass and amount of regs skipped by the bypass.
1485 */
1488
1489 OrderedSet okDestination;
1490 // DDG can only handle single hops so far.
1491 // TODO: Fix when DDG could handle multiple destinations
1492 DataDependenceGraph::NodeSet rrDestinations =
1493 ddg_->onlyRegisterRawDestinations(node, false, false);
1494 for (DataDependenceGraph::NodeSet::iterator j =
1495 rrDestinations.begin(); j != rrDestinations.end(); j++) {
1496 MoveNode* n = *j;
1497 if (ddg_->onlyRegisterRawSource(*n) == NULL) {
1498 // No bypassing of moves with multiple register definition
1499 // sources.
1500 // TODO: bypass destination with multiple definition sources
1501 // using inverse guard of guarded source.
1502 continue;
1503 }
1504 MachineConnectivityCheck::PortSet destinationPorts;
1505 destinationPorts.insert(&n->move().destination().port());
1506
1508 node, destinationPorts)) {
1509 if (n->isScheduled() == false
1510 && rm_->initiationInterval() != 0) {
1511 // Found node connected by loop edge, ignore it.
1512 ddg_->writeToDotFile("failing_test.dot");
1513 continue;
1514 }
1515 okDestination.insert(n);
1516 }
1517 destinationPorts.clear();
1518 }
1519 return okDestination;
1520}
1521
1522/**
1523 * Remove all the bypasses of result write in moveNode and restore and schedule
1524 * original moves.
1525 */
1526void
1528 MoveNode& moveNode, MoveNode* single, int oCycle) {
1529
1530 if (single == NULL) {
1532 std::vector<MoveNode*> destinationsVector =
1533 bypassDestinations_[&moveNode];
1534 std::vector<std::pair<MoveNode*, int> > rescheduleVector;
1535
1536 for (unsigned int j = 0; j < destinationsVector.size(); j++) {
1537 // unschedule and unmerge all bypassed nodes
1538 MoveNode* dest = destinationsVector[j];
1539 if (dest->isScheduled()) {
1540 unschedule(*dest);
1541 }
1542 ddg_->unMergeUser(moveNode, *dest);
1543 int originalCycle =
1544 bypassDestinationsCycle_[&moveNode][j];
1545 const TTAMachine::Bus* bus =
1546 bypassDestinationsBus_[&moveNode][j];
1547 dest->move().setBus(*bus);
1548 rescheduleVector.push_back(
1549 std::pair<MoveNode*, int>(dest, originalCycle));
1550 droppedNodes_.erase(dest);
1551 }
1552 for (unsigned int i = 0; i < rescheduleVector.size(); i++) {
1553 // reassign nodes to their original places
1554 std::pair<MoveNode*, int> dest = rescheduleVector[i];
1555 //rm_->assign(dest.second, *dest.first);
1556 scheduleMove(*dest.first, dest.second, false);
1557 if (!dest.first->isScheduled()) {
1558 ddg_->writeToDotFile("unbypassFailed.dot");
1559 std::cerr << " Source: " << moveNode.toString()
1560 << ", Original: " << dest.first->toString() <<
1561 ", original cycle: " << dest.second << std::endl<< std::endl;
1562 }
1563 assert(dest.first->isScheduled());
1564 }
1565 bypassDestinations_.erase(&moveNode);
1566 bypassDestinationsCycle_.erase(&moveNode);
1567 bypassDestinationsBus_.erase(&moveNode);
1568 }
1569 } else {
1570 if (single->isScheduled()) {
1571 // Bypassed node could get scheduled too early, in such a case
1572 // this move need to be unscheduled.
1573 unschedule(*single);
1574 }
1575 int size = bypassDestinationsBus_[&moveNode].size();
1576 const TTAMachine::Bus* bus =
1577 bypassDestinationsBus_[&moveNode][size-1];
1578 ddg_->unMergeUser(moveNode, *single);
1579 single->move().setBus(*bus);
1580 //rm_->assign(oCycle, *single);
1581 scheduleMove(*single, oCycle, false);
1582 if (!single->isScheduled()) {
1583 ddg_->writeToDotFile("unbypassFailed.dot");
1584 std::cerr << " Source: " << moveNode.toString()
1585 << ", Original: " << single->toString() << ", original cycle: "
1586 << oCycle << std::endl;
1587 }
1588 droppedNodes_.erase(single);
1589 assert(single->isScheduled());
1590 }
1591}
1592
1593/**
1594 * Tries to bypass node with all of it's successors.
1595 *
1596 * @param moveNode, node which is tried to bypass
1597 * @param maxResultCycle, cycle of latest of rescheduled nodes
1598 * @return True if all of the successors were successfully bypassed
1599 */
1600bool
1602 MoveNode& moveNode,
1603 int& maxResultCycle) {
1604 bool edgesCopied = false;
1605 unsigned int bypassCount = 0;
1606 int localMaximum = 0;
1607 if (!bypass_)
1608 return false;
1609 // First try to bypass all uses of the result
1610 unsigned int rawDestinations =
1611 ddg_->onlyRegisterRawDestinations(moveNode, false, false).size();
1612 OrderedSet destinations =
1613 findBypassDestinations(moveNode);
1614 if (destinations.size() > 0) {
1615 for (OrderedSet::iterator it = destinations.begin();
1616 it != destinations.end(); it++) {
1617 if (!ddg_->guardsAllowBypass(moveNode, **it)) {
1618 continue;
1619 }
1620 MoveNode* temp = succeedingTempMove(moveNode);
1621 if (!(*it)->isScheduled() && temp == (*it)) {
1622 // skip temp moves if unscheduled.
1623 // The temp moves of reading operand could be
1624 // scheduled and bypass will try to skip those
1625 // but temp moves of result are there for reason
1626 // so bypass would only revert to original
1627 // status which is unschedulable.
1628 std::cerr << "\t\tSkipping temporary outgoing move " <<
1629 (*it)->toString() << std::endl;
1630 continue;
1631 }
1632 assert((*it)->isScheduled());
1633 int originalCycle = (*it)->cycle();
1634 int latestLimit = originalCycle + bypassDistance_;
1635 int earliestLimit = originalCycle - bypassDistance_;
1636 if ((*it)->isDestinationVariable() && temp == (*it)) {
1637 // If bypassing to temporary register
1638 // missing edges in DDG could cause
1639 // overwrite of temporary value before it is
1640 // consumed.
1641 // Find previous and following reads from temp
1642 // register around location of original temp write.
1643 MoveNode* lastRead =
1645 (*it)->move().destination().registerFile(),
1646 (*it)->move().destination().index(),
1647 originalCycle);
1648 if (lastRead != NULL) {
1649 assert(lastRead->isScheduled());
1650 earliestLimit = lastRead->cycle();
1651 }
1652 MoveNode *firstRead =
1654 (*it)->move().destination().registerFile(),
1655 (*it)->move().destination().index(),
1656 originalCycle);
1657 if (firstRead != NULL) {
1658 assert(firstRead->isScheduled());
1659 latestLimit = firstRead->cycle();
1660 }
1661 }
1662
1663#ifdef DEBUG_BYPASS
1664 ddg_->writeToDotFile("beforeUnschedule.dot");
1665#endif
1666 const TTAMachine::Bus* bus = &(*it)->move().bus();
1667 bypassDestinationsBus_[&moveNode].push_back(
1668 dynamic_cast<const TTAMachine::Bus*>(bus));
1669 unschedule(**it);
1670 if (!ddg_->mergeAndKeepUser(moveNode, **it)) {
1671 assert(!(*it)->isScheduled());
1672 scheduleMove(**it, originalCycle, true);
1673#ifdef DEBUG_BYPASS
1674 std::cerr << "Merge fail. moveNode=" << moveNode.toString()
1675 << ", **it=" << (*it)->toString() << std::endl;
1676#endif
1677 bypassDestinationsBus_[&moveNode].pop_back();
1678 continue;
1679 }
1680
1681 if ((**it).move().source().isImmediateRegister()) {
1682 (**it).move().setSource(
1683 static_cast<SimpleResourceManager*>(rm_)->immediateValue(moveNode)->copy());
1684 }
1685
1686 bypassDestinations_[&moveNode].push_back(*it);
1687 bypassDestinationsCycle_[&moveNode].push_back(
1688 originalCycle);
1689 assert((*it)->isScheduled() == false);
1690 int startCycle = std::min(latestLimit, maxResultCycle);
1691 scheduleMove(**it, startCycle, true);
1692
1693#ifdef DEBUG_BYPASS
1694 std::cerr << "\t\t\tCreated " << (*it)->toString()
1695 << " with original cycle " << originalCycle << std::endl;
1696#endif
1697 if (!(*it)->isScheduled() ||
1698 (*it)->cycle() > latestLimit ||
1699 (*it)->cycle() < earliestLimit ||
1700 (*it)->cycle() < originalCycle) {
1701 // Scheduling bypass failed, undo and try to
1702 // schedule other possible bypasses.
1703 undoBypass(moveNode, *it, originalCycle);
1704 bypassDestinations_[&moveNode].pop_back();
1705 bypassDestinationsCycle_[&moveNode].pop_back();
1706 bypassDestinationsBus_[&moveNode].pop_back();
1707 } else {
1708 localMaximum =
1709 ((*it)->cycle() > localMaximum) ?
1710 (*it)->cycle() : localMaximum;
1711 if (!edgesCopied) {
1712 // In case operands reads same register that
1713 // result writes, removing result move after
1714 // successfull bypass could lead to operand
1715 // scheduled after the register it reads is
1716 // overwriten. This should prevent such situation.
1717 ddg_->copyDepsOver(moveNode, true, true);
1718 edgesCopied = true;
1719 }
1720 bypassCount++;
1721 }
1722 }
1723 } else {
1724 DataDependenceGraph::NodeSet rrDestinations =
1725 ddg_->onlyRegisterRawDestinations(moveNode, false, false);
1726 if (rrDestinations.size() == 0 &&
1727 moveNode.isDestinationVariable() &&
1728 moveNode.isSourceVariable() &&
1729 !ddg_->resultUsed(moveNode)) {
1730 // move is not used at all anywhere? Lets try to drop it
1731 return true;
1732 }
1733 }
1734 if (bypassCount == rawDestinations && bypassCount != 0) {
1735 maxResultCycle = localMaximum;
1736 return true;
1737 } else {
1738 return false;
1739 }
1740}
1741
1742void
1744 MoveNode& node, BUMoveNodeSelector& selector) {
1745 if (node.isScheduled()) {
1746 selector.notifyScheduled(node);
1747 std::map<const MoveNode*, DataDependenceGraph::NodeSet >::
1748 iterator tmIter = scheduledTempMoves_.find(&node);
1749 if (tmIter != scheduledTempMoves_.end()) {
1750 DataDependenceGraph::NodeSet& tempMoves = tmIter->second;
1751 for (DataDependenceGraph::NodeSet::iterator i =
1752 tempMoves.begin(); i != tempMoves.end(); i++) {
1753 selector.notifyScheduled(**i);
1754 }
1755 }
1756 } else if (MapTools::containsKey(bypassDestinations_, &node) && dre_) {
1757
1758#ifdef DEBUG_BYPASS
1759 std::cerr << "\tDroping node " << node.toString() << std::endl;
1760 ddg_->writeToDotFile("before_copyDeps.dot");
1761#endif
1762 static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
1763 copyDepsOver(node, true, true);
1765 ddg_->dropNode(node);
1766 droppedNodes_.insert(&node);
1767#ifdef DEBUG_BYPASS
1768 ddg_->writeToDotFile("after_dropNode.dot");
1769#endif
1770
1771 for (DataDependenceGraph::NodeSet::iterator i =
1772 preds.begin(); i != preds.end(); i++) {
1773 selector.mightBeReady(**i);
1774 }
1775 std::map<const MoveNode*, DataDependenceGraph::NodeSet >::
1776 iterator tmIter = scheduledTempMoves_.find(&node);
1777 if (tmIter != scheduledTempMoves_.end()) {
1778 DataDependenceGraph::NodeSet& tempMoves = tmIter->second;
1779 for (DataDependenceGraph::NodeSet::iterator i =
1780 tempMoves.begin(); i != tempMoves.end(); i++) {
1781 if ((*i)->isScheduled()) {
1782 selector.notifyScheduled(**i);
1783 } else {
1784#ifdef DEBUG_BYPASS
1785 std::cerr << "\tDroping temp move for node "
1786 << node.toString() << ", " << (*i)->toString()
1787 << std::endl;
1788 ddg_->writeToDotFile("before_temp_copyDeps.dot");
1789#endif
1790 static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
1791 copyDepsOver(**i, true, true);
1792 ddg_->dropNode(**i);
1793 droppedNodes_.insert(*i);
1794#ifdef DEBUG_BYPASS
1795 ddg_->writeToDotFile("after_temp_dropNode.dot");
1796#endif
1797 }
1798 }
1799 }
1800 } else if (node.move().source().equals(node.move().destination()) ||
1801 (node.isSourceVariable()
1802 && node.isDestinationVariable()
1803 && !ddg_->resultUsed(node))) {
1804
1805 // we lost edges so our notifyScheduled does not notify
1806 // some antidependencies. store them for notification.
1807
1808 DataDependenceGraph::NodeSet predecessors =
1809 ddg_->predecessors(node);
1810 predecessors.erase(&node); // if WaW to itself, rremove it.
1811
1812 assert(node.isScheduled() == false);
1813
1814 // this may lead to extra raw edges.
1815 static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
1816 copyDepsOver(node, true, true);
1817
1818 ddg_->dropNode(node);
1819 droppedNodes_.insert(&node);
1820 // we lost edges so our notifyScheduled does not notify
1821 // some antidependencies. notify them.
1822 for (DataDependenceGraph::NodeSet::iterator iter =
1823 predecessors.begin();
1824 iter != predecessors.end(); iter++) {
1825 selector.mightBeReady(**iter);
1826 }
1827
1828 } else {
1829 TCEString msg = "Node " + node.toString() + " did not get scheduled";
1830 ddg_->writeToDotFile("after_dropNode.dot");
1831 throw InvalidData(
1832 __FILE__, __LINE__, __func__, msg);
1833 }
1834}
1835/**
1836 * Calls unschedule() for all ddg nodes, which were scheduled and remove possible
1837 * bypasses.
1838 */
1839void
1842
1843 for (DataDependenceGraph::NodeSet::iterator i = scheduled.begin();
1844 i != scheduled.end(); ++i) {
1845 MoveNode& moveNode = **i;
1846 if (moveNode.isScheduled()) {
1847 unschedule(moveNode);
1848 i = scheduled.begin();
1849 }
1850 }
1851 std::map<MoveNode*, std::vector<MoveNode*>, MoveNode::Comparator>::iterator it =
1852 bypassDestinations_.begin();
1853 for (; it != bypassDestinations_.end(); it++) {
1854 std::vector<MoveNode*> destinationsVector = (*it).second;
1855 for (unsigned int k = 0; k < destinationsVector.size(); k++) {
1856 // unschedule and unmerge all bypassed nodes
1857 MoveNode* dest = destinationsVector[k];
1858 ddg_->unMergeUser(*(*it).first, *dest);
1859 }
1860 }
1862 bypassDestinationsBus_.clear();
1863 bypassDestinations_.clear();
1864 droppedNodes_.clear();
1866}
1867
1868/**
1869 * Finaly, remove moves that were dropped during dead result move elimination
1870 * also from the parent of the given subgraph DDG.
1871 */
1872void
1874
1875 for (std::set<MoveNode*>::iterator i = droppedNodes_.begin();
1876 i != droppedNodes_.end(); i++) {
1877 MoveNode& node = **i;
1878 if (ddg_->rootGraph() != ddg_ && !node.isScheduled()) {
1879 ddg_->rootGraph()->removeNode(node);
1881 bypassDestinations_.erase(&node);
1882 bypassDestinationsCycle_.erase(&node);
1883 bypassDestinationsBus_.erase(&node);
1884 }
1885 }
1886 }
1887 droppedNodes_.clear();
1888}
1889/**
1890 * If the operation is commutative, tries to change the operands so that
1891 * the scheduler can schedule it better.
1892 *
1893 * If the operation is not commutative, does nothing.
1894 *
1895 * Which is better depends lots on the code being compiled and architecture
1896 * which we are compiling for.
1897 *
1898 * Current implementation tries to make constants triggers,
1899 * and if there are no constant inputs, try to also change inputs so
1900 * that last ready operand becomes trigger if it's near,
1901 * but first ready operand becomes trigger if it's further
1902 * (allows better bypassing of other operands)
1903 * This seems to work in practice
1904 *
1905 * @param po programoperation whose inputs to switch
1906 * @return true if changed inputs, false if not.
1907 */
1908bool
1910
1911 const Operation& op = po.operation();
1912 if (op.numberOfInputs() == 2 && op.canSwap(1, 2)) {
1913
1914 int triggerOperand = getTriggerOperand(op, *targetMachine_);
1915
1916 if (triggerOperand != 0) {
1917 MoveNode* latest = NULL;
1918 int latestMinCycle = -1;
1919 int firstMinCycle = INT_MAX;
1920
1921 //check all input moves.
1922 for (int i = 0; i < po.inputMoveCount(); i++) {
1923 MoveNode& node = po.inputMove(i);
1924 // always make constants triggers.
1925 // todo: shoudl do this only with short imms?
1926 if (node.isSourceConstant()) {
1927 int operandIndex =
1928 node.move().destination().operationIndex();
1929 if (operandIndex != triggerOperand) {
1930 po.switchInputs();
1931 return true;
1932 } else {
1933 return false;
1934 }
1935 }
1936
1937 int minCycle = ddg_->latestCycle(
1938 node, rm_->initiationInterval(), false, true, true, true, true);
1939 if (minCycle > latestMinCycle) {
1940 latest = &node;
1941 latestMinCycle = minCycle;
1942 }
1943 if (minCycle < firstMinCycle) {
1944 firstMinCycle = minCycle;
1945 }
1946 }
1947
1948 int lastOperand = latest->move().destination().operationIndex();
1949
1950 // don't change if min cycles of first and last are equal.
1951 if (latestMinCycle == firstMinCycle) {
1952 return false;
1953 }
1954 if (latestMinCycle - firstMinCycle > 1) { // reverse logic if far.
1955 if (lastOperand == triggerOperand) {
1956 po.switchInputs();
1957 return true;
1958 }
1959 } else {
1960 if (lastOperand != triggerOperand) {
1961 po.switchInputs();
1962 return true;
1963 }
1964 }
1965 }
1966 }
1967 return false;
1968}
1969
1970/**
1971 * Tries to get rid of WaW dependence from unconditional to conditional.
1972 *
1973 * if the conditional move's result is overwritten by the cond for
1974 * all users, make the unconditional move conditional, with opposite guard.
1975 */
1976bool
1978
1979 if (ddg_->latestCycle(moveNode, endCycle_ , false, true, true) >=
1980 ddg_->latestCycle(moveNode)) {
1981 return false;
1982 }
1983
1984 MoveNode* wawPred = NULL;
1985 DataDependenceEdge* wawEdge = NULL;
1986
1987 DataDependenceGraph::EdgeSet inEdges = ddg_->inEdges(moveNode);
1988 for (DataDependenceGraph::EdgeSet::iterator i = inEdges.begin();
1989 i != inEdges.end(); i++) {
1990 DataDependenceEdge* e = *i;
1991
1994 !e->tailPseudo()) {
1995 if (wawPred == NULL) {
1996 wawPred = &ddg_->tailNode(**i);
1997 wawEdge = e;
1998 } else {
1999 return false;
2000 }
2001 }
2002 }
2003 if (wawPred == NULL) {
2004 return false;
2005 }
2006
2007 if (!wawPred->move().isUnconditional()) {
2008 return false;
2009 }
2010
2011 // check that no other usage of the data.
2012 DataDependenceGraph::NodeSet consumers = ddg_->regRawSuccessors(*wawPred);
2013 DataDependenceGraph::NodeSet consumers2 = ddg_->regRawSuccessors(moveNode);
2014 for (DataDependenceGraph::NodeSet::iterator i = consumers.begin();
2015 i != consumers.end(); i++) {
2016 MoveNode* mn = *i;
2017 if (consumers2.find(mn) == consumers2.end() &&
2018 (mn->move().isUnconditional() ||
2019 !ddg_->exclusingGuards(*mn, moveNode))) {
2020 return false;
2021 }
2022 }
2023 if (wawPred->isScheduled())
2024 unschedule(*wawPred);
2025
2027 wawPred->move().setGuard(cg.createInverseGuard(moveNode.move().guard()));
2028
2029 ddg_->copyDepsOver(*wawPred, true, false);
2030
2031 ddg_->copyIncomingGuardEdges(moveNode, *wawPred);
2032 ddg_->copyOutgoingGuardWarEdges(moveNode, *wawPred);
2033
2034 ddg_->removeEdge(*wawEdge);
2035
2036 scheduleMove(*wawPred, endCycle_, false);
2037 bool revert = false;
2038
2039 if (!wawPred->isScheduled()) {
2040 revert = true;
2041 }
2042 if (revert) {
2043 wawPred->move().setGuard(NULL);
2044 ddg_->removeIncomingGuardEdges(*wawPred);
2046 ddg_->connectNodes(*wawPred, moveNode, *wawEdge);
2047 return false;
2048 }
2049
2050 return true;
2051}
#define debugLog(text)
#define __func__
#define abortWithError(message)
#define assert(condition)
static CmdLineOptions * cmdLineOptions()
static std::ostream & logStream()
void scheduleRRMove(MoveNode &moveNode)
std::map< MoveNode *, std::vector< int >, MoveNode::Comparator > bypassDestinationsCycle_
void scheduleOperation(MoveNodeGroup &moves, BUMoveNodeSelector &selector)
bool scheduleOperandWrites(MoveNodeGroup &moves, int cycle)
bool tryToSwitchInputs(ProgramOperation &op)
bool scheduleOperand(MoveNode &, int cycle)
bool tryToOptimizeWaw(const MoveNode &moveNode)
virtual int handleLoopDDG(DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine, int tripCount, SimpleResourceManager *prologRM=NULL, bool testOnly=false)
bool bypassNode(MoveNode &node, int &maxResultCycle)
virtual std::string longDescription() const
void undoBypass(MoveNode &node, MoveNode *single=NULL, int originalCycle=-1)
MoveNode * precedingTempMove(MoveNode &current)
void scheduleMove(MoveNode &move, int cycle, bool allowPredicationandRenaming)
void finalizeSchedule(MoveNode &node, BUMoveNodeSelector &selector)
std::set< MoveNode *, ltstr > OrderedSet
std::set< MoveNode * > droppedNodes_
OrderedSet findBypassDestinations(MoveNode &node)
std::map< MoveNode *, std::vector< const TTAMachine::Bus * >, MoveNode::Comparator > bypassDestinationsBus_
virtual int handleDDG(DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine, int minCycle=0, bool testOnly=false)
virtual std::string shortDescription() const
void scheduleResultReadTempMoves(MoveNode &resultMove, MoveNode &resultRead, int lastUse)
void scheduleInputOperandTempMoves(MoveNode &resultMove, MoveNode &resultRead)
std::map< MoveNode *, std::vector< MoveNode * >, MoveNode::Comparator > bypassDestinations_
int scheduleResultReads(MoveNodeGroup &moves, int cycle, bool bypass=false, bool bypassLate=false)
BUBasicBlockScheduler(InterPassData &data, SoftwareBypasser *bypasser=NULL, RegisterRenamer *registerRenamer=NULL)
void scheduleRRTempMoves(MoveNode &regToRegMove, MoveNode &firstMove, int lastUse)
virtual MoveNodeGroup candidates()
virtual void notifyScheduled(MoveNode &node)
virtual void mightBeReady(MoveNode &node)
MoveNodeSelector * selector_
void unscheduleInputOperandTempMoves(MoveNode &operandMove)
SimpleResourceManager * rm_
Resource Manager of the currently scheduled BB.
static MoveNode * findTrigger(const ProgramOperation &po, const TTAMachine::Machine &mach)
void unscheduleResultReadTempMoves(MoveNode &resultMove)
const TTAMachine::Machine * targetMachine_
The target machine we are scheduling the program against.
DataDependenceGraph * ddg_
DDG of the currently scheduled BB.
std::map< const MoveNode *, DataDependenceGraph::NodeSet > scheduledTempMoves_
Stores the MoveNodes that were scheduled as temp moves during scheduling of the operand move.
int getTriggerOperand(const Operation &operation, const TTAMachine::Machine &machine)
LLVMTCECmdLineOptions * options_
int minCycle_
The earliest cycle to schedule moves in. Used to leave room for sched_yield() by the sched_yield() em...
void notifyScheduled(MoveNodeGroup &moves, MoveNodeSelector &selector)
void unschedule(MoveNode &moveNode)
MoveNode * succeedingTempMove(MoveNode &current)
RegisterRenamer * renamer_
void ddgSnapshot(DataDependenceGraph &ddg, const std::string &name, DataDependenceGraph::DumpFileFormat format, bool final, bool resetCounter=false) const
BoostGraph * rootGraph()
virtual void removeEdge(Edge &e)
int nodeCount() const
virtual void removeNode(Node &node)
Node & node(const int index) const
bool hasNode(const Node &) const
virtual void dropNode(Node &node)
virtual const TCEString & name() const
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
virtual Node & tailNode(const Edge &edge) const
virtual EdgeSet inEdges(const Node &node) const
virtual void connectNodes(const Node &nTail, const Node &nHead, Edge &e)
static std::string toString(const T &source)
DependenceType dependenceType() const
EdgeReason edgeReason() const
MoveNode * firstScheduledRegisterWrite(const TTAMachine::BaseRegisterFile &rf, int registerIndex) const
int latestCycle(const MoveNode &moveNode, unsigned int ii=UINT_MAX, bool ignoreRegAntideps=false, bool ignoreUnscheduledSuccessors=true, bool ignoreGuards=false, bool ignoreFUDeps=false, bool ignoreSameOperationEdges=false) const
NodeSet regRawSuccessors(const MoveNode &node) const
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, bool assumeBypassing=false) const
void copyOutgoingGuardWarEdges(const MoveNode &src, MoveNode &dst)
void unMergeUser(MoveNode &resultNode, MoveNode &mergedNode, bool loopBypass=false)
void moveFUDependenciesToTrigger(MoveNode &trigger)
bool mergeAndKeepUser(MoveNode &resultNode, MoveNode &userNode, bool force=false)
bool exclusingGuards(const MoveNode &mn1, const MoveNode &mn2) const
NodeSet onlyRegisterRawDestinations(const MoveNode &mn, bool allowGuardEdges=false, bool allowBackEdges=false) const
MoveNode * lastScheduledRegisterRead(const TTAMachine::BaseRegisterFile &rf, int registerIndex, int lastCycleToTest=INT_MAX) const
void copyIncomingGuardEdges(const MoveNode &src, MoveNode &dst)
MoveNode * onlyRegisterRawSource(const MoveNode &mn, int allowGuardEdges=2, int backEdges=0) const
std::pair< MoveNode *, MoveNode * > findLoopLimitAndIndex(MoveNode &jumpMove)
bool resultUsed(MoveNode &resultNode)
virtual void setCycleGrouping(bool flag)
void removeOutgoingGuardWarEdges(MoveNode &node)
EdgeSet copyDepsOver(MoveNode &node, bool anti, bool raw)
MoveNode * firstScheduledRegisterRead(const TTAMachine::BaseRegisterFile &rf, int registerIndex, int firstCycleToTest=0) const
void removeIncomingGuardEdges(MoveNode &node)
bool guardsAllowBypass(const MoveNode &defNode, const MoveNode &useNode, bool loopBypass=false)
MoveNode * findLimitingAntidependenceDestination(MoveNode &mn)
virtual void writeToDotFile(const TCEString &fileName) const
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
std::set< GraphEdge *, typename GraphEdge::Comparator > EdgeSet
Definition Graph.hh:54
virtual bool dumpDDGsDot() const
virtual bool dumpDDGsXML() const
static int canSourceWriteToAnyDestinationPort(const MoveNode &src, PortSet &ports, bool ignoreGuard=false)
std::set< const TTAMachine::Port *, const TTAMachine::MachinePart::Comparator > PortSet
static bool containsKey(const MapType &aMap, const KeyType &aKey)
int nodeCount() const
MoveNode & node(int index) const
std::string toString() const
bool isScheduled() const
bool isOperationMove() const
Definition MoveNode.cc:253
int latestTriggerWriteCycle() const
Definition MoveNode.cc:698
int cycle() const
Definition MoveNode.cc:421
bool isSourceVariable() const
Definition MoveNode.cc:196
bool isMove() const
int guardLatency() const
Definition MoveNode.cc:779
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
bool isDestinationOperation() const
std::string toString() const
Definition MoveNode.cc:576
TTAProgram::Move & move()
bool isSourceOperation() const
Definition MoveNode.cc:168
bool isScheduled() const
Definition MoveNode.cc:409
bool isSourceConstant() const
Definition MoveNode.cc:238
bool isDestinationVariable() const
Definition MoveNode.cc:264
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual TCEString name() const
Definition Operation.cc:93
virtual bool hasSideEffects() const
Definition Operation.cc:272
virtual int affectsCount() const
Definition Operation.cc:402
virtual bool writesMemory() const
Definition Operation.cc:252
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual bool canSwap(int id1, int id2) const
Definition Operation.cc:470
int outputMoveCount() const
const Operation & operation() const
int inputMoveCount() const
MoveNode & inputMove(int index) const
void switchInputs(int idx1=1, int idx2=2)
MoveNode & outputMove(int index) const
void operandsScheduled(AddedRegisterCopies &copies, DataDependenceGraph &ddg)
AddedRegisterCopies addRegisterCopiesToRRMove(MoveNode &moveNode, DataDependenceGraph *ddg)
void resultsScheduled(AddedRegisterCopies &copies, DataDependenceGraph &ddg)
AddedRegisterCopies addMinimumRegisterCopies(ProgramOperation &programOperation, const TTAMachine::Machine &targetMachine, DataDependenceGraph *ddg)
bool renameDestinationRegister(MoveNode &node, bool loopScheduling, bool allowSameRf, bool differentRfOnlyDirectlyReachable, int earliestCycle=-1)
void setSelector(MoveNodeSelector *selector)
bool renameSourceRegister(MoveNode &node, bool loopScheduling, bool allowSameRf, bool differentRfOnlyDirectlyReachable, int latestCycle=INT_MAX)
void initialize(DataDependenceGraph &ddg)
virtual bool killDeadResults() const
InterPassData & interPassData()
unsigned int unsignedValue() const
Definition SimValue.cc:919
int width() const
Definition SimValue.cc:103
virtual int smallestCycle() const override
virtual void assign(int cycle, MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) override
void setMaxCycle(unsigned int maxCycle)
virtual int earliestCycle(MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
virtual unsigned initiationInterval() const
virtual bool canTransportImmediate(const MoveNode &node, const TTAMachine::Bus *preAssignedBus=NULL) const
virtual void unassign(MoveNode &node) override
virtual int largestCycle() const override
virtual int latestCycle(MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
virtual HWOperation * operation(const std::string &name) const
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
void setAnnotation(const ProgramAnnotation &annotation)
bool hasAnnotations(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
static TTAProgram::MoveGuard * createInverseGuard(const TTAProgram::MoveGuard &mg, const TTAMachine::Bus *bus=NULL)
void setSource(Terminal *src)
Definition Move.cc:312
MoveGuard & guard() const
Definition Move.cc:345
bool isControlFlowMove() const
Definition Move.cc:233
bool isReturn() const
Definition Move.cc:259
bool isUnconditional() const
Definition Move.cc:154
Terminal & source() const
Definition Move.cc:302
void setGuard(MoveGuard *guard)
Definition Move.cc:360
void setBus(const TTAMachine::Bus &bus)
Definition Move.cc:383
Terminal & destination() const
Definition Move.cc:323
@ ANN_STACKFRAME_PROCEDURE_RETURN
precedure return jmp
@ ANN_CONNECTIVITY_MOVE
A reg to reg move that was added because of missing connectivity between the original target and dest...
virtual SimValue value() const
virtual bool isRA() const
Definition Terminal.cc:129
virtual bool isTriggering() const
Definition Terminal.cc:298
virtual const TTAMachine::FunctionUnit & functionUnit() const
Definition Terminal.cc:251
virtual int index() const
Definition Terminal.cc:274
virtual bool equals(const Terminal &other) const =0
virtual bool isGPR() const
Definition Terminal.cc:107
virtual int operationIndex() const
Definition Terminal.cc:364
virtual const TTAMachine::Port & port() const
Definition Terminal.cc:378
virtual const TTAMachine::RegisterFile & registerFile() const
Definition Terminal.cc:225