13ca95b02SDimitry Andric //===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine ----===//
2dff0c46cSDimitry Andric //
3dff0c46cSDimitry Andric //                     The LLVM Compiler Infrastructure
4dff0c46cSDimitry Andric //
5dff0c46cSDimitry Andric // This file is distributed under the University of Illinois Open Source
6dff0c46cSDimitry Andric // License. See LICENSE.TXT for details.
7dff0c46cSDimitry Andric //
8dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
9dff0c46cSDimitry Andric //
10dff0c46cSDimitry Andric // This class parses the Schedule.td file and produces an API that can be used
11dff0c46cSDimitry Andric // to reason about whether an instruction can be added to a packet on a VLIW
12dff0c46cSDimitry Andric // architecture. The class internally generates a deterministic finite
13dff0c46cSDimitry Andric // automaton (DFA) that models all possible mappings of machine instructions
14dff0c46cSDimitry Andric // to functional units as instructions are added to a packet.
15dff0c46cSDimitry Andric //
16dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
17dff0c46cSDimitry Andric 
187d523365SDimitry Andric #define DEBUG_TYPE "dfa-emitter"
197d523365SDimitry Andric 
20dff0c46cSDimitry Andric #include "CodeGenTarget.h"
217ae0e2c9SDimitry Andric #include "llvm/ADT/DenseSet.h"
22d88c1a5aSDimitry Andric #include "llvm/ADT/SmallVector.h"
237d523365SDimitry Andric #include "llvm/ADT/StringExtras.h"
247ae0e2c9SDimitry Andric #include "llvm/TableGen/Record.h"
257ae0e2c9SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
267d523365SDimitry Andric #include "llvm/Support/Debug.h"
27d88c1a5aSDimitry Andric #include "llvm/Support/raw_ostream.h"
28d88c1a5aSDimitry Andric #include <cassert>
29d88c1a5aSDimitry Andric #include <cstdint>
307ae0e2c9SDimitry Andric #include <map>
31d88c1a5aSDimitry Andric #include <set>
327ae0e2c9SDimitry Andric #include <string>
33d88c1a5aSDimitry Andric #include <vector>
343ca95b02SDimitry Andric 
35dff0c46cSDimitry Andric using namespace llvm;
36dff0c46cSDimitry Andric 
377d523365SDimitry Andric // --------------------------------------------------------------------
387d523365SDimitry Andric // Definitions shared between DFAPacketizer.cpp and DFAPacketizerEmitter.cpp
397d523365SDimitry Andric 
407d523365SDimitry Andric // DFA_MAX_RESTERMS * DFA_MAX_RESOURCES must fit within sizeof DFAInput.
417d523365SDimitry Andric // This is verified in DFAPacketizer.cpp:DFAPacketizer::DFAPacketizer.
427d523365SDimitry Andric //
437d523365SDimitry Andric // e.g. terms x resource bit combinations that fit in uint32_t:
447d523365SDimitry Andric //      4 terms x 8  bits = 32 bits
457d523365SDimitry Andric //      3 terms x 10 bits = 30 bits
467d523365SDimitry Andric //      2 terms x 16 bits = 32 bits
477d523365SDimitry Andric //
487d523365SDimitry Andric // e.g. terms x resource bit combinations that fit in uint64_t:
497d523365SDimitry Andric //      8 terms x 8  bits = 64 bits
507d523365SDimitry Andric //      7 terms x 9  bits = 63 bits
517d523365SDimitry Andric //      6 terms x 10 bits = 60 bits
527d523365SDimitry Andric //      5 terms x 12 bits = 60 bits
537d523365SDimitry Andric //      4 terms x 16 bits = 64 bits <--- current
547d523365SDimitry Andric //      3 terms x 21 bits = 63 bits
557d523365SDimitry Andric //      2 terms x 32 bits = 64 bits
567d523365SDimitry Andric //
577d523365SDimitry Andric #define DFA_MAX_RESTERMS        4   // The max # of AND'ed resource terms.
587d523365SDimitry Andric #define DFA_MAX_RESOURCES       16  // The max # of resource bits in one term.
597d523365SDimitry Andric 
607d523365SDimitry Andric typedef uint64_t                DFAInput;
617d523365SDimitry Andric typedef int64_t                 DFAStateInput;
627d523365SDimitry Andric #define DFA_TBLTYPE             "int64_t" // For generating DFAStateInputTable.
637d523365SDimitry Andric 
647d523365SDimitry Andric namespace {
65d88c1a5aSDimitry Andric 
addDFAFuncUnits(DFAInput Inp,unsigned FuncUnits)667d523365SDimitry Andric   DFAInput addDFAFuncUnits(DFAInput Inp, unsigned FuncUnits) {
677d523365SDimitry Andric     return (Inp << DFA_MAX_RESOURCES) | FuncUnits;
687d523365SDimitry Andric   }
697d523365SDimitry Andric 
707d523365SDimitry Andric   /// Return the DFAInput for an instruction class input vector.
717d523365SDimitry Andric   /// This function is used in both DFAPacketizer.cpp and in
727d523365SDimitry Andric   /// DFAPacketizerEmitter.cpp.
getDFAInsnInput(const std::vector<unsigned> & InsnClass)737d523365SDimitry Andric   DFAInput getDFAInsnInput(const std::vector<unsigned> &InsnClass) {
747d523365SDimitry Andric     DFAInput InsnInput = 0;
757d523365SDimitry Andric     assert((InsnClass.size() <= DFA_MAX_RESTERMS) &&
767d523365SDimitry Andric            "Exceeded maximum number of DFA terms");
777d523365SDimitry Andric     for (auto U : InsnClass)
787d523365SDimitry Andric       InsnInput = addDFAFuncUnits(InsnInput, U);
797d523365SDimitry Andric     return InsnInput;
807d523365SDimitry Andric   }
81d88c1a5aSDimitry Andric 
823ca95b02SDimitry Andric } // end anonymous namespace
833ca95b02SDimitry Andric 
847d523365SDimitry Andric // --------------------------------------------------------------------
857d523365SDimitry Andric 
867d523365SDimitry Andric #ifndef NDEBUG
877d523365SDimitry Andric // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter".
887d523365SDimitry Andric //
897d523365SDimitry Andric // dbgsInsnClass - When debugging, print instruction class stages.
907d523365SDimitry Andric //
917d523365SDimitry Andric void dbgsInsnClass(const std::vector<unsigned> &InsnClass);
927d523365SDimitry Andric //
937d523365SDimitry Andric // dbgsStateInfo - When debugging, print the set of state info.
947d523365SDimitry Andric //
957d523365SDimitry Andric void dbgsStateInfo(const std::set<unsigned> &stateInfo);
967d523365SDimitry Andric //
977d523365SDimitry Andric // dbgsIndent - When debugging, indent by the specified amount.
987d523365SDimitry Andric //
997d523365SDimitry Andric void dbgsIndent(unsigned indent);
1007d523365SDimitry Andric #endif
1017d523365SDimitry Andric 
102dff0c46cSDimitry Andric //
1037ae0e2c9SDimitry Andric // class DFAPacketizerEmitter: class that generates and prints out the DFA
1047ae0e2c9SDimitry Andric // for resource tracking.
1057ae0e2c9SDimitry Andric //
1067ae0e2c9SDimitry Andric namespace {
107d88c1a5aSDimitry Andric 
1087ae0e2c9SDimitry Andric class DFAPacketizerEmitter {
1097ae0e2c9SDimitry Andric private:
1107ae0e2c9SDimitry Andric   std::string TargetName;
1117ae0e2c9SDimitry Andric   //
1127ae0e2c9SDimitry Andric   // allInsnClasses is the set of all possible resources consumed by an
1137ae0e2c9SDimitry Andric   // InstrStage.
1147ae0e2c9SDimitry Andric   //
1157d523365SDimitry Andric   std::vector<std::vector<unsigned>> allInsnClasses;
1167ae0e2c9SDimitry Andric   RecordKeeper &Records;
1177ae0e2c9SDimitry Andric 
1187ae0e2c9SDimitry Andric public:
1197ae0e2c9SDimitry Andric   DFAPacketizerEmitter(RecordKeeper &R);
1207ae0e2c9SDimitry Andric 
1217ae0e2c9SDimitry Andric   //
1227d523365SDimitry Andric   // collectAllFuncUnits - Construct a map of function unit names to bits.
1237d523365SDimitry Andric   //
1247d523365SDimitry Andric   int collectAllFuncUnits(std::vector<Record*> &ProcItinList,
1257d523365SDimitry Andric                            std::map<std::string, unsigned> &FUNameToBitsMap,
1267d523365SDimitry Andric                            int &maxResources,
1277d523365SDimitry Andric                            raw_ostream &OS);
1287d523365SDimitry Andric 
1297d523365SDimitry Andric   //
1307d523365SDimitry Andric   // collectAllComboFuncs - Construct a map from a combo function unit bit to
1317d523365SDimitry Andric   //                        the bits of all included functional units.
1327d523365SDimitry Andric   //
1337d523365SDimitry Andric   int collectAllComboFuncs(std::vector<Record*> &ComboFuncList,
1347d523365SDimitry Andric                            std::map<std::string, unsigned> &FUNameToBitsMap,
1357d523365SDimitry Andric                            std::map<unsigned, unsigned> &ComboBitToBitsMap,
1367d523365SDimitry Andric                            raw_ostream &OS);
1377d523365SDimitry Andric 
1387d523365SDimitry Andric   //
1397d523365SDimitry Andric   // collectOneInsnClass - Populate allInsnClasses with one instruction class.
1407d523365SDimitry Andric   //
1417d523365SDimitry Andric   int collectOneInsnClass(const std::string &ProcName,
1427d523365SDimitry Andric                            std::vector<Record*> &ProcItinList,
1437d523365SDimitry Andric                            std::map<std::string, unsigned> &FUNameToBitsMap,
1447d523365SDimitry Andric                            Record *ItinData,
1457d523365SDimitry Andric                            raw_ostream &OS);
1467d523365SDimitry Andric 
1477d523365SDimitry Andric   //
1487d523365SDimitry Andric   // collectAllInsnClasses - Populate allInsnClasses which is a set of units
1497ae0e2c9SDimitry Andric   // used in each stage.
1507ae0e2c9SDimitry Andric   //
1517d523365SDimitry Andric   int collectAllInsnClasses(const std::string &ProcName,
1527d523365SDimitry Andric                            std::vector<Record*> &ProcItinList,
1537d523365SDimitry Andric                            std::map<std::string, unsigned> &FUNameToBitsMap,
1547d523365SDimitry Andric                            std::vector<Record*> &ItinDataList,
1557d523365SDimitry Andric                            int &maxStages,
1567ae0e2c9SDimitry Andric                            raw_ostream &OS);
1577ae0e2c9SDimitry Andric 
1587ae0e2c9SDimitry Andric   void run(raw_ostream &OS);
1597ae0e2c9SDimitry Andric };
1607ae0e2c9SDimitry Andric 
1617ae0e2c9SDimitry Andric //
162dff0c46cSDimitry Andric // State represents the usage of machine resources if the packet contains
163dff0c46cSDimitry Andric // a set of instruction classes.
164dff0c46cSDimitry Andric //
165dff0c46cSDimitry Andric // Specifically, currentState is a set of bit-masks.
166dff0c46cSDimitry Andric // The nth bit in a bit-mask indicates whether the nth resource is being used
167dff0c46cSDimitry Andric // by this state. The set of bit-masks in a state represent the different
168dff0c46cSDimitry Andric // possible outcomes of transitioning to this state.
169dff0c46cSDimitry Andric // For example: consider a two resource architecture: resource L and resource M
170dff0c46cSDimitry Andric // with three instruction classes: L, M, and L_or_M.
171dff0c46cSDimitry Andric // From the initial state (currentState = 0x00), if we add instruction class
172dff0c46cSDimitry Andric // L_or_M we will transition to a state with currentState = [0x01, 0x10]. This
173dff0c46cSDimitry Andric // represents the possible resource states that can result from adding a L_or_M
174dff0c46cSDimitry Andric // instruction
175dff0c46cSDimitry Andric //
176dff0c46cSDimitry Andric // Another way of thinking about this transition is we are mapping a NDFA with
177dff0c46cSDimitry Andric // two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10].
178dff0c46cSDimitry Andric //
1793861d79fSDimitry Andric // A State instance also contains a collection of transitions from that state:
1803861d79fSDimitry Andric // a map from inputs to new states.
181dff0c46cSDimitry Andric //
182dff0c46cSDimitry Andric class State {
183dff0c46cSDimitry Andric  public:
184dff0c46cSDimitry Andric   static int currentStateNum;
18591bc56edSDimitry Andric   // stateNum is the only member used for equality/ordering, all other members
18691bc56edSDimitry Andric   // can be mutated even in const State objects.
18791bc56edSDimitry Andric   const int stateNum;
18891bc56edSDimitry Andric   mutable bool isInitial;
18991bc56edSDimitry Andric   mutable std::set<unsigned> stateInfo;
1907d523365SDimitry Andric   typedef std::map<std::vector<unsigned>, const State *> TransitionMap;
19191bc56edSDimitry Andric   mutable TransitionMap Transitions;
192dff0c46cSDimitry Andric 
193dff0c46cSDimitry Andric   State();
194dff0c46cSDimitry Andric 
operator <(const State & s) const1953861d79fSDimitry Andric   bool operator<(const State &s) const {
1963861d79fSDimitry Andric     return stateNum < s.stateNum;
1973861d79fSDimitry Andric   }
1983861d79fSDimitry Andric 
199dff0c46cSDimitry Andric   //
2007d523365SDimitry Andric   // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass
2017d523365SDimitry Andric   // may be a valid transition from this state i.e., can an instruction of type
2027d523365SDimitry Andric   // InsnClass be added to the packet represented by this state.
203dff0c46cSDimitry Andric   //
2047d523365SDimitry Andric   // Note that for multiple stages, this quick check does not take into account
2057d523365SDimitry Andric   // any possible resource competition between the stages themselves.  That is
2067d523365SDimitry Andric   // enforced in AddInsnClassStages which checks the cross product of all
2077d523365SDimitry Andric   // stages for resource availability (which is a more involved check).
208dff0c46cSDimitry Andric   //
2097d523365SDimitry Andric   bool canMaybeAddInsnClass(std::vector<unsigned> &InsnClass,
2107d523365SDimitry Andric                         std::map<unsigned, unsigned> &ComboBitToBitsMap) const;
211d88c1a5aSDimitry Andric 
2127ae0e2c9SDimitry Andric   //
2137ae0e2c9SDimitry Andric   // AddInsnClass - Return all combinations of resource reservation
2147ae0e2c9SDimitry Andric   // which are possible from this state (PossibleStates).
2157ae0e2c9SDimitry Andric   //
2167d523365SDimitry Andric   // PossibleStates is the set of valid resource states that ensue from valid
2177d523365SDimitry Andric   // transitions.
2187d523365SDimitry Andric   //
2197d523365SDimitry Andric   void AddInsnClass(std::vector<unsigned> &InsnClass,
2207d523365SDimitry Andric                         std::map<unsigned, unsigned> &ComboBitToBitsMap,
2217d523365SDimitry Andric                         std::set<unsigned> &PossibleStates) const;
222d88c1a5aSDimitry Andric 
2237d523365SDimitry Andric   //
2247d523365SDimitry Andric   // AddInsnClassStages - Return all combinations of resource reservation
2257d523365SDimitry Andric   // resulting from the cross product of all stages for this InsnClass
2267d523365SDimitry Andric   // which are possible from this state (PossibleStates).
2277d523365SDimitry Andric   //
2287d523365SDimitry Andric   void AddInsnClassStages(std::vector<unsigned> &InsnClass,
2297d523365SDimitry Andric                         std::map<unsigned, unsigned> &ComboBitToBitsMap,
2307d523365SDimitry Andric                         unsigned chkstage, unsigned numstages,
2317d523365SDimitry Andric                         unsigned prevState, unsigned origState,
2327d523365SDimitry Andric                         DenseSet<unsigned> &VisitedResourceStates,
2337d523365SDimitry Andric                         std::set<unsigned> &PossibleStates) const;
234d88c1a5aSDimitry Andric 
235dff0c46cSDimitry Andric   //
2363861d79fSDimitry Andric   // addTransition - Add a transition from this state given the input InsnClass
237dff0c46cSDimitry Andric   //
2387d523365SDimitry Andric   void addTransition(std::vector<unsigned> InsnClass, const State *To) const;
239d88c1a5aSDimitry Andric 
2403861d79fSDimitry Andric   //
2413861d79fSDimitry Andric   // hasTransition - Returns true if there is a transition from this state
2423861d79fSDimitry Andric   // given the input InsnClass
2433861d79fSDimitry Andric   //
2447d523365SDimitry Andric   bool hasTransition(std::vector<unsigned> InsnClass) const;
2457ae0e2c9SDimitry Andric };
246dff0c46cSDimitry Andric 
247dff0c46cSDimitry Andric //
248dff0c46cSDimitry Andric // class DFA: deterministic finite automaton for processor resource tracking.
249dff0c46cSDimitry Andric //
250dff0c46cSDimitry Andric class DFA {
251dff0c46cSDimitry Andric public:
252d88c1a5aSDimitry Andric   DFA() = default;
253dff0c46cSDimitry Andric 
254dff0c46cSDimitry Andric   // Set of states. Need to keep this sorted to emit the transition table.
25591bc56edSDimitry Andric   typedef std::set<State> StateSet;
2563861d79fSDimitry Andric   StateSet states;
257dff0c46cSDimitry Andric 
258d88c1a5aSDimitry Andric   State *currentState = nullptr;
259dff0c46cSDimitry Andric 
260dff0c46cSDimitry Andric   //
261dff0c46cSDimitry Andric   // Modify the DFA.
262dff0c46cSDimitry Andric   //
26391bc56edSDimitry Andric   const State &newState();
264dff0c46cSDimitry Andric 
265dff0c46cSDimitry Andric   //
266dff0c46cSDimitry Andric   // writeTable: Print out a table representing the DFA.
267dff0c46cSDimitry Andric   //
2687d523365SDimitry Andric   void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName,
2697d523365SDimitry Andric                  int numInsnClasses = 0,
2707d523365SDimitry Andric                  int maxResources = 0, int numCombos = 0, int maxStages = 0);
271dff0c46cSDimitry Andric };
272d88c1a5aSDimitry Andric 
2733ca95b02SDimitry Andric } // end anonymous namespace
274dff0c46cSDimitry Andric 
2757d523365SDimitry Andric #ifndef NDEBUG
2767d523365SDimitry Andric // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter".
2777d523365SDimitry Andric //
2787d523365SDimitry Andric // dbgsInsnClass - When debugging, print instruction class stages.
2797d523365SDimitry Andric //
dbgsInsnClass(const std::vector<unsigned> & InsnClass)2807d523365SDimitry Andric void dbgsInsnClass(const std::vector<unsigned> &InsnClass) {
281*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "InsnClass: ");
2827d523365SDimitry Andric   for (unsigned i = 0; i < InsnClass.size(); ++i) {
2837d523365SDimitry Andric     if (i > 0) {
284*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << ", ");
2857d523365SDimitry Andric     }
286*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(InsnClass[i]));
2877d523365SDimitry Andric   }
2887d523365SDimitry Andric   DFAInput InsnInput = getDFAInsnInput(InsnClass);
289*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << " (input: 0x" << Twine::utohexstr(InsnInput) << ")");
2907d523365SDimitry Andric }
2917d523365SDimitry Andric 
2927d523365SDimitry Andric //
2937d523365SDimitry Andric // dbgsStateInfo - When debugging, print the set of state info.
2947d523365SDimitry Andric //
dbgsStateInfo(const std::set<unsigned> & stateInfo)2957d523365SDimitry Andric void dbgsStateInfo(const std::set<unsigned> &stateInfo) {
296*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "StateInfo: ");
2977d523365SDimitry Andric   unsigned i = 0;
2987d523365SDimitry Andric   for (std::set<unsigned>::iterator SI = stateInfo.begin();
2997d523365SDimitry Andric        SI != stateInfo.end(); ++SI, ++i) {
3007d523365SDimitry Andric     unsigned thisState = *SI;
3017d523365SDimitry Andric     if (i > 0) {
302*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << ", ");
3037d523365SDimitry Andric     }
304*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(thisState));
3057d523365SDimitry Andric   }
3067d523365SDimitry Andric }
3077d523365SDimitry Andric 
3087d523365SDimitry Andric //
3097d523365SDimitry Andric // dbgsIndent - When debugging, indent by the specified amount.
3107d523365SDimitry Andric //
dbgsIndent(unsigned indent)3117d523365SDimitry Andric void dbgsIndent(unsigned indent) {
3127d523365SDimitry Andric   for (unsigned i = 0; i < indent; ++i) {
313*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << " ");
3147d523365SDimitry Andric   }
3157d523365SDimitry Andric }
3163ca95b02SDimitry Andric #endif // NDEBUG
317dff0c46cSDimitry Andric 
318dff0c46cSDimitry Andric //
3193861d79fSDimitry Andric // Constructors and destructors for State and DFA
320dff0c46cSDimitry Andric //
State()321dff0c46cSDimitry Andric State::State() :
322dff0c46cSDimitry Andric   stateNum(currentStateNum++), isInitial(false) {}
323dff0c46cSDimitry Andric 
3243861d79fSDimitry Andric //
3253861d79fSDimitry Andric // addTransition - Add a transition from this state given the input InsnClass
3263861d79fSDimitry Andric //
addTransition(std::vector<unsigned> InsnClass,const State * To) const3277d523365SDimitry Andric void State::addTransition(std::vector<unsigned> InsnClass, const State *To)
3287d523365SDimitry Andric       const {
3293861d79fSDimitry Andric   assert(!Transitions.count(InsnClass) &&
3303861d79fSDimitry Andric       "Cannot have multiple transitions for the same input");
3313861d79fSDimitry Andric   Transitions[InsnClass] = To;
3323861d79fSDimitry Andric }
3333861d79fSDimitry Andric 
3343861d79fSDimitry Andric //
3353861d79fSDimitry Andric // hasTransition - Returns true if there is a transition from this state
3363861d79fSDimitry Andric // given the input InsnClass
3373861d79fSDimitry Andric //
hasTransition(std::vector<unsigned> InsnClass) const3387d523365SDimitry Andric bool State::hasTransition(std::vector<unsigned> InsnClass) const {
3393861d79fSDimitry Andric   return Transitions.count(InsnClass) > 0;
3407ae0e2c9SDimitry Andric }
341dff0c46cSDimitry Andric 
342dff0c46cSDimitry Andric //
3437ae0e2c9SDimitry Andric // AddInsnClass - Return all combinations of resource reservation
3447ae0e2c9SDimitry Andric // which are possible from this state (PossibleStates).
345dff0c46cSDimitry Andric //
3467d523365SDimitry Andric // PossibleStates is the set of valid resource states that ensue from valid
3477d523365SDimitry Andric // transitions.
3487d523365SDimitry Andric //
AddInsnClass(std::vector<unsigned> & InsnClass,std::map<unsigned,unsigned> & ComboBitToBitsMap,std::set<unsigned> & PossibleStates) const3497d523365SDimitry Andric void State::AddInsnClass(std::vector<unsigned> &InsnClass,
3507d523365SDimitry Andric                         std::map<unsigned, unsigned> &ComboBitToBitsMap,
35191bc56edSDimitry Andric                         std::set<unsigned> &PossibleStates) const {
352dff0c46cSDimitry Andric   //
353dff0c46cSDimitry Andric   // Iterate over all resource states in currentState.
354dff0c46cSDimitry Andric   //
3557d523365SDimitry Andric   unsigned numstages = InsnClass.size();
3567d523365SDimitry Andric   assert((numstages > 0) && "InsnClass has no stages");
357dff0c46cSDimitry Andric 
358dff0c46cSDimitry Andric   for (std::set<unsigned>::iterator SI = stateInfo.begin();
359dff0c46cSDimitry Andric        SI != stateInfo.end(); ++SI) {
360dff0c46cSDimitry Andric     unsigned thisState = *SI;
361dff0c46cSDimitry Andric 
362dff0c46cSDimitry Andric     DenseSet<unsigned> VisitedResourceStates;
3637d523365SDimitry Andric 
364*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "  thisState: 0x" << Twine::utohexstr(thisState)
365*4ba319b5SDimitry Andric                       << "\n");
3667d523365SDimitry Andric     AddInsnClassStages(InsnClass, ComboBitToBitsMap,
3677d523365SDimitry Andric                                 numstages - 1, numstages,
3687d523365SDimitry Andric                                 thisState, thisState,
3697d523365SDimitry Andric                                 VisitedResourceStates, PossibleStates);
3707d523365SDimitry Andric   }
3717d523365SDimitry Andric }
3727d523365SDimitry Andric 
AddInsnClassStages(std::vector<unsigned> & InsnClass,std::map<unsigned,unsigned> & ComboBitToBitsMap,unsigned chkstage,unsigned numstages,unsigned prevState,unsigned origState,DenseSet<unsigned> & VisitedResourceStates,std::set<unsigned> & PossibleStates) const3737d523365SDimitry Andric void State::AddInsnClassStages(std::vector<unsigned> &InsnClass,
3747d523365SDimitry Andric                         std::map<unsigned, unsigned> &ComboBitToBitsMap,
3757d523365SDimitry Andric                         unsigned chkstage, unsigned numstages,
3767d523365SDimitry Andric                         unsigned prevState, unsigned origState,
3777d523365SDimitry Andric                         DenseSet<unsigned> &VisitedResourceStates,
3787d523365SDimitry Andric                         std::set<unsigned> &PossibleStates) const {
3797d523365SDimitry Andric   assert((chkstage < numstages) && "AddInsnClassStages: stage out of range");
3807d523365SDimitry Andric   unsigned thisStage = InsnClass[chkstage];
3817d523365SDimitry Andric 
382*4ba319b5SDimitry Andric   LLVM_DEBUG({
3837d523365SDimitry Andric     dbgsIndent((1 + numstages - chkstage) << 1);
3847d523365SDimitry Andric     dbgs() << "AddInsnClassStages " << chkstage << " (0x"
385fe4fed2eSDimitry Andric            << Twine::utohexstr(thisStage) << ") from ";
3867d523365SDimitry Andric     dbgsInsnClass(InsnClass);
3877d523365SDimitry Andric     dbgs() << "\n";
3887d523365SDimitry Andric   });
3897d523365SDimitry Andric 
390dff0c46cSDimitry Andric   //
3917d523365SDimitry Andric   // Iterate over all possible resources used in thisStage.
3927d523365SDimitry Andric   // For ex: for thisStage = 0x11, all resources = {0x01, 0x10}.
3937d523365SDimitry Andric   //
3947d523365SDimitry Andric   for (unsigned int j = 0; j < DFA_MAX_RESOURCES; ++j) {
3957d523365SDimitry Andric     unsigned resourceMask = (0x1 << j);
3967d523365SDimitry Andric     if (resourceMask & thisStage) {
3977d523365SDimitry Andric       unsigned combo = ComboBitToBitsMap[resourceMask];
3987d523365SDimitry Andric       if (combo && ((~prevState & combo) != combo)) {
399*4ba319b5SDimitry Andric         LLVM_DEBUG(dbgs() << "\tSkipped Add 0x" << Twine::utohexstr(prevState)
400fe4fed2eSDimitry Andric                           << " - combo op 0x" << Twine::utohexstr(resourceMask)
401fe4fed2eSDimitry Andric                           << " (0x" << Twine::utohexstr(combo)
402fe4fed2eSDimitry Andric                           << ") cannot be scheduled\n");
4037d523365SDimitry Andric         continue;
4047d523365SDimitry Andric       }
4057d523365SDimitry Andric       //
4067d523365SDimitry Andric       // For each possible resource used in thisStage, generate the
407dff0c46cSDimitry Andric       // resource state if that resource was used.
408dff0c46cSDimitry Andric       //
4097d523365SDimitry Andric       unsigned ResultingResourceState = prevState | resourceMask | combo;
410*4ba319b5SDimitry Andric       LLVM_DEBUG({
4117d523365SDimitry Andric         dbgsIndent((2 + numstages - chkstage) << 1);
412fe4fed2eSDimitry Andric         dbgs() << "0x" << Twine::utohexstr(prevState) << " | 0x"
413fe4fed2eSDimitry Andric                << Twine::utohexstr(resourceMask);
4147d523365SDimitry Andric         if (combo)
415fe4fed2eSDimitry Andric           dbgs() << " | 0x" << Twine::utohexstr(combo);
416fe4fed2eSDimitry Andric         dbgs() << " = 0x" << Twine::utohexstr(ResultingResourceState) << " ";
4177d523365SDimitry Andric       });
4187d523365SDimitry Andric 
4197d523365SDimitry Andric       //
4207d523365SDimitry Andric       // If this is the final stage for this class
4217d523365SDimitry Andric       //
4227d523365SDimitry Andric       if (chkstage == 0) {
423dff0c46cSDimitry Andric         //
424dff0c46cSDimitry Andric         // Check if the resulting resource state can be accommodated in this
425dff0c46cSDimitry Andric         // packet.
4267d523365SDimitry Andric         // We compute resource OR prevState (originally started as origState).
4277d523365SDimitry Andric         // If the result of the OR is different than origState, it implies
428dff0c46cSDimitry Andric         // that there is at least one resource that can be used to schedule
4297d523365SDimitry Andric         // thisStage in the current packet.
430dff0c46cSDimitry Andric         // Insert ResultingResourceState into PossibleStates only if we haven't
431dff0c46cSDimitry Andric         // processed ResultingResourceState before.
432dff0c46cSDimitry Andric         //
4337d523365SDimitry Andric         if (ResultingResourceState != prevState) {
4347d523365SDimitry Andric           if (VisitedResourceStates.count(ResultingResourceState) == 0) {
435dff0c46cSDimitry Andric             VisitedResourceStates.insert(ResultingResourceState);
436dff0c46cSDimitry Andric             PossibleStates.insert(ResultingResourceState);
437*4ba319b5SDimitry Andric             LLVM_DEBUG(dbgs()
438*4ba319b5SDimitry Andric                        << "\tResultingResourceState: 0x"
439fe4fed2eSDimitry Andric                        << Twine::utohexstr(ResultingResourceState) << "\n");
4407d523365SDimitry Andric           } else {
441*4ba319b5SDimitry Andric             LLVM_DEBUG(dbgs() << "\tSkipped Add - state already seen\n");
4427d523365SDimitry Andric           }
4437d523365SDimitry Andric         } else {
444*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs()
445*4ba319b5SDimitry Andric                      << "\tSkipped Add - no final resources available\n");
4467d523365SDimitry Andric         }
4477d523365SDimitry Andric       } else {
4487d523365SDimitry Andric         //
4497d523365SDimitry Andric         // If the current resource can be accommodated, check the next
4507d523365SDimitry Andric         // stage in InsnClass for available resources.
4517d523365SDimitry Andric         //
4527d523365SDimitry Andric         if (ResultingResourceState != prevState) {
453*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << "\n");
4547d523365SDimitry Andric           AddInsnClassStages(InsnClass, ComboBitToBitsMap,
4557d523365SDimitry Andric                                 chkstage - 1, numstages,
4567d523365SDimitry Andric                                 ResultingResourceState, origState,
4577d523365SDimitry Andric                                 VisitedResourceStates, PossibleStates);
4587d523365SDimitry Andric         } else {
459*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << "\tSkipped Add - no resources available\n");
460dff0c46cSDimitry Andric         }
461dff0c46cSDimitry Andric       }
462dff0c46cSDimitry Andric     }
463dff0c46cSDimitry Andric   }
4647ae0e2c9SDimitry Andric }
4657ae0e2c9SDimitry Andric 
4667ae0e2c9SDimitry Andric //
4677d523365SDimitry Andric // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass
4687d523365SDimitry Andric // may be a valid transition from this state i.e., can an instruction of type
4697d523365SDimitry Andric // InsnClass be added to the packet represented by this state.
4707ae0e2c9SDimitry Andric //
4717d523365SDimitry Andric // Note that this routine is performing conservative checks that can be
4727d523365SDimitry Andric // quickly executed acting as a filter before calling AddInsnClassStages.
4737d523365SDimitry Andric // Any cases allowed through here will be caught later in AddInsnClassStages
4747d523365SDimitry Andric // which performs the more expensive exact check.
4757d523365SDimitry Andric //
canMaybeAddInsnClass(std::vector<unsigned> & InsnClass,std::map<unsigned,unsigned> & ComboBitToBitsMap) const4767d523365SDimitry Andric bool State::canMaybeAddInsnClass(std::vector<unsigned> &InsnClass,
4777d523365SDimitry Andric                     std::map<unsigned, unsigned> &ComboBitToBitsMap) const {
4787ae0e2c9SDimitry Andric   for (std::set<unsigned>::const_iterator SI = stateInfo.begin();
4797ae0e2c9SDimitry Andric        SI != stateInfo.end(); ++SI) {
4807d523365SDimitry Andric     // Check to see if all required resources are available.
4817d523365SDimitry Andric     bool available = true;
4827d523365SDimitry Andric 
4837d523365SDimitry Andric     // Inspect each stage independently.
4847d523365SDimitry Andric     // note: This is a conservative check as we aren't checking for
4857d523365SDimitry Andric     //       possible resource competition between the stages themselves
4867d523365SDimitry Andric     //       The full cross product is examined later in AddInsnClass.
4877d523365SDimitry Andric     for (unsigned i = 0; i < InsnClass.size(); ++i) {
4887d523365SDimitry Andric       unsigned resources = *SI;
4897d523365SDimitry Andric       if ((~resources & InsnClass[i]) == 0) {
4907d523365SDimitry Andric         available = false;
4917d523365SDimitry Andric         break;
4927d523365SDimitry Andric       }
4937d523365SDimitry Andric       // Make sure _all_ resources for a combo function are available.
4947d523365SDimitry Andric       // note: This is a quick conservative check as it won't catch an
4957d523365SDimitry Andric       //       unscheduleable combo if this stage is an OR expression
4967d523365SDimitry Andric       //       containing a combo.
4977d523365SDimitry Andric       //       These cases are caught later in AddInsnClass.
4987d523365SDimitry Andric       unsigned combo = ComboBitToBitsMap[InsnClass[i]];
4997d523365SDimitry Andric       if (combo && ((~resources & combo) != combo)) {
500*4ba319b5SDimitry Andric         LLVM_DEBUG(dbgs() << "\tSkipped canMaybeAdd 0x"
501fe4fed2eSDimitry Andric                           << Twine::utohexstr(resources) << " - combo op 0x"
502fe4fed2eSDimitry Andric                           << Twine::utohexstr(InsnClass[i]) << " (0x"
503*4ba319b5SDimitry Andric                           << Twine::utohexstr(combo)
504*4ba319b5SDimitry Andric                           << ") cannot be scheduled\n");
5057d523365SDimitry Andric         available = false;
5067d523365SDimitry Andric         break;
5077d523365SDimitry Andric       }
5087d523365SDimitry Andric     }
5097d523365SDimitry Andric 
5107d523365SDimitry Andric     if (available) {
5117ae0e2c9SDimitry Andric       return true;
5127ae0e2c9SDimitry Andric     }
5137d523365SDimitry Andric   }
5147ae0e2c9SDimitry Andric   return false;
515dff0c46cSDimitry Andric }
516dff0c46cSDimitry Andric 
newState()51791bc56edSDimitry Andric const State &DFA::newState() {
51891bc56edSDimitry Andric   auto IterPair = states.insert(State());
51991bc56edSDimitry Andric   assert(IterPair.second && "State already exists");
52091bc56edSDimitry Andric   return *IterPair.first;
521dff0c46cSDimitry Andric }
522dff0c46cSDimitry Andric 
523dff0c46cSDimitry Andric int State::currentStateNum = 0;
524dff0c46cSDimitry Andric 
DFAPacketizerEmitter(RecordKeeper & R)5257ae0e2c9SDimitry Andric DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R):
526d88c1a5aSDimitry Andric   TargetName(CodeGenTarget(R).getName()), Records(R) {}
527dff0c46cSDimitry Andric 
528dff0c46cSDimitry Andric //
529dff0c46cSDimitry Andric // writeTableAndAPI - Print out a table representing the DFA and the
530dff0c46cSDimitry Andric // associated API to create a DFA packetizer.
531dff0c46cSDimitry Andric //
532dff0c46cSDimitry Andric // Format:
533dff0c46cSDimitry Andric // DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
534dff0c46cSDimitry Andric //                           transitions.
535dff0c46cSDimitry Andric // DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for
536dff0c46cSDimitry Andric //                         the ith state.
537dff0c46cSDimitry Andric //
538dff0c46cSDimitry Andric //
writeTableAndAPI(raw_ostream & OS,const std::string & TargetName,int numInsnClasses,int maxResources,int numCombos,int maxStages)5397d523365SDimitry Andric void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName,
5407d523365SDimitry Andric                            int numInsnClasses,
5417d523365SDimitry Andric                            int maxResources, int numCombos, int maxStages) {
5427d523365SDimitry Andric   unsigned numStates = states.size();
5437d523365SDimitry Andric 
544*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "-------------------------------------------------------"
545*4ba319b5SDimitry Andric                        "----------------------\n");
546*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "writeTableAndAPI\n");
547*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "Total states: " << numStates << "\n");
5487d523365SDimitry Andric 
5497d523365SDimitry Andric   OS << "namespace llvm {\n";
5507d523365SDimitry Andric 
5517d523365SDimitry Andric   OS << "\n// Input format:\n";
5527d523365SDimitry Andric   OS << "#define DFA_MAX_RESTERMS        " << DFA_MAX_RESTERMS
5537d523365SDimitry Andric      << "\t// maximum AND'ed resource terms\n";
5547d523365SDimitry Andric   OS << "#define DFA_MAX_RESOURCES       " << DFA_MAX_RESOURCES
5557d523365SDimitry Andric      << "\t// maximum resource bits in one term\n";
5567d523365SDimitry Andric 
5577d523365SDimitry Andric   OS << "\n// " << TargetName << "DFAStateInputTable[][2] = "
5587d523365SDimitry Andric      << "pairs of <Input, NextState> for all valid\n";
5597d523365SDimitry Andric   OS << "//                           transitions.\n";
5607d523365SDimitry Andric   OS << "// " << numStates << "\tstates\n";
5617d523365SDimitry Andric   OS << "// " << numInsnClasses << "\tinstruction classes\n";
5627d523365SDimitry Andric   OS << "// " << maxResources << "\tresources max\n";
5637d523365SDimitry Andric   OS << "// " << numCombos << "\tcombo resources\n";
5647d523365SDimitry Andric   OS << "// " << maxStages << "\tstages max\n";
5657d523365SDimitry Andric   OS << "const " << DFA_TBLTYPE << " "
5667d523365SDimitry Andric      << TargetName << "DFAStateInputTable[][2] = {\n";
5677d523365SDimitry Andric 
568dff0c46cSDimitry Andric   // This table provides a map to the beginning of the transitions for State s
569dff0c46cSDimitry Andric   // in DFAStateInputTable.
5707d523365SDimitry Andric   std::vector<int> StateEntry(numStates+1);
5717d523365SDimitry Andric   static const std::string SentinelEntry = "{-1, -1}";
572dff0c46cSDimitry Andric 
573dff0c46cSDimitry Andric   // Tracks the total valid transitions encountered so far. It is used
574dff0c46cSDimitry Andric   // to construct the StateEntry table.
575dff0c46cSDimitry Andric   int ValidTransitions = 0;
5767d523365SDimitry Andric   DFA::StateSet::iterator SI = states.begin();
5777d523365SDimitry Andric   for (unsigned i = 0; i < numStates; ++i, ++SI) {
57891bc56edSDimitry Andric     assert ((SI->stateNum == (int) i) && "Mismatch in state numbers");
5793861d79fSDimitry Andric     StateEntry[i] = ValidTransitions;
5803861d79fSDimitry Andric     for (State::TransitionMap::iterator
58191bc56edSDimitry Andric         II = SI->Transitions.begin(), IE = SI->Transitions.end();
5823861d79fSDimitry Andric         II != IE; ++II) {
583fe4fed2eSDimitry Andric       OS << "{0x" << Twine::utohexstr(getDFAInsnInput(II->first)) << ", "
584fe4fed2eSDimitry Andric          << II->second->stateNum << "},\t";
585dff0c46cSDimitry Andric     }
58691bc56edSDimitry Andric     ValidTransitions += SI->Transitions.size();
587dff0c46cSDimitry Andric 
588dff0c46cSDimitry Andric     // If there are no valid transitions from this stage, we need a sentinel
589dff0c46cSDimitry Andric     // transition.
590dff0c46cSDimitry Andric     if (ValidTransitions == StateEntry[i]) {
5917d523365SDimitry Andric       OS << SentinelEntry << ",\t";
592dff0c46cSDimitry Andric       ++ValidTransitions;
593dff0c46cSDimitry Andric     }
594dff0c46cSDimitry Andric 
5957d523365SDimitry Andric     OS << " // state " << i << ": " << StateEntry[i];
5967d523365SDimitry Andric     if (StateEntry[i] != (ValidTransitions-1)) {   // More than one transition.
5977d523365SDimitry Andric        OS << "-" << (ValidTransitions-1);
5987d523365SDimitry Andric     }
599dff0c46cSDimitry Andric     OS << "\n";
600dff0c46cSDimitry Andric   }
601139f7f9bSDimitry Andric 
602139f7f9bSDimitry Andric   // Print out a sentinel entry at the end of the StateInputTable. This is
603139f7f9bSDimitry Andric   // needed to iterate over StateInputTable in DFAPacketizer::ReadTable()
6047d523365SDimitry Andric   OS << SentinelEntry << "\t";
6057d523365SDimitry Andric   OS << " // state " << numStates << ": " << ValidTransitions;
6067d523365SDimitry Andric   OS << "\n";
607139f7f9bSDimitry Andric 
608dff0c46cSDimitry Andric   OS << "};\n\n";
6097d523365SDimitry Andric   OS << "// " << TargetName << "DFAStateEntryTable[i] = "
6107d523365SDimitry Andric      << "Index of the first entry in DFAStateInputTable for\n";
6117d523365SDimitry Andric   OS << "//                         "
6127d523365SDimitry Andric      << "the ith state.\n";
6137d523365SDimitry Andric   OS << "// " << numStates << " states\n";
614dff0c46cSDimitry Andric   OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n";
615dff0c46cSDimitry Andric 
616dff0c46cSDimitry Andric   // Multiply i by 2 since each entry in DFAStateInputTable is a set of
617dff0c46cSDimitry Andric   // two numbers.
6187d523365SDimitry Andric   unsigned lastState = 0;
6197d523365SDimitry Andric   for (unsigned i = 0; i < numStates; ++i) {
6207d523365SDimitry Andric     if (i && ((i % 10) == 0)) {
6217d523365SDimitry Andric         lastState = i-1;
6227d523365SDimitry Andric         OS << "   // states " << (i-10) << ":" << lastState << "\n";
6237d523365SDimitry Andric     }
624dff0c46cSDimitry Andric     OS << StateEntry[i] << ", ";
6257d523365SDimitry Andric   }
626dff0c46cSDimitry Andric 
627139f7f9bSDimitry Andric   // Print out the index to the sentinel entry in StateInputTable
628139f7f9bSDimitry Andric   OS << ValidTransitions << ", ";
6297d523365SDimitry Andric   OS << "   // states " << (lastState+1) << ":" << numStates << "\n";
630139f7f9bSDimitry Andric 
6317d523365SDimitry Andric   OS << "};\n";
632dff0c46cSDimitry Andric   OS << "} // namespace\n";
633dff0c46cSDimitry Andric 
634dff0c46cSDimitry Andric   //
635dff0c46cSDimitry Andric   // Emit DFA Packetizer tables if the target is a VLIW machine.
636dff0c46cSDimitry Andric   //
637dff0c46cSDimitry Andric   std::string SubTargetClassName = TargetName + "GenSubtargetInfo";
638dff0c46cSDimitry Andric   OS << "\n" << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";
639dff0c46cSDimitry Andric   OS << "namespace llvm {\n";
640dff0c46cSDimitry Andric   OS << "DFAPacketizer *" << SubTargetClassName << "::"
641dff0c46cSDimitry Andric      << "createDFAPacketizer(const InstrItineraryData *IID) const {\n"
642dff0c46cSDimitry Andric      << "   return new DFAPacketizer(IID, " << TargetName
643dff0c46cSDimitry Andric      << "DFAStateInputTable, " << TargetName << "DFAStateEntryTable);\n}\n\n";
644dff0c46cSDimitry Andric   OS << "} // End llvm namespace \n";
645dff0c46cSDimitry Andric }
646dff0c46cSDimitry Andric 
647dff0c46cSDimitry Andric //
6487d523365SDimitry Andric // collectAllFuncUnits - Construct a map of function unit names to bits.
649dff0c46cSDimitry Andric //
collectAllFuncUnits(std::vector<Record * > & ProcItinList,std::map<std::string,unsigned> & FUNameToBitsMap,int & maxFUs,raw_ostream & OS)6507d523365SDimitry Andric int DFAPacketizerEmitter::collectAllFuncUnits(
6517d523365SDimitry Andric                             std::vector<Record*> &ProcItinList,
6527d523365SDimitry Andric                             std::map<std::string, unsigned> &FUNameToBitsMap,
6537d523365SDimitry Andric                             int &maxFUs,
654dff0c46cSDimitry Andric                             raw_ostream &OS) {
655*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "-------------------------------------------------------"
656*4ba319b5SDimitry Andric                        "----------------------\n");
657*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "collectAllFuncUnits");
658*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << " (" << ProcItinList.size() << " itineraries)\n");
659dff0c46cSDimitry Andric 
6607d523365SDimitry Andric   int totalFUs = 0;
661dff0c46cSDimitry Andric   // Parse functional units for all the itineraries.
662dff0c46cSDimitry Andric   for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) {
663dff0c46cSDimitry Andric     Record *Proc = ProcItinList[i];
664dff0c46cSDimitry Andric     std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU");
665dff0c46cSDimitry Andric 
666*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "    FU:" << i << " (" << FUs.size() << " FUs) "
6677d523365SDimitry Andric                       << Proc->getName());
6687d523365SDimitry Andric 
669dff0c46cSDimitry Andric     // Convert macros to bits for each stage.
6707d523365SDimitry Andric     unsigned numFUs = FUs.size();
6717d523365SDimitry Andric     for (unsigned j = 0; j < numFUs; ++j) {
6727d523365SDimitry Andric       assert ((j < DFA_MAX_RESOURCES) &&
6737d523365SDimitry Andric                       "Exceeded maximum number of representable resources");
6747d523365SDimitry Andric       unsigned FuncResources = (unsigned) (1U << j);
6757d523365SDimitry Andric       FUNameToBitsMap[FUs[j]->getName()] = FuncResources;
676*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x"
677fe4fed2eSDimitry Andric                         << Twine::utohexstr(FuncResources));
6787d523365SDimitry Andric     }
6797d523365SDimitry Andric     if (((int) numFUs) > maxFUs) {
6807d523365SDimitry Andric       maxFUs = numFUs;
6817d523365SDimitry Andric     }
6827d523365SDimitry Andric     totalFUs += numFUs;
683*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "\n");
6847d523365SDimitry Andric   }
6857d523365SDimitry Andric   return totalFUs;
686dff0c46cSDimitry Andric }
687dff0c46cSDimitry Andric 
6887d523365SDimitry Andric //
6897d523365SDimitry Andric // collectAllComboFuncs - Construct a map from a combo function unit bit to
6907d523365SDimitry Andric //                        the bits of all included functional units.
6917d523365SDimitry Andric //
collectAllComboFuncs(std::vector<Record * > & ComboFuncList,std::map<std::string,unsigned> & FUNameToBitsMap,std::map<unsigned,unsigned> & ComboBitToBitsMap,raw_ostream & OS)6927d523365SDimitry Andric int DFAPacketizerEmitter::collectAllComboFuncs(
6937d523365SDimitry Andric                             std::vector<Record*> &ComboFuncList,
6947d523365SDimitry Andric                             std::map<std::string, unsigned> &FUNameToBitsMap,
6957d523365SDimitry Andric                             std::map<unsigned, unsigned> &ComboBitToBitsMap,
6967d523365SDimitry Andric                             raw_ostream &OS) {
697*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "-------------------------------------------------------"
698*4ba319b5SDimitry Andric                        "----------------------\n");
699*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "collectAllComboFuncs");
700*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << " (" << ComboFuncList.size() << " sets)\n");
7017d523365SDimitry Andric 
7027d523365SDimitry Andric   int numCombos = 0;
7037d523365SDimitry Andric   for (unsigned i = 0, N = ComboFuncList.size(); i < N; ++i) {
7047d523365SDimitry Andric     Record *Func = ComboFuncList[i];
7057d523365SDimitry Andric     std::vector<Record*> FUs = Func->getValueAsListOfDefs("CFD");
7067d523365SDimitry Andric 
707*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "    CFD:" << i << " (" << FUs.size() << " combo FUs) "
7087d523365SDimitry Andric                       << Func->getName() << "\n");
7097d523365SDimitry Andric 
7107d523365SDimitry Andric     // Convert macros to bits for each stage.
7117d523365SDimitry Andric     for (unsigned j = 0, N = FUs.size(); j < N; ++j) {
7127d523365SDimitry Andric       assert ((j < DFA_MAX_RESOURCES) &&
7137d523365SDimitry Andric                       "Exceeded maximum number of DFA resources");
7147d523365SDimitry Andric       Record *FuncData = FUs[j];
7157d523365SDimitry Andric       Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc");
7167d523365SDimitry Andric       const std::vector<Record*> &FuncList =
7177d523365SDimitry Andric                                    FuncData->getValueAsListOfDefs("FuncList");
7183ca95b02SDimitry Andric       const std::string &ComboFuncName = ComboFunc->getName();
7197d523365SDimitry Andric       unsigned ComboBit = FUNameToBitsMap[ComboFuncName];
7207d523365SDimitry Andric       unsigned ComboResources = ComboBit;
721*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << "      combo: " << ComboFuncName << ":0x"
722fe4fed2eSDimitry Andric                         << Twine::utohexstr(ComboResources) << "\n");
7237d523365SDimitry Andric       for (unsigned k = 0, M = FuncList.size(); k < M; ++k) {
7247d523365SDimitry Andric         std::string FuncName = FuncList[k]->getName();
7257d523365SDimitry Andric         unsigned FuncResources = FUNameToBitsMap[FuncName];
726*4ba319b5SDimitry Andric         LLVM_DEBUG(dbgs() << "        " << FuncName << ":0x"
727fe4fed2eSDimitry Andric                           << Twine::utohexstr(FuncResources) << "\n");
7287d523365SDimitry Andric         ComboResources |= FuncResources;
7297d523365SDimitry Andric       }
7307d523365SDimitry Andric       ComboBitToBitsMap[ComboBit] = ComboResources;
7317d523365SDimitry Andric       numCombos++;
732*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << "          => combo bits: " << ComboFuncName << ":0x"
733fe4fed2eSDimitry Andric                         << Twine::utohexstr(ComboBit) << " = 0x"
734fe4fed2eSDimitry Andric                         << Twine::utohexstr(ComboResources) << "\n");
7357d523365SDimitry Andric     }
7367d523365SDimitry Andric   }
7377d523365SDimitry Andric   return numCombos;
7387d523365SDimitry Andric }
7397d523365SDimitry Andric 
7407d523365SDimitry Andric //
7417d523365SDimitry Andric // collectOneInsnClass - Populate allInsnClasses with one instruction class
7427d523365SDimitry Andric //
collectOneInsnClass(const std::string & ProcName,std::vector<Record * > & ProcItinList,std::map<std::string,unsigned> & FUNameToBitsMap,Record * ItinData,raw_ostream & OS)7437d523365SDimitry Andric int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName,
7447d523365SDimitry Andric                         std::vector<Record*> &ProcItinList,
7457d523365SDimitry Andric                         std::map<std::string, unsigned> &FUNameToBitsMap,
7467d523365SDimitry Andric                         Record *ItinData,
7477d523365SDimitry Andric                         raw_ostream &OS) {
748dff0c46cSDimitry Andric   const std::vector<Record*> &StageList =
749dff0c46cSDimitry Andric     ItinData->getValueAsListOfDefs("Stages");
750dff0c46cSDimitry Andric 
751dff0c46cSDimitry Andric   // The number of stages.
7527d523365SDimitry Andric   unsigned NStages = StageList.size();
753dff0c46cSDimitry Andric 
754*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "    " << ItinData->getValueAsDef("TheClass")->getName()
7557d523365SDimitry Andric                     << "\n");
7567d523365SDimitry Andric 
7577d523365SDimitry Andric   std::vector<unsigned> UnitBits;
758dff0c46cSDimitry Andric 
759dff0c46cSDimitry Andric   // Compute the bitwise or of each unit used in this stage.
760dff0c46cSDimitry Andric   for (unsigned i = 0; i < NStages; ++i) {
761dff0c46cSDimitry Andric     const Record *Stage = StageList[i];
762dff0c46cSDimitry Andric 
763dff0c46cSDimitry Andric     // Get unit list.
764dff0c46cSDimitry Andric     const std::vector<Record*> &UnitList =
765dff0c46cSDimitry Andric       Stage->getValueAsListOfDefs("Units");
766dff0c46cSDimitry Andric 
767*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "        stage:" << i << " [" << UnitList.size()
768*4ba319b5SDimitry Andric                       << " units]:");
7697d523365SDimitry Andric     unsigned dbglen = 26;  // cursor after stage dbgs
7707d523365SDimitry Andric 
7717d523365SDimitry Andric     // Compute the bitwise or of each unit used in this stage.
7727d523365SDimitry Andric     unsigned UnitBitValue = 0;
773dff0c46cSDimitry Andric     for (unsigned j = 0, M = UnitList.size(); j < M; ++j) {
774dff0c46cSDimitry Andric       // Conduct bitwise or.
775dff0c46cSDimitry Andric       std::string UnitName = UnitList[j]->getName();
776*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << " " << j << ":" << UnitName);
7777d523365SDimitry Andric       dbglen += 3 + UnitName.length();
7787d523365SDimitry Andric       assert(FUNameToBitsMap.count(UnitName));
7797d523365SDimitry Andric       UnitBitValue |= FUNameToBitsMap[UnitName];
780dff0c46cSDimitry Andric     }
781dff0c46cSDimitry Andric 
782dff0c46cSDimitry Andric     if (UnitBitValue != 0)
7837d523365SDimitry Andric       UnitBits.push_back(UnitBitValue);
7847d523365SDimitry Andric 
7857d523365SDimitry Andric     while (dbglen <= 64) {   // line up bits dbgs
7867d523365SDimitry Andric         dbglen += 8;
787*4ba319b5SDimitry Andric         LLVM_DEBUG(dbgs() << "\t");
788dff0c46cSDimitry Andric     }
789*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << " (bits: 0x" << Twine::utohexstr(UnitBitValue)
790*4ba319b5SDimitry Andric                       << ")\n");
791dff0c46cSDimitry Andric   }
792dff0c46cSDimitry Andric 
793d88c1a5aSDimitry Andric   if (!UnitBits.empty())
7947d523365SDimitry Andric     allInsnClasses.push_back(UnitBits);
7957d523365SDimitry Andric 
796*4ba319b5SDimitry Andric   LLVM_DEBUG({
7977d523365SDimitry Andric     dbgs() << "        ";
7987d523365SDimitry Andric     dbgsInsnClass(UnitBits);
7997d523365SDimitry Andric     dbgs() << "\n";
8007d523365SDimitry Andric   });
8017d523365SDimitry Andric 
8027d523365SDimitry Andric   return NStages;
8037d523365SDimitry Andric }
8047d523365SDimitry Andric 
8057d523365SDimitry Andric //
8067d523365SDimitry Andric // collectAllInsnClasses - Populate allInsnClasses which is a set of units
8077d523365SDimitry Andric // used in each stage.
8087d523365SDimitry Andric //
collectAllInsnClasses(const std::string & ProcName,std::vector<Record * > & ProcItinList,std::map<std::string,unsigned> & FUNameToBitsMap,std::vector<Record * > & ItinDataList,int & maxStages,raw_ostream & OS)8097d523365SDimitry Andric int DFAPacketizerEmitter::collectAllInsnClasses(const std::string &ProcName,
8107d523365SDimitry Andric                             std::vector<Record*> &ProcItinList,
8117d523365SDimitry Andric                             std::map<std::string, unsigned> &FUNameToBitsMap,
8127d523365SDimitry Andric                             std::vector<Record*> &ItinDataList,
8137d523365SDimitry Andric                             int &maxStages,
8147d523365SDimitry Andric                             raw_ostream &OS) {
8157d523365SDimitry Andric   // Collect all instruction classes.
8167d523365SDimitry Andric   unsigned M = ItinDataList.size();
8177d523365SDimitry Andric 
8187d523365SDimitry Andric   int numInsnClasses = 0;
819*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "-------------------------------------------------------"
820*4ba319b5SDimitry Andric                        "----------------------\n"
821*4ba319b5SDimitry Andric                     << "collectAllInsnClasses " << ProcName << " (" << M
822*4ba319b5SDimitry Andric                     << " classes)\n");
8237d523365SDimitry Andric 
8247d523365SDimitry Andric   // Collect stages for each instruction class for all itinerary data
8257d523365SDimitry Andric   for (unsigned j = 0; j < M; j++) {
8267d523365SDimitry Andric     Record *ItinData = ItinDataList[j];
8277d523365SDimitry Andric     int NStages = collectOneInsnClass(ProcName, ProcItinList,
8287d523365SDimitry Andric                                       FUNameToBitsMap, ItinData, OS);
8297d523365SDimitry Andric     if (NStages > maxStages) {
8307d523365SDimitry Andric       maxStages = NStages;
8317d523365SDimitry Andric     }
8327d523365SDimitry Andric     numInsnClasses++;
8337d523365SDimitry Andric   }
8347d523365SDimitry Andric   return numInsnClasses;
8357d523365SDimitry Andric }
836dff0c46cSDimitry Andric 
837dff0c46cSDimitry Andric //
838dff0c46cSDimitry Andric // Run the worklist algorithm to generate the DFA.
839dff0c46cSDimitry Andric //
run(raw_ostream & OS)8407ae0e2c9SDimitry Andric void DFAPacketizerEmitter::run(raw_ostream &OS) {
841dff0c46cSDimitry Andric   // Collect processor iteraries.
842dff0c46cSDimitry Andric   std::vector<Record*> ProcItinList =
843dff0c46cSDimitry Andric     Records.getAllDerivedDefinitions("ProcessorItineraries");
844dff0c46cSDimitry Andric 
845dff0c46cSDimitry Andric   //
8467d523365SDimitry Andric   // Collect the Functional units.
847dff0c46cSDimitry Andric   //
8487d523365SDimitry Andric   std::map<std::string, unsigned> FUNameToBitsMap;
8497d523365SDimitry Andric   int maxResources = 0;
8507d523365SDimitry Andric   collectAllFuncUnits(ProcItinList,
8517d523365SDimitry Andric                               FUNameToBitsMap, maxResources, OS);
8527d523365SDimitry Andric 
8537d523365SDimitry Andric   //
8547d523365SDimitry Andric   // Collect the Combo Functional units.
8557d523365SDimitry Andric   //
8567d523365SDimitry Andric   std::map<unsigned, unsigned> ComboBitToBitsMap;
8577d523365SDimitry Andric   std::vector<Record*> ComboFuncList =
8587d523365SDimitry Andric     Records.getAllDerivedDefinitions("ComboFuncUnits");
8597d523365SDimitry Andric   int numCombos = collectAllComboFuncs(ComboFuncList,
8607d523365SDimitry Andric                               FUNameToBitsMap, ComboBitToBitsMap, OS);
8617d523365SDimitry Andric 
8627d523365SDimitry Andric   //
8637d523365SDimitry Andric   // Collect the itineraries.
8647d523365SDimitry Andric   //
8657d523365SDimitry Andric   int maxStages = 0;
8667d523365SDimitry Andric   int numInsnClasses = 0;
867dff0c46cSDimitry Andric   for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) {
868dff0c46cSDimitry Andric     Record *Proc = ProcItinList[i];
869dff0c46cSDimitry Andric 
870dff0c46cSDimitry Andric     // Get processor itinerary name.
8717d523365SDimitry Andric     const std::string &ProcName = Proc->getName();
872dff0c46cSDimitry Andric 
873dff0c46cSDimitry Andric     // Skip default.
8747d523365SDimitry Andric     if (ProcName == "NoItineraries")
875dff0c46cSDimitry Andric       continue;
876dff0c46cSDimitry Andric 
877dff0c46cSDimitry Andric     // Sanity check for at least one instruction itinerary class.
878dff0c46cSDimitry Andric     unsigned NItinClasses =
879dff0c46cSDimitry Andric       Records.getAllDerivedDefinitions("InstrItinClass").size();
880dff0c46cSDimitry Andric     if (NItinClasses == 0)
881dff0c46cSDimitry Andric       return;
882dff0c46cSDimitry Andric 
883dff0c46cSDimitry Andric     // Get itinerary data list.
884dff0c46cSDimitry Andric     std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID");
885dff0c46cSDimitry Andric 
8867d523365SDimitry Andric     // Collect all instruction classes
8877d523365SDimitry Andric     numInsnClasses += collectAllInsnClasses(ProcName, ProcItinList,
8887d523365SDimitry Andric                           FUNameToBitsMap, ItinDataList, maxStages, OS);
889dff0c46cSDimitry Andric   }
890dff0c46cSDimitry Andric 
891dff0c46cSDimitry Andric   //
892dff0c46cSDimitry Andric   // Run a worklist algorithm to generate the DFA.
893dff0c46cSDimitry Andric   //
894dff0c46cSDimitry Andric   DFA D;
89591bc56edSDimitry Andric   const State *Initial = &D.newState();
896dff0c46cSDimitry Andric   Initial->isInitial = true;
897dff0c46cSDimitry Andric   Initial->stateInfo.insert(0x0);
89891bc56edSDimitry Andric   SmallVector<const State*, 32> WorkList;
89991bc56edSDimitry Andric   std::map<std::set<unsigned>, const State*> Visited;
900dff0c46cSDimitry Andric 
901dff0c46cSDimitry Andric   WorkList.push_back(Initial);
902dff0c46cSDimitry Andric 
903dff0c46cSDimitry Andric   //
904dff0c46cSDimitry Andric   // Worklist algorithm to create a DFA for processor resource tracking.
905dff0c46cSDimitry Andric   // C = {set of InsnClasses}
906dff0c46cSDimitry Andric   // Begin with initial node in worklist. Initial node does not have
907dff0c46cSDimitry Andric   // any consumed resources,
908dff0c46cSDimitry Andric   //     ResourceState = 0x0
909dff0c46cSDimitry Andric   // Visited = {}
910dff0c46cSDimitry Andric   // While worklist != empty
911dff0c46cSDimitry Andric   //    S = first element of worklist
912dff0c46cSDimitry Andric   //    For every instruction class C
913dff0c46cSDimitry Andric   //      if we can accommodate C in S:
914dff0c46cSDimitry Andric   //          S' = state with resource states = {S Union C}
915dff0c46cSDimitry Andric   //          Add a new transition: S x C -> S'
916dff0c46cSDimitry Andric   //          If S' is not in Visited:
917dff0c46cSDimitry Andric   //             Add S' to worklist
918dff0c46cSDimitry Andric   //             Add S' to Visited
919dff0c46cSDimitry Andric   //
920dff0c46cSDimitry Andric   while (!WorkList.empty()) {
92191bc56edSDimitry Andric     const State *current = WorkList.pop_back_val();
922*4ba319b5SDimitry Andric     LLVM_DEBUG({
9237d523365SDimitry Andric       dbgs() << "---------------------\n";
9247d523365SDimitry Andric       dbgs() << "Processing state: " << current->stateNum << " - ";
9257d523365SDimitry Andric       dbgsStateInfo(current->stateInfo);
9267d523365SDimitry Andric       dbgs() << "\n";
9277d523365SDimitry Andric     });
9287d523365SDimitry Andric     for (unsigned i = 0; i < allInsnClasses.size(); i++) {
9297d523365SDimitry Andric       std::vector<unsigned> InsnClass = allInsnClasses[i];
930*4ba319b5SDimitry Andric       LLVM_DEBUG({
9317d523365SDimitry Andric         dbgs() << i << " ";
9327d523365SDimitry Andric         dbgsInsnClass(InsnClass);
9337d523365SDimitry Andric         dbgs() << "\n";
9347d523365SDimitry Andric       });
935dff0c46cSDimitry Andric 
936dff0c46cSDimitry Andric       std::set<unsigned> NewStateResources;
937dff0c46cSDimitry Andric       //
938dff0c46cSDimitry Andric       // If we haven't already created a transition for this input
939dff0c46cSDimitry Andric       // and the state can accommodate this InsnClass, create a transition.
940dff0c46cSDimitry Andric       //
9413861d79fSDimitry Andric       if (!current->hasTransition(InsnClass) &&
9427d523365SDimitry Andric           current->canMaybeAddInsnClass(InsnClass, ComboBitToBitsMap)) {
9433ca95b02SDimitry Andric         const State *NewState = nullptr;
9447d523365SDimitry Andric         current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources);
945d88c1a5aSDimitry Andric         if (NewStateResources.empty()) {
946*4ba319b5SDimitry Andric           LLVM_DEBUG(dbgs() << "  Skipped - no new states generated\n");
9477d523365SDimitry Andric           continue;
9487d523365SDimitry Andric         }
9497d523365SDimitry Andric 
950*4ba319b5SDimitry Andric         LLVM_DEBUG({
9517d523365SDimitry Andric           dbgs() << "\t";
9527d523365SDimitry Andric           dbgsStateInfo(NewStateResources);
9537d523365SDimitry Andric           dbgs() << "\n";
9547d523365SDimitry Andric         });
955dff0c46cSDimitry Andric 
956dff0c46cSDimitry Andric         //
957dff0c46cSDimitry Andric         // If we have seen this state before, then do not create a new state.
958dff0c46cSDimitry Andric         //
95991bc56edSDimitry Andric         auto VI = Visited.find(NewStateResources);
9607d523365SDimitry Andric         if (VI != Visited.end()) {
961dff0c46cSDimitry Andric           NewState = VI->second;
962*4ba319b5SDimitry Andric           LLVM_DEBUG({
9637d523365SDimitry Andric             dbgs() << "\tFound existing state: " << NewState->stateNum
9647d523365SDimitry Andric                    << " - ";
9657d523365SDimitry Andric             dbgsStateInfo(NewState->stateInfo);
9667d523365SDimitry Andric             dbgs() << "\n";
9677d523365SDimitry Andric           });
9687d523365SDimitry Andric         } else {
96991bc56edSDimitry Andric           NewState = &D.newState();
970dff0c46cSDimitry Andric           NewState->stateInfo = NewStateResources;
971dff0c46cSDimitry Andric           Visited[NewStateResources] = NewState;
972dff0c46cSDimitry Andric           WorkList.push_back(NewState);
973*4ba319b5SDimitry Andric           LLVM_DEBUG({
9747d523365SDimitry Andric             dbgs() << "\tAccepted new state: " << NewState->stateNum << " - ";
9757d523365SDimitry Andric             dbgsStateInfo(NewState->stateInfo);
9767d523365SDimitry Andric             dbgs() << "\n";
9777d523365SDimitry Andric           });
978dff0c46cSDimitry Andric         }
979dff0c46cSDimitry Andric 
9803861d79fSDimitry Andric         current->addTransition(InsnClass, NewState);
981dff0c46cSDimitry Andric       }
982dff0c46cSDimitry Andric     }
983dff0c46cSDimitry Andric   }
984dff0c46cSDimitry Andric 
985dff0c46cSDimitry Andric   // Print out the table.
9867d523365SDimitry Andric   D.writeTableAndAPI(OS, TargetName,
9877d523365SDimitry Andric                numInsnClasses, maxResources, numCombos, maxStages);
988dff0c46cSDimitry Andric }
9897ae0e2c9SDimitry Andric 
9907ae0e2c9SDimitry Andric namespace llvm {
9917ae0e2c9SDimitry Andric 
EmitDFAPacketizer(RecordKeeper & RK,raw_ostream & OS)9927ae0e2c9SDimitry Andric void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) {
9937ae0e2c9SDimitry Andric   emitSourceFileHeader("Target DFA Packetizer Tables", OS);
9947ae0e2c9SDimitry Andric   DFAPacketizerEmitter(RK).run(OS);
9957ae0e2c9SDimitry Andric }
9967ae0e2c9SDimitry Andric 
997d88c1a5aSDimitry Andric } // end namespace llvm
998