#include #include "ModuloSchedGraph.h" #include "llvm/CodeGen/InstrSelection.h" #include "llvm/BasicBlock.h" #include "llvm/Function.h" #include "llvm/iOther.h" #include "Support/StringExtras.h" #include "Support/STLExtras.h" #include #include #include "llvm/iOperators.h" #include "llvm/iOther.h" #include "llvm/iPHINode.h" #include "llvm/iTerminators.h" #include "llvm/iMemory.h" #include "llvm/Type.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/Target/MachineSchedInfo.h" #define UNIDELAY 1 #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) < (b) ? (b) : (a)) using std::vector; using std::pair; //using std::hash_map; using std::cerr; extern std::ostream modSched_os; extern ModuloSchedDebugLevel_t ModuloSchedDebugLevel; //*********************** Internal Data Structures *************************/ // The following two types need to be classes, not typedefs, so we can use // opaque declarations in SchedGraph.h // struct RefVec: public vector< pair > { typedef vector< pair >:: iterator iterator; typedef vector< pair >::const_iterator const_iterator; }; struct RegToRefVecMap: public hash_map { typedef hash_map:: iterator iterator; typedef hash_map::const_iterator const_iterator; }; struct ValueToDefVecMap: public hash_map { typedef hash_map:: iterator iterator; typedef hash_map::const_iterator const_iterator; }; // class Modulo SchedGraphNode /*ctor*/ ModuloSchedGraphNode::ModuloSchedGraphNode(unsigned int _nodeId, const BasicBlock* _bb, const Instruction* _inst, int indexInBB, const TargetMachine& target) : SchedGraphNodeCommon(_nodeId, _bb, indexInBB), inst(_inst) { if(inst) { //FIXME: find the latency //currently setthe latency to zero latency =0; } } //class ModuloScheGraph void ModuloSchedGraph::addDummyEdges() { assert(graphRoot->outEdges.size() == 0); for (const_iterator I=begin(); I != end(); ++I) { ModuloSchedGraphNode* node = (ModuloSchedGraphNode*)( (*I).second); assert(node != graphRoot && node != graphLeaf); if (node->beginInEdges() == node->endInEdges()) (void) new SchedGraphEdge(graphRoot, node, SchedGraphEdge::CtrlDep, SchedGraphEdge::NonDataDep, 0); if (node->beginOutEdges() == node->endOutEdges()) (void) new SchedGraphEdge(node, graphLeaf, SchedGraphEdge::CtrlDep, SchedGraphEdge::NonDataDep, 0); } } bool isDefinition(const Instruction* I) { //if(TerminatorInst::classof(I)||FreeInst::classof(I) || StoreInst::classof(I) || CallInst::classof(I)) if(!I->hasName()) return false; else return true; } void ModuloSchedGraph::addDefUseEdges(const BasicBlock* bb) { //collect def instructions, store them in vector const MachineInstrInfo& mii = target.getInstrInfo(); typedef std::vector DefVec; DefVec defVec; //find those def instructions for(BasicBlock::const_iterator I=bb->begin(), E=bb->end(); I !=E; I++) if(I->getType() != Type::VoidTy) { defVec.push_back(this->getGraphNodeForInst(I)) ; } for(unsigned int i=0; i < defVec.size();i++) for(Value::use_const_iterator I=defVec[i]->getInst()->use_begin();I !=defVec[i]->getInst()->use_end() ;I++) { //for each use of a def, add a flow edge from the def instruction to the ref instruction const Instruction* value=defVec[i]->getInst(); Instruction *inst=(Instruction*)(*I); ModuloSchedGraphNode* node=NULL; for(BasicBlock::const_iterator I=bb->begin(), E=bb->end(); I !=E; I++) if((const Instruction*)I == inst) { node=(*this)[inst]; break; } assert(inst != NULL &&" Use not an Instruction ?" ); if(node == NULL) //inst is not an instruction in this block {} else { //add a flow edge from the def instruction to the ref instruction //self loop will not happen in SSA form assert(defVec[i] != node && "same node?"); //this is a true dependence, so the delay is equal to the delay of the pred node. int delay=0; MachineCodeForInstruction& tempMvec= MachineCodeForInstruction::get(value); for(unsigned j=0;j< tempMvec.size();j++) { MachineInstr* temp=tempMvec[j]; //delay +=mii.minLatency(temp->getOpCode()); delay = max(delay, mii.minLatency(temp->getOpCode())); } SchedGraphEdge* trueEdge=new SchedGraphEdge(defVec[i],node,value, SchedGraphEdge::TrueDep,delay); //if the ref instruction is before the def instrution //then the def instruction must be a phi instruction //add an anti-dependence edge to from the ref instruction to the def instruction if( node->getOrigIndexInBB() < defVec[i]->getOrigIndexInBB()) { assert(PHINode::classof(inst) && "the ref instruction befre def is not PHINode?"); trueEdge->setIteDiff(1); } } } } void ModuloSchedGraph::addCDEdges(const BasicBlock* bb) { //find the last instruction in the basic block //see if it is an branch instruction. //If yes, then add an edge from each node expcept the last node to the last node const Instruction* inst=&(bb->back()); ModuloSchedGraphNode* lastNode=(*this)[inst]; if( TerminatorInst::classof(inst)) for(BasicBlock::const_iterator I=bb->begin(),E=bb->end(); I != E; I++) { if(inst != I) { ModuloSchedGraphNode* node = (*this)[I]; //use latency of 0 (void) new SchedGraphEdge(node,lastNode,SchedGraphEdge::CtrlDep, SchedGraphEdge::NonDataDep,0); } } } static const int SG_LOAD_REF = 0; static const int SG_STORE_REF = 1; static const int SG_CALL_REF = 2; static const unsigned int SG_DepOrderArray[][3] = { { SchedGraphEdge::NonDataDep, SchedGraphEdge::AntiDep, SchedGraphEdge::AntiDep }, { SchedGraphEdge::TrueDep, SchedGraphEdge::OutputDep, SchedGraphEdge::TrueDep | SchedGraphEdge::OutputDep }, { SchedGraphEdge::TrueDep, SchedGraphEdge::AntiDep | SchedGraphEdge::OutputDep, SchedGraphEdge::TrueDep | SchedGraphEdge::AntiDep | SchedGraphEdge::OutputDep } }; // Add a dependence edge between every pair of machine load/store/call // instructions, where at least one is a store or a call. // Use latency 1 just to ensure that memory operations are ordered; // latency does not otherwise matter (true dependences enforce that). // void ModuloSchedGraph::addMemEdges(const BasicBlock* bb) { vector memNodeVec; //construct the memNodeVec for( BasicBlock::const_iterator I=bb->begin(), E=bb->end();I != E; I++) if(LoadInst::classof(I) ||StoreInst::classof(I) || CallInst::classof(I)) { ModuloSchedGraphNode* node =(*this)[(const Instruction*)I]; memNodeVec.push_back(node); } // Instructions in memNodeVec are in execution order within the basic block, // so simply look at all pairs i]>. // for (unsigned im=0, NM=memNodeVec.size(); im < NM; im++) { const Instruction* fromInst = memNodeVec[im]->getInst(); int fromType = CallInst::classof(fromInst)? SG_CALL_REF : LoadInst::classof(fromInst)? SG_LOAD_REF : SG_STORE_REF; for (unsigned jm=im+1; jm < NM; jm++) { const Instruction* toInst=memNodeVec[jm]->getInst(); int toType = CallInst::classof(toInst)? SG_CALL_REF : LoadInst::classof(toInst)? SG_LOAD_REF : SG_STORE_REF; if (fromType != SG_LOAD_REF || toType != SG_LOAD_REF) { (void) new SchedGraphEdge(memNodeVec[im], memNodeVec[jm], SchedGraphEdge::MemoryDep, SG_DepOrderArray[fromType][toType], 1); SchedGraphEdge* edge=new SchedGraphEdge(memNodeVec[jm],memNodeVec[im], SchedGraphEdge::MemoryDep, SG_DepOrderArray[toType][fromType],1); edge->setIteDiff(1); } } } } void ModuloSchedGraph::buildNodesforBB (const TargetMachine& target, const BasicBlock* bb, std::vector& memNode, RegToRefVecMap& regToRefVecMap, ValueToDefVecMap& valueToDefVecMap) { //const MachineInstrInfo& mii=target.getInstrInfo(); //Build graph nodes for each LLVM instruction and gather def/use info. //Do both together in a single pass over all machine instructions. int i=0; for(BasicBlock::const_iterator I=bb->begin(), E=bb->end(); I!=E; I++) { ModuloSchedGraphNode* node=new ModuloSchedGraphNode(getNumNodes(), bb,I,i, target); i++; this->noteModuloSchedGraphNodeForInst(I,node); } //this function finds some info about instruction in basic block for later use //findDefUseInfoAtInstr(target, node, memNode,regToRefVecMap,valueToDefVecMap); } bool ModuloSchedGraph::isLoop(const BasicBlock* bb) { //only if the last instruction in the basicblock is branch instruction and //there is at least an option to branch itself const Instruction* inst=&(bb->back()); if( BranchInst::classof(inst)) for(unsigned i=0;i < ((BranchInst*)inst)->getNumSuccessors();i++) { BasicBlock* sb=((BranchInst*)inst)->getSuccessor(i); if(sb ==bb) return true; } return false; } bool ModuloSchedGraph::isLoop() { //only if the last instruction in the basicblock is branch instruction and //there is at least an option to branch itself assert(bbVec.size() ==1 &&"only 1 basicblock in a graph"); const BasicBlock* bb=bbVec[0]; const Instruction* inst=&(bb->back()); if( BranchInst::classof(inst)) for(unsigned i=0;i < ((BranchInst*)inst)->getNumSuccessors();i++) { BasicBlock* sb=((BranchInst*)inst)->getSuccessor(i); if(sb ==bb) return true; } return false; } void ModuloSchedGraph::computeNodeASAP(const BasicBlock* bb) { //FIXME: now assume the only backward edges come from the edges from other nodes to the phi Node //so i will ignore all edges to the phi node; after this, there shall be no recurrence. unsigned numNodes=bb->size(); for(unsigned i=2;i < numNodes+2;i++) { ModuloSchedGraphNode* node=getNode(i); node->setPropertyComputed(false); } for(unsigned i=2;i < numNodes+2; i++) { ModuloSchedGraphNode* node=getNode(i); node->ASAP=0; if(i==2 ||node->getNumInEdges() ==0) { node->setPropertyComputed(true);continue;} for(ModuloSchedGraphNode::const_iterator I=node->beginInEdges(), E=node->endInEdges();I !=E; I++) { SchedGraphEdge* edge=*I; ModuloSchedGraphNode* pred=(ModuloSchedGraphNode*)(edge->getSrc()); assert(pred->getPropertyComputed()&&"pred node property is not computed!"); int temp=pred->ASAP + edge->getMinDelay() - edge->getIteDiff()*this->MII; node->ASAP= max(node->ASAP,temp); } node->setPropertyComputed(true); } } void ModuloSchedGraph::computeNodeALAP(const BasicBlock* bb) { unsigned numNodes=bb->size(); int maxASAP=0; for(unsigned i=numNodes+1;i >= 2;i--) { ModuloSchedGraphNode* node=getNode(i); node->setPropertyComputed(false); //cerr<< " maxASAP= " <ASAP= "<< node->ASAP<<"\n"; maxASAP=max(maxASAP,node->ASAP); } //cerr<<"maxASAP is "<= 2; i--) { ModuloSchedGraphNode* node=getNode(i); node->ALAP=maxASAP; for(ModuloSchedGraphNode::const_iterator I=node->beginOutEdges(), E=node->endOutEdges(); I!=E; I++) { SchedGraphEdge* edge= *I; ModuloSchedGraphNode* succ=(ModuloSchedGraphNode*) (edge->getSink()); if(PHINode::classof(succ->getInst()))continue; assert(succ->getPropertyComputed()&&"succ node property is not computed!"); int temp=succ->ALAP - edge->getMinDelay()+edge->getIteDiff()*this->MII; node->ALAP =min(node->ALAP,temp); } node->setPropertyComputed(true); } } void ModuloSchedGraph::computeNodeMov(const BasicBlock* bb) { unsigned numNodes=bb->size(); for(unsigned i =2;i < numNodes +2 ;i++) { ModuloSchedGraphNode* node=getNode(i); node->mov=node->ALAP-node->ASAP; assert(node->mov >=0 &&"move freedom for this node is less than zero? "); } } void ModuloSchedGraph::computeNodeDepth(const BasicBlock* bb) { unsigned numNodes=bb->size(); for(unsigned i=2;i < numNodes+2;i++) { ModuloSchedGraphNode* node=getNode(i); node->setPropertyComputed(false); } for(unsigned i=2;i < numNodes+2; i++) { ModuloSchedGraphNode* node=getNode(i); node->depth=0; if(i==2 ||node->getNumInEdges() ==0) { node->setPropertyComputed(true);continue;} for(ModuloSchedGraphNode::const_iterator I=node->beginInEdges(), E=node->endInEdges();I !=E; I++) { SchedGraphEdge* edge=*I; ModuloSchedGraphNode* pred=(ModuloSchedGraphNode*)(edge->getSrc()); assert(pred->getPropertyComputed()&&"pred node property is not computed!"); int temp=pred->depth + edge->getMinDelay(); node->depth= max(node->depth,temp); } node->setPropertyComputed(true); } } void ModuloSchedGraph::computeNodeHeight(const BasicBlock* bb) { unsigned numNodes=bb->size(); for(unsigned i=numNodes+1;i >= 2;i--) { ModuloSchedGraphNode* node=getNode(i); node->setPropertyComputed(false); } for(unsigned i=numNodes+1;i >= 2; i--) { ModuloSchedGraphNode* node=getNode(i); node->height=0; for(ModuloSchedGraphNode::const_iterator I=node->beginOutEdges(), E=node->endOutEdges(); I!=E; I++) { SchedGraphEdge* edge= *I; ModuloSchedGraphNode* succ=(ModuloSchedGraphNode*)(edge->getSink()); if(PHINode::classof(succ->getInst())) continue; assert(succ->getPropertyComputed()&&"succ node property is not computed!"); node->height=max(node->height, succ->height+edge->getMinDelay()); } node->setPropertyComputed(true); } } void ModuloSchedGraph::computeNodeProperty(const BasicBlock* bb) { //FIXME: now assume the only backward edges come from the edges from other nodes to the phi Node //so i will ignore all edges to the phi node; after this, there shall be no recurrence. this->computeNodeASAP(bb); this->computeNodeALAP(bb); this->computeNodeMov(bb); this->computeNodeDepth(bb); this->computeNodeHeight(bb); } //do not consider the backedge in these two functions: // i.e. don't consider the edge with destination in phi node std::vector ModuloSchedGraph::predSet(std::vector set, unsigned backEdgeSrc, unsigned backEdgeSink) { std::vector predS; for(unsigned i=0; i < set.size(); i++) { ModuloSchedGraphNode* node = set[i]; for(ModuloSchedGraphNode::const_iterator I=node->beginInEdges(), E=node->endInEdges(); I !=E; I++) { SchedGraphEdge* edge= *I; if(edge->getSrc()->getNodeId() ==backEdgeSrc && edge->getSink()->getNodeId() == backEdgeSink) continue; ModuloSchedGraphNode* pred= (ModuloSchedGraphNode*)(edge->getSrc()); //if pred is not in the predSet, push it in vector bool alreadyInset=false; for(unsigned j=0; j < predS.size(); j++) if(predS[j]->getNodeId() == pred->getNodeId() ) {alreadyInset=true;break;} for(unsigned j=0; j < set.size(); j++) if(set[j]->getNodeId() == pred->getNodeId() ) {alreadyInset=true; break;} if(! alreadyInset) predS.push_back(pred); } } return predS; } ModuloSchedGraph::NodeVec ModuloSchedGraph::predSet(NodeVec set) { //node number increases from 2 return predSet(set,0, 0); } std::vector ModuloSchedGraph::predSet(ModuloSchedGraphNode* _node, unsigned backEdgeSrc, unsigned backEdgeSink) { std::vector set; set.push_back(_node); return predSet(set, backEdgeSrc, backEdgeSink); } std::vector ModuloSchedGraph::predSet(ModuloSchedGraphNode* _node) { return predSet(_node,0,0); } std::vector ModuloSchedGraph::succSet(std::vector set,unsigned src, unsigned sink) { vector succS; for(unsigned i=0; i < set.size(); i++) { ModuloSchedGraphNode* node = set[i]; for(ModuloSchedGraphNode::const_iterator I=node->beginOutEdges(), E=node->endOutEdges(); I !=E; I++) { SchedGraphEdge* edge= *I; if(edge->getSrc()->getNodeId() == src && edge->getSink()->getNodeId() == sink) continue; ModuloSchedGraphNode* succ= (ModuloSchedGraphNode*)(edge->getSink()); //if pred is not in the predSet, push it in vector bool alreadyInset=false; for(unsigned j=0; j < succS.size(); j++) if(succS[j]->getNodeId() == succ->getNodeId() ) {alreadyInset=true;break;} for(unsigned j=0; j < set.size(); j++) if(set[j]->getNodeId() == succ->getNodeId() ) {alreadyInset=true;break;} if(! alreadyInset) succS.push_back(succ); } } return succS; } ModuloSchedGraph::NodeVec ModuloSchedGraph::succSet(NodeVec set) { return succSet(set,0,0); } std::vector ModuloSchedGraph::succSet(ModuloSchedGraphNode* _node,unsigned src, unsigned sink) { std::vector set; set.push_back(_node); return succSet(set, src, sink); } std::vector ModuloSchedGraph::succSet(ModuloSchedGraphNode* _node) { return succSet(_node, 0, 0); } SchedGraphEdge* ModuloSchedGraph::getMaxDelayEdge(unsigned srcId, unsigned sinkId) { ModuloSchedGraphNode* node =getNode(srcId); SchedGraphEdge* maxDelayEdge=NULL; int maxDelay=-1; for(ModuloSchedGraphNode::const_iterator I=node->beginOutEdges(), E=node->endOutEdges();I !=E; I++) { SchedGraphEdge* edge= *I; if(edge->getSink()->getNodeId() == sinkId) if(edge->getMinDelay() > maxDelay){ maxDelayEdge=edge; maxDelay=edge->getMinDelay(); } } assert(maxDelayEdge != NULL&&"no edge between the srcId and sinkId?"); return maxDelayEdge; } void ModuloSchedGraph::dumpCircuits() { modSched_os<<"dumping circuits for graph: "<<"\n"; int j=-1; while(circuits[++j][0] !=0){ int k=-1; while(circuits[j][++k] !=0) modSched_os<< circuits[j][k]<<"\t"; modSched_os<<"\n"; } } void ModuloSchedGraph::dumpSet(std::vector set) { for(unsigned i=0;i < set.size() ; i++) modSched_os<< set[i]->getNodeId()<<"\t"; modSched_os<<"\n"; } std::vector ModuloSchedGraph::vectorUnion(std::vector set1,std::vector set2 ) { std::vector unionVec; for(unsigned i=0;i ModuloSchedGraph::vectorConj(std::vector set1,std::vector set2 ) { std::vector conjVec; for(unsigned i=0;igetNodeId() ==(*II)->getNodeId()) {inset=true;break;} if(!inset) newVec.push_back(*I); } return newVec; } void ModuloSchedGraph::orderNodes(){ oNodes.clear(); std::vector set; const BasicBlock* bb=bbVec[0]; unsigned numNodes = bb->size(); //first order all the sets int j=-1; int totalDelay=-1; int preDelay=-1; while(circuits[++j][0] !=0){ int k=-1; preDelay=totalDelay; while(circuits[j][++k] !=0){ ModuloSchedGraphNode* node =getNode(circuits[j][k]); unsigned nextNodeId; nextNodeId =circuits[j][k+1] !=0? circuits[j][k+1]:circuits[j][0]; SchedGraphEdge* edge = getMaxDelayEdge(circuits[j][k], nextNodeId); totalDelay += edge->getMinDelay(); } if(preDelay != -1 && totalDelay > preDelay){ //swap circuits[j][] and cuicuits[j-1][] unsigned temp[MAXNODE]; for(int k=0;k= ModuloSched_PrintScheduleProcess) modSched_os<<"building the first set"<<"\n"; int setSeq=-1; int k=-1; setSeq++; while(circuits[setSeq][++k]!=0) set.push_back(getNode(circuits[setSeq][k])); if(circuits[setSeq][0]!=0){ backEdgeSrc=circuits[setSeq][k-1]; backEdgeSink=circuits[setSeq][0]; } if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess){ modSched_os<<"the first set is:"; dumpSet(set); } //implement the ordering algorithm enum OrderSeq{ bottom_up, top_down}; OrderSeq order; std::vector R; while(!set.empty()) { std::vector pset=predSet(oNodes); std::vector sset=succSet(oNodes); if(!pset.empty() && !vectorConj(pset,set).empty()) {R=vectorConj(pset,set);order=bottom_up;} else if( !sset.empty() && !vectorConj(sset,set).empty()) {R=vectorConj(sset,set);order=top_down;} else { int maxASAP=-1; int position=-1; for(unsigned i=0;igetASAP(); if(temp>maxASAP ) { maxASAP=temp; position=i; } } R.push_back(set[position]); order=bottom_up; } while(!R.empty()){ if(order== top_down){ if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"in top_down round"<<"\n"; while(!R.empty()){ int maxHeight=-1; NodeVec::iterator chosenI; for(NodeVec::iterator I=R.begin();I != R.end();I++){ int temp=(*I)->height; if( (temp > maxHeight) || ( temp == maxHeight && (*I)->mov <= (*chosenI)->mov ) ){ if((temp > maxHeight) || ( temp == maxHeight && (*I)->mov < (*chosenI)->mov )){ maxHeight=temp; chosenI=I; continue; } //possible case: instruction A and B has the same height and mov, but A has dependence to B //e.g B is the branch instruction in the end, or A is the phi instruction at the beginning if((*I)->mov == (*chosenI)->mov) for(ModuloSchedGraphNode::const_iterator oe=(*I)->beginOutEdges(), end=(*I)->endOutEdges();oe !=end; oe++){ if((*oe)->getSink() == (*chosenI)){ maxHeight=temp; chosenI=I; continue; } } } } ModuloSchedGraphNode* mu= *chosenI; oNodes.push_back(mu); R.erase(chosenI); std::vector succ_mu= succSet(mu,backEdgeSrc,backEdgeSink); std::vector comm=vectorConj(succ_mu,set); comm=vectorSub(comm,oNodes); R = vectorUnion(comm, R); } order=bottom_up; R= vectorConj(predSet(oNodes), set); } else{ if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"in bottom up round"<<"\n"; while(!R.empty()){ int maxDepth=-1; NodeVec::iterator chosenI; for(NodeVec::iterator I=R.begin();I != R.end();I++){ int temp=(*I)->depth; if( (temp > maxDepth) || ( temp == maxDepth && (*I)->mov < (*chosenI)->mov )){ maxDepth=temp; chosenI=I; } } ModuloSchedGraphNode* mu=*chosenI; oNodes.push_back(mu); R.erase(chosenI); std::vector pred_mu= predSet(mu,backEdgeSrc,backEdgeSink); std::vector comm=vectorConj(pred_mu,set); comm=vectorSub(comm,oNodes); R = vectorUnion(comm, R); } order=top_down; R= vectorConj(succSet(oNodes), set); } } if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess){ modSched_os<<"order finished"<<"\n"; modSched_os<<"dumping the ordered nodes: "<<"\n"; dumpSet(oNodes); dumpCircuits(); } //create a new set //FIXME: the nodes between onodes and this circuit should also be include in this set if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"building the next set"<<"\n"; set.clear(); int k=-1; setSeq++; while(circuits[setSeq][++k]!=0) set.push_back(getNode(circuits[setSeq][k])); if(circuits[setSeq][0]!=0){ backEdgeSrc=circuits[setSeq][k-1]; backEdgeSink=circuits[setSeq][0]; } if(set.empty()){ //no circuits any more //collect all other nodes if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"no circuits any more, collect the rest nodes"<<"\n"; for(unsigned i=2;igetNodeId() == i) {inset=true;break;} if(!inset)set.push_back(getNode(i)); } } if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess){ modSched_os<<"next set is: "<<"\n"; dumpSet(set); } }//while(!set.empty()) } void ModuloSchedGraph::buildGraph (const TargetMachine& target) { const BasicBlock* bb=bbVec[0]; assert(bbVec.size() ==1 &&"only handling a single basic block here"); // Use this data structure to note all machine operands that compute // ordinary LLVM values. These must be computed defs (i.e., instructions). // Note that there may be multiple machine instructions that define // each Value. ValueToDefVecMap valueToDefVecMap; // Use this data structure to note all memory instructions. // We use this to add memory dependence edges without a second full walk. // // vector memVec; vector memNodeVec; // Use this data structure to note any uses or definitions of // machine registers so we can add edges for those later without // extra passes over the nodes. // The vector holds an ordered list of references to the machine reg, // ordered according to control-flow order. This only works for a // single basic block, hence the assertion. Each reference is identified // by the pair: . // RegToRefVecMap regToRefVecMap; // Make a dummy root node. We'll add edges to the real roots later. graphRoot = new ModuloSchedGraphNode(0, NULL, NULL, -1,target); graphLeaf = new ModuloSchedGraphNode(1, NULL, NULL, -1,target); //---------------------------------------------------------------- // First add nodes for all the LLVM instructions in the basic block // because this greatly simplifies identifying which edges to add. // Do this one VM instruction at a time since the ModuloSchedGraphNode needs that. // Also, remember the load/store instructions to add memory deps later. //---------------------------------------------------------------- //FIXME:if there is call instruction, then we shall quit somewhere // currently we leave call instruction and continue construct graph //dump only the blocks which are from loops if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) this->dump(bb); if(!isLoop(bb)){ modSched_os <<" dumping non-loop BB:"<addDefUseEdges(bb); this->addCDEdges(bb); this->addMemEdges(bb); //this->dump(); int ResII=this->computeResII(bb); if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os << "ResII is " << ResII<<"\n";; int RecII=this->computeRecII(bb); if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os << "RecII is " <MII=max(ResII, RecII); this->computeNodeProperty(bb); if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) this->dumpNodeProperty(); this->orderNodes(); if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) this->dump(); //this->instrScheduling(); //this->dumpScheduling(); } } ModuloSchedGraphNode* ModuloSchedGraph::getNode (const unsigned nodeId) const { for(const_iterator I=begin(), E=end();I !=E;I++) if((*I).second->getNodeId() ==nodeId) return (ModuloSchedGraphNode*)(*I).second; return NULL; } int ModuloSchedGraph::computeRecII(const BasicBlock* bb) { int RecII=0; //os<<"begining computerRecII()"<<"\n"; //FIXME: only deal with circuits starting at the first node: the phi node nodeId=2; //search all elementary circuits in the dependance graph //assume maximum number of nodes is MAXNODE unsigned path[MAXNODE]; unsigned stack[MAXNODE][MAXNODE]; for(int j=0;jsize(); int i=0; path[i]=2; ModuloSchedGraphNode* initNode=getNode(path[0]); unsigned initNodeId=initNode->getNodeId(); ModuloSchedGraphNode* currentNode=initNode; while(currentNode != NULL) { unsigned currentNodeId=currentNode->getNodeId(); // modSched_os<<"current node is "<beginOutEdges(), E=currentNode->endOutEdges(); I !=E; I++) { //modSched_os <<" searching in outgoint edges of node "<getSink()->getNodeId(); bool inpath=false,instack=false; int k; //modSched_os<<"nodeId is "< currentNodeId && !inpath && !instack) {nextNode=(ModuloSchedGraphNode*) ((SchedGraphEdge*)*I)->getSink();break;} } if(nextNode != NULL) { //modSched_os<<"find the next Node "<getNodeId()<<"\n"; int j=0; while( stack[i][j] !=0) j++; stack[i][j]=nextNode->getNodeId(); i++; path[i]=nextNode->getNodeId(); currentNode=nextNode; } else { //modSched_os<<"no expansion any more"<<"\n"; //confirmCircuit(); for(ModuloSchedGraphNode::const_iterator I=currentNode->beginOutEdges(), E=currentNode->endOutEdges() ; I != E; I++) { unsigned nodeId=((SchedGraphEdge*)*I)->getSink()->getNodeId(); if(nodeId == initNodeId) { int j=-1; while(circuits[++j][0] !=0); for(int k=0;k= ModuloSched_PrintScheduleProcess) modSched_os<<"circuits found are: "<<"\n"; int j=-1; while(circuits[++j][0] !=0){ int k=-1; while(circuits[j][++k] !=0) if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<< circuits[j][k]<<"\t"; if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"\n"; //for this circuit, compute the sum of all edge delay int sumDelay=0; k=-1; while(circuits[j][++k] !=0) { //ModuloSchedGraphNode* node =getNode(circuits[j][k]); unsigned nextNodeId; nextNodeId =circuits[j][k+1] !=0? circuits[j][k+1]:circuits[j][0]; /* for(ModuloSchedGraphNode::const_iterator I=node->beginOutEdges(), E=node->endOutEdges();I !=E; I++) { SchedGraphEdge* edge= *I; if(edge->getSink()->getNodeId() == nextNodeId) {sumDelay += edge->getMinDelay();break;} } */ sumDelay += getMaxDelayEdge(circuits[j][k],nextNodeId)->getMinDelay(); } // assume we have distance 1, in this case the sumDelay is RecII // this is correct for SSA form only // if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"The total Delay in the circuit is " < sumDelay? RecII: sumDelay; } return RecII; } } return -1; } void ModuloSchedGraph::addResourceUsage(std::vector >& ruVec, int rid){ //modSched_os<<"\nadding a resouce , current resouceUsage vector size is "< > &ru) { MachineSchedInfo& msi = (MachineSchedInfo&)target.getSchedInfo(); std::vector > resourceNumVector = msi.resourceNumVector; modSched_os <<"resourceID\t"<<"resourceNum"<<"\n"; for(unsigned i=0;i > resourceUsage; //pair //FIXME: number of functional units the target machine can provide should be get from Target // here I temporary hardcode it for(BasicBlock::const_iterator I=bb->begin(),E=bb->end(); I !=E; I++) { if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess){ modSched_os<<"machine instruction for llvm instruction( node "<getNodeId()<<")" <<"\n"; modSched_os<<"\t"<<*I; } MachineCodeForInstruction& tempMvec= MachineCodeForInstruction::get(I); if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os <<"size =" <getOpCode()); InstrRUsage rUsage=msi.getInstrRUsage(minstr->getOpCode()); InstrClassRUsage classRUsage=msi.getClassRUsage(mii.getSchedClass(minstr->getOpCode())); unsigned totCycles= classRUsage.totCycles; std::vector > resources =rUsage.resourcesByCycle; assert(totCycles == resources.size()); if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os <<"resources Usage for this Instr(totCycles=" << totCycles << ",mindLatency="<getOpCode())<<"): "<< *minstr <<"\n"; for(unsigned j=0;j< resources.size();j++){ if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) modSched_os<<"cycle "<= ModuloSched_PrintScheduleProcess) modSched_os<<"\t"<= ModuloSched_PrintScheduleProcess) modSched_os<<"\n"; } } } if(ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess) this->dumpResourceUsage(resourceUsage); //compute ResII ResII=0; int issueSlots=msi.maxNumIssueTotal; for(unsigned i=0;igetName() << "' =========\n\n"; for(const_iterator I=begin(); I != end(); ++I) (*I)->dump(); modSched_os << "\n=========End graphs for funtion` "<getName() << "' ==========\n\n"; } void ModuloSchedGraph::dump(const BasicBlock* bb) { modSched_os<<"dumping basic block:"; modSched_os<<(bb->hasName()?bb->getName(): "block") <<" (" << bb << ")"<<"\n"; } void ModuloSchedGraph::dump(const BasicBlock* bb, std::ostream& os) { os<<"dumping basic block:"; os<<(bb->hasName()?bb->getName(): "block") <<" (" << bb << ")"<<"\n"; } void ModuloSchedGraph::dump() const { modSched_os << " ModuloSchedGraph for basic Blocks:"; for(unsigned i=0, N =bbVec.size(); i< N; i++) { modSched_os<<(bbVec[i]->hasName()?bbVec[i]->getName(): "block") <<" (" << bbVec[i] << ")" << ((i==N-1)?"":", "); } modSched_os <<"\n\n Actual Root nodes : "; for (unsigned i=0, N=graphRoot->outEdges.size(); i < N; i++) modSched_os << graphRoot->outEdges[i]->getSink()->getNodeId() << ((i == N-1)? "" : ", "); modSched_os << "\n Graph Nodes:\n"; //for (const_iterator I=begin(); I != end(); ++I) //modSched_os << "\n" << *I->second; unsigned numNodes=bbVec[0]->size(); for(unsigned i=2;i< numNodes+2;i++) { ModuloSchedGraphNode* node= getNode(i); modSched_os << "\n" << *node; } modSched_os << "\n"; } void ModuloSchedGraph::dumpNodeProperty() const { const BasicBlock* bb=bbVec[0]; unsigned numNodes=bb->size(); for(unsigned i=2;i < numNodes+2;i++) { ModuloSchedGraphNode* node=getNode(i); modSched_os<<"NodeId "<getNodeId()<<"\t"; modSched_os<<"ASAP "<getASAP()<<"\t"; modSched_os<<"ALAP "<getALAP()<<"\t"; modSched_os<<"mov " <getMov() <<"\t"; modSched_os<<"depth "<getDepth()<<"\t"; modSched_os<<"height "<getHeight()<<"\t"; modSched_os<<"\n"; } } void ModuloSchedGraphSet::buildGraphsForMethod (const Function *F, const TargetMachine& target) { for(Function::const_iterator BI = F->begin(); BI != F->end(); ++BI) addGraph(new ModuloSchedGraph(BI,target)); } std::ostream &operator<<(std::ostream &os, const ModuloSchedGraphNode& node) { os << std::string(8, ' ') << "Node " << node.nodeId << " : " << "latency = " << node.latency << "\n" << std::string(12, ' '); if (node.getInst() == NULL) os << "(Dummy node)\n"; else { os << *node.getInst() << "\n" << std::string(12, ' '); os << node.inEdges.size() << " Incoming Edges:\n"; for (unsigned i=0, N=node.inEdges.size(); i < N; i++) os << std::string(16, ' ') << *node.inEdges[i]; os << std::string(12, ' ') << node.outEdges.size() << " Outgoing Edges:\n"; for (unsigned i=0, N=node.outEdges.size(); i < N; i++) os << std::string(16, ' ') << *node.outEdges[i]; } return os; }