1444ed5c5SDimitry Andric //===-- SIMachineScheduler.cpp - SI Scheduler Interface -*- C++ -*-----===// 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 15444ed5c5SDimitry Andric #include "SIMachineScheduler.h" 16444ed5c5SDimitry Andric #include "AMDGPUSubtarget.h" 17444ed5c5SDimitry Andric #include "llvm/CodeGen/LiveInterval.h" 18444ed5c5SDimitry Andric #include "llvm/CodeGen/LiveIntervalAnalysis.h" 19444ed5c5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 20444ed5c5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 21444ed5c5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h" 22444ed5c5SDimitry Andric 23444ed5c5SDimitry Andric using namespace llvm; 24444ed5c5SDimitry Andric 25444ed5c5SDimitry Andric #define DEBUG_TYPE "misched" 26444ed5c5SDimitry Andric 27444ed5c5SDimitry Andric // This scheduler implements a different scheduling algorithm than 28444ed5c5SDimitry Andric // GenericScheduler. 29444ed5c5SDimitry Andric // 30444ed5c5SDimitry Andric // There are several specific architecture behaviours that can't be modelled 31444ed5c5SDimitry Andric // for GenericScheduler: 32444ed5c5SDimitry Andric // . When accessing the result of an SGPR load instruction, you have to wait 33444ed5c5SDimitry Andric // for all the SGPR load instructions before your current instruction to 34444ed5c5SDimitry Andric // have finished. 35444ed5c5SDimitry Andric // . When accessing the result of an VGPR load instruction, you have to wait 36444ed5c5SDimitry Andric // for all the VGPR load instructions previous to the VGPR load instruction 37444ed5c5SDimitry Andric // you are interested in to finish. 38444ed5c5SDimitry Andric // . The less the register pressure, the best load latencies are hidden 39444ed5c5SDimitry Andric // 40444ed5c5SDimitry Andric // Moreover some specifities (like the fact a lot of instructions in the shader 41444ed5c5SDimitry Andric // have few dependencies) makes the generic scheduler have some unpredictable 42444ed5c5SDimitry Andric // behaviours. For example when register pressure becomes high, it can either 43444ed5c5SDimitry Andric // manage to prevent register pressure from going too high, or it can 44444ed5c5SDimitry Andric // increase register pressure even more than if it hadn't taken register 45444ed5c5SDimitry Andric // pressure into account. 46444ed5c5SDimitry Andric // 47444ed5c5SDimitry Andric // Also some other bad behaviours are generated, like loading at the beginning 48444ed5c5SDimitry Andric // of the shader a constant in VGPR you won't need until the end of the shader. 49444ed5c5SDimitry Andric // 50444ed5c5SDimitry Andric // The scheduling problem for SI can distinguish three main parts: 51444ed5c5SDimitry Andric // . Hiding high latencies (texture sampling, etc) 52444ed5c5SDimitry Andric // . Hiding low latencies (SGPR constant loading, etc) 53444ed5c5SDimitry Andric // . Keeping register usage low for better latency hiding and general 54444ed5c5SDimitry Andric // performance 55444ed5c5SDimitry Andric // 56444ed5c5SDimitry Andric // Some other things can also affect performance, but are hard to predict 57444ed5c5SDimitry Andric // (cache usage, the fact the HW can issue several instructions from different 58444ed5c5SDimitry Andric // wavefronts if different types, etc) 59444ed5c5SDimitry Andric // 60444ed5c5SDimitry Andric // This scheduler tries to solve the scheduling problem by dividing it into 61444ed5c5SDimitry Andric // simpler sub-problems. It divides the instructions into blocks, schedules 62444ed5c5SDimitry Andric // locally inside the blocks where it takes care of low latencies, and then 63444ed5c5SDimitry Andric // chooses the order of the blocks by taking care of high latencies. 64444ed5c5SDimitry Andric // Dividing the instructions into blocks helps control keeping register 65444ed5c5SDimitry Andric // usage low. 66444ed5c5SDimitry Andric // 67444ed5c5SDimitry Andric // First the instructions are put into blocks. 68444ed5c5SDimitry Andric // We want the blocks help control register usage and hide high latencies 69444ed5c5SDimitry Andric // later. To help control register usage, we typically want all local 70444ed5c5SDimitry Andric // computations, when for example you create a result that can be comsummed 71444ed5c5SDimitry Andric // right away, to be contained in a block. Block inputs and outputs would 72444ed5c5SDimitry Andric // typically be important results that are needed in several locations of 73444ed5c5SDimitry Andric // the shader. Since we do want blocks to help hide high latencies, we want 74444ed5c5SDimitry Andric // the instructions inside the block to have a minimal set of dependencies 75444ed5c5SDimitry Andric // on high latencies. It will make it easy to pick blocks to hide specific 76444ed5c5SDimitry Andric // high latencies. 77444ed5c5SDimitry Andric // The block creation algorithm is divided into several steps, and several 78444ed5c5SDimitry Andric // variants can be tried during the scheduling process. 79444ed5c5SDimitry Andric // 80444ed5c5SDimitry Andric // Second the order of the instructions inside the blocks is choosen. 81444ed5c5SDimitry Andric // At that step we do take into account only register usage and hiding 82444ed5c5SDimitry Andric // low latency instructions 83444ed5c5SDimitry Andric // 84444ed5c5SDimitry Andric // Third the block order is choosen, there we try to hide high latencies 85444ed5c5SDimitry Andric // and keep register usage low. 86444ed5c5SDimitry Andric // 87444ed5c5SDimitry Andric // After the third step, a pass is done to improve the hiding of low 88444ed5c5SDimitry Andric // latencies. 89444ed5c5SDimitry Andric // 90444ed5c5SDimitry Andric // Actually when talking about 'low latency' or 'high latency' it includes 91444ed5c5SDimitry Andric // both the latency to get the cache (or global mem) data go to the register, 92444ed5c5SDimitry Andric // and the bandwith limitations. 93444ed5c5SDimitry Andric // Increasing the number of active wavefronts helps hide the former, but it 94444ed5c5SDimitry Andric // doesn't solve the latter, thus why even if wavefront count is high, we have 95444ed5c5SDimitry Andric // to try have as many instructions hiding high latencies as possible. 96444ed5c5SDimitry Andric // The OpenCL doc says for example latency of 400 cycles for a global mem access, 97444ed5c5SDimitry Andric // which is hidden by 10 instructions if the wavefront count is 10. 98444ed5c5SDimitry Andric 99444ed5c5SDimitry Andric // Some figures taken from AMD docs: 100444ed5c5SDimitry Andric // Both texture and constant L1 caches are 4-way associative with 64 bytes 101444ed5c5SDimitry Andric // lines. 102444ed5c5SDimitry Andric // Constant cache is shared with 4 CUs. 103444ed5c5SDimitry Andric // For texture sampling, the address generation unit receives 4 texture 104444ed5c5SDimitry Andric // addresses per cycle, thus we could expect texture sampling latency to be 105444ed5c5SDimitry Andric // equivalent to 4 instructions in the very best case (a VGPR is 64 work items, 106444ed5c5SDimitry Andric // instructions in a wavefront group are executed every 4 cycles), 107444ed5c5SDimitry Andric // or 16 instructions if the other wavefronts associated to the 3 other VALUs 108444ed5c5SDimitry Andric // of the CU do texture sampling too. (Don't take these figures too seriously, 109444ed5c5SDimitry Andric // as I'm not 100% sure of the computation) 110444ed5c5SDimitry Andric // Data exports should get similar latency. 111444ed5c5SDimitry Andric // For constant loading, the cache is shader with 4 CUs. 112444ed5c5SDimitry Andric // The doc says "a throughput of 16B/cycle for each of the 4 Compute Unit" 113444ed5c5SDimitry Andric // I guess if the other CU don't read the cache, it can go up to 64B/cycle. 114444ed5c5SDimitry Andric // It means a simple s_buffer_load should take one instruction to hide, as 115444ed5c5SDimitry Andric // well as a s_buffer_loadx2 and potentially a s_buffer_loadx8 if on the same 116444ed5c5SDimitry Andric // cache line. 117444ed5c5SDimitry Andric // 118444ed5c5SDimitry Andric // As of today the driver doesn't preload the constants in cache, thus the 119444ed5c5SDimitry Andric // first loads get extra latency. The doc says global memory access can be 120444ed5c5SDimitry Andric // 300-600 cycles. We do not specially take that into account when scheduling 121444ed5c5SDimitry Andric // As we expect the driver to be able to preload the constants soon. 122444ed5c5SDimitry Andric 123444ed5c5SDimitry Andric 124444ed5c5SDimitry Andric // common code // 125444ed5c5SDimitry Andric 126444ed5c5SDimitry Andric #ifndef NDEBUG 127444ed5c5SDimitry Andric 128444ed5c5SDimitry Andric static const char *getReasonStr(SIScheduleCandReason Reason) { 129444ed5c5SDimitry Andric switch (Reason) { 130444ed5c5SDimitry Andric case NoCand: return "NOCAND"; 131444ed5c5SDimitry Andric case RegUsage: return "REGUSAGE"; 132444ed5c5SDimitry Andric case Latency: return "LATENCY"; 133444ed5c5SDimitry Andric case Successor: return "SUCCESSOR"; 134444ed5c5SDimitry Andric case Depth: return "DEPTH"; 135444ed5c5SDimitry Andric case NodeOrder: return "ORDER"; 136444ed5c5SDimitry Andric } 137444ed5c5SDimitry Andric llvm_unreachable("Unknown reason!"); 138444ed5c5SDimitry Andric } 139444ed5c5SDimitry Andric 140444ed5c5SDimitry Andric #endif 141444ed5c5SDimitry Andric 142444ed5c5SDimitry Andric static bool tryLess(int TryVal, int CandVal, 143444ed5c5SDimitry Andric SISchedulerCandidate &TryCand, 144444ed5c5SDimitry Andric SISchedulerCandidate &Cand, 145444ed5c5SDimitry Andric SIScheduleCandReason Reason) { 146444ed5c5SDimitry Andric if (TryVal < CandVal) { 147444ed5c5SDimitry Andric TryCand.Reason = Reason; 148444ed5c5SDimitry Andric return true; 149444ed5c5SDimitry Andric } 150444ed5c5SDimitry Andric if (TryVal > CandVal) { 151444ed5c5SDimitry Andric if (Cand.Reason > Reason) 152444ed5c5SDimitry Andric Cand.Reason = Reason; 153444ed5c5SDimitry Andric return true; 154444ed5c5SDimitry Andric } 155444ed5c5SDimitry Andric Cand.setRepeat(Reason); 156444ed5c5SDimitry Andric return false; 157444ed5c5SDimitry Andric } 158444ed5c5SDimitry Andric 159444ed5c5SDimitry Andric static bool tryGreater(int TryVal, int CandVal, 160444ed5c5SDimitry Andric SISchedulerCandidate &TryCand, 161444ed5c5SDimitry Andric SISchedulerCandidate &Cand, 162444ed5c5SDimitry Andric SIScheduleCandReason Reason) { 163444ed5c5SDimitry Andric if (TryVal > CandVal) { 164444ed5c5SDimitry Andric TryCand.Reason = Reason; 165444ed5c5SDimitry Andric return true; 166444ed5c5SDimitry Andric } 167444ed5c5SDimitry Andric if (TryVal < CandVal) { 168444ed5c5SDimitry Andric if (Cand.Reason > Reason) 169444ed5c5SDimitry Andric Cand.Reason = Reason; 170444ed5c5SDimitry Andric return true; 171444ed5c5SDimitry Andric } 172444ed5c5SDimitry Andric Cand.setRepeat(Reason); 173444ed5c5SDimitry Andric return false; 174444ed5c5SDimitry Andric } 175444ed5c5SDimitry Andric 176444ed5c5SDimitry Andric // SIScheduleBlock // 177444ed5c5SDimitry Andric 178444ed5c5SDimitry Andric void SIScheduleBlock::addUnit(SUnit *SU) { 179444ed5c5SDimitry Andric NodeNum2Index[SU->NodeNum] = SUnits.size(); 180444ed5c5SDimitry Andric SUnits.push_back(SU); 181444ed5c5SDimitry Andric } 182444ed5c5SDimitry Andric 183444ed5c5SDimitry Andric #ifndef NDEBUG 184444ed5c5SDimitry Andric 185444ed5c5SDimitry Andric void SIScheduleBlock::traceCandidate(const SISchedCandidate &Cand) { 186444ed5c5SDimitry Andric 187444ed5c5SDimitry Andric dbgs() << " SU(" << Cand.SU->NodeNum << ") " << getReasonStr(Cand.Reason); 188444ed5c5SDimitry Andric dbgs() << '\n'; 189444ed5c5SDimitry Andric } 190444ed5c5SDimitry Andric #endif 191444ed5c5SDimitry Andric 192444ed5c5SDimitry Andric void SIScheduleBlock::tryCandidateTopDown(SISchedCandidate &Cand, 193444ed5c5SDimitry Andric SISchedCandidate &TryCand) { 194444ed5c5SDimitry Andric // Initialize the candidate if needed. 195444ed5c5SDimitry Andric if (!Cand.isValid()) { 196444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 197444ed5c5SDimitry Andric return; 198444ed5c5SDimitry Andric } 199444ed5c5SDimitry Andric 200444ed5c5SDimitry Andric if (Cand.SGPRUsage > 60 && 201444ed5c5SDimitry Andric tryLess(TryCand.SGPRUsage, Cand.SGPRUsage, TryCand, Cand, RegUsage)) 202444ed5c5SDimitry Andric return; 203444ed5c5SDimitry Andric 204444ed5c5SDimitry Andric // Schedule low latency instructions as top as possible. 205444ed5c5SDimitry Andric // Order of priority is: 206444ed5c5SDimitry Andric // . Low latency instructions which do not depend on other low latency 207444ed5c5SDimitry Andric // instructions we haven't waited for 208444ed5c5SDimitry Andric // . Other instructions which do not depend on low latency instructions 209444ed5c5SDimitry Andric // we haven't waited for 210444ed5c5SDimitry Andric // . Low latencies 211444ed5c5SDimitry Andric // . All other instructions 212444ed5c5SDimitry Andric // Goal is to get: low latency instructions - independant instructions 213444ed5c5SDimitry Andric // - (eventually some more low latency instructions) 214444ed5c5SDimitry Andric // - instructions that depend on the first low latency instructions. 215444ed5c5SDimitry Andric // If in the block there is a lot of constant loads, the SGPR usage 216444ed5c5SDimitry Andric // could go quite high, thus above the arbitrary limit of 60 will encourage 217444ed5c5SDimitry Andric // use the already loaded constants (in order to release some SGPRs) before 218444ed5c5SDimitry Andric // loading more. 219444ed5c5SDimitry Andric if (tryLess(TryCand.HasLowLatencyNonWaitedParent, 220444ed5c5SDimitry Andric Cand.HasLowLatencyNonWaitedParent, 221444ed5c5SDimitry Andric TryCand, Cand, SIScheduleCandReason::Depth)) 222444ed5c5SDimitry Andric return; 223444ed5c5SDimitry Andric 224444ed5c5SDimitry Andric if (tryGreater(TryCand.IsLowLatency, Cand.IsLowLatency, 225444ed5c5SDimitry Andric TryCand, Cand, SIScheduleCandReason::Depth)) 226444ed5c5SDimitry Andric return; 227444ed5c5SDimitry Andric 228444ed5c5SDimitry Andric if (TryCand.IsLowLatency && 229444ed5c5SDimitry Andric tryLess(TryCand.LowLatencyOffset, Cand.LowLatencyOffset, 230444ed5c5SDimitry Andric TryCand, Cand, SIScheduleCandReason::Depth)) 231444ed5c5SDimitry Andric return; 232444ed5c5SDimitry Andric 233444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsage, Cand.VGPRUsage, TryCand, Cand, RegUsage)) 234444ed5c5SDimitry Andric return; 235444ed5c5SDimitry Andric 236444ed5c5SDimitry Andric // Fall through to original instruction order. 237444ed5c5SDimitry Andric if (TryCand.SU->NodeNum < Cand.SU->NodeNum) { 238444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 239444ed5c5SDimitry Andric } 240444ed5c5SDimitry Andric } 241444ed5c5SDimitry Andric 242444ed5c5SDimitry Andric SUnit* SIScheduleBlock::pickNode() { 243444ed5c5SDimitry Andric SISchedCandidate TopCand; 244444ed5c5SDimitry Andric 245444ed5c5SDimitry Andric for (SUnit* SU : TopReadySUs) { 246444ed5c5SDimitry Andric SISchedCandidate TryCand; 247444ed5c5SDimitry Andric std::vector<unsigned> pressure; 248444ed5c5SDimitry Andric std::vector<unsigned> MaxPressure; 249444ed5c5SDimitry Andric // Predict register usage after this instruction. 250444ed5c5SDimitry Andric TryCand.SU = SU; 251444ed5c5SDimitry Andric TopRPTracker.getDownwardPressure(SU->getInstr(), pressure, MaxPressure); 252444ed5c5SDimitry Andric TryCand.SGPRUsage = pressure[DAG->getSGPRSetID()]; 253444ed5c5SDimitry Andric TryCand.VGPRUsage = pressure[DAG->getVGPRSetID()]; 254444ed5c5SDimitry Andric TryCand.IsLowLatency = DAG->IsLowLatencySU[SU->NodeNum]; 255444ed5c5SDimitry Andric TryCand.LowLatencyOffset = DAG->LowLatencyOffset[SU->NodeNum]; 256444ed5c5SDimitry Andric TryCand.HasLowLatencyNonWaitedParent = 257444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]]; 258444ed5c5SDimitry Andric tryCandidateTopDown(TopCand, TryCand); 259444ed5c5SDimitry Andric if (TryCand.Reason != NoCand) 260444ed5c5SDimitry Andric TopCand.setBest(TryCand); 261444ed5c5SDimitry Andric } 262444ed5c5SDimitry Andric 263444ed5c5SDimitry Andric return TopCand.SU; 264444ed5c5SDimitry Andric } 265444ed5c5SDimitry Andric 266444ed5c5SDimitry Andric 267444ed5c5SDimitry Andric // Schedule something valid. 268444ed5c5SDimitry Andric void SIScheduleBlock::fastSchedule() { 269444ed5c5SDimitry Andric TopReadySUs.clear(); 270444ed5c5SDimitry Andric if (Scheduled) 271444ed5c5SDimitry Andric undoSchedule(); 272444ed5c5SDimitry Andric 273444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 274444ed5c5SDimitry Andric if (!SU->NumPredsLeft) 275444ed5c5SDimitry Andric TopReadySUs.push_back(SU); 276444ed5c5SDimitry Andric } 277444ed5c5SDimitry Andric 278444ed5c5SDimitry Andric while (!TopReadySUs.empty()) { 279444ed5c5SDimitry Andric SUnit *SU = TopReadySUs[0]; 280444ed5c5SDimitry Andric ScheduledSUnits.push_back(SU); 281444ed5c5SDimitry Andric nodeScheduled(SU); 282444ed5c5SDimitry Andric } 283444ed5c5SDimitry Andric 284444ed5c5SDimitry Andric Scheduled = true; 285444ed5c5SDimitry Andric } 286444ed5c5SDimitry Andric 287444ed5c5SDimitry Andric // Returns if the register was set between first and last. 288444ed5c5SDimitry Andric static bool isDefBetween(unsigned Reg, 289444ed5c5SDimitry Andric SlotIndex First, SlotIndex Last, 290444ed5c5SDimitry Andric const MachineRegisterInfo *MRI, 291444ed5c5SDimitry Andric const LiveIntervals *LIS) { 292444ed5c5SDimitry Andric for (MachineRegisterInfo::def_instr_iterator 293444ed5c5SDimitry Andric UI = MRI->def_instr_begin(Reg), 294444ed5c5SDimitry Andric UE = MRI->def_instr_end(); UI != UE; ++UI) { 295444ed5c5SDimitry Andric const MachineInstr* MI = &*UI; 296444ed5c5SDimitry Andric if (MI->isDebugValue()) 297444ed5c5SDimitry Andric continue; 298444ed5c5SDimitry Andric SlotIndex InstSlot = LIS->getInstructionIndex(MI).getRegSlot(); 299444ed5c5SDimitry Andric if (InstSlot >= First && InstSlot <= Last) 300444ed5c5SDimitry Andric return true; 301444ed5c5SDimitry Andric } 302444ed5c5SDimitry Andric return false; 303444ed5c5SDimitry Andric } 304444ed5c5SDimitry Andric 305444ed5c5SDimitry Andric void SIScheduleBlock::initRegPressure(MachineBasicBlock::iterator BeginBlock, 306444ed5c5SDimitry Andric MachineBasicBlock::iterator EndBlock) { 307444ed5c5SDimitry Andric IntervalPressure Pressure, BotPressure; 308444ed5c5SDimitry Andric RegPressureTracker RPTracker(Pressure), BotRPTracker(BotPressure); 309444ed5c5SDimitry Andric LiveIntervals *LIS = DAG->getLIS(); 310444ed5c5SDimitry Andric MachineRegisterInfo *MRI = DAG->getMRI(); 311444ed5c5SDimitry Andric DAG->initRPTracker(TopRPTracker); 312444ed5c5SDimitry Andric DAG->initRPTracker(BotRPTracker); 313444ed5c5SDimitry Andric DAG->initRPTracker(RPTracker); 314444ed5c5SDimitry Andric 315444ed5c5SDimitry Andric // Goes though all SU. RPTracker captures what had to be alive for the SUs 316444ed5c5SDimitry Andric // to execute, and what is still alive at the end. 317444ed5c5SDimitry Andric for (SUnit* SU : ScheduledSUnits) { 318444ed5c5SDimitry Andric RPTracker.setPos(SU->getInstr()); 319444ed5c5SDimitry Andric RPTracker.advance(); 320444ed5c5SDimitry Andric } 321444ed5c5SDimitry Andric 322444ed5c5SDimitry Andric // Close the RPTracker to finalize live ins/outs. 323444ed5c5SDimitry Andric RPTracker.closeRegion(); 324444ed5c5SDimitry Andric 325444ed5c5SDimitry Andric // Initialize the live ins and live outs. 326444ed5c5SDimitry Andric TopRPTracker.addLiveRegs(RPTracker.getPressure().LiveInRegs); 327444ed5c5SDimitry Andric BotRPTracker.addLiveRegs(RPTracker.getPressure().LiveOutRegs); 328444ed5c5SDimitry Andric 329444ed5c5SDimitry Andric // Do not Track Physical Registers, because it messes up. 330444ed5c5SDimitry Andric for (unsigned Reg : RPTracker.getPressure().LiveInRegs) { 331444ed5c5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg)) 332444ed5c5SDimitry Andric LiveInRegs.insert(Reg); 333444ed5c5SDimitry Andric } 334444ed5c5SDimitry Andric LiveOutRegs.clear(); 335444ed5c5SDimitry Andric // There is several possibilities to distinguish: 336444ed5c5SDimitry Andric // 1) Reg is not input to any instruction in the block, but is output of one 337444ed5c5SDimitry Andric // 2) 1) + read in the block and not needed after it 338444ed5c5SDimitry Andric // 3) 1) + read in the block but needed in another block 339444ed5c5SDimitry Andric // 4) Reg is input of an instruction but another block will read it too 340444ed5c5SDimitry Andric // 5) Reg is input of an instruction and then rewritten in the block. 341444ed5c5SDimitry Andric // result is not read in the block (implies used in another block) 342444ed5c5SDimitry Andric // 6) Reg is input of an instruction and then rewritten in the block. 343444ed5c5SDimitry Andric // result is read in the block and not needed in another block 344444ed5c5SDimitry Andric // 7) Reg is input of an instruction and then rewritten in the block. 345444ed5c5SDimitry Andric // result is read in the block but also needed in another block 346444ed5c5SDimitry Andric // LiveInRegs will contains all the regs in situation 4, 5, 6, 7 347444ed5c5SDimitry Andric // We want LiveOutRegs to contain only Regs whose content will be read after 348444ed5c5SDimitry Andric // in another block, and whose content was written in the current block, 349444ed5c5SDimitry Andric // that is we want it to get 1, 3, 5, 7 350444ed5c5SDimitry Andric // Since we made the MIs of a block to be packed all together before 351444ed5c5SDimitry Andric // scheduling, then the LiveIntervals were correct, and the RPTracker was 352444ed5c5SDimitry Andric // able to correctly handle 5 vs 6, 2 vs 3. 353444ed5c5SDimitry Andric // (Note: This is not sufficient for RPTracker to not do mistakes for case 4) 354444ed5c5SDimitry Andric // The RPTracker's LiveOutRegs has 1, 3, (some correct or incorrect)4, 5, 7 355444ed5c5SDimitry Andric // Comparing to LiveInRegs is not sufficient to differenciate 4 vs 5, 7 356444ed5c5SDimitry Andric // The use of findDefBetween removes the case 4. 357444ed5c5SDimitry Andric for (unsigned Reg : RPTracker.getPressure().LiveOutRegs) { 358444ed5c5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg) && 359444ed5c5SDimitry Andric isDefBetween(Reg, LIS->getInstructionIndex(BeginBlock).getRegSlot(), 360444ed5c5SDimitry Andric LIS->getInstructionIndex(EndBlock).getRegSlot(), 361444ed5c5SDimitry Andric MRI, LIS)) { 362444ed5c5SDimitry Andric LiveOutRegs.insert(Reg); 363444ed5c5SDimitry Andric } 364444ed5c5SDimitry Andric } 365444ed5c5SDimitry Andric 366444ed5c5SDimitry Andric // Pressure = sum_alive_registers register size 367444ed5c5SDimitry Andric // Internally llvm will represent some registers as big 128 bits registers 368444ed5c5SDimitry Andric // for example, but they actually correspond to 4 actual 32 bits registers. 369444ed5c5SDimitry Andric // Thus Pressure is not equal to num_alive_registers * constant. 370444ed5c5SDimitry Andric LiveInPressure = TopPressure.MaxSetPressure; 371444ed5c5SDimitry Andric LiveOutPressure = BotPressure.MaxSetPressure; 372444ed5c5SDimitry Andric 373444ed5c5SDimitry Andric // Prepares TopRPTracker for top down scheduling. 374444ed5c5SDimitry Andric TopRPTracker.closeTop(); 375444ed5c5SDimitry Andric } 376444ed5c5SDimitry Andric 377444ed5c5SDimitry Andric void SIScheduleBlock::schedule(MachineBasicBlock::iterator BeginBlock, 378444ed5c5SDimitry Andric MachineBasicBlock::iterator EndBlock) { 379444ed5c5SDimitry Andric if (!Scheduled) 380444ed5c5SDimitry Andric fastSchedule(); 381444ed5c5SDimitry Andric 382444ed5c5SDimitry Andric // PreScheduling phase to set LiveIn and LiveOut. 383444ed5c5SDimitry Andric initRegPressure(BeginBlock, EndBlock); 384444ed5c5SDimitry Andric undoSchedule(); 385444ed5c5SDimitry Andric 386444ed5c5SDimitry Andric // Schedule for real now. 387444ed5c5SDimitry Andric 388444ed5c5SDimitry Andric TopReadySUs.clear(); 389444ed5c5SDimitry Andric 390444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 391444ed5c5SDimitry Andric if (!SU->NumPredsLeft) 392444ed5c5SDimitry Andric TopReadySUs.push_back(SU); 393444ed5c5SDimitry Andric } 394444ed5c5SDimitry Andric 395444ed5c5SDimitry Andric while (!TopReadySUs.empty()) { 396444ed5c5SDimitry Andric SUnit *SU = pickNode(); 397444ed5c5SDimitry Andric ScheduledSUnits.push_back(SU); 398444ed5c5SDimitry Andric TopRPTracker.setPos(SU->getInstr()); 399444ed5c5SDimitry Andric TopRPTracker.advance(); 400444ed5c5SDimitry Andric nodeScheduled(SU); 401444ed5c5SDimitry Andric } 402444ed5c5SDimitry Andric 403444ed5c5SDimitry Andric // TODO: compute InternalAdditionnalPressure. 404444ed5c5SDimitry Andric InternalAdditionnalPressure.resize(TopPressure.MaxSetPressure.size()); 405444ed5c5SDimitry Andric 406444ed5c5SDimitry Andric // Check everything is right. 407444ed5c5SDimitry Andric #ifndef NDEBUG 408444ed5c5SDimitry Andric assert(SUnits.size() == ScheduledSUnits.size() && 409444ed5c5SDimitry Andric TopReadySUs.empty()); 410444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 411444ed5c5SDimitry Andric assert(SU->isScheduled && 412444ed5c5SDimitry Andric SU->NumPredsLeft == 0); 413444ed5c5SDimitry Andric } 414444ed5c5SDimitry Andric #endif 415444ed5c5SDimitry Andric 416444ed5c5SDimitry Andric Scheduled = true; 417444ed5c5SDimitry Andric } 418444ed5c5SDimitry Andric 419444ed5c5SDimitry Andric void SIScheduleBlock::undoSchedule() { 420444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 421444ed5c5SDimitry Andric SU->isScheduled = false; 422444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 423444ed5c5SDimitry Andric if (BC->isSUInBlock(Succ.getSUnit(), ID)) 424444ed5c5SDimitry Andric undoReleaseSucc(SU, &Succ); 425444ed5c5SDimitry Andric } 426444ed5c5SDimitry Andric } 427444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0); 428444ed5c5SDimitry Andric ScheduledSUnits.clear(); 429444ed5c5SDimitry Andric Scheduled = false; 430444ed5c5SDimitry Andric } 431444ed5c5SDimitry Andric 432444ed5c5SDimitry Andric void SIScheduleBlock::undoReleaseSucc(SUnit *SU, SDep *SuccEdge) { 433444ed5c5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 434444ed5c5SDimitry Andric 435444ed5c5SDimitry Andric if (SuccEdge->isWeak()) { 436444ed5c5SDimitry Andric ++SuccSU->WeakPredsLeft; 437444ed5c5SDimitry Andric return; 438444ed5c5SDimitry Andric } 439444ed5c5SDimitry Andric ++SuccSU->NumPredsLeft; 440444ed5c5SDimitry Andric } 441444ed5c5SDimitry Andric 442444ed5c5SDimitry Andric void SIScheduleBlock::releaseSucc(SUnit *SU, SDep *SuccEdge) { 443444ed5c5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 444444ed5c5SDimitry Andric 445444ed5c5SDimitry Andric if (SuccEdge->isWeak()) { 446444ed5c5SDimitry Andric --SuccSU->WeakPredsLeft; 447444ed5c5SDimitry Andric return; 448444ed5c5SDimitry Andric } 449444ed5c5SDimitry Andric #ifndef NDEBUG 450444ed5c5SDimitry Andric if (SuccSU->NumPredsLeft == 0) { 451444ed5c5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n"; 452444ed5c5SDimitry Andric SuccSU->dump(DAG); 453444ed5c5SDimitry Andric dbgs() << " has been released too many times!\n"; 454444ed5c5SDimitry Andric llvm_unreachable(nullptr); 455444ed5c5SDimitry Andric } 456444ed5c5SDimitry Andric #endif 457444ed5c5SDimitry Andric 458444ed5c5SDimitry Andric --SuccSU->NumPredsLeft; 459444ed5c5SDimitry Andric } 460444ed5c5SDimitry Andric 461444ed5c5SDimitry Andric /// Release Successors of the SU that are in the block or not. 462444ed5c5SDimitry Andric void SIScheduleBlock::releaseSuccessors(SUnit *SU, bool InOrOutBlock) { 463444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 464444ed5c5SDimitry Andric SUnit *SuccSU = Succ.getSUnit(); 465444ed5c5SDimitry Andric 466444ed5c5SDimitry Andric if (BC->isSUInBlock(SuccSU, ID) != InOrOutBlock) 467444ed5c5SDimitry Andric continue; 468444ed5c5SDimitry Andric 469444ed5c5SDimitry Andric releaseSucc(SU, &Succ); 470444ed5c5SDimitry Andric if (SuccSU->NumPredsLeft == 0 && InOrOutBlock) 471444ed5c5SDimitry Andric TopReadySUs.push_back(SuccSU); 472444ed5c5SDimitry Andric } 473444ed5c5SDimitry Andric } 474444ed5c5SDimitry Andric 475444ed5c5SDimitry Andric void SIScheduleBlock::nodeScheduled(SUnit *SU) { 476444ed5c5SDimitry Andric // Is in TopReadySUs 477444ed5c5SDimitry Andric assert (!SU->NumPredsLeft); 478444ed5c5SDimitry Andric std::vector<SUnit*>::iterator I = 479444ed5c5SDimitry Andric std::find(TopReadySUs.begin(), TopReadySUs.end(), SU); 480444ed5c5SDimitry Andric if (I == TopReadySUs.end()) { 481444ed5c5SDimitry Andric dbgs() << "Data Structure Bug in SI Scheduler\n"; 482444ed5c5SDimitry Andric llvm_unreachable(nullptr); 483444ed5c5SDimitry Andric } 484444ed5c5SDimitry Andric TopReadySUs.erase(I); 485444ed5c5SDimitry Andric 486444ed5c5SDimitry Andric releaseSuccessors(SU, true); 487444ed5c5SDimitry Andric // Scheduling this node will trigger a wait, 488444ed5c5SDimitry Andric // thus propagate to other instructions that they do not need to wait either. 489444ed5c5SDimitry Andric if (HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]]) 490444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0); 491444ed5c5SDimitry Andric 492444ed5c5SDimitry Andric if (DAG->IsLowLatencySU[SU->NodeNum]) { 493444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 494444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator I = 495444ed5c5SDimitry Andric NodeNum2Index.find(Succ.getSUnit()->NodeNum); 496444ed5c5SDimitry Andric if (I != NodeNum2Index.end()) 497444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent[I->second] = 1; 498444ed5c5SDimitry Andric } 499444ed5c5SDimitry Andric } 500444ed5c5SDimitry Andric SU->isScheduled = true; 501444ed5c5SDimitry Andric } 502444ed5c5SDimitry Andric 503444ed5c5SDimitry Andric void SIScheduleBlock::finalizeUnits() { 504444ed5c5SDimitry Andric // We remove links from outside blocks to enable scheduling inside the block. 505444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 506444ed5c5SDimitry Andric releaseSuccessors(SU, false); 507444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) 508444ed5c5SDimitry Andric HighLatencyBlock = true; 509444ed5c5SDimitry Andric } 510444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.resize(SUnits.size(), 0); 511444ed5c5SDimitry Andric } 512444ed5c5SDimitry Andric 513444ed5c5SDimitry Andric // we maintain ascending order of IDs 514444ed5c5SDimitry Andric void SIScheduleBlock::addPred(SIScheduleBlock *Pred) { 515444ed5c5SDimitry Andric unsigned PredID = Pred->getID(); 516444ed5c5SDimitry Andric 517444ed5c5SDimitry Andric // Check if not already predecessor. 518444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 519444ed5c5SDimitry Andric if (PredID == P->getID()) 520444ed5c5SDimitry Andric return; 521444ed5c5SDimitry Andric } 522444ed5c5SDimitry Andric Preds.push_back(Pred); 523444ed5c5SDimitry Andric 524444ed5c5SDimitry Andric #ifndef NDEBUG 525444ed5c5SDimitry Andric for (SIScheduleBlock* S : Succs) { 526444ed5c5SDimitry Andric if (PredID == S->getID()) 527444ed5c5SDimitry Andric assert(!"Loop in the Block Graph!\n"); 528444ed5c5SDimitry Andric } 529444ed5c5SDimitry Andric #endif 530444ed5c5SDimitry Andric } 531444ed5c5SDimitry Andric 532444ed5c5SDimitry Andric void SIScheduleBlock::addSucc(SIScheduleBlock *Succ) { 533444ed5c5SDimitry Andric unsigned SuccID = Succ->getID(); 534444ed5c5SDimitry Andric 535444ed5c5SDimitry Andric // Check if not already predecessor. 536444ed5c5SDimitry Andric for (SIScheduleBlock* S : Succs) { 537444ed5c5SDimitry Andric if (SuccID == S->getID()) 538444ed5c5SDimitry Andric return; 539444ed5c5SDimitry Andric } 540444ed5c5SDimitry Andric if (Succ->isHighLatencyBlock()) 541444ed5c5SDimitry Andric ++NumHighLatencySuccessors; 542444ed5c5SDimitry Andric Succs.push_back(Succ); 543444ed5c5SDimitry Andric #ifndef NDEBUG 544444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 545444ed5c5SDimitry Andric if (SuccID == P->getID()) 546444ed5c5SDimitry Andric assert("Loop in the Block Graph!\n"); 547444ed5c5SDimitry Andric } 548444ed5c5SDimitry Andric #endif 549444ed5c5SDimitry Andric } 550444ed5c5SDimitry Andric 551444ed5c5SDimitry Andric #ifndef NDEBUG 552444ed5c5SDimitry Andric void SIScheduleBlock::printDebug(bool full) { 553444ed5c5SDimitry Andric dbgs() << "Block (" << ID << ")\n"; 554444ed5c5SDimitry Andric if (!full) 555444ed5c5SDimitry Andric return; 556444ed5c5SDimitry Andric 557444ed5c5SDimitry Andric dbgs() << "\nContains High Latency Instruction: " 558444ed5c5SDimitry Andric << HighLatencyBlock << '\n'; 559444ed5c5SDimitry Andric dbgs() << "\nDepends On:\n"; 560444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 561444ed5c5SDimitry Andric P->printDebug(false); 562444ed5c5SDimitry Andric } 563444ed5c5SDimitry Andric 564444ed5c5SDimitry Andric dbgs() << "\nSuccessors:\n"; 565444ed5c5SDimitry Andric for (SIScheduleBlock* S : Succs) { 566444ed5c5SDimitry Andric S->printDebug(false); 567444ed5c5SDimitry Andric } 568444ed5c5SDimitry Andric 569444ed5c5SDimitry Andric if (Scheduled) { 570444ed5c5SDimitry Andric dbgs() << "LiveInPressure " << LiveInPressure[DAG->getSGPRSetID()] << ' ' 571444ed5c5SDimitry Andric << LiveInPressure[DAG->getVGPRSetID()] << '\n'; 572444ed5c5SDimitry Andric dbgs() << "LiveOutPressure " << LiveOutPressure[DAG->getSGPRSetID()] << ' ' 573444ed5c5SDimitry Andric << LiveOutPressure[DAG->getVGPRSetID()] << "\n\n"; 574444ed5c5SDimitry Andric dbgs() << "LiveIns:\n"; 575444ed5c5SDimitry Andric for (unsigned Reg : LiveInRegs) 576444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 577444ed5c5SDimitry Andric 578444ed5c5SDimitry Andric dbgs() << "\nLiveOuts:\n"; 579444ed5c5SDimitry Andric for (unsigned Reg : LiveOutRegs) 580444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 581444ed5c5SDimitry Andric } 582444ed5c5SDimitry Andric 583444ed5c5SDimitry Andric dbgs() << "\nInstructions:\n"; 584444ed5c5SDimitry Andric if (!Scheduled) { 585444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 586444ed5c5SDimitry Andric SU->dump(DAG); 587444ed5c5SDimitry Andric } 588444ed5c5SDimitry Andric } else { 589444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 590444ed5c5SDimitry Andric SU->dump(DAG); 591444ed5c5SDimitry Andric } 592444ed5c5SDimitry Andric } 593444ed5c5SDimitry Andric 594444ed5c5SDimitry Andric dbgs() << "///////////////////////\n"; 595444ed5c5SDimitry Andric } 596444ed5c5SDimitry Andric 597444ed5c5SDimitry Andric #endif 598444ed5c5SDimitry Andric 599444ed5c5SDimitry Andric // SIScheduleBlockCreator // 600444ed5c5SDimitry Andric 601444ed5c5SDimitry Andric SIScheduleBlockCreator::SIScheduleBlockCreator(SIScheduleDAGMI *DAG) : 602444ed5c5SDimitry Andric DAG(DAG) { 603444ed5c5SDimitry Andric } 604444ed5c5SDimitry Andric 605444ed5c5SDimitry Andric SIScheduleBlockCreator::~SIScheduleBlockCreator() { 606444ed5c5SDimitry Andric } 607444ed5c5SDimitry Andric 608444ed5c5SDimitry Andric SIScheduleBlocks 609444ed5c5SDimitry Andric SIScheduleBlockCreator::getBlocks(SISchedulerBlockCreatorVariant BlockVariant) { 610444ed5c5SDimitry Andric std::map<SISchedulerBlockCreatorVariant, SIScheduleBlocks>::iterator B = 611444ed5c5SDimitry Andric Blocks.find(BlockVariant); 612444ed5c5SDimitry Andric if (B == Blocks.end()) { 613444ed5c5SDimitry Andric SIScheduleBlocks Res; 614444ed5c5SDimitry Andric createBlocksForVariant(BlockVariant); 615444ed5c5SDimitry Andric topologicalSort(); 616444ed5c5SDimitry Andric scheduleInsideBlocks(); 617444ed5c5SDimitry Andric fillStats(); 618444ed5c5SDimitry Andric Res.Blocks = CurrentBlocks; 619444ed5c5SDimitry Andric Res.TopDownIndex2Block = TopDownIndex2Block; 620444ed5c5SDimitry Andric Res.TopDownBlock2Index = TopDownBlock2Index; 621444ed5c5SDimitry Andric Blocks[BlockVariant] = Res; 622444ed5c5SDimitry Andric return Res; 623444ed5c5SDimitry Andric } else { 624444ed5c5SDimitry Andric return B->second; 625444ed5c5SDimitry Andric } 626444ed5c5SDimitry Andric } 627444ed5c5SDimitry Andric 628444ed5c5SDimitry Andric bool SIScheduleBlockCreator::isSUInBlock(SUnit *SU, unsigned ID) { 629444ed5c5SDimitry Andric if (SU->NodeNum >= DAG->SUnits.size()) 630444ed5c5SDimitry Andric return false; 631444ed5c5SDimitry Andric return CurrentBlocks[Node2CurrentBlock[SU->NodeNum]]->getID() == ID; 632444ed5c5SDimitry Andric } 633444ed5c5SDimitry Andric 634444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorHighLatenciesAlone() { 635444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 636444ed5c5SDimitry Andric 637444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 638444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 639444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) { 640444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = NextReservedID++; 641444ed5c5SDimitry Andric } 642444ed5c5SDimitry Andric } 643444ed5c5SDimitry Andric } 644444ed5c5SDimitry Andric 645444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorHighLatenciesGroups() { 646444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 647444ed5c5SDimitry Andric unsigned NumHighLatencies = 0; 648444ed5c5SDimitry Andric unsigned GroupSize; 649444ed5c5SDimitry Andric unsigned Color = NextReservedID; 650444ed5c5SDimitry Andric unsigned Count = 0; 651444ed5c5SDimitry Andric std::set<unsigned> FormingGroup; 652444ed5c5SDimitry Andric 653444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 654444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 655444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) 656444ed5c5SDimitry Andric ++NumHighLatencies; 657444ed5c5SDimitry Andric } 658444ed5c5SDimitry Andric 659444ed5c5SDimitry Andric if (NumHighLatencies == 0) 660444ed5c5SDimitry Andric return; 661444ed5c5SDimitry Andric 662444ed5c5SDimitry Andric if (NumHighLatencies <= 6) 663444ed5c5SDimitry Andric GroupSize = 2; 664444ed5c5SDimitry Andric else if (NumHighLatencies <= 12) 665444ed5c5SDimitry Andric GroupSize = 3; 666444ed5c5SDimitry Andric else 667444ed5c5SDimitry Andric GroupSize = 4; 668444ed5c5SDimitry Andric 669444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 670444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 671444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) { 672444ed5c5SDimitry Andric unsigned CompatibleGroup = true; 673444ed5c5SDimitry Andric unsigned ProposedColor = Color; 674444ed5c5SDimitry Andric for (unsigned j : FormingGroup) { 675444ed5c5SDimitry Andric // TODO: Currently CompatibleGroup will always be false, 676444ed5c5SDimitry Andric // because the graph enforces the load order. This 677444ed5c5SDimitry Andric // can be fixed, but as keeping the load order is often 678444ed5c5SDimitry Andric // good for performance that causes a performance hit (both 679444ed5c5SDimitry Andric // the default scheduler and this scheduler). 680444ed5c5SDimitry Andric // When this scheduler determines a good load order, 681444ed5c5SDimitry Andric // this can be fixed. 682444ed5c5SDimitry Andric if (!DAG->canAddEdge(SU, &DAG->SUnits[j]) || 683444ed5c5SDimitry Andric !DAG->canAddEdge(&DAG->SUnits[j], SU)) 684444ed5c5SDimitry Andric CompatibleGroup = false; 685444ed5c5SDimitry Andric } 686444ed5c5SDimitry Andric if (!CompatibleGroup || ++Count == GroupSize) { 687444ed5c5SDimitry Andric FormingGroup.clear(); 688444ed5c5SDimitry Andric Color = ++NextReservedID; 689444ed5c5SDimitry Andric if (!CompatibleGroup) { 690444ed5c5SDimitry Andric ProposedColor = Color; 691444ed5c5SDimitry Andric FormingGroup.insert(SU->NodeNum); 692444ed5c5SDimitry Andric } 693444ed5c5SDimitry Andric Count = 0; 694444ed5c5SDimitry Andric } else { 695444ed5c5SDimitry Andric FormingGroup.insert(SU->NodeNum); 696444ed5c5SDimitry Andric } 697444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = ProposedColor; 698444ed5c5SDimitry Andric } 699444ed5c5SDimitry Andric } 700444ed5c5SDimitry Andric } 701444ed5c5SDimitry Andric 702444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorComputeReservedDependencies() { 703444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 704444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned> ColorCombinations; 705444ed5c5SDimitry Andric 706444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring.clear(); 707444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring.clear(); 708444ed5c5SDimitry Andric 709444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring.resize(DAGSize, 0); 710444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring.resize(DAGSize, 0); 711444ed5c5SDimitry Andric 712444ed5c5SDimitry Andric // Traverse TopDown, and give different colors to SUs depending 713444ed5c5SDimitry Andric // on which combination of High Latencies they depend on. 714444ed5c5SDimitry Andric 715444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 716444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->TopDownIndex2SU[i]]; 717444ed5c5SDimitry Andric std::set<unsigned> SUColors; 718444ed5c5SDimitry Andric 719444ed5c5SDimitry Andric // Already given. 720444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) { 721444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 722444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum]; 723444ed5c5SDimitry Andric continue; 724444ed5c5SDimitry Andric } 725444ed5c5SDimitry Andric 726444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 727444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 728444ed5c5SDimitry Andric if (PredDep.isWeak() || Pred->NodeNum >= DAGSize) 729444ed5c5SDimitry Andric continue; 730444ed5c5SDimitry Andric if (CurrentTopDownReservedDependencyColoring[Pred->NodeNum] > 0) 731444ed5c5SDimitry Andric SUColors.insert(CurrentTopDownReservedDependencyColoring[Pred->NodeNum]); 732444ed5c5SDimitry Andric } 733444ed5c5SDimitry Andric // Color 0 by default. 734444ed5c5SDimitry Andric if (SUColors.empty()) 735444ed5c5SDimitry Andric continue; 736444ed5c5SDimitry Andric // Same color than parents. 737444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() > DAGSize) 738444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 739444ed5c5SDimitry Andric *SUColors.begin(); 740444ed5c5SDimitry Andric else { 741444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned>::iterator Pos = 742444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 743444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 744444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = Pos->second; 745444ed5c5SDimitry Andric } else { 746444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 747444ed5c5SDimitry Andric NextNonReservedID; 748444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 749444ed5c5SDimitry Andric } 750444ed5c5SDimitry Andric } 751444ed5c5SDimitry Andric } 752444ed5c5SDimitry Andric 753444ed5c5SDimitry Andric ColorCombinations.clear(); 754444ed5c5SDimitry Andric 755444ed5c5SDimitry Andric // Same as before, but BottomUp. 756444ed5c5SDimitry Andric 757444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 758444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 759444ed5c5SDimitry Andric std::set<unsigned> SUColors; 760444ed5c5SDimitry Andric 761444ed5c5SDimitry Andric // Already given. 762444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) { 763444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 764444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum]; 765444ed5c5SDimitry Andric continue; 766444ed5c5SDimitry Andric } 767444ed5c5SDimitry Andric 768444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 769444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 770444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 771444ed5c5SDimitry Andric continue; 772444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0) 773444ed5c5SDimitry Andric SUColors.insert(CurrentBottomUpReservedDependencyColoring[Succ->NodeNum]); 774444ed5c5SDimitry Andric } 775444ed5c5SDimitry Andric // Keep color 0. 776444ed5c5SDimitry Andric if (SUColors.empty()) 777444ed5c5SDimitry Andric continue; 778444ed5c5SDimitry Andric // Same color than parents. 779444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() > DAGSize) 780444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 781444ed5c5SDimitry Andric *SUColors.begin(); 782444ed5c5SDimitry Andric else { 783444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned>::iterator Pos = 784444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 785444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 786444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = Pos->second; 787444ed5c5SDimitry Andric } else { 788444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 789444ed5c5SDimitry Andric NextNonReservedID; 790444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 791444ed5c5SDimitry Andric } 792444ed5c5SDimitry Andric } 793444ed5c5SDimitry Andric } 794444ed5c5SDimitry Andric } 795444ed5c5SDimitry Andric 796444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorAccordingToReservedDependencies() { 797444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 798444ed5c5SDimitry Andric std::map<std::pair<unsigned, unsigned>, unsigned> ColorCombinations; 799444ed5c5SDimitry Andric 800444ed5c5SDimitry Andric // Every combination of colors given by the top down 801444ed5c5SDimitry Andric // and bottom up Reserved node dependency 802444ed5c5SDimitry Andric 803444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 804444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 805444ed5c5SDimitry Andric std::pair<unsigned, unsigned> SUColors; 806444ed5c5SDimitry Andric 807444ed5c5SDimitry Andric // High latency instructions: already given. 808444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) 809444ed5c5SDimitry Andric continue; 810444ed5c5SDimitry Andric 811444ed5c5SDimitry Andric SUColors.first = CurrentTopDownReservedDependencyColoring[SU->NodeNum]; 812444ed5c5SDimitry Andric SUColors.second = CurrentBottomUpReservedDependencyColoring[SU->NodeNum]; 813444ed5c5SDimitry Andric 814444ed5c5SDimitry Andric std::map<std::pair<unsigned, unsigned>, unsigned>::iterator Pos = 815444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 816444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 817444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = Pos->second; 818444ed5c5SDimitry Andric } else { 819444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = NextNonReservedID; 820444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 821444ed5c5SDimitry Andric } 822444ed5c5SDimitry Andric } 823444ed5c5SDimitry Andric } 824444ed5c5SDimitry Andric 825444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorEndsAccordingToDependencies() { 826444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 827444ed5c5SDimitry Andric std::vector<int> PendingColoring = CurrentColoring; 828444ed5c5SDimitry Andric 829444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 830444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 831444ed5c5SDimitry Andric std::set<unsigned> SUColors; 832444ed5c5SDimitry Andric std::set<unsigned> SUColorsPending; 833444ed5c5SDimitry Andric 834444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 835444ed5c5SDimitry Andric continue; 836444ed5c5SDimitry Andric 837444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[SU->NodeNum] > 0 || 838444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] > 0) 839444ed5c5SDimitry Andric continue; 840444ed5c5SDimitry Andric 841444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 842444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 843444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 844444ed5c5SDimitry Andric continue; 845444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0 || 846444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[Succ->NodeNum] > 0) 847444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 848444ed5c5SDimitry Andric SUColorsPending.insert(PendingColoring[Succ->NodeNum]); 849444ed5c5SDimitry Andric } 850444ed5c5SDimitry Andric if (SUColors.size() == 1 && SUColorsPending.size() == 1) 851444ed5c5SDimitry Andric PendingColoring[SU->NodeNum] = *SUColors.begin(); 852444ed5c5SDimitry Andric else // TODO: Attribute new colors depending on color 853444ed5c5SDimitry Andric // combination of children. 854444ed5c5SDimitry Andric PendingColoring[SU->NodeNum] = NextNonReservedID++; 855444ed5c5SDimitry Andric } 856444ed5c5SDimitry Andric CurrentColoring = PendingColoring; 857444ed5c5SDimitry Andric } 858444ed5c5SDimitry Andric 859444ed5c5SDimitry Andric 860444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorForceConsecutiveOrderInGroup() { 861444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 862444ed5c5SDimitry Andric unsigned PreviousColor; 863444ed5c5SDimitry Andric std::set<unsigned> SeenColors; 864444ed5c5SDimitry Andric 865444ed5c5SDimitry Andric if (DAGSize <= 1) 866444ed5c5SDimitry Andric return; 867444ed5c5SDimitry Andric 868444ed5c5SDimitry Andric PreviousColor = CurrentColoring[0]; 869444ed5c5SDimitry Andric 870444ed5c5SDimitry Andric for (unsigned i = 1, e = DAGSize; i != e; ++i) { 871444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 872444ed5c5SDimitry Andric unsigned CurrentColor = CurrentColoring[i]; 873444ed5c5SDimitry Andric unsigned PreviousColorSave = PreviousColor; 874444ed5c5SDimitry Andric assert(i == SU->NodeNum); 875444ed5c5SDimitry Andric 876444ed5c5SDimitry Andric if (CurrentColor != PreviousColor) 877444ed5c5SDimitry Andric SeenColors.insert(PreviousColor); 878444ed5c5SDimitry Andric PreviousColor = CurrentColor; 879444ed5c5SDimitry Andric 880444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 881444ed5c5SDimitry Andric continue; 882444ed5c5SDimitry Andric 883444ed5c5SDimitry Andric if (SeenColors.find(CurrentColor) == SeenColors.end()) 884444ed5c5SDimitry Andric continue; 885444ed5c5SDimitry Andric 886444ed5c5SDimitry Andric if (PreviousColorSave != CurrentColor) 887444ed5c5SDimitry Andric CurrentColoring[i] = NextNonReservedID++; 888444ed5c5SDimitry Andric else 889444ed5c5SDimitry Andric CurrentColoring[i] = CurrentColoring[i-1]; 890444ed5c5SDimitry Andric } 891444ed5c5SDimitry Andric } 892444ed5c5SDimitry Andric 893444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeConstantLoadsNextGroup() { 894444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 895444ed5c5SDimitry Andric 896444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 897444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 898444ed5c5SDimitry Andric std::set<unsigned> SUColors; 899444ed5c5SDimitry Andric 900444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 901444ed5c5SDimitry Andric continue; 902444ed5c5SDimitry Andric 903444ed5c5SDimitry Andric // No predecessor: Vgpr constant loading. 904444ed5c5SDimitry Andric // Low latency instructions usually have a predecessor (the address) 905444ed5c5SDimitry Andric if (SU->Preds.size() > 0 && !DAG->IsLowLatencySU[SU->NodeNum]) 906444ed5c5SDimitry Andric continue; 907444ed5c5SDimitry Andric 908444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 909444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 910444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 911444ed5c5SDimitry Andric continue; 912444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 913444ed5c5SDimitry Andric } 914444ed5c5SDimitry Andric if (SUColors.size() == 1) 915444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 916444ed5c5SDimitry Andric } 917444ed5c5SDimitry Andric } 918444ed5c5SDimitry Andric 919444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleNextGroup() { 920444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 921444ed5c5SDimitry Andric 922444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 923444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 924444ed5c5SDimitry Andric std::set<unsigned> SUColors; 925444ed5c5SDimitry Andric 926444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 927444ed5c5SDimitry Andric continue; 928444ed5c5SDimitry Andric 929444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 930444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 931444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 932444ed5c5SDimitry Andric continue; 933444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 934444ed5c5SDimitry Andric } 935444ed5c5SDimitry Andric if (SUColors.size() == 1) 936444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 937444ed5c5SDimitry Andric } 938444ed5c5SDimitry Andric } 939444ed5c5SDimitry Andric 940444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleNextGroupOnlyForReserved() { 941444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 942444ed5c5SDimitry Andric 943444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 944444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 945444ed5c5SDimitry Andric std::set<unsigned> SUColors; 946444ed5c5SDimitry Andric 947444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 948444ed5c5SDimitry Andric continue; 949444ed5c5SDimitry Andric 950444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 951444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 952444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 953444ed5c5SDimitry Andric continue; 954444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 955444ed5c5SDimitry Andric } 956444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() <= DAGSize) 957444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 958444ed5c5SDimitry Andric } 959444ed5c5SDimitry Andric } 960444ed5c5SDimitry Andric 961444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleSmallGroupsToNextGroup() { 962444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 963444ed5c5SDimitry Andric std::map<unsigned, unsigned> ColorCount; 964444ed5c5SDimitry Andric 965444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 966444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 967444ed5c5SDimitry Andric unsigned color = CurrentColoring[SU->NodeNum]; 968444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator Pos = ColorCount.find(color); 969444ed5c5SDimitry Andric if (Pos != ColorCount.end()) { 970444ed5c5SDimitry Andric ++ColorCount[color]; 971444ed5c5SDimitry Andric } else { 972444ed5c5SDimitry Andric ColorCount[color] = 1; 973444ed5c5SDimitry Andric } 974444ed5c5SDimitry Andric } 975444ed5c5SDimitry Andric 976444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 977444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 978444ed5c5SDimitry Andric unsigned color = CurrentColoring[SU->NodeNum]; 979444ed5c5SDimitry Andric std::set<unsigned> SUColors; 980444ed5c5SDimitry Andric 981444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 982444ed5c5SDimitry Andric continue; 983444ed5c5SDimitry Andric 984444ed5c5SDimitry Andric if (ColorCount[color] > 1) 985444ed5c5SDimitry Andric continue; 986444ed5c5SDimitry Andric 987444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 988444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 989444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 990444ed5c5SDimitry Andric continue; 991444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 992444ed5c5SDimitry Andric } 993444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() != color) { 994444ed5c5SDimitry Andric --ColorCount[color]; 995444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 996444ed5c5SDimitry Andric ++ColorCount[*SUColors.begin()]; 997444ed5c5SDimitry Andric } 998444ed5c5SDimitry Andric } 999444ed5c5SDimitry Andric } 1000444ed5c5SDimitry Andric 1001444ed5c5SDimitry Andric void SIScheduleBlockCreator::cutHugeBlocks() { 1002444ed5c5SDimitry Andric // TODO 1003444ed5c5SDimitry Andric } 1004444ed5c5SDimitry Andric 1005444ed5c5SDimitry Andric void SIScheduleBlockCreator::regroupNoUserInstructions() { 1006444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1007444ed5c5SDimitry Andric int GroupID = NextNonReservedID++; 1008444ed5c5SDimitry Andric 1009444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1010444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[DAG->BottomUpIndex2SU[i]]; 1011444ed5c5SDimitry Andric bool hasSuccessor = false; 1012444ed5c5SDimitry Andric 1013444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1014444ed5c5SDimitry Andric continue; 1015444ed5c5SDimitry Andric 1016444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1017444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1018444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1019444ed5c5SDimitry Andric continue; 1020444ed5c5SDimitry Andric hasSuccessor = true; 1021444ed5c5SDimitry Andric } 1022444ed5c5SDimitry Andric if (!hasSuccessor) 1023444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = GroupID; 1024444ed5c5SDimitry Andric } 1025444ed5c5SDimitry Andric } 1026444ed5c5SDimitry Andric 1027444ed5c5SDimitry Andric void SIScheduleBlockCreator::createBlocksForVariant(SISchedulerBlockCreatorVariant BlockVariant) { 1028444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1029444ed5c5SDimitry Andric std::map<unsigned,unsigned> RealID; 1030444ed5c5SDimitry Andric 1031444ed5c5SDimitry Andric CurrentBlocks.clear(); 1032444ed5c5SDimitry Andric CurrentColoring.clear(); 1033444ed5c5SDimitry Andric CurrentColoring.resize(DAGSize, 0); 1034444ed5c5SDimitry Andric Node2CurrentBlock.clear(); 1035444ed5c5SDimitry Andric 1036444ed5c5SDimitry Andric // Restore links previous scheduling variant has overridden. 1037444ed5c5SDimitry Andric DAG->restoreSULinksLeft(); 1038444ed5c5SDimitry Andric 1039444ed5c5SDimitry Andric NextReservedID = 1; 1040444ed5c5SDimitry Andric NextNonReservedID = DAGSize + 1; 1041444ed5c5SDimitry Andric 1042444ed5c5SDimitry Andric DEBUG(dbgs() << "Coloring the graph\n"); 1043444ed5c5SDimitry Andric 1044444ed5c5SDimitry Andric if (BlockVariant == SISchedulerBlockCreatorVariant::LatenciesGrouped) 1045444ed5c5SDimitry Andric colorHighLatenciesGroups(); 1046444ed5c5SDimitry Andric else 1047444ed5c5SDimitry Andric colorHighLatenciesAlone(); 1048444ed5c5SDimitry Andric colorComputeReservedDependencies(); 1049444ed5c5SDimitry Andric colorAccordingToReservedDependencies(); 1050444ed5c5SDimitry Andric colorEndsAccordingToDependencies(); 1051444ed5c5SDimitry Andric if (BlockVariant == SISchedulerBlockCreatorVariant::LatenciesAlonePlusConsecutive) 1052444ed5c5SDimitry Andric colorForceConsecutiveOrderInGroup(); 1053444ed5c5SDimitry Andric regroupNoUserInstructions(); 1054444ed5c5SDimitry Andric colorMergeConstantLoadsNextGroup(); 1055444ed5c5SDimitry Andric colorMergeIfPossibleNextGroupOnlyForReserved(); 1056444ed5c5SDimitry Andric 1057444ed5c5SDimitry Andric // Put SUs of same color into same block 1058444ed5c5SDimitry Andric Node2CurrentBlock.resize(DAGSize, -1); 1059444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1060444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 1061444ed5c5SDimitry Andric unsigned Color = CurrentColoring[SU->NodeNum]; 1062444ed5c5SDimitry Andric if (RealID.find(Color) == RealID.end()) { 1063444ed5c5SDimitry Andric int ID = CurrentBlocks.size(); 1064444ed5c5SDimitry Andric BlockPtrs.push_back( 1065444ed5c5SDimitry Andric make_unique<SIScheduleBlock>(DAG, this, ID)); 1066444ed5c5SDimitry Andric CurrentBlocks.push_back(BlockPtrs.rbegin()->get()); 1067444ed5c5SDimitry Andric RealID[Color] = ID; 1068444ed5c5SDimitry Andric } 1069444ed5c5SDimitry Andric CurrentBlocks[RealID[Color]]->addUnit(SU); 1070444ed5c5SDimitry Andric Node2CurrentBlock[SU->NodeNum] = RealID[Color]; 1071444ed5c5SDimitry Andric } 1072444ed5c5SDimitry Andric 1073444ed5c5SDimitry Andric // Build dependencies between blocks. 1074444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1075444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 1076444ed5c5SDimitry Andric int SUID = Node2CurrentBlock[i]; 1077444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1078444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1079444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1080444ed5c5SDimitry Andric continue; 1081444ed5c5SDimitry Andric if (Node2CurrentBlock[Succ->NodeNum] != SUID) 1082444ed5c5SDimitry Andric CurrentBlocks[SUID]->addSucc(CurrentBlocks[Node2CurrentBlock[Succ->NodeNum]]); 1083444ed5c5SDimitry Andric } 1084444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 1085444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 1086444ed5c5SDimitry Andric if (PredDep.isWeak() || Pred->NodeNum >= DAGSize) 1087444ed5c5SDimitry Andric continue; 1088444ed5c5SDimitry Andric if (Node2CurrentBlock[Pred->NodeNum] != SUID) 1089444ed5c5SDimitry Andric CurrentBlocks[SUID]->addPred(CurrentBlocks[Node2CurrentBlock[Pred->NodeNum]]); 1090444ed5c5SDimitry Andric } 1091444ed5c5SDimitry Andric } 1092444ed5c5SDimitry Andric 1093444ed5c5SDimitry Andric // Free root and leafs of all blocks to enable scheduling inside them. 1094444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1095444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1096444ed5c5SDimitry Andric Block->finalizeUnits(); 1097444ed5c5SDimitry Andric } 1098444ed5c5SDimitry Andric DEBUG( 1099444ed5c5SDimitry Andric dbgs() << "Blocks created:\n\n"; 1100444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1101444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1102444ed5c5SDimitry Andric Block->printDebug(true); 1103444ed5c5SDimitry Andric } 1104444ed5c5SDimitry Andric ); 1105444ed5c5SDimitry Andric } 1106444ed5c5SDimitry Andric 1107444ed5c5SDimitry Andric // Two functions taken from Codegen/MachineScheduler.cpp 1108444ed5c5SDimitry Andric 1109444ed5c5SDimitry Andric /// If this iterator is a debug value, increment until reaching the End or a 1110444ed5c5SDimitry Andric /// non-debug instruction. 1111444ed5c5SDimitry Andric static MachineBasicBlock::const_iterator 1112444ed5c5SDimitry Andric nextIfDebug(MachineBasicBlock::const_iterator I, 1113444ed5c5SDimitry Andric MachineBasicBlock::const_iterator End) { 1114444ed5c5SDimitry Andric for(; I != End; ++I) { 1115444ed5c5SDimitry Andric if (!I->isDebugValue()) 1116444ed5c5SDimitry Andric break; 1117444ed5c5SDimitry Andric } 1118444ed5c5SDimitry Andric return I; 1119444ed5c5SDimitry Andric } 1120444ed5c5SDimitry Andric 1121444ed5c5SDimitry Andric /// Non-const version. 1122444ed5c5SDimitry Andric static MachineBasicBlock::iterator 1123444ed5c5SDimitry Andric nextIfDebug(MachineBasicBlock::iterator I, 1124444ed5c5SDimitry Andric MachineBasicBlock::const_iterator End) { 1125444ed5c5SDimitry Andric // Cast the return value to nonconst MachineInstr, then cast to an 1126444ed5c5SDimitry Andric // instr_iterator, which does not check for null, finally return a 1127444ed5c5SDimitry Andric // bundle_iterator. 1128444ed5c5SDimitry Andric return MachineBasicBlock::instr_iterator( 1129444ed5c5SDimitry Andric const_cast<MachineInstr*>( 1130444ed5c5SDimitry Andric &*nextIfDebug(MachineBasicBlock::const_iterator(I), End))); 1131444ed5c5SDimitry Andric } 1132444ed5c5SDimitry Andric 1133444ed5c5SDimitry Andric void SIScheduleBlockCreator::topologicalSort() { 1134444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1135444ed5c5SDimitry Andric std::vector<int> WorkList; 1136444ed5c5SDimitry Andric 1137444ed5c5SDimitry Andric DEBUG(dbgs() << "Topological Sort\n"); 1138444ed5c5SDimitry Andric 1139444ed5c5SDimitry Andric WorkList.reserve(DAGSize); 1140444ed5c5SDimitry Andric TopDownIndex2Block.resize(DAGSize); 1141444ed5c5SDimitry Andric TopDownBlock2Index.resize(DAGSize); 1142444ed5c5SDimitry Andric BottomUpIndex2Block.resize(DAGSize); 1143444ed5c5SDimitry Andric 1144444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1145444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1146444ed5c5SDimitry Andric unsigned Degree = Block->getSuccs().size(); 1147444ed5c5SDimitry Andric TopDownBlock2Index[i] = Degree; 1148444ed5c5SDimitry Andric if (Degree == 0) { 1149444ed5c5SDimitry Andric WorkList.push_back(i); 1150444ed5c5SDimitry Andric } 1151444ed5c5SDimitry Andric } 1152444ed5c5SDimitry Andric 1153444ed5c5SDimitry Andric int Id = DAGSize; 1154444ed5c5SDimitry Andric while (!WorkList.empty()) { 1155444ed5c5SDimitry Andric int i = WorkList.back(); 1156444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1157444ed5c5SDimitry Andric WorkList.pop_back(); 1158444ed5c5SDimitry Andric TopDownBlock2Index[i] = --Id; 1159444ed5c5SDimitry Andric TopDownIndex2Block[Id] = i; 1160444ed5c5SDimitry Andric for (SIScheduleBlock* Pred : Block->getPreds()) { 1161444ed5c5SDimitry Andric if (!--TopDownBlock2Index[Pred->getID()]) 1162444ed5c5SDimitry Andric WorkList.push_back(Pred->getID()); 1163444ed5c5SDimitry Andric } 1164444ed5c5SDimitry Andric } 1165444ed5c5SDimitry Andric 1166444ed5c5SDimitry Andric #ifndef NDEBUG 1167444ed5c5SDimitry Andric // Check correctness of the ordering. 1168444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1169444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1170444ed5c5SDimitry Andric for (SIScheduleBlock* Pred : Block->getPreds()) { 1171444ed5c5SDimitry Andric assert(TopDownBlock2Index[i] > TopDownBlock2Index[Pred->getID()] && 1172444ed5c5SDimitry Andric "Wrong Top Down topological sorting"); 1173444ed5c5SDimitry Andric } 1174444ed5c5SDimitry Andric } 1175444ed5c5SDimitry Andric #endif 1176444ed5c5SDimitry Andric 1177444ed5c5SDimitry Andric BottomUpIndex2Block = std::vector<int>(TopDownIndex2Block.rbegin(), 1178444ed5c5SDimitry Andric TopDownIndex2Block.rend()); 1179444ed5c5SDimitry Andric } 1180444ed5c5SDimitry Andric 1181444ed5c5SDimitry Andric void SIScheduleBlockCreator::scheduleInsideBlocks() { 1182444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1183444ed5c5SDimitry Andric 1184444ed5c5SDimitry Andric DEBUG(dbgs() << "\nScheduling Blocks\n\n"); 1185444ed5c5SDimitry Andric 1186444ed5c5SDimitry Andric // We do schedule a valid scheduling such that a Block corresponds 1187444ed5c5SDimitry Andric // to a range of instructions. 1188444ed5c5SDimitry Andric DEBUG(dbgs() << "First phase: Fast scheduling for Reg Liveness\n"); 1189444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1190444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1191444ed5c5SDimitry Andric Block->fastSchedule(); 1192444ed5c5SDimitry Andric } 1193444ed5c5SDimitry Andric 1194444ed5c5SDimitry Andric // Note: the following code, and the part restoring previous position 1195444ed5c5SDimitry Andric // is by far the most expensive operation of the Scheduler. 1196444ed5c5SDimitry Andric 1197444ed5c5SDimitry Andric // Do not update CurrentTop. 1198444ed5c5SDimitry Andric MachineBasicBlock::iterator CurrentTopFastSched = DAG->getCurrentTop(); 1199444ed5c5SDimitry Andric std::vector<MachineBasicBlock::iterator> PosOld; 1200444ed5c5SDimitry Andric std::vector<MachineBasicBlock::iterator> PosNew; 1201444ed5c5SDimitry Andric PosOld.reserve(DAG->SUnits.size()); 1202444ed5c5SDimitry Andric PosNew.reserve(DAG->SUnits.size()); 1203444ed5c5SDimitry Andric 1204444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1205444ed5c5SDimitry Andric int BlockIndice = TopDownIndex2Block[i]; 1206444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1207444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1208444ed5c5SDimitry Andric 1209444ed5c5SDimitry Andric for (SUnit* SU : SUs) { 1210444ed5c5SDimitry Andric MachineInstr *MI = SU->getInstr(); 1211444ed5c5SDimitry Andric MachineBasicBlock::iterator Pos = MI; 1212444ed5c5SDimitry Andric PosOld.push_back(Pos); 1213444ed5c5SDimitry Andric if (&*CurrentTopFastSched == MI) { 1214444ed5c5SDimitry Andric PosNew.push_back(Pos); 1215444ed5c5SDimitry Andric CurrentTopFastSched = nextIfDebug(++CurrentTopFastSched, 1216444ed5c5SDimitry Andric DAG->getCurrentBottom()); 1217444ed5c5SDimitry Andric } else { 1218444ed5c5SDimitry Andric // Update the instruction stream. 1219444ed5c5SDimitry Andric DAG->getBB()->splice(CurrentTopFastSched, DAG->getBB(), MI); 1220444ed5c5SDimitry Andric 1221444ed5c5SDimitry Andric // Update LiveIntervals. 1222444ed5c5SDimitry Andric // Note: Moving all instructions and calling handleMove everytime 1223444ed5c5SDimitry Andric // is the most cpu intensive operation of the scheduler. 1224444ed5c5SDimitry Andric // It would gain a lot if there was a way to recompute the 1225444ed5c5SDimitry Andric // LiveIntervals for the entire scheduling region. 1226444ed5c5SDimitry Andric DAG->getLIS()->handleMove(MI, /*UpdateFlags=*/true); 1227444ed5c5SDimitry Andric PosNew.push_back(CurrentTopFastSched); 1228444ed5c5SDimitry Andric } 1229444ed5c5SDimitry Andric } 1230444ed5c5SDimitry Andric } 1231444ed5c5SDimitry Andric 1232444ed5c5SDimitry Andric // Now we have Block of SUs == Block of MI. 1233444ed5c5SDimitry Andric // We do the final schedule for the instructions inside the block. 1234444ed5c5SDimitry Andric // The property that all the SUs of the Block are grouped together as MI 1235444ed5c5SDimitry Andric // is used for correct reg usage tracking. 1236444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1237444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1238444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1239444ed5c5SDimitry Andric Block->schedule((*SUs.begin())->getInstr(), (*SUs.rbegin())->getInstr()); 1240444ed5c5SDimitry Andric } 1241444ed5c5SDimitry Andric 1242444ed5c5SDimitry Andric DEBUG(dbgs() << "Restoring MI Pos\n"); 1243444ed5c5SDimitry Andric // Restore old ordering (which prevents a LIS->handleMove bug). 1244444ed5c5SDimitry Andric for (unsigned i = PosOld.size(), e = 0; i != e; --i) { 1245444ed5c5SDimitry Andric MachineBasicBlock::iterator POld = PosOld[i-1]; 1246444ed5c5SDimitry Andric MachineBasicBlock::iterator PNew = PosNew[i-1]; 1247444ed5c5SDimitry Andric if (PNew != POld) { 1248444ed5c5SDimitry Andric // Update the instruction stream. 1249444ed5c5SDimitry Andric DAG->getBB()->splice(POld, DAG->getBB(), PNew); 1250444ed5c5SDimitry Andric 1251444ed5c5SDimitry Andric // Update LiveIntervals. 1252444ed5c5SDimitry Andric DAG->getLIS()->handleMove(POld, /*UpdateFlags=*/true); 1253444ed5c5SDimitry Andric } 1254444ed5c5SDimitry Andric } 1255444ed5c5SDimitry Andric 1256444ed5c5SDimitry Andric DEBUG( 1257444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1258444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1259444ed5c5SDimitry Andric Block->printDebug(true); 1260444ed5c5SDimitry Andric } 1261444ed5c5SDimitry Andric ); 1262444ed5c5SDimitry Andric } 1263444ed5c5SDimitry Andric 1264444ed5c5SDimitry Andric void SIScheduleBlockCreator::fillStats() { 1265444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1266444ed5c5SDimitry Andric 1267444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1268444ed5c5SDimitry Andric int BlockIndice = TopDownIndex2Block[i]; 1269444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1270444ed5c5SDimitry Andric if (Block->getPreds().size() == 0) 1271444ed5c5SDimitry Andric Block->Depth = 0; 1272444ed5c5SDimitry Andric else { 1273444ed5c5SDimitry Andric unsigned Depth = 0; 1274444ed5c5SDimitry Andric for (SIScheduleBlock *Pred : Block->getPreds()) { 1275444ed5c5SDimitry Andric if (Depth < Pred->Depth + 1) 1276444ed5c5SDimitry Andric Depth = Pred->Depth + 1; 1277444ed5c5SDimitry Andric } 1278444ed5c5SDimitry Andric Block->Depth = Depth; 1279444ed5c5SDimitry Andric } 1280444ed5c5SDimitry Andric } 1281444ed5c5SDimitry Andric 1282444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1283444ed5c5SDimitry Andric int BlockIndice = BottomUpIndex2Block[i]; 1284444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1285444ed5c5SDimitry Andric if (Block->getSuccs().size() == 0) 1286444ed5c5SDimitry Andric Block->Height = 0; 1287444ed5c5SDimitry Andric else { 1288444ed5c5SDimitry Andric unsigned Height = 0; 1289444ed5c5SDimitry Andric for (SIScheduleBlock *Succ : Block->getSuccs()) { 1290444ed5c5SDimitry Andric if (Height < Succ->Height + 1) 1291444ed5c5SDimitry Andric Height = Succ->Height + 1; 1292444ed5c5SDimitry Andric } 1293444ed5c5SDimitry Andric Block->Height = Height; 1294444ed5c5SDimitry Andric } 1295444ed5c5SDimitry Andric } 1296444ed5c5SDimitry Andric } 1297444ed5c5SDimitry Andric 1298444ed5c5SDimitry Andric // SIScheduleBlockScheduler // 1299444ed5c5SDimitry Andric 1300444ed5c5SDimitry Andric SIScheduleBlockScheduler::SIScheduleBlockScheduler(SIScheduleDAGMI *DAG, 1301444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant Variant, 1302444ed5c5SDimitry Andric SIScheduleBlocks BlocksStruct) : 1303444ed5c5SDimitry Andric DAG(DAG), Variant(Variant), Blocks(BlocksStruct.Blocks), 1304444ed5c5SDimitry Andric LastPosWaitedHighLatency(0), NumBlockScheduled(0), VregCurrentUsage(0), 1305444ed5c5SDimitry Andric SregCurrentUsage(0), maxVregUsage(0), maxSregUsage(0) { 1306444ed5c5SDimitry Andric 1307444ed5c5SDimitry Andric // Fill the usage of every output 1308444ed5c5SDimitry Andric // Warning: while by construction we always have a link between two blocks 1309444ed5c5SDimitry Andric // when one needs a result from the other, the number of users of an output 1310444ed5c5SDimitry Andric // is not the sum of child blocks having as input the same virtual register. 1311444ed5c5SDimitry Andric // Here is an example. A produces x and y. B eats x and produces x'. 1312444ed5c5SDimitry Andric // C eats x' and y. The register coalescer may have attributed the same 1313444ed5c5SDimitry Andric // virtual register to x and x'. 1314444ed5c5SDimitry Andric // To count accurately, we do a topological sort. In case the register is 1315444ed5c5SDimitry Andric // found for several parents, we increment the usage of the one with the 1316444ed5c5SDimitry Andric // highest topological index. 1317444ed5c5SDimitry Andric LiveOutRegsNumUsages.resize(Blocks.size()); 1318444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1319444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1320444ed5c5SDimitry Andric for (unsigned Reg : Block->getInRegs()) { 1321444ed5c5SDimitry Andric bool Found = false; 1322444ed5c5SDimitry Andric int topoInd = -1; 1323444ed5c5SDimitry Andric for (SIScheduleBlock* Pred: Block->getPreds()) { 1324444ed5c5SDimitry Andric std::set<unsigned> PredOutRegs = Pred->getOutRegs(); 1325444ed5c5SDimitry Andric std::set<unsigned>::iterator RegPos = PredOutRegs.find(Reg); 1326444ed5c5SDimitry Andric 1327444ed5c5SDimitry Andric if (RegPos != PredOutRegs.end()) { 1328444ed5c5SDimitry Andric Found = true; 1329444ed5c5SDimitry Andric if (topoInd < BlocksStruct.TopDownBlock2Index[Pred->getID()]) { 1330444ed5c5SDimitry Andric topoInd = BlocksStruct.TopDownBlock2Index[Pred->getID()]; 1331444ed5c5SDimitry Andric } 1332444ed5c5SDimitry Andric } 1333444ed5c5SDimitry Andric } 1334444ed5c5SDimitry Andric 1335444ed5c5SDimitry Andric if (!Found) 1336444ed5c5SDimitry Andric continue; 1337444ed5c5SDimitry Andric 1338444ed5c5SDimitry Andric int PredID = BlocksStruct.TopDownIndex2Block[topoInd]; 1339444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator RegPos = 1340444ed5c5SDimitry Andric LiveOutRegsNumUsages[PredID].find(Reg); 1341444ed5c5SDimitry Andric if (RegPos != LiveOutRegsNumUsages[PredID].end()) { 1342444ed5c5SDimitry Andric ++LiveOutRegsNumUsages[PredID][Reg]; 1343444ed5c5SDimitry Andric } else { 1344444ed5c5SDimitry Andric LiveOutRegsNumUsages[PredID][Reg] = 1; 1345444ed5c5SDimitry Andric } 1346444ed5c5SDimitry Andric } 1347444ed5c5SDimitry Andric } 1348444ed5c5SDimitry Andric 1349444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled.resize(Blocks.size(), 0); 1350444ed5c5SDimitry Andric BlockNumPredsLeft.resize(Blocks.size()); 1351444ed5c5SDimitry Andric BlockNumSuccsLeft.resize(Blocks.size()); 1352444ed5c5SDimitry Andric 1353444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1354444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1355444ed5c5SDimitry Andric BlockNumPredsLeft[i] = Block->getPreds().size(); 1356444ed5c5SDimitry Andric BlockNumSuccsLeft[i] = Block->getSuccs().size(); 1357444ed5c5SDimitry Andric } 1358444ed5c5SDimitry Andric 1359444ed5c5SDimitry Andric #ifndef NDEBUG 1360444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1361444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1362444ed5c5SDimitry Andric assert(Block->getID() == i); 1363444ed5c5SDimitry Andric } 1364444ed5c5SDimitry Andric #endif 1365444ed5c5SDimitry Andric 1366444ed5c5SDimitry Andric std::set<unsigned> InRegs = DAG->getInRegs(); 1367444ed5c5SDimitry Andric addLiveRegs(InRegs); 1368444ed5c5SDimitry Andric 1369444ed5c5SDimitry Andric // Fill LiveRegsConsumers for regs that were already 1370444ed5c5SDimitry Andric // defined before scheduling. 1371444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1372444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1373444ed5c5SDimitry Andric for (unsigned Reg : Block->getInRegs()) { 1374444ed5c5SDimitry Andric bool Found = false; 1375444ed5c5SDimitry Andric for (SIScheduleBlock* Pred: Block->getPreds()) { 1376444ed5c5SDimitry Andric std::set<unsigned> PredOutRegs = Pred->getOutRegs(); 1377444ed5c5SDimitry Andric std::set<unsigned>::iterator RegPos = PredOutRegs.find(Reg); 1378444ed5c5SDimitry Andric 1379444ed5c5SDimitry Andric if (RegPos != PredOutRegs.end()) { 1380444ed5c5SDimitry Andric Found = true; 1381444ed5c5SDimitry Andric break; 1382444ed5c5SDimitry Andric } 1383444ed5c5SDimitry Andric } 1384444ed5c5SDimitry Andric 1385444ed5c5SDimitry Andric if (!Found) { 1386444ed5c5SDimitry Andric if (LiveRegsConsumers.find(Reg) == LiveRegsConsumers.end()) 1387444ed5c5SDimitry Andric LiveRegsConsumers[Reg] = 1; 1388444ed5c5SDimitry Andric else 1389444ed5c5SDimitry Andric ++LiveRegsConsumers[Reg]; 1390444ed5c5SDimitry Andric } 1391444ed5c5SDimitry Andric } 1392444ed5c5SDimitry Andric } 1393444ed5c5SDimitry Andric 1394444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1395444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1396444ed5c5SDimitry Andric if (BlockNumPredsLeft[i] == 0) { 1397444ed5c5SDimitry Andric ReadyBlocks.push_back(Block); 1398444ed5c5SDimitry Andric } 1399444ed5c5SDimitry Andric } 1400444ed5c5SDimitry Andric 1401444ed5c5SDimitry Andric while (SIScheduleBlock *Block = pickBlock()) { 1402444ed5c5SDimitry Andric BlocksScheduled.push_back(Block); 1403444ed5c5SDimitry Andric blockScheduled(Block); 1404444ed5c5SDimitry Andric } 1405444ed5c5SDimitry Andric 1406444ed5c5SDimitry Andric DEBUG( 1407444ed5c5SDimitry Andric dbgs() << "Block Order:"; 1408444ed5c5SDimitry Andric for (SIScheduleBlock* Block : BlocksScheduled) { 1409444ed5c5SDimitry Andric dbgs() << ' ' << Block->getID(); 1410444ed5c5SDimitry Andric } 1411444ed5c5SDimitry Andric ); 1412444ed5c5SDimitry Andric } 1413444ed5c5SDimitry Andric 1414444ed5c5SDimitry Andric bool SIScheduleBlockScheduler::tryCandidateLatency(SIBlockSchedCandidate &Cand, 1415444ed5c5SDimitry Andric SIBlockSchedCandidate &TryCand) { 1416444ed5c5SDimitry Andric if (!Cand.isValid()) { 1417444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 1418444ed5c5SDimitry Andric return true; 1419444ed5c5SDimitry Andric } 1420444ed5c5SDimitry Andric 1421444ed5c5SDimitry Andric // Try to hide high latencies. 1422444ed5c5SDimitry Andric if (tryLess(TryCand.LastPosHighLatParentScheduled, 1423444ed5c5SDimitry Andric Cand.LastPosHighLatParentScheduled, TryCand, Cand, Latency)) 1424444ed5c5SDimitry Andric return true; 1425444ed5c5SDimitry Andric // Schedule high latencies early so you can hide them better. 1426444ed5c5SDimitry Andric if (tryGreater(TryCand.IsHighLatency, Cand.IsHighLatency, 1427444ed5c5SDimitry Andric TryCand, Cand, Latency)) 1428444ed5c5SDimitry Andric return true; 1429444ed5c5SDimitry Andric if (TryCand.IsHighLatency && tryGreater(TryCand.Height, Cand.Height, 1430444ed5c5SDimitry Andric TryCand, Cand, Depth)) 1431444ed5c5SDimitry Andric return true; 1432444ed5c5SDimitry Andric if (tryGreater(TryCand.NumHighLatencySuccessors, 1433444ed5c5SDimitry Andric Cand.NumHighLatencySuccessors, 1434444ed5c5SDimitry Andric TryCand, Cand, Successor)) 1435444ed5c5SDimitry Andric return true; 1436444ed5c5SDimitry Andric return false; 1437444ed5c5SDimitry Andric } 1438444ed5c5SDimitry Andric 1439444ed5c5SDimitry Andric bool SIScheduleBlockScheduler::tryCandidateRegUsage(SIBlockSchedCandidate &Cand, 1440444ed5c5SDimitry Andric SIBlockSchedCandidate &TryCand) { 1441444ed5c5SDimitry Andric if (!Cand.isValid()) { 1442444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 1443444ed5c5SDimitry Andric return true; 1444444ed5c5SDimitry Andric } 1445444ed5c5SDimitry Andric 1446444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsageDiff > 0, Cand.VGPRUsageDiff > 0, 1447444ed5c5SDimitry Andric TryCand, Cand, RegUsage)) 1448444ed5c5SDimitry Andric return true; 1449444ed5c5SDimitry Andric if (tryGreater(TryCand.NumSuccessors > 0, 1450444ed5c5SDimitry Andric Cand.NumSuccessors > 0, 1451444ed5c5SDimitry Andric TryCand, Cand, Successor)) 1452444ed5c5SDimitry Andric return true; 1453444ed5c5SDimitry Andric if (tryGreater(TryCand.Height, Cand.Height, TryCand, Cand, Depth)) 1454444ed5c5SDimitry Andric return true; 1455444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsageDiff, Cand.VGPRUsageDiff, 1456444ed5c5SDimitry Andric TryCand, Cand, RegUsage)) 1457444ed5c5SDimitry Andric return true; 1458444ed5c5SDimitry Andric return false; 1459444ed5c5SDimitry Andric } 1460444ed5c5SDimitry Andric 1461444ed5c5SDimitry Andric SIScheduleBlock *SIScheduleBlockScheduler::pickBlock() { 1462444ed5c5SDimitry Andric SIBlockSchedCandidate Cand; 1463444ed5c5SDimitry Andric std::vector<SIScheduleBlock*>::iterator Best; 1464444ed5c5SDimitry Andric SIScheduleBlock *Block; 1465444ed5c5SDimitry Andric if (ReadyBlocks.empty()) 1466444ed5c5SDimitry Andric return nullptr; 1467444ed5c5SDimitry Andric 1468444ed5c5SDimitry Andric DAG->fillVgprSgprCost(LiveRegs.begin(), LiveRegs.end(), 1469444ed5c5SDimitry Andric VregCurrentUsage, SregCurrentUsage); 1470444ed5c5SDimitry Andric if (VregCurrentUsage > maxVregUsage) 1471444ed5c5SDimitry Andric maxVregUsage = VregCurrentUsage; 1472444ed5c5SDimitry Andric if (VregCurrentUsage > maxSregUsage) 1473444ed5c5SDimitry Andric maxSregUsage = VregCurrentUsage; 1474444ed5c5SDimitry Andric DEBUG( 1475444ed5c5SDimitry Andric dbgs() << "Picking New Blocks\n"; 1476444ed5c5SDimitry Andric dbgs() << "Available: "; 1477444ed5c5SDimitry Andric for (SIScheduleBlock* Block : ReadyBlocks) 1478444ed5c5SDimitry Andric dbgs() << Block->getID() << ' '; 1479444ed5c5SDimitry Andric dbgs() << "\nCurrent Live:\n"; 1480444ed5c5SDimitry Andric for (unsigned Reg : LiveRegs) 1481444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 1482444ed5c5SDimitry Andric dbgs() << '\n'; 1483444ed5c5SDimitry Andric dbgs() << "Current VGPRs: " << VregCurrentUsage << '\n'; 1484444ed5c5SDimitry Andric dbgs() << "Current SGPRs: " << SregCurrentUsage << '\n'; 1485444ed5c5SDimitry Andric ); 1486444ed5c5SDimitry Andric 1487444ed5c5SDimitry Andric Cand.Block = nullptr; 1488444ed5c5SDimitry Andric for (std::vector<SIScheduleBlock*>::iterator I = ReadyBlocks.begin(), 1489444ed5c5SDimitry Andric E = ReadyBlocks.end(); I != E; ++I) { 1490444ed5c5SDimitry Andric SIBlockSchedCandidate TryCand; 1491444ed5c5SDimitry Andric TryCand.Block = *I; 1492444ed5c5SDimitry Andric TryCand.IsHighLatency = TryCand.Block->isHighLatencyBlock(); 1493444ed5c5SDimitry Andric TryCand.VGPRUsageDiff = 1494444ed5c5SDimitry Andric checkRegUsageImpact(TryCand.Block->getInRegs(), 1495444ed5c5SDimitry Andric TryCand.Block->getOutRegs())[DAG->getVGPRSetID()]; 1496444ed5c5SDimitry Andric TryCand.NumSuccessors = TryCand.Block->getSuccs().size(); 1497444ed5c5SDimitry Andric TryCand.NumHighLatencySuccessors = 1498444ed5c5SDimitry Andric TryCand.Block->getNumHighLatencySuccessors(); 1499444ed5c5SDimitry Andric TryCand.LastPosHighLatParentScheduled = 1500444ed5c5SDimitry Andric (unsigned int) std::max<int> (0, 1501444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[TryCand.Block->getID()] - 1502444ed5c5SDimitry Andric LastPosWaitedHighLatency); 1503444ed5c5SDimitry Andric TryCand.Height = TryCand.Block->Height; 1504444ed5c5SDimitry Andric // Try not to increase VGPR usage too much, else we may spill. 1505444ed5c5SDimitry Andric if (VregCurrentUsage > 120 || 1506444ed5c5SDimitry Andric Variant != SISchedulerBlockSchedulerVariant::BlockLatencyRegUsage) { 1507444ed5c5SDimitry Andric if (!tryCandidateRegUsage(Cand, TryCand) && 1508444ed5c5SDimitry Andric Variant != SISchedulerBlockSchedulerVariant::BlockRegUsage) 1509444ed5c5SDimitry Andric tryCandidateLatency(Cand, TryCand); 1510444ed5c5SDimitry Andric } else { 1511444ed5c5SDimitry Andric if (!tryCandidateLatency(Cand, TryCand)) 1512444ed5c5SDimitry Andric tryCandidateRegUsage(Cand, TryCand); 1513444ed5c5SDimitry Andric } 1514444ed5c5SDimitry Andric if (TryCand.Reason != NoCand) { 1515444ed5c5SDimitry Andric Cand.setBest(TryCand); 1516444ed5c5SDimitry Andric Best = I; 1517444ed5c5SDimitry Andric DEBUG(dbgs() << "Best Current Choice: " << Cand.Block->getID() << ' ' 1518444ed5c5SDimitry Andric << getReasonStr(Cand.Reason) << '\n'); 1519444ed5c5SDimitry Andric } 1520444ed5c5SDimitry Andric } 1521444ed5c5SDimitry Andric 1522444ed5c5SDimitry Andric DEBUG( 1523444ed5c5SDimitry Andric dbgs() << "Picking: " << Cand.Block->getID() << '\n'; 1524444ed5c5SDimitry Andric dbgs() << "Is a block with high latency instruction: " 1525444ed5c5SDimitry Andric << (Cand.IsHighLatency ? "yes\n" : "no\n"); 1526444ed5c5SDimitry Andric dbgs() << "Position of last high latency dependency: " 1527444ed5c5SDimitry Andric << Cand.LastPosHighLatParentScheduled << '\n'; 1528444ed5c5SDimitry Andric dbgs() << "VGPRUsageDiff: " << Cand.VGPRUsageDiff << '\n'; 1529444ed5c5SDimitry Andric dbgs() << '\n'; 1530444ed5c5SDimitry Andric ); 1531444ed5c5SDimitry Andric 1532444ed5c5SDimitry Andric Block = Cand.Block; 1533444ed5c5SDimitry Andric ReadyBlocks.erase(Best); 1534444ed5c5SDimitry Andric return Block; 1535444ed5c5SDimitry Andric } 1536444ed5c5SDimitry Andric 1537444ed5c5SDimitry Andric // Tracking of currently alive registers to determine VGPR Usage. 1538444ed5c5SDimitry Andric 1539444ed5c5SDimitry Andric void SIScheduleBlockScheduler::addLiveRegs(std::set<unsigned> &Regs) { 1540444ed5c5SDimitry Andric for (unsigned Reg : Regs) { 1541444ed5c5SDimitry Andric // For now only track virtual registers. 1542444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1543444ed5c5SDimitry Andric continue; 1544444ed5c5SDimitry Andric // If not already in the live set, then add it. 1545444ed5c5SDimitry Andric (void) LiveRegs.insert(Reg); 1546444ed5c5SDimitry Andric } 1547444ed5c5SDimitry Andric } 1548444ed5c5SDimitry Andric 1549444ed5c5SDimitry Andric void SIScheduleBlockScheduler::decreaseLiveRegs(SIScheduleBlock *Block, 1550444ed5c5SDimitry Andric std::set<unsigned> &Regs) { 1551444ed5c5SDimitry Andric for (unsigned Reg : Regs) { 1552444ed5c5SDimitry Andric // For now only track virtual registers. 1553444ed5c5SDimitry Andric std::set<unsigned>::iterator Pos = LiveRegs.find(Reg); 1554444ed5c5SDimitry Andric assert (Pos != LiveRegs.end() && // Reg must be live. 1555444ed5c5SDimitry Andric LiveRegsConsumers.find(Reg) != LiveRegsConsumers.end() && 1556444ed5c5SDimitry Andric LiveRegsConsumers[Reg] >= 1); 1557444ed5c5SDimitry Andric --LiveRegsConsumers[Reg]; 1558444ed5c5SDimitry Andric if (LiveRegsConsumers[Reg] == 0) 1559444ed5c5SDimitry Andric LiveRegs.erase(Pos); 1560444ed5c5SDimitry Andric } 1561444ed5c5SDimitry Andric } 1562444ed5c5SDimitry Andric 1563444ed5c5SDimitry Andric void SIScheduleBlockScheduler::releaseBlockSuccs(SIScheduleBlock *Parent) { 1564444ed5c5SDimitry Andric for (SIScheduleBlock* Block : Parent->getSuccs()) { 1565444ed5c5SDimitry Andric --BlockNumPredsLeft[Block->getID()]; 1566444ed5c5SDimitry Andric if (BlockNumPredsLeft[Block->getID()] == 0) { 1567444ed5c5SDimitry Andric ReadyBlocks.push_back(Block); 1568444ed5c5SDimitry Andric } 1569444ed5c5SDimitry Andric // TODO: Improve check. When the dependency between the high latency 1570444ed5c5SDimitry Andric // instructions and the instructions of the other blocks are WAR or WAW 1571444ed5c5SDimitry Andric // there will be no wait triggered. We would like these cases to not 1572444ed5c5SDimitry Andric // update LastPosHighLatencyParentScheduled. 1573444ed5c5SDimitry Andric if (Parent->isHighLatencyBlock()) 1574444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[Block->getID()] = NumBlockScheduled; 1575444ed5c5SDimitry Andric } 1576444ed5c5SDimitry Andric } 1577444ed5c5SDimitry Andric 1578444ed5c5SDimitry Andric void SIScheduleBlockScheduler::blockScheduled(SIScheduleBlock *Block) { 1579444ed5c5SDimitry Andric decreaseLiveRegs(Block, Block->getInRegs()); 1580444ed5c5SDimitry Andric addLiveRegs(Block->getOutRegs()); 1581444ed5c5SDimitry Andric releaseBlockSuccs(Block); 1582444ed5c5SDimitry Andric for (std::map<unsigned, unsigned>::iterator RegI = 1583444ed5c5SDimitry Andric LiveOutRegsNumUsages[Block->getID()].begin(), 1584444ed5c5SDimitry Andric E = LiveOutRegsNumUsages[Block->getID()].end(); RegI != E; ++RegI) { 1585444ed5c5SDimitry Andric std::pair<unsigned, unsigned> RegP = *RegI; 1586444ed5c5SDimitry Andric if (LiveRegsConsumers.find(RegP.first) == LiveRegsConsumers.end()) 1587444ed5c5SDimitry Andric LiveRegsConsumers[RegP.first] = RegP.second; 1588444ed5c5SDimitry Andric else { 1589444ed5c5SDimitry Andric assert(LiveRegsConsumers[RegP.first] == 0); 1590444ed5c5SDimitry Andric LiveRegsConsumers[RegP.first] += RegP.second; 1591444ed5c5SDimitry Andric } 1592444ed5c5SDimitry Andric } 1593444ed5c5SDimitry Andric if (LastPosHighLatencyParentScheduled[Block->getID()] > 1594444ed5c5SDimitry Andric (unsigned)LastPosWaitedHighLatency) 1595444ed5c5SDimitry Andric LastPosWaitedHighLatency = 1596444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[Block->getID()]; 1597444ed5c5SDimitry Andric ++NumBlockScheduled; 1598444ed5c5SDimitry Andric } 1599444ed5c5SDimitry Andric 1600444ed5c5SDimitry Andric std::vector<int> 1601444ed5c5SDimitry Andric SIScheduleBlockScheduler::checkRegUsageImpact(std::set<unsigned> &InRegs, 1602444ed5c5SDimitry Andric std::set<unsigned> &OutRegs) { 1603444ed5c5SDimitry Andric std::vector<int> DiffSetPressure; 1604444ed5c5SDimitry Andric DiffSetPressure.assign(DAG->getTRI()->getNumRegPressureSets(), 0); 1605444ed5c5SDimitry Andric 1606444ed5c5SDimitry Andric for (unsigned Reg : InRegs) { 1607444ed5c5SDimitry Andric // For now only track virtual registers. 1608444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1609444ed5c5SDimitry Andric continue; 1610444ed5c5SDimitry Andric if (LiveRegsConsumers[Reg] > 1) 1611444ed5c5SDimitry Andric continue; 1612444ed5c5SDimitry Andric PSetIterator PSetI = DAG->getMRI()->getPressureSets(Reg); 1613444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1614444ed5c5SDimitry Andric DiffSetPressure[*PSetI] -= PSetI.getWeight(); 1615444ed5c5SDimitry Andric } 1616444ed5c5SDimitry Andric } 1617444ed5c5SDimitry Andric 1618444ed5c5SDimitry Andric for (unsigned Reg : OutRegs) { 1619444ed5c5SDimitry Andric // For now only track virtual registers. 1620444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1621444ed5c5SDimitry Andric continue; 1622444ed5c5SDimitry Andric PSetIterator PSetI = DAG->getMRI()->getPressureSets(Reg); 1623444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1624444ed5c5SDimitry Andric DiffSetPressure[*PSetI] += PSetI.getWeight(); 1625444ed5c5SDimitry Andric } 1626444ed5c5SDimitry Andric } 1627444ed5c5SDimitry Andric 1628444ed5c5SDimitry Andric return DiffSetPressure; 1629444ed5c5SDimitry Andric } 1630444ed5c5SDimitry Andric 1631444ed5c5SDimitry Andric // SIScheduler // 1632444ed5c5SDimitry Andric 1633444ed5c5SDimitry Andric struct SIScheduleBlockResult 1634444ed5c5SDimitry Andric SIScheduler::scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant, 1635444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant ScheduleVariant) { 1636444ed5c5SDimitry Andric SIScheduleBlocks Blocks = BlockCreator.getBlocks(BlockVariant); 1637444ed5c5SDimitry Andric SIScheduleBlockScheduler Scheduler(DAG, ScheduleVariant, Blocks); 1638444ed5c5SDimitry Andric std::vector<SIScheduleBlock*> ScheduledBlocks; 1639444ed5c5SDimitry Andric struct SIScheduleBlockResult Res; 1640444ed5c5SDimitry Andric 1641444ed5c5SDimitry Andric ScheduledBlocks = Scheduler.getBlocks(); 1642444ed5c5SDimitry Andric 1643444ed5c5SDimitry Andric for (unsigned b = 0; b < ScheduledBlocks.size(); ++b) { 1644444ed5c5SDimitry Andric SIScheduleBlock *Block = ScheduledBlocks[b]; 1645444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1646444ed5c5SDimitry Andric 1647444ed5c5SDimitry Andric for (SUnit* SU : SUs) 1648444ed5c5SDimitry Andric Res.SUs.push_back(SU->NodeNum); 1649444ed5c5SDimitry Andric } 1650444ed5c5SDimitry Andric 1651444ed5c5SDimitry Andric Res.MaxSGPRUsage = Scheduler.getSGPRUsage(); 1652444ed5c5SDimitry Andric Res.MaxVGPRUsage = Scheduler.getVGPRUsage(); 1653444ed5c5SDimitry Andric return Res; 1654444ed5c5SDimitry Andric } 1655444ed5c5SDimitry Andric 1656444ed5c5SDimitry Andric // SIScheduleDAGMI // 1657444ed5c5SDimitry Andric 1658444ed5c5SDimitry Andric SIScheduleDAGMI::SIScheduleDAGMI(MachineSchedContext *C) : 1659444ed5c5SDimitry Andric ScheduleDAGMILive(C, make_unique<GenericScheduler>(C)) { 1660444ed5c5SDimitry Andric SITII = static_cast<const SIInstrInfo*>(TII); 1661444ed5c5SDimitry Andric SITRI = static_cast<const SIRegisterInfo*>(TRI); 1662444ed5c5SDimitry Andric 1663444ed5c5SDimitry Andric VGPRSetID = SITRI->getVGPR32PressureSet(); 1664444ed5c5SDimitry Andric SGPRSetID = SITRI->getSGPR32PressureSet(); 1665444ed5c5SDimitry Andric } 1666444ed5c5SDimitry Andric 1667444ed5c5SDimitry Andric SIScheduleDAGMI::~SIScheduleDAGMI() { 1668444ed5c5SDimitry Andric } 1669444ed5c5SDimitry Andric 1670444ed5c5SDimitry Andric ScheduleDAGInstrs *llvm::createSIMachineScheduler(MachineSchedContext *C) { 1671444ed5c5SDimitry Andric return new SIScheduleDAGMI(C); 1672444ed5c5SDimitry Andric } 1673444ed5c5SDimitry Andric 1674444ed5c5SDimitry Andric // Code adapted from scheduleDAG.cpp 1675444ed5c5SDimitry Andric // Does a topological sort over the SUs. 1676444ed5c5SDimitry Andric // Both TopDown and BottomUp 1677444ed5c5SDimitry Andric void SIScheduleDAGMI::topologicalSort() { 1678444ed5c5SDimitry Andric std::vector<int> TopDownSU2Index; 1679444ed5c5SDimitry Andric unsigned DAGSize = SUnits.size(); 1680444ed5c5SDimitry Andric std::vector<SUnit*> WorkList; 1681444ed5c5SDimitry Andric 1682444ed5c5SDimitry Andric DEBUG(dbgs() << "Topological Sort\n"); 1683444ed5c5SDimitry Andric WorkList.reserve(DAGSize); 1684444ed5c5SDimitry Andric 1685444ed5c5SDimitry Andric TopDownIndex2SU.resize(DAGSize); 1686444ed5c5SDimitry Andric TopDownSU2Index.resize(DAGSize); 1687444ed5c5SDimitry Andric BottomUpIndex2SU.resize(DAGSize); 1688444ed5c5SDimitry Andric 1689444ed5c5SDimitry Andric WorkList.push_back(&getExitSU()); 1690444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1691444ed5c5SDimitry Andric SUnit *SU = &SUnits[i]; 1692444ed5c5SDimitry Andric int NodeNum = SU->NodeNum; 1693444ed5c5SDimitry Andric unsigned Degree = SU->Succs.size(); 1694444ed5c5SDimitry Andric TopDownSU2Index[NodeNum] = Degree; 1695444ed5c5SDimitry Andric if (Degree == 0) { 1696444ed5c5SDimitry Andric assert(SU->Succs.empty() && "SUnit should have no successors"); 1697444ed5c5SDimitry Andric WorkList.push_back(SU); 1698444ed5c5SDimitry Andric } 1699444ed5c5SDimitry Andric } 1700444ed5c5SDimitry Andric 1701444ed5c5SDimitry Andric int Id = DAGSize; 1702444ed5c5SDimitry Andric while (!WorkList.empty()) { 1703444ed5c5SDimitry Andric SUnit *SU = WorkList.back(); 1704444ed5c5SDimitry Andric WorkList.pop_back(); 1705444ed5c5SDimitry Andric if (SU->NodeNum < DAGSize) { 1706444ed5c5SDimitry Andric TopDownSU2Index[SU->NodeNum] = --Id; 1707444ed5c5SDimitry Andric TopDownIndex2SU[Id] = SU->NodeNum; 1708444ed5c5SDimitry Andric } 1709444ed5c5SDimitry Andric for (SDep& Pred : SU->Preds) { 1710444ed5c5SDimitry Andric SUnit *SU = Pred.getSUnit(); 1711444ed5c5SDimitry Andric if (SU->NodeNum < DAGSize && !--TopDownSU2Index[SU->NodeNum]) 1712444ed5c5SDimitry Andric WorkList.push_back(SU); 1713444ed5c5SDimitry Andric } 1714444ed5c5SDimitry Andric } 1715444ed5c5SDimitry Andric 1716444ed5c5SDimitry Andric BottomUpIndex2SU = std::vector<int>(TopDownIndex2SU.rbegin(), 1717444ed5c5SDimitry Andric TopDownIndex2SU.rend()); 1718444ed5c5SDimitry Andric 1719444ed5c5SDimitry Andric #ifndef NDEBUG 1720444ed5c5SDimitry Andric // Check correctness of the ordering 1721444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1722444ed5c5SDimitry Andric SUnit *SU = &SUnits[i]; 1723444ed5c5SDimitry Andric for (SDep& Pred : SU->Preds) { 1724444ed5c5SDimitry Andric if (Pred.getSUnit()->NodeNum >= DAGSize) 1725444ed5c5SDimitry Andric continue; 1726444ed5c5SDimitry Andric assert(TopDownSU2Index[SU->NodeNum] > 1727444ed5c5SDimitry Andric TopDownSU2Index[Pred.getSUnit()->NodeNum] && 1728444ed5c5SDimitry Andric "Wrong Top Down topological sorting"); 1729444ed5c5SDimitry Andric } 1730444ed5c5SDimitry Andric } 1731444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1732444ed5c5SDimitry Andric SUnit *SU = &SUnits[i]; 1733444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 1734444ed5c5SDimitry Andric if (Succ.getSUnit()->NodeNum >= DAGSize) 1735444ed5c5SDimitry Andric continue; 1736444ed5c5SDimitry Andric assert(TopDownSU2Index[SU->NodeNum] < 1737444ed5c5SDimitry Andric TopDownSU2Index[Succ.getSUnit()->NodeNum] && 1738444ed5c5SDimitry Andric "Wrong Bottom Up topological sorting"); 1739444ed5c5SDimitry Andric } 1740444ed5c5SDimitry Andric } 1741444ed5c5SDimitry Andric #endif 1742444ed5c5SDimitry Andric } 1743444ed5c5SDimitry Andric 1744444ed5c5SDimitry Andric // Move low latencies further from their user without 1745444ed5c5SDimitry Andric // increasing SGPR usage (in general) 1746444ed5c5SDimitry Andric // This is to be replaced by a better pass that would 1747444ed5c5SDimitry Andric // take into account SGPR usage (based on VGPR Usage 1748444ed5c5SDimitry Andric // and the corresponding wavefront count), that would 1749444ed5c5SDimitry Andric // try to merge groups of loads if it make sense, etc 1750444ed5c5SDimitry Andric void SIScheduleDAGMI::moveLowLatencies() { 1751444ed5c5SDimitry Andric unsigned DAGSize = SUnits.size(); 1752444ed5c5SDimitry Andric int LastLowLatencyUser = -1; 1753444ed5c5SDimitry Andric int LastLowLatencyPos = -1; 1754444ed5c5SDimitry Andric 1755444ed5c5SDimitry Andric for (unsigned i = 0, e = ScheduledSUnits.size(); i != e; ++i) { 1756444ed5c5SDimitry Andric SUnit *SU = &SUnits[ScheduledSUnits[i]]; 1757444ed5c5SDimitry Andric bool IsLowLatencyUser = false; 1758444ed5c5SDimitry Andric unsigned MinPos = 0; 1759444ed5c5SDimitry Andric 1760444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 1761444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 1762444ed5c5SDimitry Andric if (SITII->isLowLatencyInstruction(Pred->getInstr())) { 1763444ed5c5SDimitry Andric IsLowLatencyUser = true; 1764444ed5c5SDimitry Andric } 1765444ed5c5SDimitry Andric if (Pred->NodeNum >= DAGSize) 1766444ed5c5SDimitry Andric continue; 1767444ed5c5SDimitry Andric unsigned PredPos = ScheduledSUnitsInv[Pred->NodeNum]; 1768444ed5c5SDimitry Andric if (PredPos >= MinPos) 1769444ed5c5SDimitry Andric MinPos = PredPos + 1; 1770444ed5c5SDimitry Andric } 1771444ed5c5SDimitry Andric 1772444ed5c5SDimitry Andric if (SITII->isLowLatencyInstruction(SU->getInstr())) { 1773444ed5c5SDimitry Andric unsigned BestPos = LastLowLatencyUser + 1; 1774444ed5c5SDimitry Andric if ((int)BestPos <= LastLowLatencyPos) 1775444ed5c5SDimitry Andric BestPos = LastLowLatencyPos + 1; 1776444ed5c5SDimitry Andric if (BestPos < MinPos) 1777444ed5c5SDimitry Andric BestPos = MinPos; 1778444ed5c5SDimitry Andric if (BestPos < i) { 1779444ed5c5SDimitry Andric for (unsigned u = i; u > BestPos; --u) { 1780444ed5c5SDimitry Andric ++ScheduledSUnitsInv[ScheduledSUnits[u-1]]; 1781444ed5c5SDimitry Andric ScheduledSUnits[u] = ScheduledSUnits[u-1]; 1782444ed5c5SDimitry Andric } 1783444ed5c5SDimitry Andric ScheduledSUnits[BestPos] = SU->NodeNum; 1784444ed5c5SDimitry Andric ScheduledSUnitsInv[SU->NodeNum] = BestPos; 1785444ed5c5SDimitry Andric } 1786444ed5c5SDimitry Andric LastLowLatencyPos = BestPos; 1787444ed5c5SDimitry Andric if (IsLowLatencyUser) 1788444ed5c5SDimitry Andric LastLowLatencyUser = BestPos; 1789444ed5c5SDimitry Andric } else if (IsLowLatencyUser) { 1790444ed5c5SDimitry Andric LastLowLatencyUser = i; 1791444ed5c5SDimitry Andric // Moves COPY instructions on which depends 1792444ed5c5SDimitry Andric // the low latency instructions too. 1793444ed5c5SDimitry Andric } else if (SU->getInstr()->getOpcode() == AMDGPU::COPY) { 1794444ed5c5SDimitry Andric bool CopyForLowLat = false; 1795444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1796444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1797444ed5c5SDimitry Andric if (SITII->isLowLatencyInstruction(Succ->getInstr())) { 1798444ed5c5SDimitry Andric CopyForLowLat = true; 1799444ed5c5SDimitry Andric } 1800444ed5c5SDimitry Andric } 1801444ed5c5SDimitry Andric if (!CopyForLowLat) 1802444ed5c5SDimitry Andric continue; 1803444ed5c5SDimitry Andric if (MinPos < i) { 1804444ed5c5SDimitry Andric for (unsigned u = i; u > MinPos; --u) { 1805444ed5c5SDimitry Andric ++ScheduledSUnitsInv[ScheduledSUnits[u-1]]; 1806444ed5c5SDimitry Andric ScheduledSUnits[u] = ScheduledSUnits[u-1]; 1807444ed5c5SDimitry Andric } 1808444ed5c5SDimitry Andric ScheduledSUnits[MinPos] = SU->NodeNum; 1809444ed5c5SDimitry Andric ScheduledSUnitsInv[SU->NodeNum] = MinPos; 1810444ed5c5SDimitry Andric } 1811444ed5c5SDimitry Andric } 1812444ed5c5SDimitry Andric } 1813444ed5c5SDimitry Andric } 1814444ed5c5SDimitry Andric 1815444ed5c5SDimitry Andric void SIScheduleDAGMI::restoreSULinksLeft() { 1816444ed5c5SDimitry Andric for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { 1817444ed5c5SDimitry Andric SUnits[i].isScheduled = false; 1818444ed5c5SDimitry Andric SUnits[i].WeakPredsLeft = SUnitsLinksBackup[i].WeakPredsLeft; 1819444ed5c5SDimitry Andric SUnits[i].NumPredsLeft = SUnitsLinksBackup[i].NumPredsLeft; 1820444ed5c5SDimitry Andric SUnits[i].WeakSuccsLeft = SUnitsLinksBackup[i].WeakSuccsLeft; 1821444ed5c5SDimitry Andric SUnits[i].NumSuccsLeft = SUnitsLinksBackup[i].NumSuccsLeft; 1822444ed5c5SDimitry Andric } 1823444ed5c5SDimitry Andric } 1824444ed5c5SDimitry Andric 1825444ed5c5SDimitry Andric // Return the Vgpr and Sgpr usage corresponding to some virtual registers. 1826444ed5c5SDimitry Andric template<typename _Iterator> void 1827444ed5c5SDimitry Andric SIScheduleDAGMI::fillVgprSgprCost(_Iterator First, _Iterator End, 1828444ed5c5SDimitry Andric unsigned &VgprUsage, unsigned &SgprUsage) { 1829444ed5c5SDimitry Andric VgprUsage = 0; 1830444ed5c5SDimitry Andric SgprUsage = 0; 1831444ed5c5SDimitry Andric for (_Iterator RegI = First; RegI != End; ++RegI) { 1832444ed5c5SDimitry Andric unsigned Reg = *RegI; 1833444ed5c5SDimitry Andric // For now only track virtual registers 1834444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1835444ed5c5SDimitry Andric continue; 1836444ed5c5SDimitry Andric PSetIterator PSetI = MRI.getPressureSets(Reg); 1837444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1838444ed5c5SDimitry Andric if (*PSetI == VGPRSetID) 1839444ed5c5SDimitry Andric VgprUsage += PSetI.getWeight(); 1840444ed5c5SDimitry Andric else if (*PSetI == SGPRSetID) 1841444ed5c5SDimitry Andric SgprUsage += PSetI.getWeight(); 1842444ed5c5SDimitry Andric } 1843444ed5c5SDimitry Andric } 1844444ed5c5SDimitry Andric } 1845444ed5c5SDimitry Andric 1846444ed5c5SDimitry Andric void SIScheduleDAGMI::schedule() 1847444ed5c5SDimitry Andric { 1848444ed5c5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots; 1849444ed5c5SDimitry Andric SIScheduleBlockResult Best, Temp; 1850444ed5c5SDimitry Andric DEBUG(dbgs() << "Preparing Scheduling\n"); 1851444ed5c5SDimitry Andric 1852444ed5c5SDimitry Andric buildDAGWithRegPressure(); 1853444ed5c5SDimitry Andric DEBUG( 1854444ed5c5SDimitry Andric for(SUnit& SU : SUnits) 1855444ed5c5SDimitry Andric SU.dumpAll(this) 1856444ed5c5SDimitry Andric ); 1857444ed5c5SDimitry Andric 1858444ed5c5SDimitry Andric Topo.InitDAGTopologicalSorting(); 1859444ed5c5SDimitry Andric topologicalSort(); 1860444ed5c5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots); 1861444ed5c5SDimitry Andric // We reuse several ScheduleDAGMI and ScheduleDAGMILive 1862444ed5c5SDimitry Andric // functions, but to make them happy we must initialize 1863444ed5c5SDimitry Andric // the default Scheduler implementation (even if we do not 1864444ed5c5SDimitry Andric // run it) 1865444ed5c5SDimitry Andric SchedImpl->initialize(this); 1866444ed5c5SDimitry Andric initQueues(TopRoots, BotRoots); 1867444ed5c5SDimitry Andric 1868444ed5c5SDimitry Andric // Fill some stats to help scheduling. 1869444ed5c5SDimitry Andric 1870444ed5c5SDimitry Andric SUnitsLinksBackup = SUnits; 1871444ed5c5SDimitry Andric IsLowLatencySU.clear(); 1872444ed5c5SDimitry Andric LowLatencyOffset.clear(); 1873444ed5c5SDimitry Andric IsHighLatencySU.clear(); 1874444ed5c5SDimitry Andric 1875444ed5c5SDimitry Andric IsLowLatencySU.resize(SUnits.size(), 0); 1876444ed5c5SDimitry Andric LowLatencyOffset.resize(SUnits.size(), 0); 1877444ed5c5SDimitry Andric IsHighLatencySU.resize(SUnits.size(), 0); 1878444ed5c5SDimitry Andric 1879444ed5c5SDimitry Andric for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) { 1880444ed5c5SDimitry Andric SUnit *SU = &SUnits[i]; 1881444ed5c5SDimitry Andric unsigned BaseLatReg, OffLatReg; 1882444ed5c5SDimitry Andric if (SITII->isLowLatencyInstruction(SU->getInstr())) { 1883444ed5c5SDimitry Andric IsLowLatencySU[i] = 1; 1884444ed5c5SDimitry Andric if (SITII->getMemOpBaseRegImmOfs(SU->getInstr(), BaseLatReg, 1885444ed5c5SDimitry Andric OffLatReg, TRI)) 1886444ed5c5SDimitry Andric LowLatencyOffset[i] = OffLatReg; 1887444ed5c5SDimitry Andric } else if (SITII->isHighLatencyInstruction(SU->getInstr())) 1888444ed5c5SDimitry Andric IsHighLatencySU[i] = 1; 1889444ed5c5SDimitry Andric } 1890444ed5c5SDimitry Andric 1891444ed5c5SDimitry Andric SIScheduler Scheduler(this); 1892444ed5c5SDimitry Andric Best = Scheduler.scheduleVariant(SISchedulerBlockCreatorVariant::LatenciesAlone, 1893444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant::BlockLatencyRegUsage); 1894444ed5c5SDimitry Andric #if 0 // To enable when handleMove fix lands 1895444ed5c5SDimitry Andric // if VGPR usage is extremely high, try other good performing variants 1896444ed5c5SDimitry Andric // which could lead to lower VGPR usage 1897444ed5c5SDimitry Andric if (Best.MaxVGPRUsage > 180) { 1898444ed5c5SDimitry Andric std::vector<std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant>> Variants = { 1899444ed5c5SDimitry Andric { LatenciesAlone, BlockRegUsageLatency }, 1900444ed5c5SDimitry Andric // { LatenciesAlone, BlockRegUsage }, 1901444ed5c5SDimitry Andric { LatenciesGrouped, BlockLatencyRegUsage }, 1902444ed5c5SDimitry Andric // { LatenciesGrouped, BlockRegUsageLatency }, 1903444ed5c5SDimitry Andric // { LatenciesGrouped, BlockRegUsage }, 1904444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage }, 1905444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockRegUsageLatency }, 1906444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockRegUsage } 1907444ed5c5SDimitry Andric }; 1908444ed5c5SDimitry Andric for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) { 1909444ed5c5SDimitry Andric Temp = Scheduler.scheduleVariant(v.first, v.second); 1910444ed5c5SDimitry Andric if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage) 1911444ed5c5SDimitry Andric Best = Temp; 1912444ed5c5SDimitry Andric } 1913444ed5c5SDimitry Andric } 1914444ed5c5SDimitry Andric // if VGPR usage is still extremely high, we may spill. Try other variants 1915444ed5c5SDimitry Andric // which are less performing, but that could lead to lower VGPR usage. 1916444ed5c5SDimitry Andric if (Best.MaxVGPRUsage > 200) { 1917444ed5c5SDimitry Andric std::vector<std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant>> Variants = { 1918444ed5c5SDimitry Andric // { LatenciesAlone, BlockRegUsageLatency }, 1919444ed5c5SDimitry Andric { LatenciesAlone, BlockRegUsage }, 1920444ed5c5SDimitry Andric // { LatenciesGrouped, BlockLatencyRegUsage }, 1921444ed5c5SDimitry Andric { LatenciesGrouped, BlockRegUsageLatency }, 1922444ed5c5SDimitry Andric { LatenciesGrouped, BlockRegUsage }, 1923444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage }, 1924444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockRegUsageLatency }, 1925444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockRegUsage } 1926444ed5c5SDimitry Andric }; 1927444ed5c5SDimitry Andric for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) { 1928444ed5c5SDimitry Andric Temp = Scheduler.scheduleVariant(v.first, v.second); 1929444ed5c5SDimitry Andric if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage) 1930444ed5c5SDimitry Andric Best = Temp; 1931444ed5c5SDimitry Andric } 1932444ed5c5SDimitry Andric } 1933444ed5c5SDimitry Andric #endif 1934444ed5c5SDimitry Andric ScheduledSUnits = Best.SUs; 1935444ed5c5SDimitry Andric ScheduledSUnitsInv.resize(SUnits.size()); 1936444ed5c5SDimitry Andric 1937444ed5c5SDimitry Andric for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) { 1938444ed5c5SDimitry Andric ScheduledSUnitsInv[ScheduledSUnits[i]] = i; 1939444ed5c5SDimitry Andric } 1940444ed5c5SDimitry Andric 1941444ed5c5SDimitry Andric moveLowLatencies(); 1942444ed5c5SDimitry Andric 1943444ed5c5SDimitry Andric // Tell the outside world about the result of the scheduling. 1944444ed5c5SDimitry Andric 1945444ed5c5SDimitry Andric assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker"); 1946444ed5c5SDimitry Andric TopRPTracker.setPos(CurrentTop); 1947444ed5c5SDimitry Andric 1948444ed5c5SDimitry Andric for (std::vector<unsigned>::iterator I = ScheduledSUnits.begin(), 1949444ed5c5SDimitry Andric E = ScheduledSUnits.end(); I != E; ++I) { 1950444ed5c5SDimitry Andric SUnit *SU = &SUnits[*I]; 1951444ed5c5SDimitry Andric 1952444ed5c5SDimitry Andric scheduleMI(SU, true); 1953444ed5c5SDimitry Andric 1954444ed5c5SDimitry Andric DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " 1955444ed5c5SDimitry Andric << *SU->getInstr()); 1956444ed5c5SDimitry Andric } 1957444ed5c5SDimitry Andric 1958444ed5c5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); 1959444ed5c5SDimitry Andric 1960444ed5c5SDimitry Andric placeDebugValues(); 1961444ed5c5SDimitry Andric 1962444ed5c5SDimitry Andric DEBUG({ 1963444ed5c5SDimitry Andric unsigned BBNum = begin()->getParent()->getNumber(); 1964444ed5c5SDimitry Andric dbgs() << "*** Final schedule for BB#" << BBNum << " ***\n"; 1965444ed5c5SDimitry Andric dumpSchedule(); 1966444ed5c5SDimitry Andric dbgs() << '\n'; 1967444ed5c5SDimitry Andric }); 1968444ed5c5SDimitry Andric } 1969