1*0b57cec5SDimitry Andric //===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine ----===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This class parses the Schedule.td file and produces an API that can be used 10*0b57cec5SDimitry Andric // to reason about whether an instruction can be added to a packet on a VLIW 11*0b57cec5SDimitry Andric // architecture. The class internally generates a deterministic finite 12*0b57cec5SDimitry Andric // automaton (DFA) that models all possible mappings of machine instructions 13*0b57cec5SDimitry Andric // to functional units as instructions are added to a packet. 14*0b57cec5SDimitry Andric // 15*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #define DEBUG_TYPE "dfa-emitter" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric #include "CodeGenTarget.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 22*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 23*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 24*0b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 25*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 27*0b57cec5SDimitry Andric #include <cassert> 28*0b57cec5SDimitry Andric #include <cstdint> 29*0b57cec5SDimitry Andric #include <map> 30*0b57cec5SDimitry Andric #include <set> 31*0b57cec5SDimitry Andric #include <string> 32*0b57cec5SDimitry Andric #include <vector> 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric using namespace llvm; 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric // -------------------------------------------------------------------- 37*0b57cec5SDimitry Andric // Definitions shared between DFAPacketizer.cpp and DFAPacketizerEmitter.cpp 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric // DFA_MAX_RESTERMS * DFA_MAX_RESOURCES must fit within sizeof DFAInput. 40*0b57cec5SDimitry Andric // This is verified in DFAPacketizer.cpp:DFAPacketizer::DFAPacketizer. 41*0b57cec5SDimitry Andric // 42*0b57cec5SDimitry Andric // e.g. terms x resource bit combinations that fit in uint32_t: 43*0b57cec5SDimitry Andric // 4 terms x 8 bits = 32 bits 44*0b57cec5SDimitry Andric // 3 terms x 10 bits = 30 bits 45*0b57cec5SDimitry Andric // 2 terms x 16 bits = 32 bits 46*0b57cec5SDimitry Andric // 47*0b57cec5SDimitry Andric // e.g. terms x resource bit combinations that fit in uint64_t: 48*0b57cec5SDimitry Andric // 8 terms x 8 bits = 64 bits 49*0b57cec5SDimitry Andric // 7 terms x 9 bits = 63 bits 50*0b57cec5SDimitry Andric // 6 terms x 10 bits = 60 bits 51*0b57cec5SDimitry Andric // 5 terms x 12 bits = 60 bits 52*0b57cec5SDimitry Andric // 4 terms x 16 bits = 64 bits <--- current 53*0b57cec5SDimitry Andric // 3 terms x 21 bits = 63 bits 54*0b57cec5SDimitry Andric // 2 terms x 32 bits = 64 bits 55*0b57cec5SDimitry Andric // 56*0b57cec5SDimitry Andric #define DFA_MAX_RESTERMS 4 // The max # of AND'ed resource terms. 57*0b57cec5SDimitry Andric #define DFA_MAX_RESOURCES 16 // The max # of resource bits in one term. 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric typedef uint64_t DFAInput; 60*0b57cec5SDimitry Andric typedef int64_t DFAStateInput; 61*0b57cec5SDimitry Andric #define DFA_TBLTYPE "int64_t" // For generating DFAStateInputTable. 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric namespace { 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric DFAInput addDFAFuncUnits(DFAInput Inp, unsigned FuncUnits) { 66*0b57cec5SDimitry Andric return (Inp << DFA_MAX_RESOURCES) | FuncUnits; 67*0b57cec5SDimitry Andric } 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric /// Return the DFAInput for an instruction class input vector. 70*0b57cec5SDimitry Andric /// This function is used in both DFAPacketizer.cpp and in 71*0b57cec5SDimitry Andric /// DFAPacketizerEmitter.cpp. 72*0b57cec5SDimitry Andric DFAInput getDFAInsnInput(const std::vector<unsigned> &InsnClass) { 73*0b57cec5SDimitry Andric DFAInput InsnInput = 0; 74*0b57cec5SDimitry Andric assert((InsnClass.size() <= DFA_MAX_RESTERMS) && 75*0b57cec5SDimitry Andric "Exceeded maximum number of DFA terms"); 76*0b57cec5SDimitry Andric for (auto U : InsnClass) 77*0b57cec5SDimitry Andric InsnInput = addDFAFuncUnits(InsnInput, U); 78*0b57cec5SDimitry Andric return InsnInput; 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric } // end anonymous namespace 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric // -------------------------------------------------------------------- 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric #ifndef NDEBUG 86*0b57cec5SDimitry Andric // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter". 87*0b57cec5SDimitry Andric // 88*0b57cec5SDimitry Andric // dbgsInsnClass - When debugging, print instruction class stages. 89*0b57cec5SDimitry Andric // 90*0b57cec5SDimitry Andric void dbgsInsnClass(const std::vector<unsigned> &InsnClass); 91*0b57cec5SDimitry Andric // 92*0b57cec5SDimitry Andric // dbgsStateInfo - When debugging, print the set of state info. 93*0b57cec5SDimitry Andric // 94*0b57cec5SDimitry Andric void dbgsStateInfo(const std::set<unsigned> &stateInfo); 95*0b57cec5SDimitry Andric // 96*0b57cec5SDimitry Andric // dbgsIndent - When debugging, indent by the specified amount. 97*0b57cec5SDimitry Andric // 98*0b57cec5SDimitry Andric void dbgsIndent(unsigned indent); 99*0b57cec5SDimitry Andric #endif 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric // 102*0b57cec5SDimitry Andric // class DFAPacketizerEmitter: class that generates and prints out the DFA 103*0b57cec5SDimitry Andric // for resource tracking. 104*0b57cec5SDimitry Andric // 105*0b57cec5SDimitry Andric namespace { 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric class DFAPacketizerEmitter { 108*0b57cec5SDimitry Andric private: 109*0b57cec5SDimitry Andric std::string TargetName; 110*0b57cec5SDimitry Andric // 111*0b57cec5SDimitry Andric // allInsnClasses is the set of all possible resources consumed by an 112*0b57cec5SDimitry Andric // InstrStage. 113*0b57cec5SDimitry Andric // 114*0b57cec5SDimitry Andric std::vector<std::vector<unsigned>> allInsnClasses; 115*0b57cec5SDimitry Andric RecordKeeper &Records; 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric public: 118*0b57cec5SDimitry Andric DFAPacketizerEmitter(RecordKeeper &R); 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric // 121*0b57cec5SDimitry Andric // collectAllFuncUnits - Construct a map of function unit names to bits. 122*0b57cec5SDimitry Andric // 123*0b57cec5SDimitry Andric int collectAllFuncUnits(std::vector<Record*> &ProcItinList, 124*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 125*0b57cec5SDimitry Andric int &maxResources, 126*0b57cec5SDimitry Andric raw_ostream &OS); 127*0b57cec5SDimitry Andric 128*0b57cec5SDimitry Andric // 129*0b57cec5SDimitry Andric // collectAllComboFuncs - Construct a map from a combo function unit bit to 130*0b57cec5SDimitry Andric // the bits of all included functional units. 131*0b57cec5SDimitry Andric // 132*0b57cec5SDimitry Andric int collectAllComboFuncs(std::vector<Record*> &ComboFuncList, 133*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 134*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 135*0b57cec5SDimitry Andric raw_ostream &OS); 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric // 138*0b57cec5SDimitry Andric // collectOneInsnClass - Populate allInsnClasses with one instruction class. 139*0b57cec5SDimitry Andric // 140*0b57cec5SDimitry Andric int collectOneInsnClass(const std::string &ProcName, 141*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 142*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 143*0b57cec5SDimitry Andric Record *ItinData, 144*0b57cec5SDimitry Andric raw_ostream &OS); 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric // 147*0b57cec5SDimitry Andric // collectAllInsnClasses - Populate allInsnClasses which is a set of units 148*0b57cec5SDimitry Andric // used in each stage. 149*0b57cec5SDimitry Andric // 150*0b57cec5SDimitry Andric int collectAllInsnClasses(const std::string &ProcName, 151*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 152*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 153*0b57cec5SDimitry Andric std::vector<Record*> &ItinDataList, 154*0b57cec5SDimitry Andric int &maxStages, 155*0b57cec5SDimitry Andric raw_ostream &OS); 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric void run(raw_ostream &OS); 158*0b57cec5SDimitry Andric }; 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric // 161*0b57cec5SDimitry Andric // State represents the usage of machine resources if the packet contains 162*0b57cec5SDimitry Andric // a set of instruction classes. 163*0b57cec5SDimitry Andric // 164*0b57cec5SDimitry Andric // Specifically, currentState is a set of bit-masks. 165*0b57cec5SDimitry Andric // The nth bit in a bit-mask indicates whether the nth resource is being used 166*0b57cec5SDimitry Andric // by this state. The set of bit-masks in a state represent the different 167*0b57cec5SDimitry Andric // possible outcomes of transitioning to this state. 168*0b57cec5SDimitry Andric // For example: consider a two resource architecture: resource L and resource M 169*0b57cec5SDimitry Andric // with three instruction classes: L, M, and L_or_M. 170*0b57cec5SDimitry Andric // From the initial state (currentState = 0x00), if we add instruction class 171*0b57cec5SDimitry Andric // L_or_M we will transition to a state with currentState = [0x01, 0x10]. This 172*0b57cec5SDimitry Andric // represents the possible resource states that can result from adding a L_or_M 173*0b57cec5SDimitry Andric // instruction 174*0b57cec5SDimitry Andric // 175*0b57cec5SDimitry Andric // Another way of thinking about this transition is we are mapping a NDFA with 176*0b57cec5SDimitry Andric // two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10]. 177*0b57cec5SDimitry Andric // 178*0b57cec5SDimitry Andric // A State instance also contains a collection of transitions from that state: 179*0b57cec5SDimitry Andric // a map from inputs to new states. 180*0b57cec5SDimitry Andric // 181*0b57cec5SDimitry Andric class State { 182*0b57cec5SDimitry Andric public: 183*0b57cec5SDimitry Andric static int currentStateNum; 184*0b57cec5SDimitry Andric // stateNum is the only member used for equality/ordering, all other members 185*0b57cec5SDimitry Andric // can be mutated even in const State objects. 186*0b57cec5SDimitry Andric const int stateNum; 187*0b57cec5SDimitry Andric mutable bool isInitial; 188*0b57cec5SDimitry Andric mutable std::set<unsigned> stateInfo; 189*0b57cec5SDimitry Andric typedef std::map<std::vector<unsigned>, const State *> TransitionMap; 190*0b57cec5SDimitry Andric mutable TransitionMap Transitions; 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric State(); 193*0b57cec5SDimitry Andric 194*0b57cec5SDimitry Andric bool operator<(const State &s) const { 195*0b57cec5SDimitry Andric return stateNum < s.stateNum; 196*0b57cec5SDimitry Andric } 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric // 199*0b57cec5SDimitry Andric // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass 200*0b57cec5SDimitry Andric // may be a valid transition from this state i.e., can an instruction of type 201*0b57cec5SDimitry Andric // InsnClass be added to the packet represented by this state. 202*0b57cec5SDimitry Andric // 203*0b57cec5SDimitry Andric // Note that for multiple stages, this quick check does not take into account 204*0b57cec5SDimitry Andric // any possible resource competition between the stages themselves. That is 205*0b57cec5SDimitry Andric // enforced in AddInsnClassStages which checks the cross product of all 206*0b57cec5SDimitry Andric // stages for resource availability (which is a more involved check). 207*0b57cec5SDimitry Andric // 208*0b57cec5SDimitry Andric bool canMaybeAddInsnClass(std::vector<unsigned> &InsnClass, 209*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap) const; 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric // 212*0b57cec5SDimitry Andric // AddInsnClass - Return all combinations of resource reservation 213*0b57cec5SDimitry Andric // which are possible from this state (PossibleStates). 214*0b57cec5SDimitry Andric // 215*0b57cec5SDimitry Andric // PossibleStates is the set of valid resource states that ensue from valid 216*0b57cec5SDimitry Andric // transitions. 217*0b57cec5SDimitry Andric // 218*0b57cec5SDimitry Andric void AddInsnClass(std::vector<unsigned> &InsnClass, 219*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 220*0b57cec5SDimitry Andric std::set<unsigned> &PossibleStates) const; 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric // 223*0b57cec5SDimitry Andric // AddInsnClassStages - Return all combinations of resource reservation 224*0b57cec5SDimitry Andric // resulting from the cross product of all stages for this InsnClass 225*0b57cec5SDimitry Andric // which are possible from this state (PossibleStates). 226*0b57cec5SDimitry Andric // 227*0b57cec5SDimitry Andric void AddInsnClassStages(std::vector<unsigned> &InsnClass, 228*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 229*0b57cec5SDimitry Andric unsigned chkstage, unsigned numstages, 230*0b57cec5SDimitry Andric unsigned prevState, unsigned origState, 231*0b57cec5SDimitry Andric DenseSet<unsigned> &VisitedResourceStates, 232*0b57cec5SDimitry Andric std::set<unsigned> &PossibleStates) const; 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric // 235*0b57cec5SDimitry Andric // addTransition - Add a transition from this state given the input InsnClass 236*0b57cec5SDimitry Andric // 237*0b57cec5SDimitry Andric void addTransition(std::vector<unsigned> InsnClass, const State *To) const; 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric // 240*0b57cec5SDimitry Andric // hasTransition - Returns true if there is a transition from this state 241*0b57cec5SDimitry Andric // given the input InsnClass 242*0b57cec5SDimitry Andric // 243*0b57cec5SDimitry Andric bool hasTransition(std::vector<unsigned> InsnClass) const; 244*0b57cec5SDimitry Andric }; 245*0b57cec5SDimitry Andric 246*0b57cec5SDimitry Andric // 247*0b57cec5SDimitry Andric // class DFA: deterministic finite automaton for processor resource tracking. 248*0b57cec5SDimitry Andric // 249*0b57cec5SDimitry Andric class DFA { 250*0b57cec5SDimitry Andric public: 251*0b57cec5SDimitry Andric DFA() = default; 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric // Set of states. Need to keep this sorted to emit the transition table. 254*0b57cec5SDimitry Andric typedef std::set<State> StateSet; 255*0b57cec5SDimitry Andric StateSet states; 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric State *currentState = nullptr; 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric // 260*0b57cec5SDimitry Andric // Modify the DFA. 261*0b57cec5SDimitry Andric // 262*0b57cec5SDimitry Andric const State &newState(); 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric // 265*0b57cec5SDimitry Andric // writeTable: Print out a table representing the DFA. 266*0b57cec5SDimitry Andric // 267*0b57cec5SDimitry Andric void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName, 268*0b57cec5SDimitry Andric int numInsnClasses = 0, 269*0b57cec5SDimitry Andric int maxResources = 0, int numCombos = 0, int maxStages = 0); 270*0b57cec5SDimitry Andric }; 271*0b57cec5SDimitry Andric 272*0b57cec5SDimitry Andric } // end anonymous namespace 273*0b57cec5SDimitry Andric 274*0b57cec5SDimitry Andric #ifndef NDEBUG 275*0b57cec5SDimitry Andric // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter". 276*0b57cec5SDimitry Andric // 277*0b57cec5SDimitry Andric // dbgsInsnClass - When debugging, print instruction class stages. 278*0b57cec5SDimitry Andric // 279*0b57cec5SDimitry Andric void dbgsInsnClass(const std::vector<unsigned> &InsnClass) { 280*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "InsnClass: "); 281*0b57cec5SDimitry Andric for (unsigned i = 0; i < InsnClass.size(); ++i) { 282*0b57cec5SDimitry Andric if (i > 0) { 283*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ", "); 284*0b57cec5SDimitry Andric } 285*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(InsnClass[i])); 286*0b57cec5SDimitry Andric } 287*0b57cec5SDimitry Andric DFAInput InsnInput = getDFAInsnInput(InsnClass); 288*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (input: 0x" << Twine::utohexstr(InsnInput) << ")"); 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric // 292*0b57cec5SDimitry Andric // dbgsStateInfo - When debugging, print the set of state info. 293*0b57cec5SDimitry Andric // 294*0b57cec5SDimitry Andric void dbgsStateInfo(const std::set<unsigned> &stateInfo) { 295*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "StateInfo: "); 296*0b57cec5SDimitry Andric unsigned i = 0; 297*0b57cec5SDimitry Andric for (std::set<unsigned>::iterator SI = stateInfo.begin(); 298*0b57cec5SDimitry Andric SI != stateInfo.end(); ++SI, ++i) { 299*0b57cec5SDimitry Andric unsigned thisState = *SI; 300*0b57cec5SDimitry Andric if (i > 0) { 301*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ", "); 302*0b57cec5SDimitry Andric } 303*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(thisState)); 304*0b57cec5SDimitry Andric } 305*0b57cec5SDimitry Andric } 306*0b57cec5SDimitry Andric 307*0b57cec5SDimitry Andric // 308*0b57cec5SDimitry Andric // dbgsIndent - When debugging, indent by the specified amount. 309*0b57cec5SDimitry Andric // 310*0b57cec5SDimitry Andric void dbgsIndent(unsigned indent) { 311*0b57cec5SDimitry Andric for (unsigned i = 0; i < indent; ++i) { 312*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " "); 313*0b57cec5SDimitry Andric } 314*0b57cec5SDimitry Andric } 315*0b57cec5SDimitry Andric #endif // NDEBUG 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric // 318*0b57cec5SDimitry Andric // Constructors and destructors for State and DFA 319*0b57cec5SDimitry Andric // 320*0b57cec5SDimitry Andric State::State() : 321*0b57cec5SDimitry Andric stateNum(currentStateNum++), isInitial(false) {} 322*0b57cec5SDimitry Andric 323*0b57cec5SDimitry Andric // 324*0b57cec5SDimitry Andric // addTransition - Add a transition from this state given the input InsnClass 325*0b57cec5SDimitry Andric // 326*0b57cec5SDimitry Andric void State::addTransition(std::vector<unsigned> InsnClass, const State *To) 327*0b57cec5SDimitry Andric const { 328*0b57cec5SDimitry Andric assert(!Transitions.count(InsnClass) && 329*0b57cec5SDimitry Andric "Cannot have multiple transitions for the same input"); 330*0b57cec5SDimitry Andric Transitions[InsnClass] = To; 331*0b57cec5SDimitry Andric } 332*0b57cec5SDimitry Andric 333*0b57cec5SDimitry Andric // 334*0b57cec5SDimitry Andric // hasTransition - Returns true if there is a transition from this state 335*0b57cec5SDimitry Andric // given the input InsnClass 336*0b57cec5SDimitry Andric // 337*0b57cec5SDimitry Andric bool State::hasTransition(std::vector<unsigned> InsnClass) const { 338*0b57cec5SDimitry Andric return Transitions.count(InsnClass) > 0; 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric // 342*0b57cec5SDimitry Andric // AddInsnClass - Return all combinations of resource reservation 343*0b57cec5SDimitry Andric // which are possible from this state (PossibleStates). 344*0b57cec5SDimitry Andric // 345*0b57cec5SDimitry Andric // PossibleStates is the set of valid resource states that ensue from valid 346*0b57cec5SDimitry Andric // transitions. 347*0b57cec5SDimitry Andric // 348*0b57cec5SDimitry Andric void State::AddInsnClass(std::vector<unsigned> &InsnClass, 349*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 350*0b57cec5SDimitry Andric std::set<unsigned> &PossibleStates) const { 351*0b57cec5SDimitry Andric // 352*0b57cec5SDimitry Andric // Iterate over all resource states in currentState. 353*0b57cec5SDimitry Andric // 354*0b57cec5SDimitry Andric unsigned numstages = InsnClass.size(); 355*0b57cec5SDimitry Andric assert((numstages > 0) && "InsnClass has no stages"); 356*0b57cec5SDimitry Andric 357*0b57cec5SDimitry Andric for (std::set<unsigned>::iterator SI = stateInfo.begin(); 358*0b57cec5SDimitry Andric SI != stateInfo.end(); ++SI) { 359*0b57cec5SDimitry Andric unsigned thisState = *SI; 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric DenseSet<unsigned> VisitedResourceStates; 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " thisState: 0x" << Twine::utohexstr(thisState) 364*0b57cec5SDimitry Andric << "\n"); 365*0b57cec5SDimitry Andric AddInsnClassStages(InsnClass, ComboBitToBitsMap, 366*0b57cec5SDimitry Andric numstages - 1, numstages, 367*0b57cec5SDimitry Andric thisState, thisState, 368*0b57cec5SDimitry Andric VisitedResourceStates, PossibleStates); 369*0b57cec5SDimitry Andric } 370*0b57cec5SDimitry Andric } 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric void State::AddInsnClassStages(std::vector<unsigned> &InsnClass, 373*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 374*0b57cec5SDimitry Andric unsigned chkstage, unsigned numstages, 375*0b57cec5SDimitry Andric unsigned prevState, unsigned origState, 376*0b57cec5SDimitry Andric DenseSet<unsigned> &VisitedResourceStates, 377*0b57cec5SDimitry Andric std::set<unsigned> &PossibleStates) const { 378*0b57cec5SDimitry Andric assert((chkstage < numstages) && "AddInsnClassStages: stage out of range"); 379*0b57cec5SDimitry Andric unsigned thisStage = InsnClass[chkstage]; 380*0b57cec5SDimitry Andric 381*0b57cec5SDimitry Andric LLVM_DEBUG({ 382*0b57cec5SDimitry Andric dbgsIndent((1 + numstages - chkstage) << 1); 383*0b57cec5SDimitry Andric dbgs() << "AddInsnClassStages " << chkstage << " (0x" 384*0b57cec5SDimitry Andric << Twine::utohexstr(thisStage) << ") from "; 385*0b57cec5SDimitry Andric dbgsInsnClass(InsnClass); 386*0b57cec5SDimitry Andric dbgs() << "\n"; 387*0b57cec5SDimitry Andric }); 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric // 390*0b57cec5SDimitry Andric // Iterate over all possible resources used in thisStage. 391*0b57cec5SDimitry Andric // For ex: for thisStage = 0x11, all resources = {0x01, 0x10}. 392*0b57cec5SDimitry Andric // 393*0b57cec5SDimitry Andric for (unsigned int j = 0; j < DFA_MAX_RESOURCES; ++j) { 394*0b57cec5SDimitry Andric unsigned resourceMask = (0x1 << j); 395*0b57cec5SDimitry Andric if (resourceMask & thisStage) { 396*0b57cec5SDimitry Andric unsigned combo = ComboBitToBitsMap[resourceMask]; 397*0b57cec5SDimitry Andric if (combo && ((~prevState & combo) != combo)) { 398*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tSkipped Add 0x" << Twine::utohexstr(prevState) 399*0b57cec5SDimitry Andric << " - combo op 0x" << Twine::utohexstr(resourceMask) 400*0b57cec5SDimitry Andric << " (0x" << Twine::utohexstr(combo) 401*0b57cec5SDimitry Andric << ") cannot be scheduled\n"); 402*0b57cec5SDimitry Andric continue; 403*0b57cec5SDimitry Andric } 404*0b57cec5SDimitry Andric // 405*0b57cec5SDimitry Andric // For each possible resource used in thisStage, generate the 406*0b57cec5SDimitry Andric // resource state if that resource was used. 407*0b57cec5SDimitry Andric // 408*0b57cec5SDimitry Andric unsigned ResultingResourceState = prevState | resourceMask | combo; 409*0b57cec5SDimitry Andric LLVM_DEBUG({ 410*0b57cec5SDimitry Andric dbgsIndent((2 + numstages - chkstage) << 1); 411*0b57cec5SDimitry Andric dbgs() << "0x" << Twine::utohexstr(prevState) << " | 0x" 412*0b57cec5SDimitry Andric << Twine::utohexstr(resourceMask); 413*0b57cec5SDimitry Andric if (combo) 414*0b57cec5SDimitry Andric dbgs() << " | 0x" << Twine::utohexstr(combo); 415*0b57cec5SDimitry Andric dbgs() << " = 0x" << Twine::utohexstr(ResultingResourceState) << " "; 416*0b57cec5SDimitry Andric }); 417*0b57cec5SDimitry Andric 418*0b57cec5SDimitry Andric // 419*0b57cec5SDimitry Andric // If this is the final stage for this class 420*0b57cec5SDimitry Andric // 421*0b57cec5SDimitry Andric if (chkstage == 0) { 422*0b57cec5SDimitry Andric // 423*0b57cec5SDimitry Andric // Check if the resulting resource state can be accommodated in this 424*0b57cec5SDimitry Andric // packet. 425*0b57cec5SDimitry Andric // We compute resource OR prevState (originally started as origState). 426*0b57cec5SDimitry Andric // If the result of the OR is different than origState, it implies 427*0b57cec5SDimitry Andric // that there is at least one resource that can be used to schedule 428*0b57cec5SDimitry Andric // thisStage in the current packet. 429*0b57cec5SDimitry Andric // Insert ResultingResourceState into PossibleStates only if we haven't 430*0b57cec5SDimitry Andric // processed ResultingResourceState before. 431*0b57cec5SDimitry Andric // 432*0b57cec5SDimitry Andric if (ResultingResourceState != prevState) { 433*0b57cec5SDimitry Andric if (VisitedResourceStates.count(ResultingResourceState) == 0) { 434*0b57cec5SDimitry Andric VisitedResourceStates.insert(ResultingResourceState); 435*0b57cec5SDimitry Andric PossibleStates.insert(ResultingResourceState); 436*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 437*0b57cec5SDimitry Andric << "\tResultingResourceState: 0x" 438*0b57cec5SDimitry Andric << Twine::utohexstr(ResultingResourceState) << "\n"); 439*0b57cec5SDimitry Andric } else { 440*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tSkipped Add - state already seen\n"); 441*0b57cec5SDimitry Andric } 442*0b57cec5SDimitry Andric } else { 443*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 444*0b57cec5SDimitry Andric << "\tSkipped Add - no final resources available\n"); 445*0b57cec5SDimitry Andric } 446*0b57cec5SDimitry Andric } else { 447*0b57cec5SDimitry Andric // 448*0b57cec5SDimitry Andric // If the current resource can be accommodated, check the next 449*0b57cec5SDimitry Andric // stage in InsnClass for available resources. 450*0b57cec5SDimitry Andric // 451*0b57cec5SDimitry Andric if (ResultingResourceState != prevState) { 452*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 453*0b57cec5SDimitry Andric AddInsnClassStages(InsnClass, ComboBitToBitsMap, 454*0b57cec5SDimitry Andric chkstage - 1, numstages, 455*0b57cec5SDimitry Andric ResultingResourceState, origState, 456*0b57cec5SDimitry Andric VisitedResourceStates, PossibleStates); 457*0b57cec5SDimitry Andric } else { 458*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tSkipped Add - no resources available\n"); 459*0b57cec5SDimitry Andric } 460*0b57cec5SDimitry Andric } 461*0b57cec5SDimitry Andric } 462*0b57cec5SDimitry Andric } 463*0b57cec5SDimitry Andric } 464*0b57cec5SDimitry Andric 465*0b57cec5SDimitry Andric // 466*0b57cec5SDimitry Andric // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass 467*0b57cec5SDimitry Andric // may be a valid transition from this state i.e., can an instruction of type 468*0b57cec5SDimitry Andric // InsnClass be added to the packet represented by this state. 469*0b57cec5SDimitry Andric // 470*0b57cec5SDimitry Andric // Note that this routine is performing conservative checks that can be 471*0b57cec5SDimitry Andric // quickly executed acting as a filter before calling AddInsnClassStages. 472*0b57cec5SDimitry Andric // Any cases allowed through here will be caught later in AddInsnClassStages 473*0b57cec5SDimitry Andric // which performs the more expensive exact check. 474*0b57cec5SDimitry Andric // 475*0b57cec5SDimitry Andric bool State::canMaybeAddInsnClass(std::vector<unsigned> &InsnClass, 476*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap) const { 477*0b57cec5SDimitry Andric for (std::set<unsigned>::const_iterator SI = stateInfo.begin(); 478*0b57cec5SDimitry Andric SI != stateInfo.end(); ++SI) { 479*0b57cec5SDimitry Andric // Check to see if all required resources are available. 480*0b57cec5SDimitry Andric bool available = true; 481*0b57cec5SDimitry Andric 482*0b57cec5SDimitry Andric // Inspect each stage independently. 483*0b57cec5SDimitry Andric // note: This is a conservative check as we aren't checking for 484*0b57cec5SDimitry Andric // possible resource competition between the stages themselves 485*0b57cec5SDimitry Andric // The full cross product is examined later in AddInsnClass. 486*0b57cec5SDimitry Andric for (unsigned i = 0; i < InsnClass.size(); ++i) { 487*0b57cec5SDimitry Andric unsigned resources = *SI; 488*0b57cec5SDimitry Andric if ((~resources & InsnClass[i]) == 0) { 489*0b57cec5SDimitry Andric available = false; 490*0b57cec5SDimitry Andric break; 491*0b57cec5SDimitry Andric } 492*0b57cec5SDimitry Andric // Make sure _all_ resources for a combo function are available. 493*0b57cec5SDimitry Andric // note: This is a quick conservative check as it won't catch an 494*0b57cec5SDimitry Andric // unscheduleable combo if this stage is an OR expression 495*0b57cec5SDimitry Andric // containing a combo. 496*0b57cec5SDimitry Andric // These cases are caught later in AddInsnClass. 497*0b57cec5SDimitry Andric unsigned combo = ComboBitToBitsMap[InsnClass[i]]; 498*0b57cec5SDimitry Andric if (combo && ((~resources & combo) != combo)) { 499*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\tSkipped canMaybeAdd 0x" 500*0b57cec5SDimitry Andric << Twine::utohexstr(resources) << " - combo op 0x" 501*0b57cec5SDimitry Andric << Twine::utohexstr(InsnClass[i]) << " (0x" 502*0b57cec5SDimitry Andric << Twine::utohexstr(combo) 503*0b57cec5SDimitry Andric << ") cannot be scheduled\n"); 504*0b57cec5SDimitry Andric available = false; 505*0b57cec5SDimitry Andric break; 506*0b57cec5SDimitry Andric } 507*0b57cec5SDimitry Andric } 508*0b57cec5SDimitry Andric 509*0b57cec5SDimitry Andric if (available) { 510*0b57cec5SDimitry Andric return true; 511*0b57cec5SDimitry Andric } 512*0b57cec5SDimitry Andric } 513*0b57cec5SDimitry Andric return false; 514*0b57cec5SDimitry Andric } 515*0b57cec5SDimitry Andric 516*0b57cec5SDimitry Andric const State &DFA::newState() { 517*0b57cec5SDimitry Andric auto IterPair = states.insert(State()); 518*0b57cec5SDimitry Andric assert(IterPair.second && "State already exists"); 519*0b57cec5SDimitry Andric return *IterPair.first; 520*0b57cec5SDimitry Andric } 521*0b57cec5SDimitry Andric 522*0b57cec5SDimitry Andric int State::currentStateNum = 0; 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R): 525*0b57cec5SDimitry Andric TargetName(CodeGenTarget(R).getName()), Records(R) {} 526*0b57cec5SDimitry Andric 527*0b57cec5SDimitry Andric // 528*0b57cec5SDimitry Andric // writeTableAndAPI - Print out a table representing the DFA and the 529*0b57cec5SDimitry Andric // associated API to create a DFA packetizer. 530*0b57cec5SDimitry Andric // 531*0b57cec5SDimitry Andric // Format: 532*0b57cec5SDimitry Andric // DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid 533*0b57cec5SDimitry Andric // transitions. 534*0b57cec5SDimitry Andric // DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for 535*0b57cec5SDimitry Andric // the ith state. 536*0b57cec5SDimitry Andric // 537*0b57cec5SDimitry Andric // 538*0b57cec5SDimitry Andric void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName, 539*0b57cec5SDimitry Andric int numInsnClasses, 540*0b57cec5SDimitry Andric int maxResources, int numCombos, int maxStages) { 541*0b57cec5SDimitry Andric unsigned numStates = states.size(); 542*0b57cec5SDimitry Andric 543*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 544*0b57cec5SDimitry Andric "----------------------\n"); 545*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "writeTableAndAPI\n"); 546*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Total states: " << numStates << "\n"); 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric OS << "namespace llvm {\n"; 549*0b57cec5SDimitry Andric 550*0b57cec5SDimitry Andric OS << "\n// Input format:\n"; 551*0b57cec5SDimitry Andric OS << "#define DFA_MAX_RESTERMS " << DFA_MAX_RESTERMS 552*0b57cec5SDimitry Andric << "\t// maximum AND'ed resource terms\n"; 553*0b57cec5SDimitry Andric OS << "#define DFA_MAX_RESOURCES " << DFA_MAX_RESOURCES 554*0b57cec5SDimitry Andric << "\t// maximum resource bits in one term\n"; 555*0b57cec5SDimitry Andric 556*0b57cec5SDimitry Andric OS << "\n// " << TargetName << "DFAStateInputTable[][2] = " 557*0b57cec5SDimitry Andric << "pairs of <Input, NextState> for all valid\n"; 558*0b57cec5SDimitry Andric OS << "// transitions.\n"; 559*0b57cec5SDimitry Andric OS << "// " << numStates << "\tstates\n"; 560*0b57cec5SDimitry Andric OS << "// " << numInsnClasses << "\tinstruction classes\n"; 561*0b57cec5SDimitry Andric OS << "// " << maxResources << "\tresources max\n"; 562*0b57cec5SDimitry Andric OS << "// " << numCombos << "\tcombo resources\n"; 563*0b57cec5SDimitry Andric OS << "// " << maxStages << "\tstages max\n"; 564*0b57cec5SDimitry Andric OS << "const " << DFA_TBLTYPE << " " 565*0b57cec5SDimitry Andric << TargetName << "DFAStateInputTable[][2] = {\n"; 566*0b57cec5SDimitry Andric 567*0b57cec5SDimitry Andric // This table provides a map to the beginning of the transitions for State s 568*0b57cec5SDimitry Andric // in DFAStateInputTable. 569*0b57cec5SDimitry Andric std::vector<int> StateEntry(numStates+1); 570*0b57cec5SDimitry Andric static const std::string SentinelEntry = "{-1, -1}"; 571*0b57cec5SDimitry Andric 572*0b57cec5SDimitry Andric // Tracks the total valid transitions encountered so far. It is used 573*0b57cec5SDimitry Andric // to construct the StateEntry table. 574*0b57cec5SDimitry Andric int ValidTransitions = 0; 575*0b57cec5SDimitry Andric DFA::StateSet::iterator SI = states.begin(); 576*0b57cec5SDimitry Andric for (unsigned i = 0; i < numStates; ++i, ++SI) { 577*0b57cec5SDimitry Andric assert ((SI->stateNum == (int) i) && "Mismatch in state numbers"); 578*0b57cec5SDimitry Andric StateEntry[i] = ValidTransitions; 579*0b57cec5SDimitry Andric for (State::TransitionMap::iterator 580*0b57cec5SDimitry Andric II = SI->Transitions.begin(), IE = SI->Transitions.end(); 581*0b57cec5SDimitry Andric II != IE; ++II) { 582*0b57cec5SDimitry Andric OS << "{0x" << Twine::utohexstr(getDFAInsnInput(II->first)) << ", " 583*0b57cec5SDimitry Andric << II->second->stateNum << "},\t"; 584*0b57cec5SDimitry Andric } 585*0b57cec5SDimitry Andric ValidTransitions += SI->Transitions.size(); 586*0b57cec5SDimitry Andric 587*0b57cec5SDimitry Andric // If there are no valid transitions from this stage, we need a sentinel 588*0b57cec5SDimitry Andric // transition. 589*0b57cec5SDimitry Andric if (ValidTransitions == StateEntry[i]) { 590*0b57cec5SDimitry Andric OS << SentinelEntry << ",\t"; 591*0b57cec5SDimitry Andric ++ValidTransitions; 592*0b57cec5SDimitry Andric } 593*0b57cec5SDimitry Andric 594*0b57cec5SDimitry Andric OS << " // state " << i << ": " << StateEntry[i]; 595*0b57cec5SDimitry Andric if (StateEntry[i] != (ValidTransitions-1)) { // More than one transition. 596*0b57cec5SDimitry Andric OS << "-" << (ValidTransitions-1); 597*0b57cec5SDimitry Andric } 598*0b57cec5SDimitry Andric OS << "\n"; 599*0b57cec5SDimitry Andric } 600*0b57cec5SDimitry Andric 601*0b57cec5SDimitry Andric // Print out a sentinel entry at the end of the StateInputTable. This is 602*0b57cec5SDimitry Andric // needed to iterate over StateInputTable in DFAPacketizer::ReadTable() 603*0b57cec5SDimitry Andric OS << SentinelEntry << "\t"; 604*0b57cec5SDimitry Andric OS << " // state " << numStates << ": " << ValidTransitions; 605*0b57cec5SDimitry Andric OS << "\n"; 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric OS << "};\n\n"; 608*0b57cec5SDimitry Andric OS << "// " << TargetName << "DFAStateEntryTable[i] = " 609*0b57cec5SDimitry Andric << "Index of the first entry in DFAStateInputTable for\n"; 610*0b57cec5SDimitry Andric OS << "// " 611*0b57cec5SDimitry Andric << "the ith state.\n"; 612*0b57cec5SDimitry Andric OS << "// " << numStates << " states\n"; 613*0b57cec5SDimitry Andric OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n"; 614*0b57cec5SDimitry Andric 615*0b57cec5SDimitry Andric // Multiply i by 2 since each entry in DFAStateInputTable is a set of 616*0b57cec5SDimitry Andric // two numbers. 617*0b57cec5SDimitry Andric unsigned lastState = 0; 618*0b57cec5SDimitry Andric for (unsigned i = 0; i < numStates; ++i) { 619*0b57cec5SDimitry Andric if (i && ((i % 10) == 0)) { 620*0b57cec5SDimitry Andric lastState = i-1; 621*0b57cec5SDimitry Andric OS << " // states " << (i-10) << ":" << lastState << "\n"; 622*0b57cec5SDimitry Andric } 623*0b57cec5SDimitry Andric OS << StateEntry[i] << ", "; 624*0b57cec5SDimitry Andric } 625*0b57cec5SDimitry Andric 626*0b57cec5SDimitry Andric // Print out the index to the sentinel entry in StateInputTable 627*0b57cec5SDimitry Andric OS << ValidTransitions << ", "; 628*0b57cec5SDimitry Andric OS << " // states " << (lastState+1) << ":" << numStates << "\n"; 629*0b57cec5SDimitry Andric 630*0b57cec5SDimitry Andric OS << "};\n"; 631*0b57cec5SDimitry Andric OS << "} // namespace\n"; 632*0b57cec5SDimitry Andric 633*0b57cec5SDimitry Andric // 634*0b57cec5SDimitry Andric // Emit DFA Packetizer tables if the target is a VLIW machine. 635*0b57cec5SDimitry Andric // 636*0b57cec5SDimitry Andric std::string SubTargetClassName = TargetName + "GenSubtargetInfo"; 637*0b57cec5SDimitry Andric OS << "\n" << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n"; 638*0b57cec5SDimitry Andric OS << "namespace llvm {\n"; 639*0b57cec5SDimitry Andric OS << "DFAPacketizer *" << SubTargetClassName << "::" 640*0b57cec5SDimitry Andric << "createDFAPacketizer(const InstrItineraryData *IID) const {\n" 641*0b57cec5SDimitry Andric << " return new DFAPacketizer(IID, " << TargetName 642*0b57cec5SDimitry Andric << "DFAStateInputTable, " << TargetName << "DFAStateEntryTable);\n}\n\n"; 643*0b57cec5SDimitry Andric OS << "} // End llvm namespace \n"; 644*0b57cec5SDimitry Andric } 645*0b57cec5SDimitry Andric 646*0b57cec5SDimitry Andric // 647*0b57cec5SDimitry Andric // collectAllFuncUnits - Construct a map of function unit names to bits. 648*0b57cec5SDimitry Andric // 649*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectAllFuncUnits( 650*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 651*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 652*0b57cec5SDimitry Andric int &maxFUs, 653*0b57cec5SDimitry Andric raw_ostream &OS) { 654*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 655*0b57cec5SDimitry Andric "----------------------\n"); 656*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "collectAllFuncUnits"); 657*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (" << ProcItinList.size() << " itineraries)\n"); 658*0b57cec5SDimitry Andric 659*0b57cec5SDimitry Andric int totalFUs = 0; 660*0b57cec5SDimitry Andric // Parse functional units for all the itineraries. 661*0b57cec5SDimitry Andric for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) { 662*0b57cec5SDimitry Andric Record *Proc = ProcItinList[i]; 663*0b57cec5SDimitry Andric std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU"); 664*0b57cec5SDimitry Andric 665*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " FU:" << i << " (" << FUs.size() << " FUs) " 666*0b57cec5SDimitry Andric << Proc->getName()); 667*0b57cec5SDimitry Andric 668*0b57cec5SDimitry Andric // Convert macros to bits for each stage. 669*0b57cec5SDimitry Andric unsigned numFUs = FUs.size(); 670*0b57cec5SDimitry Andric for (unsigned j = 0; j < numFUs; ++j) { 671*0b57cec5SDimitry Andric assert ((j < DFA_MAX_RESOURCES) && 672*0b57cec5SDimitry Andric "Exceeded maximum number of representable resources"); 673*0b57cec5SDimitry Andric unsigned FuncResources = (unsigned) (1U << j); 674*0b57cec5SDimitry Andric FUNameToBitsMap[FUs[j]->getName()] = FuncResources; 675*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x" 676*0b57cec5SDimitry Andric << Twine::utohexstr(FuncResources)); 677*0b57cec5SDimitry Andric } 678*0b57cec5SDimitry Andric if (((int) numFUs) > maxFUs) { 679*0b57cec5SDimitry Andric maxFUs = numFUs; 680*0b57cec5SDimitry Andric } 681*0b57cec5SDimitry Andric totalFUs += numFUs; 682*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric return totalFUs; 685*0b57cec5SDimitry Andric } 686*0b57cec5SDimitry Andric 687*0b57cec5SDimitry Andric // 688*0b57cec5SDimitry Andric // collectAllComboFuncs - Construct a map from a combo function unit bit to 689*0b57cec5SDimitry Andric // the bits of all included functional units. 690*0b57cec5SDimitry Andric // 691*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectAllComboFuncs( 692*0b57cec5SDimitry Andric std::vector<Record*> &ComboFuncList, 693*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 694*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 695*0b57cec5SDimitry Andric raw_ostream &OS) { 696*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 697*0b57cec5SDimitry Andric "----------------------\n"); 698*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "collectAllComboFuncs"); 699*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (" << ComboFuncList.size() << " sets)\n"); 700*0b57cec5SDimitry Andric 701*0b57cec5SDimitry Andric int numCombos = 0; 702*0b57cec5SDimitry Andric for (unsigned i = 0, N = ComboFuncList.size(); i < N; ++i) { 703*0b57cec5SDimitry Andric Record *Func = ComboFuncList[i]; 704*0b57cec5SDimitry Andric std::vector<Record*> FUs = Func->getValueAsListOfDefs("CFD"); 705*0b57cec5SDimitry Andric 706*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " CFD:" << i << " (" << FUs.size() << " combo FUs) " 707*0b57cec5SDimitry Andric << Func->getName() << "\n"); 708*0b57cec5SDimitry Andric 709*0b57cec5SDimitry Andric // Convert macros to bits for each stage. 710*0b57cec5SDimitry Andric for (unsigned j = 0, N = FUs.size(); j < N; ++j) { 711*0b57cec5SDimitry Andric assert ((j < DFA_MAX_RESOURCES) && 712*0b57cec5SDimitry Andric "Exceeded maximum number of DFA resources"); 713*0b57cec5SDimitry Andric Record *FuncData = FUs[j]; 714*0b57cec5SDimitry Andric Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc"); 715*0b57cec5SDimitry Andric const std::vector<Record*> &FuncList = 716*0b57cec5SDimitry Andric FuncData->getValueAsListOfDefs("FuncList"); 717*0b57cec5SDimitry Andric const std::string &ComboFuncName = ComboFunc->getName(); 718*0b57cec5SDimitry Andric unsigned ComboBit = FUNameToBitsMap[ComboFuncName]; 719*0b57cec5SDimitry Andric unsigned ComboResources = ComboBit; 720*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " combo: " << ComboFuncName << ":0x" 721*0b57cec5SDimitry Andric << Twine::utohexstr(ComboResources) << "\n"); 722*0b57cec5SDimitry Andric for (unsigned k = 0, M = FuncList.size(); k < M; ++k) { 723*0b57cec5SDimitry Andric std::string FuncName = FuncList[k]->getName(); 724*0b57cec5SDimitry Andric unsigned FuncResources = FUNameToBitsMap[FuncName]; 725*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << FuncName << ":0x" 726*0b57cec5SDimitry Andric << Twine::utohexstr(FuncResources) << "\n"); 727*0b57cec5SDimitry Andric ComboResources |= FuncResources; 728*0b57cec5SDimitry Andric } 729*0b57cec5SDimitry Andric ComboBitToBitsMap[ComboBit] = ComboResources; 730*0b57cec5SDimitry Andric numCombos++; 731*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " => combo bits: " << ComboFuncName << ":0x" 732*0b57cec5SDimitry Andric << Twine::utohexstr(ComboBit) << " = 0x" 733*0b57cec5SDimitry Andric << Twine::utohexstr(ComboResources) << "\n"); 734*0b57cec5SDimitry Andric } 735*0b57cec5SDimitry Andric } 736*0b57cec5SDimitry Andric return numCombos; 737*0b57cec5SDimitry Andric } 738*0b57cec5SDimitry Andric 739*0b57cec5SDimitry Andric // 740*0b57cec5SDimitry Andric // collectOneInsnClass - Populate allInsnClasses with one instruction class 741*0b57cec5SDimitry Andric // 742*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName, 743*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 744*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 745*0b57cec5SDimitry Andric Record *ItinData, 746*0b57cec5SDimitry Andric raw_ostream &OS) { 747*0b57cec5SDimitry Andric const std::vector<Record*> &StageList = 748*0b57cec5SDimitry Andric ItinData->getValueAsListOfDefs("Stages"); 749*0b57cec5SDimitry Andric 750*0b57cec5SDimitry Andric // The number of stages. 751*0b57cec5SDimitry Andric unsigned NStages = StageList.size(); 752*0b57cec5SDimitry Andric 753*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << ItinData->getValueAsDef("TheClass")->getName() 754*0b57cec5SDimitry Andric << "\n"); 755*0b57cec5SDimitry Andric 756*0b57cec5SDimitry Andric std::vector<unsigned> UnitBits; 757*0b57cec5SDimitry Andric 758*0b57cec5SDimitry Andric // Compute the bitwise or of each unit used in this stage. 759*0b57cec5SDimitry Andric for (unsigned i = 0; i < NStages; ++i) { 760*0b57cec5SDimitry Andric const Record *Stage = StageList[i]; 761*0b57cec5SDimitry Andric 762*0b57cec5SDimitry Andric // Get unit list. 763*0b57cec5SDimitry Andric const std::vector<Record*> &UnitList = 764*0b57cec5SDimitry Andric Stage->getValueAsListOfDefs("Units"); 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " stage:" << i << " [" << UnitList.size() 767*0b57cec5SDimitry Andric << " units]:"); 768*0b57cec5SDimitry Andric unsigned dbglen = 26; // cursor after stage dbgs 769*0b57cec5SDimitry Andric 770*0b57cec5SDimitry Andric // Compute the bitwise or of each unit used in this stage. 771*0b57cec5SDimitry Andric unsigned UnitBitValue = 0; 772*0b57cec5SDimitry Andric for (unsigned j = 0, M = UnitList.size(); j < M; ++j) { 773*0b57cec5SDimitry Andric // Conduct bitwise or. 774*0b57cec5SDimitry Andric std::string UnitName = UnitList[j]->getName(); 775*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << j << ":" << UnitName); 776*0b57cec5SDimitry Andric dbglen += 3 + UnitName.length(); 777*0b57cec5SDimitry Andric assert(FUNameToBitsMap.count(UnitName)); 778*0b57cec5SDimitry Andric UnitBitValue |= FUNameToBitsMap[UnitName]; 779*0b57cec5SDimitry Andric } 780*0b57cec5SDimitry Andric 781*0b57cec5SDimitry Andric if (UnitBitValue != 0) 782*0b57cec5SDimitry Andric UnitBits.push_back(UnitBitValue); 783*0b57cec5SDimitry Andric 784*0b57cec5SDimitry Andric while (dbglen <= 64) { // line up bits dbgs 785*0b57cec5SDimitry Andric dbglen += 8; 786*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t"); 787*0b57cec5SDimitry Andric } 788*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (bits: 0x" << Twine::utohexstr(UnitBitValue) 789*0b57cec5SDimitry Andric << ")\n"); 790*0b57cec5SDimitry Andric } 791*0b57cec5SDimitry Andric 792*0b57cec5SDimitry Andric if (!UnitBits.empty()) 793*0b57cec5SDimitry Andric allInsnClasses.push_back(UnitBits); 794*0b57cec5SDimitry Andric 795*0b57cec5SDimitry Andric LLVM_DEBUG({ 796*0b57cec5SDimitry Andric dbgs() << " "; 797*0b57cec5SDimitry Andric dbgsInsnClass(UnitBits); 798*0b57cec5SDimitry Andric dbgs() << "\n"; 799*0b57cec5SDimitry Andric }); 800*0b57cec5SDimitry Andric 801*0b57cec5SDimitry Andric return NStages; 802*0b57cec5SDimitry Andric } 803*0b57cec5SDimitry Andric 804*0b57cec5SDimitry Andric // 805*0b57cec5SDimitry Andric // collectAllInsnClasses - Populate allInsnClasses which is a set of units 806*0b57cec5SDimitry Andric // used in each stage. 807*0b57cec5SDimitry Andric // 808*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectAllInsnClasses(const std::string &ProcName, 809*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 810*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 811*0b57cec5SDimitry Andric std::vector<Record*> &ItinDataList, 812*0b57cec5SDimitry Andric int &maxStages, 813*0b57cec5SDimitry Andric raw_ostream &OS) { 814*0b57cec5SDimitry Andric // Collect all instruction classes. 815*0b57cec5SDimitry Andric unsigned M = ItinDataList.size(); 816*0b57cec5SDimitry Andric 817*0b57cec5SDimitry Andric int numInsnClasses = 0; 818*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 819*0b57cec5SDimitry Andric "----------------------\n" 820*0b57cec5SDimitry Andric << "collectAllInsnClasses " << ProcName << " (" << M 821*0b57cec5SDimitry Andric << " classes)\n"); 822*0b57cec5SDimitry Andric 823*0b57cec5SDimitry Andric // Collect stages for each instruction class for all itinerary data 824*0b57cec5SDimitry Andric for (unsigned j = 0; j < M; j++) { 825*0b57cec5SDimitry Andric Record *ItinData = ItinDataList[j]; 826*0b57cec5SDimitry Andric int NStages = collectOneInsnClass(ProcName, ProcItinList, 827*0b57cec5SDimitry Andric FUNameToBitsMap, ItinData, OS); 828*0b57cec5SDimitry Andric if (NStages > maxStages) { 829*0b57cec5SDimitry Andric maxStages = NStages; 830*0b57cec5SDimitry Andric } 831*0b57cec5SDimitry Andric numInsnClasses++; 832*0b57cec5SDimitry Andric } 833*0b57cec5SDimitry Andric return numInsnClasses; 834*0b57cec5SDimitry Andric } 835*0b57cec5SDimitry Andric 836*0b57cec5SDimitry Andric // 837*0b57cec5SDimitry Andric // Run the worklist algorithm to generate the DFA. 838*0b57cec5SDimitry Andric // 839*0b57cec5SDimitry Andric void DFAPacketizerEmitter::run(raw_ostream &OS) { 840*0b57cec5SDimitry Andric // Collect processor iteraries. 841*0b57cec5SDimitry Andric std::vector<Record*> ProcItinList = 842*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("ProcessorItineraries"); 843*0b57cec5SDimitry Andric 844*0b57cec5SDimitry Andric // 845*0b57cec5SDimitry Andric // Collect the Functional units. 846*0b57cec5SDimitry Andric // 847*0b57cec5SDimitry Andric std::map<std::string, unsigned> FUNameToBitsMap; 848*0b57cec5SDimitry Andric int maxResources = 0; 849*0b57cec5SDimitry Andric collectAllFuncUnits(ProcItinList, 850*0b57cec5SDimitry Andric FUNameToBitsMap, maxResources, OS); 851*0b57cec5SDimitry Andric 852*0b57cec5SDimitry Andric // 853*0b57cec5SDimitry Andric // Collect the Combo Functional units. 854*0b57cec5SDimitry Andric // 855*0b57cec5SDimitry Andric std::map<unsigned, unsigned> ComboBitToBitsMap; 856*0b57cec5SDimitry Andric std::vector<Record*> ComboFuncList = 857*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("ComboFuncUnits"); 858*0b57cec5SDimitry Andric int numCombos = collectAllComboFuncs(ComboFuncList, 859*0b57cec5SDimitry Andric FUNameToBitsMap, ComboBitToBitsMap, OS); 860*0b57cec5SDimitry Andric 861*0b57cec5SDimitry Andric // 862*0b57cec5SDimitry Andric // Collect the itineraries. 863*0b57cec5SDimitry Andric // 864*0b57cec5SDimitry Andric int maxStages = 0; 865*0b57cec5SDimitry Andric int numInsnClasses = 0; 866*0b57cec5SDimitry Andric for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) { 867*0b57cec5SDimitry Andric Record *Proc = ProcItinList[i]; 868*0b57cec5SDimitry Andric 869*0b57cec5SDimitry Andric // Get processor itinerary name. 870*0b57cec5SDimitry Andric const std::string &ProcName = Proc->getName(); 871*0b57cec5SDimitry Andric 872*0b57cec5SDimitry Andric // Skip default. 873*0b57cec5SDimitry Andric if (ProcName == "NoItineraries") 874*0b57cec5SDimitry Andric continue; 875*0b57cec5SDimitry Andric 876*0b57cec5SDimitry Andric // Sanity check for at least one instruction itinerary class. 877*0b57cec5SDimitry Andric unsigned NItinClasses = 878*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("InstrItinClass").size(); 879*0b57cec5SDimitry Andric if (NItinClasses == 0) 880*0b57cec5SDimitry Andric return; 881*0b57cec5SDimitry Andric 882*0b57cec5SDimitry Andric // Get itinerary data list. 883*0b57cec5SDimitry Andric std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID"); 884*0b57cec5SDimitry Andric 885*0b57cec5SDimitry Andric // Collect all instruction classes 886*0b57cec5SDimitry Andric numInsnClasses += collectAllInsnClasses(ProcName, ProcItinList, 887*0b57cec5SDimitry Andric FUNameToBitsMap, ItinDataList, maxStages, OS); 888*0b57cec5SDimitry Andric } 889*0b57cec5SDimitry Andric 890*0b57cec5SDimitry Andric // 891*0b57cec5SDimitry Andric // Run a worklist algorithm to generate the DFA. 892*0b57cec5SDimitry Andric // 893*0b57cec5SDimitry Andric DFA D; 894*0b57cec5SDimitry Andric const State *Initial = &D.newState(); 895*0b57cec5SDimitry Andric Initial->isInitial = true; 896*0b57cec5SDimitry Andric Initial->stateInfo.insert(0x0); 897*0b57cec5SDimitry Andric SmallVector<const State*, 32> WorkList; 898*0b57cec5SDimitry Andric std::map<std::set<unsigned>, const State*> Visited; 899*0b57cec5SDimitry Andric 900*0b57cec5SDimitry Andric WorkList.push_back(Initial); 901*0b57cec5SDimitry Andric 902*0b57cec5SDimitry Andric // 903*0b57cec5SDimitry Andric // Worklist algorithm to create a DFA for processor resource tracking. 904*0b57cec5SDimitry Andric // C = {set of InsnClasses} 905*0b57cec5SDimitry Andric // Begin with initial node in worklist. Initial node does not have 906*0b57cec5SDimitry Andric // any consumed resources, 907*0b57cec5SDimitry Andric // ResourceState = 0x0 908*0b57cec5SDimitry Andric // Visited = {} 909*0b57cec5SDimitry Andric // While worklist != empty 910*0b57cec5SDimitry Andric // S = first element of worklist 911*0b57cec5SDimitry Andric // For every instruction class C 912*0b57cec5SDimitry Andric // if we can accommodate C in S: 913*0b57cec5SDimitry Andric // S' = state with resource states = {S Union C} 914*0b57cec5SDimitry Andric // Add a new transition: S x C -> S' 915*0b57cec5SDimitry Andric // If S' is not in Visited: 916*0b57cec5SDimitry Andric // Add S' to worklist 917*0b57cec5SDimitry Andric // Add S' to Visited 918*0b57cec5SDimitry Andric // 919*0b57cec5SDimitry Andric while (!WorkList.empty()) { 920*0b57cec5SDimitry Andric const State *current = WorkList.pop_back_val(); 921*0b57cec5SDimitry Andric LLVM_DEBUG({ 922*0b57cec5SDimitry Andric dbgs() << "---------------------\n"; 923*0b57cec5SDimitry Andric dbgs() << "Processing state: " << current->stateNum << " - "; 924*0b57cec5SDimitry Andric dbgsStateInfo(current->stateInfo); 925*0b57cec5SDimitry Andric dbgs() << "\n"; 926*0b57cec5SDimitry Andric }); 927*0b57cec5SDimitry Andric for (unsigned i = 0; i < allInsnClasses.size(); i++) { 928*0b57cec5SDimitry Andric std::vector<unsigned> InsnClass = allInsnClasses[i]; 929*0b57cec5SDimitry Andric LLVM_DEBUG({ 930*0b57cec5SDimitry Andric dbgs() << i << " "; 931*0b57cec5SDimitry Andric dbgsInsnClass(InsnClass); 932*0b57cec5SDimitry Andric dbgs() << "\n"; 933*0b57cec5SDimitry Andric }); 934*0b57cec5SDimitry Andric 935*0b57cec5SDimitry Andric std::set<unsigned> NewStateResources; 936*0b57cec5SDimitry Andric // 937*0b57cec5SDimitry Andric // If we haven't already created a transition for this input 938*0b57cec5SDimitry Andric // and the state can accommodate this InsnClass, create a transition. 939*0b57cec5SDimitry Andric // 940*0b57cec5SDimitry Andric if (!current->hasTransition(InsnClass) && 941*0b57cec5SDimitry Andric current->canMaybeAddInsnClass(InsnClass, ComboBitToBitsMap)) { 942*0b57cec5SDimitry Andric const State *NewState = nullptr; 943*0b57cec5SDimitry Andric current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources); 944*0b57cec5SDimitry Andric if (NewStateResources.empty()) { 945*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Skipped - no new states generated\n"); 946*0b57cec5SDimitry Andric continue; 947*0b57cec5SDimitry Andric } 948*0b57cec5SDimitry Andric 949*0b57cec5SDimitry Andric LLVM_DEBUG({ 950*0b57cec5SDimitry Andric dbgs() << "\t"; 951*0b57cec5SDimitry Andric dbgsStateInfo(NewStateResources); 952*0b57cec5SDimitry Andric dbgs() << "\n"; 953*0b57cec5SDimitry Andric }); 954*0b57cec5SDimitry Andric 955*0b57cec5SDimitry Andric // 956*0b57cec5SDimitry Andric // If we have seen this state before, then do not create a new state. 957*0b57cec5SDimitry Andric // 958*0b57cec5SDimitry Andric auto VI = Visited.find(NewStateResources); 959*0b57cec5SDimitry Andric if (VI != Visited.end()) { 960*0b57cec5SDimitry Andric NewState = VI->second; 961*0b57cec5SDimitry Andric LLVM_DEBUG({ 962*0b57cec5SDimitry Andric dbgs() << "\tFound existing state: " << NewState->stateNum 963*0b57cec5SDimitry Andric << " - "; 964*0b57cec5SDimitry Andric dbgsStateInfo(NewState->stateInfo); 965*0b57cec5SDimitry Andric dbgs() << "\n"; 966*0b57cec5SDimitry Andric }); 967*0b57cec5SDimitry Andric } else { 968*0b57cec5SDimitry Andric NewState = &D.newState(); 969*0b57cec5SDimitry Andric NewState->stateInfo = NewStateResources; 970*0b57cec5SDimitry Andric Visited[NewStateResources] = NewState; 971*0b57cec5SDimitry Andric WorkList.push_back(NewState); 972*0b57cec5SDimitry Andric LLVM_DEBUG({ 973*0b57cec5SDimitry Andric dbgs() << "\tAccepted new state: " << NewState->stateNum << " - "; 974*0b57cec5SDimitry Andric dbgsStateInfo(NewState->stateInfo); 975*0b57cec5SDimitry Andric dbgs() << "\n"; 976*0b57cec5SDimitry Andric }); 977*0b57cec5SDimitry Andric } 978*0b57cec5SDimitry Andric 979*0b57cec5SDimitry Andric current->addTransition(InsnClass, NewState); 980*0b57cec5SDimitry Andric } 981*0b57cec5SDimitry Andric } 982*0b57cec5SDimitry Andric } 983*0b57cec5SDimitry Andric 984*0b57cec5SDimitry Andric // Print out the table. 985*0b57cec5SDimitry Andric D.writeTableAndAPI(OS, TargetName, 986*0b57cec5SDimitry Andric numInsnClasses, maxResources, numCombos, maxStages); 987*0b57cec5SDimitry Andric } 988*0b57cec5SDimitry Andric 989*0b57cec5SDimitry Andric namespace llvm { 990*0b57cec5SDimitry Andric 991*0b57cec5SDimitry Andric void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) { 992*0b57cec5SDimitry Andric emitSourceFileHeader("Target DFA Packetizer Tables", OS); 993*0b57cec5SDimitry Andric DFAPacketizerEmitter(RK).run(OS); 994*0b57cec5SDimitry Andric } 995*0b57cec5SDimitry Andric 996*0b57cec5SDimitry Andric } // end namespace llvm 997