DFAPacketizerEmitter.cpp 16 KB

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