OpenASIP 2.2
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
BasicBlockScheduler Class Reference

#include <BasicBlockScheduler.hh>

Inheritance diagram for BasicBlockScheduler:
Inheritance graph
Collaboration diagram for BasicBlockScheduler:
Collaboration graph

Public Member Functions

 BasicBlockScheduler (InterPassData &data, SoftwareBypasser *bypasser=NULL, RegisterRenamer *renamer=NULL)
 
virtual ~BasicBlockScheduler ()
 
virtual int handleDDG (DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine, int minCycle=0, bool testOnly=false) override
 
virtual int handleLoopDDG (DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine, int tripCount, SimpleResourceManager *prologRM, bool testOnly=false) override
 
virtual std::string shortDescription () const
 
virtual std::string longDescription () const
 
virtual void printStats () const
 
virtual DataDependenceGraphBuilderddgBuilder ()
 
- Public Member Functions inherited from DDGPass
 DDGPass (InterPassData &data)
 
virtual ~DDGPass ()
 
- Public Member Functions inherited from SchedulerPass
 SchedulerPass (InterPassData &data)
 
virtual ~SchedulerPass ()
 
InterPassDatainterPassData ()
 
- Public Member Functions inherited from BasicBlockPass
 BasicBlockPass (InterPassData &data)
 
virtual ~BasicBlockPass ()
 
virtual void handleBasicBlock (TTAProgram::BasicBlock &basicBlock, const TTAMachine::Machine &targetMachine, TTAProgram::InstructionReferenceManager &irm, BasicBlockNode *bbn=NULL)
 
virtual void executeDDGPass (TTAProgram::BasicBlock &bb, const TTAMachine::Machine &targetMachine, TTAProgram::InstructionReferenceManager &irm, std::vector< DDGPass * > ddgPasses, BasicBlockNode *bbn=NULL)
 
virtual bool executeLoopPass (TTAProgram::BasicBlock &bb, const TTAMachine::Machine &targetMachine, TTAProgram::InstructionReferenceManager &irm, std::vector< DDGPass * > ddgPasses, BasicBlockNode *bbn=NULL)
 

Static Public Member Functions

static MoveNodefindTrigger (const ProgramOperation &po, const TTAMachine::Machine &mach)
 
- Static Public Member Functions inherited from BasicBlockPass
static void copyRMToBB (SimpleResourceManager &rm, TTAProgram::BasicBlock &bb, const TTAMachine::Machine &targetMachine, TTAProgram::InstructionReferenceManager &irm, int lastCycle=-1)
 

Protected Member Functions

void scheduleRRMove (MoveNode &moveNode)
 
void scheduleOperation (MoveNodeGroup &moves)
 
int scheduleOperandWrites (int &cycle, MoveNodeGroup &moves)
 
bool scheduleResultReads (MoveNodeGroup &moves)
 
void scheduleMove (MoveNode &move, int earliestCycle, bool allowPredicationAndRenaming)
 
void scheduleRRTempMoves (MoveNode &regToRegMove, MoveNode &firstMove, int lastUse)
 
void scheduleInputOperandTempMoves (MoveNode &operandMove, MoveNode &operandWrite)
 
void unschedule (MoveNode &moveNode)
 
void unscheduleAllNodes ()
 
void unscheduleInputOperandTempMoves (MoveNode &operandMove)
 
void scheduleResultReadTempMoves (MoveNode &resultMove, MoveNode &resultRead, int lastUse)
 
void unscheduleResultReadTempMoves (MoveNode &resultMove)
 
void notifyScheduled (MoveNodeGroup &moves, MoveNodeSelector &selector)
 
void ddgSnapshot (DataDependenceGraph &ddg, const std::string &name, DataDependenceGraph::DumpFileFormat format, bool final, bool resetCounter=false) const
 
MoveNodesucceedingTempMove (MoveNode &current)
 
int getTriggerOperand (const Operation &operation, const TTAMachine::Machine &machine)
 
bool tryToSwitchInputs (ProgramOperation &op)
 
void handleRemovedResultMoves (std::set< std::pair< TTAProgram::Move *, int > > removedMoves)
 
bool tryToOptimizeWaw (const MoveNode &moveNode)
 
void tryToDelayOperands (MoveNodeGroup &moves)
 
- Protected Member Functions inherited from BasicBlockPass
void ddgSnapshot (DataDependenceGraph *ddg, std::string &name, DataDependenceGraph::DumpFileFormat format, bool final)
 
virtual DataDependenceGraphcreateDDGFromBB (TTAProgram::BasicBlock &bb, const TTAMachine::Machine &mach)
 

Static Protected Member Functions

static MoveNodefindTriggerFromUnit (const ProgramOperation &po, const TTAMachine::Unit &unit)
 

Protected Attributes

const TTAMachine::MachinetargetMachine_
 The target machine we are scheduling the program against.
 
DataDependenceGraphddg_
 DDG of the currently scheduled BB.
 
SimpleResourceManagerrm_
 Resource Manager of the currently scheduled BB.
 
std::map< const MoveNode *, DataDependenceGraph::NodeSetscheduledTempMoves_
 Stores the MoveNodes that were scheduled as temp moves during scheduling of the operand move.
 
SoftwareBypassersoftwareBypasser_
 The software bypasser to use to bypass registers when possible.
 
RegisterRenamerrenamer_
 
int minCycle_
 The earliest cycle to schedule moves in. Used to leave room for sched_yield() by the sched_yield() emitter.
 
MoveNodeSelectorselector_
 
int bypassedCount_
 
int deadResults_
 
LLVMTCECmdLineOptionsoptions_
 
MoveNodejumpNode_
 
int tripCount_
 

Detailed Description

A class that implements the functionality of a basic block scheduler.

Schedules the program one basic block at a time. Does not fill delay slots if they couldn't be filled with the basic block's contents itself (no instruction importing).

Definition at line 63 of file BasicBlockScheduler.hh.

Constructor & Destructor Documentation

◆ BasicBlockScheduler()

BasicBlockScheduler::BasicBlockScheduler ( InterPassData data,
SoftwareBypasser bypasser = NULL,
RegisterRenamer renamer = NULL 
)

Constructs the basic block scheduler.

Parameters
dataInterpass data
bypasserHelper module implementing software bypassing
delaySlotFillerHelper module implementing jump delay slot filling

Definition at line 83 of file BasicBlockScheduler.cc.

85 :
86 DDGPass(data), BasicBlockPass(data), ddg_(NULL), rm_(NULL),
87 softwareBypasser_(bypasser), renamer_(renamer), minCycle_(0),
88 jumpNode_(NULL) {
90 options_ = dynamic_cast<LLVMTCECmdLineOptions*>(cmdLineOptions);
91}
static CmdLineOptions * cmdLineOptions()
SimpleResourceManager * rm_
Resource Manager of the currently scheduled BB.
SoftwareBypasser * softwareBypasser_
The software bypasser to use to bypass registers when possible.
DataDependenceGraph * ddg_
DDG of the currently scheduled BB.
LLVMTCECmdLineOptions * options_
int minCycle_
The earliest cycle to schedule moves in. Used to leave room for sched_yield() by the sched_yield() em...
RegisterRenamer * renamer_

References Application::cmdLineOptions(), and options_.

Here is the call graph for this function:

◆ ~BasicBlockScheduler()

BasicBlockScheduler::~BasicBlockScheduler ( )
virtual

Definition at line 93 of file BasicBlockScheduler.cc.

93 {
94}

Member Function Documentation

◆ ddgBuilder()

virtual DataDependenceGraphBuilder & BasicBlockPass::ddgBuilder ( )
inlinevirtual

Reimplemented from BasicBlockPass.

Reimplemented in BUBasicBlockScheduler.

Definition at line 86 of file BasicBlockPass.hh.

86{ return ddgBuilder_; }
DataDependenceGraphBuilder ddgBuilder_

◆ ddgSnapshot()

void BasicBlockScheduler::ddgSnapshot ( DataDependenceGraph ddg,
const std::string &  name,
DataDependenceGraph::DumpFileFormat  format,
bool  final,
bool  resetCounter = false 
) const
protected

Prints DDG to a dot file before and after scheudling

Parameters
ddgto print
nameoperation name for ddg
finalspecify if ddg is after scheduling
resetCounter
formatformat of the file
Returns
number of cycles/instructions copied.

Definition at line 1629 of file BasicBlockScheduler.cc.

1634 {
1635
1636 static int bbCounter = 0;
1637
1638 if (resetCounter) {
1639 bbCounter = 0;
1640 }
1641
1642 if (final) {
1643 if (format == DataDependenceGraph::DUMP_DOT) {
1644 ddg.writeToDotFile(
1645 (boost::format("bb_%s_%s_after_scheduling.dot") %
1646 ddg_->name() % name).str());
1647 } else {
1648 ddg.writeToXMLFile(
1649 (boost::format("bb_%s_%s_after_scheduling.xml") %
1650 ddg_->name() % name).str());
1651 }
1652
1653 } else {
1654 if (format == DataDependenceGraph::DUMP_DOT) {
1655 ddg.writeToDotFile(
1656 (boost::format("bb_%s_%d_%s_before_scheduling.dot")
1657 % ddg.name() % bbCounter % name).str());
1658 DataDependenceGraph* criticalPath = ddg.criticalPathGraph();
1659 criticalPath->writeToDotFile(
1660 (boost::format(
1661 "bb_%s_%d_%s_before_scheduling_critical_path.dot")
1662 % ddg.name() % bbCounter % name).str());
1663 delete criticalPath;
1664 } else {
1665 ddg.writeToXMLFile(
1666 (boost::format("bb_%s_%d_%s_before_scheduling.xml")
1667 % ddg.name() % bbCounter % name).str());
1668 }
1669 }
1670 ++bbCounter;
1671}
virtual const TCEString & name() const
DataDependenceGraph * criticalPathGraph()
void writeToXMLFile(std::string fileName) const
virtual void writeToDotFile(const TCEString &fileName) const

References DataDependenceGraph::criticalPathGraph(), ddg_, DataDependenceGraph::DUMP_DOT, BoostGraph< GraphNode, GraphEdge >::name(), GraphBase< GraphNode, GraphEdge >::writeToDotFile(), and DataDependenceGraph::writeToXMLFile().

Referenced by BUBasicBlockScheduler::handleDDG(), handleDDG(), handleLoopDDG(), BUBasicBlockScheduler::handleLoopDDG(), and scheduleOperation().

Here is the call graph for this function:

◆ findTrigger()

MoveNode * BasicBlockScheduler::findTrigger ( const ProgramOperation po,
const TTAMachine::Machine mach 
)
static

Definition at line 2090 of file BasicBlockScheduler.cc.

2091 {
2092
2093 MoveNode* triggerFromPO = po.triggeringMove();
2094 if (triggerFromPO) {
2095 return triggerFromPO;
2096 }
2097
2098 // no scheduled moves. getting harder.
2099
2101 mach.functionUnitNavigator();
2102 MoveNode* candidate = NULL;
2103 for (int i = 0; i < nav.count(); i++) {
2104 TTAMachine::FunctionUnit* fu = nav.item(i);
2105 if (fu->hasOperation(po.operation().name())) {
2106 if (candidate == NULL) {
2107 candidate = findTriggerFromUnit(po, *fu);
2108 } else {
2109 // make sure two different FU's don't have different
2110 // trigger ports.
2111 if (findTriggerFromUnit(po, *fu) != candidate) {
2112 return NULL;
2113 }
2114 }
2115 }
2116 }
2117
2118 if (mach.controlUnit()->hasOperation(po.operation().name())) {
2119 return findTriggerFromUnit(po, *mach.controlUnit());
2120 }
2121 return candidate;
2122
2123}
static MoveNode * findTriggerFromUnit(const ProgramOperation &po, const TTAMachine::Unit &unit)
virtual TCEString name() const
Definition Operation.cc:93
const Operation & operation() const
MoveNode * triggeringMove() const
virtual bool hasOperation(const std::string &name) const
ComponentType * item(int index) const
virtual FunctionUnitNavigator functionUnitNavigator() const
Definition Machine.cc:380
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345

References TTAMachine::Machine::controlUnit(), TTAMachine::Machine::Navigator< ComponentType >::count(), findTriggerFromUnit(), TTAMachine::Machine::functionUnitNavigator(), TTAMachine::FunctionUnit::hasOperation(), TTAMachine::Machine::Navigator< ComponentType >::item(), Operation::name(), ProgramOperation::operation(), and ProgramOperation::triggeringMove().

Referenced by BFOptimization::getSisterTrigger(), BF2Scheduler::mustBeTrigger(), and BUBasicBlockScheduler::scheduleOperandWrites().

Here is the call graph for this function:

◆ findTriggerFromUnit()

MoveNode * BasicBlockScheduler::findTriggerFromUnit ( const ProgramOperation po,
const TTAMachine::Unit unit 
)
staticprotected

Definition at line 2126 of file BasicBlockScheduler.cc.

2127 {
2128 const TTAMachine::FunctionUnit* fu =
2129 dynamic_cast<const TTAMachine::FunctionUnit*>(&unit);
2130 int ioIndex = -1;
2131
2132 int portC = fu->portCount();
2133 for (int i = 0; i < portC; i++) {
2134 auto p = fu->port(i);
2135 const TTAMachine::FUPort* port = dynamic_cast<const TTAMachine::FUPort*>(p);
2136 if (port != nullptr && port->isTriggering()) {
2137 const TTAMachine::HWOperation* hwop =
2138 fu->operation(po.operation().name());
2139 ioIndex = hwop->io(*port);
2140 return &po.inputNode(ioIndex).at(0);
2141 }
2142 }
2143 return NULL;
2144}
MoveNode & at(int index)
MoveNodeSet & inputNode(int in) const
virtual bool isTriggering() const
Definition FUPort.cc:182
virtual HWOperation * operation(const std::string &name) const
virtual BaseFUPort * port(const std::string &name) const
int io(const FUPort &port) const
virtual int portCount() const
Definition Unit.cc:135

References MoveNodeSet::at(), ProgramOperation::inputNode(), TTAMachine::HWOperation::io(), TTAMachine::FUPort::isTriggering(), Operation::name(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), TTAMachine::FunctionUnit::port(), and TTAMachine::Unit::portCount().

Referenced by findTrigger().

Here is the call graph for this function:

◆ getTriggerOperand()

int BasicBlockScheduler::getTriggerOperand ( const Operation operation,
const TTAMachine::Machine machine 
)
protected

Returns the operand which is triggering in all FU's which support the operation. If operation not found, is not gcu or multiple FU's have different triggers, returns 0

Definition at line 1680 of file BasicBlockScheduler.cc.

1682 {
1683
1684 const TCEString& opName = operation.name();
1687
1688 int trigger = 0;
1689 for (int i = 0; i < fuNav.count(); i++) {
1690 TTAMachine::FunctionUnit& fu = *fuNav.item(i);
1691 if (fu.hasOperation(opName)) {
1692 TTAMachine::HWOperation& hwop = *fu.operation(opName);
1693 for (int j = 1; j <= operation.numberOfInputs(); j++) {
1694 TTAMachine::FUPort& port = *hwop.port(j);
1695 if (port.isTriggering()) {
1696 if (trigger == 0) {
1697 trigger = j;
1698 } else {
1699 if (trigger != j) {
1700 return 0;
1701 }
1702 }
1703 }
1704 }
1705 }
1706 }
1707 return trigger;
1708}
TTAMachine::Machine * machine
the architecture definition of the estimated processor
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual FUPort * port(int operand) const

References TTAMachine::Machine::Navigator< ComponentType >::count(), TTAMachine::Machine::functionUnitNavigator(), TTAMachine::FunctionUnit::hasOperation(), TTAMachine::FUPort::isTriggering(), TTAMachine::Machine::Navigator< ComponentType >::item(), machine, Operation::name(), Operation::numberOfInputs(), TTAMachine::FunctionUnit::operation(), and TTAMachine::HWOperation::port().

Referenced by tryToSwitchInputs(), and BUBasicBlockScheduler::tryToSwitchInputs().

Here is the call graph for this function:

◆ handleDDG()

int BasicBlockScheduler::handleDDG ( DataDependenceGraph ddg,
SimpleResourceManager rm,
const TTAMachine::Machine targetMachine,
int  minCycle = 0,
bool  test = false 
)
overridevirtual

Schedules a piece of code in a DDG

Parameters
ddgThe ddg containing the code
rmResource manager that is to be used.
targetMachineThe target machine.
Returns
size of the produces schedule.
Exceptions
Exceptionseveral TCE exceptions can be thrown in case of a scheduling error.

Reimplemented from DDGPass.

Reimplemented in BUBasicBlockScheduler.

Definition at line 107 of file BasicBlockScheduler.cc.

109 {
110 tripCount_ = 0;
111 ddg_ = &ddg;
112 targetMachine_ = &targetMachine;
113 minCycle_ = minCycle;
114
115 if (renamer_ != NULL) {
116 renamer_->initialize(ddg);
117 }
118
119 if (options_ != NULL && options_->dumpDDGsDot()) {
121 ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false);
122 }
123
124 if (options_ != NULL && options_->dumpDDGsXML()) {
126 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false);
127 }
128
129 scheduledTempMoves_.clear();
130
131 // empty DDGs can be ignored
132 if (ddg.nodeCount() == 0 ||
133 (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
134 return 0;
135 }
136
137 CriticalPathBBMoveNodeSelector selector(ddg, targetMachine);
138 selector_ = &selector;
139
140 rm_ = &rm;
141
142
143 // register selector to bypasser for notfications.
144 if (softwareBypasser_ != NULL) {
145 softwareBypasser_->setSelector(&selector);
146 }
147
148 if (renamer_ != NULL) {
149 renamer_->setSelector(&selector);
150 }
151
152 MoveNodeGroup moves = selector.candidates();
153 while (moves.nodeCount() > 0) {
154 bool movesRemoved = false;
155 MoveNode& firstMove = moves.node(0);
156 if (firstMove.isOperationMove()) {
157 scheduleOperation(moves);
158 } else {
159 if (firstMove.move().destination().isRA()) {
160 scheduleMove(firstMove,0, true);
161 } else {
162 scheduleRRMove(firstMove);
163 int lastOperandFake = 0;
164 if (softwareBypasser_ != NULL) {
165 int rv =
167 firstMove, lastOperandFake, ddg, rm);
168 if (rv < 0) {
170 firstMove, ddg, rm, true);
171 scheduleRRMove(firstMove);
172 }
173
174 // did the bypass cause a reg-to-itself copy?
175 // if it did, let's kill it.
176 if (firstMove.move().source().equals(
177 firstMove.move().destination())) {
178 movesRemoved = true;
179 }
180
181 if (rv > 0) {
182 std::set<std::pair<TTAProgram::Move*, int> >
183 removedMoves;
185 moves, ddg, rm, removedMoves);
186 // TODO: disabled becaused may be problematic
187 // when rescheduled to different buses
188// handleRemovedResultMoves(removedMoves);
189 }
190 }
191 }
192 }
193
194 if (!movesRemoved) {
195 if (!moves.isScheduled()) {
196 std::string message = " Move(s) did not get scheduled: ";
197 for (int i = 0; i < moves.nodeCount(); i++) {
198 message += moves.node(i).toString() + " ";
199 }
200
202
203 throw ModuleRunTimeError(__FILE__,__LINE__,__func__,message);
204 }
205
206 // notifies successors of the scheduled moves.
207 notifyScheduled(moves, selector);
208 }
209
210 moves = selector.candidates();
211 }
212 int size = rm.largestCycle();
213 if (test) {
215 return size;
216 }
217 if (softwareBypasser_ != NULL) {
218 softwareBypasser_->clearCaches(ddg, true);
219 }
220
221 if (ddg.nodeCount() !=
222 ddg.scheduledNodeCount()) {
223 ddg.writeToDotFile("failed_bb.dot");
224 std::cerr << ddg.nodeCount() << ", " << ddg.scheduledNodeCount()
225 << std::endl;
226 throw ModuleRunTimeError(__FILE__, __LINE__, __func__,
227 "All moves in the DDG didn't get scheduled.");
228 }
229
230 if (options_ != NULL && options_->dumpDDGsDot()) {
231 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, true);
232 }
233
234 if (options_ != NULL && options_->dumpDDGsXML()) {
235 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
236 }
237 return size;
238}
#define __func__
void scheduleMove(MoveNode &move, int earliestCycle, bool allowPredicationAndRenaming)
MoveNodeSelector * selector_
void scheduleRRMove(MoveNode &moveNode)
const TTAMachine::Machine * targetMachine_
The target machine we are scheduling the program against.
std::map< const MoveNode *, DataDependenceGraph::NodeSet > scheduledTempMoves_
Stores the MoveNodes that were scheduled as temp moves during scheduling of the operand move.
void scheduleOperation(MoveNodeGroup &moves)
void notifyScheduled(MoveNodeGroup &moves, MoveNodeSelector &selector)
void ddgSnapshot(DataDependenceGraph &ddg, const std::string &name, DataDependenceGraph::DumpFileFormat format, bool final, bool resetCounter=false) const
int nodeCount() const
Node & node(const int index) const
virtual bool dumpDDGsDot() const
virtual bool dumpDDGsXML() const
int nodeCount() const
MoveNode & node(int index) const
bool isScheduled() const
bool isOperationMove() const
Definition MoveNode.cc:253
bool isMove() const
std::string toString() const
Definition MoveNode.cc:576
TTAProgram::Move & move()
void setSelector(MoveNodeSelector *selector)
void initialize(DataDependenceGraph &ddg)
virtual int largestCycle() const override
virtual int removeDeadResults(MoveNodeGroup &candidates, DataDependenceGraph &ddg, ResourceManager &rm, std::set< std::pair< TTAProgram::Move *, int > > &removedMoves)=0
virtual void setSelector(MoveNodeSelector *selector)
virtual int bypassNode(MoveNode &moveNode, int &lastOperandCycle, DataDependenceGraph &ddg, ResourceManager &rm)=0
virtual void clearCaches(DataDependenceGraph &ddg, bool removeDeadResults)=0
virtual void removeBypass(MoveNodeGroup &candidates, DataDependenceGraph &ddg, ResourceManager &rm)=0
Terminal & source() const
Definition Move.cc:302
Terminal & destination() const
Definition Move.cc:323
virtual bool isRA() const
Definition Terminal.cc:129
virtual bool equals(const Terminal &other) const =0

References __func__, SoftwareBypasser::bypassNode(), CriticalPathBBMoveNodeSelector::candidates(), SoftwareBypasser::clearCaches(), ddg_, ddgSnapshot(), TTAProgram::Move::destination(), DataDependenceGraph::DUMP_DOT, DataDependenceGraph::DUMP_XML, LLVMTCECmdLineOptions::dumpDDGsDot(), LLVMTCECmdLineOptions::dumpDDGsXML(), TTAProgram::Terminal::equals(), RegisterRenamer::initialize(), MoveNode::isMove(), MoveNode::isOperationMove(), TTAProgram::Terminal::isRA(), MoveNodeGroup::isScheduled(), SimpleResourceManager::largestCycle(), minCycle_, MoveNode::move(), BoostGraph< GraphNode, GraphEdge >::node(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), BoostGraph< GraphNode, GraphEdge >::nodeCount(), notifyScheduled(), options_, SoftwareBypasser::removeBypass(), SoftwareBypasser::removeDeadResults(), renamer_, rm_, DataDependenceGraph::scheduledNodeCount(), scheduledTempMoves_, scheduleMove(), scheduleOperation(), scheduleRRMove(), selector_, RegisterRenamer::setSelector(), SoftwareBypasser::setSelector(), softwareBypasser_, TTAProgram::Move::source(), targetMachine_, MoveNode::toString(), tripCount_, unscheduleAllNodes(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Here is the call graph for this function:

◆ handleLoopDDG()

int BasicBlockScheduler::handleLoopDDG ( DataDependenceGraph ddg,
SimpleResourceManager rm,
const TTAMachine::Machine targetMachine,
int  tripCount,
SimpleResourceManager prologRM,
bool  testOnly = false 
)
overridevirtual

Schedules loop in a DDG

Parameters
ddgThe ddg containing the loop
rmResource manager that is to be used.
targetMachineThe target machine.
Exceptions
Exceptionseveral TCE exceptions can be thrown in case of a scheduling error.
Returns
negative if failed, else overlapcount.

Reimplemented from DDGPass.

Reimplemented in BUBasicBlockScheduler.

Definition at line 251 of file BasicBlockScheduler.cc.

254 {
255 tripCount_ = tripCount;
256 ddg_ = &ddg;
257 targetMachine_ = &targetMachine;
258 minCycle_ = 0;
259
260 if (renamer_ != NULL) {
261 renamer_->initialize(ddg);
262 }
263
264 if (options_ != NULL && options_->dumpDDGsDot()) {
266 ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false, true);
267 }
268
269 if (options_ != NULL && options_->dumpDDGsXML()) {
271 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false, true);
272 }
273
274 scheduledTempMoves_.clear();
275
276 // empty DDGs can be ignored
277 if (ddg.nodeCount() == 0 ||
278 (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
279 return 0;
280 }
281
282 CriticalPathBBMoveNodeSelector selector(ddg, targetMachine);
283
284 rm_ = &rm;
285
286 // register selector to bypasser for notfications.
287 if (softwareBypasser_ != NULL) {
288 softwareBypasser_->setSelector(&selector);
289 }
290
291 if (renamer_ != NULL) {
292 renamer_->setSelector(&selector);
293 }
294
295 for (int i = ddg.nodeCount()-1; i>= 0 ; i--) {
296 MoveNode& node = ddg.node(i);
297 if (node.move().isControlFlowMove()) {
298 jumpNode_ = &node;
299 MoveNodeGroup mng;
300 mng.addNode(node);
302 }
303 }
304
305 MoveNodeGroup moves = selector.candidates();
306 while (moves.nodeCount() > 0) {
307
308 MoveNode& firstMove = moves.node(0);
309 if (firstMove.isOperationMove()) {
310 scheduleOperation(moves);
311 } else {
312 if (firstMove.move().destination().isRA()) {
313 scheduleMove(firstMove,0, true);
314 } else {
315 scheduleRRMove(firstMove);
316 }
317 }
318
319 if (!moves.isScheduled()) {
321 std::string("ii_") +
323 std::string("_dag.dot"));
324
326
327 return -1;
328 }
329
330 // notifies successors of the scheduled moves.
331 notifyScheduled(moves, selector);
332
333 moves = selector.candidates();
334 }
335
336 if (ddg.nodeCount() !=
337 ddg.scheduledNodeCount()) {
338 debugLog("All moves in the DDG didn't get scheduled.");
339// debugLog("Disassembly of the situation:");
340// Application::logStream() << bb.disassemble() << std::endl;
341 ddg.writeToDotFile("failed_bb.dot");
342 abortWithError("Should not happen!");
343 }
344
345 // loop schedulign did not help.
346 if (static_cast<unsigned>(ddg.largestCycle()) < rm.initiationInterval()
347 || testOnly) {
348 if (static_cast<unsigned>(ddg.largestCycle()) <
349 rm.initiationInterval()) {
351 << "No overlapping instructions."
352 << "Should Revert to ordinary scheduler."
353 << std::endl;
354 }
355 // this have to be calculated before unscheduling.
356 int rv = ddg.largestCycle() / rm.initiationInterval();
358 return rv;
359 }
360
361 // test that ext-cond jump not in prolog (where it is skipped)
362 int overlap_count = ddg.largestCycle() / rm.initiationInterval();
363 if (overlap_count >= tripCount) {
365 return -1;
366 }
367
368 if (softwareBypasser_ != NULL) {
369 softwareBypasser_->clearCaches(ddg, true);
370 }
371
372 if (options_ != NULL && options_->dumpDDGsDot()) {
373 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, true);
374 }
375
376 if (options_ != NULL && options_->dumpDDGsXML()) {
377 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
378 }
379
380 return ddg.largestCycle() / rm.initiationInterval();
381}
#define debugLog(text)
#define abortWithError(message)
static std::ostream & logStream()
static std::string toString(const T &source)
void addNode(MoveNode &node)
virtual unsigned initiationInterval() const
bool isControlFlowMove() const
Definition Move.cc:233

References abortWithError, MoveNodeGroup::addNode(), CriticalPathBBMoveNodeSelector::candidates(), SoftwareBypasser::clearCaches(), ddg_, ddgSnapshot(), debugLog, TTAProgram::Move::destination(), DataDependenceGraph::DUMP_DOT, DataDependenceGraph::DUMP_XML, LLVMTCECmdLineOptions::dumpDDGsDot(), LLVMTCECmdLineOptions::dumpDDGsXML(), RegisterRenamer::initialize(), SimpleResourceManager::initiationInterval(), TTAProgram::Move::isControlFlowMove(), MoveNode::isMove(), MoveNode::isOperationMove(), TTAProgram::Terminal::isRA(), MoveNodeGroup::isScheduled(), jumpNode_, DataDependenceGraph::largestCycle(), Application::logStream(), minCycle_, MoveNode::move(), BoostGraph< GraphNode, GraphEdge >::node(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), BoostGraph< GraphNode, GraphEdge >::nodeCount(), notifyScheduled(), options_, renamer_, rm_, DataDependenceGraph::scheduledNodeCount(), scheduledTempMoves_, scheduleMove(), scheduleOperation(), scheduleRRMove(), RegisterRenamer::setSelector(), SoftwareBypasser::setSelector(), softwareBypasser_, targetMachine_, Conversion::toString(), tripCount_, unscheduleAllNodes(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Here is the call graph for this function:

◆ handleRemovedResultMoves()

void BasicBlockScheduler::handleRemovedResultMoves ( std::set< std::pair< TTAProgram::Move *, int > >  removedMoves)
protected

Checks if the result moves that were removed might remove some resource bottleneck of already scheduled moves.

This situation happens at least when a result move used the last RF write port for a cycle and limited the earliest cycle of a previously scheduled move. Thus, after the last use of that result was scheduled and bypassed, the RF write port is freed as the result move becomes unnecessary, thus the move that was scheduled before could be scheduled earlier. Same thing can happen for bus (move slot) contrained moves and also moves that were restricted by a WaR edge due to the result move, etc.

Todo:
: reschedule also the moves dependent from the rescheduled ones that got earlier

Definition at line 1803 of file BasicBlockScheduler.cc.

1804 {
1805
1806 if (removedMoves.size() == 0)
1807 return;
1808
1809#ifndef RESCHEDULE_NEXT_CYCLE_AFTER_DRE
1810 return;
1811#endif
1812
1813 const bool DEBUG_PRINT = false; //Application::verboseLevel() > 0;
1814
1815 if (DEBUG_PRINT) {
1817 << removedMoves.size() << " dead results eliminated: "
1818 << std::endl;
1819 }
1820
1821 for (std::set<std::pair<TTAProgram::Move*, int> >::
1822 const_iterator i = removedMoves.begin();
1823 i != removedMoves.end(); ++i) {
1824
1825 TTAProgram::Move& eliminatedMove = *(*i).first;
1826 int cycle = (*i).second;
1827
1828 if (DEBUG_PRINT) {
1830 << eliminatedMove.toString() << " (cycle " << cycle << ") ";
1831 }
1832
1833 int oldCycle = cycle + 1;
1834 // look for already scheduled moves that were scheduled after
1835 // the cycle of the result move, thus potentially were limited by
1836 // the result move earlier
1837 DataDependenceGraph::NodeSet nextCycleMoves =
1838 ddg_->movesAtCycle(oldCycle);
1839
1840 // if true, try to reschedule all moves at the next cycle (slower,
1841 // but handles the case when the cycle was bus constrained previously),
1842 // if false, tries to schedule only potentially RF write port
1843 // constrained moves (faster)
1844 bool rescheduleAllSucceedingMoves = false;
1845 for (DataDependenceGraph::NodeSet::const_iterator m =
1846 nextCycleMoves.begin(); m != nextCycleMoves.end(); ++m) {
1847 MoveNode& moveNode = **m;
1848
1849 if (rescheduleAllSucceedingMoves ||
1850 (moveNode.move().destination().isGPR() &&
1851 &eliminatedMove.destination().registerFile() ==
1852 &moveNode.move().destination().registerFile())) {
1853
1854 if (DEBUG_PRINT) {
1856 << "Trying to reschedule "
1857 << moveNode.toString() << " " << std::endl;
1858 }
1859
1860 assert(moveNode.isScheduled() && moveNode.cycle() == oldCycle);
1861
1862 unschedule(moveNode);
1863 // because a pontially removed WaR, we might be able to
1864 // schedule this move (write to the same reg) even earlier
1865 // than the dead result move cycle
1866 scheduleMove(moveNode, std::max(oldCycle - 10, 0), false);
1867
1868 if (!moveNode.isScheduled()) {
1869 for (int c = 4; c >= 0; --c) {
1871 << "\t\t" << oldCycle - c << ": "
1872 << rm_->instruction(
1873 std::max(oldCycle - c, 0))->toString()
1874 << std::endl;
1875 }
1876 assert(moveNode.isScheduled());
1877 }
1878
1879 if (moveNode.cycle() < oldCycle) {
1880 if (DEBUG_PRINT) {
1882 << " OK at cycle " << moveNode.cycle() << ". " << std::endl;
1883 }
1884 } else {
1885 // should not get worse schedule!
1886 assert(moveNode.cycle() == oldCycle);
1887 if (DEBUG_PRINT) {
1888 Application::logStream() << " NO change. " << std::endl;
1889 }
1890 }
1891
1892 }
1893 /// @todo: reschedule also the moves dependent from the
1894 /// rescheduled ones that got earlier
1895 }
1896
1897 if (DEBUG_PRINT) {
1898 Application::logStream() << std::endl;
1899 }
1900 }
1901}
#define assert(condition)
void unschedule(MoveNode &moveNode)
NodeSet movesAtCycle(int cycle) const
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
int cycle() const
Definition MoveNode.cc:421
bool isScheduled() const
Definition MoveNode.cc:409
virtual TTAProgram::Instruction * instruction(int cycle) const override
std::string toString() const
std::string toString() const
Definition Move.cc:436
virtual bool isGPR() const
Definition Terminal.cc:107
virtual const TTAMachine::RegisterFile & registerFile() const
Definition Terminal.cc:225

References assert, MoveNode::cycle(), ddg_, TTAProgram::Move::destination(), SimpleResourceManager::instruction(), TTAProgram::Terminal::isGPR(), MoveNode::isScheduled(), Application::logStream(), MoveNode::move(), DataDependenceGraph::movesAtCycle(), TTAProgram::Terminal::registerFile(), rm_, scheduleMove(), TTAProgram::Instruction::toString(), TTAProgram::Move::toString(), MoveNode::toString(), and unschedule().

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ longDescription()

std::string BasicBlockScheduler::longDescription ( ) const
virtual

Optional longer description of the pass.

This description can include usage instructions, details of choice of algorithmic details, etc.

Returns
The description as a string.

Reimplemented from SchedulerPass.

Reimplemented in BUBasicBlockScheduler.

Definition at line 1583 of file BasicBlockScheduler.cc.

1583 {
1584 return
1585 "Basic block scheduler that uses the longest path information of "
1586 "data dependency graph to prioritize the ready list. Assumes that "
1587 "the input has registers allocated and no connectivity missing.";
1588}

◆ notifyScheduled()

void BasicBlockScheduler::notifyScheduled ( MoveNodeGroup moves,
MoveNodeSelector selector 
)
protected

Notifies to the selector that given nodes and their temp reg copies are scheduled .

Parameters
nodesnodes which are scheduled.
selectorselector which to notify.

Definition at line 1598 of file BasicBlockScheduler.cc.

1599 {
1600
1601 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
1602 MoveNode& moveNode = moves.node(moveIndex);
1603 selector.notifyScheduled(moveNode);
1604 std::map<const MoveNode*, DataDependenceGraph::NodeSet>::
1605 iterator tmIter = scheduledTempMoves_.find(&moveNode);
1606 if (tmIter != scheduledTempMoves_.end()) {
1607 DataDependenceGraph::NodeSet& tempMoves = tmIter->second;
1608 for (DataDependenceGraph::NodeSet::iterator i =
1609 tempMoves.begin(); i != tempMoves.end(); i++) {
1610 if ((**i).isScheduled()) {
1611 selector.notifyScheduled(**i);
1612 }
1613 }
1614 }
1615 }
1616}
virtual void notifyScheduled(MoveNode &node)=0

References MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), MoveNodeSelector::notifyScheduled(), and scheduledTempMoves_.

Referenced by handleDDG(), handleLoopDDG(), and BUBasicBlockScheduler::handleLoopDDG().

Here is the call graph for this function:

◆ printStats()

void BasicBlockScheduler::printStats ( ) const
virtual

Definition at line 1904 of file BasicBlockScheduler.cc.

1904 {
1905 if (Application::verboseLevel() > 0) {
1906 }
1907}
static int verboseLevel()

References Application::verboseLevel().

Here is the call graph for this function:

◆ scheduleInputOperandTempMoves()

void BasicBlockScheduler::scheduleInputOperandTempMoves ( MoveNode operandMove,
MoveNode operandWrite 
)
protected

Schedules the (possible) temporary register copy moves (due to missing connectivity) preceeding the given input move.

The function recursively goes through all the temporary moves added to the given input move.

Parameters
operandMoveA temp move whose predecessor has to be scheduled.
operandWriteThe original move of which temp moves to schedule.

Definition at line 1340 of file BasicBlockScheduler.cc.

1341 {
1342 /* Because temporary register moves do not have WaR dependency edges
1343 between the other possible uses of the same temp register in
1344 the same operation, we have to limit the scheduling of the new
1345 temp reg move to the last use of the same temp register so
1346 we don't overwrite the temp registers of other operands. */
1347
1348 /* <pekka> TODO: this could be improved by allowing to schedule also
1349 *before* the previous use, in the "holes" where it's unused. Now in effect
1350 the copies serialize the code quite badly. */
1351 int lastUse = 0;
1352
1353 // find all unscheduled preceeding temp moves of the operand move
1354 DataDependenceGraph::EdgeSet inEdges = ddg_->inEdges(operandMove);
1355 MoveNode* tempMove = NULL;
1356 for (DataDependenceGraph::EdgeSet::iterator i = inEdges.begin();
1357 i != inEdges.end(); ++i) {
1358 if ((**i).edgeReason() != DataDependenceEdge::EDGE_REGISTER ||
1359 (**i).guardUse() ||
1360 (**i).dependenceType() != DataDependenceEdge::DEP_RAW) {
1361 continue;
1362 }
1363
1364 MoveNode& m = ddg_->tailNode(**i);
1365 if (m.isScheduled() ||
1366 !m.move().hasAnnotations(
1368 continue;
1369 }
1370
1371 assert(tempMove == NULL &&
1372 "Multiple unscheduled moves for the operand move, should have "
1373 "max. one (the temporary move)!");
1374 tempMove = &m;
1375 MoveNode* lastRead =
1377 tempMove->move().destination().registerFile(),
1378 tempMove->move().destination().index());
1379 if (lastRead != NULL)
1380 lastUse = lastRead->cycle();
1381 }
1382
1383 if (tempMove == NULL)
1384 return; // no temp moves found
1385
1386 // the temp move should have maximum of one unscheduled
1387 // preceeding reg to reg copy (in case of an additional temp reg copy),
1388 // schedule it first if found, calling recursively this function
1389 scheduleInputOperandTempMoves(*tempMove, operandWrite);
1390
1391 // TODO: is the true correct here?
1392 scheduleMove(*tempMove, lastUse, true);
1393 assert(tempMove->isScheduled());
1394 scheduledTempMoves_[&operandWrite].insert(tempMove);
1395}
void scheduleInputOperandTempMoves(MoveNode &operandMove, MoveNode &operandWrite)
virtual Node & tailNode(const Edge &edge) const
virtual EdgeSet inEdges(const Node &node) const
MoveNode * lastScheduledRegisterRead(const TTAMachine::BaseRegisterFile &rf, int registerIndex, int lastCycleToTest=INT_MAX) const
std::set< GraphEdge *, typename GraphEdge::Comparator > EdgeSet
Definition Graph.hh:54
bool hasAnnotations(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID) const
@ ANN_CONNECTIVITY_MOVE
A reg to reg move that was added because of missing connectivity between the original target and dest...
virtual int index() const
Definition Terminal.cc:274

References TTAProgram::ProgramAnnotation::ANN_CONNECTIVITY_MOVE, assert, MoveNode::cycle(), ddg_, DataDependenceEdge::DEP_RAW, TTAProgram::Move::destination(), DataDependenceEdge::EDGE_REGISTER, TTAProgram::AnnotatedInstructionElement::hasAnnotations(), TTAProgram::Terminal::index(), BoostGraph< GraphNode, GraphEdge >::inEdges(), MoveNode::isScheduled(), DataDependenceGraph::lastScheduledRegisterRead(), MoveNode::move(), TTAProgram::Terminal::registerFile(), scheduledTempMoves_, scheduleInputOperandTempMoves(), scheduleMove(), and BoostGraph< GraphNode, GraphEdge >::tailNode().

Referenced by scheduleInputOperandTempMoves(), and scheduleOperandWrites().

Here is the call graph for this function:

◆ scheduleMove()

void BasicBlockScheduler::scheduleMove ( MoveNode moveNode,
int  earliestCycle,
bool  allowPredicationAndRenaming 
)
protected

Schedules a single move to the earliest possible cycle, taking in account the DDG, resource constraints, and latencies in producing source values.

This method assumes the move is possible to schedule with regards to connectivity and resources. Short immediates are converted to long immediates when needed.

Parameters
moveThe move to schedule.
earliestCycleThe earliest cycle to try.
allowPredicationAndRenamingWhether allowed to remove guard from the move being scheduled. Checks again side-effects are still made, this can be done only to operand moves and triggers without mem write or side-effects.

Definition at line 946 of file BasicBlockScheduler.cc.

947 {
948 if (moveNode.isScheduled()) {
949 throw InvalidData(
950 __FILE__, __LINE__, __func__,
951 (boost::format("Move '%s' is already scheduled!")
952 % moveNode.toString()).str());
953 }
954
955 int sourceReadyCycle = 0;
956 if (moveNode.isSourceOperation()) {
957 sourceReadyCycle = moveNode.earliestResultReadCycle();
958 }
959
960 int ddgCycle = 0;
961
962 unsigned int ii = rm_->initiationInterval();
963
964 // schedule jumps and calls...
965 if (moveNode.move().isControlFlowMove()) {
966
967 // the branch should get scheduled last, so the DDG should have
968 // only the branch move(s) at hand unscheduled. For software
969 // pipelining (ii > 0), branches might be scheduled earlier.
970 if (ii == 0 && ddg_->nodeCount() != ddg_->scheduledNodeCount() + 1) {
971 // in rare case the branch moves can have 2 parameters (SPU)
972 // and therefore 2 nodes unscheduled. Check if the unscheduled
973 // moves are all control flow moves.
974 DataDependenceGraph::NodeSet unscheduledMoves =
976 for (DataDependenceGraph::NodeSet::iterator i = unscheduledMoves.begin();
977 i != unscheduledMoves.end(); ++i) {
978 if (!(*i)->move().isControlFlowMove()) {
979 TCEString msg =
980 "Control Flow Move is not last of the unscheduled moves! ";
981 msg += "Scheduled count=" +
983 msg += " Node count=" +
985 throw InvalidData(__FILE__, __LINE__, __func__, msg);
986 }
987 }
988 }
989
990 // try to fill the delay slots with moves within the same basic
991 // block
992 // @TODO: ignore argument/rv register deps in case of call as they
993 // are not really used by the call instruction but by the called
994 // procedure, thus we can schedule them at the delay slots
995
996 // largest cycle of DDG is the highest cycle where something
997 // was scheduled, however such a move can have pipeline
998 // that spans more cycles and we should not change
999 // the control flow while something is still in pipeline
1000 int largest = std::max(rm_->largestCycle(), ddg_->largestCycle());
1001 if (ii == 0) {
1002 ddgCycle =
1003 std::max(
1004 ddg_->earliestCycle(moveNode),
1005 largest - targetMachine_->controlUnit()->delaySlots());
1006 } else {
1007 unsigned int delaySlots =
1009 // is the jump in first or later iteration?
1010 MoveNode* jumpLimit = ddg_->findLoopLimitAndIndex(moveNode).first;
1011
1012 ddgCycle = (((ddg_->earliestCycle(moveNode, ii) +
1013 delaySlots) / ii) + 1)*ii - 1 - delaySlots;
1014 if ((unsigned)ddgCycle >= ii - delaySlots) {
1015
1016 int jumpOverlapCount = (ddgCycle + delaySlots) / ii;
1017 if (jumpLimit == NULL) {
1018 // allow jump only in first iteration if we could
1019 // not find the limit
1020 return;
1021 } else {
1022 // update loop limit counter.
1023 TTAProgram::TerminalImmediate& ti = dynamic_cast<
1024 TTAProgram::TerminalImmediate&>(jumpLimit->move().source());
1025 int jumpLimitValue = ti.value().unsignedValue();
1026 int loopCounterStep = 1;
1027 if (jumpLimitValue != tripCount_) {
1028 if (jumpLimitValue == 2 * tripCount_) {
1029 loopCounterStep = 2;
1030 } else {
1031 if (jumpLimitValue == 4 * tripCount_) {
1032 loopCounterStep = 4;
1033 } else {
1034 // don't know how much to decr. counter.
1035 return;
1036 }
1037 }
1038 }
1039
1040 if (tripCount_ > jumpOverlapCount) {
1041 jumpLimit->move().setSource(
1043 SimValue(
1044 jumpLimitValue -
1045 (jumpOverlapCount * loopCounterStep),
1046 ti.value().width())));
1047 } else {
1048 // loop limit is too short.
1049 // would be always executed too many times.
1050 return;
1051 }
1052 }
1053 }
1054 }
1055 } else { // not a control flow move:
1056 ddgCycle = ddg_->earliestCycle(moveNode, ii);
1057
1058 // <pekka> This is now always called even though renaming is disabled?
1059 int minRenamedEC = std::max(
1060 sourceReadyCycle, ddg_->earliestCycle(moveNode, ii, true, true));
1061
1062 // rename if can and may alow scheuduling earlier.
1063 if (renamer_ != NULL && minRenamedEC < ddgCycle &&
1064 allowPredicationAndRenaming) {
1065 minRenamedEC = rm_->earliestCycle(minRenamedEC, moveNode);
1066 if (minRenamedEC < ddgCycle) {
1067
1069 moveNode, ii != 0, true, true, minRenamedEC)) {
1070 ddgCycle = ddg_->earliestCycle(moveNode, ii);
1071 } else {
1072#ifdef THIS_IS_BUGGY_WITH_REGCOPY_ADDER
1073 // renaming already scheduled ones may fail if
1074 // loop scheudling.
1075 if (rm_->initiationInterval() == 0) {
1076 MoveNode *limitingAdep =
1078 if (limitingAdep != NULL) {
1079 // don't try to rename is same operation.
1080 // as it would not help at all.
1081 if (!moveNode.isSourceOperation() ||
1082 !limitingAdep->isDestinationOperation() ||
1083 &moveNode.sourceOperation() !=
1084 &limitingAdep->destinationOperation()) {
1086 *limitingAdep, false, true, true)) {
1087 ddgCycle = ddg_->earliestCycle(
1088 moveNode);
1089 }
1090 }
1091 }
1092 }
1093#endif
1094 }
1095 }
1096 }
1097 }
1098
1099 // if it's a conditional move then we have to be sure that the guard
1100 // is defined before executing the move.
1101 // this is already handled by DDGs earliestCycle, except cases
1102 // where the guard is defined in a previous BB.
1103 // So this prevents scheduling unconditional moves at the beginning
1104 // of a BB.
1105
1106 if (!moveNode.move().isUnconditional()) {
1107 ddgCycle = std::max(ddgCycle, moveNode.guardLatency()-1);
1108
1109 if (allowPredicationAndRenaming) {
1110 // try to get rid of the guard if it gives earlier earliestcycle.
1111 if (ddg_->earliestCycle(moveNode, ii, false, false, true)
1112 < ddgCycle) {
1113 bool guardNeeded = false;
1114 if (moveNode.move().destination().isGPR() ||
1115 moveNode.move().isControlFlowMove()) {
1116 guardNeeded = true;
1117 } else {
1118 // this would be needed only for trigger,
1119 // but trigger may change during scheduling.
1120 // so lets just limit all operands, it seems
1121 // this does not make the schedule any worse.
1122 if (moveNode.isDestinationOperation()) {
1123 const Operation& o =
1124 moveNode.destinationOperation().operation();
1125 if (o.writesMemory() || o.hasSideEffects() ||
1126 o.affectsCount() != 0) {
1127 guardNeeded = true;
1128 }
1129 }
1130 }
1131 if (!guardNeeded) {
1132 moveNode.move().setGuard(NULL);
1133 ddg_->removeIncomingGuardEdges(moveNode);
1134 ddgCycle = ddg_->earliestCycle(moveNode, ii);
1135 assert(moveNode.move().isUnconditional());
1136 }
1137 }
1138
1139 if (ii == 0 && tryToOptimizeWaw(moveNode)) {
1140 ddgCycle = std::max(ddg_->earliestCycle(moveNode, ii),
1141 moveNode.guardLatency()-1);
1142 }
1143
1144 }
1145 }
1146
1147 // Earliest cycle from which to start, could depend on result ready
1148 // for result moves.
1149 int minCycle = std::max(std::max(earliestCycle, ddgCycle), minCycle_);
1150 minCycle = std::max(minCycle, sourceReadyCycle);
1151
1152 // RM hasConnection takes MoveNodeSet, however is called only for one
1153 // moveNode here.
1154 MoveNodeSet tempSet;
1155 tempSet.addMoveNode(moveNode);
1156 if (moveNode.isSourceConstant() &&
1157 !moveNode.move().hasAnnotations(
1159 // If source is constant and node does not have annotation already,
1160 // we add it if constant can not be transported so IU broker and
1161 // OutputPSocket brokers will add Immediate
1162 // Example : 999999 -> integer0.2
1163 if (!rm_->canTransportImmediate(moveNode)){
1166 moveNode.move().setAnnotation(annotation);
1167
1168 } else if (!moveNode.isDestinationOperation() &&
1169 rm_->earliestCycle(rm_->largestCycle() + 1, moveNode) == -1
1170 && rm_->initiationInterval() == 0) {
1171
1172 // If source is constant and node does not have annotation already,
1173 // we add it if node has no connection, so IU broker and
1174 // OutputPSocket brokers will add Immediate
1175 // Example: 27 -> integer0.2
1176 // With bus capable of transporting 27 as short immediate but
1177 // no connection from that bus to integer0 unit
1178 // this may mess up modulo scheduling.
1179 // TODO: do this more cleanly, this is a kludge.
1182 moveNode.move().setAnnotation(annotation);
1183 }
1184 }
1185 // annotate the return move otherwise it might get undetected in the
1186 // simulator after the short to long immediate conversion and thus
1187 // stopping simulation automatically might not work
1188 if (moveNode.isSourceConstant() &&
1189 moveNode.move().isReturn() &&
1190 !rm_->canTransportImmediate(moveNode)) {
1193 moveNode.move().setAnnotation(annotation);
1194 }
1195
1196 minCycle = rm_->earliestCycle(minCycle, moveNode);
1197 if (minCycle == -1 || minCycle == INT_MAX) {
1198 if (moveNode.isSourceConstant() &&
1199 !moveNode.isDestinationOperation() &&
1200 moveNode.move().hasAnnotations(
1202 // If earliest cycle returns -1 and source is constant and moveNode
1203 // needs long immediate there is most likely missing long immediate
1204 // unit
1205 std::string msg = "Assignment of MoveNode " + moveNode.toString();
1206 msg += " failed! Most likely missing Long Immediate Unit";
1207 msg += " or Instruction Template!";
1208 if (rm_->initiationInterval() == 0) {
1209 ddg_->writeToDotFile("illegalmach.dot");
1210 throw IllegalMachine(
1211 __FILE__, __LINE__, __func__, msg);
1212 } else {
1214 std::string("ii_") +
1216 std::string("_dag.dot"));
1217
1219 throw ModuleRunTimeError(
1220 __FILE__, __LINE__, __func__, msg);
1221 }
1222 }
1223 return;
1224 }
1225
1226 int latestDDG = ddg_->latestCycle(moveNode, ii);
1227
1228 if (ii != 0 && (minCycle > latestDDG)) {
1229
1230 if (ddg_->latestCycle(moveNode, ii, true) > latestDDG) {
1231
1232 if (renamer_ != NULL && allowPredicationAndRenaming) {
1233 // todo: do also otherway
1234 if (renamer_->renameSourceRegister(moveNode,true, true, true)) {
1235 latestDDG = ddg_->latestCycle(moveNode, ii);
1236 }
1237 }
1238 }
1239 }
1240
1241 // test again after renaming?
1242
1243 if (ii != 0 && (minCycle > latestDDG)) {
1244
1245 // if we pre-scheduled jump, unschedule it and try to schdule
1246 // the node again.
1247 if (jumpNode_ != NULL) {
1248 ddg_->writeToDotFile("unschedJump.dot");
1250 jumpNode_ = NULL;
1251 scheduleMove(moveNode, earliestCycle, allowPredicationAndRenaming);
1252 return;
1253 }
1254
1256 std::string("ii_") + Conversion::toString(ii) +
1257 std::string("_dag.dot"));
1258
1260 throw ModuleRunTimeError(
1261 __FILE__, __LINE__, __func__, "Schedule failed try bigger ii.");
1262 }
1263
1264 try {
1265 rm_->assign(minCycle, moveNode);
1266 } catch (const Exception& e) {
1267 throw ModuleRunTimeError(
1268 __FILE__, __LINE__, __func__, e.errorMessageStack());
1269 }
1270
1271 if (!moveNode.isScheduled()) {
1272 throw ModuleRunTimeError(
1273 __FILE__, __LINE__, __func__,
1274 (boost::format("Assignment of MoveNode '%s' failed!")
1275 % moveNode.toString()).str());
1276 }
1277 assert(moveNode.cycle() >= minCycle_);
1278}
bool tryToOptimizeWaw(const MoveNode &moveNode)
int latestCycle(const MoveNode &moveNode, unsigned int ii=UINT_MAX, bool ignoreRegAntideps=false, bool ignoreUnscheduledSuccessors=true, bool ignoreGuards=false, bool ignoreFUDeps=false, bool ignoreSameOperationEdges=false) const
int earliestCycle(const MoveNode &moveNode, unsigned int ii=UINT_MAX, bool ignoreRegWaRs=false, bool ignoreRegWaWs=false, bool ignoreGuards=false, bool ignoreFUDeps=false, bool ignoreSameOperationEdges=false, bool assumeBypassing=false) const
NodeSet unscheduledMoves() const
MoveNode * findLimitingAntidependenceSource(MoveNode &mn)
std::pair< MoveNode *, MoveNode * > findLoopLimitAndIndex(MoveNode &jumpMove)
void removeIncomingGuardEdges(MoveNode &node)
std::string errorMessageStack(bool messagesOnly=false) const
Definition Exception.cc:138
void addMoveNode(MoveNode &)
int earliestResultReadCycle() const
Definition MoveNode.cc:652
int guardLatency() const
Definition MoveNode.cc:779
ProgramOperation & sourceOperation() const
Definition MoveNode.cc:453
bool isDestinationOperation() const
bool isSourceOperation() const
Definition MoveNode.cc:168
bool isSourceConstant() const
Definition MoveNode.cc:238
ProgramOperation & destinationOperation(unsigned int index=0) const
virtual bool hasSideEffects() const
Definition Operation.cc:272
virtual int affectsCount() const
Definition Operation.cc:402
virtual bool writesMemory() const
Definition Operation.cc:252
bool renameDestinationRegister(MoveNode &node, bool loopScheduling, bool allowSameRf, bool differentRfOnlyDirectlyReachable, int earliestCycle=-1)
bool renameSourceRegister(MoveNode &node, bool loopScheduling, bool allowSameRf, bool differentRfOnlyDirectlyReachable, int latestCycle=INT_MAX)
unsigned int unsignedValue() const
Definition SimValue.cc:919
int width() const
Definition SimValue.cc:103
virtual void assign(int cycle, MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) override
virtual int earliestCycle(MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
virtual bool canTransportImmediate(const MoveNode &node, const TTAMachine::Bus *preAssignedBus=NULL) const
void setAnnotation(const ProgramAnnotation &annotation)
void setSource(Terminal *src)
Definition Move.cc:312
bool isReturn() const
Definition Move.cc:259
bool isUnconditional() const
Definition Move.cc:154
void setGuard(MoveGuard *guard)
Definition Move.cc:360
@ ANN_STACKFRAME_PROCEDURE_RETURN
precedure return jmp
virtual SimValue value() const

References __func__, MoveNodeSet::addMoveNode(), Operation::affectsCount(), TTAProgram::ProgramAnnotation::ANN_REQUIRES_LIMM, TTAProgram::ProgramAnnotation::ANN_STACKFRAME_PROCEDURE_RETURN, assert, SimpleResourceManager::assign(), SimpleResourceManager::canTransportImmediate(), TTAMachine::Machine::controlUnit(), MoveNode::cycle(), ddg_, TTAMachine::ControlUnit::delaySlots(), TTAProgram::Move::destination(), MoveNode::destinationOperation(), DataDependenceGraph::earliestCycle(), SimpleResourceManager::earliestCycle(), MoveNode::earliestResultReadCycle(), Exception::errorMessageStack(), DataDependenceGraph::findLimitingAntidependenceSource(), DataDependenceGraph::findLoopLimitAndIndex(), MoveNode::guardLatency(), TTAProgram::AnnotatedInstructionElement::hasAnnotations(), Operation::hasSideEffects(), SimpleResourceManager::initiationInterval(), TTAProgram::Move::isControlFlowMove(), MoveNode::isDestinationOperation(), TTAProgram::Terminal::isGPR(), TTAProgram::Move::isReturn(), MoveNode::isScheduled(), MoveNode::isSourceConstant(), MoveNode::isSourceOperation(), TTAProgram::Move::isUnconditional(), jumpNode_, DataDependenceGraph::largestCycle(), SimpleResourceManager::largestCycle(), DataDependenceGraph::latestCycle(), minCycle_, MoveNode::move(), BoostGraph< GraphNode, GraphEdge >::nodeCount(), ProgramOperation::operation(), DataDependenceGraph::removeIncomingGuardEdges(), RegisterRenamer::renameDestinationRegister(), renamer_, RegisterRenamer::renameSourceRegister(), rm_, DataDependenceGraph::scheduledNodeCount(), scheduleMove(), TTAProgram::AnnotatedInstructionElement::setAnnotation(), TTAProgram::Move::setGuard(), TTAProgram::Move::setSource(), TTAProgram::Move::source(), MoveNode::sourceOperation(), targetMachine_, MoveNode::toString(), Conversion::toString(), tripCount_, tryToOptimizeWaw(), unschedule(), unscheduleAllNodes(), DataDependenceGraph::unscheduledMoves(), SimValue::unsignedValue(), TTAProgram::TerminalImmediate::value(), SimValue::width(), Operation::writesMemory(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by handleDDG(), handleLoopDDG(), handleRemovedResultMoves(), scheduleInputOperandTempMoves(), scheduleMove(), scheduleOperandWrites(), scheduleResultReads(), scheduleResultReadTempMoves(), scheduleRRMove(), scheduleRRTempMoves(), and tryToOptimizeWaw().

◆ scheduleOperandWrites()

int BasicBlockScheduler::scheduleOperandWrites ( int &  cycle,
MoveNodeGroup moves 
)
protected

Schedules operand moves of an operation execution.

Assumes the given MoveNodeGroup contains all moves in the operation execution. Also assumes that all inputs to the MoveNodeGroup have been scheduled. Exception to this are the possible temporary register copies inserted before the operand move due to missing connectivity. If found, the temp moves are scheduled atomically with the operand move. Assumes top-down scheduling.

Parameters
cycleEarliest cycle for starting scheduling of operands. This parameter is modified to the highest cycle one should try next in case scheduling starting from the given cycle failed.
movesMoves of the operation execution.
Returns
The cycle the earliest of the operands got scheduled

Definition at line 629 of file BasicBlockScheduler.cc.

629 {
630 const int MAX_OPERAND_CYCLE_DIFFERENCE = 15;
631
632 const int MAX_OPERATION_START_BEFORE_EARLIEST_READ = 50;
633
634 int lastOperandCycle = 0;
635 int earliestScheduledOperand = INT_MAX;
636 int startCycle = 0;
637 MoveNode* trigger = NULL;
638 MoveNode* firstToSchedule = NULL;
639
640 // find the movenode which has highest DDG->earliestCycle and limit
641 // the starting cycle of all operands close to that.
642 // this should prevent trying to schedule immediate writes very early
643 // and having lots of retries until the cycle has risen to the level of
644 // other moves.
645 // this might make SCHEDULING_WINDOW or SimpleBrokerDirector unnecessary /
646 // allow groving it much smaller without scheduler slowdown.
647 for (int i = 0; i < moves.nodeCount(); i++) {
648 int limit = 0;
649 if (moves.node(i).isDestinationOperation()) {
650 limit = ddg_->earliestCycle(
651 moves.node(i), rm_->initiationInterval()) -
652 MAX_OPERAND_CYCLE_DIFFERENCE;
653 } else if (moves.node(i).isSourceOperation()) {
654 limit = ddg_->earliestCycle(
655 moves.node(i), rm_->initiationInterval()) -
656 MAX_OPERATION_START_BEFORE_EARLIEST_READ;
657 } else {
658 continue;
659 }
660 if (limit < 0) {
661 limit = 0;
662 }
663 if (limit > cycle) {
664 cycle = limit;
665 }
666 }
667
668 // Find and schedule moveNode which has highest "earliest Cycle"
669 // other moveNodes could be scheduled in earlier cycle but this
670 // makes sure there will be no problems with operands overwritting
671 // and assignment failures. At least it reduced a count of such.
672 // Also find smallest of all earliest cycles,
673 // make no sense to start from 0
674 for (int i = 0; i < moves.nodeCount(); i++) {
675 if (!moves.node(i).isDestinationOperation()) {
676 continue;
677 }
678
679 // Temporary moves needs to be scheduled so DDG can find
680 // earliest cycle
681 // TODO: this should also have cycle limit?
682 scheduleInputOperandTempMoves(moves.node(i), moves.node(i));
683 int earliestDDG = ddg_->earliestCycle(
684 moves.node(i), rm_->initiationInterval());
685
686 if (earliestDDG == INT_MAX) {
687 ddg_->writeToDotFile("failed_bb.dot");
689 throw InvalidData(
690 __FILE__, __LINE__, __func__,
691 (boost::format("InputTempMoves failed to schedule "
692 "successfully for '%s' ") % moves.node(i).toString()).str());
693 }
694
695 // passed argument could be larger than what DDG thinks is earliest
696 earliestDDG = std::max(earliestDDG, cycle);
697 int earliest = rm_->earliestCycle(earliestDDG, moves.node(i));
698 if (earliest == -1) {
700 continue;
701 }
702 if (earliest >= startCycle) {
703 // Find first moveNode that will be scheduled
704 startCycle = earliest;
705 firstToSchedule = &moves.node(i);
706 }
708
709 // Find also smallest of earliestCycles
710 cycle = std::min(cycle, earliest);
711 }
712
713 if (firstToSchedule != NULL) {
714 // start cycle could be null if there was problem scheduling
715 // all input temp operands
716 scheduleInputOperandTempMoves(*firstToSchedule, *firstToSchedule);
717 // earliestCycle gave us the startCycle so this must pass
718 scheduleMove(*firstToSchedule, startCycle, true);
719 if (!firstToSchedule->isScheduled()) {
721 std::string("ii_") +
723 std::string("_dag.dot"));
724
726 throw ModuleRunTimeError(
727 __FILE__, __LINE__, __func__,
728 (boost::format("Move '%s' failed to schedule")
729 % firstToSchedule->toString()).str());
730 }
731 startCycle = firstToSchedule->cycle();
732 if (firstToSchedule->move().destination().isTriggering()) {
733 trigger = firstToSchedule;
734 } else {
735 lastOperandCycle = std::max(lastOperandCycle, startCycle);
736 }
737 } else {
739 std::string("ii_") +
741 std::string("_dag.dot"));
742
744 throw ModuleRunTimeError(
745 __FILE__, __LINE__, __func__,
746 (boost::format(
747 "Unable to schedule '%s' is there enough resources?")
748 % moves.toString()).str());
749 }
750
751 // try to schedule all input moveNodes, except trigger
752 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
753 MoveNode& moveNode = moves.node(moveIndex);
754 // skip the result reads
755 if (!moveNode.isDestinationOperation()) {
756 continue;
757 }
758
759 if (moveNode.isScheduled()) {
760 earliestScheduledOperand =
761 std::min(earliestScheduledOperand, moveNode.cycle());
762 if (moveNode.move().destination().isTriggering()) {
763 trigger = &moveNode;
764 }
765 continue;
766 }
767
768 // in case the operand move requires register copies due to
769 // missing connectivity, schedule them first
770 scheduleInputOperandTempMoves(moveNode, moveNode);
771 scheduleMove(moveNode, cycle, true);
772
773 if (moveNode.isScheduled()) {
774 earliestScheduledOperand =
775 std::min(earliestScheduledOperand, moveNode.cycle());
776 if (moveNode.move().destination().isTriggering()) {
777 trigger = &moveNode;
778 earliestScheduledOperand =
779 std::min(earliestScheduledOperand, moveNode.cycle());
780 } else {
781 lastOperandCycle =
782 std::max(lastOperandCycle, moveNode.cycle());
783 }
784 } else {
785 // Movenode scheduling failed.
787 // try to unschedule trigger and then schedule this operand.
788 if (trigger != NULL && trigger->isScheduled()) {
789 unschedule(*trigger);
791 scheduleInputOperandTempMoves(moveNode, moveNode);
792 scheduleMove(moveNode, cycle, true);
793 if (!moveNode.isScheduled()) {
794 // if still failed return -1
796 // but make sure high-level loop advances some more cycles
797 if (earliestScheduledOperand != INT_MAX) {
798 cycle = earliestScheduledOperand;
799 }
800 return -1;
801 }
802 earliestScheduledOperand =
803 std::min(earliestScheduledOperand, moveNode.cycle());
804 lastOperandCycle =
805 std::max(lastOperandCycle, moveNode.cycle());
806 } else {
807 // failed even though no trigger scheduled.
808 // but make sure high-level loop advances some more cycles
809 if (earliestScheduledOperand != INT_MAX) {
810 cycle = earliestScheduledOperand;
811 }
812 return -1;
813 }
814 }
815 }
816
817 // if trigger unscheduled, schedule it again.
818 assert(trigger != NULL);
819 if (!trigger->isScheduled()) {
820 scheduleInputOperandTempMoves(*trigger, *trigger);
821 scheduleMove(*trigger, lastOperandCycle, true);
822
823 if (!trigger->isScheduled()) {
824 // trigger scheduling failed.
826 return -1;
827 }
828 earliestScheduledOperand =
829 std::min(earliestScheduledOperand, trigger->cycle());
830 }
831
832 return earliestScheduledOperand;
833}
void unscheduleInputOperandTempMoves(MoveNode &operandMove)
std::string toString() const
virtual bool isTriggering() const
Definition Terminal.cc:298

References __func__, assert, MoveNode::cycle(), ddg_, TTAProgram::Move::destination(), DataDependenceGraph::earliestCycle(), SimpleResourceManager::earliestCycle(), SimpleResourceManager::initiationInterval(), MoveNode::isDestinationOperation(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), TTAProgram::Terminal::isTriggering(), MoveNode::move(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), rm_, scheduleInputOperandTempMoves(), scheduleMove(), MoveNodeGroup::toString(), MoveNode::toString(), Conversion::toString(), unschedule(), unscheduleAllNodes(), unscheduleInputOperandTempMoves(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ scheduleOperation()

void BasicBlockScheduler::scheduleOperation ( MoveNodeGroup moves)
protected

Schedules moves in a single operation execution.

Assumes the given MoveNodeGroup contains all moves in the operation execution. Also assumes that all inputs to the MoveNodeGroup have been scheduled.

Parameters
movesMoves of the operation execution.

Definition at line 397 of file BasicBlockScheduler.cc.

397 {
398 ProgramOperation& po =
399 (moves.node(0).isSourceOperation())?
400 (moves.node(0).sourceOperation()):
401 (moves.node(0).destinationOperation());
402
403 // may switch operands of commutative operations. Do it before
404 // regcopyadder because it's easier here.
405 // cooperation with regcopyadder might make it perform better though.
407
408#ifdef DEBUG_REG_COPY_ADDER
409 ddg_->setCycleGrouping(true);
411 (boost::format("%s_before_ddg.dot") % ddg_->name()).str());
412#endif
413
414 RegisterCopyAdder regCopyAdder(
417 regCopyAdder.addMinimumRegisterCopies(po, *targetMachine_, ddg_);
418#ifdef DEBUG_REG_COPY_ADDER
419 const int tempsAdded = copies.count_;
420#endif
421
422#ifdef DEBUG_REG_COPY_ADDER
423 if (tempsAdded > 0) {
425 (boost::format("%s_after_regcopy_ddg.dot") % ddg_->name()).str());
426 }
427 ddg_->sanityCheck();
428#endif
429
430 MoveNodeSet tempSet;
431 for (int i = 0; i < moves.nodeCount(); i++) {
432 // MoveNodeGroup relates to DDG so we copy it to
433 // a simpler MoveNodeSet container
434 tempSet.addMoveNode(moves.node(i));
435 }
436
437 bool operandsFailed = true;
438 bool resultsFailed = true;
439 int operandsStartCycle = 0;
440
441 int maxFromRm = rm_->largestCycle();
442
443 // Magic number defining how many times we should try to schedule
444 // operands and results. Should not be needed in final version of
445 // scheduler
446 const int retryCount = 20;
447 int minOperand = operandsStartCycle;
448
449 bool tryBypassing = softwareBypasser_ != NULL;
450 bool bypassTrigger = true;
451
452 while ((operandsFailed || resultsFailed) &&
453 operandsStartCycle < maxFromRm + retryCount) {
454
455 minOperand = scheduleOperandWrites(operandsStartCycle, moves);
456 if (minOperand != -1) {
457 operandsFailed = false;
458 } else {
459 // Scheduling some operand failed, unschedule and try later cycle
460 for (int i = 0; i < moves.nodeCount(); i++){
461 MoveNode& moveNode = moves.node(i);
462 if (moveNode.isScheduled() &&
463 moveNode.isDestinationOperation()) {
464 unschedule(moveNode);
466 }
467 }
468 operandsFailed = true;
469 operandsStartCycle++;
470 continue;
471 }
472
473 regCopyAdder.operandsScheduled(copies, *ddg_);
474
475 int bypassedMoves = -1;
476 if (tryBypassing) {
477 bypassedMoves = softwareBypasser_->bypass(
478 moves, *ddg_, *rm_, bypassTrigger);
479 if (bypassedMoves == -1){
480 // bypassing failed try again without attempt to bypass
481 // this restores the original schedule of operands
482 // and disable bypassing
483 operandsFailed = true;
484 if (bypassTrigger == false) {
485 tryBypassing = false;
486 } else {
487 bypassTrigger = false;
488 }
490 continue;
491 }
492 // bypass was success
493 }
494
495 // TODO: disabled because may cause fail if rescheduled
496 // to different bus.
497// tryToDelayOperands(moves);
498
499 if (scheduleResultReads(moves)) {
500 resultsFailed = false;
501 // Results were scheduled, we are not going to change schedule
502 // of this program operation. Lets check if some of the
503 // bypassed operands did not produce dead result moves
504 if (tryBypassing) {
505 try {
506 std::set<std::pair<TTAProgram::Move*, int> >
507 removedMoves;
509 moves, *ddg_, *rm_, removedMoves);
510 handleRemovedResultMoves(removedMoves);
511 } catch (const Exception& e) {
512 throw ModuleRunTimeError(
513 __FILE__, __LINE__, __func__, e.errorMessageStack());
514 }
515 }
516 } else {
517 // Scheduling results failed, most likely due to large distance
518 // between trigger and earliest result cycle
519 // Some other operation is overwritting result on same FU
520 for (int i = 0; i < moves.nodeCount(); i++){
521 MoveNode& moveNode = moves.node(i);
522 if (moveNode.isScheduled()) {
523 // Operands were scheduled successfully but result can
524 // not be, we unschedule everything
525 unschedule(moveNode);
526 if (moveNode.isDestinationOperation()) {
528 }
529 if (moveNode.isSourceOperation()) {
531 }
532 }
533 }
534 resultsFailed = true;
535 // If some operands were bypassed, we need to remove bypassing
536 if (tryBypassing) {
538 tryBypassing = false;
539 continue;
540 }
541 // We will try to schedule operands in later cycle
542 // taking larger strides
543 operandsStartCycle++;
544 minOperand++;
545 operandsStartCycle = std::max(minOperand, operandsStartCycle);
546 }
547 }
548 // This fails if there is "timeout" on retry count.
549 // Should not be needed in final version.
550
551 if (operandsFailed) {
553 std::string("ii_") +
555 std::string("_dag.dot"));
556
558 throw ModuleRunTimeError(
559 __FILE__, __LINE__, __func__,
560 "Operands scheduling failed for \'" + moves.toString());
561 }
562 if (resultsFailed) {
564 std::string("ii_") +
566 std::string("_dag.dot"));
567
569 throw ModuleRunTimeError(
570 __FILE__, __LINE__, __func__,
571 "Results scheduling failed for \'" + moves.toString());
572 }
573
574 if (options_ != NULL &&
576 (resultsFailed || operandsFailed)) {
577
578 //static int failedCounter = 0;
579 if (options_->dumpDDGsDot()) {
580 ddgSnapshot(*ddg_, std::string("2_failed.dot"),
582 } else {
583 ddgSnapshot(*ddg_, std::string("2_failed.xml"),
585 }
586
588 throw ModuleRunTimeError(
589 __FILE__, __LINE__, __func__,
590 (boost::format("Bad BB %s") % ddg_->name()).str());
591 }
592
593 regCopyAdder.resultsScheduled(copies, *ddg_);
594
595#ifdef DEBUG_REG_COPY_ADDER
596 if (tempsAdded > 0) {
598 (boost::format("%s_after_scheduler_ddg.dot") %
599 ddg_->name()).str());
601 << "(operation fix #" << ddg_->name() << ")" << std::endl
602 << std::endl;
603
604 ++graphCount;
605 }
606#endif
607}
bool tryToSwitchInputs(ProgramOperation &op)
int scheduleOperandWrites(int &cycle, MoveNodeGroup &moves)
bool scheduleResultReads(MoveNodeGroup &moves)
void unscheduleResultReadTempMoves(MoveNode &resultMove)
void handleRemovedResultMoves(std::set< std::pair< TTAProgram::Move *, int > > removedMoves)
virtual void setCycleGrouping(bool flag)
InterPassData & interPassData()
virtual int bypass(MoveNodeGroup &candidates, DataDependenceGraph &ddg, ResourceManager &rm, bool bypassTrigger)=0

References __func__, RegisterCopyAdder::addMinimumRegisterCopies(), MoveNodeSet::addMoveNode(), SoftwareBypasser::bypass(), RegisterCopyAdder::AddedRegisterCopies::count_, ddg_, ddgSnapshot(), MoveNode::destinationOperation(), DataDependenceGraph::DUMP_DOT, DataDependenceGraph::DUMP_XML, LLVMTCECmdLineOptions::dumpDDGsDot(), Exception::errorMessageStack(), handleRemovedResultMoves(), SimpleResourceManager::initiationInterval(), SchedulerPass::interPassData(), MoveNode::isDestinationOperation(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), SimpleResourceManager::largestCycle(), Application::logStream(), BoostGraph< GraphNode, GraphEdge >::name(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), RegisterCopyAdder::operandsScheduled(), options_, SoftwareBypasser::removeBypass(), SoftwareBypasser::removeDeadResults(), RegisterCopyAdder::resultsScheduled(), rm_, DataDependenceGraph::sanityCheck(), scheduleOperandWrites(), scheduleResultReads(), selector_, DataDependenceGraph::setCycleGrouping(), softwareBypasser_, MoveNode::sourceOperation(), targetMachine_, MoveNodeGroup::toString(), Conversion::toString(), tryToSwitchInputs(), unschedule(), unscheduleAllNodes(), unscheduleInputOperandTempMoves(), unscheduleResultReadTempMoves(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by handleDDG(), and handleLoopDDG().

Here is the call graph for this function:

◆ scheduleResultReads()

bool BasicBlockScheduler::scheduleResultReads ( MoveNodeGroup moves)
protected

Schedules the result read moves of an operation execution.

Assumes the given MoveNodeGroup contains all moves in the operation execution. Also assumes that all operand moves have been scheduled.

Parameters
movesMoves of the operation execution.

Definition at line 843 of file BasicBlockScheduler.cc.

843 {
844 int tempRegLimitCycle = 0;
845
846 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
847 MoveNode& moveNode = moves.node(moveIndex);
848
849 if (!moveNode.isScheduled()) {
850 if (!moveNode.isSourceOperation()) {
851 throw InvalidData(
852 __FILE__, __LINE__, __func__,
853 (boost::format("Move to schedule '%s' is not "
854 "result move!") % moveNode.toString()).str());
855 }
856 if (succeedingTempMove(moveNode) != NULL) {
857
858 MoveNode* lastRead =
860 moveNode.move().destination().registerFile(),
861 moveNode.move().destination().index());
862 if (lastRead != NULL) {
863 tempRegLimitCycle = lastRead->cycle();
864 }
865 }
866
867 scheduleMove(moveNode, tempRegLimitCycle, true);
868 if (!moveNode.isScheduled()) {
869 // Result can not be scheduled even when operands were,
870 // usually caused by operands too early (data dependencies
871 // ok) and result forced to be scheduled much later
872 // because of data dependencies (WA{R,W} dependence with
873 // target register in most cases)
874 return false;
875 }
876 scheduleResultReadTempMoves(moveNode, moveNode, 0);
877 if (!moveNode.isScheduled()) {
878 throw InvalidData(
879 __FILE__, __LINE__, __func__,
880 (boost::format("Move '%s' did not get scheduled!")
881 % moveNode.toString()).str());
882 }
883 }
884 }
885 return true;
886}
void scheduleResultReadTempMoves(MoveNode &resultMove, MoveNode &resultRead, int lastUse)
MoveNode * succeedingTempMove(MoveNode &current)

References __func__, MoveNode::cycle(), ddg_, TTAProgram::Move::destination(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), DataDependenceGraph::lastScheduledRegisterRead(), MoveNode::move(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), TTAProgram::Terminal::registerFile(), scheduleMove(), scheduleResultReadTempMoves(), succeedingTempMove(), and MoveNode::toString().

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ scheduleResultReadTempMoves()

void BasicBlockScheduler::scheduleResultReadTempMoves ( MoveNode resultMove,
MoveNode resultRead,
int  lastUse 
)
protected

Schedules the (possible) temporary register copy moves (due to missing connectivity) succeeding the given result read move.

The function recursively goes through all the temporary moves added to the given input move.

Parameters
resultMoveA temp move whose successor has to be scheduled.
resultReadThe original move of which temp moves to schedule.
lastUseRecursive function parameter, it should be set as 0 for the first function call.

Definition at line 1438 of file BasicBlockScheduler.cc.

1439 {
1440 /* Because temporary register moves do not have WaR/WaW dependency edges
1441 between the other possible uses of the same temp register in
1442 the same operation, we have to limit the scheduling of the new
1443 temp reg move to the last use of the same temp register so
1444 we don't overwrite the temp registers of the other operands. */
1445
1446
1447 // find all unscheduled succeeding moves of the result read move
1448 // there should be only only one with the only dependence edge (RaW) to
1449 // the result move
1450
1451 MoveNode* tempMove1 = succeedingTempMove(resultMove);
1452 if (tempMove1 == NULL)
1453 return; // no temp moves found
1454
1455 MoveNode* tempMove2 = succeedingTempMove(*tempMove1);
1456 if (tempMove2 != NULL) {
1457 MoveNode* lastRead =
1459 tempMove1->move().destination().registerFile(),
1460 tempMove1->move().destination().index());
1461 if (lastRead != NULL)
1462 lastUse = lastRead->cycle();
1463 }
1464
1465 scheduleMove(*tempMove1, lastUse, true);
1466 assert(tempMove1->isScheduled());
1467 scheduledTempMoves_[&resultRead].insert(tempMove1);
1468
1469 // the temp move should have maximum of one unscheduled
1470 // succeeding additional reg to reg copy (in case of two temp reg copies),
1471 // schedule it also if found
1472 scheduleResultReadTempMoves(*tempMove1, resultRead, lastUse+1);
1473}

References assert, MoveNode::cycle(), ddg_, TTAProgram::Move::destination(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), DataDependenceGraph::lastScheduledRegisterRead(), MoveNode::move(), TTAProgram::Terminal::registerFile(), scheduledTempMoves_, scheduleMove(), scheduleResultReadTempMoves(), and succeedingTempMove().

Referenced by scheduleResultReads(), scheduleResultReadTempMoves(), and scheduleRRTempMoves().

Here is the call graph for this function:

◆ scheduleRRMove()

void BasicBlockScheduler::scheduleRRMove ( MoveNode moveNode)
protected

Schedules moves in a single operation execution.

Assumes the given MoveNodeGroup contains all moves in the operation execution. Also assumes that all inputs to the MoveNodeGroup have been scheduled.

Parameters
moveNodeR-R Move to schedule.

Definition at line 898 of file BasicBlockScheduler.cc.

898 {
899#ifdef DEBUG_REG_COPY_ADDER
900 ddg_->setCycleGrouping(true);
902 (boost::format("%s_before_ddg.dot") % ddg_->name()).str());
903#endif
904
905 RegisterCopyAdder regCopyAdder(
907
908#ifdef DEBUG_REG_COPY_ADDER
909 const int tempsAdded =
910#endif
911
912 regCopyAdder.addRegisterCopiesToRRMove(moveNode, ddg_)
913#ifdef DEBUG_REG_COPY_ADDER
914 .count_
915#endif
916 ;
917#ifdef DEBUG_REG_COPY_ADDER
918 if (tempsAdded > 0) {
920 (boost::format("%s_after_regcopy_ddg.dot") % ddg_->name()).str());
921 }
922 ddg_->sanityCheck();
923#endif
924
925 scheduleMove(moveNode, 0, true);
926 scheduleRRTempMoves(moveNode, moveNode, 0); //Fabio: 0 or more?!?
927}
void scheduleRRTempMoves(MoveNode &regToRegMove, MoveNode &firstMove, int lastUse)

References RegisterCopyAdder::addRegisterCopiesToRRMove(), RegisterCopyAdder::AddedRegisterCopies::count_, ddg_, SchedulerPass::interPassData(), BoostGraph< GraphNode, GraphEdge >::name(), rm_, DataDependenceGraph::sanityCheck(), scheduleMove(), scheduleRRTempMoves(), selector_, DataDependenceGraph::setCycleGrouping(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by handleDDG(), and handleLoopDDG().

Here is the call graph for this function:

◆ scheduleRRTempMoves()

void BasicBlockScheduler::scheduleRRTempMoves ( MoveNode regToRegMove,
MoveNode firstMove,
int  lastUse 
)
protected

Schedules the (possible) temporary register copy moves (due to missing connectivity) succeeding the given RR move.

The function recursively goes through all the temporary moves added to the given RR move.

Parameters
regToRegMoveA temp move whose successor has to be scheduled.
firstMoveThe original move of which temp moves to schedule.
lastUseRecursive function parameter, it should be set as 0 for the first function call.

Definition at line 1293 of file BasicBlockScheduler.cc.

1294 {
1295 /* Because temporary register moves do not have WaR/WaW dependency edges
1296 between the other possible uses of the same temp register in
1297 the same operation, we have to limit the scheduling of the new
1298 temp reg move to the last use of the same temp register so
1299 we don't overwrite the temp registers of the other operands. */
1300
1301 // find all unscheduled succeeding moves of the result read move
1302 // there should be only only one with the only dependence edge (RaW) to
1303 // the result move
1304
1305 MoveNode* tempMove1 = succeedingTempMove(regToRegMove);
1306 if (tempMove1 == NULL)
1307 return; // no temp moves found
1308
1309 MoveNode* tempMove2 = succeedingTempMove(*tempMove1);
1310 if (tempMove2 != NULL) {
1311 MoveNode* lastRead =
1313 tempMove1->move().destination().registerFile(),
1314 tempMove1->move().destination().index());
1315 if (lastRead != NULL)
1316 lastUse = lastRead->cycle();
1317 }
1318
1319 scheduleMove(*tempMove1, lastUse, true);
1320 assert(tempMove1->isScheduled());
1321 scheduledTempMoves_[&firstMove].insert(tempMove1);
1322
1323 // the temp move should have maximum of one unscheduled
1324 // succeeding additional reg to reg copy (in case of two temp reg copies),
1325 // schedule it also if found
1326 scheduleResultReadTempMoves(*tempMove1, firstMove, lastUse+1);
1327}

References assert, MoveNode::cycle(), ddg_, TTAProgram::Move::destination(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), DataDependenceGraph::lastScheduledRegisterRead(), MoveNode::move(), TTAProgram::Terminal::registerFile(), scheduledTempMoves_, scheduleMove(), scheduleResultReadTempMoves(), and succeedingTempMove().

Referenced by scheduleRRMove().

Here is the call graph for this function:

◆ shortDescription()

std::string BasicBlockScheduler::shortDescription ( ) const
virtual

A short description of the pass, usually the optimization name, such as "basic block scheduler".

Returns
The description as a string.

Implements SchedulerPass.

Reimplemented in BUBasicBlockScheduler.

Definition at line 1570 of file BasicBlockScheduler.cc.

1570 {
1571 return "Instruction scheduler with a basic block scope.";
1572}

◆ succeedingTempMove()

MoveNode * BasicBlockScheduler::succeedingTempMove ( MoveNode current)
protected

Finds the temp move succeeding the given movenode.

If it does not have one , returns null.

Parameters
currentMoveNode whose tempmoves we are searching
Returns
tempMove succeeding given node, or null if does not exist.

Definition at line 1406 of file BasicBlockScheduler.cc.

1406 {
1407
1409 MoveNode* result = NULL;
1410 for (DataDependenceGraph::NodeSet::iterator i = succ.begin();
1411 i != succ.end(); ++i) {
1412 MoveNode& m = **i;
1413 if (m.isScheduled() ||
1414 !m.move().hasAnnotations(
1416 continue;
1417
1418 assert(result == NULL &&
1419 "Multiple candidates for the temp move of result read.");
1420 result = &m;
1421 }
1422 return result;
1423}
virtual NodeSet successors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const

References TTAProgram::ProgramAnnotation::ANN_CONNECTIVITY_MOVE, assert, ddg_, TTAProgram::AnnotatedInstructionElement::hasAnnotations(), MoveNode::isScheduled(), MoveNode::move(), and BoostGraph< GraphNode, GraphEdge >::successors().

Referenced by BUBasicBlockScheduler::bypassNode(), scheduleResultReads(), BUBasicBlockScheduler::scheduleResultReads(), scheduleResultReadTempMoves(), BUBasicBlockScheduler::scheduleResultReadTempMoves(), scheduleRRTempMoves(), and BUBasicBlockScheduler::scheduleRRTempMoves().

Here is the call graph for this function:

◆ tryToDelayOperands()

void BasicBlockScheduler::tryToDelayOperands ( MoveNodeGroup moves)
protected

Definition at line 2017 of file BasicBlockScheduler.cc.

2017 {
2018
2019 // try to then push non-triggers back
2020 // to as close as possible to tirggers.
2021 // this frees up the FU to be used fr other operations before
2022 // this operation.
2023 // first search first cycle when this FU is used.
2024
2025 int ec = INT_MAX;
2026 MoveNode* trigger = NULL;
2027 for (int i = 0; i < moves.nodeCount(); i++) {
2028 MoveNode& moveNode = moves.node(i);
2029 if (!moveNode.isDestinationOperation()) {
2030 continue;
2031 }
2032 if (moveNode.move().isTriggering()) {
2033 trigger = &moveNode;
2034 } else {
2035 int oldCycle = moveNode.cycle();
2036 if (oldCycle < ec) {
2037 ec = oldCycle;
2038 }
2039 }
2040 }
2041
2042 int triggerCycle = trigger->cycle();
2043
2044 bool failed = false;
2045 while (ec < triggerCycle && !failed) {
2046 for (int i = 0; i < moves.nodeCount(); i++) {
2047 MoveNode& moveNode = moves.node(i);
2048 if (!moveNode.isDestinationOperation()) {
2049 continue;
2050 }
2051 if (&moveNode != trigger) {
2052 int oldCycle = moveNode.cycle();
2053 if (oldCycle == ec) {
2054 int latest = ddg_->latestCycle(moveNode);
2055 if (latest > oldCycle) {
2056 latest = std::min(latest, triggerCycle);
2057 assert(latest >= ec);
2058 rm_->unassign(moveNode);
2059 int latestrm = rm_->latestCycle(latest, moveNode);
2060 if (latestrm == ec) {
2061 failed = true;
2062 }
2063 assert(latestrm >= ec);
2064 rm_->assign(latestrm, moveNode);
2065 } else {
2066 failed = true;
2067 }
2068 }
2069 }
2070 }
2071 ec = INT_MAX;
2072 // first earliest scheduled operands.
2073 for (int i = 0; i < moves.nodeCount(); i++) {
2074 MoveNode& moveNode = moves.node(i);
2075 if (!moveNode.isDestinationOperation()) {
2076 continue;
2077 }
2078 if (&moveNode != trigger) {
2079 int oldCycle = moveNode.cycle();
2080 if (oldCycle < ec) {
2081 ec = oldCycle;
2082 }
2083 }
2084 }
2085 }
2086}
virtual void unassign(MoveNode &node) override
virtual int latestCycle(MoveNode &node, const TTAMachine::Bus *bus=NULL, const TTAMachine::FunctionUnit *srcFU=NULL, const TTAMachine::FunctionUnit *dstFU=NULL, int immWriteCycle=-1, const TTAMachine::ImmediateUnit *immu=nullptr, int immRegIndex=-1) const override
bool isTriggering() const
Definition Move.cc:284

References assert, SimpleResourceManager::assign(), MoveNode::cycle(), ddg_, MoveNode::isDestinationOperation(), TTAProgram::Move::isTriggering(), DataDependenceGraph::latestCycle(), SimpleResourceManager::latestCycle(), MoveNode::move(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), rm_, and SimpleResourceManager::unassign().

Here is the call graph for this function:

◆ tryToOptimizeWaw()

bool BasicBlockScheduler::tryToOptimizeWaw ( const MoveNode moveNode)
protected

Tries to get rid of WaW dependence from unconditional to conditional.

if the conditional move's result is overwritten by the cond for all users, make the unconditional move conditional, with opposite guard.

Definition at line 1916 of file BasicBlockScheduler.cc.

1916 {
1917
1918 if (ddg_->earliestCycle(moveNode, 0 , false, true) >=
1919 ddg_->earliestCycle(moveNode)) {
1920 return false;
1921 }
1922
1923 MoveNode* wawPred = NULL;
1924 DataDependenceEdge* wawEdge = NULL;
1925
1926 DataDependenceGraph::EdgeSet inEdges = ddg_->inEdges(moveNode);
1927 for (DataDependenceGraph::EdgeSet::iterator i = inEdges.begin();
1928 i != inEdges.end(); i++) {
1929 DataDependenceEdge* e = *i;
1930
1933 !e->tailPseudo()) {
1934 if (wawPred == NULL) {
1935 wawPred = &ddg_->tailNode(**i);
1936 wawEdge = e;
1937 } else {
1938 return false;
1939 }
1940 }
1941 }
1942 if (wawPred == NULL) {
1943 return false;
1944 }
1945
1946 assert(wawPred->isScheduled());
1947 int wawPredCycle = wawPred->cycle();
1948
1949 if (!wawPred->move().isUnconditional()) {
1950 return false;
1951 }
1952
1953 DataDependenceGraph::NodeSet gdMoves = ddg_->guardDefMoves(moveNode);
1954 for (DataDependenceGraph::NodeSet::iterator i = gdMoves.begin();
1955 i != gdMoves.end(); i++) {
1956 MoveNode& mn = **i;
1957 assert(mn.isScheduled());
1958 if (mn.cycle() + moveNode.guardLatency() > wawPredCycle) {
1959 return false;
1960 }
1961 }
1962
1963 // check that no other usage of the data.
1964 DataDependenceGraph::NodeSet consumers = ddg_->regRawSuccessors(*wawPred);
1965 DataDependenceGraph::NodeSet consumers2 = ddg_->regRawSuccessors(moveNode);
1966 for (DataDependenceGraph::NodeSet::iterator i = consumers.begin();
1967 i != consumers.end(); i++) {
1968 MoveNode* mn = *i;
1969 if (consumers2.find(mn) == consumers2.end() &&
1970 (mn->move().isUnconditional() ||
1971 !ddg_->exclusingGuards(*mn, moveNode))) {
1972 return false;
1973 }
1974 }
1975
1976 unschedule(*wawPred);
1977
1979 wawPred->move().setGuard(cg.createInverseGuard(moveNode.move().guard()));
1980
1981 ddg_->copyDepsOver(*wawPred, true, false);
1982
1983 ddg_->copyIncomingGuardEdges(moveNode, *wawPred);
1984 ddg_->copyOutgoingGuardWarEdges(moveNode, *wawPred);
1985
1986 ddg_->removeEdge(*wawEdge);
1987
1988 bool revert = false;
1989
1990 try {
1991 scheduleMove(*wawPred, wawPredCycle, false);
1992
1993 if (!wawPred->isScheduled()) {
1994 revert = true;
1995 }
1996 if (wawPred->isScheduled() && wawPred->cycle() > wawPredCycle) {
1997 unschedule(*wawPred);
1998 revert = true;
1999 }
2000 } catch (Exception&e) {
2001 revert = true;
2002 }
2003
2004 if (revert) {
2005 wawPred->move().setGuard(NULL);
2006 ddg_->removeIncomingGuardEdges(*wawPred);
2008 scheduleMove(*wawPred, wawPredCycle, false);
2009 ddg_->connectNodes(*wawPred, moveNode, *wawEdge);
2010 return false;
2011 }
2012
2013 return true;
2014}
virtual void removeEdge(Edge &e)
virtual void connectNodes(const Node &nTail, const Node &nHead, Edge &e)
DependenceType dependenceType() const
EdgeReason edgeReason() const
NodeSet regRawSuccessors(const MoveNode &node) const
void copyOutgoingGuardWarEdges(const MoveNode &src, MoveNode &dst)
bool exclusingGuards(const MoveNode &mn1, const MoveNode &mn2) const
void copyIncomingGuardEdges(const MoveNode &src, MoveNode &dst)
void removeOutgoingGuardWarEdges(MoveNode &node)
NodeSet guardDefMoves(const MoveNode &moveNode)
EdgeSet copyDepsOver(MoveNode &node, bool anti, bool raw)
MoveGuard & guard() const
Definition Move.cc:345

References assert, BoostGraph< GraphNode, GraphEdge >::connectNodes(), DataDependenceGraph::copyDepsOver(), DataDependenceGraph::copyIncomingGuardEdges(), DataDependenceGraph::copyOutgoingGuardWarEdges(), TTAProgram::CodeGenerator::createInverseGuard(), MoveNode::cycle(), ddg_, DataDependenceEdge::DEP_WAW, DataDependenceEdge::dependenceType(), DataDependenceGraph::earliestCycle(), DataDependenceEdge::EDGE_REGISTER, DataDependenceEdge::edgeReason(), DataDependenceGraph::exclusingGuards(), TTAProgram::Move::guard(), DataDependenceGraph::guardDefMoves(), MoveNode::guardLatency(), BoostGraph< GraphNode, GraphEdge >::inEdges(), MoveNode::isScheduled(), TTAProgram::Move::isUnconditional(), MoveNode::move(), DataDependenceGraph::regRawSuccessors(), BoostGraph< GraphNode, GraphEdge >::removeEdge(), DataDependenceGraph::removeIncomingGuardEdges(), DataDependenceGraph::removeOutgoingGuardWarEdges(), scheduleMove(), TTAProgram::Move::setGuard(), BoostGraph< GraphNode, GraphEdge >::tailNode(), DataDependenceEdge::tailPseudo(), targetMachine_, and unschedule().

Referenced by scheduleMove().

Here is the call graph for this function:

◆ tryToSwitchInputs()

bool BasicBlockScheduler::tryToSwitchInputs ( ProgramOperation po)
protected

If the operation is commutative, tries to change the operands so that the scheduler can schedule it better.

If the operation is not commutative, does nothing.

Which is better depends lots on the code being compiled and architecture which we are compiling for.

Current implementation tries to make constants triggers, and if there are no constant inputs, try to also change inputs so that last ready operand becomes trigger if it's near, but first ready operand becomes trigger if it's further (allows better bypassing of other operands) This seems to work in practice

Parameters
poprogramoperation whose inputs to switch
Returns
true if changed inputs, false if not.

Definition at line 1730 of file BasicBlockScheduler.cc.

1730 {
1731 const Operation& op = po.operation();
1732 if (op.numberOfInputs() == 2 && op.canSwap(1, 2)) {
1733
1734 int triggerOperand = getTriggerOperand(op, *targetMachine_);
1735
1736 if (triggerOperand != 0) {
1737 MoveNode* latest = NULL;
1738 int latestMinCycle = -1;
1739 int firstMinCycle = INT_MAX;
1740
1741 //check all input moves.
1742 for (int i = 0; i < po.inputMoveCount(); i++) {
1743 MoveNode& node = po.inputMove(i);
1744 // always make constants triggers.
1745 // todo: shoudl do this only with short imms?
1746 if (node.isSourceConstant()) {
1747 int operandIndex =
1748 node.move().destination().operationIndex();
1749 if (operandIndex != triggerOperand) {
1750 po.switchInputs();
1751 return true;
1752 } else {
1753 return false;
1754 }
1755 }
1756
1757 int minCycle = ddg_->earliestCycle(
1758 node, rm_->initiationInterval(), false, false, true, true);
1759 if (minCycle > latestMinCycle) {
1760 latest = &node;
1761 latestMinCycle = minCycle;
1762 }
1763 if (minCycle < firstMinCycle) {
1764 firstMinCycle = minCycle;
1765 }
1766 }
1767
1768 int lastOperand = latest->move().destination().operationIndex();
1769
1770 // don't change if min cycles of first and alst are equal.
1771 if (latestMinCycle == firstMinCycle) {
1772 return false;
1773 }
1774 if (latestMinCycle - firstMinCycle > 1) { // reverse logic if far.
1775 if (lastOperand == triggerOperand) {
1776 po.switchInputs();
1777 return true;
1778 }
1779 } else {
1780 if (lastOperand != triggerOperand) {
1781 po.switchInputs();
1782 return true;
1783 }
1784 }
1785 }
1786 }
1787 return false;
1788}
int getTriggerOperand(const Operation &operation, const TTAMachine::Machine &machine)
virtual bool canSwap(int id1, int id2) const
Definition Operation.cc:470
int inputMoveCount() const
MoveNode & inputMove(int index) const
void switchInputs(int idx1=1, int idx2=2)
virtual int operationIndex() const
Definition Terminal.cc:364

References Operation::canSwap(), ddg_, TTAProgram::Move::destination(), DataDependenceGraph::earliestCycle(), getTriggerOperand(), SimpleResourceManager::initiationInterval(), ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), MoveNode::isSourceConstant(), MoveNode::move(), Operation::numberOfInputs(), ProgramOperation::operation(), TTAProgram::Terminal::operationIndex(), rm_, ProgramOperation::switchInputs(), and targetMachine_.

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ unschedule()

void BasicBlockScheduler::unschedule ( MoveNode moveNode)
protected

Unschedules the given move.

Also restores a possible short immediate source in case it was converted to a long immediate register read during scheduling.

Parameters
moveNodeMove to unschedule.

Definition at line 1484 of file BasicBlockScheduler.cc.

1484 {
1485 if (moveNode.isScheduled()) {
1486 rm_->unassign(moveNode);
1487 }
1488
1489 if (moveNode.move().hasAnnotations(
1491 // If we added annotation during scheduleMove delete it
1492 moveNode.move().removeAnnotations(
1494 }
1495 if (moveNode.isScheduled() || moveNode.isPlaced()) {
1496 throw InvalidData(
1497 __FILE__, __LINE__, __func__,
1498 (boost::format("Unscheduling of move '%s' failed!")
1499 % moveNode.toString()).str());
1500 }
1501}
bool isPlaced() const
Definition MoveNode.cc:352
void removeAnnotations(ProgramAnnotation::Id id=ProgramAnnotation::ANN_UNDEF_ID)

References __func__, TTAProgram::ProgramAnnotation::ANN_REQUIRES_LIMM, TTAProgram::AnnotatedInstructionElement::hasAnnotations(), MoveNode::isPlaced(), MoveNode::isScheduled(), MoveNode::move(), TTAProgram::AnnotatedInstructionElement::removeAnnotations(), rm_, MoveNode::toString(), and SimpleResourceManager::unassign().

Referenced by BUBasicBlockScheduler::bypassNode(), handleRemovedResultMoves(), scheduleMove(), scheduleOperandWrites(), BUBasicBlockScheduler::scheduleOperandWrites(), scheduleOperation(), BUBasicBlockScheduler::scheduleOperation(), BUBasicBlockScheduler::scheduleResultReads(), tryToOptimizeWaw(), BUBasicBlockScheduler::tryToOptimizeWaw(), BUBasicBlockScheduler::undoBypass(), unscheduleAllNodes(), BUBasicBlockScheduler::unscheduleAllNodes(), unscheduleInputOperandTempMoves(), and unscheduleResultReadTempMoves().

Here is the call graph for this function:

◆ unscheduleAllNodes()

void BasicBlockScheduler::unscheduleAllNodes ( )
protected

Calls unschedule() for all ddg nodes, which are scheduled.

Definition at line 1507 of file BasicBlockScheduler.cc.

1507 {
1509 for (DataDependenceGraph::NodeSet::iterator i = scheduled.begin();
1510 i != scheduled.end(); ++i) {
1511 if (softwareBypasser_ != NULL) {
1512 softwareBypasser_->removeBypass(**i, *ddg_, *rm_, false);
1513 }
1514 unschedule(**i);
1515 }
1516 if (softwareBypasser_ != NULL) {
1518 }
1519}

References SoftwareBypasser::clearCaches(), ddg_, SoftwareBypasser::removeBypass(), rm_, DataDependenceGraph::scheduledMoves(), softwareBypasser_, and unschedule().

Referenced by handleDDG(), handleLoopDDG(), scheduleMove(), scheduleOperandWrites(), and scheduleOperation().

Here is the call graph for this function:

◆ unscheduleInputOperandTempMoves()

void BasicBlockScheduler::unscheduleInputOperandTempMoves ( MoveNode operandMove)
protected

Unschedules the (possible) temporary register copy moves (due to missing connectivity) preceeding the given move.

Parameters
operandMoveThe move of which temp moves to unschedule.

Definition at line 1528 of file BasicBlockScheduler.cc.

1528 {
1529
1530 if (!MapTools::containsKey(scheduledTempMoves_, &operandMove))
1531 return; // nothing to unschedule
1532
1533 DataDependenceGraph::NodeSet tempMoves = scheduledTempMoves_[&operandMove];
1534
1535 for (DataDependenceGraph::NodeSet::iterator i = tempMoves.begin();
1536 i != tempMoves.end(); ++i) {
1537 unschedule(**i);
1538 }
1539 scheduledTempMoves_.erase(&operandMove);
1540}
static bool containsKey(const MapType &aMap, const KeyType &aKey)

References MapTools::containsKey(), scheduledTempMoves_, and unschedule().

Referenced by scheduleOperandWrites(), BUBasicBlockScheduler::scheduleOperandWrites(), scheduleOperation(), and BUBasicBlockScheduler::scheduleOperation().

Here is the call graph for this function:

◆ unscheduleResultReadTempMoves()

void BasicBlockScheduler::unscheduleResultReadTempMoves ( MoveNode resultMove)
protected

Unschedules the (possible) temporary register copy moves (due to missing connectivity) succeeding the given result read move.

Parameters
resultMoveThe move of which temp moves to unschedule.

Definition at line 1549 of file BasicBlockScheduler.cc.

1549 {
1550
1551 if (!MapTools::containsKey(scheduledTempMoves_, &resultMove))
1552 return; // nothing to unschedule
1553
1554 DataDependenceGraph::NodeSet tempMoves = scheduledTempMoves_[&resultMove];
1555
1556 for (DataDependenceGraph::NodeSet::iterator i = tempMoves.begin();
1557 i != tempMoves.end(); ++i) {
1558 unschedule(**i);
1559 }
1560 scheduledTempMoves_.erase(&resultMove);
1561}

References MapTools::containsKey(), scheduledTempMoves_, and unschedule().

Referenced by scheduleOperation(), and BUBasicBlockScheduler::scheduleOperation().

Here is the call graph for this function:

Member Data Documentation

◆ bypassedCount_

int BasicBlockScheduler::bypassedCount_
protected

Definition at line 165 of file BasicBlockScheduler.hh.

◆ ddg_

DataDependenceGraph* BasicBlockScheduler::ddg_
protected

◆ deadResults_

int BasicBlockScheduler::deadResults_
protected

Definition at line 166 of file BasicBlockScheduler.hh.

◆ jumpNode_

MoveNode* BasicBlockScheduler::jumpNode_
protected

Definition at line 170 of file BasicBlockScheduler.hh.

Referenced by handleLoopDDG(), and scheduleMove().

◆ minCycle_

int BasicBlockScheduler::minCycle_
protected

The earliest cycle to schedule moves in. Used to leave room for sched_yield() by the sched_yield() emitter.

Definition at line 162 of file BasicBlockScheduler.hh.

Referenced by handleDDG(), handleLoopDDG(), BUBasicBlockScheduler::handleLoopDDG(), and scheduleMove().

◆ options_

LLVMTCECmdLineOptions* BasicBlockScheduler::options_
protected

◆ renamer_

RegisterRenamer* BasicBlockScheduler::renamer_
protected

◆ rm_

SimpleResourceManager* BasicBlockScheduler::rm_
protected

◆ scheduledTempMoves_

std::map<const MoveNode*, DataDependenceGraph::NodeSet> BasicBlockScheduler::scheduledTempMoves_
protected

◆ selector_

MoveNodeSelector* BasicBlockScheduler::selector_
protected

◆ softwareBypasser_

SoftwareBypasser* BasicBlockScheduler::softwareBypasser_
protected

The software bypasser to use to bypass registers when possible.

Definition at line 156 of file BasicBlockScheduler.hh.

Referenced by handleDDG(), handleLoopDDG(), scheduleOperation(), and unscheduleAllNodes().

◆ targetMachine_

const TTAMachine::Machine* BasicBlockScheduler::targetMachine_
protected

◆ tripCount_

int BasicBlockScheduler::tripCount_
protected

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