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