xref: /llvm-project/llvm/lib/CodeGen/DFAPacketizer.cpp (revision 1a1d78b86f74d1ef094cde2caf9284730d62665b)
1 //=- llvm/CodeGen/DFAPacketizer.cpp - DFA Packetizer for VLIW -*- C++ -*-=====//
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 // This class implements a deterministic finite automaton (DFA) based
10 // packetizing mechanism for VLIW architectures. It provides APIs to
11 // determine whether there exists a legal mapping of instructions to
12 // functional unit assignments in a packet. The DFA is auto-generated from
13 // the target's Schedule.td file.
14 //
15 // A DFA consists of 3 major elements: states, inputs, and transitions. For
16 // the packetizing mechanism, the input is the set of instruction classes for
17 // a target. The state models all possible combinations of functional unit
18 // consumption for a given set of instructions in a packet. A transition
19 // models the addition of an instruction to a packet. In the DFA constructed
20 // by this class, if an instruction can be added to a packet, then a valid
21 // transition exists from the corresponding state. Invalid transitions
22 // indicate that the instruction cannot be added to the current packet.
23 //
24 //===----------------------------------------------------------------------===//
25 
26 #include "llvm/CodeGen/DFAPacketizer.h"
27 #include "llvm/CodeGen/MachineInstr.h"
28 #include "llvm/CodeGen/MachineInstrBundle.h"
29 #include "llvm/CodeGen/ScheduleDAGInstrs.h"
30 #include "llvm/MC/MCInstrItineraries.h"
31 #include "llvm/Target/TargetInstrInfo.h"
32 
33 using namespace llvm;
34 
35 // --------------------------------------------------------------------
36 // Definitions shared between DFAPacketizer.cpp and DFAPacketizerEmitter.cpp
37 
38 namespace {
39   DFAInput addDFAFuncUnits(DFAInput Inp, unsigned FuncUnits) {
40     return (Inp << DFA_MAX_RESOURCES) | FuncUnits;
41   }
42 
43   /// Return the DFAInput for an instruction class input vector.
44   /// This function is used in both DFAPacketizer.cpp and in
45   /// DFAPacketizerEmitter.cpp.
46   DFAInput getDFAInsnInput(const std::vector<unsigned> &InsnClass) {
47     DFAInput InsnInput = 0;
48     assert((InsnClass.size() <= DFA_MAX_RESTERMS) &&
49            "Exceeded maximum number of DFA terms");
50     for (auto U : InsnClass)
51       InsnInput = addDFAFuncUnits(InsnInput, U);
52     return InsnInput;
53   }
54 }
55 // --------------------------------------------------------------------
56 
57 DFAPacketizer::DFAPacketizer(const InstrItineraryData *I,
58                              const DFAStateInput (*SIT)[2],
59                              const unsigned *SET):
60   InstrItins(I), CurrentState(0), DFAStateInputTable(SIT),
61   DFAStateEntryTable(SET) {
62   // Make sure DFA types are large enough for the number of terms & resources.
63   assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * sizeof(DFAInput))
64         && "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput");
65   assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * sizeof(DFAStateInput))
66         && "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAStateInput");
67 }
68 
69 
70 // Read the DFA transition table and update CachedTable.
71 //
72 // Format of the transition tables:
73 // DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
74 //                           transitions
75 // DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable
76 //                         for the ith state
77 //
78 void DFAPacketizer::ReadTable(unsigned int state) {
79   unsigned ThisState = DFAStateEntryTable[state];
80   unsigned NextStateInTable = DFAStateEntryTable[state+1];
81   // Early exit in case CachedTable has already contains this
82   // state's transitions.
83   if (CachedTable.count(UnsignPair(state, DFAStateInputTable[ThisState][0])))
84     return;
85 
86   for (unsigned i = ThisState; i < NextStateInTable; i++)
87     CachedTable[UnsignPair(state, DFAStateInputTable[i][0])] =
88       DFAStateInputTable[i][1];
89 }
90 
91 
92 // Return the DFAInput for an instruction class.
93 DFAInput DFAPacketizer::getInsnInput(unsigned InsnClass) {
94   // Note: this logic must match that in DFAPacketizerDefs.h for input vectors.
95   DFAInput InsnInput = 0;
96   unsigned i = 0;
97   (void)i;
98   for (const InstrStage *IS = InstrItins->beginStage(InsnClass),
99        *IE = InstrItins->endStage(InsnClass); IS != IE; ++IS) {
100     InsnInput = addDFAFuncUnits(InsnInput, IS->getUnits());
101     assert((i++ < DFA_MAX_RESTERMS) && "Exceeded maximum number of DFA inputs");
102   }
103   return InsnInput;
104 }
105 
106 
107 // Return the DFAInput for an instruction class input vector.
108 DFAInput DFAPacketizer::getInsnInput(const std::vector<unsigned> &InsnClass) {
109   return getDFAInsnInput(InsnClass);
110 }
111 
112 
113 // Check if the resources occupied by a MCInstrDesc are available in the
114 // current state.
115 bool DFAPacketizer::canReserveResources(const llvm::MCInstrDesc *MID) {
116   unsigned InsnClass = MID->getSchedClass();
117   DFAInput InsnInput = getInsnInput(InsnClass);
118   UnsignPair StateTrans = UnsignPair(CurrentState, InsnInput);
119   ReadTable(CurrentState);
120   return CachedTable.count(StateTrans) != 0;
121 }
122 
123 
124 // Reserve the resources occupied by a MCInstrDesc and change the current
125 // state to reflect that change.
126 void DFAPacketizer::reserveResources(const llvm::MCInstrDesc *MID) {
127   unsigned InsnClass = MID->getSchedClass();
128   DFAInput InsnInput = getInsnInput(InsnClass);
129   UnsignPair StateTrans = UnsignPair(CurrentState, InsnInput);
130   ReadTable(CurrentState);
131   assert(CachedTable.count(StateTrans) != 0);
132   CurrentState = CachedTable[StateTrans];
133 }
134 
135 
136 // Check if the resources occupied by a machine instruction are available
137 // in the current state.
138 bool DFAPacketizer::canReserveResources(llvm::MachineInstr &MI) {
139   const llvm::MCInstrDesc &MID = MI.getDesc();
140   return canReserveResources(&MID);
141 }
142 
143 
144 // Reserve the resources occupied by a machine instruction and change the
145 // current state to reflect that change.
146 void DFAPacketizer::reserveResources(llvm::MachineInstr &MI) {
147   const llvm::MCInstrDesc &MID = MI.getDesc();
148   reserveResources(&MID);
149 }
150 
151 
152 namespace llvm {
153 // This class extends ScheduleDAGInstrs and overrides the schedule method
154 // to build the dependence graph.
155 class DefaultVLIWScheduler : public ScheduleDAGInstrs {
156 private:
157   AliasAnalysis *AA;
158   /// Ordered list of DAG postprocessing steps.
159   std::vector<std::unique_ptr<ScheduleDAGMutation>> Mutations;
160 public:
161   DefaultVLIWScheduler(MachineFunction &MF, MachineLoopInfo &MLI,
162                        AliasAnalysis *AA);
163   // Actual scheduling work.
164   void schedule() override;
165 
166   /// DefaultVLIWScheduler takes ownership of the Mutation object.
167   void addMutation(std::unique_ptr<ScheduleDAGMutation> Mutation) {
168     Mutations.push_back(std::move(Mutation));
169   }
170 protected:
171   void postprocessDAG();
172 };
173 }
174 
175 
176 DefaultVLIWScheduler::DefaultVLIWScheduler(MachineFunction &MF,
177                                            MachineLoopInfo &MLI,
178                                            AliasAnalysis *AA)
179     : ScheduleDAGInstrs(MF, &MLI), AA(AA) {
180   CanHandleTerminators = true;
181 }
182 
183 
184 /// Apply each ScheduleDAGMutation step in order.
185 void DefaultVLIWScheduler::postprocessDAG() {
186   for (auto &M : Mutations)
187     M->apply(this);
188 }
189 
190 
191 void DefaultVLIWScheduler::schedule() {
192   // Build the scheduling graph.
193   buildSchedGraph(AA);
194   postprocessDAG();
195 }
196 
197 
198 VLIWPacketizerList::VLIWPacketizerList(MachineFunction &mf,
199                                        MachineLoopInfo &mli, AliasAnalysis *aa)
200     : MF(mf), TII(mf.getSubtarget().getInstrInfo()), AA(aa) {
201   ResourceTracker = TII->CreateTargetScheduleState(MF.getSubtarget());
202   VLIWScheduler = new DefaultVLIWScheduler(MF, mli, AA);
203 }
204 
205 
206 VLIWPacketizerList::~VLIWPacketizerList() {
207   if (VLIWScheduler)
208     delete VLIWScheduler;
209   if (ResourceTracker)
210     delete ResourceTracker;
211 }
212 
213 
214 // End the current packet, bundle packet instructions and reset DFA state.
215 void VLIWPacketizerList::endPacket(MachineBasicBlock *MBB,
216                                    MachineBasicBlock::iterator MI) {
217   if (CurrentPacketMIs.size() > 1) {
218     MachineInstr &MIFirst = *CurrentPacketMIs.front();
219     finalizeBundle(*MBB, MIFirst.getIterator(), MI.getInstrIterator());
220   }
221   CurrentPacketMIs.clear();
222   ResourceTracker->clearResources();
223 }
224 
225 
226 // Bundle machine instructions into packets.
227 void VLIWPacketizerList::PacketizeMIs(MachineBasicBlock *MBB,
228                                       MachineBasicBlock::iterator BeginItr,
229                                       MachineBasicBlock::iterator EndItr) {
230   assert(VLIWScheduler && "VLIW Scheduler is not initialized!");
231   VLIWScheduler->startBlock(MBB);
232   VLIWScheduler->enterRegion(MBB, BeginItr, EndItr,
233                              std::distance(BeginItr, EndItr));
234   VLIWScheduler->schedule();
235 
236   // Generate MI -> SU map.
237   MIToSUnit.clear();
238   for (SUnit &SU : VLIWScheduler->SUnits)
239     MIToSUnit[SU.getInstr()] = &SU;
240 
241   // The main packetizer loop.
242   for (; BeginItr != EndItr; ++BeginItr) {
243     MachineInstr &MI = *BeginItr;
244     initPacketizerState();
245 
246     // End the current packet if needed.
247     if (isSoloInstruction(MI)) {
248       endPacket(MBB, MI);
249       continue;
250     }
251 
252     // Ignore pseudo instructions.
253     if (ignorePseudoInstruction(MI, MBB))
254       continue;
255 
256     SUnit *SUI = MIToSUnit[&MI];
257     assert(SUI && "Missing SUnit Info!");
258 
259     // Ask DFA if machine resource is available for MI.
260     bool ResourceAvail = ResourceTracker->canReserveResources(MI);
261     if (ResourceAvail && shouldAddToPacket(MI)) {
262       // Dependency check for MI with instructions in CurrentPacketMIs.
263       for (auto MJ : CurrentPacketMIs) {
264         SUnit *SUJ = MIToSUnit[MJ];
265         assert(SUJ && "Missing SUnit Info!");
266 
267         // Is it legal to packetize SUI and SUJ together.
268         if (!isLegalToPacketizeTogether(SUI, SUJ)) {
269           // Allow packetization if dependency can be pruned.
270           if (!isLegalToPruneDependencies(SUI, SUJ)) {
271             // End the packet if dependency cannot be pruned.
272             endPacket(MBB, MI);
273             break;
274           }
275         }
276       }
277     } else {
278       // End the packet if resource is not available, or if the instruction
279       // shoud not be added to the current packet.
280       endPacket(MBB, MI);
281     }
282 
283     // Add MI to the current packet.
284     BeginItr = addToPacket(MI);
285   } // For all instructions in the packetization range.
286 
287   // End any packet left behind.
288   endPacket(MBB, EndItr);
289   VLIWScheduler->exitRegion();
290   VLIWScheduler->finishBlock();
291 }
292 
293 
294 // Add a DAG mutation object to the ordered list.
295 void VLIWPacketizerList::addMutation(
296       std::unique_ptr<ScheduleDAGMutation> Mutation) {
297   VLIWScheduler->addMutation(std::move(Mutation));
298 }
299