OpenASIP  2.0
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"
53 #include "OutputPSocketResource.hh"
54 #include "InputPSocketResource.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"
62 #include "DataDependenceGraph.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  */
83  const TTAMachine::FunctionUnit& fu,
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  */
101 bool
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  */
116 bool
117 ExecutionPipelineResource::isInUse(const int cycle) const {
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 &&
136  (MapTools::valueForKeyNoThrow<ResultHelperPair>(
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  }
146  if (resources->numberOfResources() !=
147  (MapTools::valueForKeyNoThrow<ResourceReservationVector>(
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 =
154  MapTools::valueForKeyNoThrow<ResourceReservationVector>(
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  */
177 bool
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  */
210 void
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  */
240 void
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 
265 void
267  const ProgramOperation& po, unsigned int triggerCycle) {
268 
269  const Operation& op = po.operation();
270  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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 
282 void
284  const ProgramOperation& po, unsigned int triggerCycle) {
285 
286  const Operation& op = po.operation();
287  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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  */
304 void
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 
335 void
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 
359 void
361  const ProgramOperation& po, unsigned int triggerCycle) {
362 
363  const Operation& op = po.operation();
364  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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 
376 void
378  const ProgramOperation& po, unsigned int triggerCycle) {
379 
380  const Operation& op = po.operation();
381  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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 
391 void
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  */
404 void
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  */
486 void
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
510  assert(node.destinationOperationCount() == 1);
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  }
532  ResourceReservation& rr =
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 
581 void
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  */
596 void
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];
616  ProgramOperation& po = node.isSourceOperation() ?
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 =
628  MapTools::valueForKey<int>(storedResultCycles_, &node);
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  */
675 void
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 
730  assert(node.destinationOperationCount() == 1);
731 
732  unsetOperandsUsed(node.destinationOperation(), cycle);
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);
767  ResourceReservation& rr =
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  */
818 bool
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;
880  return resultNotOverWritten(
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 
973  if (resultCausesTriggerBetweenOperandSharing(node, cycle)) {
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  */
989 bool
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 
1095  if (!triggerAllowedAtCycle(
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();
1156  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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()) {
1228  if (operandOverwritten(
1229  triggerCycle, triggerCycle, po, inputMove, trigger)) {
1230  return true;
1231  }
1232  continue;
1233  }
1234  int operandWriteCycle = inputMove.cycle();
1235  if (operandOverwritten(
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  */
1377 bool
1379  return true;
1380 }
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  */
1387 bool
1389  return true;
1390 }
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  */
1398 bool
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  */
1416 unsigned 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  */
1478 int
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 =
1520  MapTools::valueForKeyNoThrow<ResultHelperPair>(
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 =
1539  MapTools::valueForKeyNoThrow<ResultHelperPair>(
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 
1558 bool
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 =
1570  MapTools::valueForKeyNoThrow<ResultHelperPair>(
1571  rwi->second, modCycle);
1572 
1573  if (rhp.first.count != 0) {
1574  assert(rhp.first.po != NULL);
1575  if (rhp.first.po != &po &&
1576  !exclusiveMoves(
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  */
1601 int
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 =
1647  MapTools::valueForKeyNoThrow<ResultHelperPair>(resultWriten,modi);
1648  if (rhp.first.count != 0) {
1649  assert(rhp.first.po != NULL);
1650  if (rhp.first.po != sourcePo &&
1651  !exclusiveMoves(
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  */
1758 void
1761  fuExecutionPipeline_.clear();
1762  resultWriten_.clear();
1763  operandsUsed_.clear();
1764  operandsWriten_.clear();
1765  resultRead_.clear();
1766  operandsWriten_.clear();
1767  storedResultCycles_.clear();
1768  assignedSourceNodes_.clear();
1769  assignedDestinationNodes_.clear();
1770  cachedSize_ = 0;
1771  ddg_ = NULL;
1772  operandShareCount_ = 0;
1773 }
1774 
1775 void
1777  ddg_ = ddg;
1778 }
1779 
1780 /**
1781  * Tests the conflicts caused by results if a trigger
1782  * is scheduled to given cycle.
1783  */
1784 bool
1786  const MoveNode& trigger, int cycle) const {
1787  ProgramOperation& po = trigger.destinationOperation();
1788  const Operation& op = po.operation();
1789  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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 
1797  if (!resultAllowedAtCycle(
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  }
1831  if (!resultNotOverWritten(
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  */
1851 bool
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 =
1895  MapTools::valueForKeyNoThrow<ResultHelperPair>(resultRead, modi);
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  */
2009 const 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 {
2017  assert(mn.isGuardOperation());
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  */
2026 const 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  */
2047 bool
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 */
2181  if (!checkOperandAllowed(
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 */
2208  if (!checkOperandAllowed(
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  */
2291 bool 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();
2306  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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  */
2327 bool ExecutionPipelineResource::triggerTooEarly(const MoveNode& trigger, int cycle) const {
2328  ProgramOperation& po = trigger.destinationOperation(0);
2329  const Operation& op = po.operation();
2330  TTAMachine::HWOperation& hwop = *fu_.operation(op.name());
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 
2368 bool
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  }
2498  ProgramOperation& po = mn.sourceOperation();
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 }
ProgramOperation::operation
const Operation & operation() const
Definition: ProgramOperation.cc:590
ExecutionPipelineResource::ResultHelper::realCycle
unsigned int realCycle
Definition: ExecutionPipelineResource.hh:133
TTAProgram::Terminal::isFUPort
virtual bool isFUPort() const
Definition: Terminal.cc:118
ExecutionPipelineResource::OperandUsePair
std::pair< OperandUseHelper, OperandUseHelper > OperandUsePair
Definition: ExecutionPipelineResource.hh:149
ExecutionPipelineResource::unassign
virtual void unassign(const int cycle, MoveNode &node) override
Definition: ExecutionPipelineResource.cc:582
ExecutionPipelineResource::clear
void clear() override
Definition: ExecutionPipelineResource.cc:1759
TTAMachine::FUPort::noRegister
bool noRegister() const
Definition: FUPort.cc:469
ProgramOperation::outputIndexFromGuardOfMove
int outputIndexFromGuardOfMove(const MoveNode &node) const
Definition: ProgramOperation.cc:256
SchedulingResource::clear
virtual void clear()
Definition: SchedulingResource.cc:397
TTAProgram::Terminal::isTriggering
virtual bool isTriggering() const
Definition: Terminal.cc:298
ExecutionPipelineResource::resourcesAllowTrigger
bool resourcesAllowTrigger(int cycle, const MoveNode &move) const
Definition: ExecutionPipelineResource.cc:1244
ExecutionPipelineResource::resultAllowedAtCycle
bool resultAllowedAtCycle(int resultCycle, const ProgramOperation &po, const TTAMachine::Port &resultPort, const MoveNode &trigger, int triggerCycle) const
Definition: ExecutionPipelineResource.cc:1852
OutputPSocketResource.hh
ExecutionPipelineResource::cyclesOverlap
bool cyclesOverlap(int rangeFirst, int rangeLast, int targetCycle) const
Definition: ExecutionPipelineResource.cc:2823
ExecutionPipelineResource::canAssignSource
virtual bool canAssignSource(int cycle, const MoveNode &node, const TTAMachine::Port &resultPort) const
Definition: ExecutionPipelineResource.cc:819
ExecutionPipelineResource::MoveNodePtrPair
std::pair< MoveNode *, MoveNode * > MoveNodePtrPair
Definition: ExecutionPipelineResource.hh:164
ExecutionPipelineResourceTable::operationIndex
int operationIndex(const std::string &opName) const
MoveNode::toString
std::string toString() const
Definition: MoveNode.cc:576
ExecutionPipelineResource::operandOverwritten
bool operandOverwritten(int operandWriteCycle, int triggerCycle, const ProgramOperation &po, const MoveNode &operand, const MoveNode &trigger) const
Definition: ExecutionPipelineResource.cc:1137
TTAMachine::HWOperation
Definition: HWOperation.hh:52
Exception.hh
ExecutionPipelineResource::operandAllowedAtCycle
bool operandAllowedAtCycle(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
Definition: ExecutionPipelineResource.cc:2131
DataDependenceEdge::isBackEdge
bool isBackEdge() const
Definition: DataDependenceEdge.hh:118
ExecutionPipelineResource::operandSharePreventsTriggerForScheduledResult
bool operandSharePreventsTriggerForScheduledResult(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
Definition: ExecutionPipelineResource.cc:2605
MoveNode::isDestinationOperation
bool isDestinationOperation() const
ExecutionPipelineResource::ExecutionPipelineResource
ExecutionPipelineResource(const TTAMachine::FunctionUnit &fu, const unsigned int ii=0)
Definition: ExecutionPipelineResource.cc:82
ExecutionPipelineResource::operandsUsed_
OperandUseMap operandsUsed_
Definition: ExecutionPipelineResource.hh:310
ExecutionPipelineResource::setDDG
void setDDG(const DataDependenceGraph *ddg)
Definition: ExecutionPipelineResource.cc:1776
ProgramOperation::outputNode
MoveNodeSet & outputNode(int out) const
Definition: ProgramOperation.cc:535
ExecutionPipelineResource::ddg_
const DataDependenceGraph * ddg_
Definition: ExecutionPipelineResource.hh:330
TTAProgram::Move::isUnconditional
bool isUnconditional() const
Definition: Move.cc:154
MapTools.hh
TTAMachine::BaseFUPort
Definition: BaseFUPort.hh:44
ExecutionPipelineResource::ResultHelperPair
std::pair< ResultHelper, ResultHelper > ResultHelperPair
Definition: ExecutionPipelineResource.hh:148
TTAProgram::Move::destination
Terminal & destination() const
Definition: Move.cc:323
ExecutionPipelineResource::unassignSource
virtual void unassignSource(const int cycle, MoveNode &node)
Definition: ExecutionPipelineResource.cc:597
ExecutionPipelineResource::setResultWriten
void setResultWriten(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
Definition: ExecutionPipelineResource.cc:211
ProgramOperation::fuFromOutMove
const TTAMachine::FunctionUnit * fuFromOutMove(const MoveNode &outputNode) const
Definition: ProgramOperation.cc:844
TTAProgram::Terminal::hintOperation
virtual Operation & hintOperation() const
Definition: Terminal.cc:341
Operation::numberOfInputs
virtual int numberOfInputs() const
Definition: Operation.cc:192
DataDependenceGraph.hh
ProgramOperation
Definition: ProgramOperation.hh:70
MoveNode
Definition: MoveNode.hh:65
ExecutionPipelineResource::unsetResultWriten
void unsetResultWriten(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
Definition: ExecutionPipelineResource.cc:305
ExecutionPipelineResource::resultPort
const TTAMachine::Port & resultPort(const MoveNode &mn) const
Definition: ExecutionPipelineResource.cc:2010
TTAMachine::FunctionUnit::port
virtual BaseFUPort * port(const std::string &name) const
Definition: FunctionUnit.cc:145
Terminal.hh
SchedulingResource::initiationInterval_
int initiationInterval_
Definition: SchedulingResource.hh:132
ExecutionPipelineResource::cyclesConflict
bool cyclesConflict(const MoveNode *mn1, const MoveNode *mn2, int guardCycle, int rangeFirst, int rangeLast, int targetCycle) const
Definition: ExecutionPipelineResource.cc:2843
ExecutionPipelineResource::otherTriggerBeforeMyTrigger
bool otherTriggerBeforeMyTrigger(const TTAMachine::Port &port, const MoveNode &node, int cycle) const
Definition: ExecutionPipelineResource.cc:2425
Operation::name
virtual TCEString name() const
Definition: Operation.cc:93
SchedulingResource::isInputPSocketResource
virtual bool isInputPSocketResource() const
Conversion::toString
static std::string toString(const T &source)
ProgramOperation::triggeringMove
MoveNode * triggeringMove() const
Definition: ProgramOperation.cc:643
ExecutionPipelineResource::testTriggerResult
bool testTriggerResult(const MoveNode &trigger, int cycle) const
Definition: ExecutionPipelineResource.cc:1785
POMDisassembler.hh
ExecutionPipelineResource::poConflictsWithInputPort
bool poConflictsWithInputPort(const TTAMachine::Port &port, const ProgramOperation &po, const MoveNode &mn) const
Definition: ExecutionPipelineResource.cc:2866
MoveNode::isPlaced
bool isPlaced() const
Definition: MoveNode.cc:352
TTAProgram::Terminal::operation
virtual Operation & operation() const
Definition: Terminal.cc:319
ExecutionPipelineResourceTable::operationPipeline
bool operationPipeline(int op, int cycle, int res) const
MapTools::removeItemsByValue
static bool removeItemsByValue(MapType &aMap, const ValueType &aValue)
TCEString.hh
SparseVector::size
size_t size() const
Definition: SparseVectorMap.hh:45
MoveNode::sourceOperation
ProgramOperation & sourceOperation() const
Definition: MoveNode.cc:453
assert
#define assert(condition)
Definition: Application.hh:86
TTAMachine::FunctionUnit
Definition: FunctionUnit.hh:55
TTAMachine::HWOperation::port
virtual FUPort * port(int operand) const
Definition: HWOperation.cc:320
TTAMachine::FUPort
Definition: FUPort.hh:46
ExecutionPipelineResource::isAvailable
virtual bool isAvailable(const int cycle) const override
Definition: ExecutionPipelineResource.cc:178
ExecutionPipelineResource::nodeOfInputPort
const MoveNode * nodeOfInputPort(const ProgramOperation &po, TTAMachine::Port &port)
Definition: ExecutionPipelineResource.cc:2853
MoveNode::isMove
bool isMove() const
SchedulingResource::relatedResource
virtual SchedulingResource & relatedResource(const int group, const int index) const
Definition: SchedulingResource.cc:120
MoveNode::isGuardOperation
bool isGuardOperation() const
Definition: MoveNode.cc:181
ExecutionPipelineResource::ResultHelper
Definition: ExecutionPipelineResource.hh:132
MoveNode::earliestResultReadCycle
int earliestResultReadCycle() const
Definition: MoveNode.cc:652
IllegalParameters
Definition: Exception.hh:113
ExecutionPipelineResource::size
unsigned int size() const
Definition: ExecutionPipelineResource.cc:1417
TTAProgram::Terminal::operationIndex
virtual int operationIndex() const
Definition: Terminal.cc:364
TTAMachine::HWOperation::io
int io(const FUPort &port) const
Definition: HWOperation.cc:364
abortWithError
#define abortWithError(message)
Definition: Application.hh:72
MoveNode::cycle
int cycle() const
Definition: MoveNode.cc:421
HWOperation.hh
InvalidData
Definition: Exception.hh:149
ExecutionPipelineResource::unassignDestination
virtual void unassignDestination(const int cycle, MoveNode &node)
Definition: ExecutionPipelineResource.cc:676
MoveNodeSet::at
MoveNode & at(int index)
ExecutionPipelineResource::isLoopBypass
bool isLoopBypass(const MoveNode &node) const
Definition: ExecutionPipelineResource.cc:791
ExecutionPipelineResource::resultNotOverWritten
bool resultNotOverWritten(int resultReadCycle, int resultReadyCycle, const MoveNode &node, const TTAMachine::Port &port, const MoveNode *trigger, int triggerCycle) const
Definition: ExecutionPipelineResource.cc:2048
ExecutionPipelineResource::exclusiveMoves
bool exclusiveMoves(const MoveNode *mn1, const MoveNode *mn2, int cycle=INT_MAX) const
Definition: ExecutionPipelineResource.cc:1719
SchedulingResource
Definition: SchedulingResource.hh:52
ExecutionPipelineResource::OperandUseHelper
Definition: ExecutionPipelineResource.hh:141
ExecutionPipelineResource::cachedSize_
int cachedSize_
Definition: ExecutionPipelineResource.hh:327
ExecutionPipelineResource::fuExecutionPipeline_
ResourceReservationTable fuExecutionPipeline_
Stores one resource vector per cycle of scope for whole FU.
Definition: ExecutionPipelineResource.hh:298
TTAMachine::Port
Definition: Port.hh:54
ExecutionPipelineResourceTable::hasOperation
bool hasOperation(const std::string &opName) const
InputPSocketResource.hh
Application.hh
ExecutionPipelineResource::hasConflictingResultsOnCycle
bool hasConflictingResultsOnCycle(const ProgramOperation &po, const TTAMachine::Port &port, int cycle) const
Definition: ExecutionPipelineResource.cc:1559
TTAProgram::Move::guard
MoveGuard & guard() const
Definition: Move.cc:345
DataDependenceEdge::EDGE_OPERATION
@ EDGE_OPERATION
Definition: DataDependenceEdge.hh:56
__func__
#define __func__
Definition: Application.hh:67
ExecutionPipelineResource::assignedDestinationNodes_
std::multimap< int, MoveNode * > assignedDestinationNodes_
Definition: ExecutionPipelineResource.hh:325
ExecutionPipelineResource::validateRelatedGroups
virtual bool validateRelatedGroups() override
Definition: ExecutionPipelineResource.cc:1399
Guard.hh
Operation.hh
MoveNode::isSourceOperation
bool isSourceOperation() const
Definition: MoveNode.cc:168
TTAMachine::HWOperation::slack
int slack(int input) const
Definition: HWOperation.cc:248
ExecutionPipelineResource::fu_
const TTAMachine::FunctionUnit & fu_
Definition: ExecutionPipelineResource.hh:331
ExecutionPipelineResource::OperandUseHelper::po
const ProgramOperation * po
Definition: ExecutionPipelineResource.hh:143
ExecutionPipelineResource::checkOperandAllowed
bool checkOperandAllowed(const MoveNode &currentMn, const TTAMachine::Port &port, int operandWriteCycle, const OperandUseHelper &operandUse, int operandUseModCycle, ProgramOperation &currOp) const
Definition: ExecutionPipelineResource.cc:2234
ExecutionPipelineResource::operandsOverwritten
bool operandsOverwritten(int triggerCycle, const MoveNode &trigger) const
Definition: ExecutionPipelineResource.cc:1216
SchedulingResource::instructionIndex
int instructionIndex(int cycle) const
Machine.hh
ExecutionPipelineResource::assignSource
virtual void assignSource(int cycle, MoveNode &node)
Definition: ExecutionPipelineResource.cc:405
ModuleRunTimeError
Definition: Exception.hh:1043
ExecutionPipelineResourceTable::numberOfResources
unsigned int numberOfResources() const
MoveNode::destinationOperationCount
unsigned int destinationOperationCount() const
MoveNodeSet
Definition: MoveNodeSet.hh:41
ProgramOperation::inputMoveCount
int inputMoveCount() const
Definition: ProgramOperation.cc:600
ExecutionPipelineResource::operandPossibleAtCycle
bool operandPossibleAtCycle(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
Definition: ExecutionPipelineResource.cc:2106
BoostGraph::hasNode
bool hasNode(const Node &) const
ExecutionPipelineResource::resultRead_
ResultMap resultRead_
Definition: ExecutionPipelineResource.hh:316
ProgramOperation::findTriggerFromUnit
MoveNode * findTriggerFromUnit(const TTAMachine::Unit &unit) const
Definition: ProgramOperation.cc:677
TTAMachine::Unit::portCount
virtual int portCount() const
Definition: Unit.cc:135
Operation
Definition: Operation.hh:59
Exception::errorMessage
std::string errorMessage() const
Definition: Exception.cc:123
TTAProgram::Terminal::isOpcodeSetting
virtual bool isOpcodeSetting() const
Definition: Terminal.cc:285
ExecutionPipelineResource::resultWriten_
ResultMap resultWriten_
Definition: ExecutionPipelineResource.hh:313
BoostGraph::inEdges
virtual EdgeSet inEdges(const Node &node) const
SchedulingResource::initiationInterval
int initiationInterval() const
Definition: SchedulingResource.cc:385
ExecutionPipelineResource::triggerAllowedAtCycle
bool triggerAllowedAtCycle(int inputCount, const TTAMachine::HWOperation &hwop, const MoveNode &node, int cycle) const
Definition: ExecutionPipelineResource.cc:2369
ProgramOperation::outputMoveCount
int outputMoveCount() const
Definition: ProgramOperation.cc:610
SchedulingResource::relatedResourceCount
int relatedResourceCount(const int group) const
SparseVector
Definition: SparseVectorMap.hh:43
ProgramOperation.hh
MoveNodeSet::count
int count() const
ExecutionPipelineResource::ResourceReservationVector
std::vector< ResourceReservation > ResourceReservationVector
Type for resource vector, represents one cycle of use. Includes the ownerships of the reservation.
Definition: ExecutionPipelineResource.hh:157
MoveNode::destinationOperation
ProgramOperation & destinationOperation(unsigned int index=0) const
TTAMachine::Guard::isOpposite
virtual bool isOpposite(const Guard &guard) const =0
MoveNode::move
TTAProgram::Move & move()
ExecutionPipelineResource::setOperandUsed
void setOperandUsed(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
Definition: ExecutionPipelineResource.cc:241
ProgramOperation::toString
std::string toString() const
Definition: ProgramOperation.cc:746
ExecutionPipelineResource::setOperandsUsed
void setOperandsUsed(const ProgramOperation &po, unsigned int triggerCycle)
Definition: ExecutionPipelineResource.cc:283
ExecutionPipelineResource::resources
const ExecutionPipelineResourceTable * resources
Definition: ExecutionPipelineResource.hh:295
MapTools::containsKey
static bool containsKey(const MapType &aMap, const KeyType &aKey)
ExecutionPipelineResource::canAssignDestination
virtual bool canAssignDestination(const int cycle, const MoveNode &node, const bool triggering=false) const
Definition: ExecutionPipelineResource.cc:990
ExecutionPipelineResource::unsetOperandsUsed
void unsetOperandsUsed(const ProgramOperation &po, unsigned int triggerCycle)
Definition: ExecutionPipelineResource.cc:377
ExecutionPipelineResource::operandShareCount_
int operandShareCount_
Definition: ExecutionPipelineResource.hh:336
ExecutionPipelineResource.hh
ExecutionPipelineResource::maxCycle_
int maxCycle_
Definition: ExecutionPipelineResource.hh:328
ExecutionPipelineResourceTable::maximalLatency
unsigned int maximalLatency() const
ExecutionPipelineResource::resultCausesTriggerBetweenOperandSharing
bool resultCausesTriggerBetweenOperandSharing(const MoveNode &mn, int cycle) const
Definition: ExecutionPipelineResource.cc:2488
MoveNodeSet::begin
std::vector< MoveNode * >::iterator begin()
Definition: MoveNodeSet.hh:51
ExecutionPipelineResource::operandsWriten_
OperandWriteMap operandsWriten_
Definition: ExecutionPipelineResource.hh:309
ExecutionPipelineResource::unsetOperandUsed
void unsetOperandUsed(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
Definition: ExecutionPipelineResource.cc:336
DataDependenceGraph::exclusingGuards
bool exclusingGuards(const MoveNode &mn1, const MoveNode &mn2) const
Definition: DataDependenceGraph.cc:4480
MapTools::containsValue
static bool containsValue(const MapType &aMap, const ValueType &aValue)
MoveNodeSet.hh
TTAMachine::Port::name
virtual std::string name() const
Definition: Port.cc:141
FUPort.hh
ExecutionPipelineResource::nextResultCycle
int nextResultCycle(const TTAMachine::Port &port, int cycle, const MoveNode &node, const MoveNode *trigger=NULL, int triggerCycle=INT_MAX) const
Definition: ExecutionPipelineResource.cc:1602
DataDependenceGraph
Definition: DataDependenceGraph.hh:67
ExecutionPipelineResource::assign
virtual void assign(const int cycle, MoveNode &node) override
Definition: ExecutionPipelineResource.cc:392
ProgramOperation::inputNode
MoveNodeSet & inputNode(int in) const
Definition: ProgramOperation.cc:513
ExecutionPipelineResource::triggerTooEarly
bool triggerTooEarly(const MoveNode &trigger, int cycle) const
Definition: ExecutionPipelineResource.cc:2327
ExecutionPipelineResource::validateDependentGroups
virtual bool validateDependentGroups() override
Definition: ExecutionPipelineResource.cc:1388
ExecutionPipelineResource::resultReadyCycle
int resultReadyCycle(const ProgramOperation &po, const TTAMachine::Port &resultPort) const
Definition: ExecutionPipelineResource.cc:1677
ExecutionPipelineResource::ResultHelper::po
const ProgramOperation * po
Definition: ExecutionPipelineResource.hh:134
TTAProgram::Terminal
Definition: Terminal.hh:60
ExecutionPipelineResource::assignDestination
virtual void assignDestination(const int cycle, MoveNode &node)
Definition: ExecutionPipelineResource.cc:487
DataDependenceEdge
Definition: DataDependenceEdge.hh:43
MoveNode::isScheduled
bool isScheduled() const
Definition: MoveNode.cc:409
TTAProgram::Move::source
Terminal & source() const
Definition: Move.cc:302
ExecutionPipelineResource::storedResultCycles_
std::map< MoveNode *, int, MoveNode::Comparator > storedResultCycles_
Definition: ExecutionPipelineResource.hh:321
TTAProgram::Terminal::port
virtual const TTAMachine::Port & port() const
Definition: Terminal.cc:378
TTAMachine::PortGuard
Definition: Guard.hh:99
TTAMachine::FunctionUnit::operation
virtual HWOperation * operation(const std::string &name) const
Definition: FunctionUnit.cc:363
SchedulingResource::name
virtual const std::string & name() const
TTAMachine::HWOperation::latency
int latency() const
Definition: HWOperation.cc:216
ExecutionPipelineResource::isDestOpOfMN
bool isDestOpOfMN(const MoveNode &mn, const ProgramOperation &po) const
Definition: ExecutionPipelineResource.cc:2477
ExecutionPipelineResource::isInUse
virtual bool isInUse(const int cycle) const override
Definition: ExecutionPipelineResource.cc:117
TTAProgram::MoveGuard::guard
const TTAMachine::Guard & guard() const
Definition: MoveGuard.cc:86
SchedulingResource::relatedResourceGroupCount
virtual int relatedResourceGroupCount() const
Definition: SchedulingResource.cc:61
Move.hh
ExecutionPipelineResourceTable
Definition: ExecutionPipelineResourceTable.hh:44
MoveNode.hh
ExecutionPipelineResource::ResourceReservation
std::pair< const MoveNode *, const MoveNode * > ResourceReservation
Definition: ExecutionPipelineResource.hh:151
ExecutionPipelineResource::assignedSourceNodes_
std::multimap< int, MoveNode * > assignedSourceNodes_
Definition: ExecutionPipelineResource.hh:323
ProgramOperation::outputMove
MoveNode & outputMove(int index) const
Definition: ProgramOperation.cc:632
ExecutionPipelineResource::canAssign
virtual bool canAssign(const int cycle, const MoveNode &node) const override
Definition: ExecutionPipelineResource.cc:102
Operation::numberOfOutputs
virtual int numberOfOutputs() const
Definition: Operation.cc:202
ExecutionPipelineResource::highestKnownCycle
int highestKnownCycle() const
Definition: ExecutionPipelineResource.cc:1479
ResourceManager.hh
ProgramOperation::outputIndexOfMove
int outputIndexOfMove(const MoveNode &mn) const
Definition: ProgramOperation.cc:886
ExecutionPipelineResourceTable.hh
ExecutionPipelineResource::isExecutionPipelineResource
virtual bool isExecutionPipelineResource() const override
Definition: ExecutionPipelineResource.cc:1378
ExecutionPipelineResource::~ExecutionPipelineResource
virtual ~ExecutionPipelineResource()
Definition: ExecutionPipelineResource.cc:94
DataDependenceEdge::edgeReason
EdgeReason edgeReason() const
Definition: DataDependenceEdge.hh:91
ExecutionPipelineResource::operandPort
const TTAMachine::Port & operandPort(const MoveNode &mn) const
Definition: ExecutionPipelineResource.cc:2027
ExecutionPipelineResource::latestTriggerWriteCycle
int latestTriggerWriteCycle(const MoveNode &mn) const
Definition: ExecutionPipelineResource.cc:2393
ProgramOperation::inputMove
MoveNode & inputMove(int index) const
Definition: ProgramOperation.cc:621
ExecutionPipelineResource::operandTooLate
bool operandTooLate(const MoveNode &node, int cycle) const
Definition: ExecutionPipelineResource.cc:2291
FunctionUnit.hh
MoveNode::guardOperation
ProgramOperation & guardOperation() const
Definition: MoveNode.cc:479
MoveGuard.hh
TTAMachine::Port::parentUnit
Unit * parentUnit() const