OpenASIP 2.2
Loading...
Searching...
No Matches
Classes | Public Member Functions | Protected Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
ExecutionPipelineResource Class Reference

#include <ExecutionPipelineResource.hh>

Inheritance diagram for ExecutionPipelineResource:
Inheritance graph
Collaboration diagram for ExecutionPipelineResource:
Collaboration graph

Classes

struct  OperandUseHelper
 
struct  ResultHelper
 

Public Member Functions

 ExecutionPipelineResource (const TTAMachine::FunctionUnit &fu, const unsigned int ii=0)
 
virtual ~ExecutionPipelineResource ()
 
virtual bool isInUse (const int cycle) const override
 
virtual bool isAvailable (const int cycle) const override
 
virtual bool canAssign (const int cycle, const MoveNode &node) const override
 
virtual bool canAssignSource (int cycle, const MoveNode &node, const TTAMachine::Port &resultPort) const
 
virtual bool canAssignDestination (const int cycle, const MoveNode &node, const bool triggering=false) const
 
virtual void assign (const int cycle, MoveNode &node) override
 
virtual void assignSource (int cycle, MoveNode &node)
 
virtual void assignDestination (const int cycle, MoveNode &node)
 
virtual void unassign (const int cycle, MoveNode &node) override
 
virtual void unassignSource (const int cycle, MoveNode &node)
 
virtual void unassignDestination (const int cycle, MoveNode &node)
 
virtual bool isExecutionPipelineResource () const override
 
int highestKnownCycle () const
 
int nextResultCycle (const TTAMachine::Port &port, int cycle, const MoveNode &node, const MoveNode *trigger=NULL, int triggerCycle=INT_MAX) const
 
bool otherTriggerBeforeMyTrigger (const TTAMachine::Port &port, const MoveNode &node, int cycle) const
 
bool resultNotOverWritten (int resultReadCycle, int resultReadyCycle, const MoveNode &node, const TTAMachine::Port &port, const MoveNode *trigger, int triggerCycle) const
 
bool hasConflictingResultsOnCycle (const ProgramOperation &po, const TTAMachine::Port &port, int cycle) const
 
bool operandsOverwritten (int triggerCycle, const MoveNode &trigger) const
 
void clear () override
 
void setDDG (const DataDependenceGraph *ddg)
 
virtual void setMaxCycle (unsigned int maxCycle) override
 
- Public Member Functions inherited from SchedulingResource
virtual ~SchedulingResource ()
 
 SchedulingResource (const std::string &name, const unsigned int ii=0)
 
virtual int relatedResourceGroupCount () const
 
virtual int dependentResourceGroupCount () const
 
int relatedResourceCount (const int group) const
 
int dependentResourceCount (const int group) const
 
virtual void addToRelatedGroup (const int group, SchedulingResource &resource)
 
virtual void addToDependentGroup (const int group, SchedulingResource &resource)
 
virtual SchedulingResourcerelatedResource (const int group, const int index) const
 
virtual SchedulingResourcedependentResource (const int group, const int index) const
 
virtual bool hasRelatedResource (const SchedulingResource &sResource) const
 
virtual bool hasDependentResource (const SchedulingResource &sResource) const
 
virtual const std::string & name () const
 
virtual int useCount () const
 
virtual void increaseUseCount ()
 
virtual void decreaseUseCount ()
 
virtual bool isInputPSocketResource () const
 
virtual bool isOutputPSocketResource () const
 
virtual bool isShortImmPSocketResource () const
 
virtual bool isInputFUResource () const
 
virtual bool isOutputFUResource () const
 
virtual bool isBusResource () const
 
virtual bool isSegmentResource () const
 
virtual bool isIUResource () const
 
virtual bool isITemplateResource () const
 
int instructionIndex (int cycle) const
 
void setInitiationInterval (unsigned int ii)
 
int initiationInterval () const
 
virtual bool operator< (const SchedulingResource &other) const
 

Protected Member Functions

virtual bool validateDependentGroups () override
 
virtual bool validateRelatedGroups () override
 
unsigned int size () const
 

Private Types

typedef std::pair< ResultHelper, ResultHelperResultHelperPair
 
typedef std::pair< OperandUseHelper, OperandUseHelperOperandUsePair
 
typedef std::pair< const MoveNode *, const MoveNode * > ResourceReservation
 
typedef std::vector< ResourceReservationResourceReservationVector
 Type for resource vector, represents one cycle of use. Includes the ownerships of the reservation.
 
typedef SparseVector< ResultHelperPairResultVector
 Used for both result read and result written.
 
typedef std::map< const TTAMachine::Port *, ResultVectorResultMap
 
typedef std::pair< MoveNode *, MoveNode * > MoveNodePtrPair
 
typedef SparseVector< MoveNodePtrPairOperandWriteVector
 
typedef SparseVector< OperandUsePairOperandUseVector
 
typedef std::map< const TTAMachine::Port *, OperandUseVectorOperandUseMap
 
typedef std::map< const TTAMachine::Port *, OperandWriteVectorOperandWriteMap
 
typedef SparseVector< ResourceReservationVectorResourceReservationTable
 Type for resource reservation table, resource vector x latency. Includes the ownerships of the reservation.
 

Private Member Functions

bool cyclesOverlap (int rangeFirst, int rangeLast, int targetCycle) const
 
bool cyclesConflict (const MoveNode *mn1, const MoveNode *mn2, int guardCycle, int rangeFirst, int rangeLast, int targetCycle) const
 
bool isLoopBypass (const MoveNode &node) const
 
 ExecutionPipelineResource (const ExecutionPipelineResource &)
 
ExecutionPipelineResourceoperator= (const ExecutionPipelineResource &)
 
void findRange (const int cycle, const MoveNode &node, int popIndex, int &first, int &last, int &triggering) const
 Find first and last cycles already scheduled for same PO.
 
int resultReadyCycle (const ProgramOperation &po, const TTAMachine::Port &resultPort) const
 
void setResultWriten (const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
 
void setResultWriten (const ProgramOperation &po, unsigned int triggerCycle)
 
void unsetResultWriten (const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
 
void unsetResultWriten (const ProgramOperation &po, unsigned int triggerCycle)
 
void setOperandUsed (const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
 
void setOperandsUsed (const ProgramOperation &po, unsigned int triggerCycle)
 
void unsetOperandUsed (const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
 
void unsetOperandsUsed (const ProgramOperation &po, unsigned int triggerCycle)
 
const TTAMachine::PortoperandPort (const MoveNode &mn) const
 
bool operandOverwritten (int operandWriteCycle, int triggerCycle, const ProgramOperation &po, const MoveNode &operand, const MoveNode &trigger) const
 
bool operandOverwritten (const MoveNode &mn, int cycle) const
 
bool testTriggerResult (const MoveNode &trigger, int cycle) const
 
bool resultAllowedAtCycle (int resultCycle, const ProgramOperation &po, const TTAMachine::Port &resultPort, const MoveNode &trigger, int triggerCycle) const
 
bool resourcesAllowTrigger (int cycle, const MoveNode &move) const
 
bool operandPossibleAtCycle (const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
 
bool operandAllowedAtCycle (const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
 
bool checkOperandAllowed (const MoveNode &currentMn, const TTAMachine::Port &port, int operandWriteCycle, const OperandUseHelper &operandUse, int operandUseModCycle, ProgramOperation &currOp) const
 
bool triggerTooEarly (const MoveNode &trigger, int cycle) const
 
bool operandTooLate (const MoveNode &node, int cycle) const
 
bool triggerAllowedAtCycle (int inputCount, const TTAMachine::HWOperation &hwop, const MoveNode &node, int cycle) const
 
bool operandSharePreventsTriggerForScheduledResult (const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
 
bool resultCausesTriggerBetweenOperandSharing (const MoveNode &mn, int cycle) const
 
const MoveNodenodeOfInputPort (const ProgramOperation &po, TTAMachine::Port &port)
 
bool poConflictsWithInputPort (const TTAMachine::Port &port, const ProgramOperation &po, const MoveNode &mn) const
 
const TTAMachine::PortresultPort (const MoveNode &mn) const
 
bool exclusiveMoves (const MoveNode *mn1, const MoveNode *mn2, int cycle=INT_MAX) const
 
int latestTriggerWriteCycle (const MoveNode &mn) const
 
bool isDestOpOfMN (const MoveNode &mn, const ProgramOperation &po) const
 

Private Attributes

const ExecutionPipelineResourceTableresources
 
ResourceReservationTable fuExecutionPipeline_
 Stores one resource vector per cycle of scope for whole FU.
 
OperandWriteMap operandsWriten_
 
OperandUseMap operandsUsed_
 
ResultMap resultWriten_
 
ResultMap resultRead_
 
std::map< MoveNode *, int, MoveNode::ComparatorstoredResultCycles_
 
std::multimap< int, MoveNode * > assignedSourceNodes_
 
std::multimap< int, MoveNode * > assignedDestinationNodes_
 
int cachedSize_
 
int maxCycle_
 
const DataDependenceGraphddg_
 
const TTAMachine::FunctionUnitfu_
 
const TTAMachine::PorttriggerPort_
 
int operandShareCount_
 

Additional Inherited Members

- Protected Attributes inherited from SchedulingResource
int initiationInterval_
 

Detailed Description

ExecutionPipelineResource keeps book of pipeline resource reservation status. It uses rather simple resource reservation table approach.

Definition at line 64 of file ExecutionPipelineResource.hh.

Member Typedef Documentation

◆ MoveNodePtrPair

Definition at line 164 of file ExecutionPipelineResource.hh.

◆ OperandUseMap

Definition at line 169 of file ExecutionPipelineResource.hh.

◆ OperandUsePair

Definition at line 149 of file ExecutionPipelineResource.hh.

◆ OperandUseVector

Definition at line 167 of file ExecutionPipelineResource.hh.

◆ OperandWriteMap

Definition at line 171 of file ExecutionPipelineResource.hh.

◆ OperandWriteVector

Definition at line 166 of file ExecutionPipelineResource.hh.

◆ ResourceReservation

typedef std::pair<const MoveNode*,const MoveNode*> ExecutionPipelineResource::ResourceReservation
private

Definition at line 151 of file ExecutionPipelineResource.hh.

◆ ResourceReservationTable

Type for resource reservation table, resource vector x latency. Includes the ownerships of the reservation.

Definition at line 175 of file ExecutionPipelineResource.hh.

◆ ResourceReservationVector

Type for resource vector, represents one cycle of use. Includes the ownerships of the reservation.

Definition at line 157 of file ExecutionPipelineResource.hh.

◆ ResultHelperPair

Definition at line 148 of file ExecutionPipelineResource.hh.

◆ ResultMap

Definition at line 162 of file ExecutionPipelineResource.hh.

◆ ResultVector

Used for both result read and result written.

Definition at line 160 of file ExecutionPipelineResource.hh.

Constructor & Destructor Documentation

◆ ExecutionPipelineResource() [1/2]

ExecutionPipelineResource::ExecutionPipelineResource ( const TTAMachine::FunctionUnit fu,
const unsigned int  ii = 0 
)

Constructor.

Creates new resource with defined name

Parameters
nameName of resource
resNumNumber of resources in FU
maxLatencyLatency of longest operation FU supports

Definition at line 82 of file ExecutionPipelineResource.cc.

84 :
85 SchedulingResource("ep_" + fu.name(), ii),
87 cachedSize_(INT_MIN), maxCycle_(INT_MAX), ddg_(NULL), fu_(fu),
89}
static const ExecutionPipelineResourceTable & resourceTable(const TTAMachine::FunctionUnit &fu)
const TTAMachine::FunctionUnit & fu_
const ExecutionPipelineResourceTable * resources
const DataDependenceGraph * ddg_
virtual TCEString name() const

◆ ~ExecutionPipelineResource()

ExecutionPipelineResource::~ExecutionPipelineResource ( )
virtual

Empty destructor

Definition at line 94 of file ExecutionPipelineResource.cc.

94{}

◆ ExecutionPipelineResource() [2/2]

ExecutionPipelineResource::ExecutionPipelineResource ( const ExecutionPipelineResource )
private

Member Function Documentation

◆ assign()

void ExecutionPipelineResource::assign ( const int  cycle,
MoveNode node 
)
overridevirtual

Implements SchedulingResource.

Definition at line 392 of file ExecutionPipelineResource.cc.

392 {
393 abortWithError("Execution Pipeline Resource needs 3 arguments assign");
394}
#define abortWithError(message)

References abortWithError.

◆ assignDestination()

void ExecutionPipelineResource::assignDestination ( const int  cycle,
MoveNode node 
)
virtual

Assign resource to given node for given cycle.

Parameters
cycleCycle to assign
nodeMoveNode assigned in case move is bypassed

Definition at line 487 of file ExecutionPipelineResource.cc.

489 {
490 cachedSize_ = INT_MIN;
491
492#ifdef DEBUG_RM
493 std::cerr << "\t\t\tAssigning destination: " << node.toString() << std::endl;
494#endif
495 if (!node.isDestinationOperation()) {
496 return;
497 }
498
499 assignedDestinationNodes_.insert(std::pair<int, MoveNode*>(cycle, &node));
500
501 int modCycle = instructionIndex(cycle);
502
503 std::string opName = "";
504
505 //TODO: is this correct trigger or UM trigger?
506 if (node.move().destination().isTriggering()) {
507#ifdef DEBUG_RM
508 std::cerr << "\t\t\t\tis trigger!" << std::endl;
509#endif
511
513 if (node.move().destination().isOpcodeSetting()) {
514 opName = node.move().destination().operation().name();
515 } else {
516 std::string msg = "Using non opcodeSetting triggering move. ";
517 msg += " Move: " + node.toString();
518 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
519 }
520 int pIndex = resources->operationIndex(opName);
521 for (unsigned int i = 0; i < resources->maximalLatency(); i++) {
522 int modic = instructionIndex(cycle+i);
523 // then we can insert the resource usage.
524 for (unsigned int j = 0 ;
525 j < resources->numberOfResources(); j++) {
526 if (fuExecutionPipeline_[modic].size()
527 == 0) {
528 fuExecutionPipeline_[modic] =
531 }
533 fuExecutionPipeline_[modic][j];
534 if (resources->operationPipeline(pIndex,i,j)) {
535 if (rr.first != NULL) {
536 assert(rr.second == NULL&&"Resource already in use?");
537 rr.second = &node;
538 } else { // rr.first == NULL
539 rr.first = &node;
540 }
541 }
542 }
543 }
544 setResultWriten(pOp, cycle);
545 setOperandsUsed(pOp, cycle);
546 } else {
547 if (node.destinationOperationCount() > 1) {
549 }
550 }
551
552 const TTAMachine::Port& opPort = operandPort(node);
553 MoveNodePtrPair& mnpp = operandsWriten_[&opPort][modCycle];
554 if (mnpp.first == NULL) {
555 mnpp.first = &node;
556 } else {
557 if (mnpp.second != NULL || !exclusiveMoves(mnpp.first, &node, cycle)) {
558 std::string msg = name() + " had previous operation ";
559 msg += mnpp.first->destinationOperation().toString() + "\n ";
560 msg += mnpp.first->toString() + " in inst.index " ;
561 msg += Conversion::toString(modCycle);
562 msg += " other trigger: ";
563 msg += mnpp.first->toString();
564 msg += " Node: " + node.toString();
565 msg += "\nThis op: " + node.destinationOperation().toString();
566 msg += "\n";
567
568 if (node.isDestinationOperation()) {
569 msg += node.destinationOperation().toString();
570 }
571 throw InvalidData(__FILE__, __LINE__, __func__, msg);
572 } else {
573
574 // Marks all the cycles in range with PO
575 // which is writing operands
576 mnpp.second = &node;
577 }
578 }
579}
#define __func__
#define assert(condition)
static std::string toString(const T &source)
unsigned int maximalLatency() const
int operationIndex(const std::string &opName) const
bool operationPipeline(int op, int cycle, int res) const
unsigned int numberOfResources() const
ResourceReservationTable fuExecutionPipeline_
Stores one resource vector per cycle of scope for whole FU.
std::multimap< int, MoveNode * > assignedDestinationNodes_
bool exclusiveMoves(const MoveNode *mn1, const MoveNode *mn2, int cycle=INT_MAX) const
void setOperandsUsed(const ProgramOperation &po, unsigned int triggerCycle)
const TTAMachine::Port & operandPort(const MoveNode &mn) const
void setResultWriten(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
std::vector< ResourceReservation > ResourceReservationVector
Type for resource vector, represents one cycle of use. Includes the ownerships of the reservation.
std::pair< const MoveNode *, const MoveNode * > ResourceReservation
std::pair< MoveNode *, MoveNode * > MoveNodePtrPair
unsigned int destinationOperationCount() const
bool isDestinationOperation() const
std::string toString() const
Definition MoveNode.cc:576
TTAProgram::Move & move()
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual TCEString name() const
Definition Operation.cc:93
std::string toString() const
int instructionIndex(int cycle) const
virtual const std::string & name() const
Terminal & destination() const
Definition Move.cc:323
virtual bool isTriggering() const
Definition Terminal.cc:298
virtual bool isOpcodeSetting() const
Definition Terminal.cc:285
virtual Operation & operation() const
Definition Terminal.cc:319

References __func__, assert, assignedDestinationNodes_, cachedSize_, TTAProgram::Move::destination(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), exclusiveMoves(), fuExecutionPipeline_, SchedulingResource::instructionIndex(), MoveNode::isDestinationOperation(), TTAProgram::Terminal::isOpcodeSetting(), TTAProgram::Terminal::isTriggering(), ExecutionPipelineResourceTable::maximalLatency(), MoveNode::move(), SchedulingResource::name(), Operation::name(), ExecutionPipelineResourceTable::numberOfResources(), operandPort(), operandShareCount_, operandsWriten_, TTAProgram::Terminal::operation(), ExecutionPipelineResourceTable::operationIndex(), ExecutionPipelineResourceTable::operationPipeline(), resources, setOperandsUsed(), setResultWriten(), size(), MoveNode::toString(), ProgramOperation::toString(), and Conversion::toString().

Referenced by InputFUResource::assign().

Here is the call graph for this function:

◆ assignSource()

void ExecutionPipelineResource::assignSource ( int  cycle,
MoveNode node 
)
virtual

Assign resource to given node for given cycle.

Parameters
cycleCycle to assign
nodeMoveNode assigned
sourceIndicates if we want to unassing source part of move in case move is bypassed

Assiging result read

Record Program Operation in cycle where the "result read" is scheduled

Definition at line 405 of file ExecutionPipelineResource.cc.

407 {
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}
const TTAMachine::Port & resultPort(const MoveNode &mn) const
std::map< MoveNode *, int, MoveNode::Comparator > storedResultCycles_
bool isLoopBypass(const MoveNode &node) const
SparseVector< ResultHelperPair > ResultVector
Used for both result read and result written.
std::pair< ResultHelper, ResultHelper > ResultHelperPair
std::multimap< int, MoveNode * > assignedSourceNodes_
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
ProgramOperation & guardOperation() const
Definition MoveNode.cc:479
bool isSourceOperation() const
Definition MoveNode.cc:168

References assert, assignedSourceNodes_, cachedSize_, MoveNode::guardOperation(), SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), isLoopBypass(), MoveNode::isSourceOperation(), resultPort(), resultRead_, setResultWriten(), SparseVector< ValueType >::size(), MoveNode::sourceOperation(), and storedResultCycles_.

Referenced by OutputFUResource::assign().

Here is the call graph for this function:

◆ canAssign()

bool ExecutionPipelineResource::canAssign ( const int  cycle,
const MoveNode node 
) const
overridevirtual

Not to be used. ExecutionPipelineResource needs to be tested also with PSocket parameter to find if the desired part of MoveNode is source or destination from type of PSocket.

Implements SchedulingResource.

Definition at line 102 of file ExecutionPipelineResource.cc.

102 {
103 abortWithError("Wrong use of canAssign, use also third parameter!");
104 return false;
105}

References abortWithError.

Referenced by resourcesAllowTrigger().

◆ canAssignDestination()

bool ExecutionPipelineResource::canAssignDestination ( const int  cycle,
const MoveNode node,
const bool  triggering = false 
) const
virtual

Return true if resource can be assigned for given node in given cycle.

Parameters
cycleCycle to test
nodeMoveNode to test
pSocketSocket which was assigned to move by previous broker
triggersIndicates if move is triggering
Returns
true if node can be assigned to cycle

Definition at line 990 of file ExecutionPipelineResource.cc.

993 {
994
995 if (!node.isDestinationOperation()) {
996 return true;
997 }
998
999#ifdef DEBUG_RM
1000 std::cerr << "\t\t\tCanAssignDestination called for: " << node.toString()
1001 << " Cycle: " << cycle << " PO: "
1002 << node.destinationOperation().toString() << std::endl;
1003 if (triggers) {
1004 std::cerr << "\t\t\t\tTriggers." << std::endl;
1005 }
1006#endif
1007 unsigned int ii = initiationInterval_;
1008 if (ii < 1) {
1009 ii = INT_MAX;
1010 }
1011
1012 // then handle operation inputs.
1013
1014 MoveNode* newNode = const_cast<MoveNode*>(&node);
1015 ProgramOperation* pOp = NULL;
1016 try {
1017 pOp = &newNode->destinationOperation();
1018 } catch (const InvalidData& e) {
1020 }
1021
1022 const TTAMachine::HWOperation& hwop =
1023 *fu_.operation(pOp->operation().name());
1024 TTAMachine::FUPort& port =
1025 *hwop.port(newNode->move().destination().operationIndex());
1026
1027 if (!operandPossibleAtCycle(port, node, cycle)) {
1028 return false;
1029 }
1030
1031 if (!operandAllowedAtCycle(port, node, cycle)) {
1032 return false;
1033 }
1034
1035 if (otherTriggerBeforeMyTrigger(port, node, cycle)) {
1036 return false;
1037 }
1038
1039 if (operandOverwritten(node, cycle)) {
1040 return false;
1041 }
1042
1043 if (!triggers) {
1044 if (operandTooLate(node, cycle)) {
1045#ifdef DEBUG_RM
1046 std::cerr << "\t\tOperand too late" << std::endl;
1047#endif
1048 return false;
1049 }
1050
1051 if (operandSharePreventsTriggerForScheduledResult(port, node, cycle)) {
1052 return false;
1053 }
1054 return true;
1055 }
1056
1057 if (triggerTooEarly(node, cycle)) {
1058#ifdef DEBUG_RM
1059 std::cerr << "\t\tTrigger too early" << std::endl;
1060#endif
1061
1062 return false;
1063 }
1064
1065#ifdef DEBUG_RM
1066 std::cerr << "\t\t\t\tCanAssignDestination is trigger: "
1067 << node.toString() << " Cycle: " << cycle << std::endl;
1068#endif
1069
1070 // Too late to schedule trigger, results would not be ready in time.
1071 if (cycle > latestTriggerWriteCycle(node)) {
1072#ifdef DEBUG_RM
1073 std::cerr << "\t\t\t\t\tTrigger too late for results" << std::endl;
1074#endif
1075 return false;
1076 }
1077
1078 // now we know we have a trigger.
1079 if (operandsOverwritten(cycle, node)) {
1080#ifdef DEBUG_RM
1081 std::cerr << "\t\t\t\tOperands overwritten" << std::endl;
1082#endif
1083
1084 return false;
1085 }
1086
1087 if (!resourcesAllowTrigger(cycle, node)) {
1088#ifdef DEBUG_RM
1089 std::cerr << "\t\t\t\tResources prevent trigger" << std::endl;
1090#endif
1091
1092 return false;
1093 }
1094
1096 pOp->operation().numberOfInputs(), hwop, node, cycle)) {
1097 return false;
1098 }
1099 // TODO: if ports have no regs..
1100
1101 // Test for result read WaW already when scheduling trigger.
1102 return testTriggerResult(node, cycle);
1103}
std::string errorMessage() const
Definition Exception.cc:123
bool operandOverwritten(int operandWriteCycle, int triggerCycle, const ProgramOperation &po, const MoveNode &operand, const MoveNode &trigger) const
bool operandSharePreventsTriggerForScheduledResult(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
bool testTriggerResult(const MoveNode &trigger, int cycle) const
bool operandAllowedAtCycle(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
bool operandsOverwritten(int triggerCycle, const MoveNode &trigger) const
bool operandTooLate(const MoveNode &node, int cycle) const
int latestTriggerWriteCycle(const MoveNode &mn) const
bool triggerAllowedAtCycle(int inputCount, const TTAMachine::HWOperation &hwop, const MoveNode &node, int cycle) const
bool operandPossibleAtCycle(const TTAMachine::Port &port, const MoveNode &mn, int cycle) const
bool otherTriggerBeforeMyTrigger(const TTAMachine::Port &port, const MoveNode &node, int cycle) const
bool resourcesAllowTrigger(int cycle, const MoveNode &move) const
bool triggerTooEarly(const MoveNode &trigger, int cycle) const
virtual int numberOfInputs() const
Definition Operation.cc:192
const Operation & operation() const
virtual HWOperation * operation(const std::string &name) const
virtual FUPort * port(int operand) const
virtual int operationIndex() const
Definition Terminal.cc:364

References abortWithError, TTAProgram::Move::destination(), MoveNode::destinationOperation(), Exception::errorMessage(), fu_, SchedulingResource::initiationInterval_, MoveNode::isDestinationOperation(), latestTriggerWriteCycle(), MoveNode::move(), Operation::name(), Operation::numberOfInputs(), operandAllowedAtCycle(), operandOverwritten(), operandPossibleAtCycle(), operandSharePreventsTriggerForScheduledResult(), operandsOverwritten(), operandTooLate(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), otherTriggerBeforeMyTrigger(), TTAMachine::HWOperation::port(), resourcesAllowTrigger(), testTriggerResult(), MoveNode::toString(), ProgramOperation::toString(), triggerAllowedAtCycle(), and triggerTooEarly().

Referenced by InputFUResource::canAssign().

Here is the call graph for this function:

◆ canAssignSource()

bool ExecutionPipelineResource::canAssignSource ( int  cycle,
const MoveNode node,
const TTAMachine::Port resultPort 
) const
virtual

Return true if resource can be assigned for given node in given cycle.

Parameters
cycleCycle to test
nodeMoveNode to test
pSocketSocket which was assigned to move by previous broker
triggersIndicates if move is triggering
Returns
true if node can be assigned to cycle

Testing the result read move Find the cycle first of the possible results of PO will be produced

Check if the port has a register. If not result read must be in same cycle as result ready.

Definition at line 819 of file ExecutionPipelineResource.cc.

822 {
823
824 if (initiationInterval_ != 0 && isLoopBypass(node)) {
825 cycle+=initiationInterval_;
826 }
827
828#ifdef DEBUG_RM
829 std::cerr << "\t\t\tcanAssignSource called for: " << node.toString() << " on cycle: "
830 << cycle << std::endl;
831#endif
832 int outputIndex = -1;
833 ProgramOperation* po = nullptr;
834
835 if (node.isSourceOperation()) {
836 po = &node.sourceOperation();
837 outputIndex = node.move().source().operationIndex();
838 } else {
839 assert(node.isGuardOperation());
840 po = &node.guardOperation();
841 outputIndex = po->outputIndexFromGuardOfMove(node);
842 }
843
844 const TTAMachine::HWOperation& hwop =
845 *fu_.operation(po->operation().name());
846
847 if (initiationInterval_ != 0 &&
848 hwop.latency(outputIndex) > (int)initiationInterval_) {
849#ifdef DEBUG_RM
850 std::cerr << "too long latency overlappingloop" << std::endl;
851#endif
852 return false;
853 }
854
855 /// Testing the result read move
856 /// Find the cycle first of the possible results of PO will be produced
857 int resultReady = node.earliestResultReadCycle();
858
859 /// Check if the port has a register. If not result read must be
860 /// in same cycle as result ready.
861 const TTAMachine::FUPort& port = *hwop.port(outputIndex);
862 if (resultReady != INT_MAX) {
863 if (port.noRegister() && resultReady != cycle) {
864 return false;
865 }
866
867 if (cycle < resultReady) {
868 // resultReady is INT_MAX if trigger was not scheduled yet
869 // also tested cycle can not be before result is in output
870 // register
871#ifdef DEBUG_RM
872 std::cerr << "\tresult not yet ready" << std::endl;
873#endif
874 return false;
875 }
876
877 const MoveNode* trigger = po->triggeringMove();
878 int triggerCycle = (trigger != NULL && trigger->isPlaced()) ?
879 trigger->cycle() : -1;
881 cycle, resultReady, node, resultPort,
882 trigger, triggerCycle) &&
884 resultReady, *po, resultPort, *trigger, triggerCycle);
885 } else {
886 // trigger not yet scheduled, do not know when result ready
887 if (hasConflictingResultsOnCycle(*po, resultPort, cycle)) {
888#ifdef DEBUG_RM
889 std::cerr << "Other op writing result at same cycle, this is illgal" << std::endl;
890#endif
891 return false;
892 }
893
894 // limit result cycle to latency of operation, so that
895 // trigger does nto have to be scheduled to negative cycle.
896 // find the OSAL id of the operand of the output we are reading
897 // ignore this for guard ops due to the thread switch kludge.
898 if (hwop.latency(outputIndex) > cycle && node.isSourceOperation()) {
899#ifdef DEBUG_RM
900 std::cerr << "\t\t\t\t\ttrigger needs negative cycle" << std::endl;
901#endif
902 return false;
903 }
904
905 // If some another result read of this op is scheduled,
906 // take the trigger cycle from that and call resultNotOverWritten?
907
908 MoveNodeSet& allResults = po->outputNode(outputIndex);
909 if (allResults.count() >1) {
910#ifdef DEBUG_RM
911 std::cerr << "\t\t\t\tSame op has multiple results." << std::endl;
912#endif
913 const MoveNode* trigger = NULL;
914 for (int i = 0; i < allResults.count(); i++) {
915 MoveNode& res = allResults.at(i);
916 if (&res == &node || !res.isPlaced()) {
917 continue;
918 }
919 int resCycle = res.cycle();
920 if (initiationInterval_ && isLoopBypass(res)) {
921 resCycle += initiationInterval_;
922 }
923 resultReady = std::min(resultReady, resCycle);
924#ifdef DEBUG_RM
925 std::cerr << "\t\t\t\t\tother result, of node: "
926 << res.toString()
927 <<" used at cycle: " << resCycle << std::endl;
928#endif
929 if (trigger == NULL) {
930 trigger = po->triggeringMove();
931 }
932 if (cycle < resCycle && !resultNotOverWritten(
933 resCycle, cycle, node, resultPort, trigger,-1)) {
934 return false;
935 }
936 }
937 if (resultReady != INT_MAX && resultReady < cycle) {
938#ifdef DEBUG_RM
939 std::cerr << "\t\t\t\tChecking if res not overwritten."
940 << std::endl;
941#endif
943 cycle, resultReady, node, resultPort, trigger, -1)) {
944 return false;
945 }
946#ifdef DEBUG_RM
947 std::cerr << "\t\t\t\tres not overwritten." << std::endl;
948#endif
949 }
950 }
951
952 const MoveNode* trigger = po->triggeringMove();
953 int triggerCycle = (trigger != NULL && trigger->isPlaced()) ?
954 trigger->cycle() : -1;
955
956 // We need to test if the write in given cycle is possible
957 // even if we do not yet have trigger scheduled and
958 // node.earliestResultReadCycle() returns INT_MAX.
959 // This allows for comparison of result moves in Bottom-Up schedule
960
961#ifdef DEBUG_RM
962 std::cerr << "\t\t\t\tcheck if result allowed at this cycle?" << std::endl;
963#endif
965 cycle, *po, resultPort, *trigger, triggerCycle)) {
966 return false;
967 }
968
969#ifdef DEBUG_RM
970 std::cerr << "\t\t\t\tcheck if result causes trigger between opshares?" << std::endl;
971#endif
972
974 return false;
975 }
976 }
977 return true;
978}
bool hasConflictingResultsOnCycle(const ProgramOperation &po, const TTAMachine::Port &port, int cycle) const
bool resultNotOverWritten(int resultReadCycle, int resultReadyCycle, const MoveNode &node, const TTAMachine::Port &port, const MoveNode *trigger, int triggerCycle) const
bool resultAllowedAtCycle(int resultCycle, const ProgramOperation &po, const TTAMachine::Port &resultPort, const MoveNode &trigger, int triggerCycle) const
bool resultCausesTriggerBetweenOperandSharing(const MoveNode &mn, int cycle) const
int count() const
MoveNode & at(int index)
int earliestResultReadCycle() const
Definition MoveNode.cc:652
bool isGuardOperation() const
Definition MoveNode.cc:181
int cycle() const
Definition MoveNode.cc:421
bool isPlaced() const
Definition MoveNode.cc:352
int outputIndexFromGuardOfMove(const MoveNode &node) const
MoveNode * triggeringMove() const
MoveNodeSet & outputNode(int out) const
bool noRegister() const
Definition FUPort.cc:469
Terminal & source() const
Definition Move.cc:302

References assert, MoveNodeSet::at(), MoveNodeSet::count(), MoveNode::cycle(), MoveNode::earliestResultReadCycle(), fu_, MoveNode::guardOperation(), hasConflictingResultsOnCycle(), SchedulingResource::initiationInterval_, MoveNode::isGuardOperation(), isLoopBypass(), MoveNode::isPlaced(), MoveNode::isSourceOperation(), TTAMachine::HWOperation::latency(), MoveNode::move(), Operation::name(), TTAMachine::FUPort::noRegister(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), ProgramOperation::outputIndexFromGuardOfMove(), ProgramOperation::outputNode(), TTAMachine::HWOperation::port(), resultAllowedAtCycle(), resultCausesTriggerBetweenOperandSharing(), resultNotOverWritten(), resultPort(), TTAProgram::Move::source(), MoveNode::sourceOperation(), MoveNode::toString(), and ProgramOperation::triggeringMove().

Referenced by OutputFUResource::canAssign().

Here is the call graph for this function:

◆ checkOperandAllowed()

bool ExecutionPipelineResource::checkOperandAllowed ( const MoveNode currentMn,
const TTAMachine::Port port,
int  operandWriteCycle,
const OperandUseHelper operandUse,
int  operandUseModCycle,
ProgramOperation currOp 
) const
private

Definition at line 2234 of file ExecutionPipelineResource.cc.

2239 {
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}
virtual std::string name() const
Definition Port.cc:141
virtual const TTAMachine::Port & port() const
Definition Terminal.cc:378

References MoveNode::cycle(), TTAProgram::Move::destination(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), exclusiveMoves(), ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), SchedulingResource::instructionIndex(), MoveNode::isPlaced(), MoveNode::move(), TTAMachine::Port::name(), ExecutionPipelineResource::OperandUseHelper::po, TTAProgram::Terminal::port(), MoveNode::toString(), and ProgramOperation::toString().

Referenced by operandAllowedAtCycle().

Here is the call graph for this function:

◆ clear()

void ExecutionPipelineResource::clear ( )
overridevirtual

Clears bookkeeping of the scheduling resource.

After this call the state of the resource should be identical to a newly-created and initialized resource.

Reimplemented from SchedulingResource.

Definition at line 1759 of file ExecutionPipelineResource.cc.

1759 {
1761 fuExecutionPipeline_.clear();
1762 resultWriten_.clear();
1763 operandsUsed_.clear();
1764 operandsWriten_.clear();
1765 resultRead_.clear();
1766 operandsWriten_.clear();
1767 storedResultCycles_.clear();
1768 assignedSourceNodes_.clear();
1770 cachedSize_ = 0;
1771 ddg_ = NULL;
1773}

References assignedDestinationNodes_, assignedSourceNodes_, cachedSize_, SchedulingResource::clear(), ddg_, fuExecutionPipeline_, operandShareCount_, operandsUsed_, operandsWriten_, resultRead_, resultWriten_, and storedResultCycles_.

Here is the call graph for this function:

◆ cyclesConflict()

bool ExecutionPipelineResource::cyclesConflict ( const MoveNode mn1,
const MoveNode mn2,
int  guardCycle,
int  rangeFirst,
int  rangeLast,
int  targetCycle 
) const
private

Definition at line 2843 of file ExecutionPipelineResource.cc.

2845 {
2846 if (exclusiveMoves(mn1, mn2, guardCycle)) {
2847 return false;
2848 }
2849 return cyclesOverlap (rangeFirst, rangeLast, targetCycle);
2850}
bool cyclesOverlap(int rangeFirst, int rangeLast, int targetCycle) const

References cyclesOverlap(), and exclusiveMoves().

Referenced by operandSharePreventsTriggerForScheduledResult().

Here is the call graph for this function:

◆ cyclesOverlap()

bool ExecutionPipelineResource::cyclesOverlap ( int  rangeFirst,
int  rangeLast,
int  targetCycle 
) const
inlineprivate

Definition at line 2823 of file ExecutionPipelineResource.cc.

2824 {
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}

References SchedulingResource::instructionIndex().

Referenced by cyclesConflict().

Here is the call graph for this function:

◆ exclusiveMoves()

bool ExecutionPipelineResource::exclusiveMoves ( const MoveNode mn1,
const MoveNode mn2,
int  cycle = INT_MAX 
) const
private

Checks whether both of two moves have exclusive guards so that both moves are never executed, only either of those. Those can then be scheduled to use same resources.

This checks that the guards are exclusive, and that the moves are to be scheduled in same cycle (one already scheduled, on is going to be scheudled to given cycle, which has to be the same. the same cycle requirements makes sure the value of the guard cannot be changed between the moves.

Parameters
mn1movenode which has already been scheduled
mn2move which we are going to schedule
cyclecycle where we are going to scheudle mn2.

Definition at line 1719 of file ExecutionPipelineResource.cc.

1720 {
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}
bool exclusingGuards(const MoveNode &mn1, const MoveNode &mn2) const
bool isMove() const
virtual bool isOpposite(const Guard &guard) const =0
const TTAMachine::Guard & guard() const
Definition MoveGuard.cc:86
MoveGuard & guard() const
Definition Move.cc:345
bool isUnconditional() const
Definition Move.cc:154

References MoveNode::cycle(), ddg_, DataDependenceGraph::exclusingGuards(), TTAProgram::Move::guard(), TTAProgram::MoveGuard::guard(), MoveNode::isMove(), TTAMachine::Guard::isOpposite(), MoveNode::isPlaced(), TTAProgram::Move::isUnconditional(), and MoveNode::move().

Referenced by assignDestination(), checkOperandAllowed(), cyclesConflict(), hasConflictingResultsOnCycle(), nextResultCycle(), operandAllowedAtCycle(), operandOverwritten(), operandPossibleAtCycle(), otherTriggerBeforeMyTrigger(), resourcesAllowTrigger(), resultAllowedAtCycle(), and resultCausesTriggerBetweenOperandSharing().

Here is the call graph for this function:

◆ findRange()

void ExecutionPipelineResource::findRange ( const int  cycle,
const MoveNode node,
int  popIndex,
int &  first,
int &  last,
int &  triggering 
) const
private

Find first and last cycles already scheduled for same PO.

◆ hasConflictingResultsOnCycle()

bool ExecutionPipelineResource::hasConflictingResultsOnCycle ( const ProgramOperation po,
const TTAMachine::Port port,
int  cycle 
) const

Definition at line 1559 of file ExecutionPipelineResource.cc.

1561 {
1562 ResultMap::const_iterator rwi = resultWriten_.find(&port);
1563 if (rwi == resultWriten_.end()) {
1564 return false;
1565 }
1566
1567 unsigned int modCycle = instructionIndex(cycle);
1568 MoveNode* trigger = po.triggeringMove();
1569 const ResultHelperPair& rhp =
1571 rwi->second, modCycle);
1572
1573 if (rhp.first.count != 0) {
1574 assert(rhp.first.po != NULL);
1575 if (rhp.first.po != &po &&
1577 rhp.first.po->triggeringMove(), trigger, INT_MAX)) {
1578 return true;
1579 }
1580 if (rhp.second.po != &po && rhp.second.count != 0) {
1581 assert(rhp.second.po != NULL);
1582 if (!exclusiveMoves(
1583 rhp.second.po->triggeringMove(), trigger, INT_MAX)) {
1584 return true;
1585 }
1586 }
1587 }
1588 return false;
1589}
static KeyType keyForValue(const MapType &aMap, const ValueType &aValue)

References assert, exclusiveMoves(), SchedulingResource::instructionIndex(), MapTools::keyForValue(), resultWriten_, and ProgramOperation::triggeringMove().

Referenced by canAssignSource().

Here is the call graph for this function:

◆ highestKnownCycle()

int ExecutionPipelineResource::highestKnownCycle ( ) const

Returns the highest cycle known to Execution Pipeline to be used by either pipeline resources or some operands, trigger or result read/write

TODO: module thingies

Returns
Highest cycle in which the pipeline is known to be used.

Definition at line 1479 of file ExecutionPipelineResource.cc.

1479 {
1480 if (initiationInterval_ == 0 || initiationInterval_ == INT_MAX) {
1481
1482 // Find largest cycle where any operand or result was previously
1483 // scheduled.
1484 int maximum = 0;
1485 if (assignedDestinationNodes_.size() > 0) {
1486 maximum = (*assignedDestinationNodes_.rbegin()).first;
1487 } else {
1488 maximum = -1;
1489 }
1490
1491 int maxResults = 0;
1492 if (assignedSourceNodes_.size() > 0) {
1493 maxResults = (*assignedSourceNodes_.rbegin()).first;
1494 } else {
1495 maxResults = 0;
1496 }
1497 if (maxResults> maximum) {
1498 maximum = maxResults;
1499 }
1500 // size returns count of cycle, max cycle address needs -1
1501 return std::max(maximum, (int)(size()) - 1);
1502 } else {
1503 int highest = -1;
1504 int min = INT_MAX;
1505 if (assignedSourceNodes_.size() > 0) {
1506 int srcMin = (*assignedSourceNodes_.begin()).first;
1507 min = std::min(min, srcMin);
1508 }
1509 if (assignedDestinationNodes_.size() > 0) {
1510 int dstMin = (*assignedDestinationNodes_.begin()).first;
1511 min = std::min(min, dstMin);
1512 }
1513
1514 for (ResultMap::const_iterator rwi = resultWriten_.begin();
1515 rwi != resultWriten_.end(); rwi++) {
1516 const ResultVector& resultWriten = rwi->second;
1517
1518 for (int i = resultWriten.size() -1; i >= min; i--) {
1519 const ResultHelperPair& rhp =
1521 resultWriten,i);
1522 if (rhp.first.po != NULL) {
1523 if (int(rhp.first.realCycle) > highest) {
1524 highest = rhp.first.realCycle;
1525 }
1526 if (rhp.second.po != NULL) {
1527 if (int(rhp.second.realCycle) > highest) {
1528 highest = rhp.second.realCycle;
1529 }
1530 }
1531 }
1532 }
1533 }
1534 for (ResultMap::const_iterator rri = resultRead_.begin();
1535 rri != resultRead_.end(); rri++) {
1536 const ResultVector& resultRead = rri->second;
1537 for (int i = resultRead.size() -1; i >= min ; i--) {
1538 const ResultHelperPair& rrp =
1540 resultRead,i);
1541 if (rrp.first.po != NULL) {
1542 if (int(rrp.first.realCycle) > highest) {
1543 highest = rrp.first.realCycle;
1544 }
1545 if (rrp.second.po != NULL) {
1546 if (int(rrp.second.realCycle) > highest) {
1547 highest = rrp.second.realCycle;
1548 }
1549 }
1550 }
1551 }
1552 }
1553 // TODO: operand writes not yet handled for this.
1554 return highest;
1555 }
1556}

References assignedDestinationNodes_, assignedSourceNodes_, SchedulingResource::initiationInterval_, MapTools::keyForValue(), resultRead_, resultWriten_, size(), and SparseVector< ValueType >::size().

Referenced by ExecutionPipelineBroker::highestKnownCycle().

Here is the call graph for this function:

◆ isAvailable()

bool ExecutionPipelineResource::isAvailable ( const int  cycle) const
overridevirtual

Test if resource ExecutionPipelineResource is available for any of the supported operations (at least one).

Parameters
cycleCycle which to test
Returns
True if ExecutionPipelineResource is available in cycle

Implements SchedulingResource.

Definition at line 178 of file ExecutionPipelineResource.cc.

178 {
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}
SparseVector< MoveNodePtrPair > OperandWriteVector
virtual BaseFUPort * port(const std::string &name) const
virtual int portCount() const
Definition Unit.cc:135

References fu_, SchedulingResource::instructionIndex(), operandsWriten_, TTAMachine::FunctionUnit::port(), and TTAMachine::Unit::portCount().

Here is the call graph for this function:

◆ isDestOpOfMN()

bool ExecutionPipelineResource::isDestOpOfMN ( const MoveNode mn,
const ProgramOperation po 
) const
private

Definition at line 2477 of file ExecutionPipelineResource.cc.

2478 {
2479 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
2481 if (&p == &po) {
2482 return true;
2483 }
2484 }
2485 return false;
2486}

References MoveNode::destinationOperation(), and MoveNode::destinationOperationCount().

Referenced by otherTriggerBeforeMyTrigger().

Here is the call graph for this function:

◆ isExecutionPipelineResource()

bool ExecutionPipelineResource::isExecutionPipelineResource ( ) const
overridevirtual

Always return true.

Returns
true

Reimplemented from SchedulingResource.

Definition at line 1378 of file ExecutionPipelineResource.cc.

1378 {
1379 return true;
1380}

◆ isInUse()

bool ExecutionPipelineResource::isInUse ( const int  cycle) const
overridevirtual

Test if resource ExecutionPipelineResource is used in given cycle.

If there is any of pipeline resources already used in given cycle.

Parameters
cycleCycle which to test
Returns
True if ExecutionPipelineResource is already used in cycle
Exceptions
Internalerror, the recorded resource usage for cycle is shorter then the number of resources the FU has.

Some result is already read in tested cycle

Cycle is beyond already scheduled scope, not in use therefore

Some pipeline resource is already in use in tested cycle

Implements SchedulingResource.

Definition at line 117 of file ExecutionPipelineResource.cc.

117 {
118
119 // check if any operand port is used
120 int modCycle = instructionIndex(cycle);
121 for (OperandWriteMap::const_iterator i = operandsWriten_.begin();
122 i != operandsWriten_.end(); i++) {
123
124 const OperandWriteVector& operandWrites = i->second;
125 OperandWriteVector::const_iterator j = operandWrites.find(modCycle);
126 if (j != operandWrites.end()) {
127 return true;
128 }
129 }
130
131 for (ResultMap::const_iterator rri = resultRead_.begin();
132 rri != resultRead_.end(); rri++) {
133 const ResultVector& resultRead = rri->second;
134 unsigned int resultReadCount = resultRead.rbegin()->first;//.size();
135 if (modCycle < (int)resultReadCount &&
137 resultRead, modCycle)).first.po != NULL) {
138 /// Some result is already read in tested cycle
139 return true;
140 }
141 }
142 if (modCycle >= (int)size()) {
143 /// Cycle is beyond already scheduled scope, not in use therefore
144 return false;
145 }
148 fuExecutionPipeline_, modCycle)).size()) {
149 std::string msg = "Execution pipeline is missing resources!";
150 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
151 }
152 for (unsigned int i = 0; i < resources->numberOfResources(); i++) {
153 const ResourceReservationVector& rrv =
155 fuExecutionPipeline_, modCycle);
156 if (rrv.size() == 0) {
157 return false;
158 }
159
160 const ResourceReservation& rr = rrv[i];
161
162 if (rr.first != NULL) {
163 /// Some pipeline resource is already in use in tested cycle
164 return true;
165 }
166 }
167 return false;
168}

References __func__, fuExecutionPipeline_, SchedulingResource::instructionIndex(), MapTools::keyForValue(), ExecutionPipelineResourceTable::numberOfResources(), operandsWriten_, resources, resultRead_, and size().

Here is the call graph for this function:

◆ isLoopBypass()

bool ExecutionPipelineResource::isLoopBypass ( const MoveNode node) const
private

Definition at line 791 of file ExecutionPipelineResource.cc.

791 {
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}
bool hasNode(const Node &) const
virtual EdgeSet inEdges(const Node &node) const
EdgeReason edgeReason() const

References ddg_, DataDependenceEdge::EDGE_OPERATION, DataDependenceEdge::edgeReason(), BoostGraph< GraphNode, GraphEdge >::hasNode(), BoostGraph< GraphNode, GraphEdge >::inEdges(), and DataDependenceEdge::isBackEdge().

Referenced by assignSource(), canAssignSource(), latestTriggerWriteCycle(), and testTriggerResult().

Here is the call graph for this function:

◆ latestTriggerWriteCycle()

int ExecutionPipelineResource::latestTriggerWriteCycle ( const MoveNode mn) const
private

Returns the lates cycle the given trigger move can be scheduled at, taking in the account the latency of the operation results.

In case the none of the result moves has been scheduled yet, returns INT_MAX.

Exceptions
IllegalObjectif this MoveNode is not a result read.

Definition at line 2393 of file ExecutionPipelineResource.cc.

2394 {
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}
bool isScheduled() const
Definition MoveNode.cc:409
int outputMoveCount() const
const TTAMachine::FunctionUnit * fuFromOutMove(const MoveNode &outputNode) const
MoveNode & outputMove(int index) const
int outputIndexOfMove(const MoveNode &mn) const

References __func__, MoveNode::cycle(), MoveNode::destinationOperation(), ProgramOperation::fuFromOutMove(), SchedulingResource::initiationInterval_, MoveNode::isDestinationOperation(), isLoopBypass(), MoveNode::isScheduled(), TTAMachine::HWOperation::latency(), Operation::name(), ProgramOperation::operation(), ProgramOperation::outputIndexOfMove(), ProgramOperation::outputMove(), and ProgramOperation::outputMoveCount().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ nextResultCycle()

int ExecutionPipelineResource::nextResultCycle ( const TTAMachine::Port port,
int  cycle,
const MoveNode node,
const MoveNode trigger = NULL,
int  triggerCycle = INT_MAX 
) const

Returns a cycle in which result of next program operation will be writen to result. This method results the next one of any iteration, not just the current iteration.

Parameters
cycleCycle from which to start testing.
nodeNode for which to test
Returns
Cycle in which next result will be writen, overwriting curent one.

Definition at line 1602 of file ExecutionPipelineResource.cc.

1605 {
1606
1607 ResultMap::const_iterator rwi = resultWriten_.find(&port);
1608 if (rwi == resultWriten_.end()) {
1609 return INT_MAX;
1610 }
1611 const ResultVector& resultWriten = rwi->second;
1612
1613 ProgramOperation* sourcePo;
1614 if (!node.isSourceOperation()) {
1615 if (node.isGuardOperation()) {
1616 sourcePo = &node.guardOperation();
1617 } else {
1618 throw InvalidData(__FILE__, __LINE__, __func__,
1619 "Trying to get next result for move that is not"
1620 " in ProgramOperation");
1621 }
1622 } else {
1623 sourcePo = &node.sourceOperation();
1624 if (trigger == NULL) {
1625 trigger = sourcePo->triggeringMove();
1626 }
1627 }
1628
1629 unsigned int ii = initiationInterval_;
1630 if (ii < 1) {
1631 ii = INT_MAX;
1632 }
1633
1634 unsigned int rwSize = resultWriten.size();
1635 for (unsigned int i = cycle; i < cycle + ii; i++) {
1636 unsigned int modi = instructionIndex(i);
1637
1638 if (rwSize <= modi) {
1639 if (ii == INT_MAX) {
1640 return INT_MAX;
1641 } else {
1642 continue;
1643 }
1644 }
1645
1646 const ResultHelperPair& rhp =
1648 if (rhp.first.count != 0) {
1649 assert(rhp.first.po != NULL);
1650 if (rhp.first.po != sourcePo &&
1652 rhp.first.po->triggeringMove(), trigger,
1653 triggerCycle)) {
1654 return rhp.first.realCycle;
1655 }
1656 if (rhp.second.po != sourcePo && rhp.second.count != 0) {
1657 assert(rhp.second.po != NULL);
1658 if (!exclusiveMoves(
1659 rhp.second.po->triggeringMove(), trigger,
1660 triggerCycle)) {
1661 return rhp.second.realCycle;
1662 }
1663 }
1664 }
1665 }
1666 return INT_MAX;
1667}

References __func__, assert, exclusiveMoves(), MoveNode::guardOperation(), SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), MoveNode::isGuardOperation(), MoveNode::isSourceOperation(), MapTools::keyForValue(), resultWriten_, SparseVector< ValueType >::size(), MoveNode::sourceOperation(), and ProgramOperation::triggeringMove().

Referenced by ExecutionPipelineBroker::latestFromSource(), and resultNotOverWritten().

Here is the call graph for this function:

◆ nodeOfInputPort()

const MoveNode * ExecutionPipelineResource::nodeOfInputPort ( const ProgramOperation po,
TTAMachine::Port port 
)
private

Definition at line 2853 of file ExecutionPipelineResource.cc.

2854 {
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}
std::vector< MoveNode * >::iterator begin()
MoveNodeSet & inputNode(int in) const
int io(const FUPort &port) const

References MoveNodeSet::begin(), fu_, ProgramOperation::inputNode(), TTAMachine::HWOperation::io(), Operation::name(), ProgramOperation::operation(), and TTAMachine::FunctionUnit::operation().

Here is the call graph for this function:

◆ operandAllowedAtCycle()

bool ExecutionPipelineResource::operandAllowedAtCycle ( const TTAMachine::Port port,
const MoveNode mn,
int  cycle 
) const
private

Definition at line 2131 of file ExecutionPipelineResource.cc.

2132 {
2133#ifdef DEBUG_RM
2134 std::cerr << "\t\tTesting " << mn.toString() << " that operand at port: "
2135 << port.name() << " allowed at cycle: " << cycle << std::endl;
2136#endif
2137 int ii = initiationInterval();
2138 if (ii < 1) {
2139 ii = INT_MAX;
2140 }
2141
2142 OperandUseMap::const_iterator rui = operandsUsed_.find(&port);
2143 if (rui == operandsUsed_.end()) {
2144 return true;
2145 }
2146
2147 const OperandUseVector& operandUsed = rui->second;
2148 size_t operandUsedSize = operandUsed.size();
2149
2150 if (!mn.isDestinationOperation()) {
2151 throw InvalidData(__FILE__, __LINE__, __func__,
2152 "Trying to get next result for move that is not "
2153 "in ProgramOperation");
2154 }
2155
2156 // TODO: this may be very slow if big BB with not much code
2157 int nextOperandUseCycle = cycle;
2158 int nextOperandUseModCycle = instructionIndex(nextOperandUseCycle);
2159 OperandUseVector::const_iterator i =
2160 operandUsed.find(nextOperandUseModCycle);
2161
2162 while(true) {
2163#ifdef DEBUG_RM
2164 std::cerr << "\t\t\tTesting use from cycle: " << nextOperandUseCycle << std::endl;
2165#endif
2166 if (i != operandUsed.end()) {
2167#ifdef DEBUG_RM
2168 std::cerr << "\t\t\t\tcycle " << nextOperandUseCycle << " not empty." << std::endl;
2169#endif
2170 const OperandUseHelper& operandUse = i->second.first;
2171 if (operandUse.po != NULL) {
2172 const MoveNode* opUseTrigger =
2173 operandUse.po->triggeringMove();
2174 if (opUseTrigger != NULL) {
2175#ifdef DEBUG_RM
2176 std::cerr << "\t\t\t\tFound using trigger: " << opUseTrigger->toString() << std::endl;
2177#endif
2178 }
2179 if (!exclusiveMoves(opUseTrigger, &mn, cycle)) {
2180 /* destinationOperation(0) sounds suspicious */
2182 mn, port, cycle, operandUse, nextOperandUseModCycle,
2183 mn.destinationOperation(0))) {
2184 return false;
2185 }
2186 if (opUseTrigger == NULL ||
2187 opUseTrigger->move().isUnconditional()) {
2188 bool allScheduled = true;
2189 int imc = operandUse.po->inputMoveCount();
2190 for (int i = 0; i < imc; i++) {
2191 if (!operandUse.po->inputMove(i).isPlaced()) {
2192 allScheduled = false;
2193 break;
2194 }
2195 }
2196 if (allScheduled) {
2197 return true;
2198 }
2199 }
2200 }
2201 // conditional moves, second exclusive?
2202 const OperandUseHelper& operandUse2 = i->second.second;
2203 if (operandUse2.po != NULL) {
2204 const MoveNode& opUseTrigger2 =
2205 *operandUse2.po->triggeringMove();
2206 if (!exclusiveMoves(&opUseTrigger2, &mn, cycle)) {
2207 /* destinationOperation(0) sounds suspicious */
2209 mn, port, cycle, operandUse2,
2210 nextOperandUseModCycle,
2211 mn.destinationOperation(0))) {
2212 return false;
2213 }
2214 }
2215 }
2216 }
2217 }
2218 nextOperandUseCycle++;
2219
2220 if (ii == INT_MAX && nextOperandUseCycle >= (int)operandUsedSize) {
2221 return true;
2222 }
2223
2224 if (nextOperandUseCycle - cycle >= (int)ii) {
2225 return true;
2226 }
2227 nextOperandUseModCycle = instructionIndex(nextOperandUseCycle);
2228 i = operandUsed.find(nextOperandUseModCycle);
2229 }
2230
2231 return true;
2232}
SparseVector< OperandUsePair > OperandUseVector
bool checkOperandAllowed(const MoveNode &currentMn, const TTAMachine::Port &port, int operandWriteCycle, const OperandUseHelper &operandUse, int operandUseModCycle, ProgramOperation &currOp) const

References __func__, checkOperandAllowed(), MoveNode::destinationOperation(), exclusiveMoves(), SchedulingResource::initiationInterval(), ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), SchedulingResource::instructionIndex(), MoveNode::isDestinationOperation(), MoveNode::isPlaced(), TTAProgram::Move::isUnconditional(), MoveNode::move(), TTAMachine::Port::name(), operandsUsed_, ExecutionPipelineResource::OperandUseHelper::po, SparseVector< ValueType >::size(), MoveNode::toString(), and ProgramOperation::triggeringMove().

Referenced by canAssignDestination(), resultCausesTriggerBetweenOperandSharing(), and triggerAllowedAtCycle().

Here is the call graph for this function:

◆ operandOverwritten() [1/2]

bool ExecutionPipelineResource::operandOverwritten ( const MoveNode mn,
int  cycle 
) const
private

Definition at line 1105 of file ExecutionPipelineResource.cc.

1106 {
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}

References MoveNode::cycle(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), MoveNode::isPlaced(), operandOverwritten(), MoveNode::toString(), ProgramOperation::toString(), and ProgramOperation::triggeringMove().

Here is the call graph for this function:

◆ operandOverwritten() [2/2]

bool ExecutionPipelineResource::operandOverwritten ( int  operandWriteCycle,
int  triggerCycle,
const ProgramOperation po,
const MoveNode operand,
const MoveNode trigger 
) const
private

Definition at line 1137 of file ExecutionPipelineResource.cc.

1142 {
1143
1144 unsigned int ii = initiationInterval_;
1145 if (ii < 1) {
1146 ii = INT_MAX;
1147 }
1148
1149#ifdef DEBUG_RM
1150 std::cerr << "\t\t\tOperandOverWritten called for: " << operand.toString()
1151 << " PO: " << po.toString()
1152 << " trigger: " << trigger.toString() << "owc: "
1153 << operandWriteCycle << " tc: " << triggerCycle << std::endl;
1154#endif
1155 const Operation& op = po.operation();
1157
1158 int opIndex = operand.move().destination().operationIndex();
1159 const TTAMachine::Port& port = *hwop.port(opIndex);
1160 int operandUseCycle = triggerCycle + hwop.slack(opIndex);
1161
1162 // same op on next loop iteration overwrites?
1163 if (operandUseCycle - operandWriteCycle >= (int)ii) {
1164#ifdef DEBUG_RM
1165 std::cerr << "\t\t\t\tOperand LR over loop iteration(2): " << ii
1166 << std::endl;
1167#endif
1168 return true;
1169 }
1170
1171#ifdef DEBUG_RM
1172 std::cerr << "\t\t\t\tTesting port: " << port.name() << std::endl;
1173#endif
1174 OperandWriteMap::const_iterator iter = operandsWriten_.find(&port);
1175 if (iter == operandsWriten_.end()) {
1176 return false;
1177 }
1178 const OperandWriteVector& operandWritten = iter->second;
1179#ifdef DEBUG_RM
1180
1181 std::cerr << "\t\t\t\tOperandWriteCycle: " << operandWriteCycle << std::endl
1182 << "\t\t\t\tOperandUseCycle: " << operandUseCycle << std::endl;
1183#endif
1184
1185 for (int j = operandWriteCycle; j <= operandUseCycle; j++) {
1186#ifdef DEBUG_RM
1187 std::cerr << "\t\t\t\tTesting if overwritten in cycle: " << j << std::endl;
1188#endif
1189 unsigned int modCycle = instructionIndex(j);
1190 OperandWriteVector::const_iterator owi = operandWritten.find(modCycle);
1191 if (owi == operandWritten.end()) {
1192 continue;
1193 }
1194 const MoveNodePtrPair& mnpp = owi->second;
1195 if (mnpp.first != NULL && mnpp.first != &operand &&
1196 !exclusiveMoves(mnpp.first, &trigger, triggerCycle)) {
1197#ifdef DEBUG_RM
1198 std::cerr << "\t\t\t\t\tOverwritten by: " << mnpp.first->toString() << std::endl;
1199#endif
1200 return true;
1201 }
1202 if (mnpp.second != NULL && mnpp.second != &operand &&
1203 !exclusiveMoves(mnpp.second, &trigger, triggerCycle)) {
1204#ifdef DEBUG_RM
1205 std::cerr << "\t\t\t\t\tOverwritten(2) by: " << mnpp.second->toString() << std::endl;
1206#endif
1207 return true;
1208 }
1209 }
1210#ifdef DEBUG_RM
1211 std::cerr << "\t\t\tNot overwritten" << std::endl;
1212#endif
1213 return false;
1214}
int slack(int input) const

References TTAProgram::Move::destination(), exclusiveMoves(), fu_, SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), MoveNode::move(), TTAMachine::Port::name(), Operation::name(), operandsWriten_, ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), TTAMachine::HWOperation::port(), TTAMachine::HWOperation::slack(), MoveNode::toString(), and ProgramOperation::toString().

Referenced by canAssignDestination(), operandOverwritten(), and operandsOverwritten().

Here is the call graph for this function:

◆ operandPort()

const TTAMachine::Port & ExecutionPipelineResource::operandPort ( const MoveNode mn) const
private

◆ operandPossibleAtCycle()

bool ExecutionPipelineResource::operandPossibleAtCycle ( const TTAMachine::Port port,
const MoveNode mn,
int  cycle 
) const
private

Checks that no other operand of another op is written at exactly same cycle

Definition at line 2106 of file ExecutionPipelineResource.cc.

2107 {
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}

References exclusiveMoves(), SchedulingResource::instructionIndex(), and operandsWriten_.

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ operandSharePreventsTriggerForScheduledResult()

bool ExecutionPipelineResource::operandSharePreventsTriggerForScheduledResult ( const TTAMachine::Port port,
const MoveNode mn,
int  cycle 
) const
private

Definition at line 2605 of file ExecutionPipelineResource.cc.

2606 {
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}
bool poConflictsWithInputPort(const TTAMachine::Port &port, const ProgramOperation &po, const MoveNode &mn) const
bool cyclesConflict(const MoveNode *mn1, const MoveNode *mn2, int guardCycle, int rangeFirst, int rangeLast, int targetCycle) const
virtual bool isFUPort() const
Definition Terminal.cc:118

References assert, MoveNode::cycle(), cyclesConflict(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), fu_, SchedulingResource::instructionIndex(), TTAMachine::HWOperation::io(), TTAProgram::Terminal::isFUPort(), MoveNode::isScheduled(), TTAMachine::HWOperation::latency(), MoveNode::move(), Operation::name(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), ProgramOperation::outputIndexOfMove(), ProgramOperation::outputMove(), ProgramOperation::outputMoveCount(), ExecutionPipelineResource::ResultHelper::po, poConflictsWithInputPort(), TTAProgram::Terminal::port(), TTAMachine::HWOperation::port(), ExecutionPipelineResource::ResultHelper::realCycle, resultRead_, TTAProgram::Move::source(), and ProgramOperation::triggeringMove().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ operandsOverwritten()

bool ExecutionPipelineResource::operandsOverwritten ( int  triggerCycle,
const MoveNode trigger 
) const

Definition at line 1216 of file ExecutionPipelineResource.cc.

1217 {
1218 ProgramOperation &po = trigger.destinationOperation();
1219#ifdef DEBUG_RM
1220 std::cerr << "\t\tTesting op overwrite for: " << po.toString() << " cycle: " << triggerCycle << std::endl;
1221#endif
1222 for (int i = 0; i < po.inputMoveCount(); i++) {
1223 MoveNode& inputMove = po.inputMove(i);
1224 if (&inputMove == &trigger) {
1225 continue;
1226 }
1227 if (!inputMove.isPlaced()) {
1229 triggerCycle, triggerCycle, po, inputMove, trigger)) {
1230 return true;
1231 }
1232 continue;
1233 }
1234 int operandWriteCycle = inputMove.cycle();
1236 operandWriteCycle, triggerCycle, po, inputMove, trigger)) {
1237 return true;
1238 }
1239 }
1240 return false;
1241}
int inputMoveCount() const
MoveNode & inputMove(int index) const

References MoveNode::cycle(), MoveNode::destinationOperation(), ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), MoveNode::isPlaced(), operandOverwritten(), and ProgramOperation::toString().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ operandTooLate()

bool ExecutionPipelineResource::operandTooLate ( const MoveNode mn,
int  cycle 
) const
private

Checks that operand is not scheduled too late(after trigger+slack)

Definition at line 2291 of file ExecutionPipelineResource.cc.

2291 {
2292 for (unsigned int i = 0; i < mn.destinationOperationCount(); i++) {
2294 MoveNode* trigger = po.triggeringMove();
2295 if (trigger == &mn) {
2296#ifdef DEBUG_RM
2297 std::cerr << "\t\t\tmn is trigger, no need to check overwrite" << std::endl;
2298#endif
2299 return false;
2300 }
2301 if (trigger == NULL || !trigger->isPlaced()) {
2302 continue;
2303 }
2304
2305 const Operation& op = po.operation();
2307
2308 int opIndex = mn.move().destination().operationIndex();
2309 int slack = hwop.slack(opIndex);
2310 const TTAMachine::FUPort& port = *hwop.port(opIndex);
2311 if (port.noRegister()) {
2312 if (cycle != trigger->cycle() + slack) {
2313 return true;
2314 }
2315 } else {
2316 if (cycle > trigger->cycle() + slack) {
2317 return true;
2318 }
2319 }
2320 }
2321 return false;
2322}

References MoveNode::cycle(), TTAProgram::Move::destination(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), fu_, MoveNode::isPlaced(), MoveNode::move(), Operation::name(), TTAMachine::FUPort::noRegister(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), TTAMachine::HWOperation::port(), TTAMachine::HWOperation::slack(), and ProgramOperation::triggeringMove().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ operator=()

ExecutionPipelineResource & ExecutionPipelineResource::operator= ( const ExecutionPipelineResource )
private

◆ otherTriggerBeforeMyTrigger()

bool ExecutionPipelineResource::otherTriggerBeforeMyTrigger ( const TTAMachine::Port port,
const MoveNode node,
int  cycle 
) const

Definition at line 2425 of file ExecutionPipelineResource.cc.

2426 {
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++) {
2432 ProgramOperation& po = mn.destinationOperation(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}
bool isDestOpOfMN(const MoveNode &mn, const ProgramOperation &po) const

References MoveNode::cycle(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), exclusiveMoves(), SchedulingResource::instructionIndex(), isDestOpOfMN(), MoveNode::isScheduled(), operandsUsed_, and ProgramOperation::triggeringMove().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ poConflictsWithInputPort()

bool ExecutionPipelineResource::poConflictsWithInputPort ( const TTAMachine::Port port,
const ProgramOperation po,
const MoveNode mn 
) const
private

Definition at line 2866 of file ExecutionPipelineResource.cc.

2869 {
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}
Unit * parentUnit() const

References TTAProgram::Move::destination(), ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), TTAProgram::Terminal::isFUPort(), MoveNode::move(), Operation::name(), Operation::numberOfInputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::Port::parentUnit(), TTAProgram::Terminal::port(), and TTAMachine::HWOperation::port().

Referenced by operandSharePreventsTriggerForScheduledResult().

Here is the call graph for this function:

◆ resourcesAllowTrigger()

bool ExecutionPipelineResource::resourcesAllowTrigger ( int  cycle,
const MoveNode move 
) const
private

Definition at line 1244 of file ExecutionPipelineResource.cc.

1245 {
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}
bool hasOperation(const std::string &opName) const
virtual bool canAssign(const int cycle, const MoveNode &node) const override
size_t size() const

References assert, canAssign(), TTAProgram::Move::destination(), exclusiveMoves(), fuExecutionPipeline_, ExecutionPipelineResourceTable::hasOperation(), TTAProgram::Terminal::hintOperation(), SchedulingResource::initiationInterval(), SchedulingResource::instructionIndex(), TTAProgram::Terminal::isOpcodeSetting(), maxCycle_, ExecutionPipelineResourceTable::maximalLatency(), MoveNode::move(), Operation::name(), ExecutionPipelineResourceTable::numberOfResources(), TTAProgram::Terminal::operation(), ExecutionPipelineResourceTable::operationIndex(), ExecutionPipelineResourceTable::operationPipeline(), resources, size(), and SparseVector< ValueType >::size().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ resultAllowedAtCycle()

bool ExecutionPipelineResource::resultAllowedAtCycle ( int  resultCycle,
const ProgramOperation po,
const TTAMachine::Port resultPort,
const MoveNode trigger,
int  triggerCycle 
) const
private

Tests that a new result at given cycle does not mess up result of some other operation

Parameters
resultCyclecycle when the nw result appears @po Programoperation which the new result belongs to @resultPort port where the result is written to @trigger trigger movenode of the operation @triggercycle cycle of the trigger

Definition at line 1852 of file ExecutionPipelineResource.cc.

1856 {
1857
1858#ifdef DEBUG_RM
1859 if (&trigger != NULL) {
1860 std::cerr << "\t\tChecking that result for po: " << po.toString() << " allowed at cycle "
1861 << resultCycle << " , trigger: " << trigger.toString() << " at cycle: " << triggerCycle << std::endl;
1862 } else {
1863 std::cerr << "\t\tChecking that result for po: " << po.toString() << " allowed at cycle "
1864 << resultCycle << " , trigger: NULL at cycle: " << triggerCycle << std::endl;
1865 }
1866#endif
1867 // if none found from the map, this used.
1868 ResultVector empty;
1869 ResultMap::const_iterator rri = resultRead_.find(&resultPort);
1870
1871 const ResultVector& resultRead = (rri != resultRead_.end()) ?
1872 rri->second : empty;
1873
1874 unsigned int ii = initiationInterval_;
1875 if (ii < 1) {
1876 ii = INT_MAX;
1877 }
1878
1879 unsigned int rrSize = resultRead.size();
1880 unsigned int rrMod = instructionIndex(resultCycle);
1881 for (unsigned int i = rrMod; i < rrMod + ii; i++) {
1882 unsigned int modi = instructionIndex(i);
1883 bool modiLooped = modi < rrMod;
1884
1885 if (modi >= rrSize) {
1886 if (ii == INT_MAX) {
1887 break;
1888 } else {
1889 // may be read at small instr index of next iteration.
1890 // so may not abort, but can skip this cycle.
1891 continue;
1892 }
1893 }
1894 const ResultHelperPair& resultReadPair =
1896 if (resultReadPair.first.count > 0) {
1897 // same operation reading result again. cannot fail.
1898 if (resultReadPair.first.po != &po) {
1899 assert (resultReadPair.first.po != NULL);
1900
1901 // first check conflicts to first of po.
1902 MoveNode* otherTrigger =
1903 resultReadPair.first.po->triggeringMove();
1904 if (!exclusiveMoves(otherTrigger, &trigger, triggerCycle)) {
1905 if (resultReadPair.first.po == &po) {
1906 break;
1907 }
1908 // here check conflicts against first.
1909 int otherReady = resultReadyCycle(
1910 *resultReadPair.first.po, resultPort);
1911
1912 if (otherReady == -1) {
1913 otherReady = modi;
1914 }
1915 int or2Mod = instructionIndex(otherReady);
1916 bool orLooped = or2Mod > (int)modi; // FAIL HERE?
1917
1918#ifdef DEBUG_RM
1919 std::cerr << "\t\t\tOther po: " << resultReadPair.first.po->toString() << std::endl;
1920 std::cerr << "\t\t\tOther ready: " << otherReady << std::endl;
1921 std::cerr << "\t\t\tRR cycle: " << rrMod << std::endl;
1922 std::cerr << "\t\t\tOther ready mod: " << or2Mod << std::endl;
1923#endif
1924 // neither looped or both looped.
1925 if (modiLooped == orLooped) {
1926 if ((or2Mod <= (int)rrMod && or2Mod != -1) &&
1927 (triggerCycle == -1 || or2Mod != -1)) {
1928#ifdef DEBUG_RM
1929 std::cerr << "\t\t\t\tfail(1)" << std::endl;
1930#endif
1931 return false;
1932 } else {
1933 if (otherTrigger != NULL &&
1934 otherTrigger->move().isUnconditional()) {
1935 break;
1936 }
1937 }
1938 } else {
1939 // either one looped, order has to be reverse.
1940 if (or2Mod >= (int)rrMod && (triggerCycle == -1 || or2Mod != -1)) {
1941#ifdef DEBUG_RM
1942 std::cerr << "\t\t\t\tfail(2)" << std::endl;
1943#endif
1944 return false;
1945 } else {
1946 if (otherTrigger != NULL &&
1947 otherTrigger->move().isUnconditional()) {
1948 break;
1949 }
1950 }
1951 }
1952 }
1953 }
1954
1955 // then check conflicts to second po
1956 if (resultReadPair.second.count > 0) {
1957 MoveNode* otherTrigger =
1958 resultReadPair.second.po->triggeringMove();
1959 if (!exclusiveMoves(otherTrigger, &trigger, triggerCycle)) {
1960 if (resultReadPair.second.po == &po) {
1961 break;
1962 }
1963 int otherReady = resultReadyCycle(
1964 *resultReadPair.second.po, resultPort);
1965
1966 int or2Mod = instructionIndex(otherReady);
1967 bool orLooped = or2Mod > (int)modi;
1968
1969 // neither looped or both looped.
1970 if (modiLooped == orLooped) {
1971 if (or2Mod <= (int)rrMod &&
1972 (triggerCycle == -1 || or2Mod != -1)) {
1973#ifdef DEBUG_RM
1974 std::cerr << "\t\t\t\tfail(3)" << std::endl;
1975#endif
1976 return false;
1977 } else {
1978 if (otherTrigger != NULL &&
1979 otherTrigger->move().isUnconditional()) {
1980 break;
1981 }
1982 }
1983 } else {
1984 // either looped, order has to be reverse.
1985 if (or2Mod >= (int)rrMod &&
1986 (triggerCycle == -1 || or2Mod != -1)) {
1987#ifdef DEBUG_RM
1988 std::cerr << "\t\t\t\tfail(4)" << std::endl;
1989#endif
1990 return false;
1991 } else {
1992 if (otherTrigger != NULL &&
1993 otherTrigger->move().isUnconditional()) {
1994 break;
1995 }
1996 }
1997 }
1998 }
1999 }
2000 }
2001 }
2002 return true;
2003}
int resultReadyCycle(const ProgramOperation &po, const TTAMachine::Port &resultPort) const

References assert, exclusiveMoves(), SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), TTAProgram::Move::isUnconditional(), MapTools::keyForValue(), MoveNode::move(), resultPort(), resultRead_, resultReadyCycle(), SparseVector< ValueType >::size(), MoveNode::toString(), and ProgramOperation::toString().

Referenced by canAssignSource(), and testTriggerResult().

Here is the call graph for this function:

◆ resultCausesTriggerBetweenOperandSharing()

bool ExecutionPipelineResource::resultCausesTriggerBetweenOperandSharing ( const MoveNode mn,
int  cycle 
) const
private

Definition at line 2488 of file ExecutionPipelineResource.cc.

2489 {
2490
2491 if (!operandShareCount_) {
2492 return false;
2493 }
2494
2495 if (!mn.isSourceOperation()) {
2496 return false;
2497 }
2499 const MoveNode* trigger = po.findTriggerFromUnit(fu_);
2500 // if trigger is already scheduled, the checks have been done
2501 // while scheduling it.
2502 if (trigger == nullptr || trigger->isScheduled()) {
2503 return false;
2504 }
2505 const int outputIndex = po.outputIndexOfMove(mn);
2506 const TTAMachine::HWOperation& hwop =
2507 *fu_.operation(po.operation().name());
2508 const TTAMachine::Port* outPort = hwop.port(outputIndex);
2509 int latency = hwop.latency(outputIndex);
2510 int latestTriggerCycle = cycle - latency;
2511
2512 std::map<const TTAMachine::Port*, const MoveNode*> usedOperandPorts;
2513
2514 // result vector for the correct port
2515 auto rvi = resultRead_.find(outPort);
2516 if (rvi == resultRead_.end()) {
2517 return false;
2518 }
2519 auto& rv = rvi->second;
2520
2521 int smallestCycle = (*rv.begin()).first;
2522 int earliestAllowedResReady = -1;
2523
2524 for (int c = cycle-1;c >= smallestCycle;c--) {
2525 int mc = instructionIndex(c);
2526 auto ri = rv.find(mc);
2527 if (ri == rv.end()) {
2528 continue;
2529 }
2530 auto res = ri->second;
2531 ResultHelper& rh1 = res.first;
2532 ResultHelper& rh2 = res.second;
2533
2534 if (rh1.po != nullptr && rh1.po != &po) {
2535 int rc = rh1.realCycle;
2536 if (!exclusiveMoves(trigger, rh1.po->triggeringMove(), c-latency)) {
2537 earliestAllowedResReady = rc +1;
2538 break;
2539 }
2540 }
2541
2542 if (rh2.po != nullptr && rh2.po != &po) {
2543 int rc = rh2.realCycle;
2544 if (!exclusiveMoves(trigger, rh2.po->triggeringMove(), c-latency)) {
2545 earliestAllowedResReady = rc +1;
2546 break;
2547 }
2548 }
2549 }
2550
2551 if (earliestAllowedResReady == -1) {
2552 return false;
2553 }
2554
2555 int earliestTriggerCycle = earliestAllowedResReady - latency;
2556
2557 // if overlaps between earliest and last trigger
2558 if (earliestTriggerCycle > latestTriggerCycle &&
2559 initiationInterval_ != 0) {
2560 earliestTriggerCycle -= initiationInterval_;
2561 }
2562
2563#ifdef DEBUG_RM
2564 std::cerr << "\t\t\t\tEarliest allowed res ready: "
2565 << earliestAllowedResReady << std::endl;
2566 std::cerr << "\t\t\t\tEarliestTrigger cycle: "
2567 << earliestTriggerCycle << std::endl;
2568 std::cerr << "\t\t\t\tLatestTrigger cycle: "
2569 << latestTriggerCycle << std::endl;
2570#endif
2571
2572 bool ok = false;
2573 for (int c = latestTriggerCycle; c >= earliestTriggerCycle && !ok ; c--) {
2574
2575 bool fail = false;
2576 for (int i = 0; i < po.inputMoveCount(); i++) {
2577 const MoveNode& inMove = po.inputMove(i);
2578 if (!inMove.move().destination().isFUPort()) {
2579 continue;
2580 }
2581 const int inputIndex =
2582 inMove.move().destination().operationIndex();
2583 const TTAMachine::HWOperation& hwop =
2584 *fu_.operation(po.operation().name());
2585 auto inPort = hwop.port(inputIndex);
2586 if (!inPort->isTriggering()) {
2587 if (!operandAllowedAtCycle(*inPort, inMove,c)) {
2588 fail = true;
2589#ifdef DEBUG_RM
2590 std::cerr << "\t\t\t\t\tOperand not allowed at cycle: " << c << std::endl;
2591#endif
2592 continue;
2593 }
2594 }
2595 }
2596 if (!fail) {
2597 return false;
2598 }
2599 }
2600 return true;
2601}
MoveNode * findTriggerFromUnit(const TTAMachine::Unit &unit) const

References TTAProgram::Move::destination(), exclusiveMoves(), ProgramOperation::findTriggerFromUnit(), fu_, SchedulingResource::initiationInterval_, ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), SchedulingResource::instructionIndex(), TTAProgram::Terminal::isFUPort(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), TTAMachine::HWOperation::latency(), MoveNode::move(), Operation::name(), operandAllowedAtCycle(), operandShareCount_, ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), ProgramOperation::outputIndexOfMove(), ExecutionPipelineResource::ResultHelper::po, TTAMachine::HWOperation::port(), ExecutionPipelineResource::ResultHelper::realCycle, resultRead_, MoveNode::sourceOperation(), and ProgramOperation::triggeringMove().

Referenced by canAssignSource().

Here is the call graph for this function:

◆ resultNotOverWritten()

bool ExecutionPipelineResource::resultNotOverWritten ( int  resultReadCycle,
int  resultReadyCycle,
const MoveNode node,
const TTAMachine::Port resultPort,
const MoveNode trigger,
int  triggerCycle 
) const

Returns if the result can be scheduled to given cycle so that the results of other operations do not overwrite it.

Parameters
resultReadCyclecycle when the result is read
resultReadyCyclecycle when the result becomes available
poProgramOperation where the result move belongs
nodethe result read node being scheduled
resultPortthe port which is being read by the result
triggerTrigger of the program operation
triggercyclecycle of the trigger of the PO

Definition at line 2048 of file ExecutionPipelineResource.cc.

2051 {
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}
int nextResultCycle(const TTAMachine::Port &port, int cycle, const MoveNode &node, const MoveNode *trigger=NULL, int triggerCycle=INT_MAX) const

References SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), nextResultCycle(), resultPort(), and resultReadyCycle().

Referenced by canAssignSource(), ExecutionPipelineBroker::earliestFromSource(), and testTriggerResult().

Here is the call graph for this function:

◆ resultPort()

const TTAMachine::Port & ExecutionPipelineResource::resultPort ( const MoveNode mn) const
private

◆ resultReadyCycle()

int ExecutionPipelineResource::resultReadyCycle ( const ProgramOperation po,
const TTAMachine::Port resultPort 
) const
private

Returns cycle when result of some PO is ready.

Parameters
poprogramoperation int resultReadCycle cycle when the result is read

@TODO: multiple out values still not supported correctly.

Definition at line 1677 of file ExecutionPipelineResource.cc.

1678 {
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}
virtual int numberOfOutputs() const
Definition Operation.cc:202

References MoveNode::cycle(), fu_, MoveNode::isPlaced(), TTAMachine::HWOperation::latency(), Operation::name(), Operation::numberOfInputs(), Operation::numberOfOutputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::HWOperation::port(), resultPort(), ProgramOperation::toString(), and ProgramOperation::triggeringMove().

Referenced by resultAllowedAtCycle(), and resultNotOverWritten().

Here is the call graph for this function:

◆ setDDG()

void ExecutionPipelineResource::setDDG ( const DataDependenceGraph ddg)

Definition at line 1776 of file ExecutionPipelineResource.cc.

1776 {
1777 ddg_ = ddg;
1778}

References ddg_.

◆ setMaxCycle()

virtual void ExecutionPipelineResource::setMaxCycle ( unsigned int  maxCycle)
inlineoverridevirtual

Reimplemented from SchedulingResource.

Definition at line 116 of file ExecutionPipelineResource.hh.

116{ maxCycle_ = maxCycle; }

References maxCycle_.

◆ setOperandsUsed()

void ExecutionPipelineResource::setOperandsUsed ( const ProgramOperation po,
unsigned int  triggerCycle 
)
private

Definition at line 283 of file ExecutionPipelineResource.cc.

284 {
285
286 const Operation& op = po.operation();
288
289 // Loops over all output values produced by this
290 for (int i = 0; i < op.numberOfInputs(); i++) {
291 const TTAMachine::Port& port = *hwop.port(i+1);
292 int operandUseCycle = triggerCycle + hwop.slack(i+1);
293
294 setOperandUsed(port, operandUseCycle, po);
295 }
296}
void setOperandUsed(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)

References fu_, Operation::name(), Operation::numberOfInputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::HWOperation::port(), setOperandUsed(), and TTAMachine::HWOperation::slack().

Referenced by assignDestination().

Here is the call graph for this function:

◆ setOperandUsed()

void ExecutionPipelineResource::setOperandUsed ( const TTAMachine::Port port,
unsigned int  realCycle,
const ProgramOperation po 
)
private

Definition at line 241 of file ExecutionPipelineResource.cc.

243 {
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}
std::pair< OperandUseHelper, OperandUseHelper > OperandUsePair

References assert, SchedulingResource::instructionIndex(), and operandsUsed_.

Referenced by setOperandsUsed().

Here is the call graph for this function:

◆ setResultWriten() [1/2]

void ExecutionPipelineResource::setResultWriten ( const ProgramOperation po,
unsigned int  triggerCycle 
)
private

Definition at line 266 of file ExecutionPipelineResource.cc.

267 {
268
269 const Operation& op = po.operation();
271
272 // Loops over all output values produced by this
273 for (int i = 0; i < op.numberOfOutputs(); i++) {
274 int outIndex = op.numberOfInputs() + 1 + i;
275 const TTAMachine::Port& port = *hwop.port(outIndex);
276 int resultCycle = triggerCycle + hwop.latency(outIndex);
277
278 setResultWriten(port, resultCycle, po);
279 }
280}

References fu_, TTAMachine::HWOperation::latency(), Operation::name(), Operation::numberOfInputs(), Operation::numberOfOutputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::HWOperation::port(), and setResultWriten().

Here is the call graph for this function:

◆ setResultWriten() [2/2]

void ExecutionPipelineResource::setResultWriten ( const TTAMachine::Port port,
unsigned int  realCycle,
const ProgramOperation po 
)
private

Definition at line 211 of file ExecutionPipelineResource.cc.

213 {
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}

References SchedulingResource::instructionIndex(), and resultWriten_.

Referenced by assignDestination(), assignSource(), and setResultWriten().

Here is the call graph for this function:

◆ size()

unsigned int ExecutionPipelineResource::size ( ) const
protected

Return number of cycles current execution pipeline for FU contains. Effectively, highest cycle in which any of the resources of an FU is occupied plus 1.

Returns
Number of cycles in pipeline.

Definition at line 1417 of file ExecutionPipelineResource.cc.

1417 {
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}

References assignedDestinationNodes_, assignedSourceNodes_, cachedSize_, fuExecutionPipeline_, ExecutionPipelineResourceTable::numberOfResources(), resources, and SparseVector< ValueType >::size().

Referenced by assignDestination(), highestKnownCycle(), isInUse(), resourcesAllowTrigger(), and unassignDestination().

Here is the call graph for this function:

◆ testTriggerResult()

bool ExecutionPipelineResource::testTriggerResult ( const MoveNode trigger,
int  cycle 
) const
private

Tests the conflicts caused by results if a trigger is scheduled to given cycle.

Definition at line 1785 of file ExecutionPipelineResource.cc.

1786 {
1787 ProgramOperation& po = trigger.destinationOperation();
1788 const Operation& op = po.operation();
1790
1791 // Loops over all output values produced by this
1792 for (int i = 0; i < op.numberOfOutputs(); i++) {
1793 int outIndex = op.numberOfInputs() + 1 + i;
1794 const TTAMachine::Port& port = *hwop.port(outIndex);
1795 int resultCycle = cycle + hwop.latency(outIndex);
1796
1798 resultCycle, po, port, trigger, cycle)) {
1799 return false;
1800 }
1801
1802 if (initiationInterval_ != 0 &&
1803 hwop.latency(outIndex) > (int)initiationInterval_) {
1804 return false;
1805 }
1806 }
1807
1808 // If we have alreayd scheduled some result, we have to make sure
1809 // nobody overwrites it.
1810 for (int i = 0; i < po.outputMoveCount(); i++) {
1811 MoveNode& mn = po.outputMove(i);
1812 if (mn.isPlaced()) {
1813 int outIndex = -1;
1814 if (mn.isSourceOperation() && &mn.sourceOperation() == &po) {
1815 assert(mn.move().source().isFUPort());
1816 outIndex = mn.move().source().operationIndex();
1817 } else {
1818 assert (mn.isGuardOperation() && &mn.guardOperation() == &po);
1819 outIndex = po.outputIndexFromGuardOfMove(mn);
1820 }
1821 const TTAMachine::Port& port = *hwop.port(outIndex);
1822 int resultCycle = cycle + hwop.latency(outIndex);
1823 // WAW conflict of result on same op on different iteration?
1824 if (initiationInterval_ != 0 && isLoopBypass(mn) && mn.cycle() >= resultCycle) {
1825#ifdef DEBUG_RM
1826 std::cerr << "\t\t\t\tresult move: " << mn.toString()
1827 << " schedule too late: " << resultCycle << std::endl;
1828#endif
1829 return false;
1830 }
1832 mn.cycle(), resultCycle, mn, port, &trigger, cycle)) {
1833 return false;
1834 }
1835 }
1836 }
1837 return true;
1838
1839}

References assert, MoveNode::cycle(), MoveNode::destinationOperation(), fu_, MoveNode::guardOperation(), SchedulingResource::initiationInterval_, TTAProgram::Terminal::isFUPort(), MoveNode::isGuardOperation(), isLoopBypass(), MoveNode::isPlaced(), MoveNode::isSourceOperation(), TTAMachine::HWOperation::latency(), MoveNode::move(), Operation::name(), Operation::numberOfInputs(), Operation::numberOfOutputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), ProgramOperation::outputIndexFromGuardOfMove(), ProgramOperation::outputMove(), ProgramOperation::outputMoveCount(), TTAMachine::HWOperation::port(), resultAllowedAtCycle(), resultNotOverWritten(), TTAProgram::Move::source(), MoveNode::sourceOperation(), and MoveNode::toString().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ triggerAllowedAtCycle()

bool ExecutionPipelineResource::triggerAllowedAtCycle ( int  inputCount,
const TTAMachine::HWOperation hwop,
const MoveNode node,
int  cycle 
) const
private

Definition at line 2369 of file ExecutionPipelineResource.cc.

2373 {
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}

References operandAllowedAtCycle(), and TTAMachine::HWOperation::port().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ triggerTooEarly()

bool ExecutionPipelineResource::triggerTooEarly ( const MoveNode trigger,
int  cycle 
) const
private

Checks that trigger is not scheduled too early(before operand-slack)

Definition at line 2327 of file ExecutionPipelineResource.cc.

2327 {
2328 ProgramOperation& po = trigger.destinationOperation(0);
2329 const Operation& op = po.operation();
2331#ifdef DEBUG_RM
2332 std::cerr << "\t\t\t\tTesting if trigger too early for: " << trigger.toString() << " PO: " << po.toString() << std::endl;
2333#endif
2334 for (int i = 0; i < po.inputMoveCount(); i++) {
2335 MoveNode& mn = po.inputMove(i);
2336#ifdef DEBUG_RM
2337 std::cerr << "\t\t\t\tTesting operand: " << mn.toString() << std::endl;
2338#endif
2339 if (mn.isPlaced()) {
2340#ifdef DEBUG_RM
2341 std::cerr << "\t\t\t\tCycle: " << mn.cycle() << ", ";
2342#endif
2343 int slack = hwop.slack(mn.move().destination().operationIndex());
2344 const TTAMachine::Port& port = mn.move().destination().port();
2345 const TTAMachine::FUPort& fuPort =
2346 dynamic_cast<const TTAMachine::FUPort&>(port);
2347
2348#ifdef DEBUG_RM
2349 std::cerr << "slack(" << mn.move().destination().operationIndex()
2350 << ")=" << slack << ", noReg=" << fuPort.noRegister()
2351 << std::endl;
2352#endif
2353
2354 if (fuPort.noRegister()) {
2355 if (cycle != mn.cycle() - slack) {
2356 return true;
2357 }
2358 } else {
2359 if (cycle < mn.cycle() - slack) {
2360 return true;
2361 }
2362 }
2363 }
2364 }
2365 return false;
2366}

References MoveNode::cycle(), TTAProgram::Move::destination(), MoveNode::destinationOperation(), fu_, ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), MoveNode::isPlaced(), MoveNode::move(), Operation::name(), TTAMachine::FUPort::noRegister(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAProgram::Terminal::operationIndex(), TTAProgram::Terminal::port(), TTAMachine::HWOperation::slack(), MoveNode::toString(), and ProgramOperation::toString().

Referenced by canAssignDestination().

Here is the call graph for this function:

◆ unassign()

void ExecutionPipelineResource::unassign ( const int  cycle,
MoveNode node 
)
overridevirtual

Implements SchedulingResource.

Definition at line 582 of file ExecutionPipelineResource.cc.

582 {
583 abortWithError("Execution Pipeline Resource needs 3 arguments unassign");
584}

References abortWithError.

◆ unassignDestination()

void ExecutionPipelineResource::unassignDestination ( const int  cycle,
MoveNode node 
)
virtual

Unassign resource from given node for given cycle.

Parameters
cycleCycle to remove assignment from
nodeMoveNode to remove assignment from in case move is bypassed
Exceptions
Incase there was no previous assignment or wrong operation is unassigned

Now unassing destination part of move

Definition at line 676 of file ExecutionPipelineResource.cc.

678 {
679
680#ifdef DEBUG_RM
681 std::cerr << "\tUnassigning destination: " << node.toString() << std::endl;
682#endif
683
684 if (!node.isDestinationOperation()) {
685#ifdef DEBUG_RM
686 std::cerr << "\t\tNot dest operatioN!" << std::endl;
687#endif
688 return;
689 }
690
691 int modCycle = instructionIndex(cycle);
692 unsigned int ii = initiationInterval_;
693 if (ii < 1) {
694 ii = INT_MAX;
695 }
696
698#ifdef DEBUG_RM
699 std::cerr << "\t\t assigned destinations not contain!" << std::endl;
700#endif
701 return;
702 }
703 /// Now unassing destination part of move
705
706 const TTAMachine::Port& opPort = operandPort(node);
707 MoveNodePtrPair& mnpp = operandsWriten_[&opPort][modCycle];
708 assert (mnpp.first != NULL);
709 if (mnpp.second == &node) {
710 mnpp.second = NULL;
711 } else {
712 assert(mnpp.first == &node);
713 mnpp.first = mnpp.second;
714 mnpp.second = NULL;
715 }
716
717 // if not trigger, we are done
718 // TODO: correct trigger or UM trigger?
719 if (!node.move().destination().isTriggering()) {
720#ifdef DEBUG_RM
721 std::cerr << "\t\t not trigger!" << std::endl;
722#endif
723
724 if (node.destinationOperationCount() > 1) {
726 }
727 return;
728 }
729
731
734
735 std::string opName = "";
736 if (node.move().destination().isOpcodeSetting()) {
737 opName = node.move().destination().operation().name();
738 } else {
739 opName = node.move().destination().hintOperation().name();
740 }
741 if (!resources->hasOperation(opName)) {
742 std::string msg = "Trying to unassign operation \'";
743 msg += opName ;
744 msg += "\' not supported on FU!";
745 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
746 }
747
748 // Cannot trust size() since that one ignores empty pipeline
749 // and here we need to go up to the maximalLatency.
750 size_t fuEpSize = fuExecutionPipeline_.size();
751 if ((size_t)instructionIndex(cycle + resources->maximalLatency() - 1)
752 >= fuEpSize) {
753 std::string msg = "Unassigning operation longer then scope!";
754 msg += " - cycle:";
755 msg += Conversion::toString(cycle);
756 msg += " - scope:";
757 msg += Conversion::toString(fuEpSize);
758 msg += " - ii:";
760 throw ModuleRunTimeError(__FILE__, __LINE__, __func__, msg);
761 }
762 for (unsigned int i = 0; i < resources->maximalLatency(); i++) {
763 int modic = instructionIndex(cycle+i);
764 for (unsigned int j = 0 ; j < resources->numberOfResources(); j++) {
765 assert(
766 fuExecutionPipeline_[modic].size() != 0);
768 fuExecutionPipeline_[modic][j];
769 if (rr.first == &node) {
771 resources->operationIndex(opName),i,j) &&
772 "unassigning pipeline res not used by this op");
773
774 rr.first = rr.second;
775 rr.second = NULL;
776 } else {
777 if (rr.second == &node) {
779 resources->operationIndex(opName),i,j) &&
780 "unassigning pipeline res not used by this op");
781
782 rr.second = NULL;
783 }
784 }
785 }
786 }
787}
void unsetOperandsUsed(const ProgramOperation &po, unsigned int triggerCycle)
void unsetResultWriten(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)
static bool removeItemsByValue(MapType &aMap, const ValueType &aValue)
static bool containsValue(const MapType &aMap, const ValueType &aValue)
virtual Operation & hintOperation() const
Definition Terminal.cc:341

References __func__, assert, assignedDestinationNodes_, MapTools::containsValue(), TTAProgram::Move::destination(), MoveNode::destinationOperation(), MoveNode::destinationOperationCount(), fuExecutionPipeline_, ExecutionPipelineResourceTable::hasOperation(), TTAProgram::Terminal::hintOperation(), SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), MoveNode::isDestinationOperation(), TTAProgram::Terminal::isOpcodeSetting(), TTAProgram::Terminal::isTriggering(), ExecutionPipelineResourceTable::maximalLatency(), MoveNode::move(), Operation::name(), ExecutionPipelineResourceTable::numberOfResources(), operandPort(), operandShareCount_, operandsWriten_, TTAProgram::Terminal::operation(), ExecutionPipelineResourceTable::operationIndex(), ExecutionPipelineResourceTable::operationPipeline(), MapTools::removeItemsByValue(), resources, size(), SparseVector< ValueType >::size(), MoveNode::toString(), Conversion::toString(), unsetOperandsUsed(), and unsetResultWriten().

Referenced by InputFUResource::unassign().

Here is the call graph for this function:

◆ unassignSource()

void ExecutionPipelineResource::unassignSource ( const int  cycle,
MoveNode node 
)
virtual

Unassign resource from given node for given cycle.

Parameters
cycleCycle to remove assignment from
nodeMoveNode to remove assignment from
sourceIndicates if we want to unassign source part of move in case move is bypassed
Exceptions
Incase there was no previous assignment or wrong operation is unassigned

Unscheduling result read

Remove record of result beeing written to result register or decrease count in case there are more results

Remove record or decrease count of result read moves

Remove record or decrease count of result read moves

Definition at line 597 of file ExecutionPipelineResource.cc.

599 {
600 cachedSize_ = INT_MIN;
601
602 int modCycle = instructionIndex(cycle);
603 unsigned int ii = initiationInterval_;
604 if (ii < 1) {
605 ii = INT_MAX;
606 }
607
608 if (node.cycle() != cycle) {
609 throw InvalidData(__FILE__, __LINE__, __func__,
610 "Trying to unassign node from different cycle "
611 "then it was assigned to!");
612 }
613
614 const TTAMachine::Port& port = resultPort(node);
615 ResultVector& resultRead = resultRead_[&port];
617 node.sourceOperation() :
618 node.guardOperation();
619
620 /// Unscheduling result read
623
625 /// Remove record of result beeing written to result register
626 /// or decrease count in case there are more results
627 unsigned int resultReady =
629
630 unsetResultWriten(port, resultReady, po);
631 storedResultCycles_.erase(&node);
632
633 // assert fail is much nicer than unknown exception.
634 assert(modCycle < (int)resultRead.size());
635 ResultHelperPair& resultReadPair = resultRead[modCycle];
636
637 if (resultReadPair.first.po == &po) {
638 /// Remove record or decrease count of result read moves
639 resultReadPair.first.count--;
640 if (resultReadPair.first.count == 0) {
641 if (resultReadPair.second.count == 0) {
642 // erase from the bookkeeping, this is empty.
643 resultRead.erase(modCycle);
644 } else {
645 resultReadPair.first = resultReadPair.second;
646 resultReadPair.second.count = 0;
647 resultReadPair.second.realCycle = modCycle;
648 resultReadPair.second.po = NULL;
649 }
650 }
651 } else {
652 if (resultReadPair.second.po == &po) {
653 ///Remove record or decrease count of result read moves
654 resultReadPair.second.count--;
655 if (resultReadPair.second.count == 0) {
656 resultReadPair.second.realCycle = modCycle;
657 resultReadPair.second.po = NULL;
658 }
659 }
660 }
661 }
662 }
663}
static bool containsKey(const MapType &aMap, const KeyType &aKey)

References __func__, assert, assignedSourceNodes_, cachedSize_, MapTools::containsKey(), MapTools::containsValue(), MoveNode::cycle(), MoveNode::guardOperation(), SchedulingResource::initiationInterval_, SchedulingResource::instructionIndex(), MoveNode::isSourceOperation(), MapTools::keyForValue(), MapTools::removeItemsByValue(), resultPort(), resultRead_, SparseVector< ValueType >::size(), MoveNode::sourceOperation(), storedResultCycles_, and unsetResultWriten().

Referenced by OutputFUResource::unassign().

Here is the call graph for this function:

◆ unsetOperandsUsed()

void ExecutionPipelineResource::unsetOperandsUsed ( const ProgramOperation po,
unsigned int  triggerCycle 
)
private

Definition at line 377 of file ExecutionPipelineResource.cc.

378 {
379
380 const Operation& op = po.operation();
382
383 // Loops over all output values produced by this
384 for (int i = 0; i < op.numberOfInputs(); i++) {
385 const TTAMachine::Port& port = *hwop.port(i+1);
386 int resultCycle = triggerCycle + hwop.slack(i+1);
387 unsetOperandUsed(port, resultCycle, po);
388 }
389}
void unsetOperandUsed(const TTAMachine::Port &port, unsigned int realCycle, const ProgramOperation &po)

References fu_, Operation::name(), Operation::numberOfInputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::HWOperation::port(), TTAMachine::HWOperation::slack(), and unsetOperandUsed().

Referenced by unassignDestination().

Here is the call graph for this function:

◆ unsetOperandUsed()

void ExecutionPipelineResource::unsetOperandUsed ( const TTAMachine::Port port,
unsigned int  realCycle,
const ProgramOperation po 
)
private

Definition at line 336 of file ExecutionPipelineResource.cc.

338 {
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}

References assert, SchedulingResource::instructionIndex(), and operandsUsed_.

Referenced by unsetOperandsUsed().

Here is the call graph for this function:

◆ unsetResultWriten() [1/2]

void ExecutionPipelineResource::unsetResultWriten ( const ProgramOperation po,
unsigned int  triggerCycle 
)
private

Definition at line 360 of file ExecutionPipelineResource.cc.

361 {
362
363 const Operation& op = po.operation();
365
366 // Loops over all output values produced by this
367 for (int i = 0; i < op.numberOfOutputs(); i++) {
368 int outIndex = op.numberOfInputs() + 1 + i;
369 const TTAMachine::Port& port = *hwop.port(outIndex);
370 int resultCycle = triggerCycle + hwop.latency(outIndex);
371
372 unsetResultWriten(port, resultCycle, po);
373 }
374}

References fu_, TTAMachine::HWOperation::latency(), Operation::name(), Operation::numberOfInputs(), Operation::numberOfOutputs(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::HWOperation::port(), and unsetResultWriten().

Here is the call graph for this function:

◆ unsetResultWriten() [2/2]

void ExecutionPipelineResource::unsetResultWriten ( const TTAMachine::Port port,
unsigned int  realCycle,
const ProgramOperation po 
)
private

Definition at line 305 of file ExecutionPipelineResource.cc.

307 {
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}

References assert, SchedulingResource::instructionIndex(), and resultWriten_.

Referenced by unassignDestination(), unassignSource(), and unsetResultWriten().

Here is the call graph for this function:

◆ validateDependentGroups()

bool ExecutionPipelineResource::validateDependentGroups ( )
overrideprotectedvirtual

Tests if all referred resources in dependent groups are of proper types.

Returns
true Allways true, pipelines are internal to object.

Reimplemented from SchedulingResource.

Definition at line 1388 of file ExecutionPipelineResource.cc.

1388 {
1389 return true;
1390}

◆ validateRelatedGroups()

bool ExecutionPipelineResource::validateRelatedGroups ( )
overrideprotectedvirtual

Tests if all resources in related resource groups are of proper types.

Returns
true If all resources in related resource groups are Triggering PSockets - for now InputPSockets

Reimplemented from SchedulingResource.

Definition at line 1399 of file ExecutionPipelineResource.cc.

1399 {
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}
virtual SchedulingResource & relatedResource(const int group, const int index) const
int relatedResourceCount(const int group) const
virtual bool isInputPSocketResource() const
virtual int relatedResourceGroupCount() const

References SchedulingResource::isInputPSocketResource(), SchedulingResource::relatedResource(), SchedulingResource::relatedResourceCount(), and SchedulingResource::relatedResourceGroupCount().

Here is the call graph for this function:

Member Data Documentation

◆ assignedDestinationNodes_

std::multimap<int, MoveNode*> ExecutionPipelineResource::assignedDestinationNodes_
private

◆ assignedSourceNodes_

std::multimap<int, MoveNode*> ExecutionPipelineResource::assignedSourceNodes_
private

◆ cachedSize_

int ExecutionPipelineResource::cachedSize_
mutableprivate

◆ ddg_

const DataDependenceGraph* ExecutionPipelineResource::ddg_
private

Definition at line 330 of file ExecutionPipelineResource.hh.

Referenced by clear(), exclusiveMoves(), isLoopBypass(), and setDDG().

◆ fu_

const TTAMachine::FunctionUnit& ExecutionPipelineResource::fu_
private

◆ fuExecutionPipeline_

ResourceReservationTable ExecutionPipelineResource::fuExecutionPipeline_
mutableprivate

Stores one resource vector per cycle of scope for whole FU.

Definition at line 298 of file ExecutionPipelineResource.hh.

Referenced by assignDestination(), clear(), isInUse(), resourcesAllowTrigger(), size(), and unassignDestination().

◆ maxCycle_

int ExecutionPipelineResource::maxCycle_
private

Definition at line 328 of file ExecutionPipelineResource.hh.

Referenced by resourcesAllowTrigger(), and setMaxCycle().

◆ operandShareCount_

int ExecutionPipelineResource::operandShareCount_
private

◆ operandsUsed_

OperandUseMap ExecutionPipelineResource::operandsUsed_
private

◆ operandsWriten_

OperandWriteMap ExecutionPipelineResource::operandsWriten_
private

◆ resources

const ExecutionPipelineResourceTable* ExecutionPipelineResource::resources
private

◆ resultRead_

ResultMap ExecutionPipelineResource::resultRead_
private

◆ resultWriten_

ResultMap ExecutionPipelineResource::resultWriten_
private

◆ storedResultCycles_

std::map<MoveNode*, int, MoveNode::Comparator> ExecutionPipelineResource::storedResultCycles_
private

Definition at line 321 of file ExecutionPipelineResource.hh.

Referenced by assignSource(), clear(), and unassignSource().

◆ triggerPort_

const TTAMachine::Port* ExecutionPipelineResource::triggerPort_
private

Definition at line 334 of file ExecutionPipelineResource.hh.


The documentation for this class was generated from the following files: