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