Home | History | Annotate | Download | only in TableGen
      1 //===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine-----===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This class parses the Schedule.td file and produces an API that can be used
     11 // to reason about whether an instruction can be added to a packet on a VLIW
     12 // architecture. The class internally generates a deterministic finite
     13 // automaton (DFA) that models all possible mappings of machine instructions
     14 // to functional units as instructions are added to a packet.
     15 //
     16 //===----------------------------------------------------------------------===//
     17 
     18 #include "llvm/TableGen/Record.h"
     19 #include "CodeGenTarget.h"
     20 #include "DFAPacketizerEmitter.h"
     21 #include <list>
     22 
     23 using namespace llvm;
     24 
     25 //
     26 //
     27 // State represents the usage of machine resources if the packet contains
     28 // a set of instruction classes.
     29 //
     30 // Specifically, currentState is a set of bit-masks.
     31 // The nth bit in a bit-mask indicates whether the nth resource is being used
     32 // by this state. The set of bit-masks in a state represent the different
     33 // possible outcomes of transitioning to this state.
     34 // For example: consider a two resource architecture: resource L and resource M
     35 // with three instruction classes: L, M, and L_or_M.
     36 // From the initial state (currentState = 0x00), if we add instruction class
     37 // L_or_M we will transition to a state with currentState = [0x01, 0x10]. This
     38 // represents the possible resource states that can result from adding a L_or_M
     39 // instruction
     40 //
     41 // Another way of thinking about this transition is we are mapping a NDFA with
     42 // two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10].
     43 //
     44 //
     45 namespace {
     46 class State {
     47  public:
     48   static int currentStateNum;
     49   int stateNum;
     50   bool isInitial;
     51   std::set<unsigned> stateInfo;
     52 
     53   State();
     54   State(const State &S);
     55 
     56   //
     57   // canAddInsnClass - Returns true if an instruction of type InsnClass is a
     58   // valid transition from this state, i.e., can an instruction of type InsnClass
     59   // be added to the packet represented by this state.
     60   //
     61   // PossibleStates is the set of valid resource states that ensue from valid
     62   // transitions.
     63   //
     64   bool canAddInsnClass(unsigned InsnClass, std::set<unsigned> &PossibleStates);
     65 };
     66 } // End anonymous namespace.
     67 
     68 
     69 namespace {
     70 struct Transition {
     71  public:
     72   static int currentTransitionNum;
     73   int transitionNum;
     74   State *from;
     75   unsigned input;
     76   State *to;
     77 
     78   Transition(State *from_, unsigned input_, State *to_);
     79 };
     80 } // End anonymous namespace.
     81 
     82 
     83 //
     84 // Comparators to keep set of states sorted.
     85 //
     86 namespace {
     87 struct ltState {
     88   bool operator()(const State *s1, const State *s2) const;
     89 };
     90 } // End anonymous namespace.
     91 
     92 
     93 //
     94 // class DFA: deterministic finite automaton for processor resource tracking.
     95 //
     96 namespace {
     97 class DFA {
     98 public:
     99   DFA();
    100 
    101   // Set of states. Need to keep this sorted to emit the transition table.
    102   std::set<State*, ltState> states;
    103 
    104   // Map from a state to the list of transitions with that state as source.
    105   std::map<State*, SmallVector<Transition*, 16>, ltState> stateTransitions;
    106   State *currentState;
    107 
    108   // Highest valued Input seen.
    109   unsigned LargestInput;
    110 
    111   //
    112   // Modify the DFA.
    113   //
    114   void initialize();
    115   void addState(State *);
    116   void addTransition(Transition *);
    117 
    118   //
    119   // getTransition -  Return the state when a transition is made from
    120   // State From with Input I. If a transition is not found, return NULL.
    121   //
    122   State *getTransition(State *, unsigned);
    123 
    124   //
    125   // isValidTransition: Predicate that checks if there is a valid transition
    126   // from state From on input InsnClass.
    127   //
    128   bool isValidTransition(State *From, unsigned InsnClass);
    129 
    130   //
    131   // writeTable: Print out a table representing the DFA.
    132   //
    133   void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName);
    134 };
    135 } // End anonymous namespace.
    136 
    137 
    138 //
    139 // Constructors for State, Transition, and DFA
    140 //
    141 State::State() :
    142   stateNum(currentStateNum++), isInitial(false) {}
    143 
    144 
    145 State::State(const State &S) :
    146   stateNum(currentStateNum++), isInitial(S.isInitial),
    147   stateInfo(S.stateInfo) {}
    148 
    149 
    150 Transition::Transition(State *from_, unsigned input_, State *to_) :
    151   transitionNum(currentTransitionNum++), from(from_), input(input_),
    152   to(to_) {}
    153 
    154 
    155 DFA::DFA() :
    156   LargestInput(0) {}
    157 
    158 
    159 bool ltState::operator()(const State *s1, const State *s2) const {
    160     return (s1->stateNum < s2->stateNum);
    161 }
    162 
    163 
    164 //
    165 // canAddInsnClass - Returns true if an instruction of type InsnClass is a
    166 // valid transition from this state i.e., can an instruction of type InsnClass
    167 // be added to the packet represented by this state.
    168 //
    169 // PossibleStates is the set of valid resource states that ensue from valid
    170 // transitions.
    171 //
    172 bool State::canAddInsnClass(unsigned InsnClass,
    173                             std::set<unsigned> &PossibleStates) {
    174   //
    175   // Iterate over all resource states in currentState.
    176   //
    177   bool AddedState = false;
    178 
    179   for (std::set<unsigned>::iterator SI = stateInfo.begin();
    180        SI != stateInfo.end(); ++SI) {
    181     unsigned thisState = *SI;
    182 
    183     //
    184     // Iterate over all possible resources used in InsnClass.
    185     // For ex: for InsnClass = 0x11, all resources = {0x01, 0x10}.
    186     //
    187 
    188     DenseSet<unsigned> VisitedResourceStates;
    189     for (unsigned int j = 0; j < sizeof(InsnClass) * 8; ++j) {
    190       if ((0x1 << j) & InsnClass) {
    191         //
    192         // For each possible resource used in InsnClass, generate the
    193         // resource state if that resource was used.
    194         //
    195         unsigned ResultingResourceState = thisState | (0x1 << j);
    196         //
    197         // Check if the resulting resource state can be accommodated in this
    198         // packet.
    199         // We compute ResultingResourceState OR thisState.
    200         // If the result of the OR is different than thisState, it implies
    201         // that there is at least one resource that can be used to schedule
    202         // InsnClass in the current packet.
    203         // Insert ResultingResourceState into PossibleStates only if we haven't
    204         // processed ResultingResourceState before.
    205         //
    206         if ((ResultingResourceState != thisState) &&
    207             (VisitedResourceStates.count(ResultingResourceState) == 0)) {
    208           VisitedResourceStates.insert(ResultingResourceState);
    209           PossibleStates.insert(ResultingResourceState);
    210           AddedState = true;
    211         }
    212       }
    213     }
    214   }
    215 
    216   return AddedState;
    217 }
    218 
    219 
    220 void DFA::initialize() {
    221   currentState->isInitial = true;
    222 }
    223 
    224 
    225 void DFA::addState(State *S) {
    226   assert(!states.count(S) && "State already exists");
    227   states.insert(S);
    228 }
    229 
    230 
    231 void DFA::addTransition(Transition *T) {
    232   // Update LargestInput.
    233   if (T->input > LargestInput)
    234     LargestInput = T->input;
    235 
    236   // Add the new transition.
    237   stateTransitions[T->from].push_back(T);
    238 }
    239 
    240 
    241 //
    242 // getTransition - Return the state when a transition is made from
    243 // State From with Input I. If a transition is not found, return NULL.
    244 //
    245 State *DFA::getTransition(State *From, unsigned I) {
    246   // Do we have a transition from state From?
    247   if (!stateTransitions.count(From))
    248     return NULL;
    249 
    250   // Do we have a transition from state From with Input I?
    251   for (SmallVector<Transition*, 16>::iterator VI =
    252          stateTransitions[From].begin();
    253          VI != stateTransitions[From].end(); ++VI)
    254     if ((*VI)->input == I)
    255       return (*VI)->to;
    256 
    257   return NULL;
    258 }
    259 
    260 
    261 bool DFA::isValidTransition(State *From, unsigned InsnClass) {
    262   return (getTransition(From, InsnClass) != NULL);
    263 }
    264 
    265 
    266 int State::currentStateNum = 0;
    267 int Transition::currentTransitionNum = 0;
    268 
    269 DFAGen::DFAGen(RecordKeeper &R):
    270   TargetName(CodeGenTarget(R).getName()),
    271   allInsnClasses(), Records(R) {}
    272 
    273 
    274 //
    275 // writeTableAndAPI - Print out a table representing the DFA and the
    276 // associated API to create a DFA packetizer.
    277 //
    278 // Format:
    279 // DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
    280 //                           transitions.
    281 // DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for
    282 //                         the ith state.
    283 //
    284 //
    285 void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName) {
    286   std::set<State*, ltState>::iterator SI = states.begin();
    287   // This table provides a map to the beginning of the transitions for State s
    288   // in DFAStateInputTable.
    289   std::vector<int> StateEntry(states.size());
    290 
    291   OS << "namespace llvm {\n\n";
    292   OS << "const int " << TargetName << "DFAStateInputTable[][2] = {\n";
    293 
    294   // Tracks the total valid transitions encountered so far. It is used
    295   // to construct the StateEntry table.
    296   int ValidTransitions = 0;
    297   for (unsigned i = 0; i < states.size(); ++i, ++SI) {
    298     StateEntry[i] = ValidTransitions;
    299     for (unsigned j = 0; j <= LargestInput; ++j) {
    300       assert (((*SI)->stateNum == (int) i) && "Mismatch in state numbers");
    301       if (!isValidTransition(*SI, j))
    302         continue;
    303 
    304       OS << "{" << j << ", "
    305          << getTransition(*SI, j)->stateNum
    306          << "},    ";
    307       ++ValidTransitions;
    308     }
    309 
    310     // If there are no valid transitions from this stage, we need a sentinel
    311     // transition.
    312     if (ValidTransitions == StateEntry[i]) {
    313       OS << "{-1, -1},";
    314       ++ValidTransitions;
    315     }
    316 
    317     OS << "\n";
    318   }
    319   OS << "};\n\n";
    320   OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n";
    321 
    322   // Multiply i by 2 since each entry in DFAStateInputTable is a set of
    323   // two numbers.
    324   for (unsigned i = 0; i < states.size(); ++i)
    325     OS << StateEntry[i] << ", ";
    326 
    327   OS << "\n};\n";
    328   OS << "} // namespace\n";
    329 
    330 
    331   //
    332   // Emit DFA Packetizer tables if the target is a VLIW machine.
    333   //
    334   std::string SubTargetClassName = TargetName + "GenSubtargetInfo";
    335   OS << "\n" << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
    336   OS << "namespace llvm {\n";
    337   OS << "DFAPacketizer *" << SubTargetClassName << "::"
    338      << "createDFAPacketizer(const InstrItineraryData *IID) const {\n"
    339      << "   return new DFAPacketizer(IID, " << TargetName
    340      << "DFAStateInputTable, " << TargetName << "DFAStateEntryTable);\n}\n\n";
    341   OS << "} // End llvm namespace \n";
    342 }
    343 
    344 
    345 //
    346 // collectAllInsnClasses - Populate allInsnClasses which is a set of units
    347 // used in each stage.
    348 //
    349 void DFAGen::collectAllInsnClasses(const std::string &Name,
    350                                   Record *ItinData,
    351                                   unsigned &NStages,
    352                                   raw_ostream &OS) {
    353   // Collect processor itineraries.
    354   std::vector<Record*> ProcItinList =
    355     Records.getAllDerivedDefinitions("ProcessorItineraries");
    356 
    357   // If just no itinerary then don't bother.
    358   if (ProcItinList.size() < 2)
    359     return;
    360   std::map<std::string, unsigned> NameToBitsMap;
    361 
    362   // Parse functional units for all the itineraries.
    363   for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
    364     Record *Proc = ProcItinList[i];
    365     std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
    366 
    367     // Convert macros to bits for each stage.
    368     for (unsigned i = 0, N = FUs.size(); i < N; ++i)
    369       NameToBitsMap[FUs[i]->getName()] = (unsigned) (1U << i);
    370   }
    371 
    372   const std::vector<Record*> &StageList =
    373     ItinData->getValueAsListOfDefs("Stages");
    374 
    375   // The number of stages.
    376   NStages = StageList.size();
    377 
    378   // For each unit.
    379   unsigned UnitBitValue = 0;
    380 
    381   // Compute the bitwise or of each unit used in this stage.
    382   for (unsigned i = 0; i < NStages; ++i) {
    383     const Record *Stage = StageList[i];
    384 
    385     // Get unit list.
    386     const std::vector<Record*> &UnitList =
    387       Stage->getValueAsListOfDefs("Units");
    388 
    389     for (unsigned j = 0, M = UnitList.size(); j < M; ++j) {
    390       // Conduct bitwise or.
    391       std::string UnitName = UnitList[j]->getName();
    392       assert(NameToBitsMap.count(UnitName));
    393       UnitBitValue |= NameToBitsMap[UnitName];
    394     }
    395 
    396     if (UnitBitValue != 0)
    397       allInsnClasses.insert(UnitBitValue);
    398   }
    399 }
    400 
    401 
    402 //
    403 // Run the worklist algorithm to generate the DFA.
    404 //
    405 void DFAGen::run(raw_ostream &OS) {
    406   EmitSourceFileHeader("Target DFA Packetizer Tables", OS);
    407 
    408   // Collect processor iteraries.
    409   std::vector<Record*> ProcItinList =
    410     Records.getAllDerivedDefinitions("ProcessorItineraries");
    411 
    412   //
    413   // Collect the instruction classes.
    414   //
    415   for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
    416     Record *Proc = ProcItinList[i];
    417 
    418     // Get processor itinerary name.
    419     const std::string &Name = Proc->getName();
    420 
    421     // Skip default.
    422     if (Name == "NoItineraries")
    423       continue;
    424 
    425     // Sanity check for at least one instruction itinerary class.
    426     unsigned NItinClasses =
    427       Records.getAllDerivedDefinitions("InstrItinClass").size();
    428     if (NItinClasses == 0)
    429       return;
    430 
    431     // Get itinerary data list.
    432     std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
    433 
    434     // Collect instruction classes for all itinerary data.
    435     for (unsigned j = 0, M = ItinDataList.size(); j < M; j++) {
    436       Record *ItinData = ItinDataList[j];
    437       unsigned NStages;
    438       collectAllInsnClasses(Name, ItinData, NStages, OS);
    439     }
    440   }
    441 
    442 
    443   //
    444   // Run a worklist algorithm to generate the DFA.
    445   //
    446   DFA D;
    447   State *Initial = new State;
    448   Initial->isInitial = true;
    449   Initial->stateInfo.insert(0x0);
    450   D.addState(Initial);
    451   SmallVector<State*, 32> WorkList;
    452   std::map<std::set<unsigned>, State*> Visited;
    453 
    454   WorkList.push_back(Initial);
    455 
    456   //
    457   // Worklist algorithm to create a DFA for processor resource tracking.
    458   // C = {set of InsnClasses}
    459   // Begin with initial node in worklist. Initial node does not have
    460   // any consumed resources,
    461   //     ResourceState = 0x0
    462   // Visited = {}
    463   // While worklist != empty
    464   //    S = first element of worklist
    465   //    For every instruction class C
    466   //      if we can accommodate C in S:
    467   //          S' = state with resource states = {S Union C}
    468   //          Add a new transition: S x C -> S'
    469   //          If S' is not in Visited:
    470   //             Add S' to worklist
    471   //             Add S' to Visited
    472   //
    473   while (!WorkList.empty()) {
    474     State *current = WorkList.pop_back_val();
    475     for (DenseSet<unsigned>::iterator CI = allInsnClasses.begin(),
    476            CE = allInsnClasses.end(); CI != CE; ++CI) {
    477       unsigned InsnClass = *CI;
    478 
    479       std::set<unsigned> NewStateResources;
    480       //
    481       // If we haven't already created a transition for this input
    482       // and the state can accommodate this InsnClass, create a transition.
    483       //
    484       if (!D.getTransition(current, InsnClass) &&
    485           current->canAddInsnClass(InsnClass, NewStateResources)) {
    486         State *NewState = NULL;
    487 
    488         //
    489         // If we have seen this state before, then do not create a new state.
    490         //
    491         //
    492         std::map<std::set<unsigned>, State*>::iterator VI;
    493         if ((VI = Visited.find(NewStateResources)) != Visited.end())
    494           NewState = VI->second;
    495         else {
    496           NewState = new State;
    497           NewState->stateInfo = NewStateResources;
    498           D.addState(NewState);
    499           Visited[NewStateResources] = NewState;
    500           WorkList.push_back(NewState);
    501         }
    502 
    503         Transition *NewTransition = new Transition(current, InsnClass,
    504                                                    NewState);
    505         D.addTransition(NewTransition);
    506       }
    507     }
    508   }
    509 
    510   // Print out the table.
    511   D.writeTableAndAPI(OS, TargetName);
    512 }
    513