1dff0c46cSDimitry Andric //=- llvm/CodeGen/DFAPacketizer.cpp - DFA Packetizer for VLIW -*- C++ -*-=====//
2dff0c46cSDimitry Andric //
3dff0c46cSDimitry Andric //                     The LLVM Compiler Infrastructure
4dff0c46cSDimitry Andric //
5dff0c46cSDimitry Andric // This file is distributed under the University of Illinois Open Source
6dff0c46cSDimitry Andric // License. See LICENSE.TXT for details.
7dff0c46cSDimitry Andric //
8dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
9dff0c46cSDimitry Andric // This class implements a deterministic finite automaton (DFA) based
10dff0c46cSDimitry Andric // packetizing mechanism for VLIW architectures. It provides APIs to
11dff0c46cSDimitry Andric // determine whether there exists a legal mapping of instructions to
12dff0c46cSDimitry Andric // functional unit assignments in a packet. The DFA is auto-generated from
13dff0c46cSDimitry Andric // the target's Schedule.td file.
14dff0c46cSDimitry Andric //
15dff0c46cSDimitry Andric // A DFA consists of 3 major elements: states, inputs, and transitions. For
16dff0c46cSDimitry Andric // the packetizing mechanism, the input is the set of instruction classes for
17dff0c46cSDimitry Andric // a target. The state models all possible combinations of functional unit
18dff0c46cSDimitry Andric // consumption for a given set of instructions in a packet. A transition
19dff0c46cSDimitry Andric // models the addition of an instruction to a packet. In the DFA constructed
20dff0c46cSDimitry Andric // by this class, if an instruction can be added to a packet, then a valid
21dff0c46cSDimitry Andric // transition exists from the corresponding state. Invalid transitions
22dff0c46cSDimitry Andric // indicate that the instruction cannot be added to the current packet.
23dff0c46cSDimitry Andric //
24dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
25dff0c46cSDimitry Andric 
26dff0c46cSDimitry Andric #include "llvm/CodeGen/DFAPacketizer.h"
27dff0c46cSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
28dff0c46cSDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h"
29139f7f9bSDimitry Andric #include "llvm/CodeGen/ScheduleDAGInstrs.h"
30dff0c46cSDimitry Andric #include "llvm/MC/MCInstrItineraries.h"
31139f7f9bSDimitry Andric #include "llvm/Target/TargetInstrInfo.h"
32dff0c46cSDimitry Andric using namespace llvm;
33dff0c46cSDimitry Andric 
34dff0c46cSDimitry Andric DFAPacketizer::DFAPacketizer(const InstrItineraryData *I, const int (*SIT)[2],
35dff0c46cSDimitry Andric                              const unsigned *SET):
36dff0c46cSDimitry Andric   InstrItins(I), CurrentState(0), DFAStateInputTable(SIT),
37dff0c46cSDimitry Andric   DFAStateEntryTable(SET) {}
38dff0c46cSDimitry Andric 
39dff0c46cSDimitry Andric 
40dff0c46cSDimitry Andric //
41dff0c46cSDimitry Andric // ReadTable - Read the DFA transition table and update CachedTable.
42dff0c46cSDimitry Andric //
43dff0c46cSDimitry Andric // Format of the transition tables:
44dff0c46cSDimitry Andric // DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid
45dff0c46cSDimitry Andric //                           transitions
46dff0c46cSDimitry Andric // DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable
47dff0c46cSDimitry Andric //                         for the ith state
48dff0c46cSDimitry Andric //
49dff0c46cSDimitry Andric void DFAPacketizer::ReadTable(unsigned int state) {
50dff0c46cSDimitry Andric   unsigned ThisState = DFAStateEntryTable[state];
51dff0c46cSDimitry Andric   unsigned NextStateInTable = DFAStateEntryTable[state+1];
52dff0c46cSDimitry Andric   // Early exit in case CachedTable has already contains this
53dff0c46cSDimitry Andric   // state's transitions.
54dff0c46cSDimitry Andric   if (CachedTable.count(UnsignPair(state,
55dff0c46cSDimitry Andric                                    DFAStateInputTable[ThisState][0])))
56dff0c46cSDimitry Andric     return;
57dff0c46cSDimitry Andric 
58dff0c46cSDimitry Andric   for (unsigned i = ThisState; i < NextStateInTable; i++)
59dff0c46cSDimitry Andric     CachedTable[UnsignPair(state, DFAStateInputTable[i][0])] =
60dff0c46cSDimitry Andric       DFAStateInputTable[i][1];
61dff0c46cSDimitry Andric }
62dff0c46cSDimitry Andric 
63dff0c46cSDimitry Andric 
64dff0c46cSDimitry Andric // canReserveResources - Check if the resources occupied by a MCInstrDesc
65dff0c46cSDimitry Andric // are available in the current state.
66dff0c46cSDimitry Andric bool DFAPacketizer::canReserveResources(const llvm::MCInstrDesc *MID) {
67dff0c46cSDimitry Andric   unsigned InsnClass = MID->getSchedClass();
68dff0c46cSDimitry Andric   const llvm::InstrStage *IS = InstrItins->beginStage(InsnClass);
69dff0c46cSDimitry Andric   unsigned FuncUnits = IS->getUnits();
70dff0c46cSDimitry Andric   UnsignPair StateTrans = UnsignPair(CurrentState, FuncUnits);
71dff0c46cSDimitry Andric   ReadTable(CurrentState);
72dff0c46cSDimitry Andric   return (CachedTable.count(StateTrans) != 0);
73dff0c46cSDimitry Andric }
74dff0c46cSDimitry Andric 
75dff0c46cSDimitry Andric 
76dff0c46cSDimitry Andric // reserveResources - Reserve the resources occupied by a MCInstrDesc and
77dff0c46cSDimitry Andric // change the current state to reflect that change.
78dff0c46cSDimitry Andric void DFAPacketizer::reserveResources(const llvm::MCInstrDesc *MID) {
79dff0c46cSDimitry Andric   unsigned InsnClass = MID->getSchedClass();
80dff0c46cSDimitry Andric   const llvm::InstrStage *IS = InstrItins->beginStage(InsnClass);
81dff0c46cSDimitry Andric   unsigned FuncUnits = IS->getUnits();
82dff0c46cSDimitry Andric   UnsignPair StateTrans = UnsignPair(CurrentState, FuncUnits);
83dff0c46cSDimitry Andric   ReadTable(CurrentState);
84dff0c46cSDimitry Andric   assert(CachedTable.count(StateTrans) != 0);
85dff0c46cSDimitry Andric   CurrentState = CachedTable[StateTrans];
86dff0c46cSDimitry Andric }
87dff0c46cSDimitry Andric 
88dff0c46cSDimitry Andric 
89dff0c46cSDimitry Andric // canReserveResources - Check if the resources occupied by a machine
90dff0c46cSDimitry Andric // instruction are available in the current state.
91dff0c46cSDimitry Andric bool DFAPacketizer::canReserveResources(llvm::MachineInstr *MI) {
92dff0c46cSDimitry Andric   const llvm::MCInstrDesc &MID = MI->getDesc();
93dff0c46cSDimitry Andric   return canReserveResources(&MID);
94dff0c46cSDimitry Andric }
95dff0c46cSDimitry Andric 
96dff0c46cSDimitry Andric // reserveResources - Reserve the resources occupied by a machine
97dff0c46cSDimitry Andric // instruction and change the current state to reflect that change.
98dff0c46cSDimitry Andric void DFAPacketizer::reserveResources(llvm::MachineInstr *MI) {
99dff0c46cSDimitry Andric   const llvm::MCInstrDesc &MID = MI->getDesc();
100dff0c46cSDimitry Andric   reserveResources(&MID);
101dff0c46cSDimitry Andric }
102dff0c46cSDimitry Andric 
1037ae0e2c9SDimitry Andric namespace llvm {
104dff0c46cSDimitry Andric // DefaultVLIWScheduler - This class extends ScheduleDAGInstrs and overrides
105dff0c46cSDimitry Andric // Schedule method to build the dependence graph.
106dff0c46cSDimitry Andric class DefaultVLIWScheduler : public ScheduleDAGInstrs {
107dff0c46cSDimitry Andric public:
108dff0c46cSDimitry Andric   DefaultVLIWScheduler(MachineFunction &MF, MachineLoopInfo &MLI,
109dff0c46cSDimitry Andric                    MachineDominatorTree &MDT, bool IsPostRA);
110dff0c46cSDimitry Andric   // Schedule - Actual scheduling work.
11191bc56edSDimitry Andric   void schedule() override;
112dff0c46cSDimitry Andric };
1137ae0e2c9SDimitry Andric }
114dff0c46cSDimitry Andric 
115dff0c46cSDimitry Andric DefaultVLIWScheduler::DefaultVLIWScheduler(
116dff0c46cSDimitry Andric   MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT,
117dff0c46cSDimitry Andric   bool IsPostRA) :
118dff0c46cSDimitry Andric   ScheduleDAGInstrs(MF, MLI, MDT, IsPostRA) {
1197ae0e2c9SDimitry Andric   CanHandleTerminators = true;
120dff0c46cSDimitry Andric }
121dff0c46cSDimitry Andric 
122dff0c46cSDimitry Andric void DefaultVLIWScheduler::schedule() {
123dff0c46cSDimitry Andric   // Build the scheduling graph.
12491bc56edSDimitry Andric   buildSchedGraph(nullptr);
125dff0c46cSDimitry Andric }
126dff0c46cSDimitry Andric 
127dff0c46cSDimitry Andric // VLIWPacketizerList Ctor
128dff0c46cSDimitry Andric VLIWPacketizerList::VLIWPacketizerList(
129dff0c46cSDimitry Andric   MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT,
130dff0c46cSDimitry Andric   bool IsPostRA) : TM(MF.getTarget()), MF(MF)  {
131dff0c46cSDimitry Andric   TII = TM.getInstrInfo();
13291bc56edSDimitry Andric   ResourceTracker = TII->CreateTargetScheduleState(&TM, nullptr);
1337ae0e2c9SDimitry Andric   VLIWScheduler = new DefaultVLIWScheduler(MF, MLI, MDT, IsPostRA);
134dff0c46cSDimitry Andric }
135dff0c46cSDimitry Andric 
136dff0c46cSDimitry Andric // VLIWPacketizerList Dtor
137dff0c46cSDimitry Andric VLIWPacketizerList::~VLIWPacketizerList() {
1387ae0e2c9SDimitry Andric   if (VLIWScheduler)
1397ae0e2c9SDimitry Andric     delete VLIWScheduler;
1407ae0e2c9SDimitry Andric 
1417ae0e2c9SDimitry Andric   if (ResourceTracker)
142dff0c46cSDimitry Andric     delete ResourceTracker;
143dff0c46cSDimitry Andric }
144dff0c46cSDimitry Andric 
145dff0c46cSDimitry Andric // endPacket - End the current packet, bundle packet instructions and reset
146dff0c46cSDimitry Andric // DFA state.
147dff0c46cSDimitry Andric void VLIWPacketizerList::endPacket(MachineBasicBlock *MBB,
1487ae0e2c9SDimitry Andric                                          MachineInstr *MI) {
149dff0c46cSDimitry Andric   if (CurrentPacketMIs.size() > 1) {
150dff0c46cSDimitry Andric     MachineInstr *MIFirst = CurrentPacketMIs.front();
1517ae0e2c9SDimitry Andric     finalizeBundle(*MBB, MIFirst, MI);
152dff0c46cSDimitry Andric   }
153dff0c46cSDimitry Andric   CurrentPacketMIs.clear();
154dff0c46cSDimitry Andric   ResourceTracker->clearResources();
155dff0c46cSDimitry Andric }
156dff0c46cSDimitry Andric 
157dff0c46cSDimitry Andric // PacketizeMIs - Bundle machine instructions into packets.
158dff0c46cSDimitry Andric void VLIWPacketizerList::PacketizeMIs(MachineBasicBlock *MBB,
159dff0c46cSDimitry Andric                                       MachineBasicBlock::iterator BeginItr,
160dff0c46cSDimitry Andric                                       MachineBasicBlock::iterator EndItr) {
1617ae0e2c9SDimitry Andric   assert(VLIWScheduler && "VLIW Scheduler is not initialized!");
1627ae0e2c9SDimitry Andric   VLIWScheduler->startBlock(MBB);
163f785676fSDimitry Andric   VLIWScheduler->enterRegion(MBB, BeginItr, EndItr,
164f785676fSDimitry Andric                              std::distance(BeginItr, EndItr));
1657ae0e2c9SDimitry Andric   VLIWScheduler->schedule();
166dff0c46cSDimitry Andric 
1677ae0e2c9SDimitry Andric   // Generate MI -> SU map.
1687ae0e2c9SDimitry Andric   MIToSUnit.clear();
1697ae0e2c9SDimitry Andric   for (unsigned i = 0, e = VLIWScheduler->SUnits.size(); i != e; ++i) {
1707ae0e2c9SDimitry Andric     SUnit *SU = &VLIWScheduler->SUnits[i];
1717ae0e2c9SDimitry Andric     MIToSUnit[SU->getInstr()] = SU;
1727ae0e2c9SDimitry Andric   }
173dff0c46cSDimitry Andric 
174dff0c46cSDimitry Andric   // The main packetizer loop.
175dff0c46cSDimitry Andric   for (; BeginItr != EndItr; ++BeginItr) {
176dff0c46cSDimitry Andric     MachineInstr *MI = BeginItr;
177dff0c46cSDimitry Andric 
1787ae0e2c9SDimitry Andric     this->initPacketizerState();
179dff0c46cSDimitry Andric 
180dff0c46cSDimitry Andric     // End the current packet if needed.
1817ae0e2c9SDimitry Andric     if (this->isSoloInstruction(MI)) {
182dff0c46cSDimitry Andric       endPacket(MBB, MI);
183dff0c46cSDimitry Andric       continue;
184dff0c46cSDimitry Andric     }
185dff0c46cSDimitry Andric 
1867ae0e2c9SDimitry Andric     // Ignore pseudo instructions.
1877ae0e2c9SDimitry Andric     if (this->ignorePseudoInstruction(MI, MBB))
1887ae0e2c9SDimitry Andric       continue;
1897ae0e2c9SDimitry Andric 
1907ae0e2c9SDimitry Andric     SUnit *SUI = MIToSUnit[MI];
191dff0c46cSDimitry Andric     assert(SUI && "Missing SUnit Info!");
192dff0c46cSDimitry Andric 
193dff0c46cSDimitry Andric     // Ask DFA if machine resource is available for MI.
194dff0c46cSDimitry Andric     bool ResourceAvail = ResourceTracker->canReserveResources(MI);
195dff0c46cSDimitry Andric     if (ResourceAvail) {
196dff0c46cSDimitry Andric       // Dependency check for MI with instructions in CurrentPacketMIs.
197dff0c46cSDimitry Andric       for (std::vector<MachineInstr*>::iterator VI = CurrentPacketMIs.begin(),
198dff0c46cSDimitry Andric            VE = CurrentPacketMIs.end(); VI != VE; ++VI) {
199dff0c46cSDimitry Andric         MachineInstr *MJ = *VI;
2007ae0e2c9SDimitry Andric         SUnit *SUJ = MIToSUnit[MJ];
201dff0c46cSDimitry Andric         assert(SUJ && "Missing SUnit Info!");
202dff0c46cSDimitry Andric 
203dff0c46cSDimitry Andric         // Is it legal to packetize SUI and SUJ together.
2047ae0e2c9SDimitry Andric         if (!this->isLegalToPacketizeTogether(SUI, SUJ)) {
205dff0c46cSDimitry Andric           // Allow packetization if dependency can be pruned.
2067ae0e2c9SDimitry Andric           if (!this->isLegalToPruneDependencies(SUI, SUJ)) {
207dff0c46cSDimitry Andric             // End the packet if dependency cannot be pruned.
208dff0c46cSDimitry Andric             endPacket(MBB, MI);
209dff0c46cSDimitry Andric             break;
210dff0c46cSDimitry Andric           } // !isLegalToPruneDependencies.
211dff0c46cSDimitry Andric         } // !isLegalToPacketizeTogether.
212dff0c46cSDimitry Andric       } // For all instructions in CurrentPacketMIs.
213dff0c46cSDimitry Andric     } else {
214dff0c46cSDimitry Andric       // End the packet if resource is not available.
215dff0c46cSDimitry Andric       endPacket(MBB, MI);
216dff0c46cSDimitry Andric     }
217dff0c46cSDimitry Andric 
218dff0c46cSDimitry Andric     // Add MI to the current packet.
2197ae0e2c9SDimitry Andric     BeginItr = this->addToPacket(MI);
220dff0c46cSDimitry Andric   } // For all instructions in BB.
221dff0c46cSDimitry Andric 
222dff0c46cSDimitry Andric   // End any packet left behind.
223dff0c46cSDimitry Andric   endPacket(MBB, EndItr);
2247ae0e2c9SDimitry Andric   VLIWScheduler->exitRegion();
2257ae0e2c9SDimitry Andric   VLIWScheduler->finishBlock();
226dff0c46cSDimitry Andric }
227