OpenASIP 2.2
Loading...
Searching...
No Matches
ExecutionPipelineResource.cc
Go to the documentation of this file.
1/*
2 Copyright (c) 2002-2020 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 ExecutionPipelineResource.cc
26 *
27 * Implementation of prototype of Resource Model:
28 * implementation of the ExecutionPipelineResource.
29 *
30 * @author Vladimir Guzma 2006 (vladimir.guzma-no.spam-tut.fi)
31 * @author Heikki Kultala 2009 (heikki.kultala-no.spam-tut.fi)
32 * @author Heikki Kultala 2013 (heikki.kultala-no.spam-tut.fi)
33 * @note rating: red
34 */
35
36//#define DEBUG_RM
37
38//#define NO_OVERCOMMIT
39
40#include <climits>
41
44#include "MapTools.hh"
45#include "Move.hh"
46#include "Operation.hh"
47#include "Application.hh"
48#include "Exception.hh"
49#include "ProgramOperation.hh"
50#include "MapTools.hh"
51#include "MoveNode.hh"
52#include "POMDisassembler.hh"
55#include "Machine.hh"
56#include "FunctionUnit.hh"
57#include "HWOperation.hh"
58#include "FUPort.hh"
59#include "TCEString.hh"
60#include "MoveGuard.hh"
61#include "Guard.hh"
63#include "HWOperation.hh"
64#include "FUPort.hh"
65#include "MoveNodeSet.hh"
66
67#include <fstream>
68#include <sstream>
69#include "ResourceManager.hh"
70#include "MoveNode.hh"
71#include "Terminal.hh"
72
73/**
74 * Constructor.
75 *
76 * Creates new resource with defined name
77 *
78 * @param name Name of resource
79 * @param resNum Number of resources in FU
80 * @param maxLatency Latency of longest operation FU supports
81 */
84 const unsigned int ii) :
85 SchedulingResource("ep_" + fu.name(), ii),
86 resources(&ExecutionPipelineResourceTable::resourceTable(fu)),
87 cachedSize_(INT_MIN), maxCycle_(INT_MAX), ddg_(NULL), fu_(fu),
88 operandShareCount_(0) {
89}
90
91/**
92 * Empty destructor
93 */
95
96/**
97 * Not to be used. ExecutionPipelineResource needs to be
98 * tested also with PSocket parameter to find if the desired
99 * part of MoveNode is source or destination from type of PSocket.
100 */
101bool
103 abortWithError("Wrong use of canAssign, use also third parameter!");
104 return false;
105}
106
107/**
108 * Test if resource ExecutionPipelineResource is used in given cycle.
109 *
110 * If there is any of pipeline resources already used in given cycle.
111 * @param cycle Cycle which to test
112 * @return True if ExecutionPipelineResource is already used in cycle
113 * @throw Internal error, the recorded resource usage for cycle is shorter
114 * then the number of resources the FU has.
115 */
116bool
118
119 // check if any operand port is used
120 int modCycle = instructionIndex(cycle);
121 for (OperandWriteMap::const_iterator i = operandsWriten_.begin();
122 i != operandsWriten_.end(); i++) {
123
124 const OperandWriteVector& operandWrites = i->second;
125 OperandWriteVector::const_iterator j = operandWrites.find(modCycle);
126 if (j != operandWrites.end()) {
127 return true;
128 }
129 }
130
131 for (ResultMap::const_iterator rri = resultRead_.begin();
132 rri != resultRead_.end(); rri++) {
133 const ResultVector& resultRead = rri->second;
134 unsigned int resultReadCount = resultRead.rbegin()->first;//.size();
135 if (modCycle < (int)resultReadCount &&
137 resultRead, modCycle)).first.po != NULL) {
138 /// Some result is already read in tested cycle
139 return true;
140 }
141 }
142 if (modCycle >= (int)size()) {
143 /// Cycle is beyond already scheduled scope, not in use therefore
144 return false;
145 }
148 fuExecutionPipeline_, modCycle)).size()) {
149 std::string msg = "Execution pipeline is missing resources!";
150 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
151 }
152 for (unsigned int i = 0; i < resources->numberOfResources(); i++) {
153 const ResourceReservationVector& rrv =
155 fuExecutionPipeline_, modCycle);
156 if (rrv.size() == 0) {
157 return false;
158 }
159
160 const ResourceReservation& rr = rrv[i];
161
162 if (rr.first != NULL) {
163 /// Some pipeline resource is already in use in tested cycle
164 return true;
165 }
166 }
167 return false;
168}
169
170/**
171 * Test if resource ExecutionPipelineResource is available for any of
172 * the supported operations (at least one).
173 *
174 * @param cycle Cycle which to test
175 * @return True if ExecutionPipelineResource is available in cycle
176 */
177bool
179 // check if all operand ports are used
180 int modCycle = instructionIndex(cycle);
181 for (int i = 0; i < fu_.portCount(); i++) {
182 const TTAMachine::BaseFUPort* port = fu_.port(i);
183 OperandWriteMap::const_iterator it = operandsWriten_.find(port);
184 if (it == operandsWriten_.end()) {
185 return true;
186 }
187 const OperandWriteVector& operandWrites = it->second;
188 OperandWriteVector::const_iterator j = operandWrites.find(modCycle);
189 if (j == operandWrites.end()) {
190 return true;
191 }
192
193 MoveNodePtrPair mnpp = j->second;
194 if (mnpp.first == NULL ||
195 (!mnpp.first->move().isUnconditional() &&
196 mnpp.second == NULL)) {
197 return true;
198 }
199 }
200 return true;
201}
202
203
204/*
205 * Record PO in cycle where result is produced into output register,
206 *
207 * increase number of results produced if same PO already producing
208 * something in that cycle
209 */
210void
212 const TTAMachine::Port& port, unsigned int realCycle,
213 const ProgramOperation& po) {
214
215 ResultVector& resultWriten = resultWriten_[&port];
216
217 unsigned int modCycle = instructionIndex(realCycle);
218
219 ResultHelperPair& rhp = resultWriten[modCycle];
220 if (rhp.first.po == NULL) {
221 rhp.first = ResultHelper(realCycle, &po, 1);
222 } else {
223 if (rhp.first.realCycle == realCycle &&
224 rhp.first.po == &po) {
225 rhp.first.count++;
226 } else {
227 if (rhp.second.po == NULL) {
228 rhp.second = ResultHelper(realCycle, &po, 1);
229 } else {
230 rhp.second.count++;
231 }
232 }
233 }
234}
235
236/*
237 * Record PO in cycle where operand is used by the pipeline.
238 *
239 */
240void
242 const TTAMachine::Port& port, unsigned int realCycle,
243 const ProgramOperation& po) {
244
245 OperandUseVector& operandUsed = operandsUsed_[&port];
246 unsigned int modCycle = instructionIndex(realCycle);
247
248 OperandUsePair& oup = operandUsed[modCycle];
249 if (oup.first.po == NULL) {
250 oup.first.po = &po;
251 } else {
252 if (oup.first.realCycle == realCycle &&
253 oup.first.po == &po) {
254 assert(false);
255 } else {
256 if (oup.second.po == NULL) {
257 oup.second.po = &po;
258 } else {
259 assert(false);
260 }
261 }
262 }
263}
264
265void
267 const ProgramOperation& po, unsigned int triggerCycle) {
268
269 const Operation& op = po.operation();
271
272 // Loops over all output values produced by this
273 for (int i = 0; i < op.numberOfOutputs(); i++) {
274 int outIndex = op.numberOfInputs() + 1 + i;
275 const TTAMachine::Port& port = *hwop.port(outIndex);
276 int resultCycle = triggerCycle + hwop.latency(outIndex);
277
278 setResultWriten(port, resultCycle, po);
279 }
280}
281
282void
284 const ProgramOperation& po, unsigned int triggerCycle) {
285
286 const Operation& op = po.operation();
288
289 // Loops over all output values produced by this
290 for (int i = 0; i < op.numberOfInputs(); i++) {
291 const TTAMachine::Port& port = *hwop.port(i+1);
292 int operandUseCycle = triggerCycle + hwop.slack(i+1);
293
294 setOperandUsed(port, operandUseCycle, po);
295 }
296}
297
298/*
299 * Record PO in cycle where result is produced into output register,
300 *
301 * increase number of results produced if same PO already producing
302 * something in that cycle
303 */
304void
306 const TTAMachine::Port& port, unsigned int realCycle,
307 const ProgramOperation& po) {
308 unsigned int rrMod = instructionIndex(realCycle);
309
310 ResultVector& resultWriten = resultWriten_[&port];
311 ResultHelperPair& rhp = resultWriten[rrMod];
312
313 if (rhp.first.po == &po) {
314 // Decrease counter of results written in
315 rhp.first.count--;
316 if (rhp.first.count == 0) {
317 if (rhp.second.count == 0) {
318 resultWriten.erase(rrMod);
319 } else {
320 // move second to first.
321 rhp.first = rhp.second;
322 rhp.second = ResultHelper(); // empty it.
323 }
324 }
325 } else {
326 assert(rhp.second.po == &po);
327 // Decrease counter of results written in
328 rhp.second.count--;
329 if (rhp.second.count == 0) {
330 rhp.second = ResultHelper(); // empty it.
331 }
332 }
333}
334
335void
337 const TTAMachine::Port& port, unsigned int realCycle,
338 const ProgramOperation& po) {
339 unsigned int modCycle = instructionIndex(realCycle);
340
341 OperandUseVector& operandUsed = operandsUsed_[&port];
342 OperandUseVector::iterator i = operandUsed.find(modCycle);
343 assert(i != operandUsed.end());
344 OperandUsePair& mnpp = i->second;
345 if (mnpp.first.po == &po) {
346 if (mnpp.second.po == NULL) {
347 operandUsed.erase(i);
348 } else {
349 mnpp.first = mnpp.second;
350 mnpp.second.po = NULL;
351 }
352 } else {
353 if (mnpp.second.po == &po) {
354 mnpp.second.po = NULL;
355 }
356 }
357}
358
359void
361 const ProgramOperation& po, unsigned int triggerCycle) {
362
363 const Operation& op = po.operation();
365
366 // Loops over all output values produced by this
367 for (int i = 0; i < op.numberOfOutputs(); i++) {
368 int outIndex = op.numberOfInputs() + 1 + i;
369 const TTAMachine::Port& port = *hwop.port(outIndex);
370 int resultCycle = triggerCycle + hwop.latency(outIndex);
371
372 unsetResultWriten(port, resultCycle, po);
373 }
374}
375
376void
378 const ProgramOperation& po, unsigned int triggerCycle) {
379
380 const Operation& op = po.operation();
382
383 // Loops over all output values produced by this
384 for (int i = 0; i < op.numberOfInputs(); i++) {
385 const TTAMachine::Port& port = *hwop.port(i+1);
386 int resultCycle = triggerCycle + hwop.slack(i+1);
387 unsetOperandUsed(port, resultCycle, po);
388 }
389}
390
391void
393 abortWithError("Execution Pipeline Resource needs 3 arguments assign");
394}
395
396/**
397 * Assign resource to given node for given cycle.
398 *
399 * @param cycle Cycle to assign
400 * @param node MoveNode assigned
401 * @param source Indicates if we want to unassing source part of move
402 * in case move is bypassed
403 */
404void
406 int cycle,
407 MoveNode& node) {
408 unsigned int modCycle = instructionIndex(cycle);
409 cachedSize_ = INT_MIN;
410
411 unsigned int ii = initiationInterval_;
412 if (initiationInterval_ && isLoopBypass(node)) {
413 cycle += ii;
414 }
415
416 if (ii < 1) {
417 ii = INT_MAX;
418 }
419
420 const TTAMachine::Port& port = resultPort(node);
421 ResultVector& resultRead = resultRead_[&port];
422
423 /// Assiging result read
424 assignedSourceNodes_.insert(std::pair<int, MoveNode*>(cycle, &node));
425
426 ProgramOperation* pOp = node.isSourceOperation() ?
427 &node.sourceOperation() :
428 &node.guardOperation();
429
430 /// Record Program Operation in cycle where the "result read"
431 /// is scheduled
432 unsigned int readCount = resultRead.size();
433 if (readCount <= modCycle) {
434 resultRead[modCycle] =
436 ResultHelper(modCycle, NULL, 0),
437 ResultHelper(modCycle, NULL, 0));
438#if 0
439 for (unsigned int i = readCount; i <= modCycle; i++) {
440 // Increase the size of the vector
441 resultRead.push_back(
443 ResultHelper(i, NULL, 0),
444 ResultHelper(i, NULL, 0)));
445 }
446#endif
447 }
448 // Record PO in cycle where result is read from output,
449 // increase number of results read if same PO already reads something
450 // in that cycle
451 ResultHelperPair& rhp = resultRead[modCycle];
452 if (rhp.first.po == NULL) {
453 rhp.first = ResultHelper(cycle, pOp, 1);
454 } else {
455 if (rhp.first.po == pOp) {
456 rhp.first.count++;
457 } else {
458 if (rhp.second.po == NULL) {
459 rhp.second = ResultHelper(cycle, pOp, 1);
460 } else {
461 if (rhp.second.po == pOp) {
462 rhp.second.count++;
463 } else {
464 assert(0 && "result read of invalid op");
465 }
466 }
467 }
468 }
469
470 // Record PO in cycle where result is available in result register.
471 setResultWriten(port, cycle, *pOp);
472
473 // Record move and cycle in which the result of it is produced
474 // This uses real cycles, not modulo cycles
475 storedResultCycles_.insert(
476 std::pair<MoveNode*, int>(&node,cycle));
477}
478
479/**
480 * Assign resource to given node for given cycle.
481 *
482 * @param cycle Cycle to assign
483 * @param node MoveNode assigned
484 * in case move is bypassed
485 */
486void
488 const int cycle,
489 MoveNode& node) {
490 cachedSize_ = INT_MIN;
491
492#ifdef DEBUG_RM
493 std::cerr << "\t\t\tAssigning destination: " << node.toString() << std::endl;
494#endif
495 if (!node.isDestinationOperation()) {
496 return;
497 }
498
499 assignedDestinationNodes_.insert(std::pair<int, MoveNode*>(cycle, &node));
500
501 int modCycle = instructionIndex(cycle);
502
503 std::string opName = "";
504
505 //TODO: is this correct trigger or UM trigger?
506 if (node.move().destination().isTriggering()) {
507#ifdef DEBUG_RM
508 std::cerr << "\t\t\t\tis trigger!" << std::endl;
509#endif
511
513 if (node.move().destination().isOpcodeSetting()) {
514 opName = node.move().destination().operation().name();
515 } else {
516 std::string msg = "Using non opcodeSetting triggering move. ";
517 msg += " Move: " + node.toString();
518 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
519 }
520 int pIndex = resources->operationIndex(opName);
521 for (unsigned int i = 0; i < resources->maximalLatency(); i++) {
522 int modic = instructionIndex(cycle+i);
523 // then we can insert the resource usage.
524 for (unsigned int j = 0 ;
525 j < resources->numberOfResources(); j++) {
526 if (fuExecutionPipeline_[modic].size()
527 == 0) {
528 fuExecutionPipeline_[modic] =
531 }
533 fuExecutionPipeline_[modic][j];
534 if (resources->operationPipeline(pIndex,i,j)) {
535 if (rr.first != NULL) {
536 assert(rr.second == NULL&&"Resource already in use?");
537 rr.second = &node;
538 } else { // rr.first == NULL
539 rr.first = &node;
540 }
541 }
542 }
543 }
544 setResultWriten(pOp, cycle);
545 setOperandsUsed(pOp, cycle);
546 } else {
547 if (node.destinationOperationCount() > 1) {
549 }
550 }
551
552 const TTAMachine::Port& opPort = operandPort(node);
553 MoveNodePtrPair& mnpp = operandsWriten_[&opPort][modCycle];
554 if (mnpp.first == NULL) {
555 mnpp.first = &node;
556 } else {
557 if (mnpp.second != NULL || !exclusiveMoves(mnpp.first, &node, cycle)) {
558 std::string msg = name() + " had previous operation ";
559 msg += mnpp.first->destinationOperation().toString() + "\n ";
560 msg += mnpp.first->toString() + " in inst.index " ;
561 msg += Conversion::toString(modCycle);
562 msg += " other trigger: ";
563 msg += mnpp.first->toString();
564 msg += " Node: " + node.toString();
565 msg += "\nThis op: " + node.destinationOperation().toString();
566 msg += "\n";
567
568 if (node.isDestinationOperation()) {
569 msg += node.destinationOperation().toString();
570 }
571 throw InvalidData(__FILE__, __LINE__, __func__, msg);
572 } else {
573
574 // Marks all the cycles in range with PO
575 // which is writing operands
576 mnpp.second = &node;
577 }
578 }
579}
580
581void
583 abortWithError("Execution Pipeline Resource needs 3 arguments unassign");
584}
585
586/**
587 * Unassign resource from given node for given cycle.
588 *
589 * @param cycle Cycle to remove assignment from
590 * @param node MoveNode to remove assignment from
591 * @param source Indicates if we want to unassign source part of move
592 * in case move is bypassed
593 * @throw In case there was no previous assignment or wrong operation
594 * is unassigned
595 */
596void
598 const int cycle,
599 MoveNode& node) {
600 cachedSize_ = INT_MIN;
601
602 int modCycle = instructionIndex(cycle);
603 unsigned int ii = initiationInterval_;
604 if (ii < 1) {
605 ii = INT_MAX;
606 }
607
608 if (node.cycle() != cycle) {
609 throw InvalidData(__FILE__, __LINE__, __func__,
610 "Trying to unassign node from different cycle "
611 "then it was assigned to!");
612 }
613
614 const TTAMachine::Port& port = resultPort(node);
615 ResultVector& resultRead = resultRead_[&port];
617 node.sourceOperation() :
618 node.guardOperation();
619
620 /// Unscheduling result read
623
625 /// Remove record of result beeing written to result register
626 /// or decrease count in case there are more results
627 unsigned int resultReady =
629
630 unsetResultWriten(port, resultReady, po);
631 storedResultCycles_.erase(&node);
632
633 // assert fail is much nicer than unknown exception.
634 assert(modCycle < (int)resultRead.size());
635 ResultHelperPair& resultReadPair = resultRead[modCycle];
636
637 if (resultReadPair.first.po == &po) {
638 /// Remove record or decrease count of result read moves
639 resultReadPair.first.count--;
640 if (resultReadPair.first.count == 0) {
641 if (resultReadPair.second.count == 0) {
642 // erase from the bookkeeping, this is empty.
643 resultRead.erase(modCycle);
644 } else {
645 resultReadPair.first = resultReadPair.second;
646 resultReadPair.second.count = 0;
647 resultReadPair.second.realCycle = modCycle;
648 resultReadPair.second.po = NULL;
649 }
650 }
651 } else {
652 if (resultReadPair.second.po == &po) {
653 ///Remove record or decrease count of result read moves
654 resultReadPair.second.count--;
655 if (resultReadPair.second.count == 0) {
656 resultReadPair.second.realCycle = modCycle;
657 resultReadPair.second.po = NULL;
658 }
659 }
660 }
661 }
662 }
663}
664
665#pragma GCC diagnostic ignored "-Wunused-variable"
666/**
667 * Unassign resource from given node for given cycle.
668 *
669 * @param cycle Cycle to remove assignment from
670 * @param node MoveNode to remove assignment from
671 * in case move is bypassed
672 * @throw In case there was no previous assignment or wrong operation
673 * is unassigned
674 */
675void
677 const int cycle,
678 MoveNode& node) {
679
680#ifdef DEBUG_RM
681 std::cerr << "\tUnassigning destination: " << node.toString() << std::endl;
682#endif
683
684 if (!node.isDestinationOperation()) {
685#ifdef DEBUG_RM
686 std::cerr << "\t\tNot dest operatioN!" << std::endl;
687#endif
688 return;
689 }
690
691 int modCycle = instructionIndex(cycle);
692 unsigned int ii = initiationInterval_;
693 if (ii < 1) {
694 ii = INT_MAX;
695 }
696
698#ifdef DEBUG_RM
699 std::cerr << "\t\t assigned destinations not contain!" << std::endl;
700#endif
701 return;
702 }
703 /// Now unassing destination part of move
705
706 const TTAMachine::Port& opPort = operandPort(node);
707 MoveNodePtrPair& mnpp = operandsWriten_[&opPort][modCycle];
708 assert (mnpp.first != NULL);
709 if (mnpp.second == &node) {
710 mnpp.second = NULL;
711 } else {
712 assert(mnpp.first == &node);
713 mnpp.first = mnpp.second;
714 mnpp.second = NULL;
715 }
716
717 // if not trigger, we are done
718 // TODO: correct trigger or UM trigger?
719 if (!node.move().destination().isTriggering()) {
720#ifdef DEBUG_RM
721 std::cerr << "\t\t not trigger!" << std::endl;
722#endif
723
724 if (node.destinationOperationCount() > 1) {
726 }
727 return;
728 }
729
731
734
735 std::string opName = "";
736 if (node.move().destination().isOpcodeSetting()) {
737 opName = node.move().destination().operation().name();
738 } else {
739 opName = node.move().destination().hintOperation().name();
740 }
741 if (!resources->hasOperation(opName)) {
742 std::string msg = "Trying to unassign operation \'";
743 msg += opName ;
744 msg += "\' not supported on FU!";
745 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
746 }
747
748 // Cannot trust size() since that one ignores empty pipeline
749 // and here we need to go up to the maximalLatency.
750 size_t fuEpSize = fuExecutionPipeline_.size();
751 if ((size_t)instructionIndex(cycle + resources->maximalLatency() - 1)
752 >= fuEpSize) {
753 std::string msg = "Unassigning operation longer then scope!";
754 msg += " - cycle:";
755 msg += Conversion::toString(cycle);
756 msg += " - scope:";
757 msg += Conversion::toString(fuEpSize);
758 msg += " - ii:";
760 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
761 }
762 for (unsigned int i = 0; i < resources->maximalLatency(); i++) {
763 int modic = instructionIndex(cycle+i);
764 for (unsigned int j = 0 ; j < resources->numberOfResources(); j++) {
765 assert(
766 fuExecutionPipeline_[modic].size() != 0);
768 fuExecutionPipeline_[modic][j];
769 if (rr.first == &node) {
771 resources->operationIndex(opName),i,j) &&
772 "unassigning pipeline res not used by this op");
773
774 rr.first = rr.second;
775 rr.second = NULL;
776 } else {
777 if (rr.second == &node) {
779 resources->operationIndex(opName),i,j) &&
780 "unassigning pipeline res not used by this op");
781
782 rr.second = NULL;
783 }
784 }
785 }
786 }
787}
788
789#pragma GCC diagnostic warning "-Wunused-variable"
790
792 if (ddg_ == NULL) {
793 return false;
794 }
795 if (!ddg_->hasNode(node)) {
796 return false;
797 }
798 auto inEdges = ddg_->inEdges(node);
799 for (auto i = inEdges.begin(); i != inEdges.end(); i++) {
800 DataDependenceEdge& e = **i;
802 && e.isBackEdge()) {
803 return true;
804 }
805 }
806 return false;
807}
808
809/**
810 * Return true if resource can be assigned for given node in given cycle.
811 *
812 * @param cycle Cycle to test
813 * @param node MoveNode to test
814 * @param pSocket Socket which was assigned to move by previous broker
815 * @param triggers Indicates if move is triggering
816 * @return true if node can be assigned to cycle
817 */
818bool
820 int cycle,
821 const MoveNode& node,
822 const TTAMachine::Port& resultPort) const {
823
824 if (initiationInterval_ != 0 && isLoopBypass(node)) {
825 cycle+=initiationInterval_;
826 }
827
828#ifdef DEBUG_RM
829 std::cerr << "\t\t\tcanAssignSource called for: " << node.toString() << " on cycle: "
830 << cycle << std::endl;
831#endif
832 int outputIndex = -1;
833 ProgramOperation* po = nullptr;
834
835 if (node.isSourceOperation()) {
836 po = &node.sourceOperation();
837 outputIndex = node.move().source().operationIndex();
838 } else {
839 assert(node.isGuardOperation());
840 po = &node.guardOperation();
841 outputIndex = po->outputIndexFromGuardOfMove(node);
842 }
843
844 const TTAMachine::HWOperation& hwop =
845 *fu_.operation(po->operation().name());
846
847 if (initiationInterval_ != 0 &&
848 hwop.latency(outputIndex) > (int)initiationInterval_) {
849#ifdef DEBUG_RM
850 std::cerr << "too long latency overlappingloop" << std::endl;
851#endif
852 return false;
853 }
854
855 /// Testing the result read move
856 /// Find the cycle first of the possible results of PO will be produced
857 int resultReady = node.earliestResultReadCycle();
858
859 /// Check if the port has a register. If not result read must be
860 /// in same cycle as result ready.
861 const TTAMachine::FUPort& port = *hwop.port(outputIndex);
862 if (resultReady != INT_MAX) {
863 if (port.noRegister() && resultReady != cycle) {
864 return false;
865 }
866
867 if (cycle < resultReady) {
868 // resultReady is INT_MAX if trigger was not scheduled yet
869 // also tested cycle can not be before result is in output
870 // register
871#ifdef DEBUG_RM
872 std::cerr << "\tresult not yet ready" << std::endl;
873#endif
874 return false;
875 }
876
877 const MoveNode* trigger = po->triggeringMove();
878 int triggerCycle = (trigger != NULL && trigger->isPlaced()) ?
879 trigger->cycle() : -1;
881 cycle, resultReady, node, resultPort,
882 trigger, triggerCycle) &&
884 resultReady, *po, resultPort, *trigger, triggerCycle);
885 } else {
886 // trigger not yet scheduled, do not know when result ready
887 if (hasConflictingResultsOnCycle(*po, resultPort, cycle)) {
888#ifdef DEBUG_RM
889 std::cerr << "Other op writing result at same cycle, this is illgal" << std::endl;
890#endif
891 return false;
892 }
893
894 // limit result cycle to latency of operation, so that
895 // trigger does nto have to be scheduled to negative cycle.
896 // find the OSAL id of the operand of the output we are reading
897 // ignore this for guard ops due to the thread switch kludge.
898 if (hwop.latency(outputIndex) > cycle && node.isSourceOperation()) {
899#ifdef DEBUG_RM
900 std::cerr << "\t\t\t\t\ttrigger needs negative cycle" << std::endl;
901#endif
902 return false;
903 }
904
905 // If some another result read of this op is scheduled,
906 // take the trigger cycle from that and call resultNotOverWritten?
907
908 MoveNodeSet& allResults = po->outputNode(outputIndex);
909 if (allResults.count() >1) {
910#ifdef DEBUG_RM
911 std::cerr << "\t\t\t\tSame op has multiple results." << std::endl;
912#endif
913 const MoveNode* trigger = NULL;
914 for (int i = 0; i < allResults.count(); i++) {
915 MoveNode& res = allResults.at(i);
916 if (&res == &node || !res.isPlaced()) {
917 continue;
918 }
919 int resCycle = res.cycle();
920 if (initiationInterval_ && isLoopBypass(res)) {
921 resCycle += initiationInterval_;
922 }
923 resultReady = std::min(resultReady, resCycle);
924#ifdef DEBUG_RM
925 std::cerr << "\t\t\t\t\tother result, of node: "
926 << res.toString()
927 <<" used at cycle: " << resCycle << std::endl;
928#endif
929 if (trigger == NULL) {
930 trigger = po->triggeringMove();
931 }
932 if (cycle < resCycle && !resultNotOverWritten(
933 resCycle, cycle, node, resultPort, trigger,-1)) {
934 return false;
935 }
936 }
937 if (resultReady != INT_MAX && resultReady < cycle) {
938#ifdef DEBUG_RM
939 std::cerr << "\t\t\t\tChecking if res not overwritten."
940 << std::endl;
941#endif
943 cycle, resultReady, node, resultPort, trigger, -1)) {
944 return false;
945 }
946#ifdef DEBUG_RM
947 std::cerr << "\t\t\t\tres not overwritten." << std::endl;
948#endif
949 }
950 }
951
952 const MoveNode* trigger = po->triggeringMove();
953 int triggerCycle = (trigger != NULL && trigger->isPlaced()) ?
954 trigger->cycle() : -1;
955
956 // We need to test if the write in given cycle is possible
957 // even if we do not yet have trigger scheduled and
958 // node.earliestResultReadCycle() returns INT_MAX.
959 // This allows for comparison of result moves in Bottom-Up schedule
960
961#ifdef DEBUG_RM
962 std::cerr << "\t\t\t\tcheck if result allowed at this cycle?" << std::endl;
963#endif
965 cycle, *po, resultPort, *trigger, triggerCycle)) {
966 return false;
967 }
968
969#ifdef DEBUG_RM
970 std::cerr << "\t\t\t\tcheck if result causes trigger between opshares?" << std::endl;
971#endif
972
974 return false;
975 }
976 }
977 return true;
978}
979
980/**
981 * Return true if resource can be assigned for given node in given cycle.
982 *
983 * @param cycle Cycle to test
984 * @param node MoveNode to test
985 * @param pSocket Socket which was assigned to move by previous broker
986 * @param triggers Indicates if move is triggering
987 * @return true if node can be assigned to cycle
988 */
989bool
991 const int cycle,
992 const MoveNode& node,
993 bool triggers) const {
994
995 if (!node.isDestinationOperation()) {
996 return true;
997 }
998
999#ifdef DEBUG_RM
1000 std::cerr << "\t\t\tCanAssignDestination called for: " << node.toString()
1001 << " Cycle: " << cycle << " PO: "
1002 << node.destinationOperation().toString() << std::endl;
1003 if (triggers) {
1004 std::cerr << "\t\t\t\tTriggers." << std::endl;
1005 }
1006#endif
1007 unsigned int ii = initiationInterval_;
1008 if (ii < 1) {
1009 ii = INT_MAX;
1010 }
1011
1012 // then handle operation inputs.
1013
1014 MoveNode* newNode = const_cast<MoveNode*>(&node);
1015 ProgramOperation* pOp = NULL;
1016 try {
1017 pOp = &newNode->destinationOperation();
1018 } catch (const InvalidData& e) {
1020 }
1021
1022 const TTAMachine::HWOperation& hwop =
1023 *fu_.operation(pOp->operation().name());
1024 TTAMachine::FUPort& port =
1025 *hwop.port(newNode->move().destination().operationIndex());
1026
1027 if (!operandPossibleAtCycle(port, node, cycle)) {
1028 return false;
1029 }
1030
1031 if (!operandAllowedAtCycle(port, node, cycle)) {
1032 return false;
1033 }
1034
1035 if (otherTriggerBeforeMyTrigger(port, node, cycle)) {
1036 return false;
1037 }
1038
1039 if (operandOverwritten(node, cycle)) {
1040 return false;
1041 }
1042
1043 if (!triggers) {
1044 if (operandTooLate(node, cycle)) {
1045#ifdef DEBUG_RM
1046 std::cerr << "\t\tOperand too late" << std::endl;
1047#endif
1048 return false;
1049 }
1050
1051 if (operandSharePreventsTriggerForScheduledResult(port, node, cycle)) {
1052 return false;
1053 }
1054 return true;
1055 }
1056
1057 if (triggerTooEarly(node, cycle)) {
1058#ifdef DEBUG_RM
1059 std::cerr << "\t\tTrigger too early" << std::endl;
1060#endif
1061
1062 return false;
1063 }
1064
1065#ifdef DEBUG_RM
1066 std::cerr << "\t\t\t\tCanAssignDestination is trigger: "
1067 << node.toString() << " Cycle: " << cycle << std::endl;
1068#endif
1069
1070 // Too late to schedule trigger, results would not be ready in time.
1071 if (cycle > latestTriggerWriteCycle(node)) {
1072#ifdef DEBUG_RM
1073 std::cerr << "\t\t\t\t\tTrigger too late for results" << std::endl;
1074#endif
1075 return false;
1076 }
1077
1078 // now we know we have a trigger.
1079 if (operandsOverwritten(cycle, node)) {
1080#ifdef DEBUG_RM
1081 std::cerr << "\t\t\t\tOperands overwritten" << std::endl;
1082#endif
1083
1084 return false;
1085 }
1086
1087 if (!resourcesAllowTrigger(cycle, node)) {
1088#ifdef DEBUG_RM
1089 std::cerr << "\t\t\t\tResources prevent trigger" << std::endl;
1090#endif
1091
1092 return false;
1093 }
1094
1096 pOp->operation().numberOfInputs(), hwop, node, cycle)) {
1097 return false;
1098 }
1099 // TODO: if ports have no regs..
1100
1101 // Test for result read WaW already when scheduling trigger.
1102 return testTriggerResult(node, cycle);
1103}
1104
1106 const MoveNode& mn, int cycle) const {
1107#ifdef DEBUG_RM
1108 std::cerr << "\t\tTesting operand not overwritten by other ops: " <<
1109 mn.toString() << " cycle: " << cycle << std::endl;
1110#endif
1111 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
1113 MoveNode* trigger = po.triggeringMove();
1114 if (trigger == &mn) {
1115#ifdef DEBUG_RM
1116 std::cerr << "\t\t\tmn is trigger, no need to check overwrite" << std::endl;
1117#endif
1118 return false;
1119 }
1120 if (trigger == NULL || !trigger->isPlaced()) {
1121#ifdef DEBUG_RM
1122 std::cerr << "\t\t\ttrigger null or not scheduled on PO: "
1123 << po.toString() << std::endl;
1124#endif
1125 continue;
1126 }
1127
1128 int triggerCycle = trigger->cycle();
1129
1130 if (operandOverwritten(cycle, triggerCycle, po, mn, *trigger)) {
1131 return true;
1132 }
1133 }
1134 return false;
1135}
1136
1138 int operandWriteCycle,
1139 int triggerCycle,
1140 const ProgramOperation& po,
1141 const MoveNode& operand,
1142 const MoveNode& trigger) const {
1143
1144 unsigned int ii = initiationInterval_;
1145 if (ii < 1) {
1146 ii = INT_MAX;
1147 }
1148
1149#ifdef DEBUG_RM
1150 std::cerr << "\t\t\tOperandOverWritten called for: " << operand.toString()
1151 << " PO: " << po.toString()
1152 << " trigger: " << trigger.toString() << "owc: "
1153 << operandWriteCycle << " tc: " << triggerCycle << std::endl;
1154#endif
1155 const Operation& op = po.operation();
1157
1158 int opIndex = operand.move().destination().operationIndex();
1159 const TTAMachine::Port& port = *hwop.port(opIndex);
1160 int operandUseCycle = triggerCycle + hwop.slack(opIndex);
1161
1162 // same op on next loop iteration overwrites?
1163 if (operandUseCycle - operandWriteCycle >= (int)ii) {
1164#ifdef DEBUG_RM
1165 std::cerr << "\t\t\t\tOperand LR over loop iteration(2): " << ii
1166 << std::endl;
1167#endif
1168 return true;
1169 }
1170
1171#ifdef DEBUG_RM
1172 std::cerr << "\t\t\t\tTesting port: " << port.name() << std::endl;
1173#endif
1174 OperandWriteMap::const_iterator iter = operandsWriten_.find(&port);
1175 if (iter == operandsWriten_.end()) {
1176 return false;
1177 }
1178 const OperandWriteVector& operandWritten = iter->second;
1179#ifdef DEBUG_RM
1180
1181 std::cerr << "\t\t\t\tOperandWriteCycle: " << operandWriteCycle << std::endl
1182 << "\t\t\t\tOperandUseCycle: " << operandUseCycle << std::endl;
1183#endif
1184
1185 for (int j = operandWriteCycle; j <= operandUseCycle; j++) {
1186#ifdef DEBUG_RM
1187 std::cerr << "\t\t\t\tTesting if overwritten in cycle: " << j << std::endl;
1188#endif
1189 unsigned int modCycle = instructionIndex(j);
1190 OperandWriteVector::const_iterator owi = operandWritten.find(modCycle);
1191 if (owi == operandWritten.end()) {
1192 continue;
1193 }
1194 const MoveNodePtrPair& mnpp = owi->second;
1195 if (mnpp.first != NULL && mnpp.first != &operand &&
1196 !exclusiveMoves(mnpp.first, &trigger, triggerCycle)) {
1197#ifdef DEBUG_RM
1198 std::cerr << "\t\t\t\t\tOverwritten by: " << mnpp.first->toString() << std::endl;
1199#endif
1200 return true;
1201 }
1202 if (mnpp.second != NULL && mnpp.second != &operand &&
1203 !exclusiveMoves(mnpp.second, &trigger, triggerCycle)) {
1204#ifdef DEBUG_RM
1205 std::cerr << "\t\t\t\t\tOverwritten(2) by: " << mnpp.second->toString() << std::endl;
1206#endif
1207 return true;
1208 }
1209 }
1210#ifdef DEBUG_RM
1211 std::cerr << "\t\t\tNot overwritten" << std::endl;
1212#endif
1213 return false;
1214}
1215
1217 int triggerCycle, const MoveNode& trigger) const {
1218 ProgramOperation &po = trigger.destinationOperation();
1219#ifdef DEBUG_RM
1220 std::cerr << "\t\tTesting op overwrite for: " << po.toString() << " cycle: " << triggerCycle << std::endl;
1221#endif
1222 for (int i = 0; i < po.inputMoveCount(); i++) {
1223 MoveNode& inputMove = po.inputMove(i);
1224 if (&inputMove == &trigger) {
1225 continue;
1226 }
1227 if (!inputMove.isPlaced()) {
1229 triggerCycle, triggerCycle, po, inputMove, trigger)) {
1230 return true;
1231 }
1232 continue;
1233 }
1234 int operandWriteCycle = inputMove.cycle();
1236 operandWriteCycle, triggerCycle, po, inputMove, trigger)) {
1237 return true;
1238 }
1239 }
1240 return false;
1241}
1242
1243
1245 int cycle, const MoveNode& node) const {
1246
1247 unsigned int ii = initiationInterval();
1248 if (ii < 1) {
1249 ii = INT_MAX;
1250 }
1251
1252 int modCycle = instructionIndex(cycle);
1253 std::string opName = "";
1254 if (node.move().destination().isOpcodeSetting()) {
1255 opName = node.move().destination().operation().name();
1256// debugLogRM(opName);
1257 } else {
1258 // If target architecture has different opcode setting port
1259 // as universal machine, pick a name of operation from a hint
1260 opName = node.move().destination().hintOperation().name();
1261 }
1262
1263 if (!resources->hasOperation(opName)) {
1264 // Operation no supported by FU
1265// debugLogRM(opName + " not supported by the FU!");
1266 return false;
1267 }
1268
1269 int pIndex = resources->operationIndex(opName);
1270
1271 bool canAssign = true;
1272
1273 std::size_t maxSize = resources->maximalLatency() + modCycle;
1274 if (maxSize > ii) {
1275 maxSize = ii;
1276 }
1277
1278 unsigned int rLat = resources->maximalLatency();
1279 unsigned int nRes = resources->numberOfResources();
1280
1281 if (maxCycle_ != INT_MAX) {
1282 for (unsigned int i = 0; i < rLat && canAssign; i++) {
1283
1284 for (unsigned int j = 0 ; j < nRes; j++) {
1285 // is this resource needed by this operation?
1286 if (resources->operationPipeline(pIndex,i,j)) {
1287 // is the resource free?
1288 if (((unsigned int)(cycle + i)) >
1289 (unsigned int)(maxCycle_)) {
1290 return false;
1291 }
1292 }
1293 }
1294 }
1295 }
1296
1297 std::vector<std::vector<bool> >
1298 assigned(nRes, std::vector<bool>(rLat, false));
1299
1300 unsigned int curSize = size();
1301 unsigned int fupSize = fuExecutionPipeline_.size();
1302 for (unsigned int i = 0; i < rLat && canAssign; i++) {
1303 unsigned int modci = instructionIndex(cycle+i);
1304
1305 if (ii == INT_MAX) {
1306 if (modci >= curSize) {
1307 break;
1308 }
1309 } else {
1310 // may still fail on bigger value of i if overlaps,
1311 // so continue instead of break.
1312 if (fupSize <= modci) {
1313 continue;
1314 }
1315 }
1316
1318 if (rrv.empty()) {
1319 continue;
1320 }
1321
1322 for (unsigned int j = 0 ; j < resources->numberOfResources(); j++) {
1323
1324 ResourceReservation& rr = rrv[j];
1325
1326 // is this resource needed by this operation?
1327 if (resources->operationPipeline(pIndex,i,j)) {
1328 // is the resource free?
1329 if (rr.first != NULL) {
1330 // can still assign this with opposite guard?
1331 if (rr.second == NULL &&
1332 exclusiveMoves(rr.first, &node, modCycle)) {
1333 assigned[j][i] = true;
1334 rr.second = &node;
1335 } else { // fail.
1336 canAssign = false;
1337 break;
1338 }
1339 } else { // mark it used for this operation.
1340 assigned[j][i] = true;
1341 rr.first = &node;
1342 }
1343 }
1344 }
1345 }
1346
1347 // reverts usage of this op to resource used table
1348 for (unsigned int i = 0; i < resources->maximalLatency(); i++) {
1349 for (unsigned int j = 0; j < resources->numberOfResources(); j++) {
1350 if (assigned[j][i]) {
1351 ResourceReservation& rr =
1353 // clear the usage.
1354 if (rr.first == &node) {
1355 assert(rr.second == NULL);
1356 rr.first = rr.second;
1357 rr.second = NULL;
1358 } else {
1359 if (rr.second == &node) {
1360 rr.second = NULL;
1361 } else {
1362 assert(0&& "assignment to undo not found");
1363 }
1364 }
1365 }
1366 }
1367
1368 }
1369 return canAssign;
1370}
1371
1372/**
1373 * Always return true.
1374 *
1375 * @return true
1376 */
1377bool
1381
1382/**
1383 * Tests if all referred resources in dependent groups are of proper types.
1384 *
1385 * @return true Allways true, pipelines are internal to object.
1386 */
1387bool
1391
1392/**
1393 * Tests if all resources in related resource groups are of proper types.
1394 *
1395 * @return true If all resources in related resource groups are
1396 * Triggering PSockets - for now InputPSockets
1397 */
1398bool
1400 for (int i = 0; i < relatedResourceGroupCount(); i++) {
1401 for (int j = 0, count = relatedResourceCount(i); j < count; j++) {
1403 return false;
1404 }
1405 }
1406 return true;
1407}
1408
1409/**
1410 * Return number of cycles current execution pipeline for FU contains.
1411 * Effectively, highest cycle in which any of the resources of an
1412 * FU is occupied plus 1.
1413 *
1414 * @return Number of cycles in pipeline.
1415 */
1416unsigned int
1418
1419#if 0
1420 // Breaks for load and store units with internal pipeline resources!!!
1421 if (cachedSize_ != INT_MIN ) {
1422 return cachedSize_;
1423 }
1424#endif
1425 int length = fuExecutionPipeline_.size() - 1;
1426 int dstCount = assignedDestinationNodes_.size();
1427 int srcCount = assignedSourceNodes_.size();
1428 // If there are no sources or destinations
1429 // assigned then the pipeline has to be empty.
1430 // No point searching whole empty range
1431 if (length == -1 || (dstCount == 0 && srcCount ==0)) {
1432 cachedSize_ = 0;
1433 return 0;
1434 }
1435 int stoppingCycle = length;
1436 if (dstCount > 0) {
1437 int dstMin = (*assignedDestinationNodes_.begin()).first;
1438 stoppingCycle = std::min(stoppingCycle, dstMin);
1439 }
1440 if (srcCount > 0) {
1441 int srcMin = (*assignedSourceNodes_.begin()).first;
1442 stoppingCycle = std::min(stoppingCycle, srcMin);
1443 }
1444 // Don't go bellow smallest known assigned node
1445 for (int i = length; i >= stoppingCycle; i--) {
1446 ResourceReservationTable::const_iterator iter =
1447 fuExecutionPipeline_.find(i);
1448 if (iter == fuExecutionPipeline_.end()) {
1449 continue;
1450 } else {
1451 const ResourceReservationVector& rrv = iter->second;
1452 if (rrv.size() == 0) {
1453 continue;
1454 }
1455
1456 for (unsigned int j = 0; j < resources->numberOfResources(); j++) {
1457 const ResourceReservation& rr = rrv[j];
1458 if (rr.first != NULL) {
1459 cachedSize_ = i + 1;
1460 return i + 1;
1461 }
1462 }
1463 }
1464 }
1465 cachedSize_ = 0;
1466 return 0;
1467}
1468
1469/**
1470 * Returns the highest cycle known to Execution Pipeline to be used by either
1471 * pipeline resources or some operands, trigger or result read/write
1472 *
1473 *
1474 * TODO: module thingies
1475 *
1476 * @return Highest cycle in which the pipeline is known to be used.
1477 */
1478int
1480 if (initiationInterval_ == 0 || initiationInterval_ == INT_MAX) {
1481
1482 // Find largest cycle where any operand or result was previously
1483 // scheduled.
1484 int maximum = 0;
1485 if (assignedDestinationNodes_.size() > 0) {
1486 maximum = (*assignedDestinationNodes_.rbegin()).first;
1487 } else {
1488 maximum = -1;
1489 }
1490
1491 int maxResults = 0;
1492 if (assignedSourceNodes_.size() > 0) {
1493 maxResults = (*assignedSourceNodes_.rbegin()).first;
1494 } else {
1495 maxResults = 0;
1496 }
1497 if (maxResults> maximum) {
1498 maximum = maxResults;
1499 }
1500 // size returns count of cycle, max cycle address needs -1
1501 return std::max(maximum, (int)(size()) - 1);
1502 } else {
1503 int highest = -1;
1504 int min = INT_MAX;
1505 if (assignedSourceNodes_.size() > 0) {
1506 int srcMin = (*assignedSourceNodes_.begin()).first;
1507 min = std::min(min, srcMin);
1508 }
1509 if (assignedDestinationNodes_.size() > 0) {
1510 int dstMin = (*assignedDestinationNodes_.begin()).first;
1511 min = std::min(min, dstMin);
1512 }
1513
1514 for (ResultMap::const_iterator rwi = resultWriten_.begin();
1515 rwi != resultWriten_.end(); rwi++) {
1516 const ResultVector& resultWriten = rwi->second;
1517
1518 for (int i = resultWriten.size() -1; i >= min; i--) {
1519 const ResultHelperPair& rhp =
1521 resultWriten,i);
1522 if (rhp.first.po != NULL) {
1523 if (int(rhp.first.realCycle) > highest) {
1524 highest = rhp.first.realCycle;
1525 }
1526 if (rhp.second.po != NULL) {
1527 if (int(rhp.second.realCycle) > highest) {
1528 highest = rhp.second.realCycle;
1529 }
1530 }
1531 }
1532 }
1533 }
1534 for (ResultMap::const_iterator rri = resultRead_.begin();
1535 rri != resultRead_.end(); rri++) {
1536 const ResultVector& resultRead = rri->second;
1537 for (int i = resultRead.size() -1; i >= min ; i--) {
1538 const ResultHelperPair& rrp =
1540 resultRead,i);
1541 if (rrp.first.po != NULL) {
1542 if (int(rrp.first.realCycle) > highest) {
1543 highest = rrp.first.realCycle;
1544 }
1545 if (rrp.second.po != NULL) {
1546 if (int(rrp.second.realCycle) > highest) {
1547 highest = rrp.second.realCycle;
1548 }
1549 }
1550 }
1551 }
1552 }
1553 // TODO: operand writes not yet handled for this.
1554 return highest;
1555 }
1556}
1557
1558bool
1560 const ProgramOperation& po, const TTAMachine::Port& port, int cycle)
1561 const {
1562 ResultMap::const_iterator rwi = resultWriten_.find(&port);
1563 if (rwi == resultWriten_.end()) {
1564 return false;
1565 }
1566
1567 unsigned int modCycle = instructionIndex(cycle);
1568 MoveNode* trigger = po.triggeringMove();
1569 const ResultHelperPair& rhp =
1571 rwi->second, modCycle);
1572
1573 if (rhp.first.count != 0) {
1574 assert(rhp.first.po != NULL);
1575 if (rhp.first.po != &po &&
1577 rhp.first.po->triggeringMove(), trigger, INT_MAX)) {
1578 return true;
1579 }
1580 if (rhp.second.po != &po && rhp.second.count != 0) {
1581 assert(rhp.second.po != NULL);
1582 if (!exclusiveMoves(
1583 rhp.second.po->triggeringMove(), trigger, INT_MAX)) {
1584 return true;
1585 }
1586 }
1587 }
1588 return false;
1589}
1590
1591
1592/**
1593 * Returns a cycle in which result of next program operation will be
1594 * writen to result. This method results the next one of any iteration,
1595 * not just the current iteration.
1596 *
1597 * @param cycle Cycle from which to start testing.
1598 * @param node Node for which to test
1599 * @return Cycle in which next result will be writen, overwriting curent one.
1600 */
1601int
1603 const TTAMachine::Port& port,
1604 int cycle, const MoveNode& node, const MoveNode* trigger, int triggerCycle)
1605 const {
1606
1607 ResultMap::const_iterator rwi = resultWriten_.find(&port);
1608 if (rwi == resultWriten_.end()) {
1609 return INT_MAX;
1610 }
1611 const ResultVector& resultWriten = rwi->second;
1612
1613 ProgramOperation* sourcePo;
1614 if (!node.isSourceOperation()) {
1615 if (node.isGuardOperation()) {
1616 sourcePo = &node.guardOperation();
1617 } else {
1618 throw InvalidData(__FILE__, __LINE__, __func__,
1619 "Trying to get next result for move that is not"
1620 " in ProgramOperation");
1621 }
1622 } else {
1623 sourcePo = &node.sourceOperation();
1624 if (trigger == NULL) {
1625 trigger = sourcePo->triggeringMove();
1626 }
1627 }
1628
1629 unsigned int ii = initiationInterval_;
1630 if (ii < 1) {
1631 ii = INT_MAX;
1632 }
1633
1634 unsigned int rwSize = resultWriten.size();
1635 for (unsigned int i = cycle; i < cycle + ii; i++) {
1636 unsigned int modi = instructionIndex(i);
1637
1638 if (rwSize <= modi) {
1639 if (ii == INT_MAX) {
1640 return INT_MAX;
1641 } else {
1642 continue;
1643 }
1644 }
1645
1646 const ResultHelperPair& rhp =
1648 if (rhp.first.count != 0) {
1649 assert(rhp.first.po != NULL);
1650 if (rhp.first.po != sourcePo &&
1652 rhp.first.po->triggeringMove(), trigger,
1653 triggerCycle)) {
1654 return rhp.first.realCycle;
1655 }
1656 if (rhp.second.po != sourcePo && rhp.second.count != 0) {
1657 assert(rhp.second.po != NULL);
1658 if (!exclusiveMoves(
1659 rhp.second.po->triggeringMove(), trigger,
1660 triggerCycle)) {
1661 return rhp.second.realCycle;
1662 }
1663 }
1664 }
1665 }
1666 return INT_MAX;
1667}
1668
1669/**
1670 * Returns cycle when result of some PO is ready.
1671 *
1672 * @param po programoperation
1673 * int resultReadCycle cycle when the result is read
1674 *
1675 * @TODO: multiple out values still not supported correctly.
1676 */
1678 const ProgramOperation& po, const TTAMachine::Port& resultPort) const {
1679
1680 MoveNode* trigger = po.triggeringMove();
1681 if (trigger == NULL || !trigger->isPlaced()) {
1682#ifdef DEBUG_RM
1683 std::cerr << "\t\t\t\tTrigger NULL or not scheduled: "
1684 << po.toString() << std::endl;
1685#endif
1686 return -1;
1687 }
1688
1689 const Operation& op = po.operation();
1691 for (int i = 0; i < op.numberOfOutputs(); i++) {
1692 int outIndex = op.numberOfInputs() + 1 + i;
1693 const TTAMachine::Port *p = hwop.port(outIndex);
1694 if (p == &resultPort) {
1695 return trigger->cycle() + hwop.latency(outIndex);
1696 }
1697 }
1698#ifdef DEBUG_RM
1699 std::cerr << "\t\t\t\treturning -1 at end of rrcycle() " << std::endl;
1700#endif
1701 return -1;
1702}
1703
1704/**
1705 * Checks whether both of two moves have exclusive guards so that
1706 * both moves are never executed, only either of those.
1707 * Those can then be scheduled to use same resources.
1708 *
1709 * This checks that the guards are exclusive, and that the moves are
1710 * to be scheduled in same cycle (one already scheduled, on is going to
1711 * be scheudled to given cycle, which has to be the same.
1712 * the same cycle requirements makes sure the value of the guard cannot be
1713 * changed between the moves.
1714 *
1715 * @param mn1 movenode which has already been scheduled
1716 * @param mn2 move which we are going to schedule
1717 * @param cycle cycle where we are going to scheudle mn2.
1718 */
1720 const MoveNode* mn1, const MoveNode* mn2, int cycle) const {
1721#ifdef NO_OVERCOMMIT
1722 return false;
1723#else
1724 if (mn1 == NULL || mn2 == NULL || !mn1->isMove() || !mn2->isMove()) {
1725 return false;
1726 }
1727
1728 if (mn1->move().isUnconditional() || mn2->move().isUnconditional()) {
1729 return false;
1730 }
1731
1732 if (ddg_ != NULL) {
1733 return ddg_->exclusingGuards(*mn1, *mn2);
1734 }
1735
1736 if (!mn1->move().guard().guard().isOpposite(mn2->move().guard().guard())) {
1737 return false;
1738 }
1739
1740 if (!mn1->isPlaced()) {
1741 return false;
1742 }
1743
1744 if ((mn2->isPlaced() && mn1->cycle() == mn2->cycle()) ||
1745 (!mn2->isPlaced() && (mn1->cycle() == cycle || cycle == INT_MAX))) {
1746 return true;
1747 }
1748 return false;
1749#endif
1750}
1751
1752/**
1753 * Clears bookkeeping of the scheduling resource.
1754 *
1755 * After this call the state of the resource should be identical to a
1756 * newly-created and initialized resource.
1757 */
1758void
1761 fuExecutionPipeline_.clear();
1762 resultWriten_.clear();
1763 operandsUsed_.clear();
1764 operandsWriten_.clear();
1765 resultRead_.clear();
1766 operandsWriten_.clear();
1767 storedResultCycles_.clear();
1768 assignedSourceNodes_.clear();
1770 cachedSize_ = 0;
1771 ddg_ = NULL;
1773}
1774
1775void
1779
1780/**
1781 * Tests the conflicts caused by results if a trigger
1782 * is scheduled to given cycle.
1783 */
1784bool
1786 const MoveNode& trigger, int cycle) const {
1787 ProgramOperation& po = trigger.destinationOperation();
1788 const Operation& op = po.operation();
1790
1791 // Loops over all output values produced by this
1792 for (int i = 0; i < op.numberOfOutputs(); i++) {
1793 int outIndex = op.numberOfInputs() + 1 + i;
1794 const TTAMachine::Port& port = *hwop.port(outIndex);
1795 int resultCycle = cycle + hwop.latency(outIndex);
1796
1798 resultCycle, po, port, trigger, cycle)) {
1799 return false;
1800 }
1801
1802 if (initiationInterval_ != 0 &&
1803 hwop.latency(outIndex) > (int)initiationInterval_) {
1804 return false;
1805 }
1806 }
1807
1808 // If we have alreayd scheduled some result, we have to make sure
1809 // nobody overwrites it.
1810 for (int i = 0; i < po.outputMoveCount(); i++) {
1811 MoveNode& mn = po.outputMove(i);
1812 if (mn.isPlaced()) {
1813 int outIndex = -1;
1814 if (mn.isSourceOperation() && &mn.sourceOperation() == &po) {
1815 assert(mn.move().source().isFUPort());
1816 outIndex = mn.move().source().operationIndex();
1817 } else {
1818 assert (mn.isGuardOperation() && &mn.guardOperation() == &po);
1819 outIndex = po.outputIndexFromGuardOfMove(mn);
1820 }
1821 const TTAMachine::Port& port = *hwop.port(outIndex);
1822 int resultCycle = cycle + hwop.latency(outIndex);
1823 // WAW conflict of result on same op on different iteration?
1824 if (initiationInterval_ != 0 && isLoopBypass(mn) && mn.cycle() >= resultCycle) {
1825#ifdef DEBUG_RM
1826 std::cerr << "\t\t\t\tresult move: " << mn.toString()
1827 << " schedule too late: " << resultCycle << std::endl;
1828#endif
1829 return false;
1830 }
1832 mn.cycle(), resultCycle, mn, port, &trigger, cycle)) {
1833 return false;
1834 }
1835 }
1836 }
1837 return true;
1838
1839}
1840
1841/**
1842 * Tests that a new result at given cycle does not mess up result of
1843 * some other operation
1844 *
1845 * @param resultCycle cycle when the nw result appears
1846 * @po Programoperation which the new result belongs to
1847 * @resultPort port where the result is written to
1848 * @trigger trigger movenode of the operation
1849 * @triggercycle cycle of the trigger
1850 */
1851bool
1853 int resultCycle, const ProgramOperation& po,
1854 const TTAMachine::Port& resultPort,
1855 const MoveNode& trigger, int triggerCycle)
1856 const {
1857
1858#ifdef DEBUG_RM
1859 if (&trigger != NULL) {
1860 std::cerr << "\t\tChecking that result for po: " << po.toString() << " allowed at cycle "
1861 << resultCycle << " , trigger: " << trigger.toString() << " at cycle: " << triggerCycle << std::endl;
1862 } else {
1863 std::cerr << "\t\tChecking that result for po: " << po.toString() << " allowed at cycle "
1864 << resultCycle << " , trigger: NULL at cycle: " << triggerCycle << std::endl;
1865 }
1866#endif
1867 // if none found from the map, this used.
1868 ResultVector empty;
1869 ResultMap::const_iterator rri = resultRead_.find(&resultPort);
1870
1871 const ResultVector& resultRead = (rri != resultRead_.end()) ?
1872 rri->second : empty;
1873
1874 unsigned int ii = initiationInterval_;
1875 if (ii < 1) {
1876 ii = INT_MAX;
1877 }
1878
1879 unsigned int rrSize = resultRead.size();
1880 unsigned int rrMod = instructionIndex(resultCycle);
1881 for (unsigned int i = rrMod; i < rrMod + ii; i++) {
1882 unsigned int modi = instructionIndex(i);
1883 bool modiLooped = modi < rrMod;
1884
1885 if (modi >= rrSize) {
1886 if (ii == INT_MAX) {
1887 break;
1888 } else {
1889 // may be read at small instr index of next iteration.
1890 // so may not abort, but can skip this cycle.
1891 continue;
1892 }
1893 }
1894 const ResultHelperPair& resultReadPair =
1896 if (resultReadPair.first.count > 0) {
1897 // same operation reading result again. cannot fail.
1898 if (resultReadPair.first.po != &po) {
1899 assert (resultReadPair.first.po != NULL);
1900
1901 // first check conflicts to first of po.
1902 MoveNode* otherTrigger =
1903 resultReadPair.first.po->triggeringMove();
1904 if (!exclusiveMoves(otherTrigger, &trigger, triggerCycle)) {
1905 if (resultReadPair.first.po == &po) {
1906 break;
1907 }
1908 // here check conflicts against first.
1909 int otherReady = resultReadyCycle(
1910 *resultReadPair.first.po, resultPort);
1911
1912 if (otherReady == -1) {
1913 otherReady = modi;
1914 }
1915 int or2Mod = instructionIndex(otherReady);
1916 bool orLooped = or2Mod > (int)modi; // FAIL HERE?
1917
1918#ifdef DEBUG_RM
1919 std::cerr << "\t\t\tOther po: " << resultReadPair.first.po->toString() << std::endl;
1920 std::cerr << "\t\t\tOther ready: " << otherReady << std::endl;
1921 std::cerr << "\t\t\tRR cycle: " << rrMod << std::endl;
1922 std::cerr << "\t\t\tOther ready mod: " << or2Mod << std::endl;
1923#endif
1924 // neither looped or both looped.
1925 if (modiLooped == orLooped) {
1926 if ((or2Mod <= (int)rrMod && or2Mod != -1) &&
1927 (triggerCycle == -1 || or2Mod != -1)) {
1928#ifdef DEBUG_RM
1929 std::cerr << "\t\t\t\tfail(1)" << std::endl;
1930#endif
1931 return false;
1932 } else {
1933 if (otherTrigger != NULL &&
1934 otherTrigger->move().isUnconditional()) {
1935 break;
1936 }
1937 }
1938 } else {
1939 // either one looped, order has to be reverse.
1940 if (or2Mod >= (int)rrMod && (triggerCycle == -1 || or2Mod != -1)) {
1941#ifdef DEBUG_RM
1942 std::cerr << "\t\t\t\tfail(2)" << std::endl;
1943#endif
1944 return false;
1945 } else {
1946 if (otherTrigger != NULL &&
1947 otherTrigger->move().isUnconditional()) {
1948 break;
1949 }
1950 }
1951 }
1952 }
1953 }
1954
1955 // then check conflicts to second po
1956 if (resultReadPair.second.count > 0) {
1957 MoveNode* otherTrigger =
1958 resultReadPair.second.po->triggeringMove();
1959 if (!exclusiveMoves(otherTrigger, &trigger, triggerCycle)) {
1960 if (resultReadPair.second.po == &po) {
1961 break;
1962 }
1963 int otherReady = resultReadyCycle(
1964 *resultReadPair.second.po, resultPort);
1965
1966 int or2Mod = instructionIndex(otherReady);
1967 bool orLooped = or2Mod > (int)modi;
1968
1969 // neither looped or both looped.
1970 if (modiLooped == orLooped) {
1971 if (or2Mod <= (int)rrMod &&
1972 (triggerCycle == -1 || or2Mod != -1)) {
1973#ifdef DEBUG_RM
1974 std::cerr << "\t\t\t\tfail(3)" << std::endl;
1975#endif
1976 return false;
1977 } else {
1978 if (otherTrigger != NULL &&
1979 otherTrigger->move().isUnconditional()) {
1980 break;
1981 }
1982 }
1983 } else {
1984 // either looped, order has to be reverse.
1985 if (or2Mod >= (int)rrMod &&
1986 (triggerCycle == -1 || or2Mod != -1)) {
1987#ifdef DEBUG_RM
1988 std::cerr << "\t\t\t\tfail(4)" << std::endl;
1989#endif
1990 return false;
1991 } else {
1992 if (otherTrigger != NULL &&
1993 otherTrigger->move().isUnconditional()) {
1994 break;
1995 }
1996 }
1997 }
1998 }
1999 }
2000 }
2001 }
2002 return true;
2003}
2004
2005//#undef DEBUG_RM
2006/**
2007 * Gives the port where from the movenode reads a result.
2008 */
2009const TTAMachine::Port&
2011 if (mn.isSourceOperation()) {
2012 const ProgramOperation& po = mn.sourceOperation();
2013 const TTAMachine::HWOperation& hwop =
2014 *fu_.operation(po.operation().name());
2015 return *hwop.port(mn.move().source().operationIndex());
2016 } else {
2018 return *(static_cast<const TTAMachine::PortGuard&>(
2019 mn.move().guard().guard())).port();
2020 }
2021}
2022
2023/**
2024 * Gives the port where from the movenode writes an operand.
2025 */
2026const TTAMachine::Port&
2029 const ProgramOperation& po = mn.destinationOperation();
2030 const TTAMachine::HWOperation& hwop =
2031 *fu_.operation(po.operation().name());
2032 return *hwop.port(mn.move().destination().operationIndex());
2033}
2034
2035/**
2036 * Returns if the result can be scheduled to given cycle
2037 * so that the results of other operations do not overwrite it.
2038 *
2039 * @param resultReadCycle cycle when the result is read
2040 * @param resultReadyCycle cycle when the result becomes available
2041 * @param po ProgramOperation where the result move belongs
2042 * @param node the result read node being scheduled
2043 * @param resultPort the port which is being read by the result
2044 * @param trigger Trigger of the program operation
2045 * @param triggercycle cycle of the trigger of the PO
2046 */
2047bool
2049 int resultReadCycle, int resultReadyCycle,
2050 const MoveNode& node, const TTAMachine::Port& resultPort,
2051 const MoveNode* trigger, int triggerCycle) const {
2052 unsigned int rrMod = instructionIndex(resultReadyCycle);
2053
2054 unsigned int modCycle = instructionIndex(resultReadCycle);
2055 unsigned int ii = initiationInterval_;
2056 if (ii < 1) {
2057 // no loop scheduling.
2058 ii = INT_MAX;
2059 } else {
2060 // loop scheudling.
2061 // make sure opeation does not cause conflict
2062 // with itself on next loop iteration.
2063 if (resultReadyCycle + (int)ii <= resultReadCycle) {
2064 return false;
2065 }
2066 }
2067 // Test when some other PO will write result to result register
2068 // starting from cycle when result could be ready
2069 int otherResult = nextResultCycle(
2070 resultPort, resultReadyCycle, node, trigger, triggerCycle);
2071 int orMod = instructionIndex(otherResult);
2072
2073 if (otherResult == INT_MAX && ii != INT_MAX) {
2074 orMod = INT_MAX;
2075 }
2076
2077 // overlaps between these.
2078 // TODO: these checks fail. true when no ii.
2079 if (orMod < (int)rrMod) {
2080 // overlaps between these. both overlap, oridinary comparison.
2081 if (modCycle < rrMod && orMod <= (int)modCycle) {
2082 // Result will be overwritten before we will read it
2083 return false;
2084 }
2085 // is cycle does not overlap, it's earlier, so does not fail.
2086 } else {
2087 // overlaps between these. it's later, fails.
2088 // neither overlaps. ordinary comparison.
2089 if ((rrMod != INT_MAX && orMod != INT_MAX && modCycle < rrMod) ||
2090 orMod <= (int)modCycle) {
2091 // Result will be overwritten before we will read it
2092#ifdef DEBUG_RM
2093 std::cerr << "\t\t\t\tresultnotoverwritten returning fail, rrmod:"
2094 << rrMod << " ormod: " << orMod << " modcycle: "
2095 << modCycle << std::endl;
2096#endif
2097 return false;
2098 }
2099 }
2100 return true;
2101}
2102
2103/**
2104 * Checks that no other operand of another op is written at exactly same cycle
2105 */
2107 const TTAMachine::Port& port, const MoveNode& mn, int cycle) const {
2108
2109 int modCycle = instructionIndex(cycle);
2110 // test that nobody writes operand at same cycle
2111 auto owi = operandsWriten_.find(&port);
2112 if (owi != operandsWriten_.end()) {
2113 const OperandWriteVector& owv = owi->second;
2114 auto owi2 = owv.find(modCycle);
2115 if (owi2 != owv.end()) {
2116 auto mnpp = owi2->second;
2117 if (mnpp.first != NULL &&
2118 (mnpp.second!=NULL || !exclusiveMoves(mnpp.first,&mn,cycle))){
2119#ifdef DEBUG_RM
2120 std::cerr << "MN of other op: " << mnpp.first->toString()
2121 << " writing to same port at same cycle"
2122 << std::endl;
2123#endif
2124 return false;
2125 }
2126 }
2127 }
2128 return true;
2129}
2130
2132 const TTAMachine::Port& port, const MoveNode& mn, int cycle) const {
2133#ifdef DEBUG_RM
2134 std::cerr << "\t\tTesting " << mn.toString() << " that operand at port: "
2135 << port.name() << " allowed at cycle: " << cycle << std::endl;
2136#endif
2137 int ii = initiationInterval();
2138 if (ii < 1) {
2139 ii = INT_MAX;
2140 }
2141
2142 OperandUseMap::const_iterator rui = operandsUsed_.find(&port);
2143 if (rui == operandsUsed_.end()) {
2144 return true;
2145 }
2146
2147 const OperandUseVector& operandUsed = rui->second;
2148 size_t operandUsedSize = operandUsed.size();
2149
2150 if (!mn.isDestinationOperation()) {
2151 throw InvalidData(__FILE__, __LINE__, __func__,
2152 "Trying to get next result for move that is not "
2153 "in ProgramOperation");
2154 }
2155
2156 // TODO: this may be very slow if big BB with not much code
2157 int nextOperandUseCycle = cycle;
2158 int nextOperandUseModCycle = instructionIndex(nextOperandUseCycle);
2159 OperandUseVector::const_iterator i =
2160 operandUsed.find(nextOperandUseModCycle);
2161
2162 while(true) {
2163#ifdef DEBUG_RM
2164 std::cerr << "\t\t\tTesting use from cycle: " << nextOperandUseCycle << std::endl;
2165#endif
2166 if (i != operandUsed.end()) {
2167#ifdef DEBUG_RM
2168 std::cerr << "\t\t\t\tcycle " << nextOperandUseCycle << " not empty." << std::endl;
2169#endif
2170 const OperandUseHelper& operandUse = i->second.first;
2171 if (operandUse.po != NULL) {
2172 const MoveNode* opUseTrigger =
2173 operandUse.po->triggeringMove();
2174 if (opUseTrigger != NULL) {
2175#ifdef DEBUG_RM
2176 std::cerr << "\t\t\t\tFound using trigger: " << opUseTrigger->toString() << std::endl;
2177#endif
2178 }
2179 if (!exclusiveMoves(opUseTrigger, &mn, cycle)) {
2180 /* destinationOperation(0) sounds suspicious */
2182 mn, port, cycle, operandUse, nextOperandUseModCycle,
2183 mn.destinationOperation(0))) {
2184 return false;
2185 }
2186 if (opUseTrigger == NULL ||
2187 opUseTrigger->move().isUnconditional()) {
2188 bool allScheduled = true;
2189 int imc = operandUse.po->inputMoveCount();
2190 for (int i = 0; i < imc; i++) {
2191 if (!operandUse.po->inputMove(i).isPlaced()) {
2192 allScheduled = false;
2193 break;
2194 }
2195 }
2196 if (allScheduled) {
2197 return true;
2198 }
2199 }
2200 }
2201 // conditional moves, second exclusive?
2202 const OperandUseHelper& operandUse2 = i->second.second;
2203 if (operandUse2.po != NULL) {
2204 const MoveNode& opUseTrigger2 =
2205 *operandUse2.po->triggeringMove();
2206 if (!exclusiveMoves(&opUseTrigger2, &mn, cycle)) {
2207 /* destinationOperation(0) sounds suspicious */
2209 mn, port, cycle, operandUse2,
2210 nextOperandUseModCycle,
2211 mn.destinationOperation(0))) {
2212 return false;
2213 }
2214 }
2215 }
2216 }
2217 }
2218 nextOperandUseCycle++;
2219
2220 if (ii == INT_MAX && nextOperandUseCycle >= (int)operandUsedSize) {
2221 return true;
2222 }
2223
2224 if (nextOperandUseCycle - cycle >= (int)ii) {
2225 return true;
2226 }
2227 nextOperandUseModCycle = instructionIndex(nextOperandUseCycle);
2228 i = operandUsed.find(nextOperandUseModCycle);
2229 }
2230
2231 return true;
2232}
2233
2235 const MoveNode& currentMn,
2236 const TTAMachine::Port& port,
2237 int operandWriteCycle,
2238 const OperandUseHelper &operandUse,
2239 int operandUseModCycle, ProgramOperation& currOp) const {
2240#ifdef DEBUG_RM
2241 std::cerr << "\t\t\t\tChecking operand allowed for port: " << port.name() << " owc: " << operandWriteCycle << " ouc: " << operandUseModCycle << " po: " << operandUse.po->toString() << std::endl;
2242#endif
2243 for (int i = 0; i < operandUse.po->inputMoveCount(); i++) {
2244 MoveNode& mn = operandUse.po->inputMove(i);
2245 if (mn.isPlaced()) {
2246 if (&mn.move().destination().port() == &port) {
2247#ifdef DEBUG_RM
2248 std::cerr << "\t\t\t\t\tInput node using same port: " << mn.toString() << std::endl;
2249#endif
2250 bool isCurrOp = false;
2251 for (unsigned int i = 0; i < mn.destinationOperationCount();
2252 i++) {
2253 if (&mn.destinationOperation(i) == &currOp) {
2254 isCurrOp = true;
2255 break;
2256 }
2257 }
2258 if (isCurrOp) {
2259 break;
2260 }
2261 // fail if the other operand happens eaelier than this (it has later usage).
2262
2263 // loop scheudling, op overlaps
2264 // need to also check that is not written before the use.
2265 if (operandUseModCycle <
2266 instructionIndex(mn.cycle())) {
2267 if (instructionIndex(operandWriteCycle) <=
2268 operandUseModCycle ||
2269 instructionIndex(mn.cycle()) <= instructionIndex(operandWriteCycle)) {
2270 if (!exclusiveMoves(&mn, &currentMn, mn.cycle()))
2271 return false;
2272 }
2273 }
2274 // not overlapping.
2275 if (instructionIndex(mn.cycle()) <=
2276 instructionIndex(operandWriteCycle) &&
2277 instructionIndex(operandWriteCycle) <=
2278 operandUseModCycle) {
2279 if (!exclusiveMoves(&mn, &currentMn, mn.cycle()))
2280 return false;
2281 }
2282 }
2283 }
2284 }
2285 return true;
2286}
2287
2288/**
2289 * Checks that operand is not scheduled too late(after trigger+slack)
2290 */
2291bool ExecutionPipelineResource::operandTooLate(const MoveNode& mn, int cycle) const {
2292 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
2294 MoveNode* trigger = po.triggeringMove();
2295 if (trigger == &mn) {
2296#ifdef DEBUG_RM
2297 std::cerr << "\t\t\tmn is trigger, no need to check overwrite" << std::endl;
2298#endif
2299 return false;
2300 }
2301 if (trigger == NULL || !trigger->isPlaced()) {
2302 continue;
2303 }
2304
2305 const Operation& op = po.operation();
2307
2308 int opIndex = mn.move().destination().operationIndex();
2309 int slack = hwop.slack(opIndex);
2310 const TTAMachine::FUPort& port = *hwop.port(opIndex);
2311 if (port.noRegister()) {
2312 if (cycle != trigger->cycle() + slack) {
2313 return true;
2314 }
2315 } else {
2316 if (cycle > trigger->cycle() + slack) {
2317 return true;
2318 }
2319 }
2320 }
2321 return false;
2322}
2323
2324/**
2325 * Checks that trigger is not scheduled too early(before operand-slack)
2326 */
2327bool ExecutionPipelineResource::triggerTooEarly(const MoveNode& trigger, int cycle) const {
2328 ProgramOperation& po = trigger.destinationOperation(0);
2329 const Operation& op = po.operation();
2331#ifdef DEBUG_RM
2332 std::cerr << "\t\t\t\tTesting if trigger too early for: " << trigger.toString() << " PO: " << po.toString() << std::endl;
2333#endif
2334 for (int i = 0; i < po.inputMoveCount(); i++) {
2335 MoveNode& mn = po.inputMove(i);
2336#ifdef DEBUG_RM
2337 std::cerr << "\t\t\t\tTesting operand: " << mn.toString() << std::endl;
2338#endif
2339 if (mn.isPlaced()) {
2340#ifdef DEBUG_RM
2341 std::cerr << "\t\t\t\tCycle: " << mn.cycle() << ", ";
2342#endif
2343 int slack = hwop.slack(mn.move().destination().operationIndex());
2344 const TTAMachine::Port& port = mn.move().destination().port();
2345 const TTAMachine::FUPort& fuPort =
2346 dynamic_cast<const TTAMachine::FUPort&>(port);
2347
2348#ifdef DEBUG_RM
2349 std::cerr << "slack(" << mn.move().destination().operationIndex()
2350 << ")=" << slack << ", noReg=" << fuPort.noRegister()
2351 << std::endl;
2352#endif
2353
2354 if (fuPort.noRegister()) {
2355 if (cycle != mn.cycle() - slack) {
2356 return true;
2357 }
2358 } else {
2359 if (cycle < mn.cycle() - slack) {
2360 return true;
2361 }
2362 }
2363 }
2364 }
2365 return false;
2366}
2367
2368bool
2370 int inputCount,
2372 hwop, const MoveNode& node,
2373 int cycle) const {
2374 for (int i = 1; i <= inputCount; i++) {
2375 TTAMachine::FUPort& port = *hwop.port(i);
2376 if (!operandAllowedAtCycle(port, node, cycle)) {
2377 return false;
2378 }
2379 }
2380 return true;
2381}
2382
2383
2384/**
2385 * Returns the lates cycle the given trigger move can be scheduled at,
2386 * taking in the account the latency of the operation results.
2387 *
2388 * In case the none of the result moves has been scheduled yet,
2389 * returns INT_MAX.
2390 *
2391 * @exception IllegalObject if this MoveNode is not a result read.
2392 */
2394 const MoveNode& mn) const {
2395
2396 if (!mn.isDestinationOperation())
2397 throw IllegalParameters(
2398 __FILE__, __LINE__, __func__, "Not a result read move.");
2399
2400 const ProgramOperation& po = mn.destinationOperation();
2401 int latestTrigger = INT_MAX;
2402 for (int i = 0; i < po.outputMoveCount(); i++){
2403 MoveNode& result = po.outputMove(i);
2404 if (!result.isScheduled()) {
2405 continue;
2406 }
2407
2408 int resultCycle = (initiationInterval_ != 0 && isLoopBypass(result)) ?
2409 result.cycle() + initiationInterval_ :
2410 result.cycle();
2411
2412 auto fu = po.fuFromOutMove(result);
2413 // find the latency of the operation output we are testing
2414 const TTAMachine::HWOperation& hwop =
2415 *fu->operation(po.operation().name());
2416
2417 // find the OSAL id of the operand of the output we are testing
2418 const int outputIndex = po.outputIndexOfMove(result);
2419 int latency = hwop.latency(outputIndex);
2420 latestTrigger = std::min(latestTrigger, resultCycle - latency);
2421 }
2422 return latestTrigger;
2423}
2424
2426 const TTAMachine::Port& port, const MoveNode& mn, int cycle) const {
2427
2428 // find last scheduled trigger cycle
2429 int triggerCycle = -1;
2430 std::set<ProgramOperation*, ProgramOperation::Comparator> poSet;
2431 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
2433 MoveNode* trigger = po.triggeringMove();
2434 if (trigger != NULL && trigger->isScheduled()) {
2435 triggerCycle = std::max(triggerCycle, trigger->cycle());
2436 }
2437 }
2438
2439 // then test each of these cycles.
2440 for (int i = cycle; i <= triggerCycle; i++) {
2441 // has other trigger in this cycle?
2442
2443 auto opUse = operandsUsed_.find(&port);
2444 if (opUse == operandsUsed_.end())
2445 continue;
2446
2447 unsigned int modCycle = instructionIndex(i);
2448 auto oupIter = opUse->second.find(modCycle);
2449 if (oupIter == opUse->second.end())
2450 continue;
2451
2452 auto& oup = oupIter->second;
2453 // no trigger on this cycle?
2454 if (oup.first.po == NULL)
2455 continue;
2456
2457 // own op reading result on this cycle
2458 if (isDestOpOfMN(mn, *oup.first.po))
2459 continue;
2460
2461 if (oup.second.po == NULL) {
2462 if (exclusiveMoves(&mn, oup.first.po->triggeringMove(), i)) {
2463 continue;
2464 } else {
2465 return true;
2466 }
2467 }
2468 if (isDestOpOfMN(mn, *oup.second.po)) {
2469 continue;
2470 } else {
2471 return true;
2472 }
2473 }
2474 return false;
2475}
2476
2478 const MoveNode& mn, const ProgramOperation& po) const {
2479 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
2481 if (&p == &po) {
2482 return true;
2483 }
2484 }
2485 return false;
2486}
2487
2489 const MoveNode& mn, int cycle) const {
2490
2491 if (!operandShareCount_) {
2492 return false;
2493 }
2494
2495 if (!mn.isSourceOperation()) {
2496 return false;
2497 }
2499 const MoveNode* trigger = po.findTriggerFromUnit(fu_);
2500 // if trigger is already scheduled, the checks have been done
2501 // while scheduling it.
2502 if (trigger == nullptr || trigger->isScheduled()) {
2503 return false;
2504 }
2505 const int outputIndex = po.outputIndexOfMove(mn);
2506 const TTAMachine::HWOperation& hwop =
2507 *fu_.operation(po.operation().name());
2508 const TTAMachine::Port* outPort = hwop.port(outputIndex);
2509 int latency = hwop.latency(outputIndex);
2510 int latestTriggerCycle = cycle - latency;
2511
2512 std::map<const TTAMachine::Port*, const MoveNode*> usedOperandPorts;
2513
2514 // result vector for the correct port
2515 auto rvi = resultRead_.find(outPort);
2516 if (rvi == resultRead_.end()) {
2517 return false;
2518 }
2519 auto& rv = rvi->second;
2520
2521 int smallestCycle = (*rv.begin()).first;
2522 int earliestAllowedResReady = -1;
2523
2524 for (int c = cycle-1;c >= smallestCycle;c--) {
2525 int mc = instructionIndex(c);
2526 auto ri = rv.find(mc);
2527 if (ri == rv.end()) {
2528 continue;
2529 }
2530 auto res = ri->second;
2531 ResultHelper& rh1 = res.first;
2532 ResultHelper& rh2 = res.second;
2533
2534 if (rh1.po != nullptr && rh1.po != &po) {
2535 int rc = rh1.realCycle;
2536 if (!exclusiveMoves(trigger, rh1.po->triggeringMove(), c-latency)) {
2537 earliestAllowedResReady = rc +1;
2538 break;
2539 }
2540 }
2541
2542 if (rh2.po != nullptr && rh2.po != &po) {
2543 int rc = rh2.realCycle;
2544 if (!exclusiveMoves(trigger, rh2.po->triggeringMove(), c-latency)) {
2545 earliestAllowedResReady = rc +1;
2546 break;
2547 }
2548 }
2549 }
2550
2551 if (earliestAllowedResReady == -1) {
2552 return false;
2553 }
2554
2555 int earliestTriggerCycle = earliestAllowedResReady - latency;
2556
2557 // if overlaps between earliest and last trigger
2558 if (earliestTriggerCycle > latestTriggerCycle &&
2559 initiationInterval_ != 0) {
2560 earliestTriggerCycle -= initiationInterval_;
2561 }
2562
2563#ifdef DEBUG_RM
2564 std::cerr << "\t\t\t\tEarliest allowed res ready: "
2565 << earliestAllowedResReady << std::endl;
2566 std::cerr << "\t\t\t\tEarliestTrigger cycle: "
2567 << earliestTriggerCycle << std::endl;
2568 std::cerr << "\t\t\t\tLatestTrigger cycle: "
2569 << latestTriggerCycle << std::endl;
2570#endif
2571
2572 bool ok = false;
2573 for (int c = latestTriggerCycle; c >= earliestTriggerCycle && !ok ; c--) {
2574
2575 bool fail = false;
2576 for (int i = 0; i < po.inputMoveCount(); i++) {
2577 const MoveNode& inMove = po.inputMove(i);
2578 if (!inMove.move().destination().isFUPort()) {
2579 continue;
2580 }
2581 const int inputIndex =
2582 inMove.move().destination().operationIndex();
2583 const TTAMachine::HWOperation& hwop =
2584 *fu_.operation(po.operation().name());
2585 auto inPort = hwop.port(inputIndex);
2586 if (!inPort->isTriggering()) {
2587 if (!operandAllowedAtCycle(*inPort, inMove,c)) {
2588 fail = true;
2589#ifdef DEBUG_RM
2590 std::cerr << "\t\t\t\t\tOperand not allowed at cycle: " << c << std::endl;
2591#endif
2592 continue;
2593 }
2594 }
2595 }
2596 if (!fail) {
2597 return false;
2598 }
2599 }
2600 return true;
2601}
2602
2603
2604
2606 const TTAMachine::Port& port, const MoveNode& mn, int cycle) const {
2607
2608 if (mn.destinationOperationCount() < 2) {
2609 return false;
2610 }
2611
2612 std::map<const TTAMachine::FUPort*, std::set<int> > myActualResultCycles;
2613
2614 // cycle range these operand shared ops may use the output port.
2615 std::map<const TTAMachine::FUPort*, std::pair<int, int> > myResultCycles;
2616
2617 // earliest possible cycle of the last trigger of these operand shared ops
2618 // can have.
2619 int lastTriggerCycle = -1;
2620 // needed for calculating the trigger cycle
2621 const MoveNode* prevOutmove = nullptr;
2622 int prevLatency = 0;
2623
2624 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
2626 MoveNode* trigger = po.triggeringMove();
2627 if (trigger != nullptr && trigger->isScheduled()) {
2628 assert(trigger->cycle() >= cycle);
2629 if (trigger->cycle() > lastTriggerCycle) {
2630 lastTriggerCycle = trigger->cycle();
2631 prevOutmove = nullptr;
2632 prevLatency = 0;
2633 }
2634 }
2635
2636 for (int j = 0; j < po.outputMoveCount(); j++) {
2637 const MoveNode& outMove = po.outputMove(j);
2638 if (!outMove.move().source().isFUPort()) {
2639 continue;
2640 }
2641
2642 const int outputIndex = po.outputIndexOfMove(outMove);
2643 const TTAMachine::HWOperation& hwop =
2644 *fu_.operation(po.operation().name());
2645 int latency = hwop.latency(outputIndex);
2646 auto outPort = hwop.port(outputIndex);
2647 auto outPortIter = myResultCycles.find(outPort);
2648 // [] operator would init to 0 which would break min.
2649 if (outPortIter == myResultCycles.end()) {
2650 // initialize to be free.
2651 myResultCycles[outPort] = std::make_pair(INT_MAX, -1);
2652 }
2653
2654 if (outMove.isScheduled()) {
2655 const TTAMachine::FUPort* outPort =
2656 static_cast<const TTAMachine::FUPort*>(
2657 &outMove.move().source().port());
2658
2659 myResultCycles[outPort].second = std::max(
2660 myResultCycles[outPort].second, outMove.cycle());
2661
2662 myResultCycles[outPort].first = std::min(
2663 myResultCycles[outPort].first, outMove.cycle());
2664
2665 // Is really used during this cycle.
2666 myActualResultCycles[outPort].insert(
2668
2669 if (trigger == nullptr || !trigger->isScheduled()) {
2670 int optimalTriggerCycle = outMove.cycle() - latency;
2671 if (optimalTriggerCycle > lastTriggerCycle) {
2672 // the trigger cycle was exact,
2673 // based on scheduled trigger
2674 // now make it inexact.
2675 if (prevOutmove == nullptr) {
2676 lastTriggerCycle++;
2677 prevOutmove = &outMove;
2678 prevLatency = latency;
2679 } else {
2680 // was already based on outmove, not trigger.
2681 // need to calculate the earlierst cycle for this
2682 // trigger
2683 // so that it does not prevewrite the prev result.
2684 int prevTriggerCycle =
2685 prevOutmove->cycle() - prevLatency;
2686 lastTriggerCycle = prevTriggerCycle + 1;
2687
2688 prevOutmove = &outMove;
2689 prevLatency = latency;
2690 }
2691 }
2692 } else { // trigger is scheduled.
2693 int resultReady = trigger->cycle() + latency;
2694 for (int i = outMove.cycle(); i >= resultReady; i--) {
2695 myActualResultCycles[outPort].insert(
2696 instructionIndex(i));
2697 }
2698 }
2699
2700 } else { // out move not scheduled.
2701 if (trigger != nullptr && trigger->isScheduled()) {
2702 myActualResultCycles[outPort].insert(
2703 instructionIndex(trigger->cycle() + latency));
2704
2705 myResultCycles[outPort].second = std::max(
2706 myResultCycles[outPort].second,
2707 trigger->cycle() + latency);
2708
2709 myResultCycles[outPort].first = std::min(
2710 myResultCycles[outPort].first,
2711 trigger->cycle() + latency);
2712 }
2713
2714 }
2715 }
2716 }
2717
2718 // loop through all result ports used by the operand.
2719 for (auto p : myResultCycles) {
2720
2721 auto& myActualResCycles = myActualResultCycles[p.first];
2722 // result read vector for that port
2723 auto rri = resultRead_.find(p.first);
2724 // first and last cycles for that port.
2725 int myFirstResultCycle = p.second.first;
2726 int myLastResultCycle = p.second.second;
2727
2728 // modulo versions of these cycles
2729 int myFirstModResult = instructionIndex(myFirstResultCycle);
2730 int myLastModResult = instructionIndex(myLastResultCycle);
2731
2732 // no bookkeeping for this result port? Cannot conflict.
2733 if (rri == resultRead_.end()) {
2734 continue;
2735 }
2736 auto& resVec = rri->second;
2737
2738 for (auto& res : resVec) {
2739 int anotherResCycle = res.first;
2740 int anotherResModCycle = instructionIndex(anotherResCycle);
2741 assert(anotherResCycle == anotherResModCycle);
2742
2743 // IF found fromt he actual result cycles, have to check.
2744 if (myActualResCycles.find(anotherResModCycle)
2745 == myActualResCycles.end()) {
2746 // the range overlaps
2747 if (myLastModResult < myFirstModResult) {
2748 // before first but after overlapped last, ok
2749 if (anotherResModCycle < myFirstModResult &&
2750 anotherResModCycle > myLastModResult)
2751 continue;
2752 } else { // no overlap.
2753 // Before first of after last is ok.
2754 if (anotherResModCycle < myFirstModResult ||
2755 anotherResModCycle > myLastModResult)
2756 continue;
2757 }
2758 }
2759 auto& foo = res.second;
2760 const ResultHelper& rh1 = foo.first;
2761 const ResultHelper& rh2 = foo.second;
2762 if (rh1.po != nullptr) {
2763 int rc = rh1.realCycle;
2764 MoveNode* trigger = rh1.po->triggeringMove();
2765 if (!trigger->isScheduled() &&
2766 poConflictsWithInputPort(port, *rh1.po, mn)) {
2767 const TTAMachine::HWOperation& hwop =
2768 *fu_.operation(rh1.po->operation().name());
2769 int outIndex = hwop.io(*p.first);
2770 int latency = hwop.latency(outIndex);
2771 bool foundWorkingCycle = false;
2772 // try to find a legal cycle for the trigger of other op
2773 for (int i = rc;
2774 myActualResCycles.find(instructionIndex(i)) ==
2775 myActualResCycles.end(); i--) {
2776 int otherTriggerCycle = i - latency;
2777 if (!cyclesConflict(
2778 &mn, trigger, cycle, cycle, lastTriggerCycle,
2779 otherTriggerCycle)) {
2780 foundWorkingCycle = true;
2781 }
2782 }
2783 // did not found a legal place for the trigger?
2784 if (!foundWorkingCycle) {
2785 return true;
2786 }
2787 }
2788 }
2789
2790 if (rh2.po != nullptr) {
2791 int rc = rh2.realCycle;
2792 MoveNode* trigger = rh2.po->triggeringMove();
2793 if (!trigger->isScheduled() &&
2794 poConflictsWithInputPort(port, *rh2.po, mn)) {
2795 const TTAMachine::HWOperation& hwop =
2796 *fu_.operation(rh2.po->operation().name());
2797 int outIndex = hwop.io(*p.first);
2798 int latency = hwop.latency(outIndex);
2799 bool foundWorkingCycle = false;
2800 // try to find a legal cycle for the trigger of other op
2801 for (int i = rc;
2802 myActualResCycles.find(i) == myActualResCycles.end();
2803 i--) {
2804 assert (i > myFirstResultCycle);
2805 int otherTriggerCycle = i - latency;
2806 if (!cyclesConflict(
2807 &mn, trigger, cycle, cycle, lastTriggerCycle,
2808 otherTriggerCycle)) {
2809 foundWorkingCycle = true;
2810 }
2811 }
2812 // did not found a legal place for the trigger?
2813 if (!foundWorkingCycle) {
2814 return true;
2815 }
2816 }
2817 }
2818 }
2819 }
2820 return false;
2821}
2822
2824 int rangeFirst, int rangeLast, int targetCycle) const {
2825 int rangeFirstMod = instructionIndex(rangeFirst);
2826 int rangeLastMod = instructionIndex(rangeLast);
2827 int targetCycleMod = instructionIndex(targetCycle);
2828
2829 // no overlap for the range
2830 if (rangeFirstMod <= rangeLastMod) {
2831 return targetCycleMod >= rangeFirstMod &&
2832 targetCycleMod <= rangeLastMod;
2833 } else { // overlaps.
2834 return targetCycleMod >= rangeFirstMod ||
2835 targetCycleMod <= rangeLastMod;
2836 }
2837}
2838
2839/*
2840 * mn1 move osed for exclusive check
2841 * mn2 another move used for exclusive check
2842 */
2844 const MoveNode* mn1, const MoveNode* mn2, int guardCycle,
2845 int rangeFirst, int rangeLast, int targetCycle) const {
2846 if (exclusiveMoves(mn1, mn2, guardCycle)) {
2847 return false;
2848 }
2849 return cyclesOverlap (rangeFirst, rangeLast, targetCycle);
2850}
2851
2852
2854 const ProgramOperation& po, TTAMachine::Port& port) {
2855
2856 const Operation& op = po.operation();
2857 auto hwop = fu_.operation(op.name());
2858 if (!hwop->isBound(static_cast<TTAMachine::FUPort&>(port))) {
2859 return nullptr;
2860 }
2861 int idx = hwop->io(static_cast<TTAMachine::FUPort&>(port));
2862 return *po.inputNode(idx).begin();
2863}
2864
2865
2867 const TTAMachine::Port& port,
2868 const ProgramOperation& po,
2869 const MoveNode& mn) const {
2870
2871 const TTAMachine::FunctionUnit* fu =
2872 static_cast<const TTAMachine::FunctionUnit*>(port.parentUnit());
2873
2874
2875 for (int i = 0; i < po.inputMoveCount(); i++) {
2876 MoveNode& in = po.inputMove(i);
2877 if (&mn == &in) {
2878 return false;
2879 }
2880 TTAProgram::Terminal& dest = in.move().destination();
2881 if (!dest.isFUPort()) {
2882 continue;
2883 }
2884 const TTAMachine::BaseFUPort* fup =
2885 static_cast<const TTAMachine::BaseFUPort*>(&dest.port());
2886 if (fup == &port) {
2887 return true;
2888 }
2889 }
2890
2891 if (fu != nullptr) {
2892 const Operation& op = po.operation();
2893 auto hwop = fu->operation(op.name());
2894 for (int i = 1; i <= op.numberOfInputs(); i++) {
2895 auto p = hwop->port(i);
2896 if (p == &port) {
2897 return true;
2898 }
2899 }
2900 }
2901 return false;
2902}
#define __func__
#define abortWithError(message)
#define assert(condition)
bool hasNode(const Node &) const
virtual EdgeSet inEdges(const Node &node) const
static std::string toString(const T &source)
EdgeReason edgeReason() const
bool exclusingGuards(const MoveNode &mn1, const MoveNode &mn2) const
std::string errorMessage() const
Definition Exception.cc:123
unsigned int maximalLatency() const
bool hasOperation(const std::string &opName) const
int operationIndex(const std::string &opName) const
bool operationPipeline(int op, int cycle, int res) const
unsigned int numberOfResources() const
void unsetOperandsUsed(const ProgramOperation &po, unsigned int triggerCycle)
bool hasConflictingResultsOnCycle(const ProgramOperation &po, const TTAMachine::Port &port, int cycle) const
const TTAMachine::FunctionUnit & fu_
const TTAMachine::Port & resultPort(const MoveNode &mn) const
ResourceReservationTable fuExecutionPipeline_
Stores one resource vector per cycle of scope for whole FU.
virtual void assignDestination(const int cycle, MoveNode &node)
std::multimap< int, MoveNode * > assignedDestinationNodes_
bool resultNotOverWritten(int resultReadCycle, int resultReadyCycle, const MoveNode &node, const TTAMachine::Port &port, const MoveNode *trigger, int triggerCycle) const
virtual bool canAssignSource(int cycle, const MoveNode &node, const TTAMachine::Port &resultPort) const
bool exclusiveMoves(const MoveNode *mn1, const MoveNode *mn2, int cycle=INT_MAX) const
bool operandOverwritten(int operandWriteCycle, int triggerCycle, const ProgramOperation &po, const MoveNode &operand, const MoveNode &trigger) const
std::map< MoveNode *, int, MoveNode::Comparator > storedResultCycles_
bool operandSharePreventsTriggerForScheduledResult(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
virtual bool isExecutionPipelineResource() const override
void setOperandsUsed(const ProgramOperation &po, unsigned int triggerCycle)
void setOperandUsed(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
const TTAMachine::Port & operandPort(const MoveNode &mn) const
bool testTriggerResult(const MoveNode &trigger, int cycle) const
bool resultAllowedAtCycle(int resultCycle, const ProgramOperation &po, const TTAMachine::Port &resultPort, const MoveNode &trigger, int triggerCycle) const
virtual bool validateRelatedGroups() override
int resultReadyCycle(const ProgramOperation &po, const TTAMachine::Port &resultPort) const
bool operandAllowedAtCycle(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
void setResultWriten(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
virtual void assignSource(int cycle, MoveNode &node)
int nextResultCycle(const TTAMachine::Port &port, int cycle, const MoveNode &node, const MoveNode *trigger=NULL, int triggerCycle=INT_MAX) const
bool isLoopBypass(const MoveNode &node) const
bool isDestOpOfMN(const MoveNode &mn, const ProgramOperation &po) const
bool poConflictsWithInputPort(const TTAMachine::Port &port, const ProgramOperation &po, const MoveNode &mn) const
bool operandsOverwritten(int triggerCycle, const MoveNode &trigger) const
virtual bool canAssign(const int cycle, const MoveNode &node) const override
virtual void unassignSource(const int cycle, MoveNode &node)
bool cyclesConflict(const MoveNode *mn1, const MoveNode *mn2, int guardCycle, int rangeFirst, int rangeLast, int targetCycle) const
bool cyclesOverlap(int rangeFirst, int rangeLast, int targetCycle) const
void unsetResultWriten(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
std::pair< ResultHelper, ResultHelper > ResultHelperPair
const ExecutionPipelineResourceTable * resources
bool operandTooLate(const MoveNode &node, int cycle) const
std::multimap< int, MoveNode * > assignedSourceNodes_
std::vector< ResourceReservation > ResourceReservationVector
Type for resource vector, represents one cycle of use. Includes the ownerships of the reservation.
virtual bool validateDependentGroups() override
virtual void unassign(const int cycle, MoveNode &node) override
bool checkOperandAllowed(const MoveNode &currentMn, const TTAMachine::Port &port, int operandWriteCycle, const OperandUseHelper &operandUse, int operandUseModCycle, ProgramOperation &currOp) const
void unsetOperandUsed(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
int latestTriggerWriteCycle(const MoveNode &mn) const
std::pair< const MoveNode *, const MoveNode * > ResourceReservation
bool triggerAllowedAtCycle(int inputCount, const TTAMachine::HWOperation &hwop, const MoveNode &node, int cycle) const
std::pair< OperandUseHelper, OperandUseHelper > OperandUsePair
virtual void assign(const int cycle, MoveNode &node) override
void setDDG(const DataDependenceGraph *ddg)
virtual bool canAssignDestination(const int cycle, const MoveNode &node, const bool triggering=false) const
bool operandPossibleAtCycle(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
std::pair< MoveNode *, MoveNode * > MoveNodePtrPair
const DataDependenceGraph * ddg_
bool otherTriggerBeforeMyTrigger(const TTAMachine::Port &port, const MoveNode &node, int cycle) const
ExecutionPipelineResource(const TTAMachine::FunctionUnit &fu, const unsigned int ii=0)
virtual void unassignDestination(const int cycle, MoveNode &node)
virtual bool isInUse(const int cycle) const override
bool resourcesAllowTrigger(int cycle, const MoveNode &move) const
bool triggerTooEarly(const MoveNode &trigger, int cycle) const
const MoveNode * nodeOfInputPort(const ProgramOperation &po, TTAMachine::Port &port)
virtual bool isAvailable(const int cycle) const override
bool resultCausesTriggerBetweenOperandSharing(const MoveNode &mn, int cycle) const
static KeyType keyForValue(const MapType &aMap, const ValueType &aValue)
static bool removeItemsByValue(MapType &aMap, const ValueType &aValue)
static bool containsKey(const MapType &aMap, const KeyType &aKey)
static bool containsValue(const MapType &aMap, const ValueType &aValue)
int count() const
MoveNode & at(int index)
std::vector< MoveNode * >::iterator begin()
int earliestResultReadCycle() const
Definition MoveNode.cc:652
unsigned int destinationOperationCount() const
bool isGuardOperation() const
Definition MoveNode.cc:181
int cycle() const
Definition MoveNode.cc:421
bool isMove() const
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
bool isDestinationOperation() const
std::string toString() const
Definition MoveNode.cc:576
ProgramOperation & guardOperation() const
Definition MoveNode.cc:479
bool isPlaced() const
Definition MoveNode.cc:352
TTAProgram::Move & move()
bool isSourceOperation() const
Definition MoveNode.cc:168
bool isScheduled() const
Definition MoveNode.cc:409
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual TCEString name() const
Definition Operation.cc:93
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual int numberOfOutputs() const
Definition Operation.cc:202
int outputMoveCount() const
const Operation & operation() const
MoveNode * findTriggerFromUnit(const TTAMachine::Unit &unit) const
int outputIndexFromGuardOfMove(const MoveNode &node) const
int inputMoveCount() const
MoveNode * triggeringMove() const
MoveNodeSet & inputNode(int in) const
std::string toString() const
MoveNode & inputMove(int index) const
const TTAMachine::FunctionUnit * fuFromOutMove(const MoveNode &outputNode) const
MoveNode & outputMove(int index) const
int outputIndexOfMove(const MoveNode &mn) const
MoveNodeSet & outputNode(int out) const
virtual SchedulingResource & relatedResource(const int group, const int index) const
int instructionIndex(int cycle) const
int relatedResourceCount(const int group) const
virtual bool isInputPSocketResource() const
virtual const std::string & name() const
virtual int relatedResourceGroupCount() const
size_t size() const
bool noRegister() const
Definition FUPort.cc:469
virtual HWOperation * operation(const std::string &name) const
virtual BaseFUPort * port(const std::string &name) const
virtual bool isOpposite(const Guard &guard) const =0
virtual FUPort * port(int operand) const
int io(const FUPort &port) const
int slack(int input) const
Unit * parentUnit() const
virtual std::string name() const
Definition Port.cc:141
virtual int portCount() const
Definition Unit.cc:135
const TTAMachine::Guard & guard() const
Definition MoveGuard.cc:86
MoveGuard & guard() const
Definition Move.cc:345
bool isUnconditional() const
Definition Move.cc:154
Terminal & source() const
Definition Move.cc:302
Terminal & destination() const
Definition Move.cc:323
virtual bool isTriggering() const
Definition Terminal.cc:298
virtual Operation & hintOperation() const
Definition Terminal.cc:341
virtual bool isOpcodeSetting() const
Definition Terminal.cc:285
virtual Operation & operation() const
Definition Terminal.cc:319
virtual int operationIndex() const
Definition Terminal.cc:364
virtual const TTAMachine::Port & port() const
Definition Terminal.cc:378
virtual bool isFUPort() const
Definition Terminal.cc:118