1 //===- ModuloScheduling.cpp - Modulo Software Pipelining ------------------===//
3 // Implements the llvm/CodeGen/ModuloScheduling.h interface
5 //===----------------------------------------------------------------------===//
7 //#include "llvm/CodeGen/MachineCodeForBasicBlock.h"
8 //#include "llvm/CodeGen/MachineCodeForMethod.h"
9 //#include "llvm/Analysis/LiveVar/FunctionLiveVarInfo.h" // FIXME: Remove when modularized better
10 #include "llvm/BasicBlock.h"
11 #include "llvm/Constants.h"
12 #include "llvm/Instruction.h"
13 #include "llvm/iTerminators.h"
14 #include "llvm/iPHINode.h"
15 #include "llvm/CodeGen/MachineInstr.h"
16 #include "llvm/CodeGen/MachineCodeForInstruction.h"
17 #include "llvm/CodeGen/MachineFunction.h"
18 #include "llvm/CodeGen/InstrSelection.h"
19 #include "llvm/Target/TargetSchedInfo.h"
20 #include "llvm/Target/TargetMachine.h"
21 #include "Support/CommandLine.h"
22 #include "Support/Statistic.h"
23 #include "ModuloSchedGraph.h"
24 #include "ModuloScheduling.h"
31 //************************************************************
32 // printing Debug information
33 // ModuloSchedDebugLevel stores the value of debug level
34 // modsched_os is the ostream to dump debug information, which is written into
35 // the file 'moduloSchedDebugInfo.output'
36 // see ModuloSchedulingPass::runOnFunction()
37 //************************************************************
39 ModuloSchedDebugLevel_t ModuloSchedDebugLevel;
41 cl::opt<ModuloSchedDebugLevel_t,true>
42 SDL_opt("modsched", cl::Hidden, cl::location(ModuloSchedDebugLevel),
43 cl::desc("enable modulo scheduling debugging information"),
44 cl::values(clEnumValN(ModuloSchedDebugLevel_NoDebugInfo,
45 "none", "disable debug output"),
46 clEnumValN(ModuloSchedDebugLevel_PrintSchedule,
47 "psched", "print original and new schedule"),
48 clEnumValN(ModuloSchedDebugLevel_PrintScheduleProcess,
50 "print how the new schdule is produced"),
53 // Computes the schedule and inserts epilogue and prologue
55 void ModuloScheduling::instrScheduling()
58 printf(" instrScheduling \n");
60 if (ModuloScheduling::printScheduleProcess())
61 DEBUG_PRINT(std::cerr << "************ computing modulo schedule ***********\n");
63 const TargetSchedInfo & msi = target.getSchedInfo();
65 //number of issue slots in the in each cycle
66 int numIssueSlots = msi.maxNumIssueTotal;
68 //compute the schedule
71 //clear memory from the last round and initialize if necessary
74 //compute schedule and coreSchedule with the current II
75 success = computeSchedule();
79 if (ModuloScheduling::printScheduleProcess())
80 DEBUG_PRINT(std::cerr << "increase II to " << II << "\n");
84 //print the final schedule if necessary
85 if (ModuloScheduling::printSchedule())
88 //the schedule has been computed
89 //create epilogue, prologue and kernel BasicBlock
91 //find the successor for this BasicBlock
92 BasicBlock *succ_bb = getSuccBB(bb);
94 //print the original BasicBlock if necessary
95 if (ModuloScheduling::printSchedule()) {
96 DEBUG_PRINT(std::cerr << "dumping the orginal block\n");
99 //construction of prologue, kernel and epilogue
102 BasicBlock *kernel = bb->splitBasicBlock(bb->begin());
103 BasicBlock *prologue = bb;
104 BasicBlock *epilogue = kernel->splitBasicBlock(kernel->begin());
107 // Construct prologue
108 /*constructPrologue(prologue);*/
112 /*constructKernel(prologue, kernel, epilogue);*/
114 // Construct epilogue
116 /*constructEpilogue(epilogue, succ_bb);*/
118 //print the BasicBlocks if necessary
120 // DEBUG_PRINT(std::cerr << "dumping the prologue block:\n");
121 // graph.dump(prologue);
122 // DEBUG_PRINT(std::cerr << "dumping the kernel block\n");
123 // graph.dump(kernel);
124 // DEBUG_PRINT(std::cerr << "dumping the epilogue block\n");
125 // graph.dump(epilogue);
130 // Clear memory from the last round and initialize if necessary
132 void ModuloScheduling::clearInitMem(const TargetSchedInfo & msi)
134 unsigned numIssueSlots = msi.maxNumIssueTotal;
135 // clear nodeScheduled from the last round
136 if (ModuloScheduling::printScheduleProcess()) {
137 DEBUG_PRINT(std::cerr << "***** new round with II= " << II << " ***********\n");
138 DEBUG_PRINT(std::cerr <<
139 " ************clear the vector nodeScheduled*************\n");
141 nodeScheduled.clear();
143 // clear resourceTable from the last round and reset it
144 resourceTable.clear();
145 for (unsigned i = 0; i < II; ++i)
146 resourceTable.push_back(msi.resourceNumVector);
148 // clear the schdule and coreSchedule from the last round
150 coreSchedule.clear();
152 // create a coreSchedule of size II*numIssueSlots
153 // each entry is NULL
154 while (coreSchedule.size() < II) {
155 std::vector < ModuloSchedGraphNode * >*newCycle =
156 new std::vector < ModuloSchedGraphNode * >();
157 for (unsigned k = 0; k < numIssueSlots; ++k)
158 newCycle->push_back(NULL);
159 coreSchedule.push_back(*newCycle);
163 // Compute schedule and coreSchedule with the current II
165 bool ModuloScheduling::computeSchedule()
168 if (ModuloScheduling::printScheduleProcess())
169 DEBUG_PRINT(std::cerr << "start to compute schedule\n");
171 // Loop over the ordered nodes
172 for (NodeVec::const_iterator I = oNodes.begin(); I != oNodes.end(); ++I) {
173 // Try to schedule for node I
174 if (ModuloScheduling::printScheduleProcess())
176 ModuloSchedGraphNode *node = *I;
178 // Compute whether this node has successor(s)
181 // Compute whether this node has predessor(s)
184 NodeVec schSucc = graph.vectorConj(nodeScheduled, graph.succSet(node));
187 NodeVec schPred = graph.vectorConj(nodeScheduled, graph.predSet(node));
191 //startTime: the earliest time we will try to schedule this node
192 //endTime: the latest time we will try to schedule this node
193 int startTime, endTime;
195 //node's earlyStart: possible earliest time to schedule this node
196 //node's lateStart: possible latest time to schedule this node
197 node->setEarlyStart(-1);
198 node->setLateStart(9999);
200 //this node has predessor but no successor
202 // This node's earlyStart is it's predessor's schedule time + the edge
203 // delay - the iteration difference* II
204 for (unsigned i = 0; i < schPred.size(); i++) {
205 ModuloSchedGraphNode *predNode = schPred[i];
206 SchedGraphEdge *edge =
207 graph.getMaxDelayEdge(predNode->getNodeId(),
210 predNode->getSchTime() + edge->getMinDelay() -
211 edge->getIteDiff() * II;
212 node->setEarlyStart(std::max(node->getEarlyStart(), temp));
214 startTime = node->getEarlyStart();
215 endTime = node->getEarlyStart() + II - 1;
217 // This node has a successor but no predecessor
219 for (unsigned i = 0; i < schSucc.size(); ++i) {
220 ModuloSchedGraphNode *succNode = schSucc[i];
221 SchedGraphEdge *edge =
222 graph.getMaxDelayEdge(succNode->getNodeId(),
225 succNode->getSchTime() - edge->getMinDelay() +
226 edge->getIteDiff() * II;
227 node->setLateStart(std::min(node->getEarlyStart(), temp));
229 startTime = node->getLateStart() - II + 1;
230 endTime = node->getLateStart();
232 // This node has both successors and predecessors
234 for (unsigned i = 0; i < schPred.size(); ++i) {
235 ModuloSchedGraphNode *predNode = schPred[i];
236 SchedGraphEdge *edge =
237 graph.getMaxDelayEdge(predNode->getNodeId(),
240 predNode->getSchTime() + edge->getMinDelay() -
241 edge->getIteDiff() * II;
242 node->setEarlyStart(std::max(node->getEarlyStart(), temp));
244 for (unsigned i = 0; i < schSucc.size(); ++i) {
245 ModuloSchedGraphNode *succNode = schSucc[i];
246 SchedGraphEdge *edge =
247 graph.getMaxDelayEdge(succNode->getNodeId(),
250 succNode->getSchTime() - edge->getMinDelay() +
251 edge->getIteDiff() * II;
252 node->setLateStart(std::min(node->getEarlyStart(), temp));
254 startTime = node->getEarlyStart();
255 endTime = std::min(node->getLateStart(),
256 node->getEarlyStart() + ((int) II) - 1);
258 //this node has no successor or predessor
259 if (!succ && !pred) {
260 node->setEarlyStart(node->getASAP());
261 startTime = node->getEarlyStart();
262 endTime = node->getEarlyStart() + II - 1;
264 //try to schedule this node based on the startTime and endTime
265 if (ModuloScheduling::printScheduleProcess())
266 DEBUG_PRINT(std::cerr << "scheduling the node " << (*I)->getNodeId() << "\n");
269 this->ScheduleNode(node, startTime, endTime, nodeScheduled);
277 // Get the successor of the BasicBlock
279 BasicBlock *ModuloScheduling::getSuccBB(BasicBlock *bb)
282 for (unsigned i = 0; i < II; ++i)
283 for (unsigned j = 0; j < coreSchedule[i].size(); ++j)
284 if (coreSchedule[i][j]) {
285 const Instruction *ist = coreSchedule[i][j]->getInst();
287 //we can get successor from the BranchInst instruction
288 //assume we only have one successor (besides itself) here
289 if (BranchInst::classof(ist)) {
290 BranchInst *bi = (BranchInst *) ist;
291 assert(bi->isConditional() &&
292 "the branchInst is not a conditional one");
293 assert(bi->getNumSuccessors() == 2
294 && " more than two successors?");
295 BasicBlock *bb1 = bi->getSuccessor(0);
296 BasicBlock *bb2 = bi->getSuccessor(1);
297 assert((bb1 == bb || bb2 == bb) &&
298 " None of its successors is itself?");
306 assert(0 && "NO Successor?");
311 // Get the predecessor of the BasicBlock
313 BasicBlock *ModuloScheduling::getPredBB(BasicBlock *bb)
316 for (unsigned i = 0; i < II; ++i)
317 for (unsigned j = 0; j < coreSchedule[i].size(); ++j)
318 if (coreSchedule[i][j]) {
319 const Instruction *ist = coreSchedule[i][j]->getInst();
321 //we can get predecessor from the PHINode instruction
322 //assume we only have one predecessor (besides itself) here
323 if (PHINode::classof(ist)) {
324 PHINode *phi = (PHINode *) ist;
325 assert(phi->getNumIncomingValues() == 2 &&
326 " the number of incoming value is not equal to two? ");
327 BasicBlock *bb1 = phi->getIncomingBlock(0);
328 BasicBlock *bb2 = phi->getIncomingBlock(1);
329 assert((bb1 == bb || bb2 == bb) &&
330 " None of its predecessor is itself?");
338 assert(0 && " no predecessor?");
343 // Construct the prologue
345 void ModuloScheduling::constructPrologue(BasicBlock *prologue)
347 InstListType & prologue_ist = prologue->getInstList();
348 vvNodeType & tempSchedule_prologue =
349 *(new std::vector<std::vector<ModuloSchedGraphNode*> >(schedule));
351 //compute the schedule for prologue
353 unsigned scheduleSize = schedule.size();
354 while (round < scheduleSize / II) {
356 for (unsigned i = 0; i < scheduleSize; ++i) {
357 if (round * II + i >= scheduleSize)
359 for (unsigned j = 0; j < schedule[i].size(); ++j) {
360 if (schedule[i][j]) {
361 assert(tempSchedule_prologue[round * II + i][j] == NULL &&
362 "table not consitent with core table");
363 // move the schedule one iteration ahead and overlap with the original
364 tempSchedule_prologue[round * II + i][j] = schedule[i][j];
370 // Clear the clone memory in the core schedule instructions
373 // Fill in the prologue
374 for (unsigned i = 0; i < ceil(1.0 * scheduleSize / II - 1) * II; ++i)
375 for (unsigned j = 0; j < tempSchedule_prologue[i].size(); ++j)
376 if (tempSchedule_prologue[i][j]) {
378 //get the instruction
380 (Instruction *) tempSchedule_prologue[i][j]->getInst();
383 Instruction *cln = cloneInstSetMemory(orn);
385 //insert the instruction
386 prologue_ist.insert(prologue_ist.back(), cln);
388 //if there is PHINode in the prologue, the incoming value from itself
389 //should be removed because it is not a loop any longer
390 if (PHINode::classof(cln)) {
391 PHINode *phi = (PHINode *) cln;
392 phi->removeIncomingValue(phi->getParent());
398 // Construct the kernel BasicBlock
400 void ModuloScheduling::constructKernel(BasicBlock *prologue,
402 BasicBlock *epilogue)
404 //*************fill instructions in the kernel****************
405 InstListType & kernel_ist = kernel->getInstList();
406 BranchInst *brchInst;
407 PHINode *phiInst, *phiCln;
409 for (unsigned i = 0; i < coreSchedule.size(); ++i)
410 for (unsigned j = 0; j < coreSchedule[i].size(); ++j)
411 if (coreSchedule[i][j]) {
413 // Take care of branch instruction differently with normal instructions
414 if (BranchInst::classof(coreSchedule[i][j]->getInst())) {
415 brchInst = (BranchInst *) coreSchedule[i][j]->getInst();
418 // Take care of PHINode instruction differently with normal instructions
419 if (PHINode::classof(coreSchedule[i][j]->getInst())) {
420 phiInst = (PHINode *) coreSchedule[i][j]->getInst();
421 Instruction *cln = cloneInstSetMemory(phiInst);
422 kernel_ist.insert(kernel_ist.back(), cln);
423 phiCln = (PHINode *) cln;
426 //for normal instructions: made a clone and insert it in the kernel_ist
428 cloneInstSetMemory((Instruction *) coreSchedule[i][j]->
430 kernel_ist.insert(kernel_ist.back(), cln);
432 // The two incoming BasicBlock for PHINode is the prologue and the kernel
434 phiCln->setIncomingBlock(0, prologue);
435 phiCln->setIncomingBlock(1, kernel);
437 // The incoming value for the kernel (itself) is the new value which is
438 // computed in the kernel
439 Instruction *originalVal = (Instruction *) phiInst->getIncomingValue(1);
440 phiCln->setIncomingValue(1, originalVal->getClone());
442 // Make a clone of the branch instruction and insert it in the end
443 BranchInst *cln = (BranchInst *) cloneInstSetMemory(brchInst);
444 kernel_ist.insert(kernel_ist.back(), cln);
446 // delete the unconditional branch instruction, which is generated when
447 // splitting the basicBlock
448 kernel_ist.erase(--kernel_ist.end());
450 // set the first successor to itself
451 ((BranchInst *) cln)->setSuccessor(0, kernel);
452 // set the second successor to eiplogue
453 ((BranchInst *) cln)->setSuccessor(1, epilogue);
455 //*****change the condition*******
457 //get the condition instruction
458 Instruction *cond = (Instruction *) cln->getCondition();
460 //get the condition's second operand, it should be a constant
461 Value *operand = cond->getOperand(1);
462 assert(ConstantSInt::classof(operand));
464 //change the constant in the condtion instruction
465 ConstantSInt *iteTimes =
466 ConstantSInt::get(operand->getType(),
467 ((ConstantSInt *) operand)->getValue() - II + 1);
468 cond->setOperand(1, iteTimes);
473 // Construct the epilogue
475 void ModuloScheduling::constructEpilogue(BasicBlock *epilogue,
479 //compute the schedule for epilogue
480 vvNodeType &tempSchedule_epilogue =
481 *(new std::vector<std::vector<ModuloSchedGraphNode*> >(schedule));
482 unsigned scheduleSize = schedule.size();
484 while (round < ceil(1.0 * scheduleSize / II) - 1) {
486 for (unsigned i = 0; i < scheduleSize; i++) {
487 if (i + round * II >= scheduleSize)
489 for (unsigned j = 0; j < schedule[i].size(); j++)
490 if (schedule[i + round * II][j]) {
491 assert(tempSchedule_epilogue[i][j] == NULL
492 && "table not consitant with core table");
494 //move the schdule one iteration behind and overlap
495 tempSchedule_epilogue[i][j] = schedule[i + round * II][j];
500 //fill in the epilogue
501 InstListType & epilogue_ist = epilogue->getInstList();
502 for (unsigned i = II; i < scheduleSize; i++)
503 for (unsigned j = 0; j < tempSchedule_epilogue[i].size(); j++)
504 if (tempSchedule_epilogue[i][j]) {
506 (Instruction *) tempSchedule_epilogue[i][j]->getInst();
508 //BranchInst and PHINode should be treated differently
509 //BranchInst:unecessary, simly omitted
511 if (!BranchInst::classof(inst) && !PHINode::classof(inst)) {
512 //make a clone instruction and insert it into the epilogue
513 Instruction *cln = cloneInstSetMemory(inst);
514 epilogue_ist.push_front(cln);
518 //*************delete the original instructions****************//
519 //to delete the original instructions, we have to make sure their use is zero
521 //update original core instruction's uses, using its clone instread
522 for (unsigned i = 0; i < II; i++)
523 for (unsigned j = 0; j < coreSchedule[i].size(); j++) {
524 if (coreSchedule[i][j])
525 updateUseWithClone((Instruction *) coreSchedule[i][j]->getInst());
528 //erase these instructions
529 for (unsigned i = 0; i < II; i++)
530 for (unsigned j = 0; j < coreSchedule[i].size(); j++)
531 if (coreSchedule[i][j]) {
532 Instruction *ist = (Instruction *) coreSchedule[i][j]->getInst();
533 ist->getParent()->getInstList().erase(ist);
538 //finally, insert an unconditional branch instruction at the end
539 epilogue_ist.push_back(new BranchInst(succ_bb));
544 //------------------------------------------------------------------------------
545 //this function replace the value(instruction) ist in other instructions with
546 //its latest clone i.e. after this function is called, the ist is not used
547 //anywhere and it can be erased.
548 //------------------------------------------------------------------------------
549 void ModuloScheduling::updateUseWithClone(Instruction * ist)
552 while (ist->use_size() > 0) {
553 bool destroyed = false;
555 //other instruction is using this value ist
556 assert(Instruction::classof(*ist->use_begin()));
557 Instruction *inst = (Instruction *) (*ist->use_begin());
559 for (unsigned i = 0; i < inst->getNumOperands(); i++)
560 if (inst->getOperand(i) == ist && ist->getClone()) {
561 // if the instruction is TmpInstruction, simly delete it because it has
562 // no parent and it does not belongs to any BasicBlock
563 if (TmpInstruction::classof(inst)) {
569 //otherwise, set the instruction's operand to the value's clone
570 inst->setOperand(i, ist->getClone());
572 //the use from the original value ist is destroyed
577 //if the use can not be destroyed , something is wrong
579 assert(0 && "this use can not be destroyed");
586 //********************************************************
587 //this function clear all clone mememoy
588 //i.e. set all instruction's clone memory to NULL
589 //*****************************************************
590 void ModuloScheduling::clearCloneMemory()
592 for (unsigned i = 0; i < coreSchedule.size(); i++)
593 for (unsigned j = 0; j < coreSchedule[i].size(); j++)
594 if (coreSchedule[i][j])
595 ((Instruction *) coreSchedule[i][j]->getInst())->clearClone();
600 //******************************************************************************
601 // this function make a clone of the instruction orn the cloned instruction will
602 // use the orn's operands' latest clone as its operands it is done this way
603 // because LLVM is in SSA form and we should use the correct value
604 //this fuction also update the instruction orn's latest clone memory
605 //******************************************************************************
606 Instruction *ModuloScheduling::cloneInstSetMemory(Instruction * orn)
608 // make a clone instruction
609 Instruction *cln = orn->clone();
611 // update the operands
612 for (unsigned k = 0; k < orn->getNumOperands(); k++) {
613 const Value *op = orn->getOperand(k);
614 if (Instruction::classof(op) && ((Instruction *) op)->getClone()) {
615 Instruction *op_inst = (Instruction *) op;
616 cln->setOperand(k, op_inst->getClone());
620 // update clone memory
627 bool ModuloScheduling::ScheduleNode(ModuloSchedGraphNode * node,
628 unsigned start, unsigned end,
629 NodeVec & nodeScheduled)
631 const TargetSchedInfo & msi = target.getSchedInfo();
632 unsigned int numIssueSlots = msi.maxNumIssueTotal;
634 if (ModuloScheduling::printScheduleProcess())
635 DEBUG_PRINT(std::cerr << "startTime= " << start << " endTime= " << end << "\n");
636 bool isScheduled = false;
637 for (unsigned i = start; i <= end; i++) {
638 if (ModuloScheduling::printScheduleProcess())
639 DEBUG_PRINT(std::cerr << " now try cycle " << i << ":" << "\n");
640 for (unsigned j = 0; j < numIssueSlots; j++) {
641 unsigned int core_i = i % II;
642 unsigned int core_j = j;
643 if (ModuloScheduling::printScheduleProcess())
644 DEBUG_PRINT(std::cerr << "\t Trying slot " << j << "...........");
645 //check the resouce table, make sure there is no resource conflicts
646 const Instruction *instr = node->getInst();
647 MachineCodeForInstruction & tempMvec =
648 MachineCodeForInstruction::get(instr);
649 bool resourceConflict = false;
650 const TargetInstrInfo & mii = msi.getInstrInfo();
652 if (coreSchedule.size() < core_i + 1
653 || !coreSchedule[core_i][core_j]) {
654 //this->dumpResourceUsageTable();
656 for (unsigned k = 0; k < tempMvec.size(); k++) {
657 MachineInstr *minstr = tempMvec[k];
658 InstrRUsage rUsage = msi.getInstrRUsage(minstr->getOpCode());
659 std::vector < std::vector < resourceId_t > >resources
660 = rUsage.resourcesByCycle;
661 updateResourceTable(resources, i + latency);
662 latency += std::max(mii.minLatency(minstr->getOpCode()), 1);
665 //this->dumpResourceUsageTable();
668 if (resourceTableNegative()) {
670 //undo-update the resource table
671 for (unsigned k = 0; k < tempMvec.size(); k++) {
672 MachineInstr *minstr = tempMvec[k];
673 InstrRUsage rUsage = msi.getInstrRUsage(minstr->getOpCode());
674 std::vector < std::vector < resourceId_t > >resources
675 = rUsage.resourcesByCycle;
676 undoUpdateResourceTable(resources, i + latency);
677 latency += std::max(mii.minLatency(minstr->getOpCode()), 1);
679 resourceConflict = true;
682 if (!resourceConflict && !coreSchedule[core_i][core_j]) {
683 if (ModuloScheduling::printScheduleProcess()) {
684 DEBUG_PRINT(std::cerr << " OK!" << "\n");
685 DEBUG_PRINT(std::cerr << "Node " << node->getNodeId() << " scheduled.\n");
687 //schedule[i][j]=node;
688 while (schedule.size() <= i) {
689 std::vector < ModuloSchedGraphNode * >*newCycle =
690 new std::vector < ModuloSchedGraphNode * >();
691 for (unsigned k = 0; k < numIssueSlots; k++)
692 newCycle->push_back(NULL);
693 schedule.push_back(*newCycle);
695 std::vector<ModuloSchedGraphNode*>::iterator startIterator;
696 startIterator = schedule[i].begin();
697 schedule[i].insert(startIterator + j, node);
698 startIterator = schedule[i].begin();
699 schedule[i].erase(startIterator + j + 1);
701 //update coreSchedule
702 //coreSchedule[core_i][core_j]=node;
703 while (coreSchedule.size() <= core_i) {
704 std::vector<ModuloSchedGraphNode*> *newCycle =
705 new std::vector<ModuloSchedGraphNode*>();
706 for (unsigned k = 0; k < numIssueSlots; k++)
707 newCycle->push_back(NULL);
708 coreSchedule.push_back(*newCycle);
711 startIterator = coreSchedule[core_i].begin();
712 coreSchedule[core_i].insert(startIterator + core_j, node);
713 startIterator = coreSchedule[core_i].begin();
714 coreSchedule[core_i].erase(startIterator + core_j + 1);
718 nodeScheduled.push_back(node);
721 } else if (coreSchedule[core_i][core_j]) {
722 if (ModuloScheduling::printScheduleProcess())
723 DEBUG_PRINT(std::cerr << " Slot not available\n");
725 if (ModuloScheduling::printScheduleProcess())
726 DEBUG_PRINT(std::cerr << " Resource conflicts\n");
732 //assert(nodeScheduled &&"this node can not be scheduled?");
737 void ModuloScheduling::updateResourceTable(Resources useResources,
740 for (unsigned i = 0; i < useResources.size(); i++) {
741 int absCycle = startCycle + i;
742 int coreCycle = absCycle % II;
743 std::vector<std::pair<int,int> > &resourceRemained =
744 resourceTable[coreCycle];
745 std::vector < unsigned int >&resourceUsed = useResources[i];
746 for (unsigned j = 0; j < resourceUsed.size(); j++) {
747 for (unsigned k = 0; k < resourceRemained.size(); k++)
748 if ((int) resourceUsed[j] == resourceRemained[k].first) {
749 resourceRemained[k].second--;
755 void ModuloScheduling::undoUpdateResourceTable(Resources useResources,
758 for (unsigned i = 0; i < useResources.size(); i++) {
759 int absCycle = startCycle + i;
760 int coreCycle = absCycle % II;
761 std::vector<std::pair<int,int> > &resourceRemained =
762 resourceTable[coreCycle];
763 std::vector < unsigned int >&resourceUsed = useResources[i];
764 for (unsigned j = 0; j < resourceUsed.size(); j++) {
765 for (unsigned k = 0; k < resourceRemained.size(); k++)
766 if ((int) resourceUsed[j] == resourceRemained[k].first) {
767 resourceRemained[k].second++;
774 //-----------------------------------------------------------------------
775 // Function: resourceTableNegative
777 // return false if any element in the resouceTable is negative
778 // otherwise return true
781 // this function is used to determine if an instruction is eligible for
782 // schedule at certain cycle
783 //-----------------------------------------------------------------------
786 bool ModuloScheduling::resourceTableNegative()
788 assert(resourceTable.size() == (unsigned) II
789 && "resouceTable size must be equal to II");
790 bool isNegative = false;
791 for (unsigned i = 0; i < resourceTable.size(); i++)
792 for (unsigned j = 0; j < resourceTable[i].size(); j++) {
793 if (resourceTable[i][j].second < 0) {
802 //----------------------------------------------------------------------
803 // Function: dumpResouceUsageTable
805 // print out ResouceTable for debug
807 //------------------------------------------------------------------------
809 void ModuloScheduling::dumpResourceUsageTable()
811 DEBUG_PRINT(std::cerr << "dumping resource usage table\n");
812 for (unsigned i = 0; i < resourceTable.size(); i++) {
813 for (unsigned j = 0; j < resourceTable[i].size(); j++)
814 DEBUG_PRINT(std::cerr << resourceTable[i][j].first
815 << ":" << resourceTable[i][j].second << " ");
816 DEBUG_PRINT(std::cerr << "\n");
821 //----------------------------------------------------------------------
822 //Function: dumpSchedule
824 // print out thisSchedule for debug
826 //-----------------------------------------------------------------------
827 void ModuloScheduling::dumpSchedule(vvNodeType thisSchedule)
829 const TargetSchedInfo & msi = target.getSchedInfo();
830 unsigned numIssueSlots = msi.maxNumIssueTotal;
831 for (unsigned i = 0; i < numIssueSlots; i++)
832 DEBUG_PRINT(std::cerr << "\t#");
833 DEBUG_PRINT(std::cerr << "\n");
834 for (unsigned i = 0; i < thisSchedule.size(); i++) {
835 DEBUG_PRINT(std::cerr << "cycle" << i << ": ");
836 for (unsigned j = 0; j < thisSchedule[i].size(); j++)
837 if (thisSchedule[i][j] != NULL)
838 DEBUG_PRINT(std::cerr << thisSchedule[i][j]->getNodeId() << "\t");
840 DEBUG_PRINT(std::cerr << "\t");
841 DEBUG_PRINT(std::cerr << "\n");
846 //----------------------------------------------------
847 //Function: dumpScheduling
849 // print out the schedule and coreSchedule for debug
851 //-------------------------------------------------------
853 void ModuloScheduling::dumpScheduling()
855 DEBUG_PRINT(std::cerr << "dump schedule:" << "\n");
856 const TargetSchedInfo & msi = target.getSchedInfo();
857 unsigned numIssueSlots = msi.maxNumIssueTotal;
858 for (unsigned i = 0; i < numIssueSlots; i++)
859 DEBUG_PRINT(std::cerr << "\t#");
860 DEBUG_PRINT(std::cerr << "\n");
861 for (unsigned i = 0; i < schedule.size(); i++) {
862 DEBUG_PRINT(std::cerr << "cycle" << i << ": ");
863 for (unsigned j = 0; j < schedule[i].size(); j++)
864 if (schedule[i][j] != NULL)
865 DEBUG_PRINT(std::cerr << schedule[i][j]->getNodeId() << "\t");
867 DEBUG_PRINT(std::cerr << "\t");
868 DEBUG_PRINT(std::cerr << "\n");
871 DEBUG_PRINT(std::cerr << "dump coreSchedule:" << "\n");
872 for (unsigned i = 0; i < numIssueSlots; i++)
873 DEBUG_PRINT(std::cerr << "\t#");
874 DEBUG_PRINT(std::cerr << "\n");
875 for (unsigned i = 0; i < coreSchedule.size(); i++) {
876 DEBUG_PRINT(std::cerr << "cycle" << i << ": ");
877 for (unsigned j = 0; j < coreSchedule[i].size(); j++)
878 if (coreSchedule[i][j] != NULL)
879 DEBUG_PRINT(std::cerr << coreSchedule[i][j]->getNodeId() << "\t");
881 DEBUG_PRINT(std::cerr << "\t");
882 DEBUG_PRINT(std::cerr << "\n");
888 //---------------------------------------------------------------------------
889 // Function: ModuloSchedulingPass
892 // Entry point for Modulo Scheduling
893 // Schedules LLVM instruction
895 //---------------------------------------------------------------------------
898 class ModuloSchedulingPass:public FunctionPass {
899 const TargetMachine ⌖
902 ModuloSchedulingPass(const TargetMachine &T):target(T) {}
904 const char *getPassName() const {
905 return "Modulo Scheduling";
908 // getAnalysisUsage - We use LiveVarInfo...
909 virtual void getAnalysisUsage(AnalysisUsage &AU) const {
910 //AU.addRequired(FunctionLiveVarInfo::ID);
913 bool runOnFunction(Function & F);
915 } // end anonymous namespace
918 bool ModuloSchedulingPass::runOnFunction(Function &F)
921 ModuloSchedGraphSet *graphSet = new ModuloSchedGraphSet(&F, target);
923 ModuloSchedulingSet ModuloSchedulingSet(*graphSet);
925 printf("runOnFunction in ModuloSchedulingPass returns\n");
930 Pass *createModuloSchedulingPass(const TargetMachine & tgt)
932 printf("creating modulo scheduling \n");
933 return new ModuloSchedulingPass(tgt);