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