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 static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= 64 (8 * sizeof(DFAInput)), 65 "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput"); 66 static_assert( 67 (DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * sizeof(DFAStateInput)), 68 "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAStateInput"); 69 } 70 71 72 // Read the DFA transition table and update CachedTable. 73 // 74 // Format of the transition tables: 75 // DFAStateInputTable[][2] = pairs of <Input, Transition> for all valid 76 // transitions 77 // DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable 78 // for the ith state 79 // 80 void DFAPacketizer::ReadTable(unsigned int state) { 81 unsigned ThisState = DFAStateEntryTable[state]; 82 unsigned NextStateInTable = DFAStateEntryTable[state+1]; 83 // Early exit in case CachedTable has already contains this 84 // state's transitions. 85 if (CachedTable.count(UnsignPair(state, DFAStateInputTable[ThisState][0]))) 86 return; 87 88 for (unsigned i = ThisState; i < NextStateInTable; i++) 89 CachedTable[UnsignPair(state, DFAStateInputTable[i][0])] = 90 DFAStateInputTable[i][1]; 91 } 92 93 94 // Return the DFAInput for an instruction class. 95 DFAInput DFAPacketizer::getInsnInput(unsigned InsnClass) { 96 // Note: this logic must match that in DFAPacketizerDefs.h for input vectors. 97 DFAInput InsnInput = 0; 98 unsigned i = 0; 99 (void)i; 100 for (const InstrStage *IS = InstrItins->beginStage(InsnClass), 101 *IE = InstrItins->endStage(InsnClass); IS != IE; ++IS) { 102 InsnInput = addDFAFuncUnits(InsnInput, IS->getUnits()); 103 assert((i++ < DFA_MAX_RESTERMS) && "Exceeded maximum number of DFA inputs"); 104 } 105 return InsnInput; 106 } 107 108 109 // Return the DFAInput for an instruction class input vector. 110 DFAInput DFAPacketizer::getInsnInput(const std::vector<unsigned> &InsnClass) { 111 return getDFAInsnInput(InsnClass); 112 } 113 114 115 // Check if the resources occupied by a MCInstrDesc are available in the 116 // current state. 117 bool DFAPacketizer::canReserveResources(const llvm::MCInstrDesc *MID) { 118 unsigned InsnClass = MID->getSchedClass(); 119 DFAInput InsnInput = getInsnInput(InsnClass); 120 UnsignPair StateTrans = UnsignPair(CurrentState, InsnInput); 121 ReadTable(CurrentState); 122 return CachedTable.count(StateTrans) != 0; 123 } 124 125 126 // Reserve the resources occupied by a MCInstrDesc and change the current 127 // state to reflect that change. 128 void DFAPacketizer::reserveResources(const llvm::MCInstrDesc *MID) { 129 unsigned InsnClass = MID->getSchedClass(); 130 DFAInput InsnInput = getInsnInput(InsnClass); 131 UnsignPair StateTrans = UnsignPair(CurrentState, InsnInput); 132 ReadTable(CurrentState); 133 assert(CachedTable.count(StateTrans) != 0); 134 CurrentState = CachedTable[StateTrans]; 135 } 136 137 138 // Check if the resources occupied by a machine instruction are available 139 // in the current state. 140 bool DFAPacketizer::canReserveResources(llvm::MachineInstr &MI) { 141 const llvm::MCInstrDesc &MID = MI.getDesc(); 142 return canReserveResources(&MID); 143 } 144 145 146 // Reserve the resources occupied by a machine instruction and change the 147 // current state to reflect that change. 148 void DFAPacketizer::reserveResources(llvm::MachineInstr &MI) { 149 const llvm::MCInstrDesc &MID = MI.getDesc(); 150 reserveResources(&MID); 151 } 152 153 154 namespace llvm { 155 // This class extends ScheduleDAGInstrs and overrides the schedule method 156 // to build the dependence graph. 157 class DefaultVLIWScheduler : public ScheduleDAGInstrs { 158 private: 159 AliasAnalysis *AA; 160 /// Ordered list of DAG postprocessing steps. 161 std::vector<std::unique_ptr<ScheduleDAGMutation>> Mutations; 162 public: 163 DefaultVLIWScheduler(MachineFunction &MF, MachineLoopInfo &MLI, 164 AliasAnalysis *AA); 165 // Actual scheduling work. 166 void schedule() override; 167 168 /// DefaultVLIWScheduler takes ownership of the Mutation object. 169 void addMutation(std::unique_ptr<ScheduleDAGMutation> Mutation) { 170 Mutations.push_back(std::move(Mutation)); 171 } 172 protected: 173 void postprocessDAG(); 174 }; 175 } 176 177 178 DefaultVLIWScheduler::DefaultVLIWScheduler(MachineFunction &MF, 179 MachineLoopInfo &MLI, 180 AliasAnalysis *AA) 181 : ScheduleDAGInstrs(MF, &MLI), AA(AA) { 182 CanHandleTerminators = true; 183 } 184 185 186 /// Apply each ScheduleDAGMutation step in order. 187 void DefaultVLIWScheduler::postprocessDAG() { 188 for (auto &M : Mutations) 189 M->apply(this); 190 } 191 192 193 void DefaultVLIWScheduler::schedule() { 194 // Build the scheduling graph. 195 buildSchedGraph(AA); 196 postprocessDAG(); 197 } 198 199 200 VLIWPacketizerList::VLIWPacketizerList(MachineFunction &mf, 201 MachineLoopInfo &mli, AliasAnalysis *aa) 202 : MF(mf), TII(mf.getSubtarget().getInstrInfo()), AA(aa) { 203 ResourceTracker = TII->CreateTargetScheduleState(MF.getSubtarget()); 204 VLIWScheduler = new DefaultVLIWScheduler(MF, mli, AA); 205 } 206 207 208 VLIWPacketizerList::~VLIWPacketizerList() { 209 if (VLIWScheduler) 210 delete VLIWScheduler; 211 if (ResourceTracker) 212 delete ResourceTracker; 213 } 214 215 216 // End the current packet, bundle packet instructions and reset DFA state. 217 void VLIWPacketizerList::endPacket(MachineBasicBlock *MBB, 218 MachineBasicBlock::iterator MI) { 219 if (CurrentPacketMIs.size() > 1) { 220 MachineInstr &MIFirst = *CurrentPacketMIs.front(); 221 finalizeBundle(*MBB, MIFirst.getIterator(), MI.getInstrIterator()); 222 } 223 CurrentPacketMIs.clear(); 224 ResourceTracker->clearResources(); 225 } 226 227 228 // Bundle machine instructions into packets. 229 void VLIWPacketizerList::PacketizeMIs(MachineBasicBlock *MBB, 230 MachineBasicBlock::iterator BeginItr, 231 MachineBasicBlock::iterator EndItr) { 232 assert(VLIWScheduler && "VLIW Scheduler is not initialized!"); 233 VLIWScheduler->startBlock(MBB); 234 VLIWScheduler->enterRegion(MBB, BeginItr, EndItr, 235 std::distance(BeginItr, EndItr)); 236 VLIWScheduler->schedule(); 237 238 // Generate MI -> SU map. 239 MIToSUnit.clear(); 240 for (SUnit &SU : VLIWScheduler->SUnits) 241 MIToSUnit[SU.getInstr()] = &SU; 242 243 // The main packetizer loop. 244 for (; BeginItr != EndItr; ++BeginItr) { 245 MachineInstr &MI = *BeginItr; 246 initPacketizerState(); 247 248 // End the current packet if needed. 249 if (isSoloInstruction(MI)) { 250 endPacket(MBB, MI); 251 continue; 252 } 253 254 // Ignore pseudo instructions. 255 if (ignorePseudoInstruction(MI, MBB)) 256 continue; 257 258 SUnit *SUI = MIToSUnit[&MI]; 259 assert(SUI && "Missing SUnit Info!"); 260 261 // Ask DFA if machine resource is available for MI. 262 bool ResourceAvail = ResourceTracker->canReserveResources(MI); 263 if (ResourceAvail && shouldAddToPacket(MI)) { 264 // Dependency check for MI with instructions in CurrentPacketMIs. 265 for (auto MJ : CurrentPacketMIs) { 266 SUnit *SUJ = MIToSUnit[MJ]; 267 assert(SUJ && "Missing SUnit Info!"); 268 269 // Is it legal to packetize SUI and SUJ together. 270 if (!isLegalToPacketizeTogether(SUI, SUJ)) { 271 // Allow packetization if dependency can be pruned. 272 if (!isLegalToPruneDependencies(SUI, SUJ)) { 273 // End the packet if dependency cannot be pruned. 274 endPacket(MBB, MI); 275 break; 276 } 277 } 278 } 279 } else { 280 // End the packet if resource is not available, or if the instruction 281 // shoud not be added to the current packet. 282 endPacket(MBB, MI); 283 } 284 285 // Add MI to the current packet. 286 BeginItr = addToPacket(MI); 287 } // For all instructions in the packetization range. 288 289 // End any packet left behind. 290 endPacket(MBB, EndItr); 291 VLIWScheduler->exitRegion(); 292 VLIWScheduler->finishBlock(); 293 } 294 295 296 // Add a DAG mutation object to the ordered list. 297 void VLIWPacketizerList::addMutation( 298 std::unique_ptr<ScheduleDAGMutation> Mutation) { 299 VLIWScheduler->addMutation(std::move(Mutation)); 300 } 301