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

#include <BUBasicBlockScheduler.hh>

Inheritance diagram for BUBasicBlockScheduler:
Inheritance graph
Collaboration diagram for BUBasicBlockScheduler:
Collaboration graph

Classes

struct  ltstr
 

Public Member Functions

 BUBasicBlockScheduler (InterPassData &data, SoftwareBypasser *bypasser=NULL, RegisterRenamer *registerRenamer=NULL)
 
virtual ~BUBasicBlockScheduler ()
 
virtual int handleDDG (DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine, int minCycle=0, bool testOnly=false)
 
virtual int handleLoopDDG (DataDependenceGraph &ddg, SimpleResourceManager &rm, const TTAMachine::Machine &targetMachine, int tripCount, SimpleResourceManager *prologRM=NULL, bool testOnly=false)
 
virtual std::string shortDescription () const
 
virtual std::string longDescription () const
 
virtual DataDependenceGraphBuilderddgBuilder ()
 
- Public Member Functions inherited from BasicBlockScheduler
 BasicBlockScheduler (InterPassData &data, SoftwareBypasser *bypasser=NULL, RegisterRenamer *renamer=NULL)
 
virtual ~BasicBlockScheduler ()
 
virtual void printStats () const
 
- 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)
 

Protected Types

typedef std::set< MoveNode *, ltstrOrderedSet
 

Protected Member Functions

void scheduleRRMove (MoveNode &moveNode)
 
void scheduleOperation (MoveNodeGroup &moves, BUMoveNodeSelector &selector)
 
bool scheduleOperandWrites (MoveNodeGroup &moves, int cycle)
 
int scheduleResultReads (MoveNodeGroup &moves, int cycle, bool bypass=false, bool bypassLate=false)
 
void scheduleMove (MoveNode &move, int cycle, bool allowPredicationandRenaming)
 
void scheduleResultReadTempMoves (MoveNode &resultMove, MoveNode &resultRead, int lastUse)
 
void scheduleInputOperandTempMoves (MoveNode &resultMove, MoveNode &resultRead)
 
void scheduleRRTempMoves (MoveNode &regToRegMove, MoveNode &firstMove, int lastUse)
 
bool scheduleOperand (MoveNode &, int cycle)
 
bool tryToSwitchInputs (ProgramOperation &op)
 
bool tryToOptimizeWaw (const MoveNode &moveNode)
 
MoveNodeprecedingTempMove (MoveNode &current)
 
OrderedSet findBypassDestinations (MoveNode &node)
 
void undoBypass (MoveNode &node, MoveNode *single=NULL, int originalCycle=-1)
 
bool bypassNode (MoveNode &node, int &maxResultCycle)
 
void finalizeSchedule (MoveNode &node, BUMoveNodeSelector &selector)
 
void unscheduleAllNodes ()
 
void clearRemovedNodes ()
 
- Protected Member Functions inherited from BasicBlockScheduler
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)
 

Protected Attributes

MoveNodejumpMove_
 
std::map< MoveNode *, std::vector< MoveNode * >, MoveNode::ComparatorbypassDestinations_
 
std::map< MoveNode *, std::vector< int >, MoveNode::ComparatorbypassDestinationsCycle_
 
std::map< MoveNode *, std::vector< const TTAMachine::Bus * >, MoveNode::ComparatorbypassDestinationsBus_
 
std::set< MoveNode * > droppedNodes_
 
unsigned int endCycle_
 
bool bypass_
 
bool dre_
 
int bypassDistance_
 
- Protected Attributes inherited from BasicBlockScheduler
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_
 

Additional Inherited Members

- Static Public Member Functions inherited from BasicBlockScheduler
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)
 
- Static Protected Member Functions inherited from BasicBlockScheduler
static MoveNodefindTriggerFromUnit (const ProgramOperation &po, const TTAMachine::Unit &unit)
 

Detailed Description

A class that implements the functionality of a bottom up 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 61 of file BUBasicBlockScheduler.hh.

Member Typedef Documentation

◆ OrderedSet

typedef std::set<MoveNode*, ltstr> BUBasicBlockScheduler::OrderedSet
protected

Definition at line 97 of file BUBasicBlockScheduler.hh.

Constructor & Destructor Documentation

◆ BUBasicBlockScheduler()

BUBasicBlockScheduler::BUBasicBlockScheduler ( 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
registerRenamerHelper module implementing register renaming

Definition at line 86 of file BUBasicBlockScheduler.cc.

References Application::cmdLineOptions(), jumpMove_, and BasicBlockScheduler::options_.

Here is the call graph for this function:

◆ ~BUBasicBlockScheduler()

BUBasicBlockScheduler::~BUBasicBlockScheduler ( )
virtual

Destructor.

Definition at line 101 of file BUBasicBlockScheduler.cc.

101 {
102}

Member Function Documentation

◆ bypassNode()

bool BUBasicBlockScheduler::bypassNode ( MoveNode moveNode,
int &  maxResultCycle 
)
protected

Tries to bypass node with all of it's successors.

Parameters
moveNode,nodewhich is tried to bypass
maxResultCycle,cycleof latest of rescheduled nodes
Returns
True if all of the successors were successfully bypassed

Definition at line 1601 of file BUBasicBlockScheduler.cc.

1603 {
1604 bool edgesCopied = false;
1605 unsigned int bypassCount = 0;
1606 int localMaximum = 0;
1607 if (!bypass_)
1608 return false;
1609 // First try to bypass all uses of the result
1610 unsigned int rawDestinations =
1611 ddg_->onlyRegisterRawDestinations(moveNode, false, false).size();
1612 OrderedSet destinations =
1613 findBypassDestinations(moveNode);
1614 if (destinations.size() > 0) {
1615 for (OrderedSet::iterator it = destinations.begin();
1616 it != destinations.end(); it++) {
1617 if (!ddg_->guardsAllowBypass(moveNode, **it)) {
1618 continue;
1619 }
1620 MoveNode* temp = succeedingTempMove(moveNode);
1621 if (!(*it)->isScheduled() && temp == (*it)) {
1622 // skip temp moves if unscheduled.
1623 // The temp moves of reading operand could be
1624 // scheduled and bypass will try to skip those
1625 // but temp moves of result are there for reason
1626 // so bypass would only revert to original
1627 // status which is unschedulable.
1628 std::cerr << "\t\tSkipping temporary outgoing move " <<
1629 (*it)->toString() << std::endl;
1630 continue;
1631 }
1632 assert((*it)->isScheduled());
1633 int originalCycle = (*it)->cycle();
1634 int latestLimit = originalCycle + bypassDistance_;
1635 int earliestLimit = originalCycle - bypassDistance_;
1636 if ((*it)->isDestinationVariable() && temp == (*it)) {
1637 // If bypassing to temporary register
1638 // missing edges in DDG could cause
1639 // overwrite of temporary value before it is
1640 // consumed.
1641 // Find previous and following reads from temp
1642 // register around location of original temp write.
1643 MoveNode* lastRead =
1645 (*it)->move().destination().registerFile(),
1646 (*it)->move().destination().index(),
1647 originalCycle);
1648 if (lastRead != NULL) {
1649 assert(lastRead->isScheduled());
1650 earliestLimit = lastRead->cycle();
1651 }
1652 MoveNode *firstRead =
1654 (*it)->move().destination().registerFile(),
1655 (*it)->move().destination().index(),
1656 originalCycle);
1657 if (firstRead != NULL) {
1658 assert(firstRead->isScheduled());
1659 latestLimit = firstRead->cycle();
1660 }
1661 }
1662
1663#ifdef DEBUG_BYPASS
1664 ddg_->writeToDotFile("beforeUnschedule.dot");
1665#endif
1666 const TTAMachine::Bus* bus = &(*it)->move().bus();
1667 bypassDestinationsBus_[&moveNode].push_back(
1668 dynamic_cast<const TTAMachine::Bus*>(bus));
1669 unschedule(**it);
1670 if (!ddg_->mergeAndKeepUser(moveNode, **it)) {
1671 assert(!(*it)->isScheduled());
1672 scheduleMove(**it, originalCycle, true);
1673#ifdef DEBUG_BYPASS
1674 std::cerr << "Merge fail. moveNode=" << moveNode.toString()
1675 << ", **it=" << (*it)->toString() << std::endl;
1676#endif
1677 bypassDestinationsBus_[&moveNode].pop_back();
1678 continue;
1679 }
1680
1681 if ((**it).move().source().isImmediateRegister()) {
1682 (**it).move().setSource(
1683 static_cast<SimpleResourceManager*>(rm_)->immediateValue(moveNode)->copy());
1684 }
1685
1686 bypassDestinations_[&moveNode].push_back(*it);
1687 bypassDestinationsCycle_[&moveNode].push_back(
1688 originalCycle);
1689 assert((*it)->isScheduled() == false);
1690 int startCycle = std::min(latestLimit, maxResultCycle);
1691 scheduleMove(**it, startCycle, true);
1692
1693#ifdef DEBUG_BYPASS
1694 std::cerr << "\t\t\tCreated " << (*it)->toString()
1695 << " with original cycle " << originalCycle << std::endl;
1696#endif
1697 if (!(*it)->isScheduled() ||
1698 (*it)->cycle() > latestLimit ||
1699 (*it)->cycle() < earliestLimit ||
1700 (*it)->cycle() < originalCycle) {
1701 // Scheduling bypass failed, undo and try to
1702 // schedule other possible bypasses.
1703 undoBypass(moveNode, *it, originalCycle);
1704 bypassDestinations_[&moveNode].pop_back();
1705 bypassDestinationsCycle_[&moveNode].pop_back();
1706 bypassDestinationsBus_[&moveNode].pop_back();
1707 } else {
1708 localMaximum =
1709 ((*it)->cycle() > localMaximum) ?
1710 (*it)->cycle() : localMaximum;
1711 if (!edgesCopied) {
1712 // In case operands reads same register that
1713 // result writes, removing result move after
1714 // successfull bypass could lead to operand
1715 // scheduled after the register it reads is
1716 // overwriten. This should prevent such situation.
1717 ddg_->copyDepsOver(moveNode, true, true);
1718 edgesCopied = true;
1719 }
1720 bypassCount++;
1721 }
1722 }
1723 } else {
1724 DataDependenceGraph::NodeSet rrDestinations =
1725 ddg_->onlyRegisterRawDestinations(moveNode, false, false);
1726 if (rrDestinations.size() == 0 &&
1727 moveNode.isDestinationVariable() &&
1728 moveNode.isSourceVariable() &&
1729 !ddg_->resultUsed(moveNode)) {
1730 // move is not used at all anywhere? Lets try to drop it
1731 return true;
1732 }
1733 }
1734 if (bypassCount == rawDestinations && bypassCount != 0) {
1735 maxResultCycle = localMaximum;
1736 return true;
1737 } else {
1738 return false;
1739 }
1740}
#define assert(condition)
std::map< MoveNode *, std::vector< int >, MoveNode::Comparator > bypassDestinationsCycle_
void undoBypass(MoveNode &node, MoveNode *single=NULL, int originalCycle=-1)
void scheduleMove(MoveNode &move, int cycle, bool allowPredicationandRenaming)
std::set< MoveNode *, ltstr > OrderedSet
OrderedSet findBypassDestinations(MoveNode &node)
std::map< MoveNode *, std::vector< const TTAMachine::Bus * >, MoveNode::Comparator > bypassDestinationsBus_
std::map< MoveNode *, std::vector< MoveNode * >, MoveNode::Comparator > bypassDestinations_
SimpleResourceManager * rm_
Resource Manager of the currently scheduled BB.
DataDependenceGraph * ddg_
DDG of the currently scheduled BB.
void unschedule(MoveNode &moveNode)
MoveNode * succeedingTempMove(MoveNode &current)
bool mergeAndKeepUser(MoveNode &resultNode, MoveNode &userNode, bool force=false)
NodeSet onlyRegisterRawDestinations(const MoveNode &mn, bool allowGuardEdges=false, bool allowBackEdges=false) const
MoveNode * lastScheduledRegisterRead(const TTAMachine::BaseRegisterFile &rf, int registerIndex, int lastCycleToTest=INT_MAX) const
bool resultUsed(MoveNode &resultNode)
EdgeSet copyDepsOver(MoveNode &node, bool anti, bool raw)
MoveNode * firstScheduledRegisterRead(const TTAMachine::BaseRegisterFile &rf, int registerIndex, int firstCycleToTest=0) const
bool guardsAllowBypass(const MoveNode &defNode, const MoveNode &useNode, bool loopBypass=false)
virtual void writeToDotFile(const TCEString &fileName) const
std::set< GraphNode *, typename GraphNode::Comparator > NodeSet
Definition Graph.hh:53
int cycle() const
Definition MoveNode.cc:421
bool isSourceVariable() const
Definition MoveNode.cc:196
std::string toString() const
Definition MoveNode.cc:576
bool isScheduled() const
Definition MoveNode.cc:409
bool isDestinationVariable() const
Definition MoveNode.cc:264

References assert, bypass_, bypassDestinations_, bypassDestinationsBus_, bypassDestinationsCycle_, bypassDistance_, DataDependenceGraph::copyDepsOver(), MoveNode::cycle(), BasicBlockScheduler::ddg_, findBypassDestinations(), DataDependenceGraph::firstScheduledRegisterRead(), DataDependenceGraph::guardsAllowBypass(), MoveNode::isDestinationVariable(), MoveNode::isScheduled(), MoveNode::isSourceVariable(), DataDependenceGraph::lastScheduledRegisterRead(), DataDependenceGraph::mergeAndKeepUser(), DataDependenceGraph::onlyRegisterRawDestinations(), DataDependenceGraph::resultUsed(), BasicBlockScheduler::rm_, scheduleMove(), BasicBlockScheduler::succeedingTempMove(), MoveNode::toString(), undoBypass(), BasicBlockScheduler::unschedule(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

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

Here is the call graph for this function:

◆ clearRemovedNodes()

void BUBasicBlockScheduler::clearRemovedNodes ( )
protected

Finaly, remove moves that were dropped during dead result move elimination also from the parent of the given subgraph DDG.

Definition at line 1873 of file BUBasicBlockScheduler.cc.

1873 {
1874
1875 for (std::set<MoveNode*>::iterator i = droppedNodes_.begin();
1876 i != droppedNodes_.end(); i++) {
1877 MoveNode& node = **i;
1878 if (ddg_->rootGraph() != ddg_ && !node.isScheduled()) {
1879 ddg_->rootGraph()->removeNode(node);
1881 bypassDestinations_.erase(&node);
1882 bypassDestinationsCycle_.erase(&node);
1883 bypassDestinationsBus_.erase(&node);
1884 }
1885 }
1886 }
1887 droppedNodes_.clear();
1888}
std::set< MoveNode * > droppedNodes_
BoostGraph * rootGraph()
virtual void removeNode(Node &node)
static bool containsKey(const MapType &aMap, const KeyType &aKey)

References bypassDestinations_, bypassDestinationsBus_, bypassDestinationsCycle_, MapTools::containsKey(), BasicBlockScheduler::ddg_, droppedNodes_, MoveNode::isScheduled(), BoostGraph< GraphNode, GraphEdge >::removeNode(), and BoostGraph< GraphNode, GraphEdge >::rootGraph().

Referenced by handleDDG(), and handleLoopDDG().

Here is the call graph for this function:

◆ ddgBuilder()

virtual DataDependenceGraphBuilder & BasicBlockPass::ddgBuilder ( )
inlinevirtual

Reimplemented from BasicBlockScheduler.

Definition at line 86 of file BasicBlockPass.hh.

86{ return ddgBuilder_; }
DataDependenceGraphBuilder ddgBuilder_

◆ finalizeSchedule()

void BUBasicBlockScheduler::finalizeSchedule ( MoveNode node,
BUMoveNodeSelector selector 
)
protected

Definition at line 1743 of file BUBasicBlockScheduler.cc.

1744 {
1745 if (node.isScheduled()) {
1746 selector.notifyScheduled(node);
1747 std::map<const MoveNode*, DataDependenceGraph::NodeSet >::
1748 iterator tmIter = scheduledTempMoves_.find(&node);
1749 if (tmIter != scheduledTempMoves_.end()) {
1750 DataDependenceGraph::NodeSet& tempMoves = tmIter->second;
1751 for (DataDependenceGraph::NodeSet::iterator i =
1752 tempMoves.begin(); i != tempMoves.end(); i++) {
1753 selector.notifyScheduled(**i);
1754 }
1755 }
1756 } else if (MapTools::containsKey(bypassDestinations_, &node) && dre_) {
1757
1758#ifdef DEBUG_BYPASS
1759 std::cerr << "\tDroping node " << node.toString() << std::endl;
1760 ddg_->writeToDotFile("before_copyDeps.dot");
1761#endif
1762 static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
1763 copyDepsOver(node, true, true);
1765 ddg_->dropNode(node);
1766 droppedNodes_.insert(&node);
1767#ifdef DEBUG_BYPASS
1768 ddg_->writeToDotFile("after_dropNode.dot");
1769#endif
1770
1771 for (DataDependenceGraph::NodeSet::iterator i =
1772 preds.begin(); i != preds.end(); i++) {
1773 selector.mightBeReady(**i);
1774 }
1775 std::map<const MoveNode*, DataDependenceGraph::NodeSet >::
1776 iterator tmIter = scheduledTempMoves_.find(&node);
1777 if (tmIter != scheduledTempMoves_.end()) {
1778 DataDependenceGraph::NodeSet& tempMoves = tmIter->second;
1779 for (DataDependenceGraph::NodeSet::iterator i =
1780 tempMoves.begin(); i != tempMoves.end(); i++) {
1781 if ((*i)->isScheduled()) {
1782 selector.notifyScheduled(**i);
1783 } else {
1784#ifdef DEBUG_BYPASS
1785 std::cerr << "\tDroping temp move for node "
1786 << node.toString() << ", " << (*i)->toString()
1787 << std::endl;
1788 ddg_->writeToDotFile("before_temp_copyDeps.dot");
1789#endif
1790 static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
1791 copyDepsOver(**i, true, true);
1792 ddg_->dropNode(**i);
1793 droppedNodes_.insert(*i);
1794#ifdef DEBUG_BYPASS
1795 ddg_->writeToDotFile("after_temp_dropNode.dot");
1796#endif
1797 }
1798 }
1799 }
1800 } else if (node.move().source().equals(node.move().destination()) ||
1801 (node.isSourceVariable()
1802 && node.isDestinationVariable()
1803 && !ddg_->resultUsed(node))) {
1804
1805 // we lost edges so our notifyScheduled does not notify
1806 // some antidependencies. store them for notification.
1807
1808 DataDependenceGraph::NodeSet predecessors =
1809 ddg_->predecessors(node);
1810 predecessors.erase(&node); // if WaW to itself, rremove it.
1811
1812 assert(node.isScheduled() == false);
1813
1814 // this may lead to extra raw edges.
1815 static_cast<DataDependenceGraph*>(ddg_->rootGraph())->
1816 copyDepsOver(node, true, true);
1817
1818 ddg_->dropNode(node);
1819 droppedNodes_.insert(&node);
1820 // we lost edges so our notifyScheduled does not notify
1821 // some antidependencies. notify them.
1822 for (DataDependenceGraph::NodeSet::iterator iter =
1823 predecessors.begin();
1824 iter != predecessors.end(); iter++) {
1825 selector.mightBeReady(**iter);
1826 }
1827
1828 } else {
1829 TCEString msg = "Node " + node.toString() + " did not get scheduled";
1830 ddg_->writeToDotFile("after_dropNode.dot");
1831 throw InvalidData(
1832 __FILE__, __LINE__, __func__, msg);
1833 }
1834}
#define __func__
virtual void notifyScheduled(MoveNode &node)
virtual void mightBeReady(MoveNode &node)
std::map< const MoveNode *, DataDependenceGraph::NodeSet > scheduledTempMoves_
Stores the MoveNodes that were scheduled as temp moves during scheduling of the operand move.
virtual void dropNode(Node &node)
virtual NodeSet predecessors(const Node &node, bool ignoreBackEdges=false, bool ignoreForwardEdges=false) const
TTAProgram::Move & move()
Terminal & source() const
Definition Move.cc:302
Terminal & destination() const
Definition Move.cc:323
virtual bool equals(const Terminal &other) const =0

References __func__, assert, bypassDestinations_, MapTools::containsKey(), BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), dre_, BoostGraph< GraphNode, GraphEdge >::dropNode(), droppedNodes_, TTAProgram::Terminal::equals(), MoveNode::isDestinationVariable(), MoveNode::isScheduled(), MoveNode::isSourceVariable(), BUMoveNodeSelector::mightBeReady(), MoveNode::move(), BUMoveNodeSelector::notifyScheduled(), BoostGraph< GraphNode, GraphEdge >::predecessors(), DataDependenceGraph::resultUsed(), BoostGraph< GraphNode, GraphEdge >::rootGraph(), BasicBlockScheduler::scheduledTempMoves_, TTAProgram::Move::source(), MoveNode::toString(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by handleDDG(), handleLoopDDG(), scheduleOperation(), scheduleResultReadTempMoves(), and scheduleRRTempMoves().

Here is the call graph for this function:

◆ findBypassDestinations()

BUBasicBlockScheduler::OrderedSet BUBasicBlockScheduler::findBypassDestinations ( MoveNode node)
protected

Finds a destination where to bypass.

Goes through ddg and checks for connectivity.

Returns
pair of destination of bypass and amount of regs skipped by the bypass.

Definition at line 1487 of file BUBasicBlockScheduler.cc.

1487 {
1488
1489 OrderedSet okDestination;
1490 // DDG can only handle single hops so far.
1491 // TODO: Fix when DDG could handle multiple destinations
1492 DataDependenceGraph::NodeSet rrDestinations =
1493 ddg_->onlyRegisterRawDestinations(node, false, false);
1494 for (DataDependenceGraph::NodeSet::iterator j =
1495 rrDestinations.begin(); j != rrDestinations.end(); j++) {
1496 MoveNode* n = *j;
1497 if (ddg_->onlyRegisterRawSource(*n) == NULL) {
1498 // No bypassing of moves with multiple register definition
1499 // sources.
1500 // TODO: bypass destination with multiple definition sources
1501 // using inverse guard of guarded source.
1502 continue;
1503 }
1504 MachineConnectivityCheck::PortSet destinationPorts;
1505 destinationPorts.insert(&n->move().destination().port());
1506
1508 node, destinationPorts)) {
1509 if (n->isScheduled() == false
1510 && rm_->initiationInterval() != 0) {
1511 // Found node connected by loop edge, ignore it.
1512 ddg_->writeToDotFile("failing_test.dot");
1513 continue;
1514 }
1515 okDestination.insert(n);
1516 }
1517 destinationPorts.clear();
1518 }
1519 return okDestination;
1520}
MoveNode * onlyRegisterRawSource(const MoveNode &mn, int allowGuardEdges=2, int backEdges=0) const
static int canSourceWriteToAnyDestinationPort(const MoveNode &src, PortSet &ports, bool ignoreGuard=false)
std::set< const TTAMachine::Port *, const TTAMachine::MachinePart::Comparator > PortSet
virtual unsigned initiationInterval() const
virtual const TTAMachine::Port & port() const
Definition Terminal.cc:378

References MachineConnectivityCheck::canSourceWriteToAnyDestinationPort(), BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), SimpleResourceManager::initiationInterval(), MoveNode::isScheduled(), MoveNode::move(), DataDependenceGraph::onlyRegisterRawDestinations(), DataDependenceGraph::onlyRegisterRawSource(), TTAProgram::Terminal::port(), BasicBlockScheduler::rm_, and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by bypassNode().

Here is the call graph for this function:

◆ handleDDG()

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

Schedules a piece of code in a DDG

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

Reimplemented from BasicBlockScheduler.

Definition at line 113 of file BUBasicBlockScheduler.cc.

115 {
116 ddg_ = &ddg;
117 targetMachine_ = &targetMachine;
118
119 if (renamer_ != NULL) {
120 renamer_->initialize(ddg);
121 }
122
123 if (options_ != NULL && options_->dumpDDGsDot()) {
125 ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false);
126 }
127
128 if (options_ != NULL && options_->dumpDDGsXML()) {
130 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false);
131 }
132
133 if (options_ != NULL && options_->bypassDistance() > -1) {
135 }
136
137 if (options_ != NULL && options_->bypassDistance() == 0) {
138 bypass_ = false;
139 }
140
141 if (options_ != NULL && !options_->killDeadResults()) {
142 dre_ = false;
143 }
144
145 // empty need not to be scheduled
146 if (ddg.nodeCount() == 0 ||
147 (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
148 return 0;
149 }
150
151 // INT_MAX/2 won't work on trunk due to multithreading injecting empty
152 // instructions into the beginning of basic block.
153 endCycle_ = INT_MAX/1000;
154
155 // scheduling pipeline resources after last cycle may cause problems.
156 // make RM to check for those
158
159 BUMoveNodeSelector selector(ddg, targetMachine);
160 selector_ = &selector;
161 // register selector to renamer for notfications.
162 if (renamer_ != NULL) {
163 renamer_->setSelector(&selector);
164 }
165
166 rm_ = &rm;
167
168 MoveNodeGroup moves = selector.candidates();
169 while (moves.nodeCount() > 0) {
170 bool movesRemoved = false;
171 MoveNode& firstMove = moves.node(0);
172 if (firstMove.isOperationMove()) {
173 scheduleOperation(moves, selector);
174 movesRemoved = true;
175 } else {
176 if (firstMove.move().destination().isRA()) {
177 scheduleMove(firstMove, endCycle_, true);
178 finalizeSchedule(firstMove, selector);
179 } else {
180 int tmp = endCycle_;
181 if (bypassNode(firstMove,tmp) && dre_
182 &&!ddg_->resultUsed(firstMove)) {
183 // No need to schedule original move any more
184 movesRemoved = true;
185 } else {
186 // schedule original move
187 scheduleRRMove(firstMove);
188 // If move was register copy to self, it could have been
189 // just dropped.
190 movesRemoved = true;
191 if (!firstMove.isScheduled()) {
192 undoBypass(firstMove);
193 scheduleRRMove(firstMove);
194 }
195 }
196 if (bypass_) {
197 bypassNode(firstMove, tmp);
198 }
199 finalizeSchedule(firstMove, selector);
200 }
201 }
202 if (!movesRemoved) {
203 if (!moves.isScheduled()) {
204 std::string message = " Move(s) did not get scheduled: ";
205 for (int i = 0; i < moves.nodeCount(); i++) {
206 message += moves.node(i).toString() + " ";
207 }
208 ddg.writeToDotFile("failed_bb.dot");
209 throw ModuleRunTimeError(__FILE__,__LINE__,__func__, message);
210 }
211 }
212 moves = selector.candidates();
213 if (!test)
215 }
216
217 if (ddg.nodeCount() != ddg.scheduledNodeCount()) {
218 debugLog("All moves in the DDG didn't get scheduled.");
219 ddg.writeToDotFile("failed_bb.dot");
220 abortWithError("Should not happen!");
221 }
222
223 if (options_ != NULL && options_->dumpDDGsDot()) {
224 std::string wtf = "0";
226 ddg, wtf, DataDependenceGraph::DUMP_DOT, true);
227 }
228
229 if (options_ != NULL && options_->dumpDDGsXML()) {
231 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
232 }
233 if (rm_->largestCycle() > (int)endCycle_) {
234 ddg.writeToDotFile("largest_bigger_than_endcycle.dot");
235 std::cerr << "rm largest cycle bigger than endCycle_!" <<
236 std::endl << "This may break delay slot filler!" <<
237 std::endl << " rm largest: " << rm_->largestCycle() <<
238 " end cycle: " << endCycle_ << std::endl;
239
240 abortWithError("Should not happen!");
241 }
242 int size = rm_->largestCycle() - rm_->smallestCycle();
243 if (test) {
245 }
246 return size;
247}
#define debugLog(text)
#define abortWithError(message)
void scheduleRRMove(MoveNode &moveNode)
void scheduleOperation(MoveNodeGroup &moves, BUMoveNodeSelector &selector)
bool bypassNode(MoveNode &node, int &maxResultCycle)
void finalizeSchedule(MoveNode &node, BUMoveNodeSelector &selector)
MoveNodeSelector * selector_
const TTAMachine::Machine * targetMachine_
The target machine we are scheduling the program against.
RegisterRenamer * renamer_
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
void setSelector(MoveNodeSelector *selector)
void initialize(DataDependenceGraph &ddg)
virtual bool killDeadResults() const
virtual int smallestCycle() const override
void setMaxCycle(unsigned int maxCycle)
virtual int largestCycle() const override
virtual bool isRA() const
Definition Terminal.cc:129

References __func__, abortWithError, bypass_, SchedulerCmdLineOptions::bypassDistance(), bypassDistance_, bypassNode(), BUMoveNodeSelector::candidates(), clearRemovedNodes(), BasicBlockScheduler::ddg_, BasicBlockScheduler::ddgSnapshot(), debugLog, TTAProgram::Move::destination(), dre_, DataDependenceGraph::DUMP_DOT, DataDependenceGraph::DUMP_XML, LLVMTCECmdLineOptions::dumpDDGsDot(), LLVMTCECmdLineOptions::dumpDDGsXML(), endCycle_, finalizeSchedule(), RegisterRenamer::initialize(), MoveNode::isMove(), MoveNode::isOperationMove(), TTAProgram::Terminal::isRA(), MoveNodeGroup::isScheduled(), MoveNode::isScheduled(), SchedulerCmdLineOptions::killDeadResults(), SimpleResourceManager::largestCycle(), MoveNode::move(), BoostGraph< GraphNode, GraphEdge >::node(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), BoostGraph< GraphNode, GraphEdge >::nodeCount(), BasicBlockScheduler::options_, BasicBlockScheduler::renamer_, DataDependenceGraph::resultUsed(), BasicBlockScheduler::rm_, DataDependenceGraph::scheduledNodeCount(), scheduleMove(), scheduleOperation(), scheduleRRMove(), BasicBlockScheduler::selector_, SimpleResourceManager::setMaxCycle(), RegisterRenamer::setSelector(), SimpleResourceManager::smallestCycle(), BasicBlockScheduler::targetMachine_, MoveNode::toString(), undoBypass(), unscheduleAllNodes(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Here is the call graph for this function:

◆ handleLoopDDG()

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

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 BasicBlockScheduler.

Definition at line 260 of file BUBasicBlockScheduler.cc.

263 {
264 tripCount_ = tripCount;
265 ddg_ = &ddg;
266 targetMachine_ = &targetMachine;
267 minCycle_ = 0;
268
269 if (renamer_ != NULL) {
270 renamer_->initialize(ddg);
271 }
272
273 if (options_ != NULL && options_->dumpDDGsDot()) {
275 ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, false, true);
276 }
277
278 if (options_ != NULL && options_->dumpDDGsXML()) {
280 ddg, std::string("0"), DataDependenceGraph::DUMP_XML, false, true);
281 }
282
283 if (options_ != NULL && options_->bypassDistance() > -1) {
285 }
286
287 if (options_ != NULL && options_->bypassDistance() == 0) {
288 bypass_ = false;
289 }
290
291 if (options_ != NULL && !options_->killDeadResults()) {
292 dre_ = false;
293 }
294
295 scheduledTempMoves_.clear();
296
297 // empty DDGs can be ignored
298 if (ddg.nodeCount() == 0 ||
299 (ddg.nodeCount() == 1 && !ddg.node(0).isMove())) {
300 return 0;
301 }
302 endCycle_ = 2 * rm.initiationInterval() - 1;
303 BUMoveNodeSelector selector(ddg, targetMachine);
304
305 rm_ = &rm;
306
307 if (renamer_ != NULL) {
308 renamer_->setSelector(&selector);
309 }
310 MoveNodeGroup moves = selector.candidates();
311 while (moves.nodeCount() > 0) {
312 bool movesRemoved = false;
313 MoveNode& firstMove = moves.node(0);
314 if (firstMove.isOperationMove()) {
315 scheduleOperation(moves, selector);
316 movesRemoved = true;
317 } else {
318 if (firstMove.move().destination().isRA()) {
319 scheduleMove(firstMove, endCycle_, true);
320 notifyScheduled(moves, selector);
321 } else {
322 int tmp = endCycle_;
323 if (bypassNode(firstMove,tmp) && dre_
324 &&!ddg_->resultUsed(firstMove)) {
325 // No need to schedule original move any more
326 movesRemoved = true;
327 } else {
328 // schedule original move
329 scheduleRRMove(firstMove);
330 // If move was register copy to self, it could have been
331 // just dropped.
332 movesRemoved = true;
333 }
334 if (bypass_) {
335 bypassNode(firstMove, tmp);
336 }
337 finalizeSchedule(firstMove, selector);
338 }
339 }
340
341 if (!movesRemoved && !moves.isScheduled()) {
343 std::string("ii_") +
345 std::string("_dag.dot"));
346
348 return -1;
349 }
350
351 moves = selector.candidates();
352 }
353
354 if (ddg.nodeCount() !=
355 ddg.scheduledNodeCount()) {
356 debugLog("All moves in the DDG didn't get scheduled.");
357// debugLog("Disassembly of the situation:");
358// Application::logStream() << bb.disassemble() << std::endl;
359 ddg.writeToDotFile("failed_bb.dot");
360 abortWithError("Should not happen!");
361 }
362
363 // loop scheduling did not help
364 if (static_cast<unsigned>(ddg.largestCycle() - ddg.smallestCycle()) < rm.initiationInterval()
365 || testOnly) {
366 if (static_cast<unsigned>(ddg.largestCycle() - ddg.smallestCycle()) <
367 rm.initiationInterval()) {
369 << "No overlapping instructions."
370 << "Should Revert to ordinary scheduler."
371 << " ii = " << rm.initiationInterval()
372 << " size = " << ddg.largestCycle() - ddg.smallestCycle()
373 << std::endl;
374 }
375 // this have to be calculated before unscheduling.
376 int rv = (ddg.largestCycle() - ddg.smallestCycle()) / rm.initiationInterval();
378 return rv;
379 }
380
381 // test that ext-cond jump not in prolog (where it is skipped)
382 int overlap_count = (ddg.largestCycle() - ddg.smallestCycle()) / rm.initiationInterval();
383 if (overlap_count >= tripCount) {
385 return -1;
386 }
387
388 if (options_ != NULL && options_->dumpDDGsDot()) {
389 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_DOT, true);
390 }
391
392 if (options_ != NULL && options_->dumpDDGsXML()) {
393 ddgSnapshot(ddg, std::string("0"), DataDependenceGraph::DUMP_XML, true);
394 }
395
396 if (jumpMove_ != NULL) {
397 MoveNode* jumpLimit = ddg_->findLoopLimitAndIndex(*jumpMove_).first;
398 if (jumpLimit != NULL) {
399 int jumpOverlapCount = (endCycle_ - rm.smallestCycle())
400 / rm.initiationInterval();
401 TTAProgram::TerminalImmediate& ti = dynamic_cast<
402 TTAProgram::TerminalImmediate&>(jumpLimit->move().source());
403 int jumpLimitValue = ti.value().unsignedValue();
404 int loopCounterStep = 1;
405 if (jumpLimitValue != tripCount_) {
406 if (jumpLimitValue == 2 * tripCount_) {
407 loopCounterStep = 2;
408 } else {
409 if (jumpLimitValue == 4 * tripCount_) {
410 loopCounterStep = 4;
411 } else {
412 // don't know how much to decr. counter.
414 return -1;
415 }
416 }
417 }
418 if (tripCount_ > jumpOverlapCount) {
419 jumpLimit->move().setSource(
421 SimValue(
422 jumpLimitValue -
423 (jumpOverlapCount * loopCounterStep),
424 ti.value().width())));
425 } else {
426 // loop limit is too short.
427 // would be always executed too many times.
428 jumpLimit->move().setSource(
429 new TTAProgram::TerminalImmediate(SimValue(jumpLimitValue)));
431 return -1;
432 }
433
434 }
435 }
437 return (ddg.largestCycle() - ddg.smallestCycle()) / rm.initiationInterval();
438}
static std::ostream & logStream()
int minCycle_
The earliest cycle to schedule moves in. Used to leave room for sched_yield() by the sched_yield() em...
void notifyScheduled(MoveNodeGroup &moves, MoveNodeSelector &selector)
static std::string toString(const T &source)
std::pair< MoveNode *, MoveNode * > findLoopLimitAndIndex(MoveNode &jumpMove)
unsigned int unsignedValue() const
Definition SimValue.cc:919
int width() const
Definition SimValue.cc:103
virtual SimValue value() const

References abortWithError, bypass_, SchedulerCmdLineOptions::bypassDistance(), bypassDistance_, bypassNode(), BUMoveNodeSelector::candidates(), clearRemovedNodes(), BasicBlockScheduler::ddg_, BasicBlockScheduler::ddgSnapshot(), debugLog, TTAProgram::Move::destination(), dre_, DataDependenceGraph::DUMP_DOT, DataDependenceGraph::DUMP_XML, LLVMTCECmdLineOptions::dumpDDGsDot(), LLVMTCECmdLineOptions::dumpDDGsXML(), endCycle_, finalizeSchedule(), DataDependenceGraph::findLoopLimitAndIndex(), RegisterRenamer::initialize(), SimpleResourceManager::initiationInterval(), MoveNode::isMove(), MoveNode::isOperationMove(), TTAProgram::Terminal::isRA(), MoveNodeGroup::isScheduled(), jumpMove_, SchedulerCmdLineOptions::killDeadResults(), DataDependenceGraph::largestCycle(), Application::logStream(), BasicBlockScheduler::minCycle_, MoveNode::move(), BoostGraph< GraphNode, GraphEdge >::node(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), BoostGraph< GraphNode, GraphEdge >::nodeCount(), BasicBlockScheduler::notifyScheduled(), BasicBlockScheduler::options_, BasicBlockScheduler::renamer_, DataDependenceGraph::resultUsed(), BasicBlockScheduler::rm_, DataDependenceGraph::scheduledNodeCount(), BasicBlockScheduler::scheduledTempMoves_, scheduleMove(), scheduleOperation(), scheduleRRMove(), RegisterRenamer::setSelector(), TTAProgram::Move::setSource(), DataDependenceGraph::smallestCycle(), SimpleResourceManager::smallestCycle(), TTAProgram::Move::source(), BasicBlockScheduler::targetMachine_, Conversion::toString(), BasicBlockScheduler::tripCount_, unscheduleAllNodes(), SimValue::unsignedValue(), TTAProgram::TerminalImmediate::value(), SimValue::width(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Here is the call graph for this function:

◆ longDescription()

std::string BUBasicBlockScheduler::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 BasicBlockScheduler.

Definition at line 1209 of file BUBasicBlockScheduler.cc.

1209 {
1210 return
1211 "Bottom-up list basic block scheduler that uses the longest path "
1212 "information of data dependency graph to prioritize the ready list."
1213 "Assumes that the input has registers allocated and no connectivity "
1214 "missing.";
1215}

◆ precedingTempMove()

MoveNode * BUBasicBlockScheduler::precedingTempMove ( MoveNode current)
protected

Finds the temp move preceding the given movenode.

If it does not have one, returns null.

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

Definition at line 1424 of file BUBasicBlockScheduler.cc.

1424 {
1425
1427 MoveNode* result = NULL;
1428 for (DataDependenceGraph::NodeSet::iterator i = pred.begin();
1429 i != pred.end(); ++i) {
1430 MoveNode& m = **i;
1431 if (m.isScheduled() ||
1432 !m.move().hasAnnotations(
1434 continue;
1435
1436 assert(result == NULL &&
1437 "Multiple candidates for the temp move of result read.");
1438 result = &m;
1439 }
1440 return result;
1441}
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...

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

Referenced by scheduleOperand().

Here is the call graph for this function:

◆ scheduleInputOperandTempMoves()

void BUBasicBlockScheduler::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 1289 of file BUBasicBlockScheduler.cc.

1290 {
1291 /* Because temporary register moves do not have WaR dependency edges
1292 between the other possible uses of the same temp register in
1293 the same operation, we have to limit the scheduling of the new
1294 temp reg move to the last use of the same temp register so
1295 we don't overwrite the temp registers of other operands. */
1296 int lastUse = endCycle_;
1297
1298 // find all unscheduled preceeding temp moves of the operand move
1299 DataDependenceGraph::EdgeSet inEdges = ddg_->inEdges(operandMove);
1300 MoveNode* tempMove = NULL;
1301 for (DataDependenceGraph::EdgeSet::iterator i = inEdges.begin();
1302 i != inEdges.end(); ++i) {
1303
1304 if ((**i).edgeReason() != DataDependenceEdge::EDGE_REGISTER ||
1305 (**i).guardUse() ||
1306 (**i).dependenceType() != DataDependenceEdge::DEP_RAW) {
1307 continue;
1308 }
1309
1310 MoveNode& m = ddg_->tailNode(**i);
1311 if (m.isScheduled() ||
1312 !m.move().hasAnnotations(
1314 continue;
1315 }
1316
1317 assert(tempMove == NULL &&
1318 "Multiple unscheduled moves for the operand move, should have "
1319 "max. one (the temporary move)!");
1320 tempMove = &m;
1321 // First cycle where temporary register will be read, this should
1322 // be actuall operand move cycle!
1323 MoveNode* firstRead =
1325 tempMove->move().destination().registerFile(),
1326 tempMove->move().destination().index());
1327 if (firstRead != NULL) {
1328 assert(firstRead->isScheduled());
1329 lastUse = firstRead->cycle();
1330 if (operandMove.isScheduled() && lastUse != operandMove.cycle()) {
1331 Application::logStream() << "\tFirst register read problem "
1332 << operandMove.toString() << " temp " << firstRead->toString()
1333 << std::endl;
1334 }
1335 }
1336 }
1337
1338 if (tempMove == NULL)
1339 return; // no temp moves found
1340
1341 scheduleMove(*tempMove, lastUse - 1, true);
1342 if (!tempMove->isScheduled()) {
1343 std::cerr << "temp move: " << tempMove->toString()
1344 << "not scheduled."
1345 << std::endl;
1346 ddg_->writeToDotFile("failTempNotSched.dot");
1347 }
1348 assert(tempMove->isScheduled());
1349 scheduledTempMoves_[&operandWrite].insert(tempMove);
1350 scheduleInputOperandTempMoves(*tempMove, operandWrite);
1351}
void scheduleInputOperandTempMoves(MoveNode &resultMove, MoveNode &resultRead)
virtual Node & tailNode(const Edge &edge) const
virtual EdgeSet inEdges(const Node &node) const
std::set< GraphEdge *, typename GraphEdge::Comparator > EdgeSet
Definition Graph.hh:54
virtual int index() const
Definition Terminal.cc:274
virtual const TTAMachine::RegisterFile & registerFile() const
Definition Terminal.cc:225

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

Referenced by scheduleInputOperandTempMoves(), and scheduleOperand().

Here is the call graph for this function:

◆ scheduleMove()

void BUBasicBlockScheduler::scheduleMove ( MoveNode moveNode,
int  latestCycle,
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.

Definition at line 959 of file BUBasicBlockScheduler.cc.

960 {
961 if (moveNode.isScheduled()) {
962 ddg_->writeToDotFile("already_sched.dot");
963 throw InvalidData(
964 __FILE__, __LINE__, __func__,
965 (boost::format("Move '%s' is already scheduled!")
966 % moveNode.toString()).str());
967 }
968 int ii = rm_->initiationInterval();
969 int ddgCycle = endCycle_;
970 if (moveNode.move().isControlFlowMove()) {
972 if (ddg_->latestCycle(moveNode, ii) < ddgCycle) {
973 // Trying to schedule CFG move but data dependence does not
974 // allow it to schedule in correct place
975 throw InvalidData(
976 __FILE__, __LINE__, __func__,
977 (boost::format("Move '%s' needs to be scheduled in %d,"
978 " but data dependence does not allow it!")
979 % moveNode.toString() % ddgCycle).str());
980 }
981 jumpMove_ = &moveNode;
982 } else { // not a control flow move:
983 ddgCycle = ddg_->latestCycle(moveNode, ii);
984 if (renamer_ != NULL && allowPredicationAndRenaming) {
985 int latestFromTrigger =
986 (moveNode.isDestinationOperation()) ?
987 moveNode.latestTriggerWriteCycle() : latestCycle;
988 int minRenamedEC = std::min(
989 latestFromTrigger, ddg_->latestCycle(
990 moveNode, ii, true)); // TODO: 0 or INT_MAX
991
992 // rename if can and may alow scheuduling later.
993 if (minRenamedEC > ddgCycle) {
994 minRenamedEC = rm_->latestCycle(minRenamedEC, moveNode);
995 if (minRenamedEC > ddgCycle) {
997 moveNode, ii != 0, true, true, minRenamedEC)) {
998 ddgCycle = ddg_->latestCycle(moveNode, ii);
999 }
1000#ifdef THIS_IS_BUGGY_WITH_REGCOPY_ADDER
1001 else {
1002 MoveNode *limitingAdep =
1004 moveNode);
1005 if (limitingAdep != NULL) {
1006 // don't try to rename is same operation.
1007 // as it would not help at all.
1008 if (!moveNode.isDestinationOperation() ||
1009 !limitingAdep->isSourceOperation() ||
1010 &moveNode.destinationOperation() !=
1011 &limitingAdep->sourceOperation()) {
1013 *limitingAdep, false, true, true)) {
1014 ddgCycle =
1015 ddg_->latestCycle(moveNode, ii);
1016 }
1017 }
1018 }
1019 }
1020#endif
1021 }
1022 }
1023 }
1024 }
1025 // if it's a conditional move then we have to be sure that the guard
1026 // is defined before executing the move.
1027 // this is already handled by DDGs earliestCycle, except cases
1028 // where the guard is defined in a previous BB.
1029 // So this prevents scheduling unconditional moves at the beginning
1030 // of a BB.
1031
1032 if (!moveNode.move().isUnconditional()) {
1033
1034 if (allowPredicationAndRenaming) {
1035 // try to get rid of the guard if it gives earlier earliestcycle.
1036 if (ddg_->latestCycle(moveNode, ii, false, true, true)
1037 > ddgCycle) {
1038 bool guardNeeded = false;
1039 if (moveNode.move().destination().isGPR() ||
1040 moveNode.move().isControlFlowMove()) {
1041 guardNeeded = true;
1042 } else {
1043 // this would be needed only for trigger,
1044 // but trigger may change during scheduling.
1045 // so lets just limit all operands, it seems
1046 // this does not make the schedule any worse.
1047 if (moveNode.isDestinationOperation()) {
1048 const Operation& o =
1049 moveNode.destinationOperation().operation();
1050 if (o.writesMemory() || o.hasSideEffects() ||
1051 o.affectsCount() != 0) {
1052 guardNeeded = true;
1053 }
1054 }
1055 }
1056 if (!guardNeeded) {
1057 moveNode.move().setGuard(NULL);
1058 ddg_->removeIncomingGuardEdges(moveNode);
1059 ddgCycle = ddg_->latestCycle(moveNode, ii);
1060 assert(moveNode.move().isUnconditional());
1061 }
1062 }
1063
1064 if (ii == 0 && tryToOptimizeWaw(moveNode)) {
1065 ddgCycle = std::max(ddg_->latestCycle(moveNode, ii),
1066 moveNode.guardLatency()-1);
1067 }
1068
1069 }
1070 }
1071
1072 ddgCycle = (ddgCycle == INT_MAX) ? endCycle_ : ddgCycle;
1073 assert(ddgCycle != -1);
1074 // Earliest cycle from which to start, could depend on result ready
1075 // for result moves.
1076 int minCycle = std::min(latestCycle, ddgCycle);
1077 if (moveNode.isSourceConstant() &&
1078 !moveNode.move().hasAnnotations(
1080 // If source is constant and node does not have annotation already,
1081 // we add it if constant can not be transported so IU broker and
1082 // OutputPSocket brokers will add Immediate
1083 // Example : 999999 -> integer0.2
1084 if (!rm_->canTransportImmediate(moveNode)){
1087 moveNode.move().setAnnotation(annotation);
1088
1089 } else if (!moveNode.isDestinationOperation() &&
1090 rm_->latestCycle(endCycle_, moveNode) == -1 && ii == 0) {
1091 // If source is constant and node does not have annotation already,
1092 // we add it if node has no connection, so IU broker and
1093 // OutputPSocket brokers will add Immediate
1094 // Example: 27 -> integer0.2
1095 // With bus capable of transporting 27 as short immediate but
1096 // no connection from that bus to integer0 unit
1099 moveNode.move().setAnnotation(annotation);
1100 }
1101 }
1102 // annotate the return move otherwise it might get undetected in the
1103 // simulator after the short to long immediate conversion and thus
1104 // stopping simulation automatically might not work
1105 if (moveNode.isSourceConstant() &&
1106 moveNode.move().isReturn() &&
1107 !rm_->canTransportImmediate(moveNode)) {
1110 moveNode.move().setAnnotation(annotation);
1111 }
1112 int earliestDDG = ddg_->earliestCycle(moveNode, ii);
1113 minCycle = rm_->latestCycle(minCycle, moveNode);
1114 if (minCycle < earliestDDG) {
1115 // Bypassed move could get scheduld too early, this should prevent it
1116 return ;
1117 }
1118 if (minCycle == -1 || minCycle == INT_MAX) {
1119 if (moveNode.isSourceConstant() &&
1120 !moveNode.isDestinationOperation() &&
1121 moveNode.move().hasAnnotations(
1123 // If earliest cycle returns -1 and source is constant and moveNode
1124 // needs long immediate there is most likely missing long immediate
1125 // unit
1126 std::string msg = "Assignment of MoveNode " + moveNode.toString();
1127 msg += " failed! Most likely missing Long Immediate Unit";
1128 msg += " or Instruction Template!";
1129 throw IllegalMachine(
1130 __FILE__, __LINE__, __func__, msg);
1131 }
1132 return;
1133 }
1134 if (moveNode.isSourceOperation() && !moveNode.isDestinationOperation()) {
1135 ProgramOperation& po = moveNode.sourceOperation();
1136 if (po.isAnyOutputAssigned()) {
1137 // Some of the output moves are already assigned, we try to
1138 // put this as close to them as possible
1139 int localMaximum = 0;
1140 for (int i = 0; i < po.outputMoveCount(); i++) {
1141 MoveNode& temp = po.outputMove(i);
1142 if (temp.isScheduled()) {
1143 localMaximum = std::max(temp.cycle(), localMaximum);
1144 }
1145 }
1146 if (localMaximum != 0 && localMaximum < minCycle) {
1147 // Bypassed moves are earlier then this one can be scheduled
1148 // scheduling it too late won't help since operands are limited
1149 // with already scheduled result move
1150
1151 // if ddg requires move to be later then the bypassed
1152 // versions, we have to obey that
1153 localMaximum = std::max(earliestDDG, localMaximum);
1154 int rmEarliest =
1155 rm_->earliestCycle((localMaximum + minCycle)/2, moveNode);
1156 if (rmEarliest != -1 &&
1157 rmEarliest != INT_MAX &&
1158 rmEarliest < minCycle) {
1159 minCycle = rmEarliest;
1160 }
1161 }
1162 }
1163 }
1164 rm_->assign(minCycle, moveNode);
1165 if (!moveNode.isScheduled()) {
1166 throw ModuleRunTimeError(
1167 __FILE__, __LINE__, __func__,
1168 (boost::format("Assignment of MoveNode '%s' failed!")
1169 % moveNode.toString()).str());
1170 }
1171 // Find out the cycle when execution of operation actually ends.
1172 // Only use for operations that uses internal pipeline after the result read.
1173 if (moveNode.isDestinationOperation()) {
1174
1175 const Operation& op = moveNode.destinationOperation().operation();
1176 const TTAMachine::HWOperation& hwop =
1177 *moveNode.move().destination().functionUnit().operation(op.name());
1178
1179 unsigned int epEndCycle = moveNode.cycle() + hwop.latency();
1180 // The pipeline will end after current the final cycle,
1181 // have to scheduler earlier.
1182 if (epEndCycle > endCycle_ &&
1183 moveNode.destinationOperation().outputMoveCount() > 0) {
1184 rm_->unassign(moveNode);
1185 }
1186 }
1187}
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
void removeIncomingGuardEdges(MoveNode &node)
MoveNode * findLimitingAntidependenceDestination(MoveNode &mn)
int latestTriggerWriteCycle() const
Definition MoveNode.cc:698
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 TCEString name() const
Definition Operation.cc:93
virtual bool hasSideEffects() const
Definition Operation.cc:272
virtual int affectsCount() const
Definition Operation.cc:402
virtual bool writesMemory() const
Definition Operation.cc:252
int outputMoveCount() const
const Operation & operation() const
MoveNode & outputMove(int index) const
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)
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
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
virtual HWOperation * operation(const std::string &name) const
virtual ControlUnit * controlUnit() const
Definition Machine.cc:345
void setAnnotation(const ProgramAnnotation &annotation)
bool isControlFlowMove() const
Definition Move.cc:233
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 const TTAMachine::FunctionUnit & functionUnit() const
Definition Terminal.cc:251
virtual bool isGPR() const
Definition Terminal.cc:107

References __func__, Operation::affectsCount(), TTAProgram::ProgramAnnotation::ANN_REQUIRES_LIMM, TTAProgram::ProgramAnnotation::ANN_STACKFRAME_PROCEDURE_RETURN, assert, SimpleResourceManager::assign(), SimpleResourceManager::canTransportImmediate(), TTAMachine::Machine::controlUnit(), MoveNode::cycle(), BasicBlockScheduler::ddg_, TTAMachine::ControlUnit::delaySlots(), TTAProgram::Move::destination(), MoveNode::destinationOperation(), DataDependenceGraph::earliestCycle(), SimpleResourceManager::earliestCycle(), endCycle_, DataDependenceGraph::findLimitingAntidependenceDestination(), TTAProgram::Terminal::functionUnit(), MoveNode::guardLatency(), TTAProgram::AnnotatedInstructionElement::hasAnnotations(), Operation::hasSideEffects(), SimpleResourceManager::initiationInterval(), ProgramOperation::isAnyOutputAssigned(), TTAProgram::Move::isControlFlowMove(), MoveNode::isDestinationOperation(), TTAProgram::Terminal::isGPR(), TTAProgram::Move::isReturn(), MoveNode::isScheduled(), MoveNode::isSourceConstant(), MoveNode::isSourceOperation(), TTAProgram::Move::isUnconditional(), jumpMove_, TTAMachine::HWOperation::latency(), DataDependenceGraph::latestCycle(), SimpleResourceManager::latestCycle(), MoveNode::latestTriggerWriteCycle(), MoveNode::move(), Operation::name(), ProgramOperation::operation(), TTAMachine::FunctionUnit::operation(), ProgramOperation::outputMove(), ProgramOperation::outputMoveCount(), DataDependenceGraph::removeIncomingGuardEdges(), RegisterRenamer::renameDestinationRegister(), BasicBlockScheduler::renamer_, RegisterRenamer::renameSourceRegister(), BasicBlockScheduler::rm_, TTAProgram::AnnotatedInstructionElement::setAnnotation(), TTAProgram::Move::setGuard(), MoveNode::sourceOperation(), BasicBlockScheduler::targetMachine_, MoveNode::toString(), tryToOptimizeWaw(), SimpleResourceManager::unassign(), Operation::writesMemory(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by bypassNode(), handleDDG(), handleLoopDDG(), scheduleInputOperandTempMoves(), scheduleOperand(), scheduleResultReads(), scheduleResultReadTempMoves(), scheduleRRMove(), scheduleRRTempMoves(), tryToOptimizeWaw(), and undoBypass().

Here is the call graph for this function:

◆ scheduleOperand()

bool BUBasicBlockScheduler::scheduleOperand ( MoveNode node,
int  cycle 
)
protected

Checks existence of temporary moves and schedules operand according to discovered dependencies.

Definition at line 1448 of file BUBasicBlockScheduler.cc.

1448 {
1449 int tempRegLimitCycle = cycle;
1450 // Find out if RegCopyAdded create temporary move for input.
1451 // If so, the operand has to be scheduled before the other use
1452 // of same temporary register.
1453 MoveNode* test = precedingTempMove(node);
1454 if (test != NULL) {
1455 // Input temp move exists. Check where the move is reading data
1456 // from, so operand move can be scheduled earlier then
1457 // the already scheduled overwriting cycle.
1458 MoveNode* firstWrite =
1460 node.move().source().registerFile(),
1461 node.move().source().index());
1462 if (firstWrite != NULL) {
1463 assert(firstWrite->isScheduled());
1464 tempRegLimitCycle = firstWrite->cycle();
1465 }
1466 }
1467 cycle = std::min(cycle, tempRegLimitCycle);
1468 // This must pass, since we got latest cycle from RM.
1469 scheduleMove(node, cycle, true);
1470 if (node.isScheduled() == false) {
1471 // the latest cycle may change because scheduleMove may do things like
1472 // register renaming, so this may fail.
1473 return false;
1474 }
1476 return true;
1477}
MoveNode * precedingTempMove(MoveNode &current)
MoveNode * firstScheduledRegisterWrite(const TTAMachine::BaseRegisterFile &rf, int registerIndex) const

References assert, MoveNode::cycle(), BasicBlockScheduler::ddg_, DataDependenceGraph::firstScheduledRegisterWrite(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), MoveNode::move(), precedingTempMove(), TTAProgram::Terminal::registerFile(), scheduleInputOperandTempMoves(), scheduleMove(), and TTAProgram::Move::source().

Referenced by scheduleOperandWrites().

Here is the call graph for this function:

◆ scheduleOperandWrites()

bool BUBasicBlockScheduler::scheduleOperandWrites ( MoveNodeGroup moves,
int  cycle 
)
protected

Schedules operand moves of an operation execution.

Assumes the given MoveNodeGroup contains all moves in the operation execution. Also assumes that all result moves of the MoveNodeGroup have been scheduled. Assumes bottom up scheduling.

Parameters
movesMoves of the operation execution.
cyclelatest cycle for starting scheduling of operands
Returns
True if all operands got scheduled

Definition at line 663 of file BUBasicBlockScheduler.cc.

663 {
664 ProgramOperation& po =
665 (moves.node(0).isSourceOperation())?
666 (moves.node(0).sourceOperation()):
667 (moves.node(0).destinationOperation());
668
669 int unscheduledMoves = 0;
670 int scheduledMoves = 0;
671 MoveNode* trigger = NULL;
672
673 for (int i = 0; i < moves.nodeCount(); i++) {
674 if (!moves.node(i).isDestinationOperation()) {
675 continue;
676 }
677 // count how many operand moves will need to be scheduled
678 unscheduledMoves++;
679 if (moves.node(i).move().destination().isTriggering()) {
680 int limit = moves.node(i).latestTriggerWriteCycle();
681 // update starting cycle based on scheduled results
682 // if necessary.
683 cycle = (limit < cycle) ? limit : cycle;
684 }
685 }
686 int counter = 0;
687
688 while (unscheduledMoves != scheduledMoves && counter < 5 && cycle >=0) {
689 // try to schedule all input moveNodes, also find trigger
690 // Try to schedule trigger first, otherwise the operand
691 // may get scheduled in cycle where trigger does not fit and
692 // later cycle will not be possible for trigger.
693 trigger = findTrigger(po, *targetMachine_);
694 if (trigger != NULL && !trigger->isScheduled()) {
695 if (scheduleOperand(*trigger, cycle) == false) {
696 cycle--;
697 counter++;
698 continue;
699 }
700 assert(trigger->isScheduled());
701 cycle = trigger->cycle();
702
703 if (trigger->move().destination().isTriggering()) {
704 // We schedulled trigger, this will give us latest possible cycle
705 // in order not to have operands later then trigger.
706 if (ddg_->hasNode(*trigger)) {
707 // handle moving fu deps.
708 // they may move trigger to later time.
710 int triggerLatest =
711 std::min(ddg_->latestCycle(*trigger,
713 cycle);
714 triggerLatest = rm_->latestCycle(triggerLatest, *trigger);
715 if (triggerLatest != INT_MAX &&
716 triggerLatest > trigger->cycle()) {
717 unschedule(*trigger);
719 if (scheduleOperand(*trigger, triggerLatest) == false) {
720 // reschedule with new dependencies failed,
721 // bringing back originaly scheduled trigger
722 scheduleOperand(*trigger, cycle);
723 }
724 assert(trigger->isScheduled());
725 cycle = trigger->cycle();
726 }
727 }
728 }
729 }
730
731 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
732 MoveNode& moveNode = moves.node(moveIndex);
733 // skip the result reads
734 if (!moveNode.isDestinationOperation()) {
735 continue;
736 }
737
738 if (moveNode.isScheduled()) {
739 continue;
740 }
741 if (scheduleOperand(moveNode, cycle) == false) {
743 break;
744 }
745
746 }
747 // Tests if all input moveNodes were scheduled, if so check if trigger
748 // is latest
749 scheduledMoves = 0;
750 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
751 MoveNode& moveNode = moves.node(moveIndex);
752 // skip the result reads
753 if (!moveNode.isDestinationOperation()) {
754 continue;
755 }
756 if (moveNode.isScheduled()) {
757 scheduledMoves++;
758 if (moveNode.cycle() > cycle) {
759 // moveNode is operand and it is scheduled after the
760 // trigger! This is wrong!
761 std::cerr << "Move " << moveNode.toString()
762 << " is scheduled after the trigger!" << std::endl;
763 scheduledMoves--;
764 }
765 }
766 }
767
768 // Some moveNodes were not scheduled
769 // unschedule all and try with higher start cycle
770 if (scheduledMoves != unscheduledMoves) {
771 for (int i = 0; i < moves.nodeCount(); i++){
772 MoveNode& moveNode = moves.node(i);
773 if (moveNode.isScheduled() &&
774 moveNode.isDestinationOperation()) {
775 unschedule(moveNode);
777 }
778 }
779 scheduledMoves = 0;
780 } else {
781 // every operand is scheduled, we can return quickly
782 return true;
783 }
784 cycle--;
785 counter++;
786 }
787 // If loop timeouts we get here
788 if (scheduledMoves != unscheduledMoves) {
789 return false;
790 }
791 return true;
792}
bool scheduleOperand(MoveNode &, int cycle)
void unscheduleInputOperandTempMoves(MoveNode &operandMove)
static MoveNode * findTrigger(const ProgramOperation &po, const TTAMachine::Machine &mach)
bool hasNode(const Node &) const
void moveFUDependenciesToTrigger(MoveNode &trigger)
virtual bool isTriggering() const
Definition Terminal.cc:298

References assert, MoveNode::cycle(), BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), MoveNode::destinationOperation(), BasicBlockScheduler::findTrigger(), BoostGraph< GraphNode, GraphEdge >::hasNode(), SimpleResourceManager::initiationInterval(), MoveNode::isDestinationOperation(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), TTAProgram::Terminal::isTriggering(), DataDependenceGraph::latestCycle(), SimpleResourceManager::latestCycle(), MoveNode::latestTriggerWriteCycle(), MoveNode::move(), DataDependenceGraph::moveFUDependenciesToTrigger(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), BasicBlockScheduler::rm_, scheduleOperand(), MoveNode::sourceOperation(), BasicBlockScheduler::targetMachine_, MoveNode::toString(), BasicBlockScheduler::unschedule(), and BasicBlockScheduler::unscheduleInputOperandTempMoves().

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ scheduleOperation()

void BUBasicBlockScheduler::scheduleOperation ( MoveNodeGroup moves,
BUMoveNodeSelector selector 
)
protected

Schedules moves in a single operation execution.

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

Parameters
movesMoves of the operation execution.

Definition at line 454 of file BUBasicBlockScheduler.cc.

455 {
456 ProgramOperation& po =
457 (moves.node(0).isSourceOperation())?
458 (moves.node(0).sourceOperation()):
459 (moves.node(0).destinationOperation());
461 bool operandsFailed = true;
462 bool resultsFailed = true;
463 int resultsStartCycle = endCycle_;
464 int maxResult = resultsStartCycle;
465
466#ifdef DEBUG_REG_COPY_ADDER
467 ddg_->setCycleGrouping(true);
469 (boost::format("%s_before_ddg.dot") % ddg_->name()).str());
470#endif
471 RegisterCopyAdder regCopyAdder(
474 regCopyAdder.addMinimumRegisterCopies(po, *targetMachine_, ddg_);
475
476#ifdef DEBUG_REG_COPY_ADDER
477 const int tempsAdded = copies.count_;
478#endif
479 ;
480#ifdef DEBUG_REG_COPY_ADDER
481 if (tempsAdded > 0) {
483 (boost::format("%s_after_regcopy_ddg.dot") % ddg_->name()).str());
484 }
485// ddg_->sanityCheck();
486#endif
487
488 bool bypass = bypass_;
489 bool bypassLate = bypass_;
490 int ii = rm_->initiationInterval();
491 // Find smallest cycle from RM is known, otherwise 1
492 int rmSmallest = (rm_->smallestCycle() < INT_MAX) ? rm_->smallestCycle() : 1;
493 // rmSmallest is cycle where there is nothing scheduled, and nothing
494 // is scheduled before it, so it the schedule of result fails there
495 // there is no point decreasing the schedule any more.
496 int stopingPoint = (ii == 0) ?
497 rmSmallest - 1 :
498 endCycle_ - ii -1;
499 while ((operandsFailed || resultsFailed) &&
500 resultsStartCycle >= stopingPoint) {
501 maxResult = scheduleResultReads(
502 moves, resultsStartCycle, bypass, bypassLate);
503 if (maxResult != -1) {
504 resultsFailed = false;
505 } else {
506 // At least one of the results did not get scheduled correctly,
507 // We try with earlier starting cycle.
508 // Drawback, in case of 3 results, 1 could be scheduled very late,
509 // second bit earlier and third failing because of location of
510 // second scheduled result, not first.
511 // Better solution would be to try to push scheduled results up
512 // individually, but that would be rather slow process.
513 for (int i = 0; i < moves.nodeCount(); i++){
514 MoveNode& moveNode = moves.node(i);
515 if (moveNode.isScheduled() &&
516 moveNode.isSourceOperation()) {
517 unschedule(moveNode);
519 undoBypass(moveNode);
520 }
521 }
522 resultsFailed = true;
523 if (bypass && bypassLate) {
524 bypass = true;
525 bypassLate = false;
526 } else if (bypass && !bypassLate) {
527 bypass = false;
528 bypassLate = true;
529 } else if (!bypass && bypassLate) {
530 bypassLate = false;
531 } else {
532 // We will try to schedule results in earlier cycle
533 resultsStartCycle--;
534 bypass = bypass_;
535 bypassLate = bypass_;
536 }
537 continue;
538 }
539 regCopyAdder.resultsScheduled(copies, *ddg_);
540 if (scheduleOperandWrites(moves, resultsStartCycle)) {
541 operandsFailed = false;
542 } else {
543 // Scheduling some operand failed, unschedule all moves, try earlier
544 for (int i = 0;i < po.inputMoveCount(); i++) {
545 MoveNode& moveNode = po.inputMove(i);//moves.node(i);
546 if (moveNode.isScheduled()) {
547 unschedule(moveNode);
548 if (moveNode.isDestinationOperation()) {
550 }
551
552 if (moveNode.isSourceOperation()) {
554 }
555 }
556 }
557
558 for (int i = 0;i < po.outputMoveCount(); i++) {
559 MoveNode& moveNode = po.outputMove(i);//moves.node(i);
560 if (moveNode.isScheduled()) {
561 unschedule(moveNode);
562 if (moveNode.isDestinationOperation()) {
564 }
565
566 if (moveNode.isSourceOperation()) {
568 }
569 }
570 }
571
572 std::vector<MoveNode*> outputMoves;
573 for (int i = 0; i < po.outputMoveCount(); i++) {
574 outputMoves.push_back(&po.outputMove(i));
575 }
576
577 for (unsigned int i = 0; i < outputMoves.size(); i++) {
578 // then undo the bypass etc.
579 MoveNode& moveNode = *outputMoves[i]; //moves.node(i);
580 if (moveNode.isSourceOperation()) {
581 undoBypass(moveNode);
582 }
583 }
584
585 operandsFailed = true;
586 if (bypass && bypassLate) {
587 bypass = true;
588 bypassLate = false;
589 } else if (bypass && !bypassLate) {
590 bypass = false;
591 bypassLate = true;
592 } else if (!bypass && bypassLate) {
593 bypassLate = false;
594 } else {
595 resultsStartCycle--;
596 maxResult--;
597 resultsStartCycle = std::min(maxResult, resultsStartCycle);
598 bypass = bypass_;
599 bypassLate = bypass_;
600 }
601 }
602 }
603 // This fails if we reach 0 cycle.
604 if (resultsFailed) {
605 if (ii == 0) {
606 // This is only problem with regular scheduling, with loop schedule
607 // this is expected for too small II.
609 (boost::format("bb_%s_2_failed_scheduling.dot")
610 % ddg_->name()).str());
611 }
613 throw ModuleRunTimeError(
614 __FILE__, __LINE__, __func__,
615 "Results scheduling failed for \'" + moves.toString());
616 }
617
618 if (operandsFailed) {
619 if (ii == 0) {
620 // This is only problem with regular scheduling, with loop schedule
621 // this is expected for too small II.
623 (boost::format("bb_%s_2_scheduling.dot")
624 % ddg_->name()).str());
625 }
627 throw ModuleRunTimeError(
628 __FILE__, __LINE__, __func__,
629 "Operands scheduling failed for \'" + moves.toString());
630 }
631
632 for (int i = 0; i < moves.nodeCount(); i++) {
633 finalizeSchedule(moves.node(i), selector);
634 }
635 regCopyAdder.operandsScheduled(copies,*ddg_);
636#ifdef DEBUG_REG_COPY_ADDER
637 if (tempsAdded > 0) {
639 (boost::format("%s_after_scheduler_ddg.dot") %
640 ddg_->name()).str());
642 << "(operation fix #" << ddg_->name() << ")" << std::endl
643 << std::endl;
644 ++graphCount;
645 }
646
647#endif
648}
bool scheduleOperandWrites(MoveNodeGroup &moves, int cycle)
bool tryToSwitchInputs(ProgramOperation &op)
int scheduleResultReads(MoveNodeGroup &moves, int cycle, bool bypass=false, bool bypassLate=false)
void unscheduleResultReadTempMoves(MoveNode &resultMove)
virtual const TCEString & name() const
virtual void setCycleGrouping(bool flag)
std::string toString() const
int inputMoveCount() const
MoveNode & inputMove(int index) const
InterPassData & interPassData()

References __func__, RegisterCopyAdder::addMinimumRegisterCopies(), bypass_, RegisterCopyAdder::AddedRegisterCopies::count_, BasicBlockScheduler::ddg_, MoveNode::destinationOperation(), endCycle_, finalizeSchedule(), SimpleResourceManager::initiationInterval(), ProgramOperation::inputMove(), ProgramOperation::inputMoveCount(), SchedulerPass::interPassData(), MoveNode::isDestinationOperation(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), Application::logStream(), BoostGraph< GraphNode, GraphEdge >::name(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), RegisterCopyAdder::operandsScheduled(), ProgramOperation::outputMove(), ProgramOperation::outputMoveCount(), RegisterCopyAdder::resultsScheduled(), BasicBlockScheduler::rm_, scheduleOperandWrites(), scheduleResultReads(), BasicBlockScheduler::selector_, DataDependenceGraph::setCycleGrouping(), SimpleResourceManager::smallestCycle(), MoveNode::sourceOperation(), BasicBlockScheduler::targetMachine_, MoveNodeGroup::toString(), tryToSwitchInputs(), undoBypass(), BasicBlockScheduler::unschedule(), unscheduleAllNodes(), BasicBlockScheduler::unscheduleInputOperandTempMoves(), BasicBlockScheduler::unscheduleResultReadTempMoves(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by handleDDG(), and handleLoopDDG().

Here is the call graph for this function:

◆ scheduleResultReads()

int BUBasicBlockScheduler::scheduleResultReads ( MoveNodeGroup moves,
int  cycle,
bool  bypass = false,
bool  bypassLate = false 
)
protected

Schedules the result read moves of an operation execution.

Assumes the given MoveNodeGroup contains all moves in the operation execution.

Parameters
movesMoves of the operation execution.
Returns
Last cycle in which any of the results was scheduled

Definition at line 804 of file BUBasicBlockScheduler.cc.

805 {
806 int maxResultCycle = cycle;
807 int tempRegLimitCycle = cycle;
808 int localMaximum = 0;
809 bool resultScheduled = false;
810 for (int moveIndex = 0; moveIndex < moves.nodeCount(); ++moveIndex) {
811 if (!moves.node(moveIndex).isSourceOperation()) {
812 continue;
813 }
814 MoveNode& moveNode = moves.node(moveIndex);
815 bool bypassSuccess = false;
816 if (!moveNode.isScheduled()) {
817 if (!moveNode.isSourceOperation()) {
818 throw InvalidData(
819 __FILE__, __LINE__, __func__,
820 (boost::format("Move to schedule '%s' is not "
821 "result move!") % moveNode.toString()).str());
822 }
823 if (bypass) {
824 int newMaximum = maxResultCycle + bypassDistance_;
825 bypassSuccess = bypassNode(moveNode, newMaximum);
826 localMaximum =
827 (newMaximum > localMaximum) ? newMaximum : localMaximum;
828 if (dre_ && bypassSuccess &&
829 !ddg_->resultUsed(moveNode)) {
830 // All uses of result were bypassed, result will be removed
831 // after whole operation is scheduled.
832 //tempRegLimitCycle = std::max(tempRegLimitCycle, maxResultCycle);
833 resultScheduled = true;
834 continue;
835 }
836 }
837
838 // Find out if RegCopyAdded create temporary copy for output move
839 MoveNode* test = succeedingTempMove(moveNode);
840 if (test != NULL) {
841 // Output temp move exists. Check where the original move
842 // will be writing, that is the temporary register.
843 MoveNode* firstWrite =
845 moveNode.move().destination().registerFile(),
846 moveNode.move().destination().index());
847 if (firstWrite != NULL) {
848 assert(firstWrite->isScheduled());
849 tempRegLimitCycle = firstWrite->cycle();
850 }
851 // Schedule temporary move first.
853 moveNode, moveNode, tempRegLimitCycle);
854 // If there was temporary result read scheduled, write needs
855 // to be at least one cycle earlier.
856 if (test != NULL && test->isScheduled())
857 tempRegLimitCycle = std::min(test->cycle() -1, cycle);
858 }
859 tempRegLimitCycle =
860 (localMaximum != 0)
861 ? std::min(localMaximum +1, tempRegLimitCycle)
862 : tempRegLimitCycle;
863
864 scheduleMove(moveNode, tempRegLimitCycle, true);
865 if (!moveNode.isScheduled()) {
866 // Scheduling result failed due to some of the bypassed moves
867 // will try again without bypassing anything.
868 undoBypass(moveNode);
869 return -1;
870 }
871 if (bypassLate) {
872 int newMaximum = moveNode.cycle() + bypassDistance_;
873 if (bypassNode(moveNode, newMaximum)) {
874 localMaximum =
875 (localMaximum < newMaximum) ? newMaximum : localMaximum;
876 localMaximum = (localMaximum > cycle) ? localMaximum : cycle;
877 int originalCycle = moveNode.cycle();
878 unschedule(moveNode);
879 scheduleMove(moveNode, localMaximum, true);
880 if (!moveNode.isScheduled()) {
881 scheduleMove(moveNode, originalCycle, false);
882 }
883 }
884 assert(moveNode.isScheduled());
885 }
886 resultScheduled = true;
887 // Find latest schedule result cycle
888 localMaximum =
889 (localMaximum < moveNode.cycle())
890 ? moveNode.cycle() : localMaximum;
891
892 maxResultCycle =
893 (moveNode.cycle() > maxResultCycle) ?
894 moveNode.cycle() : maxResultCycle;
895 }
896
897 }
898 return (resultScheduled) ? localMaximum : maxResultCycle;
899}
void scheduleResultReadTempMoves(MoveNode &resultMove, MoveNode &resultRead, int lastUse)

References __func__, assert, bypassDistance_, bypassNode(), MoveNode::cycle(), BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), dre_, DataDependenceGraph::firstScheduledRegisterWrite(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), MoveNode::isSourceOperation(), MoveNode::move(), MoveNodeGroup::node(), MoveNodeGroup::nodeCount(), TTAProgram::Terminal::registerFile(), DataDependenceGraph::resultUsed(), scheduleMove(), scheduleResultReadTempMoves(), BasicBlockScheduler::succeedingTempMove(), MoveNode::toString(), undoBypass(), and BasicBlockScheduler::unschedule().

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ scheduleResultReadTempMoves()

void BUBasicBlockScheduler::scheduleResultReadTempMoves ( MoveNode resultMove,
MoveNode resultRead,
int  firstWriteCycle 
)
protected

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

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

Parameters
resultMoveA temp move whose predecessor has to be scheduled.
resultReadThe original move of which temp moves to schedule.
firstWriteCycleRecursive function parameter.

Definition at line 1228 of file BUBasicBlockScheduler.cc.

1229 {
1230 /* Because temporary register moves do not have WaR/WaW dependency edges
1231 between the other possible uses of the same temp register in
1232 the same operation, we have to limit the scheduling of the new
1233 temp reg move to the last use of the same temp register so
1234 we don't overwrite the temp registers of the other operands. */
1235
1236
1237 // find all unscheduled succeeding moves of the result read move
1238 // there should be only only one with the only dependence edge (RaW) to
1239 // the result move
1240
1241 MoveNode* tempMove1 = succeedingTempMove(resultMove);
1242 if (tempMove1 == NULL)
1243 return; // no temp moves found
1244
1245 MoveNode* tempMove2 = succeedingTempMove(*tempMove1);
1246 if (tempMove2 != NULL) {
1247 // Found second temp move. First temp move will write register
1248 // which second will read.
1249 MoveNode* firstWrite =
1251 tempMove1->move().destination().registerFile(),
1252 tempMove1->move().destination().index());
1253 if (firstWrite != NULL && firstWrite->isScheduled())
1254 firstWriteCycle = firstWrite->cycle();
1255 scheduleResultReadTempMoves(*tempMove1, resultRead, firstWriteCycle);
1256 if (tempMove2 != NULL && tempMove2->isScheduled()){ // TODO: maybe there is scheduled is missing
1257 firstWriteCycle = tempMove2->cycle() -1;
1258 }
1259 }
1260 bool bypassSuccess = false;
1261 if (bypass_) {
1262 int tmp = endCycle_;
1263 bypassSuccess = bypassNode(*tempMove1, tmp);
1264 }
1265 if (!bypassSuccess || !dre_ || ddg_->resultUsed(*tempMove1)) {
1266 scheduleMove(*tempMove1, firstWriteCycle, true);
1267 assert(tempMove1->isScheduled());
1268 if (bypass_) {
1269 int tmp = endCycle_;
1270 bypassSuccess = bypassNode(*tempMove1, tmp);
1271 }
1272 scheduledTempMoves_[&resultRead].insert(tempMove1);
1273 } else if (dre_ && !ddg_->resultUsed(*tempMove1)) {
1274 finalizeSchedule(*tempMove1, dynamic_cast<BUMoveNodeSelector&>(*selector_));
1275 }
1276}

References assert, bypass_, bypassNode(), MoveNode::cycle(), BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), dre_, endCycle_, finalizeSchedule(), DataDependenceGraph::firstScheduledRegisterWrite(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), MoveNode::move(), TTAProgram::Terminal::registerFile(), DataDependenceGraph::resultUsed(), BasicBlockScheduler::scheduledTempMoves_, scheduleMove(), scheduleResultReadTempMoves(), BasicBlockScheduler::selector_, and BasicBlockScheduler::succeedingTempMove().

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

Here is the call graph for this function:

◆ scheduleRRMove()

void BUBasicBlockScheduler::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 911 of file BUBasicBlockScheduler.cc.

911 {
912#ifdef DEBUG_REG_COPY_ADDER
913 ddg_->setCycleGrouping(true);
915 (boost::format("%s_before_ddg.dot") % ddg_->name()).str());
916#endif
917
918 if (moveNode.move().source().equals(
919 moveNode.move().destination())) {
920 return;
921 }
922
923 RegisterCopyAdder regCopyAdder(
925
926#ifdef DEBUG_REG_COPY_ADDER
927 const int tempsAdded =
928#endif
929
930 regCopyAdder.addRegisterCopiesToRRMove(moveNode, ddg_)
931#ifdef DEBUG_REG_COPY_ADDER
932 .count_
933#endif
934 ;
935#ifdef DEBUG_REG_COPY_ADDER
936 if (tempsAdded > 0) {
938 (boost::format("%s_after_regcopy_ddg.dot") % ddg_->name()).str());
939 }
940// ddg_->sanityCheck();
941#endif
942 scheduleResultReadTempMoves(moveNode, moveNode, endCycle_);
943 scheduleMove(moveNode, endCycle_, true);
944}

References RegisterCopyAdder::addRegisterCopiesToRRMove(), RegisterCopyAdder::AddedRegisterCopies::count_, BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), endCycle_, TTAProgram::Terminal::equals(), SchedulerPass::interPassData(), MoveNode::move(), BoostGraph< GraphNode, GraphEdge >::name(), BasicBlockScheduler::rm_, scheduleMove(), scheduleResultReadTempMoves(), BasicBlockScheduler::selector_, DataDependenceGraph::setCycleGrouping(), TTAProgram::Move::source(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by handleDDG(), and handleLoopDDG().

Here is the call graph for this function:

◆ scheduleRRTempMoves()

void BUBasicBlockScheduler::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 1365 of file BUBasicBlockScheduler.cc.

1366 {
1367 /* Because temporary register moves do not have WaR/WaW dependency edges
1368 between the other possible uses of the same temp register in
1369 the same operation, we have to limit the scheduling of the new
1370 temp reg move to the last use of the same temp register so
1371 we don't overwrite the temp registers of the other operands. */
1372
1373 // find all unscheduled succeeding moves of the result read move
1374 // there should be only only one with the only dependence edge (RaW) to
1375 // the result move
1376
1377 MoveNode* tempMove1 = succeedingTempMove(regToRegMove);
1378 if (tempMove1 == NULL)
1379 return; // no temp moves found
1380
1381 MoveNode* tempMove2 = succeedingTempMove(*tempMove1);
1382 if (tempMove2 != NULL) {
1383 MoveNode* firstWrite =
1385 tempMove1->move().destination().registerFile(),
1386 tempMove1->move().destination().index());
1387 if (firstWrite != NULL) {
1388 assert(firstWrite->isScheduled());
1389 lastUse = firstWrite->cycle();
1390 }
1391 }
1392 scheduleResultReadTempMoves(*tempMove1, firstMove, lastUse);
1393 bool bypassSuccess = false;
1394 if (bypass_) {
1395 int tmp = endCycle_;
1396 bypassSuccess = bypassNode(*tempMove1, tmp);
1397 }
1398 if (!bypassSuccess || !dre_ || ddg_->resultUsed(*tempMove1)) {
1399 scheduleMove(*tempMove1, lastUse - 1, true);
1400 if (!tempMove1->isScheduled()) {
1401 std::cerr << "not scheduled: " << tempMove1->toString() << std::endl;
1402 ddg_->writeToDotFile("tempNotSched.dot");
1403 }
1404 if (bypass_) {
1405 int tmp = endCycle_;
1406 bypassSuccess = bypassNode(*tempMove1, tmp);
1407 }
1408 assert(tempMove1->isScheduled());
1409 scheduledTempMoves_[&firstMove].insert(tempMove1);
1410 } else if (dre_ && !ddg_->resultUsed(*tempMove1)) {
1411 finalizeSchedule(*tempMove1, dynamic_cast<BUMoveNodeSelector&>(*selector_));
1412 }
1413}

References assert, bypass_, bypassNode(), MoveNode::cycle(), BasicBlockScheduler::ddg_, TTAProgram::Move::destination(), dre_, endCycle_, finalizeSchedule(), DataDependenceGraph::firstScheduledRegisterWrite(), TTAProgram::Terminal::index(), MoveNode::isScheduled(), MoveNode::move(), TTAProgram::Terminal::registerFile(), DataDependenceGraph::resultUsed(), BasicBlockScheduler::scheduledTempMoves_, scheduleMove(), scheduleResultReadTempMoves(), BasicBlockScheduler::selector_, BasicBlockScheduler::succeedingTempMove(), MoveNode::toString(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Here is the call graph for this function:

◆ shortDescription()

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

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

Returns
The description as a string.

Reimplemented from BasicBlockScheduler.

Definition at line 1196 of file BUBasicBlockScheduler.cc.

1196 {
1197 return "Bottom-up list scheduler with a basic block scope.";
1198}

◆ tryToOptimizeWaw()

bool BUBasicBlockScheduler::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 1977 of file BUBasicBlockScheduler.cc.

1977 {
1978
1979 if (ddg_->latestCycle(moveNode, endCycle_ , false, true, true) >=
1980 ddg_->latestCycle(moveNode)) {
1981 return false;
1982 }
1983
1984 MoveNode* wawPred = NULL;
1985 DataDependenceEdge* wawEdge = NULL;
1986
1987 DataDependenceGraph::EdgeSet inEdges = ddg_->inEdges(moveNode);
1988 for (DataDependenceGraph::EdgeSet::iterator i = inEdges.begin();
1989 i != inEdges.end(); i++) {
1990 DataDependenceEdge* e = *i;
1991
1994 !e->tailPseudo()) {
1995 if (wawPred == NULL) {
1996 wawPred = &ddg_->tailNode(**i);
1997 wawEdge = e;
1998 } else {
1999 return false;
2000 }
2001 }
2002 }
2003 if (wawPred == NULL) {
2004 return false;
2005 }
2006
2007 if (!wawPred->move().isUnconditional()) {
2008 return false;
2009 }
2010
2011 // check that no other usage of the data.
2012 DataDependenceGraph::NodeSet consumers = ddg_->regRawSuccessors(*wawPred);
2013 DataDependenceGraph::NodeSet consumers2 = ddg_->regRawSuccessors(moveNode);
2014 for (DataDependenceGraph::NodeSet::iterator i = consumers.begin();
2015 i != consumers.end(); i++) {
2016 MoveNode* mn = *i;
2017 if (consumers2.find(mn) == consumers2.end() &&
2018 (mn->move().isUnconditional() ||
2019 !ddg_->exclusingGuards(*mn, moveNode))) {
2020 return false;
2021 }
2022 }
2023 if (wawPred->isScheduled())
2024 unschedule(*wawPred);
2025
2027 wawPred->move().setGuard(cg.createInverseGuard(moveNode.move().guard()));
2028
2029 ddg_->copyDepsOver(*wawPred, true, false);
2030
2031 ddg_->copyIncomingGuardEdges(moveNode, *wawPred);
2032 ddg_->copyOutgoingGuardWarEdges(moveNode, *wawPred);
2033
2034 ddg_->removeEdge(*wawEdge);
2035
2036 scheduleMove(*wawPred, endCycle_, false);
2037 bool revert = false;
2038
2039 if (!wawPred->isScheduled()) {
2040 revert = true;
2041 }
2042 if (revert) {
2043 wawPred->move().setGuard(NULL);
2044 ddg_->removeIncomingGuardEdges(*wawPred);
2046 ddg_->connectNodes(*wawPred, moveNode, *wawEdge);
2047 return false;
2048 }
2049
2050 return true;
2051}
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)
MoveGuard & guard() const
Definition Move.cc:345

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

Referenced by scheduleMove().

Here is the call graph for this function:

◆ tryToSwitchInputs()

bool BUBasicBlockScheduler::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 1909 of file BUBasicBlockScheduler.cc.

1909 {
1910
1911 const Operation& op = po.operation();
1912 if (op.numberOfInputs() == 2 && op.canSwap(1, 2)) {
1913
1914 int triggerOperand = getTriggerOperand(op, *targetMachine_);
1915
1916 if (triggerOperand != 0) {
1917 MoveNode* latest = NULL;
1918 int latestMinCycle = -1;
1919 int firstMinCycle = INT_MAX;
1920
1921 //check all input moves.
1922 for (int i = 0; i < po.inputMoveCount(); i++) {
1923 MoveNode& node = po.inputMove(i);
1924 // always make constants triggers.
1925 // todo: shoudl do this only with short imms?
1926 if (node.isSourceConstant()) {
1927 int operandIndex =
1928 node.move().destination().operationIndex();
1929 if (operandIndex != triggerOperand) {
1930 po.switchInputs();
1931 return true;
1932 } else {
1933 return false;
1934 }
1935 }
1936
1937 int minCycle = ddg_->latestCycle(
1938 node, rm_->initiationInterval(), false, true, true, true, true);
1939 if (minCycle > latestMinCycle) {
1940 latest = &node;
1941 latestMinCycle = minCycle;
1942 }
1943 if (minCycle < firstMinCycle) {
1944 firstMinCycle = minCycle;
1945 }
1946 }
1947
1948 int lastOperand = latest->move().destination().operationIndex();
1949
1950 // don't change if min cycles of first and last are equal.
1951 if (latestMinCycle == firstMinCycle) {
1952 return false;
1953 }
1954 if (latestMinCycle - firstMinCycle > 1) { // reverse logic if far.
1955 if (lastOperand == triggerOperand) {
1956 po.switchInputs();
1957 return true;
1958 }
1959 } else {
1960 if (lastOperand != triggerOperand) {
1961 po.switchInputs();
1962 return true;
1963 }
1964 }
1965 }
1966 }
1967 return false;
1968}
int getTriggerOperand(const Operation &operation, const TTAMachine::Machine &machine)
virtual int numberOfInputs() const
Definition Operation.cc:192
virtual bool canSwap(int id1, int id2) const
Definition Operation.cc:470
void switchInputs(int idx1=1, int idx2=2)
virtual int operationIndex() const
Definition Terminal.cc:364

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

Referenced by scheduleOperation().

Here is the call graph for this function:

◆ undoBypass()

void BUBasicBlockScheduler::undoBypass ( MoveNode moveNode,
MoveNode single = NULL,
int  oCycle = -1 
)
protected

Remove all the bypasses of result write in moveNode and restore and schedule original moves.

Definition at line 1527 of file BUBasicBlockScheduler.cc.

1528 {
1529
1530 if (single == NULL) {
1532 std::vector<MoveNode*> destinationsVector =
1533 bypassDestinations_[&moveNode];
1534 std::vector<std::pair<MoveNode*, int> > rescheduleVector;
1535
1536 for (unsigned int j = 0; j < destinationsVector.size(); j++) {
1537 // unschedule and unmerge all bypassed nodes
1538 MoveNode* dest = destinationsVector[j];
1539 if (dest->isScheduled()) {
1540 unschedule(*dest);
1541 }
1542 ddg_->unMergeUser(moveNode, *dest);
1543 int originalCycle =
1544 bypassDestinationsCycle_[&moveNode][j];
1545 const TTAMachine::Bus* bus =
1546 bypassDestinationsBus_[&moveNode][j];
1547 dest->move().setBus(*bus);
1548 rescheduleVector.push_back(
1549 std::pair<MoveNode*, int>(dest, originalCycle));
1550 droppedNodes_.erase(dest);
1551 }
1552 for (unsigned int i = 0; i < rescheduleVector.size(); i++) {
1553 // reassign nodes to their original places
1554 std::pair<MoveNode*, int> dest = rescheduleVector[i];
1555 //rm_->assign(dest.second, *dest.first);
1556 scheduleMove(*dest.first, dest.second, false);
1557 if (!dest.first->isScheduled()) {
1558 ddg_->writeToDotFile("unbypassFailed.dot");
1559 std::cerr << " Source: " << moveNode.toString()
1560 << ", Original: " << dest.first->toString() <<
1561 ", original cycle: " << dest.second << std::endl<< std::endl;
1562 }
1563 assert(dest.first->isScheduled());
1564 }
1565 bypassDestinations_.erase(&moveNode);
1566 bypassDestinationsCycle_.erase(&moveNode);
1567 bypassDestinationsBus_.erase(&moveNode);
1568 }
1569 } else {
1570 if (single->isScheduled()) {
1571 // Bypassed node could get scheduled too early, in such a case
1572 // this move need to be unscheduled.
1573 unschedule(*single);
1574 }
1575 int size = bypassDestinationsBus_[&moveNode].size();
1576 const TTAMachine::Bus* bus =
1577 bypassDestinationsBus_[&moveNode][size-1];
1578 ddg_->unMergeUser(moveNode, *single);
1579 single->move().setBus(*bus);
1580 //rm_->assign(oCycle, *single);
1581 scheduleMove(*single, oCycle, false);
1582 if (!single->isScheduled()) {
1583 ddg_->writeToDotFile("unbypassFailed.dot");
1584 std::cerr << " Source: " << moveNode.toString()
1585 << ", Original: " << single->toString() << ", original cycle: "
1586 << oCycle << std::endl;
1587 }
1588 droppedNodes_.erase(single);
1589 assert(single->isScheduled());
1590 }
1591}
void unMergeUser(MoveNode &resultNode, MoveNode &mergedNode, bool loopBypass=false)
void setBus(const TTAMachine::Bus &bus)
Definition Move.cc:383

References assert, bypassDestinations_, bypassDestinationsBus_, bypassDestinationsCycle_, MapTools::containsKey(), BasicBlockScheduler::ddg_, droppedNodes_, MoveNode::isScheduled(), MoveNode::move(), scheduleMove(), TTAProgram::Move::setBus(), MoveNode::toString(), DataDependenceGraph::unMergeUser(), BasicBlockScheduler::unschedule(), and GraphBase< GraphNode, GraphEdge >::writeToDotFile().

Referenced by bypassNode(), handleDDG(), scheduleOperation(), and scheduleResultReads().

Here is the call graph for this function:

◆ unscheduleAllNodes()

void BUBasicBlockScheduler::unscheduleAllNodes ( )
protected

Calls unschedule() for all ddg nodes, which were scheduled and remove possible bypasses.

Definition at line 1840 of file BUBasicBlockScheduler.cc.

1840 {
1842
1843 for (DataDependenceGraph::NodeSet::iterator i = scheduled.begin();
1844 i != scheduled.end(); ++i) {
1845 MoveNode& moveNode = **i;
1846 if (moveNode.isScheduled()) {
1847 unschedule(moveNode);
1848 i = scheduled.begin();
1849 }
1850 }
1851 std::map<MoveNode*, std::vector<MoveNode*>, MoveNode::Comparator>::iterator it =
1852 bypassDestinations_.begin();
1853 for (; it != bypassDestinations_.end(); it++) {
1854 std::vector<MoveNode*> destinationsVector = (*it).second;
1855 for (unsigned int k = 0; k < destinationsVector.size(); k++) {
1856 // unschedule and unmerge all bypassed nodes
1857 MoveNode* dest = destinationsVector[k];
1858 ddg_->unMergeUser(*(*it).first, *dest);
1859 }
1860 }
1862 bypassDestinationsBus_.clear();
1863 bypassDestinations_.clear();
1864 droppedNodes_.clear();
1866}

References assert, bypassDestinations_, bypassDestinationsBus_, bypassDestinationsCycle_, BasicBlockScheduler::ddg_, droppedNodes_, MoveNode::isScheduled(), DataDependenceGraph::scheduledMoves(), DataDependenceGraph::scheduledNodeCount(), DataDependenceGraph::unMergeUser(), and BasicBlockScheduler::unschedule().

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

Here is the call graph for this function:

Member Data Documentation

◆ bypass_

bool BUBasicBlockScheduler::bypass_
protected

◆ bypassDestinations_

std::map<MoveNode*, std::vector<MoveNode*>, MoveNode::Comparator> BUBasicBlockScheduler::bypassDestinations_
protected

◆ bypassDestinationsBus_

std::map<MoveNode*, std::vector<const TTAMachine::Bus*>, MoveNode::Comparator > BUBasicBlockScheduler::bypassDestinationsBus_
protected

◆ bypassDestinationsCycle_

std::map<MoveNode*, std::vector<int>, MoveNode::Comparator > BUBasicBlockScheduler::bypassDestinationsCycle_
protected

◆ bypassDistance_

int BUBasicBlockScheduler::bypassDistance_
protected

◆ dre_

bool BUBasicBlockScheduler::dre_
protected

◆ droppedNodes_

std::set<MoveNode*> BUBasicBlockScheduler::droppedNodes_
protected

◆ endCycle_

unsigned int BUBasicBlockScheduler::endCycle_
protected

◆ jumpMove_

MoveNode* BUBasicBlockScheduler::jumpMove_
protected

Definition at line 142 of file BUBasicBlockScheduler.hh.

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


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