mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
*** empty log message ***
llvm-svn: 5755
This commit is contained in:
parent
b215db890f
commit
9ba51857c1
7
lib/CodeGen/ModuloScheduling/Makefile
Normal file
7
lib/CodeGen/ModuloScheduling/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
LEVEL = ../../..
|
||||
|
||||
DIRS =
|
||||
|
||||
LIBRARYNAME = modulosched
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
1313
lib/CodeGen/ModuloScheduling/ModuloSchedGraph.cpp
Normal file
1313
lib/CodeGen/ModuloScheduling/ModuloSchedGraph.cpp
Normal file
File diff suppressed because it is too large
Load Diff
347
lib/CodeGen/ModuloScheduling/ModuloSchedGraph.h
Normal file
347
lib/CodeGen/ModuloScheduling/ModuloSchedGraph.h
Normal file
@ -0,0 +1,347 @@
|
||||
//===- ModuloSchedGraph.h - Represent a collection of data structures ----*- C++ -*-===//
|
||||
//
|
||||
// This header defines the primative classes that make up a data structure
|
||||
// graph.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MODULO_SCHED_GRAPH_H
|
||||
#define LLVM_CODEGEN_MODULO_SCHED_GRAPH_H
|
||||
|
||||
#include "Support/HashExtras.h"
|
||||
#include "Support/GraphTraits.h"
|
||||
#include "../InstrSched/SchedGraphCommon.h"
|
||||
#include "llvm/Instruction.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <iostream>
|
||||
using std::pair;
|
||||
|
||||
//for debug information selecton
|
||||
enum ModuloSchedDebugLevel_t{
|
||||
ModuloSched_NoDebugInfo,
|
||||
ModuloSched_Disable,
|
||||
ModuloSched_PrintSchedule,
|
||||
ModuloSched_PrintScheduleProcess,
|
||||
};
|
||||
|
||||
//===============------------------------------------------------------------------------
|
||||
///ModuloSchedGraphNode - Implement a data structure based on the SchedGraphNodeCommon
|
||||
///this class stores informtion needed later to order the nodes in modulo scheduling
|
||||
///
|
||||
class ModuloSchedGraphNode: public SchedGraphNodeCommon {
|
||||
private:
|
||||
//the corresponding instruction
|
||||
const Instruction* inst;
|
||||
|
||||
//whether this node's property(ASAP,ALAP, ...) has been computed
|
||||
bool propertyComputed;
|
||||
|
||||
//ASAP: the earliest time the node could be scheduled
|
||||
//ALAP: the latest time the node couldbe scheduled
|
||||
//depth: the depth of the node
|
||||
//height: the height of the node
|
||||
//mov: the mobility function, computed as ALAP - ASAP
|
||||
//scheTime: the scheduled time if this node has been scheduled
|
||||
//earlyStart: the earliest time to be tried to schedule the node
|
||||
//lateStart: the latest time to be tried to schedule the node
|
||||
int ASAP, ALAP, depth, height, mov;
|
||||
int schTime;
|
||||
int earlyStart,lateStart;
|
||||
|
||||
public:
|
||||
|
||||
//get the instruction
|
||||
const Instruction* getInst() const { return inst;}
|
||||
|
||||
//get the instruction op-code name
|
||||
const char* getInstOpcodeName() const{ return inst->getOpcodeName();}
|
||||
|
||||
//get the instruction op-code
|
||||
const unsigned getInstOpcode() const { return inst->getOpcode();}
|
||||
|
||||
//return whether the node is NULL
|
||||
bool isNullNode() const{ return(inst== NULL);}
|
||||
|
||||
//return whether the property of the node has been computed
|
||||
bool getPropertyComputed() {return propertyComputed;}
|
||||
|
||||
//set the propertyComputed
|
||||
void setPropertyComputed(bool _propertyComputed) {propertyComputed = _propertyComputed;}
|
||||
|
||||
//get the corresponding property
|
||||
int getASAP(){ return ASAP;}
|
||||
int getALAP(){ return ALAP;}
|
||||
int getMov() { return mov;}
|
||||
int getDepth(){return depth;}
|
||||
int getHeight(){return height;}
|
||||
int getSchTime(){return schTime;}
|
||||
int getEarlyStart(){return earlyStart;}
|
||||
int getLateStart() { return lateStart;}
|
||||
void setEarlyStart(int _earlyStart) {earlyStart= _earlyStart;}
|
||||
void setLateStart(int _lateStart) {lateStart= _lateStart;}
|
||||
void setSchTime(int _time){schTime=_time;}
|
||||
|
||||
private:
|
||||
friend class ModuloSchedGraph;
|
||||
friend class SchedGraphNode;
|
||||
|
||||
//constructor:
|
||||
//nodeId: the node id, unique within the each BasicBlock
|
||||
//_bb: which BasicBlock the corresponding instruction belongs to
|
||||
//_inst: the corresponding instruction
|
||||
//indexInBB: the corresponding instruction's index in the BasicBlock
|
||||
//target: the targetMachine
|
||||
ModuloSchedGraphNode(unsigned int _nodeId,
|
||||
const BasicBlock* _bb,
|
||||
const Instruction* _inst,
|
||||
int indexInBB,
|
||||
const TargetMachine& target);
|
||||
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os,const ModuloSchedGraphNode& edge);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//FIXME: these two value should not be used
|
||||
#define MAXNODE 100
|
||||
#define MAXCC 100
|
||||
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ModuloSchedGraph- the data structure to store dependence between nodes
|
||||
/// it catches data dependence and constrol dependence
|
||||
///
|
||||
///
|
||||
|
||||
class ModuloSchedGraph:
|
||||
public SchedGraphCommon,
|
||||
protected hash_map<const Instruction*, ModuloSchedGraphNode*>
|
||||
{
|
||||
|
||||
private:
|
||||
//iteration Interval
|
||||
int MII;
|
||||
|
||||
//target machine
|
||||
const TargetMachine& target;
|
||||
|
||||
//the circuits in the dependence graph
|
||||
unsigned circuits[MAXCC][MAXNODE];
|
||||
|
||||
//the order nodes
|
||||
std::vector<ModuloSchedGraphNode*> oNodes;
|
||||
|
||||
typedef std::vector<ModuloSchedGraphNode*> NodeVec;
|
||||
|
||||
//the function to compute properties
|
||||
void computeNodeASAP(const BasicBlock* bb);
|
||||
void computeNodeALAP(const BasicBlock* bb);
|
||||
void computeNodeMov(const BasicBlock* bb);
|
||||
void computeNodeDepth(const BasicBlock* bb);
|
||||
void computeNodeHeight(const BasicBlock* bb);
|
||||
|
||||
//the function to compute node property
|
||||
void computeNodeProperty(const BasicBlock* bb);
|
||||
|
||||
//the function to sort nodes
|
||||
void orderNodes();
|
||||
|
||||
//add the resource usage
|
||||
void addResourceUsage(std::vector<pair<int,int> >&, int);
|
||||
|
||||
//debug functions:
|
||||
//dump circuits
|
||||
void dumpCircuits();
|
||||
//dump the input set of nodes
|
||||
void dumpSet(std::vector<ModuloSchedGraphNode*> set);
|
||||
//dump the input resource usage table
|
||||
void dumpResourceUsage(std::vector<pair<int,int> >&);
|
||||
|
||||
public:
|
||||
//help functions
|
||||
|
||||
//get the maxium the delay between two nodes
|
||||
SchedGraphEdge* getMaxDelayEdge(unsigned srcId, unsigned sinkId);
|
||||
|
||||
//FIXME:
|
||||
//get the predessor Set of the set
|
||||
NodeVec predSet(NodeVec set, unsigned, unsigned);
|
||||
NodeVec predSet(NodeVec set);
|
||||
|
||||
//get the predessor set of the node
|
||||
NodeVec predSet(ModuloSchedGraphNode* node, unsigned,unsigned);
|
||||
NodeVec predSet(ModuloSchedGraphNode* node);
|
||||
|
||||
//get the successor set of the set
|
||||
NodeVec succSet(NodeVec set, unsigned, unsigned);
|
||||
NodeVec succSet(NodeVec set);
|
||||
|
||||
//get the succssor set of the node
|
||||
NodeVec succSet(ModuloSchedGraphNode* node,unsigned, unsigned);
|
||||
NodeVec succSet(ModuloSchedGraphNode* node);
|
||||
|
||||
//return the uniton of the two vectors
|
||||
NodeVec vectorUnion(NodeVec set1,NodeVec set2 );
|
||||
|
||||
//return the consjuction of the two vectors
|
||||
NodeVec vectorConj(NodeVec set1,NodeVec set2 );
|
||||
|
||||
//return all nodes in set1 but not set2
|
||||
NodeVec vectorSub(NodeVec set1, NodeVec set2);
|
||||
|
||||
typedef hash_map<const Instruction*, ModuloSchedGraphNode*> map_base;
|
||||
public:
|
||||
using map_base::iterator;
|
||||
using map_base::const_iterator;
|
||||
|
||||
public:
|
||||
|
||||
//get target machine
|
||||
const TargetMachine& getTarget(){return target;}
|
||||
|
||||
//get the iteration interval
|
||||
const int getMII(){return MII;}
|
||||
|
||||
//get the ordered nodes
|
||||
const NodeVec& getONodes(){return oNodes;}
|
||||
|
||||
//get the number of nodes (including the root and leaf)
|
||||
//note: actually root and leaf is not used
|
||||
const unsigned int getNumNodes() const {return size()+2;}
|
||||
|
||||
//return wether the BasicBlock 'bb' contains a loop
|
||||
bool isLoop (const BasicBlock* bb);
|
||||
|
||||
//return this basibBlock contains a loop
|
||||
bool isLoop ();
|
||||
|
||||
|
||||
//return the node for the input instruction
|
||||
ModuloSchedGraphNode* getGraphNodeForInst(const Instruction* inst) const{
|
||||
const_iterator onePair = this->find(inst);
|
||||
return (onePair != this->end())?(*onePair).second: NULL;
|
||||
}
|
||||
|
||||
//Debugging support
|
||||
//dump the graph
|
||||
void dump() const;
|
||||
//dump the basicBlock
|
||||
void dump(const BasicBlock* bb);
|
||||
//dump the basicBlock into 'os' stream
|
||||
void dump(const BasicBlock* bb, std::ostream& os);
|
||||
//dump the node property
|
||||
void dumpNodeProperty() const ;
|
||||
|
||||
private:
|
||||
friend class ModuloSchedGraphSet; //give access to ctor
|
||||
|
||||
public:
|
||||
/*ctr*/
|
||||
ModuloSchedGraph(const BasicBlock* bb, const TargetMachine& _target)
|
||||
:SchedGraphCommon(bb), target(_target){
|
||||
buildGraph(target);
|
||||
}
|
||||
|
||||
/*dtr*/
|
||||
~ModuloSchedGraph(){
|
||||
for(const_iterator I=begin(); I!=end(); ++I)
|
||||
delete I->second;
|
||||
}
|
||||
|
||||
//unorder iterators
|
||||
//return values are pair<const Instruction*, ModuloSchedGraphNode*>
|
||||
using map_base::begin;
|
||||
using map_base::end;
|
||||
|
||||
|
||||
|
||||
inline void noteModuloSchedGraphNodeForInst(const Instruction* inst,
|
||||
ModuloSchedGraphNode* node)
|
||||
{
|
||||
assert((*this)[inst] ==NULL);
|
||||
(*this)[inst]=node;
|
||||
}
|
||||
|
||||
//Graph builder
|
||||
|
||||
ModuloSchedGraphNode* getNode (const unsigned nodeId) const;
|
||||
|
||||
//build the graph from the basicBlock
|
||||
void buildGraph (const TargetMachine& target);
|
||||
|
||||
//Build nodes for BasicBlock
|
||||
void buildNodesforBB (const TargetMachine& target,
|
||||
const BasicBlock* bb,
|
||||
NodeVec& memNode,
|
||||
RegToRefVecMap& regToRefVecMap,
|
||||
ValueToDefVecMap& valueToDefVecMap);
|
||||
|
||||
//find definitiona and use information for all nodes
|
||||
void findDefUseInfoAtInstr (const TargetMachine& target,
|
||||
ModuloSchedGraphNode* node,
|
||||
NodeVec& memNode,
|
||||
RegToRefVecMap& regToRefVecMap,
|
||||
ValueToDefVecMap& valueToDefVecMap);
|
||||
|
||||
//add def-use edge
|
||||
void addDefUseEdges (const BasicBlock* bb);
|
||||
|
||||
//add control dependence edges
|
||||
void addCDEdges (const BasicBlock* bb);
|
||||
|
||||
//add memory dependence dges
|
||||
void addMemEdges (const BasicBlock* bb);
|
||||
|
||||
//add dummy edges
|
||||
void addDummyEdges();
|
||||
|
||||
//computer source restrictoin II
|
||||
int computeResII (const BasicBlock* bb);
|
||||
|
||||
//computer recurrence II
|
||||
int computeRecII (const BasicBlock* bb);
|
||||
};
|
||||
|
||||
///==================================-
|
||||
//gragh set
|
||||
|
||||
class ModuloSchedGraphSet:
|
||||
public std::vector<ModuloSchedGraph*>
|
||||
{
|
||||
private:
|
||||
const Function* method;
|
||||
|
||||
public:
|
||||
typedef std::vector<ModuloSchedGraph*> baseVector;
|
||||
using baseVector::iterator;
|
||||
using baseVector::const_iterator;
|
||||
|
||||
public:
|
||||
/*ctor*/ ModuloSchedGraphSet (const Function* function, const TargetMachine& target);
|
||||
|
||||
/*dtor*/ ~ModuloSchedGraphSet ();
|
||||
|
||||
//iterators
|
||||
using baseVector::begin;
|
||||
using baseVector::end;
|
||||
|
||||
|
||||
//Debugging support
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
inline void addGraph(ModuloSchedGraph* graph){
|
||||
assert(graph !=NULL);
|
||||
this->push_back(graph);
|
||||
}
|
||||
|
||||
//Graph builder
|
||||
void buildGraphsForMethod (const Function *F, const TargetMachine& target);
|
||||
};
|
||||
|
||||
#endif
|
899
lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp
Normal file
899
lib/CodeGen/ModuloScheduling/ModuloScheduling.cpp
Normal file
@ -0,0 +1,899 @@
|
||||
|
||||
//===- SPLInstrScheduling.cpp - Modulo Software Pipelining Instruction Scheduling support -------===//
|
||||
//
|
||||
// this file implements the llvm/CodeGen/ModuloScheduling.h interface
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineCodeForInstruction.h"
|
||||
#include "llvm/CodeGen/MachineCodeForBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineCodeForMethod.h"
|
||||
#include "llvm/Analysis/LiveVar/FunctionLiveVarInfo.h" // FIXME: Remove when modularized better
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/BasicBlock.h"
|
||||
#include "llvm/Instruction.h"
|
||||
#include "Support/CommandLine.h"
|
||||
#include <algorithm>
|
||||
#include "ModuloSchedGraph.h"
|
||||
#include "ModuloScheduling.h"
|
||||
#include "llvm/Target/MachineSchedInfo.h"
|
||||
#include "llvm/BasicBlock.h"
|
||||
#include "llvm/iTerminators.h"
|
||||
#include "llvm/iPHINode.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include <iostream>
|
||||
#include <swig.h>
|
||||
#include <fstream>
|
||||
#include "llvm/CodeGen/InstrSelection.h"
|
||||
|
||||
#define max(x,y) (x>y?x:y)
|
||||
#define min(x,y) (x<y?x:y)
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::ostream;
|
||||
using std::ios;
|
||||
using std::filebuf;
|
||||
|
||||
//************************************************************
|
||||
//printing Debug information
|
||||
//ModuloSchedDebugLevel stores the value of debug level
|
||||
// modsched_os is the ostream to dump debug information, which is written into the file 'moduloSchedDebugInfo.output'
|
||||
//see ModuloSchedulingPass::runOnFunction()
|
||||
//************************************************************
|
||||
|
||||
ModuloSchedDebugLevel_t ModuloSchedDebugLevel;
|
||||
static cl::opt<ModuloSchedDebugLevel_t, true>
|
||||
SDL_opt("modsched", cl::Hidden, cl::location(ModuloSchedDebugLevel),
|
||||
cl::desc("enable modulo scheduling debugging information"),
|
||||
cl::values(
|
||||
clEnumValN(ModuloSched_NoDebugInfo, "n", "disable debug output"),
|
||||
clEnumValN(ModuloSched_Disable, "off", "disable modulo scheduling"),
|
||||
clEnumValN(ModuloSched_PrintSchedule, "psched", "print original and new schedule"),
|
||||
clEnumValN(ModuloSched_PrintScheduleProcess,"pschedproc", "print how the new schdule is produced"),
|
||||
0));
|
||||
|
||||
filebuf modSched_fb;
|
||||
ostream modSched_os(&modSched_fb);
|
||||
|
||||
//************************************************************
|
||||
|
||||
|
||||
///the method to compute schedule and instert epilogue and prologue
|
||||
void ModuloScheduling::instrScheduling(){
|
||||
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os<<"*************************computing modulo schedule ************************\n";
|
||||
|
||||
|
||||
const MachineSchedInfo& msi=target.getSchedInfo();
|
||||
|
||||
//number of issue slots in the in each cycle
|
||||
int numIssueSlots=msi.maxNumIssueTotal;
|
||||
|
||||
|
||||
|
||||
//compute the schedule
|
||||
bool success=false;
|
||||
while(!success)
|
||||
{
|
||||
//clear memory from the last round and initialize if necessary
|
||||
clearInitMem(msi);
|
||||
|
||||
//compute schedule and coreSchedule with the current II
|
||||
success=computeSchedule();
|
||||
|
||||
if(!success){
|
||||
II++;
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os<<"increase II to "<<II<<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
//print the final schedule if necessary
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintSchedule)
|
||||
dumpScheduling();
|
||||
|
||||
|
||||
//the schedule has been computed
|
||||
//create epilogue, prologue and kernel BasicBlock
|
||||
|
||||
//find the successor for this BasicBlock
|
||||
BasicBlock* succ_bb= getSuccBB(bb);
|
||||
|
||||
//print the original BasicBlock if necessary
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintSchedule){
|
||||
modSched_os<<"dumping the orginal block\n";
|
||||
graph.dump(bb);
|
||||
}
|
||||
|
||||
//construction of prologue, kernel and epilogue
|
||||
BasicBlock* kernel=bb->splitBasicBlock(bb->begin());
|
||||
BasicBlock* prologue= bb;
|
||||
BasicBlock* epilogue=kernel->splitBasicBlock(kernel->begin());
|
||||
|
||||
|
||||
//construct prologue
|
||||
constructPrologue(prologue);
|
||||
|
||||
//construct kernel
|
||||
constructKernel(prologue,kernel,epilogue);
|
||||
|
||||
//construct epilogue
|
||||
constructEpilogue(epilogue,succ_bb);
|
||||
|
||||
|
||||
//print the BasicBlocks if necessary
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintSchedule){
|
||||
modSched_os<<"dumping the prologue block:\n";
|
||||
graph.dump(prologue);
|
||||
modSched_os<<"dumping the kernel block\n";
|
||||
graph.dump(kernel);
|
||||
modSched_os<<"dumping the epilogue block\n";
|
||||
graph.dump(epilogue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//clear memory from the last round and initialize if necessary
|
||||
void ModuloScheduling::clearInitMem(const MachineSchedInfo& msi){
|
||||
|
||||
|
||||
unsigned numIssueSlots = msi.maxNumIssueTotal;
|
||||
//clear nodeScheduled from the last round
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess){
|
||||
modSched_os<< "***** new round with II= "<<II<<" *******************"<<endl;
|
||||
modSched_os<< " **************clear the vector nodeScheduled**************** \n";
|
||||
}
|
||||
nodeScheduled.clear();
|
||||
|
||||
|
||||
//clear resourceTable from the last round and reset it
|
||||
resourceTable.clear();
|
||||
for(unsigned i=0;i< II;i++)
|
||||
resourceTable.push_back(msi.resourceNumVector);
|
||||
|
||||
|
||||
//clear the schdule and coreSchedule from the last round
|
||||
schedule.clear();
|
||||
coreSchedule.clear();
|
||||
|
||||
//create a coreSchedule of size II*numIssueSlots
|
||||
//each entry is NULL
|
||||
while( coreSchedule.size() < II){
|
||||
std::vector<ModuloSchedGraphNode*>* newCycle=new std::vector<ModuloSchedGraphNode*>();
|
||||
for(unsigned k=0;k<numIssueSlots;k++)
|
||||
newCycle->push_back(NULL);
|
||||
coreSchedule.push_back(*newCycle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//compute schedule and coreSchedule with the current II
|
||||
bool ModuloScheduling::computeSchedule(){
|
||||
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os <<"start to compute schedule \n";
|
||||
|
||||
//loop over the ordered nodes
|
||||
for(NodeVec::const_iterator I=oNodes.begin();I!=oNodes.end();I++)
|
||||
{
|
||||
//try to schedule for node I
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
dumpScheduling();
|
||||
ModuloSchedGraphNode* node=*I;
|
||||
|
||||
//compute whether this node has successor(s)
|
||||
bool succ=true;
|
||||
|
||||
//compute whether this node has predessor(s)
|
||||
bool pred=true;
|
||||
|
||||
NodeVec schSucc=graph.vectorConj(nodeScheduled,graph.succSet(node));
|
||||
if(schSucc.empty())
|
||||
succ=false;
|
||||
NodeVec schPred=graph.vectorConj(nodeScheduled,graph.predSet(node));
|
||||
if(schPred.empty())
|
||||
pred=false;
|
||||
|
||||
//startTime: the earliest time we will try to schedule this node
|
||||
//endTime: the latest time we will try to schedule this node
|
||||
int startTime, endTime;
|
||||
|
||||
//node's earlyStart: possible earliest time to schedule this node
|
||||
//node's lateStart: possible latest time to schedule this node
|
||||
node->setEarlyStart(-1);
|
||||
node->setLateStart(9999);
|
||||
|
||||
|
||||
//this node has predessor but no successor
|
||||
if(!succ && pred){
|
||||
|
||||
//this node's earlyStart is it's predessor's schedule time + the edge delay
|
||||
// - the iteration difference* II
|
||||
for(unsigned i=0;i<schPred.size();i++){
|
||||
ModuloSchedGraphNode* predNode=schPred[i];
|
||||
SchedGraphEdge* edge=graph.getMaxDelayEdge(predNode->getNodeId(),node->getNodeId());
|
||||
int temp=predNode->getSchTime()+edge->getMinDelay() - edge->getIteDiff()*II;
|
||||
node->setEarlyStart( max(node->getEarlyStart(),temp));
|
||||
}
|
||||
startTime=node->getEarlyStart();
|
||||
endTime=node->getEarlyStart()+II-1;
|
||||
}
|
||||
|
||||
|
||||
//this node has successor but no predessor
|
||||
if(succ && !pred){
|
||||
for(unsigned i=0;i<schSucc.size();i++){
|
||||
ModuloSchedGraphNode* succNode=schSucc[i];
|
||||
SchedGraphEdge* edge=graph.getMaxDelayEdge(succNode->getNodeId(),node->getNodeId());
|
||||
int temp=succNode->getSchTime() - edge->getMinDelay() + edge->getIteDiff()*II;
|
||||
node->setLateStart(min(node->getEarlyStart(),temp));
|
||||
}
|
||||
startTime=node->getLateStart()- II+1;
|
||||
endTime=node->getLateStart();
|
||||
}
|
||||
|
||||
//this node has both successors and predessors
|
||||
if(succ && pred)
|
||||
{
|
||||
for(unsigned i=0;i<schPred.size();i++){
|
||||
ModuloSchedGraphNode* predNode=schPred[i];
|
||||
SchedGraphEdge* edge=graph.getMaxDelayEdge(predNode->getNodeId(),node->getNodeId());
|
||||
int temp=predNode->getSchTime()+edge->getMinDelay() - edge->getIteDiff()*II;
|
||||
node->setEarlyStart(max(node->getEarlyStart(),temp));
|
||||
}
|
||||
for(unsigned i=0;i<schSucc.size();i++){
|
||||
ModuloSchedGraphNode* succNode=schSucc[i];
|
||||
SchedGraphEdge* edge=graph.getMaxDelayEdge(succNode->getNodeId(),node->getNodeId());
|
||||
int temp=succNode->getSchTime() - edge->getMinDelay() + edge->getIteDiff()*II;
|
||||
node->setLateStart(min(node->getEarlyStart(),temp));
|
||||
}
|
||||
startTime=node->getEarlyStart();
|
||||
endTime=min(node->getLateStart(),node->getEarlyStart()+((int)II)-1);
|
||||
}
|
||||
|
||||
//this node has no successor or predessor
|
||||
if(!succ && !pred){
|
||||
node->setEarlyStart(node->getASAP());
|
||||
startTime=node->getEarlyStart();
|
||||
endTime=node->getEarlyStart()+II -1;
|
||||
}
|
||||
|
||||
//try to schedule this node based on the startTime and endTime
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os<<"scheduling the node "<<(*I)->getNodeId()<<"\n";
|
||||
|
||||
bool success= this->ScheduleNode(node,startTime, endTime,nodeScheduled);
|
||||
if(!success)return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//get the successor of the BasicBlock
|
||||
BasicBlock* ModuloScheduling::getSuccBB(BasicBlock* bb){
|
||||
|
||||
BasicBlock* succ_bb;
|
||||
for(unsigned i=0;i < II; i++)
|
||||
for(unsigned j=0;j< coreSchedule[i].size();j++)
|
||||
if(coreSchedule[i][j]){
|
||||
const Instruction* ist=coreSchedule[i][j]->getInst();
|
||||
|
||||
//we can get successor from the BranchInst instruction
|
||||
//assume we only have one successor (besides itself) here
|
||||
if(BranchInst::classof(ist)){
|
||||
BranchInst* bi=(BranchInst*)ist;
|
||||
assert(bi->isConditional()&&"the branchInst is not a conditional one");
|
||||
assert(bi->getNumSuccessors() ==2&&" more than two successors?");
|
||||
BasicBlock* bb1=bi->getSuccessor(0);
|
||||
BasicBlock* bb2=bi->getSuccessor(1);
|
||||
assert( (bb1 == bb|| bb2 == bb) && " None of its successor is itself?");
|
||||
if(bb1 == bb) succ_bb=bb2;
|
||||
else succ_bb=bb1;
|
||||
return succ_bb;
|
||||
}
|
||||
}
|
||||
assert( 0 && "NO Successor?");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//get the predecessor of the BasicBlock
|
||||
BasicBlock* ModuloScheduling::getPredBB(BasicBlock* bb){
|
||||
|
||||
BasicBlock* pred_bb;
|
||||
|
||||
for(unsigned i=0;i < II; i++)
|
||||
for(unsigned j=0;j< coreSchedule[i].size();j++)
|
||||
if(coreSchedule[i][j]){
|
||||
const Instruction* ist=coreSchedule[i][j]->getInst();
|
||||
|
||||
//we can get predecessor from the PHINode instruction
|
||||
//assume we only have one predecessor (besides itself) here
|
||||
if(PHINode::classof(ist)){
|
||||
PHINode* phi=(PHINode*) ist;
|
||||
assert(phi->getNumIncomingValues() == 2 &&" the number of incoming value is not equal to two? ");
|
||||
BasicBlock* bb1= phi->getIncomingBlock(0);
|
||||
BasicBlock* bb2= phi->getIncomingBlock(1);
|
||||
assert( (bb1 == bb || bb2 == bb) && " None of its predecessor is itself?");
|
||||
if(bb1 == bb) pred_bb=bb2;
|
||||
else pred_bb=bb1;
|
||||
return pred_bb;
|
||||
}
|
||||
}
|
||||
assert(0 && " no predecessor?");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//construct the prologue
|
||||
void ModuloScheduling::constructPrologue(BasicBlock* prologue){
|
||||
|
||||
InstListType& prologue_ist = prologue->getInstList();
|
||||
vvNodeType& tempSchedule_prologue= *(new vector< std::vector<ModuloSchedGraphNode*> >(schedule));
|
||||
|
||||
//compute the schedule for prologue
|
||||
unsigned round=0;
|
||||
unsigned scheduleSize=schedule.size();
|
||||
while(round < scheduleSize/II){
|
||||
round++;
|
||||
for(unsigned i=0;i < scheduleSize ;i++){
|
||||
if(round*II + i >= scheduleSize) break;
|
||||
for(unsigned j=0;j < schedule[i].size(); j++)
|
||||
if(schedule[i][j]){
|
||||
assert( tempSchedule_prologue[round*II +i ][j] == NULL && "table not consitant with core table");
|
||||
|
||||
//move the schedule one iteration ahead and overlap with the original one
|
||||
tempSchedule_prologue[round*II + i][j]=schedule[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//clear the clone memory in the core schedule instructions
|
||||
clearCloneMemory();
|
||||
|
||||
//fill in the prologue
|
||||
for(unsigned i=0;i < ceil(1.0*scheduleSize/II -1)*II ;i++)
|
||||
for(unsigned j=0;j < tempSchedule_prologue[i].size();j++)
|
||||
if(tempSchedule_prologue[i][j]){
|
||||
|
||||
//get the instruction
|
||||
Instruction* orn=(Instruction*)tempSchedule_prologue[i][j]->getInst();
|
||||
|
||||
//made a clone of it
|
||||
Instruction* cln=cloneInstSetMemory(orn);
|
||||
|
||||
//insert the instruction
|
||||
prologue_ist.insert(prologue_ist.back(),cln );
|
||||
|
||||
//if there is PHINode in the prologue, the incoming value from itself should be removed
|
||||
//because it is not a loop any longer
|
||||
if( PHINode::classof(cln)){
|
||||
PHINode* phi=(PHINode*)cln;
|
||||
phi->removeIncomingValue(phi->getParent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//construct the kernel BasicBlock
|
||||
void ModuloScheduling::constructKernel(BasicBlock* prologue,BasicBlock* kernel,BasicBlock* epilogue){
|
||||
|
||||
//*************fill instructions in the kernel****************
|
||||
InstListType& kernel_ist = kernel->getInstList();
|
||||
BranchInst* brchInst;
|
||||
PHINode* phiInst, *phiCln;
|
||||
|
||||
for(unsigned i=0;i<coreSchedule.size();i++)
|
||||
for(unsigned j=0;j<coreSchedule[i].size();j++)
|
||||
if(coreSchedule[i][j]){
|
||||
|
||||
//we should take care of branch instruction differently with normal instructions
|
||||
if(BranchInst::classof(coreSchedule[i][j]->getInst())){
|
||||
brchInst=(BranchInst*)coreSchedule[i][j]->getInst();
|
||||
continue;
|
||||
}
|
||||
|
||||
//we should take care of PHINode instruction differently with normal instructions
|
||||
if( PHINode::classof(coreSchedule[i][j]->getInst())){
|
||||
phiInst= (PHINode*)coreSchedule[i][j]->getInst();
|
||||
Instruction* cln=cloneInstSetMemory(phiInst);
|
||||
kernel_ist.insert(kernel_ist.back(),cln);
|
||||
phiCln=(PHINode*)cln;
|
||||
continue;
|
||||
}
|
||||
|
||||
//for normal instructions: made a clone and insert it in the kernel_ist
|
||||
Instruction* cln=cloneInstSetMemory( (Instruction*)coreSchedule[i][j]->getInst());
|
||||
kernel_ist.insert(kernel_ist.back(),cln);
|
||||
}
|
||||
|
||||
//the two incoming BasicBlock for PHINode is the prologue and the kernel (itself)
|
||||
phiCln->setIncomingBlock(0,prologue);
|
||||
phiCln->setIncomingBlock(1,kernel);
|
||||
|
||||
//the incoming value for the kernel (itself) is the new value which is computed in the kernel
|
||||
Instruction* originalVal=(Instruction*)phiInst->getIncomingValue(1);
|
||||
phiCln->setIncomingValue(1, originalVal->getClone());
|
||||
|
||||
|
||||
//make a clone of the branch instruction and insert it in the end
|
||||
BranchInst* cln=(BranchInst*)cloneInstSetMemory( brchInst);
|
||||
kernel_ist.insert(kernel_ist.back(),cln);
|
||||
|
||||
//delete the unconditional branch instruction, which is generated when splitting the basicBlock
|
||||
kernel_ist.erase( --kernel_ist.end());
|
||||
|
||||
//set the first successor to itself
|
||||
((BranchInst*)cln)->setSuccessor(0, kernel);
|
||||
//set the second successor to eiplogue
|
||||
((BranchInst*)cln)->setSuccessor(1,epilogue);
|
||||
|
||||
//*****change the condition*******
|
||||
|
||||
//get the condition instruction
|
||||
Instruction* cond=(Instruction*)cln->getCondition();
|
||||
|
||||
//get the condition's second operand, it should be a constant
|
||||
Value* operand=cond->getOperand(1);
|
||||
assert(ConstantSInt::classof(operand));
|
||||
|
||||
//change the constant in the condtion instruction
|
||||
ConstantSInt* iteTimes=ConstantSInt::get(operand->getType(),((ConstantSInt*)operand)->getValue()-II+1);
|
||||
cond->setOperand(1,iteTimes);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//construct the epilogue
|
||||
void ModuloScheduling::constructEpilogue(BasicBlock* epilogue, BasicBlock* succ_bb){
|
||||
|
||||
//compute the schedule for epilogue
|
||||
vvNodeType& tempSchedule_epilogue= *(new vector< std::vector<ModuloSchedGraphNode*> >(schedule));
|
||||
unsigned scheduleSize=schedule.size();
|
||||
int round =0;
|
||||
while(round < ceil(1.0*scheduleSize/II )-1 ){
|
||||
round++;
|
||||
for( unsigned i=0;i < scheduleSize ; i++){
|
||||
if(i + round *II >= scheduleSize) break;
|
||||
for(unsigned j=0;j < schedule[i].size();j++)
|
||||
if(schedule[i + round*II ][j]){
|
||||
assert( tempSchedule_epilogue[i][j] == NULL && "table not consitant with core table");
|
||||
|
||||
//move the schdule one iteration behind and overlap
|
||||
tempSchedule_epilogue[i][j]=schedule[i + round*II][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fill in the epilogue
|
||||
InstListType& epilogue_ist = epilogue->getInstList();
|
||||
for(unsigned i=II;i <scheduleSize ;i++)
|
||||
for(unsigned j=0;j < tempSchedule_epilogue[i].size();j++)
|
||||
if(tempSchedule_epilogue[i][j]){
|
||||
Instruction* inst=(Instruction*)tempSchedule_epilogue[i][j]->getInst();
|
||||
|
||||
//BranchInst and PHINode should be treated differently
|
||||
//BranchInst:unecessary, simly omitted
|
||||
//PHINode: omitted
|
||||
if( !BranchInst::classof(inst) && ! PHINode::classof(inst) ){
|
||||
//make a clone instruction and insert it into the epilogue
|
||||
Instruction* cln=cloneInstSetMemory(inst);
|
||||
epilogue_ist.push_front(cln);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//*************delete the original instructions****************//
|
||||
//to delete the original instructions, we have to make sure their use is zero
|
||||
|
||||
//update original core instruction's uses, using its clone instread
|
||||
for(unsigned i=0;i < II; i++)
|
||||
for(unsigned j=0;j < coreSchedule[i].size() ;j++){
|
||||
if(coreSchedule[i][j])
|
||||
updateUseWithClone((Instruction*)coreSchedule[i][j]->getInst() );
|
||||
}
|
||||
|
||||
//erase these instructions
|
||||
for(unsigned i=0;i < II; i++)
|
||||
for(unsigned j=0;j < coreSchedule[i].size();j++)
|
||||
if(coreSchedule[i][j]){
|
||||
Instruction* ist=(Instruction*)coreSchedule[i][j]->getInst();
|
||||
ist->getParent()->getInstList().erase(ist);
|
||||
}
|
||||
//**************************************************************//
|
||||
|
||||
|
||||
//finally, insert an unconditional branch instruction at the end
|
||||
epilogue_ist.push_back(new BranchInst(succ_bb));
|
||||
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
//this function replace the value(instruction) ist in other instructions with its latest clone
|
||||
//i.e. after this function is called, the ist is not used anywhere and it can be erased.
|
||||
//----------------------------------------------------------------------------------------------
|
||||
void ModuloScheduling::updateUseWithClone(Instruction* ist){
|
||||
|
||||
while(ist->use_size() >0){
|
||||
bool destroyed=false;
|
||||
|
||||
//other instruction is using this value ist
|
||||
assert(Instruction::classof(*ist->use_begin()));
|
||||
Instruction *inst=(Instruction*)(* ist->use_begin());
|
||||
|
||||
for(unsigned i=0;i<inst->getNumOperands();i++)
|
||||
if(inst->getOperand(i) == ist && ist->getClone()){
|
||||
|
||||
//if the instruction is TmpInstruction, simly delete it because it has no parent
|
||||
// and it does not belongs to any BasicBlock
|
||||
if(TmpInstruction::classof(inst)) {
|
||||
delete inst;
|
||||
destroyed=true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//otherwise, set the instruction's operand to the value's clone
|
||||
inst->setOperand(i, ist->getClone());
|
||||
|
||||
//the use from the original value ist is destroyed
|
||||
destroyed=true;
|
||||
break;
|
||||
}
|
||||
if( !destroyed)
|
||||
{
|
||||
//if the use can not be destroyed , something is wrong
|
||||
inst->dump();
|
||||
assert( 0 &&"this use can not be destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//********************************************************
|
||||
//this function clear all clone mememoy
|
||||
//i.e. set all instruction's clone memory to NULL
|
||||
//*****************************************************
|
||||
void ModuloScheduling::clearCloneMemory(){
|
||||
for(unsigned i=0; i < coreSchedule.size();i++)
|
||||
for(unsigned j=0;j<coreSchedule[i].size();j++)
|
||||
if(coreSchedule[i][j]) ((Instruction*)coreSchedule[i][j]->getInst())->clearClone();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//********************************************************************************
|
||||
//this function make a clone of the instruction orn
|
||||
//the cloned instruction will use the orn's operands' latest clone as its operands
|
||||
//it is done this way because LLVM is in SSA form and we should use the correct value
|
||||
//
|
||||
//this fuction also update the instruction orn's latest clone memory
|
||||
//**********************************************************************************
|
||||
Instruction* ModuloScheduling::cloneInstSetMemory(Instruction* orn) {
|
||||
|
||||
//make a clone instruction
|
||||
Instruction* cln=orn->clone();
|
||||
|
||||
|
||||
//update the operands
|
||||
for(unsigned k=0;k<orn->getNumOperands();k++){
|
||||
const Value* op=orn->getOperand(k);
|
||||
if(Instruction::classof(op) && ((Instruction*)op)->getClone()){
|
||||
Instruction* op_inst=(Instruction*)op;
|
||||
cln->setOperand(k, op_inst->getClone());
|
||||
}
|
||||
}
|
||||
|
||||
//update clone memory
|
||||
orn->setClone(cln);
|
||||
return cln;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ModuloScheduling::ScheduleNode(ModuloSchedGraphNode* node,unsigned start, unsigned end, NodeVec& nodeScheduled)
|
||||
{
|
||||
|
||||
const MachineSchedInfo& msi=target.getSchedInfo();
|
||||
unsigned int numIssueSlots=msi.maxNumIssueTotal;
|
||||
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os<<"startTime= "<<start<<" endTime= "<<end<<"\n";
|
||||
bool isScheduled=false;
|
||||
for(unsigned i=start;i<= end;i++){
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os<< " now try cycle " <<i<<":"<<"\n";
|
||||
for(unsigned j=0;j<numIssueSlots;j++){
|
||||
unsigned int core_i = i%II;
|
||||
unsigned int core_j=j;
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os <<"\t Trying slot "<<j<<"...........";
|
||||
//check the resouce table, make sure there is no resource conflicts
|
||||
const Instruction* instr=node->getInst();
|
||||
MachineCodeForInstruction& tempMvec= MachineCodeForInstruction::get(instr);
|
||||
bool resourceConflict=false;
|
||||
const MachineInstrInfo &mii=msi.getInstrInfo();
|
||||
|
||||
if(coreSchedule.size() < core_i+1 || !coreSchedule[core_i][core_j]){
|
||||
//this->dumpResourceUsageTable();
|
||||
int latency=0;
|
||||
for(unsigned k=0;k< tempMvec.size();k++)
|
||||
{
|
||||
MachineInstr* minstr=tempMvec[k];
|
||||
InstrRUsage rUsage=msi.getInstrRUsage(minstr->getOpCode());
|
||||
std::vector<std::vector<resourceId_t> > resources
|
||||
=rUsage.resourcesByCycle;
|
||||
updateResourceTable(resources,i + latency);
|
||||
latency +=max(mii.minLatency(minstr->getOpCode()),1) ;
|
||||
}
|
||||
|
||||
//this->dumpResourceUsageTable();
|
||||
|
||||
latency=0;
|
||||
if( resourceTableNegative()){
|
||||
|
||||
//undo-update the resource table
|
||||
for(unsigned k=0;k< tempMvec.size();k++){
|
||||
MachineInstr* minstr=tempMvec[k];
|
||||
InstrRUsage rUsage=msi.getInstrRUsage(minstr->getOpCode());
|
||||
std::vector<std::vector<resourceId_t> > resources
|
||||
=rUsage.resourcesByCycle;
|
||||
undoUpdateResourceTable(resources,i + latency);
|
||||
latency +=max(mii.minLatency(minstr->getOpCode()),1) ;
|
||||
}
|
||||
resourceConflict=true;
|
||||
}
|
||||
}
|
||||
if( !resourceConflict && !coreSchedule[core_i][core_j]){
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess){
|
||||
modSched_os <<" OK!"<<"\n";
|
||||
modSched_os<<"Node "<<node->getNodeId()<< " is scheduleed."<<"\n";
|
||||
}
|
||||
//schedule[i][j]=node;
|
||||
while(schedule.size() <= i){
|
||||
std::vector<ModuloSchedGraphNode*>* newCycle=new std::vector<ModuloSchedGraphNode*>();
|
||||
for(unsigned k=0;k<numIssueSlots;k++)
|
||||
newCycle->push_back(NULL);
|
||||
schedule.push_back(*newCycle);
|
||||
}
|
||||
vector<ModuloSchedGraphNode*>::iterator startIterator;
|
||||
startIterator = schedule[i].begin();
|
||||
schedule[i].insert(startIterator+j,node);
|
||||
startIterator = schedule[i].begin();
|
||||
schedule[i].erase(startIterator+j+1);
|
||||
|
||||
//update coreSchedule
|
||||
//coreSchedule[core_i][core_j]=node;
|
||||
while(coreSchedule.size() <= core_i){
|
||||
std::vector<ModuloSchedGraphNode*>* newCycle=new std::vector<ModuloSchedGraphNode*>();
|
||||
for(unsigned k=0;k<numIssueSlots;k++)
|
||||
newCycle->push_back(NULL);
|
||||
coreSchedule.push_back(*newCycle);
|
||||
}
|
||||
|
||||
startIterator = coreSchedule[core_i].begin();
|
||||
coreSchedule[core_i].insert(startIterator+core_j,node);
|
||||
startIterator = coreSchedule[core_i].begin();
|
||||
coreSchedule[core_i].erase(startIterator+core_j+1);
|
||||
|
||||
node->setSchTime(i);
|
||||
isScheduled=true;
|
||||
nodeScheduled.push_back(node);
|
||||
|
||||
break;
|
||||
}
|
||||
else if( coreSchedule[core_i][core_j]) {
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os <<" Slot not available "<<"\n";
|
||||
}
|
||||
else{
|
||||
if( ModuloSchedDebugLevel >= ModuloSched_PrintScheduleProcess)
|
||||
modSched_os <<" Resource conflicts"<<"\n";
|
||||
}
|
||||
}
|
||||
if(isScheduled) break;
|
||||
}
|
||||
//assert(nodeScheduled &&"this node can not be scheduled?");
|
||||
return isScheduled;
|
||||
}
|
||||
|
||||
void ModuloScheduling::updateResourceTable(std::vector<std::vector<unsigned int> > useResources, int startCycle){
|
||||
for(unsigned i=0;i< useResources.size();i++){
|
||||
int absCycle=startCycle+i;
|
||||
int coreCycle=absCycle % II;
|
||||
std::vector<pair<int,int> >& resourceRemained=resourceTable[coreCycle];
|
||||
std::vector<unsigned int>& resourceUsed= useResources[i];
|
||||
for(unsigned j=0;j< resourceUsed.size();j++){
|
||||
for(unsigned k=0;k< resourceRemained.size();k++)
|
||||
if((int)resourceUsed[j] == resourceRemained[k].first){
|
||||
resourceRemained[k].second--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModuloScheduling::undoUpdateResourceTable(std::vector<std::vector<unsigned int> > useResources, int startCycle){
|
||||
for(unsigned i=0;i< useResources.size();i++){
|
||||
int absCycle=startCycle+i;
|
||||
int coreCycle=absCycle % II;
|
||||
std::vector<pair<int,int> >& resourceRemained=resourceTable[coreCycle];
|
||||
std::vector<unsigned int>& resourceUsed= useResources[i];
|
||||
for(unsigned j=0;j< resourceUsed.size();j++){
|
||||
for(unsigned k=0;k< resourceRemained.size();k++)
|
||||
if((int)resourceUsed[j] == resourceRemained[k].first){
|
||||
resourceRemained[k].second++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
//Function: resouceTableNegative
|
||||
//return value:
|
||||
// return false if any element in the resouceTable is negative
|
||||
// otherwise return true
|
||||
//Purpose:
|
||||
// this function is used to determine if an instruction is eligible for schedule at certain cycle
|
||||
//---------------------------------------------------------------------------------------
|
||||
|
||||
bool ModuloScheduling::resourceTableNegative(){
|
||||
assert(resourceTable.size() == (unsigned)II&& "resouceTable size must be equal to II");
|
||||
bool isNegative=false;
|
||||
for(unsigned i=0; i < resourceTable.size();i++)
|
||||
for(unsigned j=0;j < resourceTable[i].size();j++){
|
||||
if(resourceTable[i][j].second <0) {
|
||||
isNegative=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isNegative;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//Function: dumpResouceUsageTable
|
||||
//Purpose:
|
||||
// print out ResouceTable for debug
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
void ModuloScheduling::dumpResourceUsageTable(){
|
||||
modSched_os<<"dumping resource usage table"<<"\n";
|
||||
for(unsigned i=0;i< resourceTable.size();i++){
|
||||
for(unsigned j=0;j < resourceTable[i].size();j++)
|
||||
modSched_os <<resourceTable[i][j].first<<":"<< resourceTable[i][j].second<<" ";
|
||||
modSched_os <<"\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//Function: dumpSchedule
|
||||
//Purpose:
|
||||
// print out thisSchedule for debug
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
void ModuloScheduling::dumpSchedule(std::vector< std::vector<ModuloSchedGraphNode*> > thisSchedule){
|
||||
|
||||
const MachineSchedInfo& msi=target.getSchedInfo();
|
||||
unsigned numIssueSlots=msi.maxNumIssueTotal;
|
||||
for(unsigned i=0;i< numIssueSlots;i++)
|
||||
modSched_os <<"\t#";
|
||||
modSched_os<<"\n";
|
||||
for(unsigned i=0;i < thisSchedule.size();i++)
|
||||
{
|
||||
modSched_os<<"cycle"<<i<<": ";
|
||||
for(unsigned j=0;j<thisSchedule[i].size();j++)
|
||||
if(thisSchedule[i][j]!= NULL)
|
||||
modSched_os<<thisSchedule[i][j]->getNodeId()<<"\t";
|
||||
else
|
||||
modSched_os<<"\t";
|
||||
modSched_os<<"\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------
|
||||
//Function: dumpScheduling
|
||||
//Purpose:
|
||||
// print out the schedule and coreSchedule for debug
|
||||
//
|
||||
//-------------------------------------------------------
|
||||
|
||||
void ModuloScheduling::dumpScheduling(){
|
||||
modSched_os<<"dump schedule:"<<"\n";
|
||||
const MachineSchedInfo& msi=target.getSchedInfo();
|
||||
unsigned numIssueSlots=msi.maxNumIssueTotal;
|
||||
for(unsigned i=0;i< numIssueSlots;i++)
|
||||
modSched_os <<"\t#";
|
||||
modSched_os<<"\n";
|
||||
for(unsigned i=0;i < schedule.size();i++)
|
||||
{
|
||||
modSched_os<<"cycle"<<i<<": ";
|
||||
for(unsigned j=0;j<schedule[i].size();j++)
|
||||
if(schedule[i][j]!= NULL)
|
||||
modSched_os<<schedule[i][j]->getNodeId()<<"\t";
|
||||
else
|
||||
modSched_os<<"\t";
|
||||
modSched_os<<"\n";
|
||||
}
|
||||
|
||||
modSched_os<<"dump coreSchedule:"<<"\n";
|
||||
for(unsigned i=0;i< numIssueSlots;i++)
|
||||
modSched_os <<"\t#";
|
||||
modSched_os<<"\n";
|
||||
for(unsigned i=0;i < coreSchedule.size();i++){
|
||||
modSched_os<<"cycle"<<i<<": ";
|
||||
for(unsigned j=0;j< coreSchedule[i].size();j++)
|
||||
if(coreSchedule[i][j] !=NULL)
|
||||
modSched_os<<coreSchedule[i][j]->getNodeId()<<"\t";
|
||||
else
|
||||
modSched_os<<"\t";
|
||||
modSched_os<<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Function: ModuloSchedulingPass
|
||||
//
|
||||
// Purpose:
|
||||
// Entry point for Modulo Scheduling
|
||||
// Schedules LLVM instruction
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
class ModuloSchedulingPass : public FunctionPass {
|
||||
const TargetMachine ⌖
|
||||
public:
|
||||
ModuloSchedulingPass(const TargetMachine &T) : target(T) {}
|
||||
const char *getPassName() const { return "Modulo Scheduling"; }
|
||||
|
||||
// getAnalysisUsage - We use LiveVarInfo...
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
//AU.addRequired(FunctionLiveVarInfo::ID);
|
||||
}
|
||||
bool runOnFunction(Function &F);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
|
||||
bool ModuloSchedulingPass::runOnFunction(Function &F)
|
||||
{
|
||||
|
||||
//if necessary , open the output for debug purpose
|
||||
if(ModuloSchedDebugLevel== ModuloSched_Disable)
|
||||
return false;
|
||||
|
||||
if(ModuloSchedDebugLevel>= ModuloSched_PrintSchedule){
|
||||
modSched_fb.open("moduloSchedDebugInfo.output", ios::out);
|
||||
modSched_os<<"******************Modula Scheduling debug information*************************"<<endl;
|
||||
}
|
||||
|
||||
ModuloSchedGraphSet* graphSet = new ModuloSchedGraphSet(&F,target);
|
||||
ModuloSchedulingSet ModuloSchedulingSet(*graphSet);
|
||||
|
||||
if(ModuloSchedDebugLevel>= ModuloSched_PrintSchedule)
|
||||
modSched_fb.close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Pass *createModuloSchedulingPass(const TargetMachine &tgt) {
|
||||
return new ModuloSchedulingPass(tgt);
|
||||
}
|
||||
|
160
lib/CodeGen/ModuloScheduling/ModuloScheduling.h
Normal file
160
lib/CodeGen/ModuloScheduling/ModuloScheduling.h
Normal file
@ -0,0 +1,160 @@
|
||||
//// - head file for the classes ModuloScheduling and ModuloScheduling ----*- C++ -*-===//
|
||||
//
|
||||
// This header defines the the classes ModuloScheduling and ModuloSchedulingSet 's structure
|
||||
//
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CODEGEN_MODULOSCHEDULING_H
|
||||
#define LLVM_CODEGEN_MODULOSCHEDULING_H
|
||||
|
||||
#include "ModuloSchedGraph.h"
|
||||
#include <iostream>
|
||||
|
||||
class ModuloScheduling:NonCopyable {
|
||||
private:
|
||||
typedef std::vector<ModuloSchedGraphNode*> NodeVec;
|
||||
|
||||
/// the graph to feed in
|
||||
ModuloSchedGraph& graph;
|
||||
const TargetMachine& target;
|
||||
|
||||
//the BasicBlock to be scheduled
|
||||
BasicBlock* bb;
|
||||
|
||||
///Iteration Intervel
|
||||
///FIXME: II may be a better name for its meaning
|
||||
unsigned II;
|
||||
|
||||
//the vector containing the nodes which have been scheduled
|
||||
NodeVec nodeScheduled;
|
||||
|
||||
///the remaining unscheduled nodes
|
||||
const NodeVec& oNodes;
|
||||
|
||||
///the machine resource table
|
||||
std::vector< std::vector<pair<int,int> > > resourceTable ;
|
||||
|
||||
///the schedule( with many schedule stage)
|
||||
std::vector<std::vector<ModuloSchedGraphNode*> > schedule;
|
||||
|
||||
///the kernel(core) schedule(length = II)
|
||||
std::vector<std::vector<ModuloSchedGraphNode*> > coreSchedule;
|
||||
|
||||
typedef BasicBlock::InstListType InstListType;
|
||||
typedef std::vector <std::vector<ModuloSchedGraphNode*> > vvNodeType;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
///constructor
|
||||
ModuloScheduling(ModuloSchedGraph& _graph):
|
||||
graph(_graph),
|
||||
target(graph.getTarget()),
|
||||
oNodes(graph.getONodes())
|
||||
{
|
||||
II = graph.getMII();
|
||||
bb=(BasicBlock*)graph.getBasicBlocks()[0];
|
||||
|
||||
instrScheduling();
|
||||
};
|
||||
|
||||
///destructor
|
||||
~ModuloScheduling(){};
|
||||
|
||||
///the method to compute schedule and instert epilogue and prologue
|
||||
void instrScheduling();
|
||||
|
||||
///debug functions:
|
||||
///dump the schedule and core schedule
|
||||
void dumpScheduling();
|
||||
|
||||
///dump the input vector of nodes
|
||||
//sch: the input vector of nodes
|
||||
void dumpSchedule( std::vector<std::vector<ModuloSchedGraphNode*> > sch);
|
||||
|
||||
///dump the resource usage table
|
||||
void dumpResourceUsageTable();
|
||||
|
||||
|
||||
//*******************internel functions*******************************
|
||||
private:
|
||||
//clear memory from the last round and initialize if necessary
|
||||
void clearInitMem(const MachineSchedInfo& );
|
||||
|
||||
//compute schedule and coreSchedule with the current II
|
||||
bool computeSchedule();
|
||||
|
||||
BasicBlock* getSuccBB(BasicBlock*);
|
||||
BasicBlock* getPredBB(BasicBlock*);
|
||||
void constructPrologue(BasicBlock* prologue);
|
||||
void constructKernel(BasicBlock* prologue,BasicBlock* kernel,BasicBlock* epilogue);
|
||||
void constructEpilogue(BasicBlock* epilogue,BasicBlock* succ_bb);
|
||||
|
||||
///update the resource table at the startCycle
|
||||
//vec: the resouce usage
|
||||
//startCycle: the start cycle the resouce usage is
|
||||
void updateResourceTable(std::vector<vector<unsigned int> > vec,int startCycle);
|
||||
|
||||
///un-do the update in the resource table in the startCycle
|
||||
//vec: the resouce usage
|
||||
//startCycle: the start cycle the resouce usage is
|
||||
void undoUpdateResourceTable(std::vector<vector<unsigned int> > vec,int startCycle);
|
||||
|
||||
///return whether the resourcetable has negative element
|
||||
///this function is called after updateResouceTable() to determine whether a node can
|
||||
/// be scheduled at certain cycle
|
||||
bool resourceTableNegative();
|
||||
|
||||
|
||||
///try to Schedule the node starting from start to end cycle(inclusive)
|
||||
//if it can be scheduled, put it in the schedule and update nodeScheduled
|
||||
//node: the node to be scheduled
|
||||
//start: start cycle
|
||||
//end : end cycle
|
||||
//nodeScheduled: a vector storing nodes which has been scheduled
|
||||
bool ScheduleNode(ModuloSchedGraphNode* node,unsigned start, unsigned end, NodeVec& nodeScheduled);
|
||||
|
||||
//each instruction has a memory of the latest clone instruction
|
||||
//the clone instruction can be get using getClone()
|
||||
//this function clears the memory, i.e. getClone() after calling this function returns null
|
||||
void clearCloneMemory();
|
||||
|
||||
//this fuction make a clone of this input Instruction and update the clone memory
|
||||
//inst: the instrution to be cloned
|
||||
Instruction* cloneInstSetMemory(Instruction* inst);
|
||||
|
||||
//this function update each instrutions which uses ist as its operand
|
||||
//after update, each instruction will use ist's clone as its operand
|
||||
void updateUseWithClone(Instruction* ist);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ModuloSchedulingSet:NonCopyable{
|
||||
private:
|
||||
|
||||
//the graphSet to feed in
|
||||
ModuloSchedGraphSet& graphSet;
|
||||
public:
|
||||
|
||||
//constructor
|
||||
//Scheduling graph one by one
|
||||
ModuloSchedulingSet(ModuloSchedGraphSet _graphSet):graphSet(_graphSet){
|
||||
for(unsigned i=0;i<graphSet.size();i++){
|
||||
ModuloSchedGraph& graph=*(graphSet[i]);
|
||||
if(graph.isLoop())ModuloScheduling ModuloScheduling(graph);
|
||||
}
|
||||
};
|
||||
|
||||
//destructor
|
||||
~ModuloSchedulingSet(){};
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user