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" 208bcb0991SDimitry Andric #include "DFAEmitter.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 22*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 23*0b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 24*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 25*0b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 26*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 28*0b57cec5SDimitry Andric #include <cassert> 29*0b57cec5SDimitry Andric #include <cstdint> 30*0b57cec5SDimitry Andric #include <map> 31*0b57cec5SDimitry Andric #include <set> 32*0b57cec5SDimitry Andric #include <string> 338bcb0991SDimitry Andric #include <unordered_map> 34*0b57cec5SDimitry Andric #include <vector> 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric using namespace llvm; 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric // -------------------------------------------------------------------- 39*0b57cec5SDimitry Andric // Definitions shared between DFAPacketizer.cpp and DFAPacketizerEmitter.cpp 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric // DFA_MAX_RESTERMS * DFA_MAX_RESOURCES must fit within sizeof DFAInput. 42*0b57cec5SDimitry Andric // This is verified in DFAPacketizer.cpp:DFAPacketizer::DFAPacketizer. 43*0b57cec5SDimitry Andric // 44*0b57cec5SDimitry Andric // e.g. terms x resource bit combinations that fit in uint32_t: 45*0b57cec5SDimitry Andric // 4 terms x 8 bits = 32 bits 46*0b57cec5SDimitry Andric // 3 terms x 10 bits = 30 bits 47*0b57cec5SDimitry Andric // 2 terms x 16 bits = 32 bits 48*0b57cec5SDimitry Andric // 49*0b57cec5SDimitry Andric // e.g. terms x resource bit combinations that fit in uint64_t: 50*0b57cec5SDimitry Andric // 8 terms x 8 bits = 64 bits 51*0b57cec5SDimitry Andric // 7 terms x 9 bits = 63 bits 52*0b57cec5SDimitry Andric // 6 terms x 10 bits = 60 bits 53*0b57cec5SDimitry Andric // 5 terms x 12 bits = 60 bits 54*0b57cec5SDimitry Andric // 4 terms x 16 bits = 64 bits <--- current 55*0b57cec5SDimitry Andric // 3 terms x 21 bits = 63 bits 56*0b57cec5SDimitry Andric // 2 terms x 32 bits = 64 bits 57*0b57cec5SDimitry Andric // 58*0b57cec5SDimitry Andric #define DFA_MAX_RESTERMS 4 // The max # of AND'ed resource terms. 59*0b57cec5SDimitry Andric #define DFA_MAX_RESOURCES 16 // The max # of resource bits in one term. 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric typedef uint64_t DFAInput; 62*0b57cec5SDimitry Andric typedef int64_t DFAStateInput; 63*0b57cec5SDimitry Andric #define DFA_TBLTYPE "int64_t" // For generating DFAStateInputTable. 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric namespace { 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric DFAInput addDFAFuncUnits(DFAInput Inp, unsigned FuncUnits) { 68*0b57cec5SDimitry Andric return (Inp << DFA_MAX_RESOURCES) | FuncUnits; 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric /// Return the DFAInput for an instruction class input vector. 72*0b57cec5SDimitry Andric /// This function is used in both DFAPacketizer.cpp and in 73*0b57cec5SDimitry Andric /// DFAPacketizerEmitter.cpp. 74*0b57cec5SDimitry Andric DFAInput getDFAInsnInput(const std::vector<unsigned> &InsnClass) { 75*0b57cec5SDimitry Andric DFAInput InsnInput = 0; 76*0b57cec5SDimitry Andric assert((InsnClass.size() <= DFA_MAX_RESTERMS) && 77*0b57cec5SDimitry Andric "Exceeded maximum number of DFA terms"); 78*0b57cec5SDimitry Andric for (auto U : InsnClass) 79*0b57cec5SDimitry Andric InsnInput = addDFAFuncUnits(InsnInput, U); 80*0b57cec5SDimitry Andric return InsnInput; 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric } // end anonymous namespace 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric // -------------------------------------------------------------------- 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric #ifndef NDEBUG 88*0b57cec5SDimitry Andric // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter". 89*0b57cec5SDimitry Andric // 90*0b57cec5SDimitry Andric // dbgsInsnClass - When debugging, print instruction class stages. 91*0b57cec5SDimitry Andric // 92*0b57cec5SDimitry Andric void dbgsInsnClass(const std::vector<unsigned> &InsnClass); 93*0b57cec5SDimitry Andric // 94*0b57cec5SDimitry Andric // dbgsStateInfo - When debugging, print the set of state info. 95*0b57cec5SDimitry Andric // 96*0b57cec5SDimitry Andric void dbgsStateInfo(const std::set<unsigned> &stateInfo); 97*0b57cec5SDimitry Andric // 98*0b57cec5SDimitry Andric // dbgsIndent - When debugging, indent by the specified amount. 99*0b57cec5SDimitry Andric // 100*0b57cec5SDimitry Andric void dbgsIndent(unsigned indent); 101*0b57cec5SDimitry Andric #endif 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric // 104*0b57cec5SDimitry Andric // class DFAPacketizerEmitter: class that generates and prints out the DFA 105*0b57cec5SDimitry Andric // for resource tracking. 106*0b57cec5SDimitry Andric // 107*0b57cec5SDimitry Andric namespace { 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric class DFAPacketizerEmitter { 110*0b57cec5SDimitry Andric private: 111*0b57cec5SDimitry Andric std::string TargetName; 112*0b57cec5SDimitry Andric // 113*0b57cec5SDimitry Andric // allInsnClasses is the set of all possible resources consumed by an 114*0b57cec5SDimitry Andric // InstrStage. 115*0b57cec5SDimitry Andric // 116*0b57cec5SDimitry Andric std::vector<std::vector<unsigned>> allInsnClasses; 117*0b57cec5SDimitry Andric RecordKeeper &Records; 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric public: 120*0b57cec5SDimitry Andric DFAPacketizerEmitter(RecordKeeper &R); 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric // 123*0b57cec5SDimitry Andric // collectAllFuncUnits - Construct a map of function unit names to bits. 124*0b57cec5SDimitry Andric // 125*0b57cec5SDimitry Andric int collectAllFuncUnits(std::vector<Record*> &ProcItinList, 126*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 127*0b57cec5SDimitry Andric int &maxResources, 128*0b57cec5SDimitry Andric raw_ostream &OS); 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric // 131*0b57cec5SDimitry Andric // collectAllComboFuncs - Construct a map from a combo function unit bit to 132*0b57cec5SDimitry Andric // the bits of all included functional units. 133*0b57cec5SDimitry Andric // 134*0b57cec5SDimitry Andric int collectAllComboFuncs(std::vector<Record*> &ComboFuncList, 135*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 136*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 137*0b57cec5SDimitry Andric raw_ostream &OS); 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric // 140*0b57cec5SDimitry Andric // collectOneInsnClass - Populate allInsnClasses with one instruction class. 141*0b57cec5SDimitry Andric // 142*0b57cec5SDimitry Andric int collectOneInsnClass(const std::string &ProcName, 143*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 144*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 145*0b57cec5SDimitry Andric Record *ItinData, 146*0b57cec5SDimitry Andric raw_ostream &OS); 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric // 149*0b57cec5SDimitry Andric // collectAllInsnClasses - Populate allInsnClasses which is a set of units 150*0b57cec5SDimitry Andric // used in each stage. 151*0b57cec5SDimitry Andric // 152*0b57cec5SDimitry Andric int collectAllInsnClasses(const std::string &ProcName, 153*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 154*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 155*0b57cec5SDimitry Andric std::vector<Record*> &ItinDataList, 156*0b57cec5SDimitry Andric int &maxStages, 157*0b57cec5SDimitry Andric raw_ostream &OS); 158*0b57cec5SDimitry Andric 1598bcb0991SDimitry Andric // Emit code for a subset of itineraries. 1608bcb0991SDimitry Andric void emitForItineraries(raw_ostream &OS, 1618bcb0991SDimitry Andric std::vector<Record *> &ProcItinList, 1628bcb0991SDimitry Andric std::string DFAName); 1638bcb0991SDimitry Andric 164*0b57cec5SDimitry Andric void run(raw_ostream &OS); 165*0b57cec5SDimitry Andric }; 166*0b57cec5SDimitry Andric } // end anonymous namespace 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric #ifndef NDEBUG 169*0b57cec5SDimitry Andric // To enable debugging, run llvm-tblgen with: "-debug-only dfa-emitter". 170*0b57cec5SDimitry Andric // 171*0b57cec5SDimitry Andric // dbgsInsnClass - When debugging, print instruction class stages. 172*0b57cec5SDimitry Andric // 173*0b57cec5SDimitry Andric void dbgsInsnClass(const std::vector<unsigned> &InsnClass) { 174*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "InsnClass: "); 175*0b57cec5SDimitry Andric for (unsigned i = 0; i < InsnClass.size(); ++i) { 176*0b57cec5SDimitry Andric if (i > 0) { 177*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << ", "); 178*0b57cec5SDimitry Andric } 179*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(InsnClass[i])); 180*0b57cec5SDimitry Andric } 181*0b57cec5SDimitry Andric DFAInput InsnInput = getDFAInsnInput(InsnClass); 182*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (input: 0x" << Twine::utohexstr(InsnInput) << ")"); 183*0b57cec5SDimitry Andric } 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric // 186*0b57cec5SDimitry Andric // dbgsIndent - When debugging, indent by the specified amount. 187*0b57cec5SDimitry Andric // 188*0b57cec5SDimitry Andric void dbgsIndent(unsigned indent) { 189*0b57cec5SDimitry Andric for (unsigned i = 0; i < indent; ++i) { 190*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " "); 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric } 193*0b57cec5SDimitry Andric #endif // NDEBUG 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R): 196*0b57cec5SDimitry Andric TargetName(CodeGenTarget(R).getName()), Records(R) {} 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric // 199*0b57cec5SDimitry Andric // collectAllFuncUnits - Construct a map of function unit names to bits. 200*0b57cec5SDimitry Andric // 201*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectAllFuncUnits( 202*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 203*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 204*0b57cec5SDimitry Andric int &maxFUs, 205*0b57cec5SDimitry Andric raw_ostream &OS) { 206*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 207*0b57cec5SDimitry Andric "----------------------\n"); 208*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "collectAllFuncUnits"); 209*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (" << ProcItinList.size() << " itineraries)\n"); 210*0b57cec5SDimitry Andric 211*0b57cec5SDimitry Andric int totalFUs = 0; 212*0b57cec5SDimitry Andric // Parse functional units for all the itineraries. 213*0b57cec5SDimitry Andric for (unsigned i = 0, N = ProcItinList.size(); i < N; ++i) { 214*0b57cec5SDimitry Andric Record *Proc = ProcItinList[i]; 215*0b57cec5SDimitry Andric std::vector<Record*> FUs = Proc->getValueAsListOfDefs("FU"); 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " FU:" << i << " (" << FUs.size() << " FUs) " 218*0b57cec5SDimitry Andric << Proc->getName()); 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric // Convert macros to bits for each stage. 221*0b57cec5SDimitry Andric unsigned numFUs = FUs.size(); 222*0b57cec5SDimitry Andric for (unsigned j = 0; j < numFUs; ++j) { 223*0b57cec5SDimitry Andric assert ((j < DFA_MAX_RESOURCES) && 224*0b57cec5SDimitry Andric "Exceeded maximum number of representable resources"); 225*0b57cec5SDimitry Andric unsigned FuncResources = (unsigned) (1U << j); 226*0b57cec5SDimitry Andric FUNameToBitsMap[FUs[j]->getName()] = FuncResources; 227*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x" 228*0b57cec5SDimitry Andric << Twine::utohexstr(FuncResources)); 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric if (((int) numFUs) > maxFUs) { 231*0b57cec5SDimitry Andric maxFUs = numFUs; 232*0b57cec5SDimitry Andric } 233*0b57cec5SDimitry Andric totalFUs += numFUs; 234*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric return totalFUs; 237*0b57cec5SDimitry Andric } 238*0b57cec5SDimitry Andric 239*0b57cec5SDimitry Andric // 240*0b57cec5SDimitry Andric // collectAllComboFuncs - Construct a map from a combo function unit bit to 241*0b57cec5SDimitry Andric // the bits of all included functional units. 242*0b57cec5SDimitry Andric // 243*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectAllComboFuncs( 244*0b57cec5SDimitry Andric std::vector<Record*> &ComboFuncList, 245*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 246*0b57cec5SDimitry Andric std::map<unsigned, unsigned> &ComboBitToBitsMap, 247*0b57cec5SDimitry Andric raw_ostream &OS) { 248*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 249*0b57cec5SDimitry Andric "----------------------\n"); 250*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "collectAllComboFuncs"); 251*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (" << ComboFuncList.size() << " sets)\n"); 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric int numCombos = 0; 254*0b57cec5SDimitry Andric for (unsigned i = 0, N = ComboFuncList.size(); i < N; ++i) { 255*0b57cec5SDimitry Andric Record *Func = ComboFuncList[i]; 256*0b57cec5SDimitry Andric std::vector<Record*> FUs = Func->getValueAsListOfDefs("CFD"); 257*0b57cec5SDimitry Andric 258*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " CFD:" << i << " (" << FUs.size() << " combo FUs) " 259*0b57cec5SDimitry Andric << Func->getName() << "\n"); 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric // Convert macros to bits for each stage. 262*0b57cec5SDimitry Andric for (unsigned j = 0, N = FUs.size(); j < N; ++j) { 263*0b57cec5SDimitry Andric assert ((j < DFA_MAX_RESOURCES) && 264*0b57cec5SDimitry Andric "Exceeded maximum number of DFA resources"); 265*0b57cec5SDimitry Andric Record *FuncData = FUs[j]; 266*0b57cec5SDimitry Andric Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc"); 267*0b57cec5SDimitry Andric const std::vector<Record*> &FuncList = 268*0b57cec5SDimitry Andric FuncData->getValueAsListOfDefs("FuncList"); 269*0b57cec5SDimitry Andric const std::string &ComboFuncName = ComboFunc->getName(); 270*0b57cec5SDimitry Andric unsigned ComboBit = FUNameToBitsMap[ComboFuncName]; 271*0b57cec5SDimitry Andric unsigned ComboResources = ComboBit; 272*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " combo: " << ComboFuncName << ":0x" 273*0b57cec5SDimitry Andric << Twine::utohexstr(ComboResources) << "\n"); 274*0b57cec5SDimitry Andric for (unsigned k = 0, M = FuncList.size(); k < M; ++k) { 275*0b57cec5SDimitry Andric std::string FuncName = FuncList[k]->getName(); 276*0b57cec5SDimitry Andric unsigned FuncResources = FUNameToBitsMap[FuncName]; 277*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << FuncName << ":0x" 278*0b57cec5SDimitry Andric << Twine::utohexstr(FuncResources) << "\n"); 279*0b57cec5SDimitry Andric ComboResources |= FuncResources; 280*0b57cec5SDimitry Andric } 281*0b57cec5SDimitry Andric ComboBitToBitsMap[ComboBit] = ComboResources; 282*0b57cec5SDimitry Andric numCombos++; 283*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " => combo bits: " << ComboFuncName << ":0x" 284*0b57cec5SDimitry Andric << Twine::utohexstr(ComboBit) << " = 0x" 285*0b57cec5SDimitry Andric << Twine::utohexstr(ComboResources) << "\n"); 286*0b57cec5SDimitry Andric } 287*0b57cec5SDimitry Andric } 288*0b57cec5SDimitry Andric return numCombos; 289*0b57cec5SDimitry Andric } 290*0b57cec5SDimitry Andric 291*0b57cec5SDimitry Andric // 292*0b57cec5SDimitry Andric // collectOneInsnClass - Populate allInsnClasses with one instruction class 293*0b57cec5SDimitry Andric // 294*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectOneInsnClass(const std::string &ProcName, 295*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 296*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 297*0b57cec5SDimitry Andric Record *ItinData, 298*0b57cec5SDimitry Andric raw_ostream &OS) { 299*0b57cec5SDimitry Andric const std::vector<Record*> &StageList = 300*0b57cec5SDimitry Andric ItinData->getValueAsListOfDefs("Stages"); 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric // The number of stages. 303*0b57cec5SDimitry Andric unsigned NStages = StageList.size(); 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << ItinData->getValueAsDef("TheClass")->getName() 306*0b57cec5SDimitry Andric << "\n"); 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric std::vector<unsigned> UnitBits; 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric // Compute the bitwise or of each unit used in this stage. 311*0b57cec5SDimitry Andric for (unsigned i = 0; i < NStages; ++i) { 312*0b57cec5SDimitry Andric const Record *Stage = StageList[i]; 313*0b57cec5SDimitry Andric 314*0b57cec5SDimitry Andric // Get unit list. 315*0b57cec5SDimitry Andric const std::vector<Record*> &UnitList = 316*0b57cec5SDimitry Andric Stage->getValueAsListOfDefs("Units"); 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " stage:" << i << " [" << UnitList.size() 319*0b57cec5SDimitry Andric << " units]:"); 320*0b57cec5SDimitry Andric unsigned dbglen = 26; // cursor after stage dbgs 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric // Compute the bitwise or of each unit used in this stage. 323*0b57cec5SDimitry Andric unsigned UnitBitValue = 0; 324*0b57cec5SDimitry Andric for (unsigned j = 0, M = UnitList.size(); j < M; ++j) { 325*0b57cec5SDimitry Andric // Conduct bitwise or. 326*0b57cec5SDimitry Andric std::string UnitName = UnitList[j]->getName(); 327*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << j << ":" << UnitName); 328*0b57cec5SDimitry Andric dbglen += 3 + UnitName.length(); 329*0b57cec5SDimitry Andric assert(FUNameToBitsMap.count(UnitName)); 330*0b57cec5SDimitry Andric UnitBitValue |= FUNameToBitsMap[UnitName]; 331*0b57cec5SDimitry Andric } 332*0b57cec5SDimitry Andric 333*0b57cec5SDimitry Andric if (UnitBitValue != 0) 334*0b57cec5SDimitry Andric UnitBits.push_back(UnitBitValue); 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric while (dbglen <= 64) { // line up bits dbgs 337*0b57cec5SDimitry Andric dbglen += 8; 338*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t"); 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " (bits: 0x" << Twine::utohexstr(UnitBitValue) 341*0b57cec5SDimitry Andric << ")\n"); 342*0b57cec5SDimitry Andric } 343*0b57cec5SDimitry Andric 344*0b57cec5SDimitry Andric if (!UnitBits.empty()) 345*0b57cec5SDimitry Andric allInsnClasses.push_back(UnitBits); 346*0b57cec5SDimitry Andric 347*0b57cec5SDimitry Andric LLVM_DEBUG({ 348*0b57cec5SDimitry Andric dbgs() << " "; 349*0b57cec5SDimitry Andric dbgsInsnClass(UnitBits); 350*0b57cec5SDimitry Andric dbgs() << "\n"; 351*0b57cec5SDimitry Andric }); 352*0b57cec5SDimitry Andric 353*0b57cec5SDimitry Andric return NStages; 354*0b57cec5SDimitry Andric } 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric // 357*0b57cec5SDimitry Andric // collectAllInsnClasses - Populate allInsnClasses which is a set of units 358*0b57cec5SDimitry Andric // used in each stage. 359*0b57cec5SDimitry Andric // 360*0b57cec5SDimitry Andric int DFAPacketizerEmitter::collectAllInsnClasses(const std::string &ProcName, 361*0b57cec5SDimitry Andric std::vector<Record*> &ProcItinList, 362*0b57cec5SDimitry Andric std::map<std::string, unsigned> &FUNameToBitsMap, 363*0b57cec5SDimitry Andric std::vector<Record*> &ItinDataList, 364*0b57cec5SDimitry Andric int &maxStages, 365*0b57cec5SDimitry Andric raw_ostream &OS) { 366*0b57cec5SDimitry Andric // Collect all instruction classes. 367*0b57cec5SDimitry Andric unsigned M = ItinDataList.size(); 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric int numInsnClasses = 0; 370*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "-------------------------------------------------------" 371*0b57cec5SDimitry Andric "----------------------\n" 372*0b57cec5SDimitry Andric << "collectAllInsnClasses " << ProcName << " (" << M 373*0b57cec5SDimitry Andric << " classes)\n"); 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric // Collect stages for each instruction class for all itinerary data 376*0b57cec5SDimitry Andric for (unsigned j = 0; j < M; j++) { 377*0b57cec5SDimitry Andric Record *ItinData = ItinDataList[j]; 378*0b57cec5SDimitry Andric int NStages = collectOneInsnClass(ProcName, ProcItinList, 379*0b57cec5SDimitry Andric FUNameToBitsMap, ItinData, OS); 380*0b57cec5SDimitry Andric if (NStages > maxStages) { 381*0b57cec5SDimitry Andric maxStages = NStages; 382*0b57cec5SDimitry Andric } 383*0b57cec5SDimitry Andric numInsnClasses++; 384*0b57cec5SDimitry Andric } 385*0b57cec5SDimitry Andric return numInsnClasses; 386*0b57cec5SDimitry Andric } 387*0b57cec5SDimitry Andric 388*0b57cec5SDimitry Andric // 389*0b57cec5SDimitry Andric // Run the worklist algorithm to generate the DFA. 390*0b57cec5SDimitry Andric // 391*0b57cec5SDimitry Andric void DFAPacketizerEmitter::run(raw_ostream &OS) { 3928bcb0991SDimitry Andric OS << "\n" 3938bcb0991SDimitry Andric << "#include \"llvm/CodeGen/DFAPacketizer.h\"\n"; 3948bcb0991SDimitry Andric OS << "namespace llvm {\n"; 3958bcb0991SDimitry Andric 3968bcb0991SDimitry Andric OS << "\n// Input format:\n"; 3978bcb0991SDimitry Andric OS << "#define DFA_MAX_RESTERMS " << DFA_MAX_RESTERMS 3988bcb0991SDimitry Andric << "\t// maximum AND'ed resource terms\n"; 3998bcb0991SDimitry Andric OS << "#define DFA_MAX_RESOURCES " << DFA_MAX_RESOURCES 4008bcb0991SDimitry Andric << "\t// maximum resource bits in one term\n"; 4018bcb0991SDimitry Andric 402*0b57cec5SDimitry Andric // Collect processor iteraries. 403*0b57cec5SDimitry Andric std::vector<Record*> ProcItinList = 404*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("ProcessorItineraries"); 405*0b57cec5SDimitry Andric 4068bcb0991SDimitry Andric std::unordered_map<std::string, std::vector<Record*>> ItinsByNamespace; 4078bcb0991SDimitry Andric for (Record *R : ProcItinList) 4088bcb0991SDimitry Andric ItinsByNamespace[R->getValueAsString("PacketizerNamespace")].push_back(R); 4098bcb0991SDimitry Andric 4108bcb0991SDimitry Andric for (auto &KV : ItinsByNamespace) 4118bcb0991SDimitry Andric emitForItineraries(OS, KV.second, KV.first); 4128bcb0991SDimitry Andric OS << "} // end namespace llvm\n"; 4138bcb0991SDimitry Andric } 4148bcb0991SDimitry Andric 4158bcb0991SDimitry Andric void DFAPacketizerEmitter::emitForItineraries( 4168bcb0991SDimitry Andric raw_ostream &OS, std::vector<Record *> &ProcItinList, 4178bcb0991SDimitry Andric std::string DFAName) { 418*0b57cec5SDimitry Andric // 419*0b57cec5SDimitry Andric // Collect the Functional units. 420*0b57cec5SDimitry Andric // 421*0b57cec5SDimitry Andric std::map<std::string, unsigned> FUNameToBitsMap; 422*0b57cec5SDimitry Andric int maxResources = 0; 423*0b57cec5SDimitry Andric collectAllFuncUnits(ProcItinList, 424*0b57cec5SDimitry Andric FUNameToBitsMap, maxResources, OS); 425*0b57cec5SDimitry Andric 426*0b57cec5SDimitry Andric // 427*0b57cec5SDimitry Andric // Collect the Combo Functional units. 428*0b57cec5SDimitry Andric // 429*0b57cec5SDimitry Andric std::map<unsigned, unsigned> ComboBitToBitsMap; 430*0b57cec5SDimitry Andric std::vector<Record*> ComboFuncList = 431*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("ComboFuncUnits"); 4328bcb0991SDimitry Andric collectAllComboFuncs(ComboFuncList, FUNameToBitsMap, ComboBitToBitsMap, OS); 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric // 435*0b57cec5SDimitry Andric // Collect the itineraries. 436*0b57cec5SDimitry Andric // 437*0b57cec5SDimitry Andric int maxStages = 0; 438*0b57cec5SDimitry Andric int numInsnClasses = 0; 439*0b57cec5SDimitry Andric for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) { 440*0b57cec5SDimitry Andric Record *Proc = ProcItinList[i]; 441*0b57cec5SDimitry Andric 442*0b57cec5SDimitry Andric // Get processor itinerary name. 443*0b57cec5SDimitry Andric const std::string &ProcName = Proc->getName(); 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric // Skip default. 446*0b57cec5SDimitry Andric if (ProcName == "NoItineraries") 447*0b57cec5SDimitry Andric continue; 448*0b57cec5SDimitry Andric 449*0b57cec5SDimitry Andric // Sanity check for at least one instruction itinerary class. 450*0b57cec5SDimitry Andric unsigned NItinClasses = 451*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("InstrItinClass").size(); 452*0b57cec5SDimitry Andric if (NItinClasses == 0) 453*0b57cec5SDimitry Andric return; 454*0b57cec5SDimitry Andric 455*0b57cec5SDimitry Andric // Get itinerary data list. 456*0b57cec5SDimitry Andric std::vector<Record*> ItinDataList = Proc->getValueAsListOfDefs("IID"); 457*0b57cec5SDimitry Andric 458*0b57cec5SDimitry Andric // Collect all instruction classes 459*0b57cec5SDimitry Andric numInsnClasses += collectAllInsnClasses(ProcName, ProcItinList, 460*0b57cec5SDimitry Andric FUNameToBitsMap, ItinDataList, maxStages, OS); 461*0b57cec5SDimitry Andric } 462*0b57cec5SDimitry Andric 4638bcb0991SDimitry Andric // The type of a state in the nondeterministic automaton we're defining. 4648bcb0991SDimitry Andric using NfaStateTy = unsigned; 465*0b57cec5SDimitry Andric 4668bcb0991SDimitry Andric // Given a resource state, return all resource states by applying 4678bcb0991SDimitry Andric // InsnClass. 4688bcb0991SDimitry Andric auto applyInsnClass = [&](ArrayRef<unsigned> InsnClass, 4698bcb0991SDimitry Andric NfaStateTy State) -> std::deque<unsigned> { 4708bcb0991SDimitry Andric std::deque<unsigned> V(1, State); 4718bcb0991SDimitry Andric // Apply every stage in the class individually. 4728bcb0991SDimitry Andric for (unsigned Stage : InsnClass) { 4738bcb0991SDimitry Andric // Apply this stage to every existing member of V in turn. 4748bcb0991SDimitry Andric size_t Sz = V.size(); 4758bcb0991SDimitry Andric for (unsigned I = 0; I < Sz; ++I) { 4768bcb0991SDimitry Andric unsigned S = V.front(); 4778bcb0991SDimitry Andric V.pop_front(); 478*0b57cec5SDimitry Andric 4798bcb0991SDimitry Andric // For this stage, state combination, try all possible resources. 4808bcb0991SDimitry Andric for (unsigned J = 0; J < DFA_MAX_RESOURCES; ++J) { 4818bcb0991SDimitry Andric unsigned ResourceMask = 1U << J; 4828bcb0991SDimitry Andric if ((ResourceMask & Stage) == 0) 4838bcb0991SDimitry Andric // This resource isn't required by this stage. 484*0b57cec5SDimitry Andric continue; 4858bcb0991SDimitry Andric unsigned Combo = ComboBitToBitsMap[ResourceMask]; 4868bcb0991SDimitry Andric if (Combo && ((~S & Combo) != Combo)) 4878bcb0991SDimitry Andric // This combo units bits are not available. 4888bcb0991SDimitry Andric continue; 4898bcb0991SDimitry Andric unsigned ResultingResourceState = S | ResourceMask | Combo; 4908bcb0991SDimitry Andric if (ResultingResourceState == S) 4918bcb0991SDimitry Andric continue; 4928bcb0991SDimitry Andric V.push_back(ResultingResourceState); 493*0b57cec5SDimitry Andric } 494*0b57cec5SDimitry Andric } 4958bcb0991SDimitry Andric } 4968bcb0991SDimitry Andric return V; 4978bcb0991SDimitry Andric }; 498*0b57cec5SDimitry Andric 4998bcb0991SDimitry Andric // Given a resource state, return a quick (conservative) guess as to whether 5008bcb0991SDimitry Andric // InsnClass can be applied. This is a filter for the more heavyweight 5018bcb0991SDimitry Andric // applyInsnClass. 5028bcb0991SDimitry Andric auto canApplyInsnClass = [](ArrayRef<unsigned> InsnClass, 5038bcb0991SDimitry Andric NfaStateTy State) -> bool { 5048bcb0991SDimitry Andric for (unsigned Resources : InsnClass) { 5058bcb0991SDimitry Andric if ((State | Resources) == State) 5068bcb0991SDimitry Andric return false; 5078bcb0991SDimitry Andric } 5088bcb0991SDimitry Andric return true; 5098bcb0991SDimitry Andric }; 5108bcb0991SDimitry Andric 5118bcb0991SDimitry Andric DfaEmitter Emitter; 5128bcb0991SDimitry Andric std::deque<NfaStateTy> Worklist(1, 0); 5138bcb0991SDimitry Andric std::set<NfaStateTy> SeenStates; 5148bcb0991SDimitry Andric SeenStates.insert(Worklist.front()); 5158bcb0991SDimitry Andric while (!Worklist.empty()) { 5168bcb0991SDimitry Andric NfaStateTy State = Worklist.front(); 5178bcb0991SDimitry Andric Worklist.pop_front(); 5188bcb0991SDimitry Andric for (unsigned i = 0; i < allInsnClasses.size(); i++) { 5198bcb0991SDimitry Andric const std::vector<unsigned> &InsnClass = allInsnClasses[i]; 5208bcb0991SDimitry Andric if (!canApplyInsnClass(InsnClass, State)) 5218bcb0991SDimitry Andric continue; 5228bcb0991SDimitry Andric for (unsigned NewState : applyInsnClass(InsnClass, State)) { 5238bcb0991SDimitry Andric if (SeenStates.emplace(NewState).second) 5248bcb0991SDimitry Andric Worklist.emplace_back(NewState); 5258bcb0991SDimitry Andric Emitter.addTransition(State, NewState, getDFAInsnInput(InsnClass)); 526*0b57cec5SDimitry Andric } 527*0b57cec5SDimitry Andric } 528*0b57cec5SDimitry Andric } 529*0b57cec5SDimitry Andric 5308bcb0991SDimitry Andric OS << "} // end namespace llvm\n\n"; 5318bcb0991SDimitry Andric OS << "namespace {\n"; 5328bcb0991SDimitry Andric std::string TargetAndDFAName = TargetName + DFAName; 5338bcb0991SDimitry Andric Emitter.emit(TargetAndDFAName, OS); 5348bcb0991SDimitry Andric OS << "} // end anonymous namespace\n\n"; 5358bcb0991SDimitry Andric 5368bcb0991SDimitry Andric std::string SubTargetClassName = TargetName + "GenSubtargetInfo"; 5378bcb0991SDimitry Andric OS << "namespace llvm {\n"; 5388bcb0991SDimitry Andric OS << "DFAPacketizer *" << SubTargetClassName << "::" 5398bcb0991SDimitry Andric << "create" << DFAName 5408bcb0991SDimitry Andric << "DFAPacketizer(const InstrItineraryData *IID) const {\n" 5418bcb0991SDimitry Andric << " static Automaton<uint64_t> A(ArrayRef<" << TargetAndDFAName 5428bcb0991SDimitry Andric << "Transition>(" << TargetAndDFAName << "Transitions), " 5438bcb0991SDimitry Andric << TargetAndDFAName << "TransitionInfo);\n" 5448bcb0991SDimitry Andric << " return new DFAPacketizer(IID, A);\n" 5458bcb0991SDimitry Andric << "\n}\n\n"; 546*0b57cec5SDimitry Andric } 547*0b57cec5SDimitry Andric 548*0b57cec5SDimitry Andric namespace llvm { 549*0b57cec5SDimitry Andric 550*0b57cec5SDimitry Andric void EmitDFAPacketizer(RecordKeeper &RK, raw_ostream &OS) { 551*0b57cec5SDimitry Andric emitSourceFileHeader("Target DFA Packetizer Tables", OS); 552*0b57cec5SDimitry Andric DFAPacketizerEmitter(RK).run(OS); 553*0b57cec5SDimitry Andric } 554*0b57cec5SDimitry Andric 555*0b57cec5SDimitry Andric } // end namespace llvm 556