1 //===-- ModuloScheduling.cpp - ModuloScheduling ----------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
12 //===----------------------------------------------------------------------===//
14 #define DEBUG_TYPE "ModuloSched"
16 #include "ModuloScheduling.h"
17 #include "llvm/CodeGen/MachineFunction.h"
18 #include "llvm/CodeGen/Passes.h"
19 #include "llvm/Support/CFG.h"
20 #include "llvm/Target/TargetSchedInfo.h"
21 #include "Support/Debug.h"
22 #include "Support/GraphWriter.h"
31 /// Create ModuloSchedulingPass
33 FunctionPass *llvm::createModuloSchedulingPass(TargetMachine & targ) {
34 DEBUG(std::cerr << "Created ModuloSchedulingPass\n");
35 return new ModuloSchedulingPass(targ);
38 template<typename GraphType>
39 static void WriteGraphToFile(std::ostream &O, const std::string &GraphName,
40 const GraphType >) {
41 std::string Filename = GraphName + ".dot";
42 O << "Writing '" << Filename << "'...";
43 std::ofstream F(Filename.c_str());
48 O << " error opening file for writing!";
55 struct DOTGraphTraits<MSchedGraph*> : public DefaultDOTGraphTraits {
56 static std::string getGraphName(MSchedGraph *F) {
57 return "Dependence Graph";
60 static std::string getNodeLabel(MSchedGraphNode *Node, MSchedGraph *Graph) {
61 if (Node->getInst()) {
63 ss << *(Node->getInst());
64 return ss.str(); //((MachineInstr*)Node->getInst());
69 static std::string getEdgeSourceLabel(MSchedGraphNode *Node,
70 MSchedGraphNode::succ_iterator I) {
71 //Label each edge with the type of dependence
72 std::string edgelabel = "";
73 switch (I.getEdge().getDepOrderType()) {
75 case MSchedGraphEdge::TrueDep:
79 case MSchedGraphEdge::AntiDep:
83 case MSchedGraphEdge::OutputDep:
88 edgelabel = "Unknown";
91 if(I.getEdge().getIteDiff() > 0)
92 edgelabel += I.getEdge().getIteDiff();
102 /// ModuloScheduling::runOnFunction - main transformation entry point
103 bool ModuloSchedulingPass::runOnFunction(Function &F) {
104 bool Changed = false;
106 DEBUG(std::cerr << "Creating ModuloSchedGraph for each BasicBlock in" + F.getName() + "\n");
108 //Get MachineFunction
109 MachineFunction &MF = MachineFunction::get(&F);
111 //Iterate over BasicBlocks and do ModuloScheduling if they are valid
112 for (MachineFunction::const_iterator BI = MF.begin(); BI != MF.end(); ++BI) {
113 if(MachineBBisValid(BI)) {
114 MSchedGraph *MSG = new MSchedGraph(BI, target);
116 //Write Graph out to file
117 DEBUG(WriteGraphToFile(std::cerr, "dependgraph", MSG));
119 //Print out BB for debugging
120 DEBUG(BI->print(std::cerr));
122 //Calculate Resource II
123 int ResMII = calculateResMII(BI);
125 calculateNodeAttributes(MSG, ResMII);
135 bool ModuloSchedulingPass::MachineBBisValid(const MachineBasicBlock *BI) {
137 //Valid basic blocks must be loops and can not have if/else statements or calls.
140 //Check first if its a valid loop
141 for(succ_const_iterator I = succ_begin(BI->getBasicBlock()),
142 E = succ_end(BI->getBasicBlock()); I != E; ++I) {
143 if (*I == BI->getBasicBlock()) // has single block loop
148 DEBUG(std::cerr << "Basic Block is not a loop\n");
152 DEBUG(std::cerr << "Basic Block is a loop\n");
154 //Get Target machine instruction info
155 /*const TargetInstrInfo& TMI = targ.getInstrInfo();
157 //Check each instruction and look for calls or if/else statements
159 for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) {
160 //Get opcode to check instruction type
161 MachineOpCode OC = I->getOpcode();
162 if(TMI.isControlFlow(OC) && (count+1 < BI->size()))
170 //ResMII is calculated by determining the usage count for each resource
171 //and using the maximum.
172 //FIXME: In future there should be a way to get alternative resources
173 //for each instruction
174 int ModuloSchedulingPass::calculateResMII(const MachineBasicBlock *BI) {
176 const TargetInstrInfo & mii = target.getInstrInfo();
177 const TargetSchedInfo & msi = target.getSchedInfo();
181 //Map to keep track of usage count of each resource
182 std::map<unsigned, unsigned> resourceUsageCount;
184 for(MachineBasicBlock::const_iterator I = BI->begin(), E = BI->end(); I != E; ++I) {
186 //Get resource usage for this instruction
187 InstrRUsage rUsage = msi.getInstrRUsage(I->getOpcode());
188 std::vector<std::vector<resourceId_t> > resources = rUsage.resourcesByCycle;
190 //Loop over resources in each cycle and increments their usage count
191 for(unsigned i=0; i < resources.size(); ++i)
192 for(unsigned j=0; j < resources[i].size(); ++j) {
193 if( resourceUsageCount.find(resources[i][j]) == resourceUsageCount.end()) {
194 resourceUsageCount[resources[i][j]] = 1;
197 resourceUsageCount[resources[i][j]] = resourceUsageCount[resources[i][j]] + 1;
202 //Find maximum usage count
204 //Get max number of instructions that can be issued at once.
205 int issueSlots = msi.maxNumIssueTotal;
207 for(std::map<unsigned,unsigned>::iterator RB = resourceUsageCount.begin(), RE = resourceUsageCount.end(); RB != RE; ++RB) {
208 //Get the total number of the resources in our cpu
209 //int resourceNum = msi.getCPUResourceNum(RB->first);
211 //Get total usage count for this resources
212 unsigned usageCount = RB->second;
214 //Divide the usage count by either the max number we can issue or the number of
215 //resources (whichever is its upper bound)
216 double finalUsageCount;
217 //if( resourceNum <= issueSlots)
218 //finalUsageCount = ceil(1.0 * usageCount / resourceNum);
220 finalUsageCount = ceil(1.0 * usageCount / issueSlots);
223 DEBUG(std::cerr << "Resource ID: " << RB->first << " (usage=" << usageCount << ", resourceNum=X" << ", issueSlots=" << issueSlots << ", finalUsage=" << finalUsageCount << ")\n");
225 //Only keep track of the max
226 ResMII = std::max( (int) finalUsageCount, ResMII);
230 DEBUG(std::cerr << "Final Resource MII: " << ResMII << "\n");
235 void ModuloSchedulingPass::calculateNodeAttributes(MSchedGraph *graph, int MII) {
237 //Loop over the nodes and add them to the map
238 for(MSchedGraph::iterator I = graph->begin(), E = graph->end(); I != E; ++I) {
239 //Assert if its already in the map
240 assert(nodeToAttributesMap.find(I->second) == nodeToAttributesMap.end() && "Node attributes are already in the map");
242 //Put into the map with default attribute values
243 nodeToAttributesMap[I->second] = MSNodeAttributes();
246 //Create set to deal with reccurrences
247 std::set<MSchedGraphNode*> visitedNodes;
248 std::vector<MSchedGraphNode*> vNodes;
249 //Now Loop over map and calculate the node attributes
250 for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
251 // calculateASAP(I->first, (I->second), MII, visitedNodes);
252 findAllReccurrences(I->first, vNodes);
254 visitedNodes.clear();
257 //Calculate ALAP which depends on ASAP being totally calculated
258 /*for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
259 calculateALAP(I->first, (I->second), MII, MII, visitedNodes);
260 visitedNodes.clear();
263 //Calculate MOB which depends on ASAP being totally calculated, also do depth and height
264 /*for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(), E = nodeToAttributesMap.end(); I != E; ++I) {
265 (I->second).MOB = (I->second).ALAP - (I->second).ASAP;
266 DEBUG(std::cerr << "MOB: " << (I->second).MOB << " (" << *(I->first) << ")\n");
267 calculateDepth(I->first, (I->second), visitedNodes);
268 visitedNodes.clear();
269 calculateHeight(I->first, (I->second), visitedNodes);
270 visitedNodes.clear();
276 void ModuloSchedulingPass::calculateASAP(MSchedGraphNode *node, MSNodeAttributes &attributes,
277 int MII, std::set<MSchedGraphNode*> &visitedNodes) {
279 DEBUG(std::cerr << "Calculating ASAP for " << *node << "\n");
281 if(attributes.ASAP != -1 || (visitedNodes.find(node) != visitedNodes.end())) {
282 visitedNodes.erase(node);
285 if(node->hasPredecessors()) {
286 int maxPredValue = 0;
288 //Iterate over all of the predecessors and fine max
289 for(MSchedGraphNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) {
291 //Get that nodes ASAP
292 MSNodeAttributes predAttributes = nodeToAttributesMap.find(*P)->second;
293 if(predAttributes.ASAP == -1) {
294 //Put into set before you recurse
295 visitedNodes.insert(node);
296 calculateASAP(*P, predAttributes, MII, visitedNodes);
297 predAttributes = nodeToAttributesMap.find(*P)->second;
299 int iteDiff = node->getInEdge(*P).getIteDiff();
301 int currentPredValue = predAttributes.ASAP + node->getLatency() - iteDiff * MII;
302 DEBUG(std::cerr << "Current ASAP pred: " << currentPredValue << "\n");
303 maxPredValue = std::max(maxPredValue, currentPredValue);
305 visitedNodes.erase(node);
306 attributes.ASAP = maxPredValue;
309 visitedNodes.erase(node);
313 DEBUG(std::cerr << "ASAP: " << attributes.ASAP << " (" << *node << ")\n");
317 void ModuloSchedulingPass::calculateALAP(MSchedGraphNode *node, MSNodeAttributes &attributes,
318 int MII, int maxASAP,
319 std::set<MSchedGraphNode*> &visitedNodes) {
321 DEBUG(std::cerr << "Calculating AlAP for " << *node << "\n");
323 if(attributes.ALAP != -1|| (visitedNodes.find(node) != visitedNodes.end())) {
324 visitedNodes.erase(node);
327 if(node->hasSuccessors()) {
328 int minSuccValue = 0;
330 //Iterate over all of the predecessors and fine max
331 for(MSchedGraphNode::succ_iterator P = node->succ_begin(),
332 E = node->succ_end(); P != E; ++P) {
334 MSNodeAttributes succAttributes = nodeToAttributesMap.find(*P)->second;
335 if(succAttributes.ASAP == -1) {
337 //Put into set before recursing
338 visitedNodes.insert(node);
340 calculateALAP(*P, succAttributes, MII, maxASAP, visitedNodes);
341 succAttributes = nodeToAttributesMap.find(*P)->second;
342 assert(succAttributes.ASAP == -1 && "Successors ALAP should have been caclulated");
344 int iteDiff = P.getEdge().getIteDiff();
345 int currentSuccValue = succAttributes.ALAP + node->getLatency() + iteDiff * MII;
346 minSuccValue = std::min(minSuccValue, currentSuccValue);
348 visitedNodes.erase(node);
349 attributes.ALAP = minSuccValue;
352 visitedNodes.erase(node);
353 attributes.ALAP = maxASAP;
355 DEBUG(std::cerr << "ALAP: " << attributes.ALAP << " (" << *node << ")\n");
358 int ModuloSchedulingPass::findMaxASAP() {
361 for(std::map<MSchedGraphNode*, MSNodeAttributes>::iterator I = nodeToAttributesMap.begin(),
362 E = nodeToAttributesMap.end(); I != E; ++I)
363 maxASAP = std::max(maxASAP, I->second.ASAP);
368 void ModuloSchedulingPass::calculateHeight(MSchedGraphNode *node,
369 MSNodeAttributes &attributes,
370 std::set<MSchedGraphNode*> &visitedNodes) {
372 if(attributes.depth != -1 || (visitedNodes.find(node) != visitedNodes.end())) {
373 //Remove from map before returning
374 visitedNodes.erase(node);
378 if(node->hasSuccessors()) {
381 //Iterate over all of the predecessors and fine max
382 for(MSchedGraphNode::succ_iterator P = node->succ_begin(),
383 E = node->succ_end(); P != E; ++P) {
385 MSNodeAttributes succAttributes = nodeToAttributesMap.find(*P)->second;
386 if(succAttributes.height == -1) {
388 //Put into map before recursing
389 visitedNodes.insert(node);
391 calculateHeight(*P, succAttributes, visitedNodes);
392 succAttributes = nodeToAttributesMap.find(*P)->second;
393 assert(succAttributes.height == -1 && "Successors Height should have been caclulated");
395 int currentHeight = succAttributes.height + node->getLatency();
396 maxHeight = std::max(maxHeight, currentHeight);
398 visitedNodes.erase(node);
399 attributes.height = maxHeight;
402 visitedNodes.erase(node);
403 attributes.height = 0;
406 DEBUG(std::cerr << "Height: " << attributes.height << " (" << *node << ")\n");
410 void ModuloSchedulingPass::calculateDepth(MSchedGraphNode *node,
411 MSNodeAttributes &attributes,
412 std::set<MSchedGraphNode*> &visitedNodes) {
414 if(attributes.depth != -1 || (visitedNodes.find(node) != visitedNodes.end())) {
415 //Remove from map before returning
416 visitedNodes.erase(node);
420 if(node->hasPredecessors()) {
423 //Iterate over all of the predecessors and fine max
424 for(MSchedGraphNode::pred_iterator P = node->pred_begin(), E = node->pred_end(); P != E; ++P) {
426 //Get that nodes depth
427 MSNodeAttributes predAttributes = nodeToAttributesMap.find(*P)->second;
428 if(predAttributes.depth == -1) {
430 //Put into set before recursing
431 visitedNodes.insert(node);
433 calculateDepth(*P, predAttributes, visitedNodes);
434 predAttributes = nodeToAttributesMap.find(*P)->second;
435 assert(predAttributes.depth == -1 && "Predecessors ASAP should have been caclulated");
437 int currentDepth = predAttributes.depth + node->getLatency();
438 maxDepth = std::max(maxDepth, currentDepth);
441 //Remove from map before returning
442 visitedNodes.erase(node);
444 attributes.height = maxDepth;
447 //Remove from map before returning
448 visitedNodes.erase(node);
449 attributes.depth = 0;
452 DEBUG(std::cerr << "Depth: " << attributes.depth << " (" << *node << "*)\n");
457 void ModuloSchedulingPass::findAllReccurrences(MSchedGraphNode *node,
458 std::vector<MSchedGraphNode*> &visitedNodes) {
460 if(find(visitedNodes.begin(), visitedNodes.end(), node) != visitedNodes.end()) {
461 //DUMP out recurrence
462 DEBUG(std::cerr << "Reccurrence:\n");
464 for(std::vector<MSchedGraphNode*>::iterator I = visitedNodes.begin(), E = visitedNodes.end();
470 DEBUG(std::cerr << **I << "\n");
472 DEBUG(std::cerr << "End Reccurrence:\n");
476 for(MSchedGraphNode::succ_iterator I = node->succ_begin(), E = node->succ_end(); I != E; ++I) {
477 visitedNodes.push_back(node);
478 findAllReccurrences(*I, visitedNodes);
479 visitedNodes.pop_back();
492 void ModuloSchedulingPass::orderNodes() {
497 //FIXME: Group nodes into sets and order all the sets based on RecMII
498 typedef std::vector<MSchedGraphNode*> NodeVector;
499 typedef std::pair<int, NodeVector> NodeSet;
501 std::vector<NodeSet> NodeSetsToOrder;
503 //Order the resulting sets
504 NodeVector FinalNodeOrder;
506 //Loop over all the sets and place them in the final node order
507 for(unsigned i=0; i < NodeSetsToOrder.size(); ++i) {
510 int order = BOTTOM_UP;
512 //Get Nodes in Current set
513 NodeVector CurrentSet = NodeSetsToOrder[i].second;
515 //Loop through the predecessors for each node in the final order
516 //and only keeps nodes both in the pred_set and currentset
517 NodeVector IntersectCurrent;
519 //Sort CurrentSet so we can use lowerbound
520 sort(CurrentSet.begin(), CurrentSet.end());
522 for(unsigned j=0; j < FinalNodeOrder.size(); ++j) {
523 for(MSchedGraphNode::pred_iterator P = FinalNodeOrder[j]->pred_begin(),
524 E = FinalNodeOrder[j]->pred_end(); P != E; ++P) {
525 if(lower_bound(CurrentSet.begin(),
526 CurrentSet.end(), *P) != CurrentSet.end())
527 IntersectCurrent.push_back(*P);
531 //If the intersection of predecessor and current set is not empty
532 //sort nodes bottom up
533 if(IntersectCurrent.size() != 0)
536 //If empty, use successors
539 for(unsigned j=0; j < FinalNodeOrder.size(); ++j) {
540 for(MSchedGraphNode::succ_iterator P = FinalNodeOrder[j]->succ_begin(),
541 E = FinalNodeOrder[j]->succ_end(); P != E; ++P) {
542 if(lower_bound(CurrentSet.begin(),
543 CurrentSet.end(), *P) != CurrentSet.end())
544 IntersectCurrent.push_back(*P);
549 if(IntersectCurrent.size() != 0)
553 //Find node with max ASAP in current Set
554 MSchedGraphNode *node;
556 for(unsigned j=0; j < CurrentSet.size(); ++j) {
557 //Get node attributes
558 MSNodeAttributes nodeAttr= nodeToAttributesMap.find(CurrentSet[j])->second;
559 //assert(nodeAttr != nodeToAttributesMap.end() && "Node not in attributes map!");
561 if(maxASAP < nodeAttr.ASAP) {
562 maxASAP = nodeAttr.ASAP;
563 node = CurrentSet[j];
570 //Repeat until all nodes are put into the final order from current set
571 /*while(IntersectCurrent.size() > 0) {
573 if(order == TOP_DOWN) {
574 while(IntersectCurrent.size() > 0) {
577 //Get node attributes
578 MSNodeAttributes nodeAttr= nodeToAttributesMap.find(IntersectCurrent[0])->second;
579 assert(nodeAttr != nodeToAttributesMap.end() && "Node not in attributes map!");
581 //Get node with highest height, if a tie, use one with lowest
583 int MOB = nodeAttr.MBO;
584 int height = nodeAttr.height;
585 ModuloSchedGraphNode *V = IntersectCurrent[0];
587 for(unsigned j=0; j < IntersectCurrent.size(); ++j) {
588 int temp = IntersectCurrent[j]->getHeight();
590 V = IntersectCurrent[j];
592 MOB = V->getMobility();
594 else if(height == temp) {
595 if(MOB > IntersectCurrent[j]->getMobility()) {
596 V = IntersectCurrent[j];
598 MOB = V->getMobility();
603 //Append V to the NodeOrder
604 NodeOrder.push_back(V);
606 //Remove V from IntersectOrder
607 IntersectCurrent.erase(find(IntersectCurrent.begin(),
608 IntersectCurrent.end(), V));
610 //Intersect V's successors with CurrentSet
611 for(mod_succ_iterator P = succ_begin(V),
612 E = succ_end(V); P != E; ++P) {
613 if(lower_bound(CurrentSet.begin(),
614 CurrentSet.end(), *P) != CurrentSet.end()) {
615 //If not already in Intersect, add
616 if(find(IntersectCurrent.begin(), IntersectCurrent.end(), *P) == IntersectCurrent.end())
617 IntersectCurrent.push_back(*P);
620 } //End while loop over Intersect Size
625 //Reset Intersect to reflect changes in OrderNodes
626 IntersectCurrent.clear();
627 for(unsigned j=0; j < NodeOrder.size(); ++j) {
628 for(mod_pred_iterator P = pred_begin(NodeOrder[j]),
629 E = pred_end(NodeOrder[j]); P != E; ++P) {
630 if(lower_bound(CurrentSet.begin(),
631 CurrentSet.end(), *P) != CurrentSet.end())
632 IntersectCurrent.push_back(*P);
639 while(IntersectCurrent.size() > 0) {
640 //Get node with highest depth, if a tie, use one with lowest
642 int MOB = IntersectCurrent[0]->getMobility();
643 int depth = IntersectCurrent[0]->getDepth();
644 ModuloSchedGraphNode *V = IntersectCurrent[0];
646 for(unsigned j=0; j < IntersectCurrent.size(); ++j) {
647 int temp = IntersectCurrent[j]->getDepth();
649 V = IntersectCurrent[j];
651 MOB = V->getMobility();
653 else if(depth == temp) {
654 if(MOB > IntersectCurrent[j]->getMobility()) {
655 V = IntersectCurrent[j];
657 MOB = V->getMobility();
662 //Append V to the NodeOrder
663 NodeOrder.push_back(V);
665 //Remove V from IntersectOrder
666 IntersectCurrent.erase(find(IntersectCurrent.begin(),
667 IntersectCurrent.end(),V));
669 //Intersect V's pred with CurrentSet
670 for(mod_pred_iterator P = pred_begin(V),
671 E = pred_end(V); P != E; ++P) {
672 if(lower_bound(CurrentSet.begin(),
673 CurrentSet.end(), *P) != CurrentSet.end()) {
674 //If not already in Intersect, add
675 if(find(IntersectCurrent.begin(), IntersectCurrent.end(), *P) == IntersectCurrent.end())
676 IntersectCurrent.push_back(*P);
679 } //End while loop over Intersect Size
684 //Reset IntersectCurrent to reflect changes in OrderNodes
685 IntersectCurrent.clear();
686 for(unsigned j=0; j < NodeOrder.size(); ++j) {
687 for(mod_succ_iterator P = succ_begin(NodeOrder[j]),
688 E = succ_end(NodeOrder[j]); P != E; ++P) {
689 if(lower_bound(CurrentSet.begin(),
690 CurrentSet.end(), *P) != CurrentSet.end())
691 IntersectCurrent.push_back(*P);
695 } //End if BOTTOM_DOWN
698 //End Wrapping while loop
700 }//End for over all sets of nodes
703 //return FinalNodeOrder;