1d88c1a5aSDimitry Andric //===-- SIMachineScheduler.cpp - SI Scheduler Interface -------------------===// 2444ed5c5SDimitry Andric // 3444ed5c5SDimitry Andric // The LLVM Compiler Infrastructure 4444ed5c5SDimitry Andric // 5444ed5c5SDimitry Andric // This file is distributed under the University of Illinois Open Source 6444ed5c5SDimitry Andric // License. See LICENSE.TXT for details. 7444ed5c5SDimitry Andric // 8444ed5c5SDimitry Andric //===----------------------------------------------------------------------===// 9444ed5c5SDimitry Andric // 10444ed5c5SDimitry Andric /// \file 11444ed5c5SDimitry Andric /// \brief SI Machine Scheduler interface 12444ed5c5SDimitry Andric // 13444ed5c5SDimitry Andric //===----------------------------------------------------------------------===// 14444ed5c5SDimitry Andric 15db17bf38SDimitry Andric #include "SIMachineScheduler.h" 163ca95b02SDimitry Andric #include "AMDGPU.h" 17d88c1a5aSDimitry Andric #include "SIInstrInfo.h" 18d88c1a5aSDimitry Andric #include "SIRegisterInfo.h" 19d88c1a5aSDimitry Andric #include "llvm/ADT/STLExtras.h" 20d88c1a5aSDimitry Andric #include "llvm/ADT/SmallVector.h" 21444ed5c5SDimitry Andric #include "llvm/CodeGen/LiveInterval.h" 22444ed5c5SDimitry Andric #include "llvm/CodeGen/LiveIntervalAnalysis.h" 23d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 24444ed5c5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 25444ed5c5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 26444ed5c5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h" 27d88c1a5aSDimitry Andric #include "llvm/CodeGen/SlotIndexes.h" 28d88c1a5aSDimitry Andric #include "llvm/Support/Debug.h" 29d88c1a5aSDimitry Andric #include "llvm/Support/ErrorHandling.h" 30d88c1a5aSDimitry Andric #include "llvm/Support/raw_ostream.h" 31d88c1a5aSDimitry Andric #include "llvm/Target/TargetRegisterInfo.h" 32d88c1a5aSDimitry Andric #include <algorithm> 33d88c1a5aSDimitry Andric #include <cassert> 34d88c1a5aSDimitry Andric #include <map> 35d88c1a5aSDimitry Andric #include <set> 36d88c1a5aSDimitry Andric #include <utility> 37d88c1a5aSDimitry Andric #include <vector> 38444ed5c5SDimitry Andric 39444ed5c5SDimitry Andric using namespace llvm; 40444ed5c5SDimitry Andric 41444ed5c5SDimitry Andric #define DEBUG_TYPE "misched" 42444ed5c5SDimitry Andric 43444ed5c5SDimitry Andric // This scheduler implements a different scheduling algorithm than 44444ed5c5SDimitry Andric // GenericScheduler. 45444ed5c5SDimitry Andric // 46444ed5c5SDimitry Andric // There are several specific architecture behaviours that can't be modelled 47444ed5c5SDimitry Andric // for GenericScheduler: 48444ed5c5SDimitry Andric // . When accessing the result of an SGPR load instruction, you have to wait 49444ed5c5SDimitry Andric // for all the SGPR load instructions before your current instruction to 50444ed5c5SDimitry Andric // have finished. 51444ed5c5SDimitry Andric // . When accessing the result of an VGPR load instruction, you have to wait 52444ed5c5SDimitry Andric // for all the VGPR load instructions previous to the VGPR load instruction 53444ed5c5SDimitry Andric // you are interested in to finish. 54444ed5c5SDimitry Andric // . The less the register pressure, the best load latencies are hidden 55444ed5c5SDimitry Andric // 56444ed5c5SDimitry Andric // Moreover some specifities (like the fact a lot of instructions in the shader 57444ed5c5SDimitry Andric // have few dependencies) makes the generic scheduler have some unpredictable 58444ed5c5SDimitry Andric // behaviours. For example when register pressure becomes high, it can either 59444ed5c5SDimitry Andric // manage to prevent register pressure from going too high, or it can 60444ed5c5SDimitry Andric // increase register pressure even more than if it hadn't taken register 61444ed5c5SDimitry Andric // pressure into account. 62444ed5c5SDimitry Andric // 63444ed5c5SDimitry Andric // Also some other bad behaviours are generated, like loading at the beginning 64444ed5c5SDimitry Andric // of the shader a constant in VGPR you won't need until the end of the shader. 65444ed5c5SDimitry Andric // 66444ed5c5SDimitry Andric // The scheduling problem for SI can distinguish three main parts: 67444ed5c5SDimitry Andric // . Hiding high latencies (texture sampling, etc) 68444ed5c5SDimitry Andric // . Hiding low latencies (SGPR constant loading, etc) 69444ed5c5SDimitry Andric // . Keeping register usage low for better latency hiding and general 70444ed5c5SDimitry Andric // performance 71444ed5c5SDimitry Andric // 72444ed5c5SDimitry Andric // Some other things can also affect performance, but are hard to predict 73444ed5c5SDimitry Andric // (cache usage, the fact the HW can issue several instructions from different 74444ed5c5SDimitry Andric // wavefronts if different types, etc) 75444ed5c5SDimitry Andric // 76444ed5c5SDimitry Andric // This scheduler tries to solve the scheduling problem by dividing it into 77444ed5c5SDimitry Andric // simpler sub-problems. It divides the instructions into blocks, schedules 78444ed5c5SDimitry Andric // locally inside the blocks where it takes care of low latencies, and then 79444ed5c5SDimitry Andric // chooses the order of the blocks by taking care of high latencies. 80444ed5c5SDimitry Andric // Dividing the instructions into blocks helps control keeping register 81444ed5c5SDimitry Andric // usage low. 82444ed5c5SDimitry Andric // 83444ed5c5SDimitry Andric // First the instructions are put into blocks. 84444ed5c5SDimitry Andric // We want the blocks help control register usage and hide high latencies 85444ed5c5SDimitry Andric // later. To help control register usage, we typically want all local 86444ed5c5SDimitry Andric // computations, when for example you create a result that can be comsummed 87444ed5c5SDimitry Andric // right away, to be contained in a block. Block inputs and outputs would 88444ed5c5SDimitry Andric // typically be important results that are needed in several locations of 89444ed5c5SDimitry Andric // the shader. Since we do want blocks to help hide high latencies, we want 90444ed5c5SDimitry Andric // the instructions inside the block to have a minimal set of dependencies 91444ed5c5SDimitry Andric // on high latencies. It will make it easy to pick blocks to hide specific 92444ed5c5SDimitry Andric // high latencies. 93444ed5c5SDimitry Andric // The block creation algorithm is divided into several steps, and several 94444ed5c5SDimitry Andric // variants can be tried during the scheduling process. 95444ed5c5SDimitry Andric // 96d88c1a5aSDimitry Andric // Second the order of the instructions inside the blocks is chosen. 97444ed5c5SDimitry Andric // At that step we do take into account only register usage and hiding 98444ed5c5SDimitry Andric // low latency instructions 99444ed5c5SDimitry Andric // 100d88c1a5aSDimitry Andric // Third the block order is chosen, there we try to hide high latencies 101444ed5c5SDimitry Andric // and keep register usage low. 102444ed5c5SDimitry Andric // 103444ed5c5SDimitry Andric // After the third step, a pass is done to improve the hiding of low 104444ed5c5SDimitry Andric // latencies. 105444ed5c5SDimitry Andric // 106444ed5c5SDimitry Andric // Actually when talking about 'low latency' or 'high latency' it includes 107444ed5c5SDimitry Andric // both the latency to get the cache (or global mem) data go to the register, 108d88c1a5aSDimitry Andric // and the bandwidth limitations. 109444ed5c5SDimitry Andric // Increasing the number of active wavefronts helps hide the former, but it 110444ed5c5SDimitry Andric // doesn't solve the latter, thus why even if wavefront count is high, we have 111444ed5c5SDimitry Andric // to try have as many instructions hiding high latencies as possible. 112444ed5c5SDimitry Andric // The OpenCL doc says for example latency of 400 cycles for a global mem access, 113444ed5c5SDimitry Andric // which is hidden by 10 instructions if the wavefront count is 10. 114444ed5c5SDimitry Andric 115444ed5c5SDimitry Andric // Some figures taken from AMD docs: 116444ed5c5SDimitry Andric // Both texture and constant L1 caches are 4-way associative with 64 bytes 117444ed5c5SDimitry Andric // lines. 118444ed5c5SDimitry Andric // Constant cache is shared with 4 CUs. 119444ed5c5SDimitry Andric // For texture sampling, the address generation unit receives 4 texture 120444ed5c5SDimitry Andric // addresses per cycle, thus we could expect texture sampling latency to be 121444ed5c5SDimitry Andric // equivalent to 4 instructions in the very best case (a VGPR is 64 work items, 122444ed5c5SDimitry Andric // instructions in a wavefront group are executed every 4 cycles), 123444ed5c5SDimitry Andric // or 16 instructions if the other wavefronts associated to the 3 other VALUs 124444ed5c5SDimitry Andric // of the CU do texture sampling too. (Don't take these figures too seriously, 125444ed5c5SDimitry Andric // as I'm not 100% sure of the computation) 126444ed5c5SDimitry Andric // Data exports should get similar latency. 127444ed5c5SDimitry Andric // For constant loading, the cache is shader with 4 CUs. 128444ed5c5SDimitry Andric // The doc says "a throughput of 16B/cycle for each of the 4 Compute Unit" 129444ed5c5SDimitry Andric // I guess if the other CU don't read the cache, it can go up to 64B/cycle. 130444ed5c5SDimitry Andric // It means a simple s_buffer_load should take one instruction to hide, as 131444ed5c5SDimitry Andric // well as a s_buffer_loadx2 and potentially a s_buffer_loadx8 if on the same 132444ed5c5SDimitry Andric // cache line. 133444ed5c5SDimitry Andric // 134444ed5c5SDimitry Andric // As of today the driver doesn't preload the constants in cache, thus the 135444ed5c5SDimitry Andric // first loads get extra latency. The doc says global memory access can be 136444ed5c5SDimitry Andric // 300-600 cycles. We do not specially take that into account when scheduling 137444ed5c5SDimitry Andric // As we expect the driver to be able to preload the constants soon. 138444ed5c5SDimitry Andric 139444ed5c5SDimitry Andric // common code // 140444ed5c5SDimitry Andric 141444ed5c5SDimitry Andric #ifndef NDEBUG 142444ed5c5SDimitry Andric 143444ed5c5SDimitry Andric static const char *getReasonStr(SIScheduleCandReason Reason) { 144444ed5c5SDimitry Andric switch (Reason) { 145444ed5c5SDimitry Andric case NoCand: return "NOCAND"; 146444ed5c5SDimitry Andric case RegUsage: return "REGUSAGE"; 147444ed5c5SDimitry Andric case Latency: return "LATENCY"; 148444ed5c5SDimitry Andric case Successor: return "SUCCESSOR"; 149444ed5c5SDimitry Andric case Depth: return "DEPTH"; 150444ed5c5SDimitry Andric case NodeOrder: return "ORDER"; 151444ed5c5SDimitry Andric } 152444ed5c5SDimitry Andric llvm_unreachable("Unknown reason!"); 153444ed5c5SDimitry Andric } 154444ed5c5SDimitry Andric 155444ed5c5SDimitry Andric #endif 156444ed5c5SDimitry Andric 157444ed5c5SDimitry Andric static bool tryLess(int TryVal, int CandVal, 158444ed5c5SDimitry Andric SISchedulerCandidate &TryCand, 159444ed5c5SDimitry Andric SISchedulerCandidate &Cand, 160444ed5c5SDimitry Andric SIScheduleCandReason Reason) { 161444ed5c5SDimitry Andric if (TryVal < CandVal) { 162444ed5c5SDimitry Andric TryCand.Reason = Reason; 163444ed5c5SDimitry Andric return true; 164444ed5c5SDimitry Andric } 165444ed5c5SDimitry Andric if (TryVal > CandVal) { 166444ed5c5SDimitry Andric if (Cand.Reason > Reason) 167444ed5c5SDimitry Andric Cand.Reason = Reason; 168444ed5c5SDimitry Andric return true; 169444ed5c5SDimitry Andric } 170444ed5c5SDimitry Andric Cand.setRepeat(Reason); 171444ed5c5SDimitry Andric return false; 172444ed5c5SDimitry Andric } 173444ed5c5SDimitry Andric 174444ed5c5SDimitry Andric static bool tryGreater(int TryVal, int CandVal, 175444ed5c5SDimitry Andric SISchedulerCandidate &TryCand, 176444ed5c5SDimitry Andric SISchedulerCandidate &Cand, 177444ed5c5SDimitry Andric SIScheduleCandReason Reason) { 178444ed5c5SDimitry Andric if (TryVal > CandVal) { 179444ed5c5SDimitry Andric TryCand.Reason = Reason; 180444ed5c5SDimitry Andric return true; 181444ed5c5SDimitry Andric } 182444ed5c5SDimitry Andric if (TryVal < CandVal) { 183444ed5c5SDimitry Andric if (Cand.Reason > Reason) 184444ed5c5SDimitry Andric Cand.Reason = Reason; 185444ed5c5SDimitry Andric return true; 186444ed5c5SDimitry Andric } 187444ed5c5SDimitry Andric Cand.setRepeat(Reason); 188444ed5c5SDimitry Andric return false; 189444ed5c5SDimitry Andric } 190444ed5c5SDimitry Andric 191444ed5c5SDimitry Andric // SIScheduleBlock // 192444ed5c5SDimitry Andric 193444ed5c5SDimitry Andric void SIScheduleBlock::addUnit(SUnit *SU) { 194444ed5c5SDimitry Andric NodeNum2Index[SU->NodeNum] = SUnits.size(); 195444ed5c5SDimitry Andric SUnits.push_back(SU); 196444ed5c5SDimitry Andric } 197444ed5c5SDimitry Andric 198444ed5c5SDimitry Andric #ifndef NDEBUG 199444ed5c5SDimitry Andric void SIScheduleBlock::traceCandidate(const SISchedCandidate &Cand) { 200444ed5c5SDimitry Andric 201444ed5c5SDimitry Andric dbgs() << " SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason); 202444ed5c5SDimitry Andric dbgs() << '\n'; 203444ed5c5SDimitry Andric } 204444ed5c5SDimitry Andric #endif 205444ed5c5SDimitry Andric 206444ed5c5SDimitry Andric void SIScheduleBlock::tryCandidateTopDown(SISchedCandidate &Cand, 207444ed5c5SDimitry Andric SISchedCandidate &TryCand) { 208444ed5c5SDimitry Andric // Initialize the candidate if needed. 209444ed5c5SDimitry Andric if (!Cand.isValid()) { 210444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 211444ed5c5SDimitry Andric return; 212444ed5c5SDimitry Andric } 213444ed5c5SDimitry Andric 214444ed5c5SDimitry Andric if (Cand.SGPRUsage > 60 && 215444ed5c5SDimitry Andric tryLess(TryCand.SGPRUsage, Cand.SGPRUsage, TryCand, Cand, RegUsage)) 216444ed5c5SDimitry Andric return; 217444ed5c5SDimitry Andric 218444ed5c5SDimitry Andric // Schedule low latency instructions as top as possible. 219444ed5c5SDimitry Andric // Order of priority is: 220444ed5c5SDimitry Andric // . Low latency instructions which do not depend on other low latency 221444ed5c5SDimitry Andric // instructions we haven't waited for 222444ed5c5SDimitry Andric // . Other instructions which do not depend on low latency instructions 223444ed5c5SDimitry Andric // we haven't waited for 224444ed5c5SDimitry Andric // . Low latencies 225444ed5c5SDimitry Andric // . All other instructions 226d88c1a5aSDimitry Andric // Goal is to get: low latency instructions - independent instructions 227444ed5c5SDimitry Andric // - (eventually some more low latency instructions) 228444ed5c5SDimitry Andric // - instructions that depend on the first low latency instructions. 229444ed5c5SDimitry Andric // If in the block there is a lot of constant loads, the SGPR usage 230444ed5c5SDimitry Andric // could go quite high, thus above the arbitrary limit of 60 will encourage 231444ed5c5SDimitry Andric // use the already loaded constants (in order to release some SGPRs) before 232444ed5c5SDimitry Andric // loading more. 233444ed5c5SDimitry Andric if (tryLess(TryCand.HasLowLatencyNonWaitedParent, 234444ed5c5SDimitry Andric Cand.HasLowLatencyNonWaitedParent, 235444ed5c5SDimitry Andric TryCand, Cand, SIScheduleCandReason::Depth)) 236444ed5c5SDimitry Andric return; 237444ed5c5SDimitry Andric 238444ed5c5SDimitry Andric if (tryGreater(TryCand.IsLowLatency, Cand.IsLowLatency, 239444ed5c5SDimitry Andric TryCand, Cand, SIScheduleCandReason::Depth)) 240444ed5c5SDimitry Andric return; 241444ed5c5SDimitry Andric 242444ed5c5SDimitry Andric if (TryCand.IsLowLatency && 243444ed5c5SDimitry Andric tryLess(TryCand.LowLatencyOffset, Cand.LowLatencyOffset, 244444ed5c5SDimitry Andric TryCand, Cand, SIScheduleCandReason::Depth)) 245444ed5c5SDimitry Andric return; 246444ed5c5SDimitry Andric 247444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsage, Cand.VGPRUsage, TryCand, Cand, RegUsage)) 248444ed5c5SDimitry Andric return; 249444ed5c5SDimitry Andric 250444ed5c5SDimitry Andric // Fall through to original instruction order. 251444ed5c5SDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum) { 252444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 253444ed5c5SDimitry Andric } 254444ed5c5SDimitry Andric } 255444ed5c5SDimitry Andric 256444ed5c5SDimitry Andric SUnit* SIScheduleBlock::pickNode() { 257444ed5c5SDimitry Andric SISchedCandidate TopCand; 258444ed5c5SDimitry Andric 259444ed5c5SDimitry Andric for (SUnit* SU : TopReadySUs) { 260444ed5c5SDimitry Andric SISchedCandidate TryCand; 261444ed5c5SDimitry Andric std::vector<unsigned> pressure; 262444ed5c5SDimitry Andric std::vector<unsigned> MaxPressure; 263444ed5c5SDimitry Andric // Predict register usage after this instruction. 264444ed5c5SDimitry Andric TryCand.SU = SU; 265444ed5c5SDimitry Andric TopRPTracker.getDownwardPressure(SU->getInstr(), pressure, MaxPressure); 266444ed5c5SDimitry Andric TryCand.SGPRUsage = pressure[DAG->getSGPRSetID()]; 267444ed5c5SDimitry Andric TryCand.VGPRUsage = pressure[DAG->getVGPRSetID()]; 268444ed5c5SDimitry Andric TryCand.IsLowLatency = DAG->IsLowLatencySU[SU->NodeNum]; 269444ed5c5SDimitry Andric TryCand.LowLatencyOffset = DAG->LowLatencyOffset[SU->NodeNum]; 270444ed5c5SDimitry Andric TryCand.HasLowLatencyNonWaitedParent = 271444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]]; 272444ed5c5SDimitry Andric tryCandidateTopDown(TopCand, TryCand); 273444ed5c5SDimitry Andric if (TryCand.Reason != NoCand) 274444ed5c5SDimitry Andric TopCand.setBest(TryCand); 275444ed5c5SDimitry Andric } 276444ed5c5SDimitry Andric 277444ed5c5SDimitry Andric return TopCand.SU; 278444ed5c5SDimitry Andric } 279444ed5c5SDimitry Andric 280444ed5c5SDimitry Andric 281444ed5c5SDimitry Andric // Schedule something valid. 282444ed5c5SDimitry Andric void SIScheduleBlock::fastSchedule() { 283444ed5c5SDimitry Andric TopReadySUs.clear(); 284444ed5c5SDimitry Andric if (Scheduled) 285444ed5c5SDimitry Andric undoSchedule(); 286444ed5c5SDimitry Andric 287444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 288444ed5c5SDimitry Andric if (!SU->NumPredsLeft) 289444ed5c5SDimitry Andric TopReadySUs.push_back(SU); 290444ed5c5SDimitry Andric } 291444ed5c5SDimitry Andric 292444ed5c5SDimitry Andric while (!TopReadySUs.empty()) { 293444ed5c5SDimitry Andric SUnit *SU = TopReadySUs[0]; 294444ed5c5SDimitry Andric ScheduledSUnits.push_back(SU); 295444ed5c5SDimitry Andric nodeScheduled(SU); 296444ed5c5SDimitry Andric } 297444ed5c5SDimitry Andric 298444ed5c5SDimitry Andric Scheduled = true; 299444ed5c5SDimitry Andric } 300444ed5c5SDimitry Andric 301444ed5c5SDimitry Andric // Returns if the register was set between first and last. 302444ed5c5SDimitry Andric static bool isDefBetween(unsigned Reg, 303444ed5c5SDimitry Andric SlotIndex First, SlotIndex Last, 304444ed5c5SDimitry Andric const MachineRegisterInfo *MRI, 305444ed5c5SDimitry Andric const LiveIntervals *LIS) { 306444ed5c5SDimitry Andric for (MachineRegisterInfo::def_instr_iterator 307444ed5c5SDimitry Andric UI = MRI->def_instr_begin(Reg), 308444ed5c5SDimitry Andric UE = MRI->def_instr_end(); UI != UE; ++UI) { 309444ed5c5SDimitry Andric const MachineInstr* MI = &*UI; 310444ed5c5SDimitry Andric if (MI->isDebugValue()) 311444ed5c5SDimitry Andric continue; 3123ca95b02SDimitry Andric SlotIndex InstSlot = LIS->getInstructionIndex(*MI).getRegSlot(); 313444ed5c5SDimitry Andric if (InstSlot >= First && InstSlot <= Last) 314444ed5c5SDimitry Andric return true; 315444ed5c5SDimitry Andric } 316444ed5c5SDimitry Andric return false; 317444ed5c5SDimitry Andric } 318444ed5c5SDimitry Andric 319444ed5c5SDimitry Andric void SIScheduleBlock::initRegPressure(MachineBasicBlock::iterator BeginBlock, 320444ed5c5SDimitry Andric MachineBasicBlock::iterator EndBlock) { 321444ed5c5SDimitry Andric IntervalPressure Pressure, BotPressure; 322444ed5c5SDimitry Andric RegPressureTracker RPTracker(Pressure), BotRPTracker(BotPressure); 323444ed5c5SDimitry Andric LiveIntervals *LIS = DAG->getLIS(); 324444ed5c5SDimitry Andric MachineRegisterInfo *MRI = DAG->getMRI(); 325444ed5c5SDimitry Andric DAG->initRPTracker(TopRPTracker); 326444ed5c5SDimitry Andric DAG->initRPTracker(BotRPTracker); 327444ed5c5SDimitry Andric DAG->initRPTracker(RPTracker); 328444ed5c5SDimitry Andric 329444ed5c5SDimitry Andric // Goes though all SU. RPTracker captures what had to be alive for the SUs 330444ed5c5SDimitry Andric // to execute, and what is still alive at the end. 331444ed5c5SDimitry Andric for (SUnit* SU : ScheduledSUnits) { 332444ed5c5SDimitry Andric RPTracker.setPos(SU->getInstr()); 333444ed5c5SDimitry Andric RPTracker.advance(); 334444ed5c5SDimitry Andric } 335444ed5c5SDimitry Andric 336444ed5c5SDimitry Andric // Close the RPTracker to finalize live ins/outs. 337444ed5c5SDimitry Andric RPTracker.closeRegion(); 338444ed5c5SDimitry Andric 339444ed5c5SDimitry Andric // Initialize the live ins and live outs. 340444ed5c5SDimitry Andric TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs); 341444ed5c5SDimitry Andric BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs); 342444ed5c5SDimitry Andric 343444ed5c5SDimitry Andric // Do not Track Physical Registers, because it messes up. 3443ca95b02SDimitry Andric for (const auto &RegMaskPair : RPTracker.getPressure().LiveInRegs) { 3453ca95b02SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(RegMaskPair.RegUnit)) 3463ca95b02SDimitry Andric LiveInRegs.insert(RegMaskPair.RegUnit); 347444ed5c5SDimitry Andric } 348444ed5c5SDimitry Andric LiveOutRegs.clear(); 349444ed5c5SDimitry Andric // There is several possibilities to distinguish: 350444ed5c5SDimitry Andric // 1) Reg is not input to any instruction in the block, but is output of one 351444ed5c5SDimitry Andric // 2) 1) + read in the block and not needed after it 352444ed5c5SDimitry Andric // 3) 1) + read in the block but needed in another block 353444ed5c5SDimitry Andric // 4) Reg is input of an instruction but another block will read it too 354444ed5c5SDimitry Andric // 5) Reg is input of an instruction and then rewritten in the block. 355444ed5c5SDimitry Andric // result is not read in the block (implies used in another block) 356444ed5c5SDimitry Andric // 6) Reg is input of an instruction and then rewritten in the block. 357444ed5c5SDimitry Andric // result is read in the block and not needed in another block 358444ed5c5SDimitry Andric // 7) Reg is input of an instruction and then rewritten in the block. 359444ed5c5SDimitry Andric // result is read in the block but also needed in another block 360444ed5c5SDimitry Andric // LiveInRegs will contains all the regs in situation 4, 5, 6, 7 361444ed5c5SDimitry Andric // We want LiveOutRegs to contain only Regs whose content will be read after 362444ed5c5SDimitry Andric // in another block, and whose content was written in the current block, 363444ed5c5SDimitry Andric // that is we want it to get 1, 3, 5, 7 364444ed5c5SDimitry Andric // Since we made the MIs of a block to be packed all together before 365444ed5c5SDimitry Andric // scheduling, then the LiveIntervals were correct, and the RPTracker was 366444ed5c5SDimitry Andric // able to correctly handle 5 vs 6, 2 vs 3. 367444ed5c5SDimitry Andric // (Note: This is not sufficient for RPTracker to not do mistakes for case 4) 368444ed5c5SDimitry Andric // The RPTracker's LiveOutRegs has 1, 3, (some correct or incorrect)4, 5, 7 369444ed5c5SDimitry Andric // Comparing to LiveInRegs is not sufficient to differenciate 4 vs 5, 7 370444ed5c5SDimitry Andric // The use of findDefBetween removes the case 4. 3713ca95b02SDimitry Andric for (const auto &RegMaskPair : RPTracker.getPressure().LiveOutRegs) { 3723ca95b02SDimitry Andric unsigned Reg = RegMaskPair.RegUnit; 373444ed5c5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg) && 3743ca95b02SDimitry Andric isDefBetween(Reg, LIS->getInstructionIndex(*BeginBlock).getRegSlot(), 3753ca95b02SDimitry Andric LIS->getInstructionIndex(*EndBlock).getRegSlot(), MRI, 3763ca95b02SDimitry Andric LIS)) { 377444ed5c5SDimitry Andric LiveOutRegs.insert(Reg); 378444ed5c5SDimitry Andric } 379444ed5c5SDimitry Andric } 380444ed5c5SDimitry Andric 381444ed5c5SDimitry Andric // Pressure = sum_alive_registers register size 382444ed5c5SDimitry Andric // Internally llvm will represent some registers as big 128 bits registers 383444ed5c5SDimitry Andric // for example, but they actually correspond to 4 actual 32 bits registers. 384444ed5c5SDimitry Andric // Thus Pressure is not equal to num_alive_registers * constant. 385444ed5c5SDimitry Andric LiveInPressure = TopPressure.MaxSetPressure; 386444ed5c5SDimitry Andric LiveOutPressure = BotPressure.MaxSetPressure; 387444ed5c5SDimitry Andric 388444ed5c5SDimitry Andric // Prepares TopRPTracker for top down scheduling. 389444ed5c5SDimitry Andric TopRPTracker.closeTop(); 390444ed5c5SDimitry Andric } 391444ed5c5SDimitry Andric 392444ed5c5SDimitry Andric void SIScheduleBlock::schedule(MachineBasicBlock::iterator BeginBlock, 393444ed5c5SDimitry Andric MachineBasicBlock::iterator EndBlock) { 394444ed5c5SDimitry Andric if (!Scheduled) 395444ed5c5SDimitry Andric fastSchedule(); 396444ed5c5SDimitry Andric 397444ed5c5SDimitry Andric // PreScheduling phase to set LiveIn and LiveOut. 398444ed5c5SDimitry Andric initRegPressure(BeginBlock, EndBlock); 399444ed5c5SDimitry Andric undoSchedule(); 400444ed5c5SDimitry Andric 401444ed5c5SDimitry Andric // Schedule for real now. 402444ed5c5SDimitry Andric 403444ed5c5SDimitry Andric TopReadySUs.clear(); 404444ed5c5SDimitry Andric 405444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 406444ed5c5SDimitry Andric if (!SU->NumPredsLeft) 407444ed5c5SDimitry Andric TopReadySUs.push_back(SU); 408444ed5c5SDimitry Andric } 409444ed5c5SDimitry Andric 410444ed5c5SDimitry Andric while (!TopReadySUs.empty()) { 411444ed5c5SDimitry Andric SUnit *SU = pickNode(); 412444ed5c5SDimitry Andric ScheduledSUnits.push_back(SU); 413444ed5c5SDimitry Andric TopRPTracker.setPos(SU->getInstr()); 414444ed5c5SDimitry Andric TopRPTracker.advance(); 415444ed5c5SDimitry Andric nodeScheduled(SU); 416444ed5c5SDimitry Andric } 417444ed5c5SDimitry Andric 418444ed5c5SDimitry Andric // TODO: compute InternalAdditionnalPressure. 419444ed5c5SDimitry Andric InternalAdditionnalPressure.resize(TopPressure.MaxSetPressure.size()); 420444ed5c5SDimitry Andric 421444ed5c5SDimitry Andric // Check everything is right. 422444ed5c5SDimitry Andric #ifndef NDEBUG 423444ed5c5SDimitry Andric assert(SUnits.size() == ScheduledSUnits.size() && 424444ed5c5SDimitry Andric TopReadySUs.empty()); 425444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 426444ed5c5SDimitry Andric assert(SU->isScheduled && 427444ed5c5SDimitry Andric SU->NumPredsLeft == 0); 428444ed5c5SDimitry Andric } 429444ed5c5SDimitry Andric #endif 430444ed5c5SDimitry Andric 431444ed5c5SDimitry Andric Scheduled = true; 432444ed5c5SDimitry Andric } 433444ed5c5SDimitry Andric 434444ed5c5SDimitry Andric void SIScheduleBlock::undoSchedule() { 435444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 436444ed5c5SDimitry Andric SU->isScheduled = false; 437444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 438444ed5c5SDimitry Andric if (BC->isSUInBlock(Succ.getSUnit(), ID)) 439444ed5c5SDimitry Andric undoReleaseSucc(SU, &Succ); 440444ed5c5SDimitry Andric } 441444ed5c5SDimitry Andric } 442444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0); 443444ed5c5SDimitry Andric ScheduledSUnits.clear(); 444444ed5c5SDimitry Andric Scheduled = false; 445444ed5c5SDimitry Andric } 446444ed5c5SDimitry Andric 447444ed5c5SDimitry Andric void SIScheduleBlock::undoReleaseSucc(SUnit *SU, SDep *SuccEdge) { 448444ed5c5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 449444ed5c5SDimitry Andric 450444ed5c5SDimitry Andric if (SuccEdge->isWeak()) { 451444ed5c5SDimitry Andric ++SuccSU->WeakPredsLeft; 452444ed5c5SDimitry Andric return; 453444ed5c5SDimitry Andric } 454444ed5c5SDimitry Andric ++SuccSU->NumPredsLeft; 455444ed5c5SDimitry Andric } 456444ed5c5SDimitry Andric 457444ed5c5SDimitry Andric void SIScheduleBlock::releaseSucc(SUnit *SU, SDep *SuccEdge) { 458444ed5c5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 459444ed5c5SDimitry Andric 460444ed5c5SDimitry Andric if (SuccEdge->isWeak()) { 461444ed5c5SDimitry Andric --SuccSU->WeakPredsLeft; 462444ed5c5SDimitry Andric return; 463444ed5c5SDimitry Andric } 464444ed5c5SDimitry Andric #ifndef NDEBUG 465444ed5c5SDimitry Andric if (SuccSU->NumPredsLeft == 0) { 466444ed5c5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n"; 467444ed5c5SDimitry Andric SuccSU->dump(DAG); 468444ed5c5SDimitry Andric dbgs() << " has been released too many times!\n"; 469444ed5c5SDimitry Andric llvm_unreachable(nullptr); 470444ed5c5SDimitry Andric } 471444ed5c5SDimitry Andric #endif 472444ed5c5SDimitry Andric 473444ed5c5SDimitry Andric --SuccSU->NumPredsLeft; 474444ed5c5SDimitry Andric } 475444ed5c5SDimitry Andric 476444ed5c5SDimitry Andric /// Release Successors of the SU that are in the block or not. 477444ed5c5SDimitry Andric void SIScheduleBlock::releaseSuccessors(SUnit *SU, bool InOrOutBlock) { 478444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 479444ed5c5SDimitry Andric SUnit *SuccSU = Succ.getSUnit(); 480444ed5c5SDimitry Andric 4813ca95b02SDimitry Andric if (SuccSU->NodeNum >= DAG->SUnits.size()) 4823ca95b02SDimitry Andric continue; 4833ca95b02SDimitry Andric 484444ed5c5SDimitry Andric if (BC->isSUInBlock(SuccSU, ID) != InOrOutBlock) 485444ed5c5SDimitry Andric continue; 486444ed5c5SDimitry Andric 487444ed5c5SDimitry Andric releaseSucc(SU, &Succ); 488444ed5c5SDimitry Andric if (SuccSU->NumPredsLeft == 0 && InOrOutBlock) 489444ed5c5SDimitry Andric TopReadySUs.push_back(SuccSU); 490444ed5c5SDimitry Andric } 491444ed5c5SDimitry Andric } 492444ed5c5SDimitry Andric 493444ed5c5SDimitry Andric void SIScheduleBlock::nodeScheduled(SUnit *SU) { 494444ed5c5SDimitry Andric // Is in TopReadySUs 495444ed5c5SDimitry Andric assert (!SU->NumPredsLeft); 496d88c1a5aSDimitry Andric std::vector<SUnit *>::iterator I = llvm::find(TopReadySUs, SU); 497444ed5c5SDimitry Andric if (I == TopReadySUs.end()) { 498444ed5c5SDimitry Andric dbgs() << "Data Structure Bug in SI Scheduler\n"; 499444ed5c5SDimitry Andric llvm_unreachable(nullptr); 500444ed5c5SDimitry Andric } 501444ed5c5SDimitry Andric TopReadySUs.erase(I); 502444ed5c5SDimitry Andric 503444ed5c5SDimitry Andric releaseSuccessors(SU, true); 504444ed5c5SDimitry Andric // Scheduling this node will trigger a wait, 505444ed5c5SDimitry Andric // thus propagate to other instructions that they do not need to wait either. 506444ed5c5SDimitry Andric if (HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]]) 507444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0); 508444ed5c5SDimitry Andric 509444ed5c5SDimitry Andric if (DAG->IsLowLatencySU[SU->NodeNum]) { 510444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 511444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator I = 512444ed5c5SDimitry Andric NodeNum2Index.find(Succ.getSUnit()->NodeNum); 513444ed5c5SDimitry Andric if (I != NodeNum2Index.end()) 514444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent[I->second] = 1; 515444ed5c5SDimitry Andric } 516444ed5c5SDimitry Andric } 517444ed5c5SDimitry Andric SU->isScheduled = true; 518444ed5c5SDimitry Andric } 519444ed5c5SDimitry Andric 520444ed5c5SDimitry Andric void SIScheduleBlock::finalizeUnits() { 521444ed5c5SDimitry Andric // We remove links from outside blocks to enable scheduling inside the block. 522444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 523444ed5c5SDimitry Andric releaseSuccessors(SU, false); 524444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) 525444ed5c5SDimitry Andric HighLatencyBlock = true; 526444ed5c5SDimitry Andric } 527444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.resize(SUnits.size(), 0); 528444ed5c5SDimitry Andric } 529444ed5c5SDimitry Andric 530444ed5c5SDimitry Andric // we maintain ascending order of IDs 531444ed5c5SDimitry Andric void SIScheduleBlock::addPred(SIScheduleBlock *Pred) { 532444ed5c5SDimitry Andric unsigned PredID = Pred->getID(); 533444ed5c5SDimitry Andric 534444ed5c5SDimitry Andric // Check if not already predecessor. 535444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 536444ed5c5SDimitry Andric if (PredID == P->getID()) 537444ed5c5SDimitry Andric return; 538444ed5c5SDimitry Andric } 539444ed5c5SDimitry Andric Preds.push_back(Pred); 540444ed5c5SDimitry Andric 5413ca95b02SDimitry Andric assert(none_of(Succs, 5427a7e6055SDimitry Andric [=](std::pair<SIScheduleBlock*, 5437a7e6055SDimitry Andric SIScheduleBlockLinkKind> S) { 5447a7e6055SDimitry Andric return PredID == S.first->getID(); 5457a7e6055SDimitry Andric }) && 5463ca95b02SDimitry Andric "Loop in the Block Graph!"); 547444ed5c5SDimitry Andric } 548444ed5c5SDimitry Andric 5497a7e6055SDimitry Andric void SIScheduleBlock::addSucc(SIScheduleBlock *Succ, 5507a7e6055SDimitry Andric SIScheduleBlockLinkKind Kind) { 551444ed5c5SDimitry Andric unsigned SuccID = Succ->getID(); 552444ed5c5SDimitry Andric 553444ed5c5SDimitry Andric // Check if not already predecessor. 5547a7e6055SDimitry Andric for (std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind> &S : Succs) { 5557a7e6055SDimitry Andric if (SuccID == S.first->getID()) { 5567a7e6055SDimitry Andric if (S.second == SIScheduleBlockLinkKind::NoData && 5577a7e6055SDimitry Andric Kind == SIScheduleBlockLinkKind::Data) 5587a7e6055SDimitry Andric S.second = Kind; 559444ed5c5SDimitry Andric return; 560444ed5c5SDimitry Andric } 5617a7e6055SDimitry Andric } 562444ed5c5SDimitry Andric if (Succ->isHighLatencyBlock()) 563444ed5c5SDimitry Andric ++NumHighLatencySuccessors; 5647a7e6055SDimitry Andric Succs.push_back(std::make_pair(Succ, Kind)); 5657a7e6055SDimitry Andric 5663ca95b02SDimitry Andric assert(none_of(Preds, 5673ca95b02SDimitry Andric [=](SIScheduleBlock *P) { return SuccID == P->getID(); }) && 5683ca95b02SDimitry Andric "Loop in the Block Graph!"); 569444ed5c5SDimitry Andric } 570444ed5c5SDimitry Andric 571444ed5c5SDimitry Andric #ifndef NDEBUG 572444ed5c5SDimitry Andric void SIScheduleBlock::printDebug(bool full) { 573444ed5c5SDimitry Andric dbgs() << "Block (" << ID << ")\n"; 574444ed5c5SDimitry Andric if (!full) 575444ed5c5SDimitry Andric return; 576444ed5c5SDimitry Andric 577444ed5c5SDimitry Andric dbgs() << "\nContains High Latency Instruction: " 578444ed5c5SDimitry Andric << HighLatencyBlock << '\n'; 579444ed5c5SDimitry Andric dbgs() << "\nDepends On:\n"; 580444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 581444ed5c5SDimitry Andric P->printDebug(false); 582444ed5c5SDimitry Andric } 583444ed5c5SDimitry Andric 584444ed5c5SDimitry Andric dbgs() << "\nSuccessors:\n"; 5857a7e6055SDimitry Andric for (std::pair<SIScheduleBlock*, SIScheduleBlockLinkKind> S : Succs) { 5867a7e6055SDimitry Andric if (S.second == SIScheduleBlockLinkKind::Data) 5877a7e6055SDimitry Andric dbgs() << "(Data Dep) "; 5887a7e6055SDimitry Andric S.first->printDebug(false); 589444ed5c5SDimitry Andric } 590444ed5c5SDimitry Andric 591444ed5c5SDimitry Andric if (Scheduled) { 592444ed5c5SDimitry Andric dbgs() << "LiveInPressure " << LiveInPressure[DAG->getSGPRSetID()] << ' ' 593444ed5c5SDimitry Andric << LiveInPressure[DAG->getVGPRSetID()] << '\n'; 594444ed5c5SDimitry Andric dbgs() << "LiveOutPressure " << LiveOutPressure[DAG->getSGPRSetID()] << ' ' 595444ed5c5SDimitry Andric << LiveOutPressure[DAG->getVGPRSetID()] << "\n\n"; 596444ed5c5SDimitry Andric dbgs() << "LiveIns:\n"; 597444ed5c5SDimitry Andric for (unsigned Reg : LiveInRegs) 598444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 599444ed5c5SDimitry Andric 600444ed5c5SDimitry Andric dbgs() << "\nLiveOuts:\n"; 601444ed5c5SDimitry Andric for (unsigned Reg : LiveOutRegs) 602444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 603444ed5c5SDimitry Andric } 604444ed5c5SDimitry Andric 605444ed5c5SDimitry Andric dbgs() << "\nInstructions:\n"; 606444ed5c5SDimitry Andric if (!Scheduled) { 607444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 608444ed5c5SDimitry Andric SU->dump(DAG); 609444ed5c5SDimitry Andric } 610444ed5c5SDimitry Andric } else { 611444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 612444ed5c5SDimitry Andric SU->dump(DAG); 613444ed5c5SDimitry Andric } 614444ed5c5SDimitry Andric } 615444ed5c5SDimitry Andric 616444ed5c5SDimitry Andric dbgs() << "///////////////////////\n"; 617444ed5c5SDimitry Andric } 618444ed5c5SDimitry Andric #endif 619444ed5c5SDimitry Andric 620444ed5c5SDimitry Andric // SIScheduleBlockCreator // 621444ed5c5SDimitry Andric 622444ed5c5SDimitry Andric SIScheduleBlockCreator::SIScheduleBlockCreator(SIScheduleDAGMI *DAG) : 623444ed5c5SDimitry Andric DAG(DAG) { 624444ed5c5SDimitry Andric } 625444ed5c5SDimitry Andric 626d88c1a5aSDimitry Andric SIScheduleBlockCreator::~SIScheduleBlockCreator() = default; 627444ed5c5SDimitry Andric 628444ed5c5SDimitry Andric SIScheduleBlocks 629444ed5c5SDimitry Andric SIScheduleBlockCreator::getBlocks(SISchedulerBlockCreatorVariant BlockVariant) { 630444ed5c5SDimitry Andric std::map<SISchedulerBlockCreatorVariant, SIScheduleBlocks>::iterator B = 631444ed5c5SDimitry Andric Blocks.find(BlockVariant); 632444ed5c5SDimitry Andric if (B == Blocks.end()) { 633444ed5c5SDimitry Andric SIScheduleBlocks Res; 634444ed5c5SDimitry Andric createBlocksForVariant(BlockVariant); 635444ed5c5SDimitry Andric topologicalSort(); 636444ed5c5SDimitry Andric scheduleInsideBlocks(); 637444ed5c5SDimitry Andric fillStats(); 638444ed5c5SDimitry Andric Res.Blocks = CurrentBlocks; 639444ed5c5SDimitry Andric Res.TopDownIndex2Block = TopDownIndex2Block; 640444ed5c5SDimitry Andric Res.TopDownBlock2Index = TopDownBlock2Index; 641444ed5c5SDimitry Andric Blocks[BlockVariant] = Res; 642444ed5c5SDimitry Andric return Res; 643444ed5c5SDimitry Andric } else { 644444ed5c5SDimitry Andric return B->second; 645444ed5c5SDimitry Andric } 646444ed5c5SDimitry Andric } 647444ed5c5SDimitry Andric 648444ed5c5SDimitry Andric bool SIScheduleBlockCreator::isSUInBlock(SUnit *SU, unsigned ID) { 649444ed5c5SDimitry Andric if (SU->NodeNum >= DAG->SUnits.size()) 650444ed5c5SDimitry Andric return false; 651444ed5c5SDimitry Andric return CurrentBlocks[Node2CurrentBlock[SU->NodeNum]]->getID() == ID; 652444ed5c5SDimitry Andric } 653444ed5c5SDimitry Andric 654444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorHighLatenciesAlone() { 655444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 656444ed5c5SDimitry Andric 657444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 658444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 659444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) { 660444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = NextReservedID++; 661444ed5c5SDimitry Andric } 662444ed5c5SDimitry Andric } 663444ed5c5SDimitry Andric } 664444ed5c5SDimitry Andric 6657a7e6055SDimitry Andric static bool 6667a7e6055SDimitry Andric hasDataDependencyPred(const SUnit &SU, const SUnit &FromSU) { 6677a7e6055SDimitry Andric for (const auto &PredDep : SU.Preds) { 6687a7e6055SDimitry Andric if (PredDep.getSUnit() == &FromSU && 6697a7e6055SDimitry Andric PredDep.getKind() == llvm::SDep::Data) 6707a7e6055SDimitry Andric return true; 6717a7e6055SDimitry Andric } 6727a7e6055SDimitry Andric return false; 6737a7e6055SDimitry Andric } 6747a7e6055SDimitry Andric 675444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorHighLatenciesGroups() { 676444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 677444ed5c5SDimitry Andric unsigned NumHighLatencies = 0; 678444ed5c5SDimitry Andric unsigned GroupSize; 6797a7e6055SDimitry Andric int Color = NextReservedID; 680444ed5c5SDimitry Andric unsigned Count = 0; 681444ed5c5SDimitry Andric std::set<unsigned> FormingGroup; 682444ed5c5SDimitry Andric 683444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 684444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 685444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) 686444ed5c5SDimitry Andric ++NumHighLatencies; 687444ed5c5SDimitry Andric } 688444ed5c5SDimitry Andric 689444ed5c5SDimitry Andric if (NumHighLatencies == 0) 690444ed5c5SDimitry Andric return; 691444ed5c5SDimitry Andric 692444ed5c5SDimitry Andric if (NumHighLatencies <= 6) 693444ed5c5SDimitry Andric GroupSize = 2; 694444ed5c5SDimitry Andric else if (NumHighLatencies <= 12) 695444ed5c5SDimitry Andric GroupSize = 3; 696444ed5c5SDimitry Andric else 697444ed5c5SDimitry Andric GroupSize = 4; 698444ed5c5SDimitry Andric 6997a7e6055SDimitry Andric for (unsigned SUNum : DAG->TopDownIndex2SU) { 7007a7e6055SDimitry Andric const SUnit &SU = DAG->SUnits[SUNum]; 7017a7e6055SDimitry Andric if (DAG->IsHighLatencySU[SU.NodeNum]) { 702444ed5c5SDimitry Andric unsigned CompatibleGroup = true; 7037a7e6055SDimitry Andric int ProposedColor = Color; 7047a7e6055SDimitry Andric std::vector<int> AdditionalElements; 7057a7e6055SDimitry Andric 7067a7e6055SDimitry Andric // We don't want to put in the same block 7077a7e6055SDimitry Andric // two high latency instructions that depend 7087a7e6055SDimitry Andric // on each other. 7097a7e6055SDimitry Andric // One way would be to check canAddEdge 7107a7e6055SDimitry Andric // in both directions, but that currently is not 7117a7e6055SDimitry Andric // enough because there the high latency order is 7127a7e6055SDimitry Andric // enforced (via links). 7137a7e6055SDimitry Andric // Instead, look at the dependencies between the 7147a7e6055SDimitry Andric // high latency instructions and deduce if it is 7157a7e6055SDimitry Andric // a data dependency or not. 716444ed5c5SDimitry Andric for (unsigned j : FormingGroup) { 7177a7e6055SDimitry Andric bool HasSubGraph; 7187a7e6055SDimitry Andric std::vector<int> SubGraph; 7197a7e6055SDimitry Andric // By construction (topological order), if SU and 7207a7e6055SDimitry Andric // DAG->SUnits[j] are linked, DAG->SUnits[j] is neccessary 7217a7e6055SDimitry Andric // in the parent graph of SU. 7227a7e6055SDimitry Andric #ifndef NDEBUG 7237a7e6055SDimitry Andric SubGraph = DAG->GetTopo()->GetSubGraph(SU, DAG->SUnits[j], 7247a7e6055SDimitry Andric HasSubGraph); 7257a7e6055SDimitry Andric assert(!HasSubGraph); 7267a7e6055SDimitry Andric #endif 7277a7e6055SDimitry Andric SubGraph = DAG->GetTopo()->GetSubGraph(DAG->SUnits[j], SU, 7287a7e6055SDimitry Andric HasSubGraph); 7297a7e6055SDimitry Andric if (!HasSubGraph) 7307a7e6055SDimitry Andric continue; // No dependencies between each other 7317a7e6055SDimitry Andric else if (SubGraph.size() > 5) { 7327a7e6055SDimitry Andric // Too many elements would be required to be added to the block. 733444ed5c5SDimitry Andric CompatibleGroup = false; 7347a7e6055SDimitry Andric break; 735444ed5c5SDimitry Andric } 7367a7e6055SDimitry Andric else { 7377a7e6055SDimitry Andric // Check the type of dependency 7387a7e6055SDimitry Andric for (unsigned k : SubGraph) { 7397a7e6055SDimitry Andric // If in the path to join the two instructions, 7407a7e6055SDimitry Andric // there is another high latency instruction, 7417a7e6055SDimitry Andric // or instructions colored for another block 7427a7e6055SDimitry Andric // abort the merge. 7437a7e6055SDimitry Andric if (DAG->IsHighLatencySU[k] || 7447a7e6055SDimitry Andric (CurrentColoring[k] != ProposedColor && 7457a7e6055SDimitry Andric CurrentColoring[k] != 0)) { 7467a7e6055SDimitry Andric CompatibleGroup = false; 7477a7e6055SDimitry Andric break; 7487a7e6055SDimitry Andric } 7497a7e6055SDimitry Andric // If one of the SU in the subgraph depends on the result of SU j, 7507a7e6055SDimitry Andric // there'll be a data dependency. 7517a7e6055SDimitry Andric if (hasDataDependencyPred(DAG->SUnits[k], DAG->SUnits[j])) { 7527a7e6055SDimitry Andric CompatibleGroup = false; 7537a7e6055SDimitry Andric break; 7547a7e6055SDimitry Andric } 7557a7e6055SDimitry Andric } 7567a7e6055SDimitry Andric if (!CompatibleGroup) 7577a7e6055SDimitry Andric break; 7587a7e6055SDimitry Andric // Same check for the SU 7597a7e6055SDimitry Andric if (hasDataDependencyPred(SU, DAG->SUnits[j])) { 7607a7e6055SDimitry Andric CompatibleGroup = false; 7617a7e6055SDimitry Andric break; 7627a7e6055SDimitry Andric } 7637a7e6055SDimitry Andric // Add all the required instructions to the block 7647a7e6055SDimitry Andric // These cannot live in another block (because they 7657a7e6055SDimitry Andric // depend (order dependency) on one of the 7667a7e6055SDimitry Andric // instruction in the block, and are required for the 7677a7e6055SDimitry Andric // high latency instruction we add. 7687a7e6055SDimitry Andric AdditionalElements.insert(AdditionalElements.end(), 7697a7e6055SDimitry Andric SubGraph.begin(), SubGraph.end()); 7707a7e6055SDimitry Andric } 7717a7e6055SDimitry Andric } 7727a7e6055SDimitry Andric if (CompatibleGroup) { 7737a7e6055SDimitry Andric FormingGroup.insert(SU.NodeNum); 7747a7e6055SDimitry Andric for (unsigned j : AdditionalElements) 7757a7e6055SDimitry Andric CurrentColoring[j] = ProposedColor; 7767a7e6055SDimitry Andric CurrentColoring[SU.NodeNum] = ProposedColor; 7777a7e6055SDimitry Andric ++Count; 7787a7e6055SDimitry Andric } 7797a7e6055SDimitry Andric // Found one incompatible instruction, 7807a7e6055SDimitry Andric // or has filled a big enough group. 7817a7e6055SDimitry Andric // -> start a new one. 7827a7e6055SDimitry Andric if (!CompatibleGroup) { 783444ed5c5SDimitry Andric FormingGroup.clear(); 784444ed5c5SDimitry Andric Color = ++NextReservedID; 785444ed5c5SDimitry Andric ProposedColor = Color; 7867a7e6055SDimitry Andric FormingGroup.insert(SU.NodeNum); 7877a7e6055SDimitry Andric CurrentColoring[SU.NodeNum] = ProposedColor; 788444ed5c5SDimitry Andric Count = 0; 7897a7e6055SDimitry Andric } else if (Count == GroupSize) { 7907a7e6055SDimitry Andric FormingGroup.clear(); 7917a7e6055SDimitry Andric Color = ++NextReservedID; 7927a7e6055SDimitry Andric ProposedColor = Color; 7937a7e6055SDimitry Andric Count = 0; 794444ed5c5SDimitry Andric } 795444ed5c5SDimitry Andric } 796444ed5c5SDimitry Andric } 797444ed5c5SDimitry Andric } 798444ed5c5SDimitry Andric 799444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorComputeReservedDependencies() { 800444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 801444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned> ColorCombinations; 802444ed5c5SDimitry Andric 803444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring.clear(); 804444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring.clear(); 805444ed5c5SDimitry Andric 806444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring.resize(DAGSize, 0); 807444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring.resize(DAGSize, 0); 808444ed5c5SDimitry Andric 809444ed5c5SDimitry Andric // Traverse TopDown, and give different colors to SUs depending 810444ed5c5SDimitry Andric // on which combination of High Latencies they depend on. 811444ed5c5SDimitry Andric 8123ca95b02SDimitry Andric for (unsigned SUNum : DAG->TopDownIndex2SU) { 8133ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 814444ed5c5SDimitry Andric std::set<unsigned> SUColors; 815444ed5c5SDimitry Andric 816444ed5c5SDimitry Andric // Already given. 817444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) { 818444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 819444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum]; 820444ed5c5SDimitry Andric continue; 821444ed5c5SDimitry Andric } 822444ed5c5SDimitry Andric 823444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 824444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 825444ed5c5SDimitry Andric if (PredDep.isWeak() || Pred->NodeNum >= DAGSize) 826444ed5c5SDimitry Andric continue; 827444ed5c5SDimitry Andric if (CurrentTopDownReservedDependencyColoring[Pred->NodeNum] > 0) 828444ed5c5SDimitry Andric SUColors.insert(CurrentTopDownReservedDependencyColoring[Pred->NodeNum]); 829444ed5c5SDimitry Andric } 830444ed5c5SDimitry Andric // Color 0 by default. 831444ed5c5SDimitry Andric if (SUColors.empty()) 832444ed5c5SDimitry Andric continue; 833444ed5c5SDimitry Andric // Same color than parents. 834444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() > DAGSize) 835444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 836444ed5c5SDimitry Andric *SUColors.begin(); 837444ed5c5SDimitry Andric else { 838444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned>::iterator Pos = 839444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 840444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 841444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = Pos->second; 842444ed5c5SDimitry Andric } else { 843444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 844444ed5c5SDimitry Andric NextNonReservedID; 845444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 846444ed5c5SDimitry Andric } 847444ed5c5SDimitry Andric } 848444ed5c5SDimitry Andric } 849444ed5c5SDimitry Andric 850444ed5c5SDimitry Andric ColorCombinations.clear(); 851444ed5c5SDimitry Andric 852444ed5c5SDimitry Andric // Same as before, but BottomUp. 853444ed5c5SDimitry Andric 8543ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 8553ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 856444ed5c5SDimitry Andric std::set<unsigned> SUColors; 857444ed5c5SDimitry Andric 858444ed5c5SDimitry Andric // Already given. 859444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) { 860444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 861444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum]; 862444ed5c5SDimitry Andric continue; 863444ed5c5SDimitry Andric } 864444ed5c5SDimitry Andric 865444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 866444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 867444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 868444ed5c5SDimitry Andric continue; 869444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0) 870444ed5c5SDimitry Andric SUColors.insert(CurrentBottomUpReservedDependencyColoring[Succ->NodeNum]); 871444ed5c5SDimitry Andric } 872444ed5c5SDimitry Andric // Keep color 0. 873444ed5c5SDimitry Andric if (SUColors.empty()) 874444ed5c5SDimitry Andric continue; 875444ed5c5SDimitry Andric // Same color than parents. 876444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() > DAGSize) 877444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 878444ed5c5SDimitry Andric *SUColors.begin(); 879444ed5c5SDimitry Andric else { 880444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned>::iterator Pos = 881444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 882444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 883444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = Pos->second; 884444ed5c5SDimitry Andric } else { 885444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 886444ed5c5SDimitry Andric NextNonReservedID; 887444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 888444ed5c5SDimitry Andric } 889444ed5c5SDimitry Andric } 890444ed5c5SDimitry Andric } 891444ed5c5SDimitry Andric } 892444ed5c5SDimitry Andric 893444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorAccordingToReservedDependencies() { 894444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 895444ed5c5SDimitry Andric std::map<std::pair<unsigned, unsigned>, unsigned> ColorCombinations; 896444ed5c5SDimitry Andric 897444ed5c5SDimitry Andric // Every combination of colors given by the top down 898444ed5c5SDimitry Andric // and bottom up Reserved node dependency 899444ed5c5SDimitry Andric 900444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 901444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 902444ed5c5SDimitry Andric std::pair<unsigned, unsigned> SUColors; 903444ed5c5SDimitry Andric 904444ed5c5SDimitry Andric // High latency instructions: already given. 905444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) 906444ed5c5SDimitry Andric continue; 907444ed5c5SDimitry Andric 908444ed5c5SDimitry Andric SUColors.first = CurrentTopDownReservedDependencyColoring[SU->NodeNum]; 909444ed5c5SDimitry Andric SUColors.second = CurrentBottomUpReservedDependencyColoring[SU->NodeNum]; 910444ed5c5SDimitry Andric 911444ed5c5SDimitry Andric std::map<std::pair<unsigned, unsigned>, unsigned>::iterator Pos = 912444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 913444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 914444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = Pos->second; 915444ed5c5SDimitry Andric } else { 916444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = NextNonReservedID; 917444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 918444ed5c5SDimitry Andric } 919444ed5c5SDimitry Andric } 920444ed5c5SDimitry Andric } 921444ed5c5SDimitry Andric 922444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorEndsAccordingToDependencies() { 923444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 924444ed5c5SDimitry Andric std::vector<int> PendingColoring = CurrentColoring; 925444ed5c5SDimitry Andric 9267a7e6055SDimitry Andric assert(DAGSize >= 1 && 9277a7e6055SDimitry Andric CurrentBottomUpReservedDependencyColoring.size() == DAGSize && 9287a7e6055SDimitry Andric CurrentTopDownReservedDependencyColoring.size() == DAGSize); 9297a7e6055SDimitry Andric // If there is no reserved block at all, do nothing. We don't want 9307a7e6055SDimitry Andric // everything in one block. 9317a7e6055SDimitry Andric if (*std::max_element(CurrentBottomUpReservedDependencyColoring.begin(), 9327a7e6055SDimitry Andric CurrentBottomUpReservedDependencyColoring.end()) == 0 && 9337a7e6055SDimitry Andric *std::max_element(CurrentTopDownReservedDependencyColoring.begin(), 9347a7e6055SDimitry Andric CurrentTopDownReservedDependencyColoring.end()) == 0) 9357a7e6055SDimitry Andric return; 9367a7e6055SDimitry Andric 9373ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 9383ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 939444ed5c5SDimitry Andric std::set<unsigned> SUColors; 940444ed5c5SDimitry Andric std::set<unsigned> SUColorsPending; 941444ed5c5SDimitry Andric 942444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 943444ed5c5SDimitry Andric continue; 944444ed5c5SDimitry Andric 945444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[SU->NodeNum] > 0 || 946444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] > 0) 947444ed5c5SDimitry Andric continue; 948444ed5c5SDimitry Andric 949444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 950444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 951444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 952444ed5c5SDimitry Andric continue; 953444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0 || 954444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[Succ->NodeNum] > 0) 955444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 956444ed5c5SDimitry Andric SUColorsPending.insert(PendingColoring[Succ->NodeNum]); 957444ed5c5SDimitry Andric } 9587a7e6055SDimitry Andric // If there is only one child/parent block, and that block 9597a7e6055SDimitry Andric // is not among the ones we are removing in this path, then 9607a7e6055SDimitry Andric // merge the instruction to that block 961444ed5c5SDimitry Andric if (SUColors.size() == 1 && SUColorsPending.size() == 1) 962444ed5c5SDimitry Andric PendingColoring[SU->NodeNum] = *SUColors.begin(); 963444ed5c5SDimitry Andric else // TODO: Attribute new colors depending on color 964444ed5c5SDimitry Andric // combination of children. 965444ed5c5SDimitry Andric PendingColoring[SU->NodeNum] = NextNonReservedID++; 966444ed5c5SDimitry Andric } 967444ed5c5SDimitry Andric CurrentColoring = PendingColoring; 968444ed5c5SDimitry Andric } 969444ed5c5SDimitry Andric 970444ed5c5SDimitry Andric 971444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorForceConsecutiveOrderInGroup() { 972444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 973444ed5c5SDimitry Andric unsigned PreviousColor; 974444ed5c5SDimitry Andric std::set<unsigned> SeenColors; 975444ed5c5SDimitry Andric 976444ed5c5SDimitry Andric if (DAGSize <= 1) 977444ed5c5SDimitry Andric return; 978444ed5c5SDimitry Andric 979444ed5c5SDimitry Andric PreviousColor = CurrentColoring[0]; 980444ed5c5SDimitry Andric 981444ed5c5SDimitry Andric for (unsigned i = 1, e = DAGSize; i != e; ++i) { 982444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 983444ed5c5SDimitry Andric unsigned CurrentColor = CurrentColoring[i]; 984444ed5c5SDimitry Andric unsigned PreviousColorSave = PreviousColor; 985444ed5c5SDimitry Andric assert(i == SU->NodeNum); 986444ed5c5SDimitry Andric 987444ed5c5SDimitry Andric if (CurrentColor != PreviousColor) 988444ed5c5SDimitry Andric SeenColors.insert(PreviousColor); 989444ed5c5SDimitry Andric PreviousColor = CurrentColor; 990444ed5c5SDimitry Andric 991444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 992444ed5c5SDimitry Andric continue; 993444ed5c5SDimitry Andric 994444ed5c5SDimitry Andric if (SeenColors.find(CurrentColor) == SeenColors.end()) 995444ed5c5SDimitry Andric continue; 996444ed5c5SDimitry Andric 997444ed5c5SDimitry Andric if (PreviousColorSave != CurrentColor) 998444ed5c5SDimitry Andric CurrentColoring[i] = NextNonReservedID++; 999444ed5c5SDimitry Andric else 1000444ed5c5SDimitry Andric CurrentColoring[i] = CurrentColoring[i-1]; 1001444ed5c5SDimitry Andric } 1002444ed5c5SDimitry Andric } 1003444ed5c5SDimitry Andric 1004444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeConstantLoadsNextGroup() { 1005444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1006444ed5c5SDimitry Andric 10073ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 10083ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1009444ed5c5SDimitry Andric std::set<unsigned> SUColors; 1010444ed5c5SDimitry Andric 1011444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1012444ed5c5SDimitry Andric continue; 1013444ed5c5SDimitry Andric 1014444ed5c5SDimitry Andric // No predecessor: Vgpr constant loading. 1015444ed5c5SDimitry Andric // Low latency instructions usually have a predecessor (the address) 1016444ed5c5SDimitry Andric if (SU->Preds.size() > 0 && !DAG->IsLowLatencySU[SU->NodeNum]) 1017444ed5c5SDimitry Andric continue; 1018444ed5c5SDimitry Andric 1019444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1020444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1021444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1022444ed5c5SDimitry Andric continue; 1023444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 1024444ed5c5SDimitry Andric } 1025444ed5c5SDimitry Andric if (SUColors.size() == 1) 1026444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 1027444ed5c5SDimitry Andric } 1028444ed5c5SDimitry Andric } 1029444ed5c5SDimitry Andric 1030444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleNextGroup() { 1031444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1032444ed5c5SDimitry Andric 10333ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 10343ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1035444ed5c5SDimitry Andric std::set<unsigned> SUColors; 1036444ed5c5SDimitry Andric 1037444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1038444ed5c5SDimitry Andric continue; 1039444ed5c5SDimitry Andric 1040444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1041444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1042444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1043444ed5c5SDimitry Andric continue; 1044444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 1045444ed5c5SDimitry Andric } 1046444ed5c5SDimitry Andric if (SUColors.size() == 1) 1047444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 1048444ed5c5SDimitry Andric } 1049444ed5c5SDimitry Andric } 1050444ed5c5SDimitry Andric 1051444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleNextGroupOnlyForReserved() { 1052444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1053444ed5c5SDimitry Andric 10543ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 10553ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1056444ed5c5SDimitry Andric std::set<unsigned> SUColors; 1057444ed5c5SDimitry Andric 1058444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1059444ed5c5SDimitry Andric continue; 1060444ed5c5SDimitry Andric 1061444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1062444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1063444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1064444ed5c5SDimitry Andric continue; 1065444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 1066444ed5c5SDimitry Andric } 1067444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() <= DAGSize) 1068444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 1069444ed5c5SDimitry Andric } 1070444ed5c5SDimitry Andric } 1071444ed5c5SDimitry Andric 1072444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleSmallGroupsToNextGroup() { 1073444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1074444ed5c5SDimitry Andric std::map<unsigned, unsigned> ColorCount; 1075444ed5c5SDimitry Andric 10763ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 10773ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1078444ed5c5SDimitry Andric unsigned color = CurrentColoring[SU->NodeNum]; 1079444ed5c5SDimitry Andric ++ColorCount[color]; 1080444ed5c5SDimitry Andric } 1081444ed5c5SDimitry Andric 10823ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 10833ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1084444ed5c5SDimitry Andric unsigned color = CurrentColoring[SU->NodeNum]; 1085444ed5c5SDimitry Andric std::set<unsigned> SUColors; 1086444ed5c5SDimitry Andric 1087444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1088444ed5c5SDimitry Andric continue; 1089444ed5c5SDimitry Andric 1090444ed5c5SDimitry Andric if (ColorCount[color] > 1) 1091444ed5c5SDimitry Andric continue; 1092444ed5c5SDimitry Andric 1093444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1094444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1095444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1096444ed5c5SDimitry Andric continue; 1097444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 1098444ed5c5SDimitry Andric } 1099444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() != color) { 1100444ed5c5SDimitry Andric --ColorCount[color]; 1101444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 1102444ed5c5SDimitry Andric ++ColorCount[*SUColors.begin()]; 1103444ed5c5SDimitry Andric } 1104444ed5c5SDimitry Andric } 1105444ed5c5SDimitry Andric } 1106444ed5c5SDimitry Andric 1107444ed5c5SDimitry Andric void SIScheduleBlockCreator::cutHugeBlocks() { 1108444ed5c5SDimitry Andric // TODO 1109444ed5c5SDimitry Andric } 1110444ed5c5SDimitry Andric 1111444ed5c5SDimitry Andric void SIScheduleBlockCreator::regroupNoUserInstructions() { 1112444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1113444ed5c5SDimitry Andric int GroupID = NextNonReservedID++; 1114444ed5c5SDimitry Andric 11153ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 11163ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1117444ed5c5SDimitry Andric bool hasSuccessor = false; 1118444ed5c5SDimitry Andric 1119444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1120444ed5c5SDimitry Andric continue; 1121444ed5c5SDimitry Andric 1122444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1123444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1124444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1125444ed5c5SDimitry Andric continue; 1126444ed5c5SDimitry Andric hasSuccessor = true; 1127444ed5c5SDimitry Andric } 1128444ed5c5SDimitry Andric if (!hasSuccessor) 1129444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = GroupID; 1130444ed5c5SDimitry Andric } 1131444ed5c5SDimitry Andric } 1132444ed5c5SDimitry Andric 1133444ed5c5SDimitry Andric void SIScheduleBlockCreator::createBlocksForVariant(SISchedulerBlockCreatorVariant BlockVariant) { 1134444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1135444ed5c5SDimitry Andric std::map<unsigned,unsigned> RealID; 1136444ed5c5SDimitry Andric 1137444ed5c5SDimitry Andric CurrentBlocks.clear(); 1138444ed5c5SDimitry Andric CurrentColoring.clear(); 1139444ed5c5SDimitry Andric CurrentColoring.resize(DAGSize, 0); 1140444ed5c5SDimitry Andric Node2CurrentBlock.clear(); 1141444ed5c5SDimitry Andric 1142444ed5c5SDimitry Andric // Restore links previous scheduling variant has overridden. 1143444ed5c5SDimitry Andric DAG->restoreSULinksLeft(); 1144444ed5c5SDimitry Andric 1145444ed5c5SDimitry Andric NextReservedID = 1; 1146444ed5c5SDimitry Andric NextNonReservedID = DAGSize + 1; 1147444ed5c5SDimitry Andric 1148444ed5c5SDimitry Andric DEBUG(dbgs() << "Coloring the graph\n"); 1149444ed5c5SDimitry Andric 1150444ed5c5SDimitry Andric if (BlockVariant == SISchedulerBlockCreatorVariant::LatenciesGrouped) 1151444ed5c5SDimitry Andric colorHighLatenciesGroups(); 1152444ed5c5SDimitry Andric else 1153444ed5c5SDimitry Andric colorHighLatenciesAlone(); 1154444ed5c5SDimitry Andric colorComputeReservedDependencies(); 1155444ed5c5SDimitry Andric colorAccordingToReservedDependencies(); 1156444ed5c5SDimitry Andric colorEndsAccordingToDependencies(); 1157444ed5c5SDimitry Andric if (BlockVariant == SISchedulerBlockCreatorVariant::LatenciesAlonePlusConsecutive) 1158444ed5c5SDimitry Andric colorForceConsecutiveOrderInGroup(); 1159444ed5c5SDimitry Andric regroupNoUserInstructions(); 1160444ed5c5SDimitry Andric colorMergeConstantLoadsNextGroup(); 1161444ed5c5SDimitry Andric colorMergeIfPossibleNextGroupOnlyForReserved(); 1162444ed5c5SDimitry Andric 1163444ed5c5SDimitry Andric // Put SUs of same color into same block 1164444ed5c5SDimitry Andric Node2CurrentBlock.resize(DAGSize, -1); 1165444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1166444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 1167444ed5c5SDimitry Andric unsigned Color = CurrentColoring[SU->NodeNum]; 1168444ed5c5SDimitry Andric if (RealID.find(Color) == RealID.end()) { 1169444ed5c5SDimitry Andric int ID = CurrentBlocks.size(); 1170d88c1a5aSDimitry Andric BlockPtrs.push_back(llvm::make_unique<SIScheduleBlock>(DAG, this, ID)); 1171444ed5c5SDimitry Andric CurrentBlocks.push_back(BlockPtrs.rbegin()->get()); 1172444ed5c5SDimitry Andric RealID[Color] = ID; 1173444ed5c5SDimitry Andric } 1174444ed5c5SDimitry Andric CurrentBlocks[RealID[Color]]->addUnit(SU); 1175444ed5c5SDimitry Andric Node2CurrentBlock[SU->NodeNum] = RealID[Color]; 1176444ed5c5SDimitry Andric } 1177444ed5c5SDimitry Andric 1178444ed5c5SDimitry Andric // Build dependencies between blocks. 1179444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1180444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 1181444ed5c5SDimitry Andric int SUID = Node2CurrentBlock[i]; 1182444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1183444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1184444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1185444ed5c5SDimitry Andric continue; 1186444ed5c5SDimitry Andric if (Node2CurrentBlock[Succ->NodeNum] != SUID) 11877a7e6055SDimitry Andric CurrentBlocks[SUID]->addSucc(CurrentBlocks[Node2CurrentBlock[Succ->NodeNum]], 11887a7e6055SDimitry Andric SuccDep.isCtrl() ? NoData : Data); 1189444ed5c5SDimitry Andric } 1190444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 1191444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 1192444ed5c5SDimitry Andric if (PredDep.isWeak() || Pred->NodeNum >= DAGSize) 1193444ed5c5SDimitry Andric continue; 1194444ed5c5SDimitry Andric if (Node2CurrentBlock[Pred->NodeNum] != SUID) 1195444ed5c5SDimitry Andric CurrentBlocks[SUID]->addPred(CurrentBlocks[Node2CurrentBlock[Pred->NodeNum]]); 1196444ed5c5SDimitry Andric } 1197444ed5c5SDimitry Andric } 1198444ed5c5SDimitry Andric 1199444ed5c5SDimitry Andric // Free root and leafs of all blocks to enable scheduling inside them. 1200444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1201444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1202444ed5c5SDimitry Andric Block->finalizeUnits(); 1203444ed5c5SDimitry Andric } 1204444ed5c5SDimitry Andric DEBUG( 1205444ed5c5SDimitry Andric dbgs() << "Blocks created:\n\n"; 1206444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1207444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1208444ed5c5SDimitry Andric Block->printDebug(true); 1209444ed5c5SDimitry Andric } 1210444ed5c5SDimitry Andric ); 1211444ed5c5SDimitry Andric } 1212444ed5c5SDimitry Andric 1213444ed5c5SDimitry Andric // Two functions taken from Codegen/MachineScheduler.cpp 1214444ed5c5SDimitry Andric 1215d88c1a5aSDimitry Andric /// Non-const version. 1216d88c1a5aSDimitry Andric static MachineBasicBlock::iterator 1217d88c1a5aSDimitry Andric nextIfDebug(MachineBasicBlock::iterator I, 1218444ed5c5SDimitry Andric MachineBasicBlock::const_iterator End) { 1219444ed5c5SDimitry Andric for (; I != End; ++I) { 1220444ed5c5SDimitry Andric if (!I->isDebugValue()) 1221444ed5c5SDimitry Andric break; 1222444ed5c5SDimitry Andric } 1223444ed5c5SDimitry Andric return I; 1224444ed5c5SDimitry Andric } 1225444ed5c5SDimitry Andric 1226444ed5c5SDimitry Andric void SIScheduleBlockCreator::topologicalSort() { 1227444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1228444ed5c5SDimitry Andric std::vector<int> WorkList; 1229444ed5c5SDimitry Andric 1230444ed5c5SDimitry Andric DEBUG(dbgs() << "Topological Sort\n"); 1231444ed5c5SDimitry Andric 1232444ed5c5SDimitry Andric WorkList.reserve(DAGSize); 1233444ed5c5SDimitry Andric TopDownIndex2Block.resize(DAGSize); 1234444ed5c5SDimitry Andric TopDownBlock2Index.resize(DAGSize); 1235444ed5c5SDimitry Andric BottomUpIndex2Block.resize(DAGSize); 1236444ed5c5SDimitry Andric 1237444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1238444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1239444ed5c5SDimitry Andric unsigned Degree = Block->getSuccs().size(); 1240444ed5c5SDimitry Andric TopDownBlock2Index[i] = Degree; 1241444ed5c5SDimitry Andric if (Degree == 0) { 1242444ed5c5SDimitry Andric WorkList.push_back(i); 1243444ed5c5SDimitry Andric } 1244444ed5c5SDimitry Andric } 1245444ed5c5SDimitry Andric 1246444ed5c5SDimitry Andric int Id = DAGSize; 1247444ed5c5SDimitry Andric while (!WorkList.empty()) { 1248444ed5c5SDimitry Andric int i = WorkList.back(); 1249444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1250444ed5c5SDimitry Andric WorkList.pop_back(); 1251444ed5c5SDimitry Andric TopDownBlock2Index[i] = --Id; 1252444ed5c5SDimitry Andric TopDownIndex2Block[Id] = i; 1253444ed5c5SDimitry Andric for (SIScheduleBlock* Pred : Block->getPreds()) { 1254444ed5c5SDimitry Andric if (!--TopDownBlock2Index[Pred->getID()]) 1255444ed5c5SDimitry Andric WorkList.push_back(Pred->getID()); 1256444ed5c5SDimitry Andric } 1257444ed5c5SDimitry Andric } 1258444ed5c5SDimitry Andric 1259444ed5c5SDimitry Andric #ifndef NDEBUG 1260444ed5c5SDimitry Andric // Check correctness of the ordering. 1261444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1262444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1263444ed5c5SDimitry Andric for (SIScheduleBlock* Pred : Block->getPreds()) { 1264444ed5c5SDimitry Andric assert(TopDownBlock2Index[i] > TopDownBlock2Index[Pred->getID()] && 1265444ed5c5SDimitry Andric "Wrong Top Down topological sorting"); 1266444ed5c5SDimitry Andric } 1267444ed5c5SDimitry Andric } 1268444ed5c5SDimitry Andric #endif 1269444ed5c5SDimitry Andric 1270444ed5c5SDimitry Andric BottomUpIndex2Block = std::vector<int>(TopDownIndex2Block.rbegin(), 1271444ed5c5SDimitry Andric TopDownIndex2Block.rend()); 1272444ed5c5SDimitry Andric } 1273444ed5c5SDimitry Andric 1274444ed5c5SDimitry Andric void SIScheduleBlockCreator::scheduleInsideBlocks() { 1275444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1276444ed5c5SDimitry Andric 1277444ed5c5SDimitry Andric DEBUG(dbgs() << "\nScheduling Blocks\n\n"); 1278444ed5c5SDimitry Andric 1279444ed5c5SDimitry Andric // We do schedule a valid scheduling such that a Block corresponds 1280444ed5c5SDimitry Andric // to a range of instructions. 1281444ed5c5SDimitry Andric DEBUG(dbgs() << "First phase: Fast scheduling for Reg Liveness\n"); 1282444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1283444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1284444ed5c5SDimitry Andric Block->fastSchedule(); 1285444ed5c5SDimitry Andric } 1286444ed5c5SDimitry Andric 1287444ed5c5SDimitry Andric // Note: the following code, and the part restoring previous position 1288444ed5c5SDimitry Andric // is by far the most expensive operation of the Scheduler. 1289444ed5c5SDimitry Andric 1290444ed5c5SDimitry Andric // Do not update CurrentTop. 1291444ed5c5SDimitry Andric MachineBasicBlock::iterator CurrentTopFastSched = DAG->getCurrentTop(); 1292444ed5c5SDimitry Andric std::vector<MachineBasicBlock::iterator> PosOld; 1293444ed5c5SDimitry Andric std::vector<MachineBasicBlock::iterator> PosNew; 1294444ed5c5SDimitry Andric PosOld.reserve(DAG->SUnits.size()); 1295444ed5c5SDimitry Andric PosNew.reserve(DAG->SUnits.size()); 1296444ed5c5SDimitry Andric 1297444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1298444ed5c5SDimitry Andric int BlockIndice = TopDownIndex2Block[i]; 1299444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1300444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1301444ed5c5SDimitry Andric 1302444ed5c5SDimitry Andric for (SUnit* SU : SUs) { 1303444ed5c5SDimitry Andric MachineInstr *MI = SU->getInstr(); 1304444ed5c5SDimitry Andric MachineBasicBlock::iterator Pos = MI; 1305444ed5c5SDimitry Andric PosOld.push_back(Pos); 1306444ed5c5SDimitry Andric if (&*CurrentTopFastSched == MI) { 1307444ed5c5SDimitry Andric PosNew.push_back(Pos); 1308444ed5c5SDimitry Andric CurrentTopFastSched = nextIfDebug(++CurrentTopFastSched, 1309444ed5c5SDimitry Andric DAG->getCurrentBottom()); 1310444ed5c5SDimitry Andric } else { 1311444ed5c5SDimitry Andric // Update the instruction stream. 1312444ed5c5SDimitry Andric DAG->getBB()->splice(CurrentTopFastSched, DAG->getBB(), MI); 1313444ed5c5SDimitry Andric 1314444ed5c5SDimitry Andric // Update LiveIntervals. 1315444ed5c5SDimitry Andric // Note: Moving all instructions and calling handleMove every time 1316444ed5c5SDimitry Andric // is the most cpu intensive operation of the scheduler. 1317444ed5c5SDimitry Andric // It would gain a lot if there was a way to recompute the 1318444ed5c5SDimitry Andric // LiveIntervals for the entire scheduling region. 13193ca95b02SDimitry Andric DAG->getLIS()->handleMove(*MI, /*UpdateFlags=*/true); 1320444ed5c5SDimitry Andric PosNew.push_back(CurrentTopFastSched); 1321444ed5c5SDimitry Andric } 1322444ed5c5SDimitry Andric } 1323444ed5c5SDimitry Andric } 1324444ed5c5SDimitry Andric 1325444ed5c5SDimitry Andric // Now we have Block of SUs == Block of MI. 1326444ed5c5SDimitry Andric // We do the final schedule for the instructions inside the block. 1327444ed5c5SDimitry Andric // The property that all the SUs of the Block are grouped together as MI 1328444ed5c5SDimitry Andric // is used for correct reg usage tracking. 1329444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1330444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1331444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1332444ed5c5SDimitry Andric Block->schedule((*SUs.begin())->getInstr(), (*SUs.rbegin())->getInstr()); 1333444ed5c5SDimitry Andric } 1334444ed5c5SDimitry Andric 1335444ed5c5SDimitry Andric DEBUG(dbgs() << "Restoring MI Pos\n"); 1336444ed5c5SDimitry Andric // Restore old ordering (which prevents a LIS->handleMove bug). 1337444ed5c5SDimitry Andric for (unsigned i = PosOld.size(), e = 0; i != e; --i) { 1338444ed5c5SDimitry Andric MachineBasicBlock::iterator POld = PosOld[i-1]; 1339444ed5c5SDimitry Andric MachineBasicBlock::iterator PNew = PosNew[i-1]; 1340444ed5c5SDimitry Andric if (PNew != POld) { 1341444ed5c5SDimitry Andric // Update the instruction stream. 1342444ed5c5SDimitry Andric DAG->getBB()->splice(POld, DAG->getBB(), PNew); 1343444ed5c5SDimitry Andric 1344444ed5c5SDimitry Andric // Update LiveIntervals. 13453ca95b02SDimitry Andric DAG->getLIS()->handleMove(*POld, /*UpdateFlags=*/true); 1346444ed5c5SDimitry Andric } 1347444ed5c5SDimitry Andric } 1348444ed5c5SDimitry Andric 1349444ed5c5SDimitry Andric DEBUG( 1350444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1351444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1352444ed5c5SDimitry Andric Block->printDebug(true); 1353444ed5c5SDimitry Andric } 1354444ed5c5SDimitry Andric ); 1355444ed5c5SDimitry Andric } 1356444ed5c5SDimitry Andric 1357444ed5c5SDimitry Andric void SIScheduleBlockCreator::fillStats() { 1358444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1359444ed5c5SDimitry Andric 1360444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1361444ed5c5SDimitry Andric int BlockIndice = TopDownIndex2Block[i]; 1362444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1363d88c1a5aSDimitry Andric if (Block->getPreds().empty()) 1364444ed5c5SDimitry Andric Block->Depth = 0; 1365444ed5c5SDimitry Andric else { 1366444ed5c5SDimitry Andric unsigned Depth = 0; 1367444ed5c5SDimitry Andric for (SIScheduleBlock *Pred : Block->getPreds()) { 1368444ed5c5SDimitry Andric if (Depth < Pred->Depth + 1) 1369444ed5c5SDimitry Andric Depth = Pred->Depth + 1; 1370444ed5c5SDimitry Andric } 1371444ed5c5SDimitry Andric Block->Depth = Depth; 1372444ed5c5SDimitry Andric } 1373444ed5c5SDimitry Andric } 1374444ed5c5SDimitry Andric 1375444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1376444ed5c5SDimitry Andric int BlockIndice = BottomUpIndex2Block[i]; 1377444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1378d88c1a5aSDimitry Andric if (Block->getSuccs().empty()) 1379444ed5c5SDimitry Andric Block->Height = 0; 1380444ed5c5SDimitry Andric else { 1381444ed5c5SDimitry Andric unsigned Height = 0; 13827a7e6055SDimitry Andric for (const auto &Succ : Block->getSuccs()) 13837a7e6055SDimitry Andric Height = std::min(Height, Succ.first->Height + 1); 1384444ed5c5SDimitry Andric Block->Height = Height; 1385444ed5c5SDimitry Andric } 1386444ed5c5SDimitry Andric } 1387444ed5c5SDimitry Andric } 1388444ed5c5SDimitry Andric 1389444ed5c5SDimitry Andric // SIScheduleBlockScheduler // 1390444ed5c5SDimitry Andric 1391444ed5c5SDimitry Andric SIScheduleBlockScheduler::SIScheduleBlockScheduler(SIScheduleDAGMI *DAG, 1392444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant Variant, 1393444ed5c5SDimitry Andric SIScheduleBlocks BlocksStruct) : 1394444ed5c5SDimitry Andric DAG(DAG), Variant(Variant), Blocks(BlocksStruct.Blocks), 1395444ed5c5SDimitry Andric LastPosWaitedHighLatency(0), NumBlockScheduled(0), VregCurrentUsage(0), 1396444ed5c5SDimitry Andric SregCurrentUsage(0), maxVregUsage(0), maxSregUsage(0) { 1397444ed5c5SDimitry Andric 1398444ed5c5SDimitry Andric // Fill the usage of every output 1399444ed5c5SDimitry Andric // Warning: while by construction we always have a link between two blocks 1400444ed5c5SDimitry Andric // when one needs a result from the other, the number of users of an output 1401444ed5c5SDimitry Andric // is not the sum of child blocks having as input the same virtual register. 1402444ed5c5SDimitry Andric // Here is an example. A produces x and y. B eats x and produces x'. 1403444ed5c5SDimitry Andric // C eats x' and y. The register coalescer may have attributed the same 1404444ed5c5SDimitry Andric // virtual register to x and x'. 1405444ed5c5SDimitry Andric // To count accurately, we do a topological sort. In case the register is 1406444ed5c5SDimitry Andric // found for several parents, we increment the usage of the one with the 1407444ed5c5SDimitry Andric // highest topological index. 1408444ed5c5SDimitry Andric LiveOutRegsNumUsages.resize(Blocks.size()); 1409444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1410444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1411444ed5c5SDimitry Andric for (unsigned Reg : Block->getInRegs()) { 1412444ed5c5SDimitry Andric bool Found = false; 1413444ed5c5SDimitry Andric int topoInd = -1; 1414444ed5c5SDimitry Andric for (SIScheduleBlock* Pred: Block->getPreds()) { 1415444ed5c5SDimitry Andric std::set<unsigned> PredOutRegs = Pred->getOutRegs(); 1416444ed5c5SDimitry Andric std::set<unsigned>::iterator RegPos = PredOutRegs.find(Reg); 1417444ed5c5SDimitry Andric 1418444ed5c5SDimitry Andric if (RegPos != PredOutRegs.end()) { 1419444ed5c5SDimitry Andric Found = true; 1420444ed5c5SDimitry Andric if (topoInd < BlocksStruct.TopDownBlock2Index[Pred->getID()]) { 1421444ed5c5SDimitry Andric topoInd = BlocksStruct.TopDownBlock2Index[Pred->getID()]; 1422444ed5c5SDimitry Andric } 1423444ed5c5SDimitry Andric } 1424444ed5c5SDimitry Andric } 1425444ed5c5SDimitry Andric 1426444ed5c5SDimitry Andric if (!Found) 1427444ed5c5SDimitry Andric continue; 1428444ed5c5SDimitry Andric 1429444ed5c5SDimitry Andric int PredID = BlocksStruct.TopDownIndex2Block[topoInd]; 1430444ed5c5SDimitry Andric ++LiveOutRegsNumUsages[PredID][Reg]; 1431444ed5c5SDimitry Andric } 1432444ed5c5SDimitry Andric } 1433444ed5c5SDimitry Andric 1434444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled.resize(Blocks.size(), 0); 1435444ed5c5SDimitry Andric BlockNumPredsLeft.resize(Blocks.size()); 1436444ed5c5SDimitry Andric BlockNumSuccsLeft.resize(Blocks.size()); 1437444ed5c5SDimitry Andric 1438444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1439444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1440444ed5c5SDimitry Andric BlockNumPredsLeft[i] = Block->getPreds().size(); 1441444ed5c5SDimitry Andric BlockNumSuccsLeft[i] = Block->getSuccs().size(); 1442444ed5c5SDimitry Andric } 1443444ed5c5SDimitry Andric 1444444ed5c5SDimitry Andric #ifndef NDEBUG 1445444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1446444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1447444ed5c5SDimitry Andric assert(Block->getID() == i); 1448444ed5c5SDimitry Andric } 1449444ed5c5SDimitry Andric #endif 1450444ed5c5SDimitry Andric 1451444ed5c5SDimitry Andric std::set<unsigned> InRegs = DAG->getInRegs(); 1452444ed5c5SDimitry Andric addLiveRegs(InRegs); 1453444ed5c5SDimitry Andric 14547a7e6055SDimitry Andric // Increase LiveOutRegsNumUsages for blocks 14557a7e6055SDimitry Andric // producing registers consumed in another 14567a7e6055SDimitry Andric // scheduling region. 14577a7e6055SDimitry Andric for (unsigned Reg : DAG->getOutRegs()) { 14587a7e6055SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 14597a7e6055SDimitry Andric // Do reverse traversal 14607a7e6055SDimitry Andric int ID = BlocksStruct.TopDownIndex2Block[Blocks.size()-1-i]; 14617a7e6055SDimitry Andric SIScheduleBlock *Block = Blocks[ID]; 14627a7e6055SDimitry Andric const std::set<unsigned> &OutRegs = Block->getOutRegs(); 14637a7e6055SDimitry Andric 14647a7e6055SDimitry Andric if (OutRegs.find(Reg) == OutRegs.end()) 14657a7e6055SDimitry Andric continue; 14667a7e6055SDimitry Andric 14677a7e6055SDimitry Andric ++LiveOutRegsNumUsages[ID][Reg]; 14687a7e6055SDimitry Andric break; 14697a7e6055SDimitry Andric } 14707a7e6055SDimitry Andric } 14717a7e6055SDimitry Andric 1472444ed5c5SDimitry Andric // Fill LiveRegsConsumers for regs that were already 1473444ed5c5SDimitry Andric // defined before scheduling. 1474444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1475444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1476444ed5c5SDimitry Andric for (unsigned Reg : Block->getInRegs()) { 1477444ed5c5SDimitry Andric bool Found = false; 1478444ed5c5SDimitry Andric for (SIScheduleBlock* Pred: Block->getPreds()) { 1479444ed5c5SDimitry Andric std::set<unsigned> PredOutRegs = Pred->getOutRegs(); 1480444ed5c5SDimitry Andric std::set<unsigned>::iterator RegPos = PredOutRegs.find(Reg); 1481444ed5c5SDimitry Andric 1482444ed5c5SDimitry Andric if (RegPos != PredOutRegs.end()) { 1483444ed5c5SDimitry Andric Found = true; 1484444ed5c5SDimitry Andric break; 1485444ed5c5SDimitry Andric } 1486444ed5c5SDimitry Andric } 1487444ed5c5SDimitry Andric 14887a7e6055SDimitry Andric if (!Found) 1489444ed5c5SDimitry Andric ++LiveRegsConsumers[Reg]; 1490444ed5c5SDimitry Andric } 1491444ed5c5SDimitry Andric } 1492444ed5c5SDimitry Andric 1493444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1494444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1495444ed5c5SDimitry Andric if (BlockNumPredsLeft[i] == 0) { 1496444ed5c5SDimitry Andric ReadyBlocks.push_back(Block); 1497444ed5c5SDimitry Andric } 1498444ed5c5SDimitry Andric } 1499444ed5c5SDimitry Andric 1500444ed5c5SDimitry Andric while (SIScheduleBlock *Block = pickBlock()) { 1501444ed5c5SDimitry Andric BlocksScheduled.push_back(Block); 1502444ed5c5SDimitry Andric blockScheduled(Block); 1503444ed5c5SDimitry Andric } 1504444ed5c5SDimitry Andric 1505444ed5c5SDimitry Andric DEBUG( 1506444ed5c5SDimitry Andric dbgs() << "Block Order:"; 1507444ed5c5SDimitry Andric for (SIScheduleBlock* Block : BlocksScheduled) { 1508444ed5c5SDimitry Andric dbgs() << ' ' << Block->getID(); 1509444ed5c5SDimitry Andric } 15107a7e6055SDimitry Andric dbgs() << '\n'; 1511444ed5c5SDimitry Andric ); 1512444ed5c5SDimitry Andric } 1513444ed5c5SDimitry Andric 1514444ed5c5SDimitry Andric bool SIScheduleBlockScheduler::tryCandidateLatency(SIBlockSchedCandidate &Cand, 1515444ed5c5SDimitry Andric SIBlockSchedCandidate &TryCand) { 1516444ed5c5SDimitry Andric if (!Cand.isValid()) { 1517444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 1518444ed5c5SDimitry Andric return true; 1519444ed5c5SDimitry Andric } 1520444ed5c5SDimitry Andric 1521444ed5c5SDimitry Andric // Try to hide high latencies. 1522444ed5c5SDimitry Andric if (tryLess(TryCand.LastPosHighLatParentScheduled, 1523444ed5c5SDimitry Andric Cand.LastPosHighLatParentScheduled, TryCand, Cand, Latency)) 1524444ed5c5SDimitry Andric return true; 1525444ed5c5SDimitry Andric // Schedule high latencies early so you can hide them better. 1526444ed5c5SDimitry Andric if (tryGreater(TryCand.IsHighLatency, Cand.IsHighLatency, 1527444ed5c5SDimitry Andric TryCand, Cand, Latency)) 1528444ed5c5SDimitry Andric return true; 1529444ed5c5SDimitry Andric if (TryCand.IsHighLatency && tryGreater(TryCand.Height, Cand.Height, 1530444ed5c5SDimitry Andric TryCand, Cand, Depth)) 1531444ed5c5SDimitry Andric return true; 1532444ed5c5SDimitry Andric if (tryGreater(TryCand.NumHighLatencySuccessors, 1533444ed5c5SDimitry Andric Cand.NumHighLatencySuccessors, 1534444ed5c5SDimitry Andric TryCand, Cand, Successor)) 1535444ed5c5SDimitry Andric return true; 1536444ed5c5SDimitry Andric return false; 1537444ed5c5SDimitry Andric } 1538444ed5c5SDimitry Andric 1539444ed5c5SDimitry Andric bool SIScheduleBlockScheduler::tryCandidateRegUsage(SIBlockSchedCandidate &Cand, 1540444ed5c5SDimitry Andric SIBlockSchedCandidate &TryCand) { 1541444ed5c5SDimitry Andric if (!Cand.isValid()) { 1542444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 1543444ed5c5SDimitry Andric return true; 1544444ed5c5SDimitry Andric } 1545444ed5c5SDimitry Andric 1546444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsageDiff > 0, Cand.VGPRUsageDiff > 0, 1547444ed5c5SDimitry Andric TryCand, Cand, RegUsage)) 1548444ed5c5SDimitry Andric return true; 1549444ed5c5SDimitry Andric if (tryGreater(TryCand.NumSuccessors > 0, 1550444ed5c5SDimitry Andric Cand.NumSuccessors > 0, 1551444ed5c5SDimitry Andric TryCand, Cand, Successor)) 1552444ed5c5SDimitry Andric return true; 1553444ed5c5SDimitry Andric if (tryGreater(TryCand.Height, Cand.Height, TryCand, Cand, Depth)) 1554444ed5c5SDimitry Andric return true; 1555444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsageDiff, Cand.VGPRUsageDiff, 1556444ed5c5SDimitry Andric TryCand, Cand, RegUsage)) 1557444ed5c5SDimitry Andric return true; 1558444ed5c5SDimitry Andric return false; 1559444ed5c5SDimitry Andric } 1560444ed5c5SDimitry Andric 1561444ed5c5SDimitry Andric SIScheduleBlock *SIScheduleBlockScheduler::pickBlock() { 1562444ed5c5SDimitry Andric SIBlockSchedCandidate Cand; 1563444ed5c5SDimitry Andric std::vector<SIScheduleBlock*>::iterator Best; 1564444ed5c5SDimitry Andric SIScheduleBlock *Block; 1565444ed5c5SDimitry Andric if (ReadyBlocks.empty()) 1566444ed5c5SDimitry Andric return nullptr; 1567444ed5c5SDimitry Andric 1568444ed5c5SDimitry Andric DAG->fillVgprSgprCost(LiveRegs.begin(), LiveRegs.end(), 1569444ed5c5SDimitry Andric VregCurrentUsage, SregCurrentUsage); 1570444ed5c5SDimitry Andric if (VregCurrentUsage > maxVregUsage) 1571444ed5c5SDimitry Andric maxVregUsage = VregCurrentUsage; 15727a7e6055SDimitry Andric if (SregCurrentUsage > maxSregUsage) 15737a7e6055SDimitry Andric maxSregUsage = SregCurrentUsage; 1574444ed5c5SDimitry Andric DEBUG( 1575444ed5c5SDimitry Andric dbgs() << "Picking New Blocks\n"; 1576444ed5c5SDimitry Andric dbgs() << "Available: "; 1577444ed5c5SDimitry Andric for (SIScheduleBlock* Block : ReadyBlocks) 1578444ed5c5SDimitry Andric dbgs() << Block->getID() << ' '; 1579444ed5c5SDimitry Andric dbgs() << "\nCurrent Live:\n"; 1580444ed5c5SDimitry Andric for (unsigned Reg : LiveRegs) 1581444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 1582444ed5c5SDimitry Andric dbgs() << '\n'; 1583444ed5c5SDimitry Andric dbgs() << "Current VGPRs: " << VregCurrentUsage << '\n'; 1584444ed5c5SDimitry Andric dbgs() << "Current SGPRs: " << SregCurrentUsage << '\n'; 1585444ed5c5SDimitry Andric ); 1586444ed5c5SDimitry Andric 1587444ed5c5SDimitry Andric Cand.Block = nullptr; 1588444ed5c5SDimitry Andric for (std::vector<SIScheduleBlock*>::iterator I = ReadyBlocks.begin(), 1589444ed5c5SDimitry Andric E = ReadyBlocks.end(); I != E; ++I) { 1590444ed5c5SDimitry Andric SIBlockSchedCandidate TryCand; 1591444ed5c5SDimitry Andric TryCand.Block = *I; 1592444ed5c5SDimitry Andric TryCand.IsHighLatency = TryCand.Block->isHighLatencyBlock(); 1593444ed5c5SDimitry Andric TryCand.VGPRUsageDiff = 1594444ed5c5SDimitry Andric checkRegUsageImpact(TryCand.Block->getInRegs(), 1595444ed5c5SDimitry Andric TryCand.Block->getOutRegs())[DAG->getVGPRSetID()]; 1596444ed5c5SDimitry Andric TryCand.NumSuccessors = TryCand.Block->getSuccs().size(); 1597444ed5c5SDimitry Andric TryCand.NumHighLatencySuccessors = 1598444ed5c5SDimitry Andric TryCand.Block->getNumHighLatencySuccessors(); 1599444ed5c5SDimitry Andric TryCand.LastPosHighLatParentScheduled = 1600444ed5c5SDimitry Andric (unsigned int) std::max<int> (0, 1601444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[TryCand.Block->getID()] - 1602444ed5c5SDimitry Andric LastPosWaitedHighLatency); 1603444ed5c5SDimitry Andric TryCand.Height = TryCand.Block->Height; 1604444ed5c5SDimitry Andric // Try not to increase VGPR usage too much, else we may spill. 1605444ed5c5SDimitry Andric if (VregCurrentUsage > 120 || 1606444ed5c5SDimitry Andric Variant != SISchedulerBlockSchedulerVariant::BlockLatencyRegUsage) { 1607444ed5c5SDimitry Andric if (!tryCandidateRegUsage(Cand, TryCand) && 1608444ed5c5SDimitry Andric Variant != SISchedulerBlockSchedulerVariant::BlockRegUsage) 1609444ed5c5SDimitry Andric tryCandidateLatency(Cand, TryCand); 1610444ed5c5SDimitry Andric } else { 1611444ed5c5SDimitry Andric if (!tryCandidateLatency(Cand, TryCand)) 1612444ed5c5SDimitry Andric tryCandidateRegUsage(Cand, TryCand); 1613444ed5c5SDimitry Andric } 1614444ed5c5SDimitry Andric if (TryCand.Reason != NoCand) { 1615444ed5c5SDimitry Andric Cand.setBest(TryCand); 1616444ed5c5SDimitry Andric Best = I; 1617444ed5c5SDimitry Andric DEBUG(dbgs() << "Best Current Choice: " << Cand.Block->getID() << ' ' 1618444ed5c5SDimitry Andric << getReasonStr(Cand.Reason) << '\n'); 1619444ed5c5SDimitry Andric } 1620444ed5c5SDimitry Andric } 1621444ed5c5SDimitry Andric 1622444ed5c5SDimitry Andric DEBUG( 1623444ed5c5SDimitry Andric dbgs() << "Picking: " << Cand.Block->getID() << '\n'; 1624444ed5c5SDimitry Andric dbgs() << "Is a block with high latency instruction: " 1625444ed5c5SDimitry Andric << (Cand.IsHighLatency ? "yes\n" : "no\n"); 1626444ed5c5SDimitry Andric dbgs() << "Position of last high latency dependency: " 1627444ed5c5SDimitry Andric << Cand.LastPosHighLatParentScheduled << '\n'; 1628444ed5c5SDimitry Andric dbgs() << "VGPRUsageDiff: " << Cand.VGPRUsageDiff << '\n'; 1629444ed5c5SDimitry Andric dbgs() << '\n'; 1630444ed5c5SDimitry Andric ); 1631444ed5c5SDimitry Andric 1632444ed5c5SDimitry Andric Block = Cand.Block; 1633444ed5c5SDimitry Andric ReadyBlocks.erase(Best); 1634444ed5c5SDimitry Andric return Block; 1635444ed5c5SDimitry Andric } 1636444ed5c5SDimitry Andric 1637444ed5c5SDimitry Andric // Tracking of currently alive registers to determine VGPR Usage. 1638444ed5c5SDimitry Andric 1639444ed5c5SDimitry Andric void SIScheduleBlockScheduler::addLiveRegs(std::set<unsigned> &Regs) { 1640444ed5c5SDimitry Andric for (unsigned Reg : Regs) { 1641444ed5c5SDimitry Andric // For now only track virtual registers. 1642444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1643444ed5c5SDimitry Andric continue; 1644444ed5c5SDimitry Andric // If not already in the live set, then add it. 1645444ed5c5SDimitry Andric (void) LiveRegs.insert(Reg); 1646444ed5c5SDimitry Andric } 1647444ed5c5SDimitry Andric } 1648444ed5c5SDimitry Andric 1649444ed5c5SDimitry Andric void SIScheduleBlockScheduler::decreaseLiveRegs(SIScheduleBlock *Block, 1650444ed5c5SDimitry Andric std::set<unsigned> &Regs) { 1651444ed5c5SDimitry Andric for (unsigned Reg : Regs) { 1652444ed5c5SDimitry Andric // For now only track virtual registers. 1653444ed5c5SDimitry Andric std::set<unsigned>::iterator Pos = LiveRegs.find(Reg); 1654444ed5c5SDimitry Andric assert (Pos != LiveRegs.end() && // Reg must be live. 1655444ed5c5SDimitry Andric LiveRegsConsumers.find(Reg) != LiveRegsConsumers.end() && 1656444ed5c5SDimitry Andric LiveRegsConsumers[Reg] >= 1); 1657444ed5c5SDimitry Andric --LiveRegsConsumers[Reg]; 1658444ed5c5SDimitry Andric if (LiveRegsConsumers[Reg] == 0) 1659444ed5c5SDimitry Andric LiveRegs.erase(Pos); 1660444ed5c5SDimitry Andric } 1661444ed5c5SDimitry Andric } 1662444ed5c5SDimitry Andric 1663444ed5c5SDimitry Andric void SIScheduleBlockScheduler::releaseBlockSuccs(SIScheduleBlock *Parent) { 16647a7e6055SDimitry Andric for (const auto &Block : Parent->getSuccs()) { 16657a7e6055SDimitry Andric if (--BlockNumPredsLeft[Block.first->getID()] == 0) 16667a7e6055SDimitry Andric ReadyBlocks.push_back(Block.first); 16677a7e6055SDimitry Andric 16687a7e6055SDimitry Andric if (Parent->isHighLatencyBlock() && 16697a7e6055SDimitry Andric Block.second == SIScheduleBlockLinkKind::Data) 16707a7e6055SDimitry Andric LastPosHighLatencyParentScheduled[Block.first->getID()] = NumBlockScheduled; 1671444ed5c5SDimitry Andric } 1672444ed5c5SDimitry Andric } 1673444ed5c5SDimitry Andric 1674444ed5c5SDimitry Andric void SIScheduleBlockScheduler::blockScheduled(SIScheduleBlock *Block) { 1675444ed5c5SDimitry Andric decreaseLiveRegs(Block, Block->getInRegs()); 1676444ed5c5SDimitry Andric addLiveRegs(Block->getOutRegs()); 1677444ed5c5SDimitry Andric releaseBlockSuccs(Block); 1678444ed5c5SDimitry Andric for (std::map<unsigned, unsigned>::iterator RegI = 1679444ed5c5SDimitry Andric LiveOutRegsNumUsages[Block->getID()].begin(), 1680444ed5c5SDimitry Andric E = LiveOutRegsNumUsages[Block->getID()].end(); RegI != E; ++RegI) { 1681444ed5c5SDimitry Andric std::pair<unsigned, unsigned> RegP = *RegI; 16827a7e6055SDimitry Andric // We produce this register, thus it must not be previously alive. 16837a7e6055SDimitry Andric assert(LiveRegsConsumers.find(RegP.first) == LiveRegsConsumers.end() || 16847a7e6055SDimitry Andric LiveRegsConsumers[RegP.first] == 0); 1685444ed5c5SDimitry Andric LiveRegsConsumers[RegP.first] += RegP.second; 1686444ed5c5SDimitry Andric } 1687444ed5c5SDimitry Andric if (LastPosHighLatencyParentScheduled[Block->getID()] > 1688444ed5c5SDimitry Andric (unsigned)LastPosWaitedHighLatency) 1689444ed5c5SDimitry Andric LastPosWaitedHighLatency = 1690444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[Block->getID()]; 1691444ed5c5SDimitry Andric ++NumBlockScheduled; 1692444ed5c5SDimitry Andric } 1693444ed5c5SDimitry Andric 1694444ed5c5SDimitry Andric std::vector<int> 1695444ed5c5SDimitry Andric SIScheduleBlockScheduler::checkRegUsageImpact(std::set<unsigned> &InRegs, 1696444ed5c5SDimitry Andric std::set<unsigned> &OutRegs) { 1697444ed5c5SDimitry Andric std::vector<int> DiffSetPressure; 1698444ed5c5SDimitry Andric DiffSetPressure.assign(DAG->getTRI()->getNumRegPressureSets(), 0); 1699444ed5c5SDimitry Andric 1700444ed5c5SDimitry Andric for (unsigned Reg : InRegs) { 1701444ed5c5SDimitry Andric // For now only track virtual registers. 1702444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1703444ed5c5SDimitry Andric continue; 1704444ed5c5SDimitry Andric if (LiveRegsConsumers[Reg] > 1) 1705444ed5c5SDimitry Andric continue; 1706444ed5c5SDimitry Andric PSetIterator PSetI = DAG->getMRI()->getPressureSets(Reg); 1707444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1708444ed5c5SDimitry Andric DiffSetPressure[*PSetI] -= PSetI.getWeight(); 1709444ed5c5SDimitry Andric } 1710444ed5c5SDimitry Andric } 1711444ed5c5SDimitry Andric 1712444ed5c5SDimitry Andric for (unsigned Reg : OutRegs) { 1713444ed5c5SDimitry Andric // For now only track virtual registers. 1714444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1715444ed5c5SDimitry Andric continue; 1716444ed5c5SDimitry Andric PSetIterator PSetI = DAG->getMRI()->getPressureSets(Reg); 1717444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1718444ed5c5SDimitry Andric DiffSetPressure[*PSetI] += PSetI.getWeight(); 1719444ed5c5SDimitry Andric } 1720444ed5c5SDimitry Andric } 1721444ed5c5SDimitry Andric 1722444ed5c5SDimitry Andric return DiffSetPressure; 1723444ed5c5SDimitry Andric } 1724444ed5c5SDimitry Andric 1725444ed5c5SDimitry Andric // SIScheduler // 1726444ed5c5SDimitry Andric 1727444ed5c5SDimitry Andric struct SIScheduleBlockResult 1728444ed5c5SDimitry Andric SIScheduler::scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant, 1729444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant ScheduleVariant) { 1730444ed5c5SDimitry Andric SIScheduleBlocks Blocks = BlockCreator.getBlocks(BlockVariant); 1731444ed5c5SDimitry Andric SIScheduleBlockScheduler Scheduler(DAG, ScheduleVariant, Blocks); 1732444ed5c5SDimitry Andric std::vector<SIScheduleBlock*> ScheduledBlocks; 1733444ed5c5SDimitry Andric struct SIScheduleBlockResult Res; 1734444ed5c5SDimitry Andric 1735444ed5c5SDimitry Andric ScheduledBlocks = Scheduler.getBlocks(); 1736444ed5c5SDimitry Andric 1737444ed5c5SDimitry Andric for (unsigned b = 0; b < ScheduledBlocks.size(); ++b) { 1738444ed5c5SDimitry Andric SIScheduleBlock *Block = ScheduledBlocks[b]; 1739444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1740444ed5c5SDimitry Andric 1741444ed5c5SDimitry Andric for (SUnit* SU : SUs) 1742444ed5c5SDimitry Andric Res.SUs.push_back(SU->NodeNum); 1743444ed5c5SDimitry Andric } 1744444ed5c5SDimitry Andric 1745444ed5c5SDimitry Andric Res.MaxSGPRUsage = Scheduler.getSGPRUsage(); 1746444ed5c5SDimitry Andric Res.MaxVGPRUsage = Scheduler.getVGPRUsage(); 1747444ed5c5SDimitry Andric return Res; 1748444ed5c5SDimitry Andric } 1749444ed5c5SDimitry Andric 1750444ed5c5SDimitry Andric // SIScheduleDAGMI // 1751444ed5c5SDimitry Andric 1752444ed5c5SDimitry Andric SIScheduleDAGMI::SIScheduleDAGMI(MachineSchedContext *C) : 1753d88c1a5aSDimitry Andric ScheduleDAGMILive(C, llvm::make_unique<GenericScheduler>(C)) { 1754444ed5c5SDimitry Andric SITII = static_cast<const SIInstrInfo*>(TII); 1755444ed5c5SDimitry Andric SITRI = static_cast<const SIRegisterInfo*>(TRI); 1756444ed5c5SDimitry Andric 1757d88c1a5aSDimitry Andric VGPRSetID = SITRI->getVGPRPressureSet(); 1758d88c1a5aSDimitry Andric SGPRSetID = SITRI->getSGPRPressureSet(); 1759444ed5c5SDimitry Andric } 1760444ed5c5SDimitry Andric 1761d88c1a5aSDimitry Andric SIScheduleDAGMI::~SIScheduleDAGMI() = default; 1762444ed5c5SDimitry Andric 1763444ed5c5SDimitry Andric // Code adapted from scheduleDAG.cpp 1764444ed5c5SDimitry Andric // Does a topological sort over the SUs. 1765444ed5c5SDimitry Andric // Both TopDown and BottomUp 1766444ed5c5SDimitry Andric void SIScheduleDAGMI::topologicalSort() { 17673ca95b02SDimitry Andric Topo.InitDAGTopologicalSorting(); 1768444ed5c5SDimitry Andric 17693ca95b02SDimitry Andric TopDownIndex2SU = std::vector<int>(Topo.begin(), Topo.end()); 17703ca95b02SDimitry Andric BottomUpIndex2SU = std::vector<int>(Topo.rbegin(), Topo.rend()); 1771444ed5c5SDimitry Andric } 1772444ed5c5SDimitry Andric 1773444ed5c5SDimitry Andric // Move low latencies further from their user without 1774444ed5c5SDimitry Andric // increasing SGPR usage (in general) 1775444ed5c5SDimitry Andric // This is to be replaced by a better pass that would 1776444ed5c5SDimitry Andric // take into account SGPR usage (based on VGPR Usage 1777444ed5c5SDimitry Andric // and the corresponding wavefront count), that would 1778444ed5c5SDimitry Andric // try to merge groups of loads if it make sense, etc 1779444ed5c5SDimitry Andric void SIScheduleDAGMI::moveLowLatencies() { 1780444ed5c5SDimitry Andric unsigned DAGSize = SUnits.size(); 1781444ed5c5SDimitry Andric int LastLowLatencyUser = -1; 1782444ed5c5SDimitry Andric int LastLowLatencyPos = -1; 1783444ed5c5SDimitry Andric 1784444ed5c5SDimitry Andric for (unsigned i = 0, e = ScheduledSUnits.size(); i != e; ++i) { 1785444ed5c5SDimitry Andric SUnit *SU = &SUnits[ScheduledSUnits[i]]; 1786444ed5c5SDimitry Andric bool IsLowLatencyUser = false; 1787444ed5c5SDimitry Andric unsigned MinPos = 0; 1788444ed5c5SDimitry Andric 1789444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 1790444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 17913ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*Pred->getInstr())) { 1792444ed5c5SDimitry Andric IsLowLatencyUser = true; 1793444ed5c5SDimitry Andric } 1794444ed5c5SDimitry Andric if (Pred->NodeNum >= DAGSize) 1795444ed5c5SDimitry Andric continue; 1796444ed5c5SDimitry Andric unsigned PredPos = ScheduledSUnitsInv[Pred->NodeNum]; 1797444ed5c5SDimitry Andric if (PredPos >= MinPos) 1798444ed5c5SDimitry Andric MinPos = PredPos + 1; 1799444ed5c5SDimitry Andric } 1800444ed5c5SDimitry Andric 18013ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*SU->getInstr())) { 1802444ed5c5SDimitry Andric unsigned BestPos = LastLowLatencyUser + 1; 1803444ed5c5SDimitry Andric if ((int)BestPos <= LastLowLatencyPos) 1804444ed5c5SDimitry Andric BestPos = LastLowLatencyPos + 1; 1805444ed5c5SDimitry Andric if (BestPos < MinPos) 1806444ed5c5SDimitry Andric BestPos = MinPos; 1807444ed5c5SDimitry Andric if (BestPos < i) { 1808444ed5c5SDimitry Andric for (unsigned u = i; u > BestPos; --u) { 1809444ed5c5SDimitry Andric ++ScheduledSUnitsInv[ScheduledSUnits[u-1]]; 1810444ed5c5SDimitry Andric ScheduledSUnits[u] = ScheduledSUnits[u-1]; 1811444ed5c5SDimitry Andric } 1812444ed5c5SDimitry Andric ScheduledSUnits[BestPos] = SU->NodeNum; 1813444ed5c5SDimitry Andric ScheduledSUnitsInv[SU->NodeNum] = BestPos; 1814444ed5c5SDimitry Andric } 1815444ed5c5SDimitry Andric LastLowLatencyPos = BestPos; 1816444ed5c5SDimitry Andric if (IsLowLatencyUser) 1817444ed5c5SDimitry Andric LastLowLatencyUser = BestPos; 1818444ed5c5SDimitry Andric } else if (IsLowLatencyUser) { 1819444ed5c5SDimitry Andric LastLowLatencyUser = i; 1820444ed5c5SDimitry Andric // Moves COPY instructions on which depends 1821444ed5c5SDimitry Andric // the low latency instructions too. 1822444ed5c5SDimitry Andric } else if (SU->getInstr()->getOpcode() == AMDGPU::COPY) { 1823444ed5c5SDimitry Andric bool CopyForLowLat = false; 1824444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1825444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 18263ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*Succ->getInstr())) { 1827444ed5c5SDimitry Andric CopyForLowLat = true; 1828444ed5c5SDimitry Andric } 1829444ed5c5SDimitry Andric } 1830444ed5c5SDimitry Andric if (!CopyForLowLat) 1831444ed5c5SDimitry Andric continue; 1832444ed5c5SDimitry Andric if (MinPos < i) { 1833444ed5c5SDimitry Andric for (unsigned u = i; u > MinPos; --u) { 1834444ed5c5SDimitry Andric ++ScheduledSUnitsInv[ScheduledSUnits[u-1]]; 1835444ed5c5SDimitry Andric ScheduledSUnits[u] = ScheduledSUnits[u-1]; 1836444ed5c5SDimitry Andric } 1837444ed5c5SDimitry Andric ScheduledSUnits[MinPos] = SU->NodeNum; 1838444ed5c5SDimitry Andric ScheduledSUnitsInv[SU->NodeNum] = MinPos; 1839444ed5c5SDimitry Andric } 1840444ed5c5SDimitry Andric } 1841444ed5c5SDimitry Andric } 1842444ed5c5SDimitry Andric } 1843444ed5c5SDimitry Andric 1844444ed5c5SDimitry Andric void SIScheduleDAGMI::restoreSULinksLeft() { 1845444ed5c5SDimitry Andric for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { 1846444ed5c5SDimitry Andric SUnits[i].isScheduled = false; 1847444ed5c5SDimitry Andric SUnits[i].WeakPredsLeft = SUnitsLinksBackup[i].WeakPredsLeft; 1848444ed5c5SDimitry Andric SUnits[i].NumPredsLeft = SUnitsLinksBackup[i].NumPredsLeft; 1849444ed5c5SDimitry Andric SUnits[i].WeakSuccsLeft = SUnitsLinksBackup[i].WeakSuccsLeft; 1850444ed5c5SDimitry Andric SUnits[i].NumSuccsLeft = SUnitsLinksBackup[i].NumSuccsLeft; 1851444ed5c5SDimitry Andric } 1852444ed5c5SDimitry Andric } 1853444ed5c5SDimitry Andric 1854444ed5c5SDimitry Andric // Return the Vgpr and Sgpr usage corresponding to some virtual registers. 1855444ed5c5SDimitry Andric template<typename _Iterator> void 1856444ed5c5SDimitry Andric SIScheduleDAGMI::fillVgprSgprCost(_Iterator First, _Iterator End, 1857444ed5c5SDimitry Andric unsigned &VgprUsage, unsigned &SgprUsage) { 1858444ed5c5SDimitry Andric VgprUsage = 0; 1859444ed5c5SDimitry Andric SgprUsage = 0; 1860444ed5c5SDimitry Andric for (_Iterator RegI = First; RegI != End; ++RegI) { 1861444ed5c5SDimitry Andric unsigned Reg = *RegI; 1862444ed5c5SDimitry Andric // For now only track virtual registers 1863444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1864444ed5c5SDimitry Andric continue; 1865444ed5c5SDimitry Andric PSetIterator PSetI = MRI.getPressureSets(Reg); 1866444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1867444ed5c5SDimitry Andric if (*PSetI == VGPRSetID) 1868444ed5c5SDimitry Andric VgprUsage += PSetI.getWeight(); 1869444ed5c5SDimitry Andric else if (*PSetI == SGPRSetID) 1870444ed5c5SDimitry Andric SgprUsage += PSetI.getWeight(); 1871444ed5c5SDimitry Andric } 1872444ed5c5SDimitry Andric } 1873444ed5c5SDimitry Andric } 1874444ed5c5SDimitry Andric 1875444ed5c5SDimitry Andric void SIScheduleDAGMI::schedule() 1876444ed5c5SDimitry Andric { 1877444ed5c5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots; 1878444ed5c5SDimitry Andric SIScheduleBlockResult Best, Temp; 1879444ed5c5SDimitry Andric DEBUG(dbgs() << "Preparing Scheduling\n"); 1880444ed5c5SDimitry Andric 1881444ed5c5SDimitry Andric buildDAGWithRegPressure(); 1882444ed5c5SDimitry Andric DEBUG( 1883444ed5c5SDimitry Andric for(SUnit& SU : SUnits) 1884444ed5c5SDimitry Andric SU.dumpAll(this) 1885444ed5c5SDimitry Andric ); 1886444ed5c5SDimitry Andric 1887444ed5c5SDimitry Andric topologicalSort(); 1888444ed5c5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots); 1889444ed5c5SDimitry Andric // We reuse several ScheduleDAGMI and ScheduleDAGMILive 1890444ed5c5SDimitry Andric // functions, but to make them happy we must initialize 1891444ed5c5SDimitry Andric // the default Scheduler implementation (even if we do not 1892444ed5c5SDimitry Andric // run it) 1893444ed5c5SDimitry Andric SchedImpl->initialize(this); 1894444ed5c5SDimitry Andric initQueues(TopRoots, BotRoots); 1895444ed5c5SDimitry Andric 1896444ed5c5SDimitry Andric // Fill some stats to help scheduling. 1897444ed5c5SDimitry Andric 1898444ed5c5SDimitry Andric SUnitsLinksBackup = SUnits; 1899444ed5c5SDimitry Andric IsLowLatencySU.clear(); 1900444ed5c5SDimitry Andric LowLatencyOffset.clear(); 1901444ed5c5SDimitry Andric IsHighLatencySU.clear(); 1902444ed5c5SDimitry Andric 1903444ed5c5SDimitry Andric IsLowLatencySU.resize(SUnits.size(), 0); 1904444ed5c5SDimitry Andric LowLatencyOffset.resize(SUnits.size(), 0); 1905444ed5c5SDimitry Andric IsHighLatencySU.resize(SUnits.size(), 0); 1906444ed5c5SDimitry Andric 1907444ed5c5SDimitry Andric for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) { 1908444ed5c5SDimitry Andric SUnit *SU = &SUnits[i]; 19093ca95b02SDimitry Andric unsigned BaseLatReg; 19103ca95b02SDimitry Andric int64_t OffLatReg; 19113ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*SU->getInstr())) { 1912444ed5c5SDimitry Andric IsLowLatencySU[i] = 1; 19133ca95b02SDimitry Andric if (SITII->getMemOpBaseRegImmOfs(*SU->getInstr(), BaseLatReg, OffLatReg, 19143ca95b02SDimitry Andric TRI)) 1915444ed5c5SDimitry Andric LowLatencyOffset[i] = OffLatReg; 19163ca95b02SDimitry Andric } else if (SITII->isHighLatencyInstruction(*SU->getInstr())) 1917444ed5c5SDimitry Andric IsHighLatencySU[i] = 1; 1918444ed5c5SDimitry Andric } 1919444ed5c5SDimitry Andric 1920444ed5c5SDimitry Andric SIScheduler Scheduler(this); 1921444ed5c5SDimitry Andric Best = Scheduler.scheduleVariant(SISchedulerBlockCreatorVariant::LatenciesAlone, 1922444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant::BlockLatencyRegUsage); 19233ca95b02SDimitry Andric 1924444ed5c5SDimitry Andric // if VGPR usage is extremely high, try other good performing variants 1925444ed5c5SDimitry Andric // which could lead to lower VGPR usage 1926444ed5c5SDimitry Andric if (Best.MaxVGPRUsage > 180) { 19277a7e6055SDimitry Andric static const std::pair<SISchedulerBlockCreatorVariant, 19287a7e6055SDimitry Andric SISchedulerBlockSchedulerVariant> 19297a7e6055SDimitry Andric Variants[] = { 1930444ed5c5SDimitry Andric { LatenciesAlone, BlockRegUsageLatency }, 1931444ed5c5SDimitry Andric // { LatenciesAlone, BlockRegUsage }, 1932444ed5c5SDimitry Andric { LatenciesGrouped, BlockLatencyRegUsage }, 1933444ed5c5SDimitry Andric // { LatenciesGrouped, BlockRegUsageLatency }, 1934444ed5c5SDimitry Andric // { LatenciesGrouped, BlockRegUsage }, 1935444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage }, 1936444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockRegUsageLatency }, 1937444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockRegUsage } 1938444ed5c5SDimitry Andric }; 1939444ed5c5SDimitry Andric for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) { 1940444ed5c5SDimitry Andric Temp = Scheduler.scheduleVariant(v.first, v.second); 1941444ed5c5SDimitry Andric if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage) 1942444ed5c5SDimitry Andric Best = Temp; 1943444ed5c5SDimitry Andric } 1944444ed5c5SDimitry Andric } 1945444ed5c5SDimitry Andric // if VGPR usage is still extremely high, we may spill. Try other variants 1946444ed5c5SDimitry Andric // which are less performing, but that could lead to lower VGPR usage. 1947444ed5c5SDimitry Andric if (Best.MaxVGPRUsage > 200) { 19487a7e6055SDimitry Andric static const std::pair<SISchedulerBlockCreatorVariant, 19497a7e6055SDimitry Andric SISchedulerBlockSchedulerVariant> 19507a7e6055SDimitry Andric Variants[] = { 1951444ed5c5SDimitry Andric // { LatenciesAlone, BlockRegUsageLatency }, 1952444ed5c5SDimitry Andric { LatenciesAlone, BlockRegUsage }, 1953444ed5c5SDimitry Andric // { LatenciesGrouped, BlockLatencyRegUsage }, 1954444ed5c5SDimitry Andric { LatenciesGrouped, BlockRegUsageLatency }, 1955444ed5c5SDimitry Andric { LatenciesGrouped, BlockRegUsage }, 1956444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage }, 1957444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockRegUsageLatency }, 1958444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockRegUsage } 1959444ed5c5SDimitry Andric }; 1960444ed5c5SDimitry Andric for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) { 1961444ed5c5SDimitry Andric Temp = Scheduler.scheduleVariant(v.first, v.second); 1962444ed5c5SDimitry Andric if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage) 1963444ed5c5SDimitry Andric Best = Temp; 1964444ed5c5SDimitry Andric } 1965444ed5c5SDimitry Andric } 19663ca95b02SDimitry Andric 1967444ed5c5SDimitry Andric ScheduledSUnits = Best.SUs; 1968444ed5c5SDimitry Andric ScheduledSUnitsInv.resize(SUnits.size()); 1969444ed5c5SDimitry Andric 1970444ed5c5SDimitry Andric for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) { 1971444ed5c5SDimitry Andric ScheduledSUnitsInv[ScheduledSUnits[i]] = i; 1972444ed5c5SDimitry Andric } 1973444ed5c5SDimitry Andric 1974444ed5c5SDimitry Andric moveLowLatencies(); 1975444ed5c5SDimitry Andric 1976444ed5c5SDimitry Andric // Tell the outside world about the result of the scheduling. 1977444ed5c5SDimitry Andric 1978444ed5c5SDimitry Andric assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker"); 1979444ed5c5SDimitry Andric TopRPTracker.setPos(CurrentTop); 1980444ed5c5SDimitry Andric 1981444ed5c5SDimitry Andric for (std::vector<unsigned>::iterator I = ScheduledSUnits.begin(), 1982444ed5c5SDimitry Andric E = ScheduledSUnits.end(); I != E; ++I) { 1983444ed5c5SDimitry Andric SUnit *SU = &SUnits[*I]; 1984444ed5c5SDimitry Andric 1985444ed5c5SDimitry Andric scheduleMI(SU, true); 1986444ed5c5SDimitry Andric 1987444ed5c5SDimitry Andric DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " 1988444ed5c5SDimitry Andric << *SU->getInstr()); 1989444ed5c5SDimitry Andric } 1990444ed5c5SDimitry Andric 1991444ed5c5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); 1992444ed5c5SDimitry Andric 1993444ed5c5SDimitry Andric placeDebugValues(); 1994444ed5c5SDimitry Andric 1995444ed5c5SDimitry Andric DEBUG({ 1996444ed5c5SDimitry Andric unsigned BBNum = begin()->getParent()->getNumber(); 1997444ed5c5SDimitry Andric dbgs() << "*** Final schedule for BB#" << BBNum << " ***\n"; 1998444ed5c5SDimitry Andric dumpSchedule(); 1999444ed5c5SDimitry Andric dbgs() << '\n'; 2000444ed5c5SDimitry Andric }); 2001444ed5c5SDimitry Andric } 2002