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 153ca95b02SDimitry Andric #include "AMDGPU.h" 16444ed5c5SDimitry Andric #include "SIMachineScheduler.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; 2983ca95b02SDimitry 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. 3303ca95b02SDimitry Andric for (const auto &RegMaskPair : RPTracker.getPressure().LiveInRegs) { 3313ca95b02SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(RegMaskPair.RegUnit)) 3323ca95b02SDimitry Andric LiveInRegs.insert(RegMaskPair.RegUnit); 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. 3573ca95b02SDimitry Andric for (const auto &RegMaskPair : RPTracker.getPressure().LiveOutRegs) { 3583ca95b02SDimitry Andric unsigned Reg = RegMaskPair.RegUnit; 359444ed5c5SDimitry Andric if (TargetRegisterInfo::isVirtualRegister(Reg) && 3603ca95b02SDimitry Andric isDefBetween(Reg, LIS->getInstructionIndex(*BeginBlock).getRegSlot(), 3613ca95b02SDimitry Andric LIS->getInstructionIndex(*EndBlock).getRegSlot(), MRI, 3623ca95b02SDimitry Andric LIS)) { 363444ed5c5SDimitry Andric LiveOutRegs.insert(Reg); 364444ed5c5SDimitry Andric } 365444ed5c5SDimitry Andric } 366444ed5c5SDimitry Andric 367444ed5c5SDimitry Andric // Pressure = sum_alive_registers register size 368444ed5c5SDimitry Andric // Internally llvm will represent some registers as big 128 bits registers 369444ed5c5SDimitry Andric // for example, but they actually correspond to 4 actual 32 bits registers. 370444ed5c5SDimitry Andric // Thus Pressure is not equal to num_alive_registers * constant. 371444ed5c5SDimitry Andric LiveInPressure = TopPressure.MaxSetPressure; 372444ed5c5SDimitry Andric LiveOutPressure = BotPressure.MaxSetPressure; 373444ed5c5SDimitry Andric 374444ed5c5SDimitry Andric // Prepares TopRPTracker for top down scheduling. 375444ed5c5SDimitry Andric TopRPTracker.closeTop(); 376444ed5c5SDimitry Andric } 377444ed5c5SDimitry Andric 378444ed5c5SDimitry Andric void SIScheduleBlock::schedule(MachineBasicBlock::iterator BeginBlock, 379444ed5c5SDimitry Andric MachineBasicBlock::iterator EndBlock) { 380444ed5c5SDimitry Andric if (!Scheduled) 381444ed5c5SDimitry Andric fastSchedule(); 382444ed5c5SDimitry Andric 383444ed5c5SDimitry Andric // PreScheduling phase to set LiveIn and LiveOut. 384444ed5c5SDimitry Andric initRegPressure(BeginBlock, EndBlock); 385444ed5c5SDimitry Andric undoSchedule(); 386444ed5c5SDimitry Andric 387444ed5c5SDimitry Andric // Schedule for real now. 388444ed5c5SDimitry Andric 389444ed5c5SDimitry Andric TopReadySUs.clear(); 390444ed5c5SDimitry Andric 391444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 392444ed5c5SDimitry Andric if (!SU->NumPredsLeft) 393444ed5c5SDimitry Andric TopReadySUs.push_back(SU); 394444ed5c5SDimitry Andric } 395444ed5c5SDimitry Andric 396444ed5c5SDimitry Andric while (!TopReadySUs.empty()) { 397444ed5c5SDimitry Andric SUnit *SU = pickNode(); 398444ed5c5SDimitry Andric ScheduledSUnits.push_back(SU); 399444ed5c5SDimitry Andric TopRPTracker.setPos(SU->getInstr()); 400444ed5c5SDimitry Andric TopRPTracker.advance(); 401444ed5c5SDimitry Andric nodeScheduled(SU); 402444ed5c5SDimitry Andric } 403444ed5c5SDimitry Andric 404444ed5c5SDimitry Andric // TODO: compute InternalAdditionnalPressure. 405444ed5c5SDimitry Andric InternalAdditionnalPressure.resize(TopPressure.MaxSetPressure.size()); 406444ed5c5SDimitry Andric 407444ed5c5SDimitry Andric // Check everything is right. 408444ed5c5SDimitry Andric #ifndef NDEBUG 409444ed5c5SDimitry Andric assert(SUnits.size() == ScheduledSUnits.size() && 410444ed5c5SDimitry Andric TopReadySUs.empty()); 411444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 412444ed5c5SDimitry Andric assert(SU->isScheduled && 413444ed5c5SDimitry Andric SU->NumPredsLeft == 0); 414444ed5c5SDimitry Andric } 415444ed5c5SDimitry Andric #endif 416444ed5c5SDimitry Andric 417444ed5c5SDimitry Andric Scheduled = true; 418444ed5c5SDimitry Andric } 419444ed5c5SDimitry Andric 420444ed5c5SDimitry Andric void SIScheduleBlock::undoSchedule() { 421444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 422444ed5c5SDimitry Andric SU->isScheduled = false; 423444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 424444ed5c5SDimitry Andric if (BC->isSUInBlock(Succ.getSUnit(), ID)) 425444ed5c5SDimitry Andric undoReleaseSucc(SU, &Succ); 426444ed5c5SDimitry Andric } 427444ed5c5SDimitry Andric } 428444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0); 429444ed5c5SDimitry Andric ScheduledSUnits.clear(); 430444ed5c5SDimitry Andric Scheduled = false; 431444ed5c5SDimitry Andric } 432444ed5c5SDimitry Andric 433444ed5c5SDimitry Andric void SIScheduleBlock::undoReleaseSucc(SUnit *SU, SDep *SuccEdge) { 434444ed5c5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 435444ed5c5SDimitry Andric 436444ed5c5SDimitry Andric if (SuccEdge->isWeak()) { 437444ed5c5SDimitry Andric ++SuccSU->WeakPredsLeft; 438444ed5c5SDimitry Andric return; 439444ed5c5SDimitry Andric } 440444ed5c5SDimitry Andric ++SuccSU->NumPredsLeft; 441444ed5c5SDimitry Andric } 442444ed5c5SDimitry Andric 443444ed5c5SDimitry Andric void SIScheduleBlock::releaseSucc(SUnit *SU, SDep *SuccEdge) { 444444ed5c5SDimitry Andric SUnit *SuccSU = SuccEdge->getSUnit(); 445444ed5c5SDimitry Andric 446444ed5c5SDimitry Andric if (SuccEdge->isWeak()) { 447444ed5c5SDimitry Andric --SuccSU->WeakPredsLeft; 448444ed5c5SDimitry Andric return; 449444ed5c5SDimitry Andric } 450444ed5c5SDimitry Andric #ifndef NDEBUG 451444ed5c5SDimitry Andric if (SuccSU->NumPredsLeft == 0) { 452444ed5c5SDimitry Andric dbgs() << "*** Scheduling failed! ***\n"; 453444ed5c5SDimitry Andric SuccSU->dump(DAG); 454444ed5c5SDimitry Andric dbgs() << " has been released too many times!\n"; 455444ed5c5SDimitry Andric llvm_unreachable(nullptr); 456444ed5c5SDimitry Andric } 457444ed5c5SDimitry Andric #endif 458444ed5c5SDimitry Andric 459444ed5c5SDimitry Andric --SuccSU->NumPredsLeft; 460444ed5c5SDimitry Andric } 461444ed5c5SDimitry Andric 462444ed5c5SDimitry Andric /// Release Successors of the SU that are in the block or not. 463444ed5c5SDimitry Andric void SIScheduleBlock::releaseSuccessors(SUnit *SU, bool InOrOutBlock) { 464444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 465444ed5c5SDimitry Andric SUnit *SuccSU = Succ.getSUnit(); 466444ed5c5SDimitry Andric 4673ca95b02SDimitry Andric if (SuccSU->NodeNum >= DAG->SUnits.size()) 4683ca95b02SDimitry Andric continue; 4693ca95b02SDimitry Andric 470444ed5c5SDimitry Andric if (BC->isSUInBlock(SuccSU, ID) != InOrOutBlock) 471444ed5c5SDimitry Andric continue; 472444ed5c5SDimitry Andric 473444ed5c5SDimitry Andric releaseSucc(SU, &Succ); 474444ed5c5SDimitry Andric if (SuccSU->NumPredsLeft == 0 && InOrOutBlock) 475444ed5c5SDimitry Andric TopReadySUs.push_back(SuccSU); 476444ed5c5SDimitry Andric } 477444ed5c5SDimitry Andric } 478444ed5c5SDimitry Andric 479444ed5c5SDimitry Andric void SIScheduleBlock::nodeScheduled(SUnit *SU) { 480444ed5c5SDimitry Andric // Is in TopReadySUs 481444ed5c5SDimitry Andric assert (!SU->NumPredsLeft); 482444ed5c5SDimitry Andric std::vector<SUnit*>::iterator I = 483444ed5c5SDimitry Andric std::find(TopReadySUs.begin(), TopReadySUs.end(), SU); 484444ed5c5SDimitry Andric if (I == TopReadySUs.end()) { 485444ed5c5SDimitry Andric dbgs() << "Data Structure Bug in SI Scheduler\n"; 486444ed5c5SDimitry Andric llvm_unreachable(nullptr); 487444ed5c5SDimitry Andric } 488444ed5c5SDimitry Andric TopReadySUs.erase(I); 489444ed5c5SDimitry Andric 490444ed5c5SDimitry Andric releaseSuccessors(SU, true); 491444ed5c5SDimitry Andric // Scheduling this node will trigger a wait, 492444ed5c5SDimitry Andric // thus propagate to other instructions that they do not need to wait either. 493444ed5c5SDimitry Andric if (HasLowLatencyNonWaitedParent[NodeNum2Index[SU->NodeNum]]) 494444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.assign(SUnits.size(), 0); 495444ed5c5SDimitry Andric 496444ed5c5SDimitry Andric if (DAG->IsLowLatencySU[SU->NodeNum]) { 497444ed5c5SDimitry Andric for (SDep& Succ : SU->Succs) { 498444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator I = 499444ed5c5SDimitry Andric NodeNum2Index.find(Succ.getSUnit()->NodeNum); 500444ed5c5SDimitry Andric if (I != NodeNum2Index.end()) 501444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent[I->second] = 1; 502444ed5c5SDimitry Andric } 503444ed5c5SDimitry Andric } 504444ed5c5SDimitry Andric SU->isScheduled = true; 505444ed5c5SDimitry Andric } 506444ed5c5SDimitry Andric 507444ed5c5SDimitry Andric void SIScheduleBlock::finalizeUnits() { 508444ed5c5SDimitry Andric // We remove links from outside blocks to enable scheduling inside the block. 509444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 510444ed5c5SDimitry Andric releaseSuccessors(SU, false); 511444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) 512444ed5c5SDimitry Andric HighLatencyBlock = true; 513444ed5c5SDimitry Andric } 514444ed5c5SDimitry Andric HasLowLatencyNonWaitedParent.resize(SUnits.size(), 0); 515444ed5c5SDimitry Andric } 516444ed5c5SDimitry Andric 517444ed5c5SDimitry Andric // we maintain ascending order of IDs 518444ed5c5SDimitry Andric void SIScheduleBlock::addPred(SIScheduleBlock *Pred) { 519444ed5c5SDimitry Andric unsigned PredID = Pred->getID(); 520444ed5c5SDimitry Andric 521444ed5c5SDimitry Andric // Check if not already predecessor. 522444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 523444ed5c5SDimitry Andric if (PredID == P->getID()) 524444ed5c5SDimitry Andric return; 525444ed5c5SDimitry Andric } 526444ed5c5SDimitry Andric Preds.push_back(Pred); 527444ed5c5SDimitry Andric 5283ca95b02SDimitry Andric assert(none_of(Succs, 5293ca95b02SDimitry Andric [=](SIScheduleBlock *S) { return PredID == S->getID(); }) && 5303ca95b02SDimitry Andric "Loop in the Block Graph!"); 531444ed5c5SDimitry Andric } 532444ed5c5SDimitry Andric 533444ed5c5SDimitry Andric void SIScheduleBlock::addSucc(SIScheduleBlock *Succ) { 534444ed5c5SDimitry Andric unsigned SuccID = Succ->getID(); 535444ed5c5SDimitry Andric 536444ed5c5SDimitry Andric // Check if not already predecessor. 537444ed5c5SDimitry Andric for (SIScheduleBlock* S : Succs) { 538444ed5c5SDimitry Andric if (SuccID == S->getID()) 539444ed5c5SDimitry Andric return; 540444ed5c5SDimitry Andric } 541444ed5c5SDimitry Andric if (Succ->isHighLatencyBlock()) 542444ed5c5SDimitry Andric ++NumHighLatencySuccessors; 543444ed5c5SDimitry Andric Succs.push_back(Succ); 5443ca95b02SDimitry Andric assert(none_of(Preds, 5453ca95b02SDimitry Andric [=](SIScheduleBlock *P) { return SuccID == P->getID(); }) && 5463ca95b02SDimitry Andric "Loop in the Block Graph!"); 547444ed5c5SDimitry Andric } 548444ed5c5SDimitry Andric 549444ed5c5SDimitry Andric #ifndef NDEBUG 550444ed5c5SDimitry Andric void SIScheduleBlock::printDebug(bool full) { 551444ed5c5SDimitry Andric dbgs() << "Block (" << ID << ")\n"; 552444ed5c5SDimitry Andric if (!full) 553444ed5c5SDimitry Andric return; 554444ed5c5SDimitry Andric 555444ed5c5SDimitry Andric dbgs() << "\nContains High Latency Instruction: " 556444ed5c5SDimitry Andric << HighLatencyBlock << '\n'; 557444ed5c5SDimitry Andric dbgs() << "\nDepends On:\n"; 558444ed5c5SDimitry Andric for (SIScheduleBlock* P : Preds) { 559444ed5c5SDimitry Andric P->printDebug(false); 560444ed5c5SDimitry Andric } 561444ed5c5SDimitry Andric 562444ed5c5SDimitry Andric dbgs() << "\nSuccessors:\n"; 563444ed5c5SDimitry Andric for (SIScheduleBlock* S : Succs) { 564444ed5c5SDimitry Andric S->printDebug(false); 565444ed5c5SDimitry Andric } 566444ed5c5SDimitry Andric 567444ed5c5SDimitry Andric if (Scheduled) { 568444ed5c5SDimitry Andric dbgs() << "LiveInPressure " << LiveInPressure[DAG->getSGPRSetID()] << ' ' 569444ed5c5SDimitry Andric << LiveInPressure[DAG->getVGPRSetID()] << '\n'; 570444ed5c5SDimitry Andric dbgs() << "LiveOutPressure " << LiveOutPressure[DAG->getSGPRSetID()] << ' ' 571444ed5c5SDimitry Andric << LiveOutPressure[DAG->getVGPRSetID()] << "\n\n"; 572444ed5c5SDimitry Andric dbgs() << "LiveIns:\n"; 573444ed5c5SDimitry Andric for (unsigned Reg : LiveInRegs) 574444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 575444ed5c5SDimitry Andric 576444ed5c5SDimitry Andric dbgs() << "\nLiveOuts:\n"; 577444ed5c5SDimitry Andric for (unsigned Reg : LiveOutRegs) 578444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 579444ed5c5SDimitry Andric } 580444ed5c5SDimitry Andric 581444ed5c5SDimitry Andric dbgs() << "\nInstructions:\n"; 582444ed5c5SDimitry Andric if (!Scheduled) { 583444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 584444ed5c5SDimitry Andric SU->dump(DAG); 585444ed5c5SDimitry Andric } 586444ed5c5SDimitry Andric } else { 587444ed5c5SDimitry Andric for (SUnit* SU : SUnits) { 588444ed5c5SDimitry Andric SU->dump(DAG); 589444ed5c5SDimitry Andric } 590444ed5c5SDimitry Andric } 591444ed5c5SDimitry Andric 592444ed5c5SDimitry Andric dbgs() << "///////////////////////\n"; 593444ed5c5SDimitry Andric } 594444ed5c5SDimitry Andric 595444ed5c5SDimitry Andric #endif 596444ed5c5SDimitry Andric 597444ed5c5SDimitry Andric // SIScheduleBlockCreator // 598444ed5c5SDimitry Andric 599444ed5c5SDimitry Andric SIScheduleBlockCreator::SIScheduleBlockCreator(SIScheduleDAGMI *DAG) : 600444ed5c5SDimitry Andric DAG(DAG) { 601444ed5c5SDimitry Andric } 602444ed5c5SDimitry Andric 603444ed5c5SDimitry Andric SIScheduleBlockCreator::~SIScheduleBlockCreator() { 604444ed5c5SDimitry Andric } 605444ed5c5SDimitry Andric 606444ed5c5SDimitry Andric SIScheduleBlocks 607444ed5c5SDimitry Andric SIScheduleBlockCreator::getBlocks(SISchedulerBlockCreatorVariant BlockVariant) { 608444ed5c5SDimitry Andric std::map<SISchedulerBlockCreatorVariant, SIScheduleBlocks>::iterator B = 609444ed5c5SDimitry Andric Blocks.find(BlockVariant); 610444ed5c5SDimitry Andric if (B == Blocks.end()) { 611444ed5c5SDimitry Andric SIScheduleBlocks Res; 612444ed5c5SDimitry Andric createBlocksForVariant(BlockVariant); 613444ed5c5SDimitry Andric topologicalSort(); 614444ed5c5SDimitry Andric scheduleInsideBlocks(); 615444ed5c5SDimitry Andric fillStats(); 616444ed5c5SDimitry Andric Res.Blocks = CurrentBlocks; 617444ed5c5SDimitry Andric Res.TopDownIndex2Block = TopDownIndex2Block; 618444ed5c5SDimitry Andric Res.TopDownBlock2Index = TopDownBlock2Index; 619444ed5c5SDimitry Andric Blocks[BlockVariant] = Res; 620444ed5c5SDimitry Andric return Res; 621444ed5c5SDimitry Andric } else { 622444ed5c5SDimitry Andric return B->second; 623444ed5c5SDimitry Andric } 624444ed5c5SDimitry Andric } 625444ed5c5SDimitry Andric 626444ed5c5SDimitry Andric bool SIScheduleBlockCreator::isSUInBlock(SUnit *SU, unsigned ID) { 627444ed5c5SDimitry Andric if (SU->NodeNum >= DAG->SUnits.size()) 628444ed5c5SDimitry Andric return false; 629444ed5c5SDimitry Andric return CurrentBlocks[Node2CurrentBlock[SU->NodeNum]]->getID() == ID; 630444ed5c5SDimitry Andric } 631444ed5c5SDimitry Andric 632444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorHighLatenciesAlone() { 633444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 634444ed5c5SDimitry Andric 635444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 636444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 637444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) { 638444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = NextReservedID++; 639444ed5c5SDimitry Andric } 640444ed5c5SDimitry Andric } 641444ed5c5SDimitry Andric } 642444ed5c5SDimitry Andric 643444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorHighLatenciesGroups() { 644444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 645444ed5c5SDimitry Andric unsigned NumHighLatencies = 0; 646444ed5c5SDimitry Andric unsigned GroupSize; 647444ed5c5SDimitry Andric unsigned Color = NextReservedID; 648444ed5c5SDimitry Andric unsigned Count = 0; 649444ed5c5SDimitry Andric std::set<unsigned> FormingGroup; 650444ed5c5SDimitry Andric 651444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 652444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 653444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) 654444ed5c5SDimitry Andric ++NumHighLatencies; 655444ed5c5SDimitry Andric } 656444ed5c5SDimitry Andric 657444ed5c5SDimitry Andric if (NumHighLatencies == 0) 658444ed5c5SDimitry Andric return; 659444ed5c5SDimitry Andric 660444ed5c5SDimitry Andric if (NumHighLatencies <= 6) 661444ed5c5SDimitry Andric GroupSize = 2; 662444ed5c5SDimitry Andric else if (NumHighLatencies <= 12) 663444ed5c5SDimitry Andric GroupSize = 3; 664444ed5c5SDimitry Andric else 665444ed5c5SDimitry Andric GroupSize = 4; 666444ed5c5SDimitry Andric 667444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 668444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 669444ed5c5SDimitry Andric if (DAG->IsHighLatencySU[SU->NodeNum]) { 670444ed5c5SDimitry Andric unsigned CompatibleGroup = true; 671444ed5c5SDimitry Andric unsigned ProposedColor = Color; 672444ed5c5SDimitry Andric for (unsigned j : FormingGroup) { 673444ed5c5SDimitry Andric // TODO: Currently CompatibleGroup will always be false, 674444ed5c5SDimitry Andric // because the graph enforces the load order. This 675444ed5c5SDimitry Andric // can be fixed, but as keeping the load order is often 676444ed5c5SDimitry Andric // good for performance that causes a performance hit (both 677444ed5c5SDimitry Andric // the default scheduler and this scheduler). 678444ed5c5SDimitry Andric // When this scheduler determines a good load order, 679444ed5c5SDimitry Andric // this can be fixed. 680444ed5c5SDimitry Andric if (!DAG->canAddEdge(SU, &DAG->SUnits[j]) || 681444ed5c5SDimitry Andric !DAG->canAddEdge(&DAG->SUnits[j], SU)) 682444ed5c5SDimitry Andric CompatibleGroup = false; 683444ed5c5SDimitry Andric } 684444ed5c5SDimitry Andric if (!CompatibleGroup || ++Count == GroupSize) { 685444ed5c5SDimitry Andric FormingGroup.clear(); 686444ed5c5SDimitry Andric Color = ++NextReservedID; 687444ed5c5SDimitry Andric if (!CompatibleGroup) { 688444ed5c5SDimitry Andric ProposedColor = Color; 689444ed5c5SDimitry Andric FormingGroup.insert(SU->NodeNum); 690444ed5c5SDimitry Andric } 691444ed5c5SDimitry Andric Count = 0; 692444ed5c5SDimitry Andric } else { 693444ed5c5SDimitry Andric FormingGroup.insert(SU->NodeNum); 694444ed5c5SDimitry Andric } 695444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = ProposedColor; 696444ed5c5SDimitry Andric } 697444ed5c5SDimitry Andric } 698444ed5c5SDimitry Andric } 699444ed5c5SDimitry Andric 700444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorComputeReservedDependencies() { 701444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 702444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned> ColorCombinations; 703444ed5c5SDimitry Andric 704444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring.clear(); 705444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring.clear(); 706444ed5c5SDimitry Andric 707444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring.resize(DAGSize, 0); 708444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring.resize(DAGSize, 0); 709444ed5c5SDimitry Andric 710444ed5c5SDimitry Andric // Traverse TopDown, and give different colors to SUs depending 711444ed5c5SDimitry Andric // on which combination of High Latencies they depend on. 712444ed5c5SDimitry Andric 7133ca95b02SDimitry Andric for (unsigned SUNum : DAG->TopDownIndex2SU) { 7143ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 715444ed5c5SDimitry Andric std::set<unsigned> SUColors; 716444ed5c5SDimitry Andric 717444ed5c5SDimitry Andric // Already given. 718444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) { 719444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 720444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum]; 721444ed5c5SDimitry Andric continue; 722444ed5c5SDimitry Andric } 723444ed5c5SDimitry Andric 724444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 725444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 726444ed5c5SDimitry Andric if (PredDep.isWeak() || Pred->NodeNum >= DAGSize) 727444ed5c5SDimitry Andric continue; 728444ed5c5SDimitry Andric if (CurrentTopDownReservedDependencyColoring[Pred->NodeNum] > 0) 729444ed5c5SDimitry Andric SUColors.insert(CurrentTopDownReservedDependencyColoring[Pred->NodeNum]); 730444ed5c5SDimitry Andric } 731444ed5c5SDimitry Andric // Color 0 by default. 732444ed5c5SDimitry Andric if (SUColors.empty()) 733444ed5c5SDimitry Andric continue; 734444ed5c5SDimitry Andric // Same color than parents. 735444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() > DAGSize) 736444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 737444ed5c5SDimitry Andric *SUColors.begin(); 738444ed5c5SDimitry Andric else { 739444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned>::iterator Pos = 740444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 741444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 742444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = Pos->second; 743444ed5c5SDimitry Andric } else { 744444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] = 745444ed5c5SDimitry Andric NextNonReservedID; 746444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 747444ed5c5SDimitry Andric } 748444ed5c5SDimitry Andric } 749444ed5c5SDimitry Andric } 750444ed5c5SDimitry Andric 751444ed5c5SDimitry Andric ColorCombinations.clear(); 752444ed5c5SDimitry Andric 753444ed5c5SDimitry Andric // Same as before, but BottomUp. 754444ed5c5SDimitry Andric 7553ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 7563ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 757444ed5c5SDimitry Andric std::set<unsigned> SUColors; 758444ed5c5SDimitry Andric 759444ed5c5SDimitry Andric // Already given. 760444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) { 761444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 762444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum]; 763444ed5c5SDimitry Andric continue; 764444ed5c5SDimitry Andric } 765444ed5c5SDimitry Andric 766444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 767444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 768444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 769444ed5c5SDimitry Andric continue; 770444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0) 771444ed5c5SDimitry Andric SUColors.insert(CurrentBottomUpReservedDependencyColoring[Succ->NodeNum]); 772444ed5c5SDimitry Andric } 773444ed5c5SDimitry Andric // Keep color 0. 774444ed5c5SDimitry Andric if (SUColors.empty()) 775444ed5c5SDimitry Andric continue; 776444ed5c5SDimitry Andric // Same color than parents. 777444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() > DAGSize) 778444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 779444ed5c5SDimitry Andric *SUColors.begin(); 780444ed5c5SDimitry Andric else { 781444ed5c5SDimitry Andric std::map<std::set<unsigned>, unsigned>::iterator Pos = 782444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 783444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 784444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = Pos->second; 785444ed5c5SDimitry Andric } else { 786444ed5c5SDimitry Andric CurrentBottomUpReservedDependencyColoring[SU->NodeNum] = 787444ed5c5SDimitry Andric NextNonReservedID; 788444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 789444ed5c5SDimitry Andric } 790444ed5c5SDimitry Andric } 791444ed5c5SDimitry Andric } 792444ed5c5SDimitry Andric } 793444ed5c5SDimitry Andric 794444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorAccordingToReservedDependencies() { 795444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 796444ed5c5SDimitry Andric std::map<std::pair<unsigned, unsigned>, unsigned> ColorCombinations; 797444ed5c5SDimitry Andric 798444ed5c5SDimitry Andric // Every combination of colors given by the top down 799444ed5c5SDimitry Andric // and bottom up Reserved node dependency 800444ed5c5SDimitry Andric 801444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 802444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 803444ed5c5SDimitry Andric std::pair<unsigned, unsigned> SUColors; 804444ed5c5SDimitry Andric 805444ed5c5SDimitry Andric // High latency instructions: already given. 806444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum]) 807444ed5c5SDimitry Andric continue; 808444ed5c5SDimitry Andric 809444ed5c5SDimitry Andric SUColors.first = CurrentTopDownReservedDependencyColoring[SU->NodeNum]; 810444ed5c5SDimitry Andric SUColors.second = CurrentBottomUpReservedDependencyColoring[SU->NodeNum]; 811444ed5c5SDimitry Andric 812444ed5c5SDimitry Andric std::map<std::pair<unsigned, unsigned>, unsigned>::iterator Pos = 813444ed5c5SDimitry Andric ColorCombinations.find(SUColors); 814444ed5c5SDimitry Andric if (Pos != ColorCombinations.end()) { 815444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = Pos->second; 816444ed5c5SDimitry Andric } else { 817444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = NextNonReservedID; 818444ed5c5SDimitry Andric ColorCombinations[SUColors] = NextNonReservedID++; 819444ed5c5SDimitry Andric } 820444ed5c5SDimitry Andric } 821444ed5c5SDimitry Andric } 822444ed5c5SDimitry Andric 823444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorEndsAccordingToDependencies() { 824444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 825444ed5c5SDimitry Andric std::vector<int> PendingColoring = CurrentColoring; 826444ed5c5SDimitry Andric 8273ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 8283ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 829444ed5c5SDimitry Andric std::set<unsigned> SUColors; 830444ed5c5SDimitry Andric std::set<unsigned> SUColorsPending; 831444ed5c5SDimitry Andric 832444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 833444ed5c5SDimitry Andric continue; 834444ed5c5SDimitry Andric 835444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[SU->NodeNum] > 0 || 836444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[SU->NodeNum] > 0) 837444ed5c5SDimitry Andric continue; 838444ed5c5SDimitry Andric 839444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 840444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 841444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 842444ed5c5SDimitry Andric continue; 843444ed5c5SDimitry Andric if (CurrentBottomUpReservedDependencyColoring[Succ->NodeNum] > 0 || 844444ed5c5SDimitry Andric CurrentTopDownReservedDependencyColoring[Succ->NodeNum] > 0) 845444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 846444ed5c5SDimitry Andric SUColorsPending.insert(PendingColoring[Succ->NodeNum]); 847444ed5c5SDimitry Andric } 848444ed5c5SDimitry Andric if (SUColors.size() == 1 && SUColorsPending.size() == 1) 849444ed5c5SDimitry Andric PendingColoring[SU->NodeNum] = *SUColors.begin(); 850444ed5c5SDimitry Andric else // TODO: Attribute new colors depending on color 851444ed5c5SDimitry Andric // combination of children. 852444ed5c5SDimitry Andric PendingColoring[SU->NodeNum] = NextNonReservedID++; 853444ed5c5SDimitry Andric } 854444ed5c5SDimitry Andric CurrentColoring = PendingColoring; 855444ed5c5SDimitry Andric } 856444ed5c5SDimitry Andric 857444ed5c5SDimitry Andric 858444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorForceConsecutiveOrderInGroup() { 859444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 860444ed5c5SDimitry Andric unsigned PreviousColor; 861444ed5c5SDimitry Andric std::set<unsigned> SeenColors; 862444ed5c5SDimitry Andric 863444ed5c5SDimitry Andric if (DAGSize <= 1) 864444ed5c5SDimitry Andric return; 865444ed5c5SDimitry Andric 866444ed5c5SDimitry Andric PreviousColor = CurrentColoring[0]; 867444ed5c5SDimitry Andric 868444ed5c5SDimitry Andric for (unsigned i = 1, e = DAGSize; i != e; ++i) { 869444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 870444ed5c5SDimitry Andric unsigned CurrentColor = CurrentColoring[i]; 871444ed5c5SDimitry Andric unsigned PreviousColorSave = PreviousColor; 872444ed5c5SDimitry Andric assert(i == SU->NodeNum); 873444ed5c5SDimitry Andric 874444ed5c5SDimitry Andric if (CurrentColor != PreviousColor) 875444ed5c5SDimitry Andric SeenColors.insert(PreviousColor); 876444ed5c5SDimitry Andric PreviousColor = CurrentColor; 877444ed5c5SDimitry Andric 878444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 879444ed5c5SDimitry Andric continue; 880444ed5c5SDimitry Andric 881444ed5c5SDimitry Andric if (SeenColors.find(CurrentColor) == SeenColors.end()) 882444ed5c5SDimitry Andric continue; 883444ed5c5SDimitry Andric 884444ed5c5SDimitry Andric if (PreviousColorSave != CurrentColor) 885444ed5c5SDimitry Andric CurrentColoring[i] = NextNonReservedID++; 886444ed5c5SDimitry Andric else 887444ed5c5SDimitry Andric CurrentColoring[i] = CurrentColoring[i-1]; 888444ed5c5SDimitry Andric } 889444ed5c5SDimitry Andric } 890444ed5c5SDimitry Andric 891444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeConstantLoadsNextGroup() { 892444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 893444ed5c5SDimitry Andric 8943ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 8953ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 896444ed5c5SDimitry Andric std::set<unsigned> SUColors; 897444ed5c5SDimitry Andric 898444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 899444ed5c5SDimitry Andric continue; 900444ed5c5SDimitry Andric 901444ed5c5SDimitry Andric // No predecessor: Vgpr constant loading. 902444ed5c5SDimitry Andric // Low latency instructions usually have a predecessor (the address) 903444ed5c5SDimitry Andric if (SU->Preds.size() > 0 && !DAG->IsLowLatencySU[SU->NodeNum]) 904444ed5c5SDimitry Andric continue; 905444ed5c5SDimitry Andric 906444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 907444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 908444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 909444ed5c5SDimitry Andric continue; 910444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 911444ed5c5SDimitry Andric } 912444ed5c5SDimitry Andric if (SUColors.size() == 1) 913444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 914444ed5c5SDimitry Andric } 915444ed5c5SDimitry Andric } 916444ed5c5SDimitry Andric 917444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleNextGroup() { 918444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 919444ed5c5SDimitry Andric 9203ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 9213ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 922444ed5c5SDimitry Andric std::set<unsigned> SUColors; 923444ed5c5SDimitry Andric 924444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 925444ed5c5SDimitry Andric continue; 926444ed5c5SDimitry Andric 927444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 928444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 929444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 930444ed5c5SDimitry Andric continue; 931444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 932444ed5c5SDimitry Andric } 933444ed5c5SDimitry Andric if (SUColors.size() == 1) 934444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 935444ed5c5SDimitry Andric } 936444ed5c5SDimitry Andric } 937444ed5c5SDimitry Andric 938444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleNextGroupOnlyForReserved() { 939444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 940444ed5c5SDimitry Andric 9413ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 9423ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 943444ed5c5SDimitry Andric std::set<unsigned> SUColors; 944444ed5c5SDimitry Andric 945444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 946444ed5c5SDimitry Andric continue; 947444ed5c5SDimitry Andric 948444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 949444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 950444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 951444ed5c5SDimitry Andric continue; 952444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 953444ed5c5SDimitry Andric } 954444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() <= DAGSize) 955444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 956444ed5c5SDimitry Andric } 957444ed5c5SDimitry Andric } 958444ed5c5SDimitry Andric 959444ed5c5SDimitry Andric void SIScheduleBlockCreator::colorMergeIfPossibleSmallGroupsToNextGroup() { 960444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 961444ed5c5SDimitry Andric std::map<unsigned, unsigned> ColorCount; 962444ed5c5SDimitry Andric 9633ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 9643ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 965444ed5c5SDimitry Andric unsigned color = CurrentColoring[SU->NodeNum]; 966444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator Pos = ColorCount.find(color); 967444ed5c5SDimitry Andric if (Pos != ColorCount.end()) { 968444ed5c5SDimitry Andric ++ColorCount[color]; 969444ed5c5SDimitry Andric } else { 970444ed5c5SDimitry Andric ColorCount[color] = 1; 971444ed5c5SDimitry Andric } 972444ed5c5SDimitry Andric } 973444ed5c5SDimitry Andric 9743ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 9753ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 976444ed5c5SDimitry Andric unsigned color = CurrentColoring[SU->NodeNum]; 977444ed5c5SDimitry Andric std::set<unsigned> SUColors; 978444ed5c5SDimitry Andric 979444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 980444ed5c5SDimitry Andric continue; 981444ed5c5SDimitry Andric 982444ed5c5SDimitry Andric if (ColorCount[color] > 1) 983444ed5c5SDimitry Andric continue; 984444ed5c5SDimitry Andric 985444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 986444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 987444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 988444ed5c5SDimitry Andric continue; 989444ed5c5SDimitry Andric SUColors.insert(CurrentColoring[Succ->NodeNum]); 990444ed5c5SDimitry Andric } 991444ed5c5SDimitry Andric if (SUColors.size() == 1 && *SUColors.begin() != color) { 992444ed5c5SDimitry Andric --ColorCount[color]; 993444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = *SUColors.begin(); 994444ed5c5SDimitry Andric ++ColorCount[*SUColors.begin()]; 995444ed5c5SDimitry Andric } 996444ed5c5SDimitry Andric } 997444ed5c5SDimitry Andric } 998444ed5c5SDimitry Andric 999444ed5c5SDimitry Andric void SIScheduleBlockCreator::cutHugeBlocks() { 1000444ed5c5SDimitry Andric // TODO 1001444ed5c5SDimitry Andric } 1002444ed5c5SDimitry Andric 1003444ed5c5SDimitry Andric void SIScheduleBlockCreator::regroupNoUserInstructions() { 1004444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1005444ed5c5SDimitry Andric int GroupID = NextNonReservedID++; 1006444ed5c5SDimitry Andric 10073ca95b02SDimitry Andric for (unsigned SUNum : DAG->BottomUpIndex2SU) { 10083ca95b02SDimitry Andric SUnit *SU = &DAG->SUnits[SUNum]; 1009444ed5c5SDimitry Andric bool hasSuccessor = false; 1010444ed5c5SDimitry Andric 1011444ed5c5SDimitry Andric if (CurrentColoring[SU->NodeNum] <= (int)DAGSize) 1012444ed5c5SDimitry Andric continue; 1013444ed5c5SDimitry Andric 1014444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1015444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1016444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1017444ed5c5SDimitry Andric continue; 1018444ed5c5SDimitry Andric hasSuccessor = true; 1019444ed5c5SDimitry Andric } 1020444ed5c5SDimitry Andric if (!hasSuccessor) 1021444ed5c5SDimitry Andric CurrentColoring[SU->NodeNum] = GroupID; 1022444ed5c5SDimitry Andric } 1023444ed5c5SDimitry Andric } 1024444ed5c5SDimitry Andric 1025444ed5c5SDimitry Andric void SIScheduleBlockCreator::createBlocksForVariant(SISchedulerBlockCreatorVariant BlockVariant) { 1026444ed5c5SDimitry Andric unsigned DAGSize = DAG->SUnits.size(); 1027444ed5c5SDimitry Andric std::map<unsigned,unsigned> RealID; 1028444ed5c5SDimitry Andric 1029444ed5c5SDimitry Andric CurrentBlocks.clear(); 1030444ed5c5SDimitry Andric CurrentColoring.clear(); 1031444ed5c5SDimitry Andric CurrentColoring.resize(DAGSize, 0); 1032444ed5c5SDimitry Andric Node2CurrentBlock.clear(); 1033444ed5c5SDimitry Andric 1034444ed5c5SDimitry Andric // Restore links previous scheduling variant has overridden. 1035444ed5c5SDimitry Andric DAG->restoreSULinksLeft(); 1036444ed5c5SDimitry Andric 1037444ed5c5SDimitry Andric NextReservedID = 1; 1038444ed5c5SDimitry Andric NextNonReservedID = DAGSize + 1; 1039444ed5c5SDimitry Andric 1040444ed5c5SDimitry Andric DEBUG(dbgs() << "Coloring the graph\n"); 1041444ed5c5SDimitry Andric 1042444ed5c5SDimitry Andric if (BlockVariant == SISchedulerBlockCreatorVariant::LatenciesGrouped) 1043444ed5c5SDimitry Andric colorHighLatenciesGroups(); 1044444ed5c5SDimitry Andric else 1045444ed5c5SDimitry Andric colorHighLatenciesAlone(); 1046444ed5c5SDimitry Andric colorComputeReservedDependencies(); 1047444ed5c5SDimitry Andric colorAccordingToReservedDependencies(); 1048444ed5c5SDimitry Andric colorEndsAccordingToDependencies(); 1049444ed5c5SDimitry Andric if (BlockVariant == SISchedulerBlockCreatorVariant::LatenciesAlonePlusConsecutive) 1050444ed5c5SDimitry Andric colorForceConsecutiveOrderInGroup(); 1051444ed5c5SDimitry Andric regroupNoUserInstructions(); 1052444ed5c5SDimitry Andric colorMergeConstantLoadsNextGroup(); 1053444ed5c5SDimitry Andric colorMergeIfPossibleNextGroupOnlyForReserved(); 1054444ed5c5SDimitry Andric 1055444ed5c5SDimitry Andric // Put SUs of same color into same block 1056444ed5c5SDimitry Andric Node2CurrentBlock.resize(DAGSize, -1); 1057444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1058444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 1059444ed5c5SDimitry Andric unsigned Color = CurrentColoring[SU->NodeNum]; 1060444ed5c5SDimitry Andric if (RealID.find(Color) == RealID.end()) { 1061444ed5c5SDimitry Andric int ID = CurrentBlocks.size(); 1062444ed5c5SDimitry Andric BlockPtrs.push_back( 1063444ed5c5SDimitry Andric make_unique<SIScheduleBlock>(DAG, this, ID)); 1064444ed5c5SDimitry Andric CurrentBlocks.push_back(BlockPtrs.rbegin()->get()); 1065444ed5c5SDimitry Andric RealID[Color] = ID; 1066444ed5c5SDimitry Andric } 1067444ed5c5SDimitry Andric CurrentBlocks[RealID[Color]]->addUnit(SU); 1068444ed5c5SDimitry Andric Node2CurrentBlock[SU->NodeNum] = RealID[Color]; 1069444ed5c5SDimitry Andric } 1070444ed5c5SDimitry Andric 1071444ed5c5SDimitry Andric // Build dependencies between blocks. 1072444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1073444ed5c5SDimitry Andric SUnit *SU = &DAG->SUnits[i]; 1074444ed5c5SDimitry Andric int SUID = Node2CurrentBlock[i]; 1075444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1076444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 1077444ed5c5SDimitry Andric if (SuccDep.isWeak() || Succ->NodeNum >= DAGSize) 1078444ed5c5SDimitry Andric continue; 1079444ed5c5SDimitry Andric if (Node2CurrentBlock[Succ->NodeNum] != SUID) 1080444ed5c5SDimitry Andric CurrentBlocks[SUID]->addSucc(CurrentBlocks[Node2CurrentBlock[Succ->NodeNum]]); 1081444ed5c5SDimitry Andric } 1082444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 1083444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 1084444ed5c5SDimitry Andric if (PredDep.isWeak() || Pred->NodeNum >= DAGSize) 1085444ed5c5SDimitry Andric continue; 1086444ed5c5SDimitry Andric if (Node2CurrentBlock[Pred->NodeNum] != SUID) 1087444ed5c5SDimitry Andric CurrentBlocks[SUID]->addPred(CurrentBlocks[Node2CurrentBlock[Pred->NodeNum]]); 1088444ed5c5SDimitry Andric } 1089444ed5c5SDimitry Andric } 1090444ed5c5SDimitry Andric 1091444ed5c5SDimitry Andric // Free root and leafs of all blocks to enable scheduling inside them. 1092444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1093444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1094444ed5c5SDimitry Andric Block->finalizeUnits(); 1095444ed5c5SDimitry Andric } 1096444ed5c5SDimitry Andric DEBUG( 1097444ed5c5SDimitry Andric dbgs() << "Blocks created:\n\n"; 1098444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1099444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1100444ed5c5SDimitry Andric Block->printDebug(true); 1101444ed5c5SDimitry Andric } 1102444ed5c5SDimitry Andric ); 1103444ed5c5SDimitry Andric } 1104444ed5c5SDimitry Andric 1105444ed5c5SDimitry Andric // Two functions taken from Codegen/MachineScheduler.cpp 1106444ed5c5SDimitry Andric 1107444ed5c5SDimitry Andric /// If this iterator is a debug value, increment until reaching the End or a 1108444ed5c5SDimitry Andric /// non-debug instruction. 1109444ed5c5SDimitry Andric static MachineBasicBlock::const_iterator 1110444ed5c5SDimitry Andric nextIfDebug(MachineBasicBlock::const_iterator I, 1111444ed5c5SDimitry Andric MachineBasicBlock::const_iterator End) { 1112444ed5c5SDimitry Andric for(; I != End; ++I) { 1113444ed5c5SDimitry Andric if (!I->isDebugValue()) 1114444ed5c5SDimitry Andric break; 1115444ed5c5SDimitry Andric } 1116444ed5c5SDimitry Andric return I; 1117444ed5c5SDimitry Andric } 1118444ed5c5SDimitry Andric 1119444ed5c5SDimitry Andric /// Non-const version. 1120444ed5c5SDimitry Andric static MachineBasicBlock::iterator 1121444ed5c5SDimitry Andric nextIfDebug(MachineBasicBlock::iterator I, 1122444ed5c5SDimitry Andric MachineBasicBlock::const_iterator End) { 1123444ed5c5SDimitry Andric // Cast the return value to nonconst MachineInstr, then cast to an 1124444ed5c5SDimitry Andric // instr_iterator, which does not check for null, finally return a 1125444ed5c5SDimitry Andric // bundle_iterator. 1126444ed5c5SDimitry Andric return MachineBasicBlock::instr_iterator( 1127444ed5c5SDimitry Andric const_cast<MachineInstr*>( 1128444ed5c5SDimitry Andric &*nextIfDebug(MachineBasicBlock::const_iterator(I), End))); 1129444ed5c5SDimitry Andric } 1130444ed5c5SDimitry Andric 1131444ed5c5SDimitry Andric void SIScheduleBlockCreator::topologicalSort() { 1132444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1133444ed5c5SDimitry Andric std::vector<int> WorkList; 1134444ed5c5SDimitry Andric 1135444ed5c5SDimitry Andric DEBUG(dbgs() << "Topological Sort\n"); 1136444ed5c5SDimitry Andric 1137444ed5c5SDimitry Andric WorkList.reserve(DAGSize); 1138444ed5c5SDimitry Andric TopDownIndex2Block.resize(DAGSize); 1139444ed5c5SDimitry Andric TopDownBlock2Index.resize(DAGSize); 1140444ed5c5SDimitry Andric BottomUpIndex2Block.resize(DAGSize); 1141444ed5c5SDimitry Andric 1142444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1143444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1144444ed5c5SDimitry Andric unsigned Degree = Block->getSuccs().size(); 1145444ed5c5SDimitry Andric TopDownBlock2Index[i] = Degree; 1146444ed5c5SDimitry Andric if (Degree == 0) { 1147444ed5c5SDimitry Andric WorkList.push_back(i); 1148444ed5c5SDimitry Andric } 1149444ed5c5SDimitry Andric } 1150444ed5c5SDimitry Andric 1151444ed5c5SDimitry Andric int Id = DAGSize; 1152444ed5c5SDimitry Andric while (!WorkList.empty()) { 1153444ed5c5SDimitry Andric int i = WorkList.back(); 1154444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1155444ed5c5SDimitry Andric WorkList.pop_back(); 1156444ed5c5SDimitry Andric TopDownBlock2Index[i] = --Id; 1157444ed5c5SDimitry Andric TopDownIndex2Block[Id] = i; 1158444ed5c5SDimitry Andric for (SIScheduleBlock* Pred : Block->getPreds()) { 1159444ed5c5SDimitry Andric if (!--TopDownBlock2Index[Pred->getID()]) 1160444ed5c5SDimitry Andric WorkList.push_back(Pred->getID()); 1161444ed5c5SDimitry Andric } 1162444ed5c5SDimitry Andric } 1163444ed5c5SDimitry Andric 1164444ed5c5SDimitry Andric #ifndef NDEBUG 1165444ed5c5SDimitry Andric // Check correctness of the ordering. 1166444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1167444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1168444ed5c5SDimitry Andric for (SIScheduleBlock* Pred : Block->getPreds()) { 1169444ed5c5SDimitry Andric assert(TopDownBlock2Index[i] > TopDownBlock2Index[Pred->getID()] && 1170444ed5c5SDimitry Andric "Wrong Top Down topological sorting"); 1171444ed5c5SDimitry Andric } 1172444ed5c5SDimitry Andric } 1173444ed5c5SDimitry Andric #endif 1174444ed5c5SDimitry Andric 1175444ed5c5SDimitry Andric BottomUpIndex2Block = std::vector<int>(TopDownIndex2Block.rbegin(), 1176444ed5c5SDimitry Andric TopDownIndex2Block.rend()); 1177444ed5c5SDimitry Andric } 1178444ed5c5SDimitry Andric 1179444ed5c5SDimitry Andric void SIScheduleBlockCreator::scheduleInsideBlocks() { 1180444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1181444ed5c5SDimitry Andric 1182444ed5c5SDimitry Andric DEBUG(dbgs() << "\nScheduling Blocks\n\n"); 1183444ed5c5SDimitry Andric 1184444ed5c5SDimitry Andric // We do schedule a valid scheduling such that a Block corresponds 1185444ed5c5SDimitry Andric // to a range of instructions. 1186444ed5c5SDimitry Andric DEBUG(dbgs() << "First phase: Fast scheduling for Reg Liveness\n"); 1187444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1188444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1189444ed5c5SDimitry Andric Block->fastSchedule(); 1190444ed5c5SDimitry Andric } 1191444ed5c5SDimitry Andric 1192444ed5c5SDimitry Andric // Note: the following code, and the part restoring previous position 1193444ed5c5SDimitry Andric // is by far the most expensive operation of the Scheduler. 1194444ed5c5SDimitry Andric 1195444ed5c5SDimitry Andric // Do not update CurrentTop. 1196444ed5c5SDimitry Andric MachineBasicBlock::iterator CurrentTopFastSched = DAG->getCurrentTop(); 1197444ed5c5SDimitry Andric std::vector<MachineBasicBlock::iterator> PosOld; 1198444ed5c5SDimitry Andric std::vector<MachineBasicBlock::iterator> PosNew; 1199444ed5c5SDimitry Andric PosOld.reserve(DAG->SUnits.size()); 1200444ed5c5SDimitry Andric PosNew.reserve(DAG->SUnits.size()); 1201444ed5c5SDimitry Andric 1202444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1203444ed5c5SDimitry Andric int BlockIndice = TopDownIndex2Block[i]; 1204444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1205444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1206444ed5c5SDimitry Andric 1207444ed5c5SDimitry Andric for (SUnit* SU : SUs) { 1208444ed5c5SDimitry Andric MachineInstr *MI = SU->getInstr(); 1209444ed5c5SDimitry Andric MachineBasicBlock::iterator Pos = MI; 1210444ed5c5SDimitry Andric PosOld.push_back(Pos); 1211444ed5c5SDimitry Andric if (&*CurrentTopFastSched == MI) { 1212444ed5c5SDimitry Andric PosNew.push_back(Pos); 1213444ed5c5SDimitry Andric CurrentTopFastSched = nextIfDebug(++CurrentTopFastSched, 1214444ed5c5SDimitry Andric DAG->getCurrentBottom()); 1215444ed5c5SDimitry Andric } else { 1216444ed5c5SDimitry Andric // Update the instruction stream. 1217444ed5c5SDimitry Andric DAG->getBB()->splice(CurrentTopFastSched, DAG->getBB(), MI); 1218444ed5c5SDimitry Andric 1219444ed5c5SDimitry Andric // Update LiveIntervals. 1220444ed5c5SDimitry Andric // Note: Moving all instructions and calling handleMove everytime 1221444ed5c5SDimitry Andric // is the most cpu intensive operation of the scheduler. 1222444ed5c5SDimitry Andric // It would gain a lot if there was a way to recompute the 1223444ed5c5SDimitry Andric // LiveIntervals for the entire scheduling region. 12243ca95b02SDimitry Andric DAG->getLIS()->handleMove(*MI, /*UpdateFlags=*/true); 1225444ed5c5SDimitry Andric PosNew.push_back(CurrentTopFastSched); 1226444ed5c5SDimitry Andric } 1227444ed5c5SDimitry Andric } 1228444ed5c5SDimitry Andric } 1229444ed5c5SDimitry Andric 1230444ed5c5SDimitry Andric // Now we have Block of SUs == Block of MI. 1231444ed5c5SDimitry Andric // We do the final schedule for the instructions inside the block. 1232444ed5c5SDimitry Andric // The property that all the SUs of the Block are grouped together as MI 1233444ed5c5SDimitry Andric // is used for correct reg usage tracking. 1234444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1235444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1236444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1237444ed5c5SDimitry Andric Block->schedule((*SUs.begin())->getInstr(), (*SUs.rbegin())->getInstr()); 1238444ed5c5SDimitry Andric } 1239444ed5c5SDimitry Andric 1240444ed5c5SDimitry Andric DEBUG(dbgs() << "Restoring MI Pos\n"); 1241444ed5c5SDimitry Andric // Restore old ordering (which prevents a LIS->handleMove bug). 1242444ed5c5SDimitry Andric for (unsigned i = PosOld.size(), e = 0; i != e; --i) { 1243444ed5c5SDimitry Andric MachineBasicBlock::iterator POld = PosOld[i-1]; 1244444ed5c5SDimitry Andric MachineBasicBlock::iterator PNew = PosNew[i-1]; 1245444ed5c5SDimitry Andric if (PNew != POld) { 1246444ed5c5SDimitry Andric // Update the instruction stream. 1247444ed5c5SDimitry Andric DAG->getBB()->splice(POld, DAG->getBB(), PNew); 1248444ed5c5SDimitry Andric 1249444ed5c5SDimitry Andric // Update LiveIntervals. 12503ca95b02SDimitry Andric DAG->getLIS()->handleMove(*POld, /*UpdateFlags=*/true); 1251444ed5c5SDimitry Andric } 1252444ed5c5SDimitry Andric } 1253444ed5c5SDimitry Andric 1254444ed5c5SDimitry Andric DEBUG( 1255444ed5c5SDimitry Andric for (unsigned i = 0, e = CurrentBlocks.size(); i != e; ++i) { 1256444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[i]; 1257444ed5c5SDimitry Andric Block->printDebug(true); 1258444ed5c5SDimitry Andric } 1259444ed5c5SDimitry Andric ); 1260444ed5c5SDimitry Andric } 1261444ed5c5SDimitry Andric 1262444ed5c5SDimitry Andric void SIScheduleBlockCreator::fillStats() { 1263444ed5c5SDimitry Andric unsigned DAGSize = CurrentBlocks.size(); 1264444ed5c5SDimitry Andric 1265444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1266444ed5c5SDimitry Andric int BlockIndice = TopDownIndex2Block[i]; 1267444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1268444ed5c5SDimitry Andric if (Block->getPreds().size() == 0) 1269444ed5c5SDimitry Andric Block->Depth = 0; 1270444ed5c5SDimitry Andric else { 1271444ed5c5SDimitry Andric unsigned Depth = 0; 1272444ed5c5SDimitry Andric for (SIScheduleBlock *Pred : Block->getPreds()) { 1273444ed5c5SDimitry Andric if (Depth < Pred->Depth + 1) 1274444ed5c5SDimitry Andric Depth = Pred->Depth + 1; 1275444ed5c5SDimitry Andric } 1276444ed5c5SDimitry Andric Block->Depth = Depth; 1277444ed5c5SDimitry Andric } 1278444ed5c5SDimitry Andric } 1279444ed5c5SDimitry Andric 1280444ed5c5SDimitry Andric for (unsigned i = 0, e = DAGSize; i != e; ++i) { 1281444ed5c5SDimitry Andric int BlockIndice = BottomUpIndex2Block[i]; 1282444ed5c5SDimitry Andric SIScheduleBlock *Block = CurrentBlocks[BlockIndice]; 1283444ed5c5SDimitry Andric if (Block->getSuccs().size() == 0) 1284444ed5c5SDimitry Andric Block->Height = 0; 1285444ed5c5SDimitry Andric else { 1286444ed5c5SDimitry Andric unsigned Height = 0; 1287444ed5c5SDimitry Andric for (SIScheduleBlock *Succ : Block->getSuccs()) { 1288444ed5c5SDimitry Andric if (Height < Succ->Height + 1) 1289444ed5c5SDimitry Andric Height = Succ->Height + 1; 1290444ed5c5SDimitry Andric } 1291444ed5c5SDimitry Andric Block->Height = Height; 1292444ed5c5SDimitry Andric } 1293444ed5c5SDimitry Andric } 1294444ed5c5SDimitry Andric } 1295444ed5c5SDimitry Andric 1296444ed5c5SDimitry Andric // SIScheduleBlockScheduler // 1297444ed5c5SDimitry Andric 1298444ed5c5SDimitry Andric SIScheduleBlockScheduler::SIScheduleBlockScheduler(SIScheduleDAGMI *DAG, 1299444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant Variant, 1300444ed5c5SDimitry Andric SIScheduleBlocks BlocksStruct) : 1301444ed5c5SDimitry Andric DAG(DAG), Variant(Variant), Blocks(BlocksStruct.Blocks), 1302444ed5c5SDimitry Andric LastPosWaitedHighLatency(0), NumBlockScheduled(0), VregCurrentUsage(0), 1303444ed5c5SDimitry Andric SregCurrentUsage(0), maxVregUsage(0), maxSregUsage(0) { 1304444ed5c5SDimitry Andric 1305444ed5c5SDimitry Andric // Fill the usage of every output 1306444ed5c5SDimitry Andric // Warning: while by construction we always have a link between two blocks 1307444ed5c5SDimitry Andric // when one needs a result from the other, the number of users of an output 1308444ed5c5SDimitry Andric // is not the sum of child blocks having as input the same virtual register. 1309444ed5c5SDimitry Andric // Here is an example. A produces x and y. B eats x and produces x'. 1310444ed5c5SDimitry Andric // C eats x' and y. The register coalescer may have attributed the same 1311444ed5c5SDimitry Andric // virtual register to x and x'. 1312444ed5c5SDimitry Andric // To count accurately, we do a topological sort. In case the register is 1313444ed5c5SDimitry Andric // found for several parents, we increment the usage of the one with the 1314444ed5c5SDimitry Andric // highest topological index. 1315444ed5c5SDimitry Andric LiveOutRegsNumUsages.resize(Blocks.size()); 1316444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1317444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1318444ed5c5SDimitry Andric for (unsigned Reg : Block->getInRegs()) { 1319444ed5c5SDimitry Andric bool Found = false; 1320444ed5c5SDimitry Andric int topoInd = -1; 1321444ed5c5SDimitry Andric for (SIScheduleBlock* Pred: Block->getPreds()) { 1322444ed5c5SDimitry Andric std::set<unsigned> PredOutRegs = Pred->getOutRegs(); 1323444ed5c5SDimitry Andric std::set<unsigned>::iterator RegPos = PredOutRegs.find(Reg); 1324444ed5c5SDimitry Andric 1325444ed5c5SDimitry Andric if (RegPos != PredOutRegs.end()) { 1326444ed5c5SDimitry Andric Found = true; 1327444ed5c5SDimitry Andric if (topoInd < BlocksStruct.TopDownBlock2Index[Pred->getID()]) { 1328444ed5c5SDimitry Andric topoInd = BlocksStruct.TopDownBlock2Index[Pred->getID()]; 1329444ed5c5SDimitry Andric } 1330444ed5c5SDimitry Andric } 1331444ed5c5SDimitry Andric } 1332444ed5c5SDimitry Andric 1333444ed5c5SDimitry Andric if (!Found) 1334444ed5c5SDimitry Andric continue; 1335444ed5c5SDimitry Andric 1336444ed5c5SDimitry Andric int PredID = BlocksStruct.TopDownIndex2Block[topoInd]; 1337444ed5c5SDimitry Andric std::map<unsigned, unsigned>::iterator RegPos = 1338444ed5c5SDimitry Andric LiveOutRegsNumUsages[PredID].find(Reg); 1339444ed5c5SDimitry Andric if (RegPos != LiveOutRegsNumUsages[PredID].end()) { 1340444ed5c5SDimitry Andric ++LiveOutRegsNumUsages[PredID][Reg]; 1341444ed5c5SDimitry Andric } else { 1342444ed5c5SDimitry Andric LiveOutRegsNumUsages[PredID][Reg] = 1; 1343444ed5c5SDimitry Andric } 1344444ed5c5SDimitry Andric } 1345444ed5c5SDimitry Andric } 1346444ed5c5SDimitry Andric 1347444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled.resize(Blocks.size(), 0); 1348444ed5c5SDimitry Andric BlockNumPredsLeft.resize(Blocks.size()); 1349444ed5c5SDimitry Andric BlockNumSuccsLeft.resize(Blocks.size()); 1350444ed5c5SDimitry Andric 1351444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1352444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1353444ed5c5SDimitry Andric BlockNumPredsLeft[i] = Block->getPreds().size(); 1354444ed5c5SDimitry Andric BlockNumSuccsLeft[i] = Block->getSuccs().size(); 1355444ed5c5SDimitry Andric } 1356444ed5c5SDimitry Andric 1357444ed5c5SDimitry Andric #ifndef NDEBUG 1358444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1359444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1360444ed5c5SDimitry Andric assert(Block->getID() == i); 1361444ed5c5SDimitry Andric } 1362444ed5c5SDimitry Andric #endif 1363444ed5c5SDimitry Andric 1364444ed5c5SDimitry Andric std::set<unsigned> InRegs = DAG->getInRegs(); 1365444ed5c5SDimitry Andric addLiveRegs(InRegs); 1366444ed5c5SDimitry Andric 1367444ed5c5SDimitry Andric // Fill LiveRegsConsumers for regs that were already 1368444ed5c5SDimitry Andric // defined before scheduling. 1369444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1370444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1371444ed5c5SDimitry Andric for (unsigned Reg : Block->getInRegs()) { 1372444ed5c5SDimitry Andric bool Found = false; 1373444ed5c5SDimitry Andric for (SIScheduleBlock* Pred: Block->getPreds()) { 1374444ed5c5SDimitry Andric std::set<unsigned> PredOutRegs = Pred->getOutRegs(); 1375444ed5c5SDimitry Andric std::set<unsigned>::iterator RegPos = PredOutRegs.find(Reg); 1376444ed5c5SDimitry Andric 1377444ed5c5SDimitry Andric if (RegPos != PredOutRegs.end()) { 1378444ed5c5SDimitry Andric Found = true; 1379444ed5c5SDimitry Andric break; 1380444ed5c5SDimitry Andric } 1381444ed5c5SDimitry Andric } 1382444ed5c5SDimitry Andric 1383444ed5c5SDimitry Andric if (!Found) { 1384444ed5c5SDimitry Andric if (LiveRegsConsumers.find(Reg) == LiveRegsConsumers.end()) 1385444ed5c5SDimitry Andric LiveRegsConsumers[Reg] = 1; 1386444ed5c5SDimitry Andric else 1387444ed5c5SDimitry Andric ++LiveRegsConsumers[Reg]; 1388444ed5c5SDimitry Andric } 1389444ed5c5SDimitry Andric } 1390444ed5c5SDimitry Andric } 1391444ed5c5SDimitry Andric 1392444ed5c5SDimitry Andric for (unsigned i = 0, e = Blocks.size(); i != e; ++i) { 1393444ed5c5SDimitry Andric SIScheduleBlock *Block = Blocks[i]; 1394444ed5c5SDimitry Andric if (BlockNumPredsLeft[i] == 0) { 1395444ed5c5SDimitry Andric ReadyBlocks.push_back(Block); 1396444ed5c5SDimitry Andric } 1397444ed5c5SDimitry Andric } 1398444ed5c5SDimitry Andric 1399444ed5c5SDimitry Andric while (SIScheduleBlock *Block = pickBlock()) { 1400444ed5c5SDimitry Andric BlocksScheduled.push_back(Block); 1401444ed5c5SDimitry Andric blockScheduled(Block); 1402444ed5c5SDimitry Andric } 1403444ed5c5SDimitry Andric 1404444ed5c5SDimitry Andric DEBUG( 1405444ed5c5SDimitry Andric dbgs() << "Block Order:"; 1406444ed5c5SDimitry Andric for (SIScheduleBlock* Block : BlocksScheduled) { 1407444ed5c5SDimitry Andric dbgs() << ' ' << Block->getID(); 1408444ed5c5SDimitry Andric } 1409444ed5c5SDimitry Andric ); 1410444ed5c5SDimitry Andric } 1411444ed5c5SDimitry Andric 1412444ed5c5SDimitry Andric bool SIScheduleBlockScheduler::tryCandidateLatency(SIBlockSchedCandidate &Cand, 1413444ed5c5SDimitry Andric SIBlockSchedCandidate &TryCand) { 1414444ed5c5SDimitry Andric if (!Cand.isValid()) { 1415444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 1416444ed5c5SDimitry Andric return true; 1417444ed5c5SDimitry Andric } 1418444ed5c5SDimitry Andric 1419444ed5c5SDimitry Andric // Try to hide high latencies. 1420444ed5c5SDimitry Andric if (tryLess(TryCand.LastPosHighLatParentScheduled, 1421444ed5c5SDimitry Andric Cand.LastPosHighLatParentScheduled, TryCand, Cand, Latency)) 1422444ed5c5SDimitry Andric return true; 1423444ed5c5SDimitry Andric // Schedule high latencies early so you can hide them better. 1424444ed5c5SDimitry Andric if (tryGreater(TryCand.IsHighLatency, Cand.IsHighLatency, 1425444ed5c5SDimitry Andric TryCand, Cand, Latency)) 1426444ed5c5SDimitry Andric return true; 1427444ed5c5SDimitry Andric if (TryCand.IsHighLatency && tryGreater(TryCand.Height, Cand.Height, 1428444ed5c5SDimitry Andric TryCand, Cand, Depth)) 1429444ed5c5SDimitry Andric return true; 1430444ed5c5SDimitry Andric if (tryGreater(TryCand.NumHighLatencySuccessors, 1431444ed5c5SDimitry Andric Cand.NumHighLatencySuccessors, 1432444ed5c5SDimitry Andric TryCand, Cand, Successor)) 1433444ed5c5SDimitry Andric return true; 1434444ed5c5SDimitry Andric return false; 1435444ed5c5SDimitry Andric } 1436444ed5c5SDimitry Andric 1437444ed5c5SDimitry Andric bool SIScheduleBlockScheduler::tryCandidateRegUsage(SIBlockSchedCandidate &Cand, 1438444ed5c5SDimitry Andric SIBlockSchedCandidate &TryCand) { 1439444ed5c5SDimitry Andric if (!Cand.isValid()) { 1440444ed5c5SDimitry Andric TryCand.Reason = NodeOrder; 1441444ed5c5SDimitry Andric return true; 1442444ed5c5SDimitry Andric } 1443444ed5c5SDimitry Andric 1444444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsageDiff > 0, Cand.VGPRUsageDiff > 0, 1445444ed5c5SDimitry Andric TryCand, Cand, RegUsage)) 1446444ed5c5SDimitry Andric return true; 1447444ed5c5SDimitry Andric if (tryGreater(TryCand.NumSuccessors > 0, 1448444ed5c5SDimitry Andric Cand.NumSuccessors > 0, 1449444ed5c5SDimitry Andric TryCand, Cand, Successor)) 1450444ed5c5SDimitry Andric return true; 1451444ed5c5SDimitry Andric if (tryGreater(TryCand.Height, Cand.Height, TryCand, Cand, Depth)) 1452444ed5c5SDimitry Andric return true; 1453444ed5c5SDimitry Andric if (tryLess(TryCand.VGPRUsageDiff, Cand.VGPRUsageDiff, 1454444ed5c5SDimitry Andric TryCand, Cand, RegUsage)) 1455444ed5c5SDimitry Andric return true; 1456444ed5c5SDimitry Andric return false; 1457444ed5c5SDimitry Andric } 1458444ed5c5SDimitry Andric 1459444ed5c5SDimitry Andric SIScheduleBlock *SIScheduleBlockScheduler::pickBlock() { 1460444ed5c5SDimitry Andric SIBlockSchedCandidate Cand; 1461444ed5c5SDimitry Andric std::vector<SIScheduleBlock*>::iterator Best; 1462444ed5c5SDimitry Andric SIScheduleBlock *Block; 1463444ed5c5SDimitry Andric if (ReadyBlocks.empty()) 1464444ed5c5SDimitry Andric return nullptr; 1465444ed5c5SDimitry Andric 1466444ed5c5SDimitry Andric DAG->fillVgprSgprCost(LiveRegs.begin(), LiveRegs.end(), 1467444ed5c5SDimitry Andric VregCurrentUsage, SregCurrentUsage); 1468444ed5c5SDimitry Andric if (VregCurrentUsage > maxVregUsage) 1469444ed5c5SDimitry Andric maxVregUsage = VregCurrentUsage; 1470444ed5c5SDimitry Andric if (VregCurrentUsage > maxSregUsage) 1471444ed5c5SDimitry Andric maxSregUsage = VregCurrentUsage; 1472444ed5c5SDimitry Andric DEBUG( 1473444ed5c5SDimitry Andric dbgs() << "Picking New Blocks\n"; 1474444ed5c5SDimitry Andric dbgs() << "Available: "; 1475444ed5c5SDimitry Andric for (SIScheduleBlock* Block : ReadyBlocks) 1476444ed5c5SDimitry Andric dbgs() << Block->getID() << ' '; 1477444ed5c5SDimitry Andric dbgs() << "\nCurrent Live:\n"; 1478444ed5c5SDimitry Andric for (unsigned Reg : LiveRegs) 1479444ed5c5SDimitry Andric dbgs() << PrintVRegOrUnit(Reg, DAG->getTRI()) << ' '; 1480444ed5c5SDimitry Andric dbgs() << '\n'; 1481444ed5c5SDimitry Andric dbgs() << "Current VGPRs: " << VregCurrentUsage << '\n'; 1482444ed5c5SDimitry Andric dbgs() << "Current SGPRs: " << SregCurrentUsage << '\n'; 1483444ed5c5SDimitry Andric ); 1484444ed5c5SDimitry Andric 1485444ed5c5SDimitry Andric Cand.Block = nullptr; 1486444ed5c5SDimitry Andric for (std::vector<SIScheduleBlock*>::iterator I = ReadyBlocks.begin(), 1487444ed5c5SDimitry Andric E = ReadyBlocks.end(); I != E; ++I) { 1488444ed5c5SDimitry Andric SIBlockSchedCandidate TryCand; 1489444ed5c5SDimitry Andric TryCand.Block = *I; 1490444ed5c5SDimitry Andric TryCand.IsHighLatency = TryCand.Block->isHighLatencyBlock(); 1491444ed5c5SDimitry Andric TryCand.VGPRUsageDiff = 1492444ed5c5SDimitry Andric checkRegUsageImpact(TryCand.Block->getInRegs(), 1493444ed5c5SDimitry Andric TryCand.Block->getOutRegs())[DAG->getVGPRSetID()]; 1494444ed5c5SDimitry Andric TryCand.NumSuccessors = TryCand.Block->getSuccs().size(); 1495444ed5c5SDimitry Andric TryCand.NumHighLatencySuccessors = 1496444ed5c5SDimitry Andric TryCand.Block->getNumHighLatencySuccessors(); 1497444ed5c5SDimitry Andric TryCand.LastPosHighLatParentScheduled = 1498444ed5c5SDimitry Andric (unsigned int) std::max<int> (0, 1499444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[TryCand.Block->getID()] - 1500444ed5c5SDimitry Andric LastPosWaitedHighLatency); 1501444ed5c5SDimitry Andric TryCand.Height = TryCand.Block->Height; 1502444ed5c5SDimitry Andric // Try not to increase VGPR usage too much, else we may spill. 1503444ed5c5SDimitry Andric if (VregCurrentUsage > 120 || 1504444ed5c5SDimitry Andric Variant != SISchedulerBlockSchedulerVariant::BlockLatencyRegUsage) { 1505444ed5c5SDimitry Andric if (!tryCandidateRegUsage(Cand, TryCand) && 1506444ed5c5SDimitry Andric Variant != SISchedulerBlockSchedulerVariant::BlockRegUsage) 1507444ed5c5SDimitry Andric tryCandidateLatency(Cand, TryCand); 1508444ed5c5SDimitry Andric } else { 1509444ed5c5SDimitry Andric if (!tryCandidateLatency(Cand, TryCand)) 1510444ed5c5SDimitry Andric tryCandidateRegUsage(Cand, TryCand); 1511444ed5c5SDimitry Andric } 1512444ed5c5SDimitry Andric if (TryCand.Reason != NoCand) { 1513444ed5c5SDimitry Andric Cand.setBest(TryCand); 1514444ed5c5SDimitry Andric Best = I; 1515444ed5c5SDimitry Andric DEBUG(dbgs() << "Best Current Choice: " << Cand.Block->getID() << ' ' 1516444ed5c5SDimitry Andric << getReasonStr(Cand.Reason) << '\n'); 1517444ed5c5SDimitry Andric } 1518444ed5c5SDimitry Andric } 1519444ed5c5SDimitry Andric 1520444ed5c5SDimitry Andric DEBUG( 1521444ed5c5SDimitry Andric dbgs() << "Picking: " << Cand.Block->getID() << '\n'; 1522444ed5c5SDimitry Andric dbgs() << "Is a block with high latency instruction: " 1523444ed5c5SDimitry Andric << (Cand.IsHighLatency ? "yes\n" : "no\n"); 1524444ed5c5SDimitry Andric dbgs() << "Position of last high latency dependency: " 1525444ed5c5SDimitry Andric << Cand.LastPosHighLatParentScheduled << '\n'; 1526444ed5c5SDimitry Andric dbgs() << "VGPRUsageDiff: " << Cand.VGPRUsageDiff << '\n'; 1527444ed5c5SDimitry Andric dbgs() << '\n'; 1528444ed5c5SDimitry Andric ); 1529444ed5c5SDimitry Andric 1530444ed5c5SDimitry Andric Block = Cand.Block; 1531444ed5c5SDimitry Andric ReadyBlocks.erase(Best); 1532444ed5c5SDimitry Andric return Block; 1533444ed5c5SDimitry Andric } 1534444ed5c5SDimitry Andric 1535444ed5c5SDimitry Andric // Tracking of currently alive registers to determine VGPR Usage. 1536444ed5c5SDimitry Andric 1537444ed5c5SDimitry Andric void SIScheduleBlockScheduler::addLiveRegs(std::set<unsigned> &Regs) { 1538444ed5c5SDimitry Andric for (unsigned Reg : Regs) { 1539444ed5c5SDimitry Andric // For now only track virtual registers. 1540444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1541444ed5c5SDimitry Andric continue; 1542444ed5c5SDimitry Andric // If not already in the live set, then add it. 1543444ed5c5SDimitry Andric (void) LiveRegs.insert(Reg); 1544444ed5c5SDimitry Andric } 1545444ed5c5SDimitry Andric } 1546444ed5c5SDimitry Andric 1547444ed5c5SDimitry Andric void SIScheduleBlockScheduler::decreaseLiveRegs(SIScheduleBlock *Block, 1548444ed5c5SDimitry Andric std::set<unsigned> &Regs) { 1549444ed5c5SDimitry Andric for (unsigned Reg : Regs) { 1550444ed5c5SDimitry Andric // For now only track virtual registers. 1551444ed5c5SDimitry Andric std::set<unsigned>::iterator Pos = LiveRegs.find(Reg); 1552444ed5c5SDimitry Andric assert (Pos != LiveRegs.end() && // Reg must be live. 1553444ed5c5SDimitry Andric LiveRegsConsumers.find(Reg) != LiveRegsConsumers.end() && 1554444ed5c5SDimitry Andric LiveRegsConsumers[Reg] >= 1); 1555444ed5c5SDimitry Andric --LiveRegsConsumers[Reg]; 1556444ed5c5SDimitry Andric if (LiveRegsConsumers[Reg] == 0) 1557444ed5c5SDimitry Andric LiveRegs.erase(Pos); 1558444ed5c5SDimitry Andric } 1559444ed5c5SDimitry Andric } 1560444ed5c5SDimitry Andric 1561444ed5c5SDimitry Andric void SIScheduleBlockScheduler::releaseBlockSuccs(SIScheduleBlock *Parent) { 1562444ed5c5SDimitry Andric for (SIScheduleBlock* Block : Parent->getSuccs()) { 1563444ed5c5SDimitry Andric --BlockNumPredsLeft[Block->getID()]; 1564444ed5c5SDimitry Andric if (BlockNumPredsLeft[Block->getID()] == 0) { 1565444ed5c5SDimitry Andric ReadyBlocks.push_back(Block); 1566444ed5c5SDimitry Andric } 1567444ed5c5SDimitry Andric // TODO: Improve check. When the dependency between the high latency 1568444ed5c5SDimitry Andric // instructions and the instructions of the other blocks are WAR or WAW 1569444ed5c5SDimitry Andric // there will be no wait triggered. We would like these cases to not 1570444ed5c5SDimitry Andric // update LastPosHighLatencyParentScheduled. 1571444ed5c5SDimitry Andric if (Parent->isHighLatencyBlock()) 1572444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[Block->getID()] = NumBlockScheduled; 1573444ed5c5SDimitry Andric } 1574444ed5c5SDimitry Andric } 1575444ed5c5SDimitry Andric 1576444ed5c5SDimitry Andric void SIScheduleBlockScheduler::blockScheduled(SIScheduleBlock *Block) { 1577444ed5c5SDimitry Andric decreaseLiveRegs(Block, Block->getInRegs()); 1578444ed5c5SDimitry Andric addLiveRegs(Block->getOutRegs()); 1579444ed5c5SDimitry Andric releaseBlockSuccs(Block); 1580444ed5c5SDimitry Andric for (std::map<unsigned, unsigned>::iterator RegI = 1581444ed5c5SDimitry Andric LiveOutRegsNumUsages[Block->getID()].begin(), 1582444ed5c5SDimitry Andric E = LiveOutRegsNumUsages[Block->getID()].end(); RegI != E; ++RegI) { 1583444ed5c5SDimitry Andric std::pair<unsigned, unsigned> RegP = *RegI; 1584444ed5c5SDimitry Andric if (LiveRegsConsumers.find(RegP.first) == LiveRegsConsumers.end()) 1585444ed5c5SDimitry Andric LiveRegsConsumers[RegP.first] = RegP.second; 1586444ed5c5SDimitry Andric else { 1587444ed5c5SDimitry Andric assert(LiveRegsConsumers[RegP.first] == 0); 1588444ed5c5SDimitry Andric LiveRegsConsumers[RegP.first] += RegP.second; 1589444ed5c5SDimitry Andric } 1590444ed5c5SDimitry Andric } 1591444ed5c5SDimitry Andric if (LastPosHighLatencyParentScheduled[Block->getID()] > 1592444ed5c5SDimitry Andric (unsigned)LastPosWaitedHighLatency) 1593444ed5c5SDimitry Andric LastPosWaitedHighLatency = 1594444ed5c5SDimitry Andric LastPosHighLatencyParentScheduled[Block->getID()]; 1595444ed5c5SDimitry Andric ++NumBlockScheduled; 1596444ed5c5SDimitry Andric } 1597444ed5c5SDimitry Andric 1598444ed5c5SDimitry Andric std::vector<int> 1599444ed5c5SDimitry Andric SIScheduleBlockScheduler::checkRegUsageImpact(std::set<unsigned> &InRegs, 1600444ed5c5SDimitry Andric std::set<unsigned> &OutRegs) { 1601444ed5c5SDimitry Andric std::vector<int> DiffSetPressure; 1602444ed5c5SDimitry Andric DiffSetPressure.assign(DAG->getTRI()->getNumRegPressureSets(), 0); 1603444ed5c5SDimitry Andric 1604444ed5c5SDimitry Andric for (unsigned Reg : InRegs) { 1605444ed5c5SDimitry Andric // For now only track virtual registers. 1606444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1607444ed5c5SDimitry Andric continue; 1608444ed5c5SDimitry Andric if (LiveRegsConsumers[Reg] > 1) 1609444ed5c5SDimitry Andric continue; 1610444ed5c5SDimitry Andric PSetIterator PSetI = DAG->getMRI()->getPressureSets(Reg); 1611444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1612444ed5c5SDimitry Andric DiffSetPressure[*PSetI] -= PSetI.getWeight(); 1613444ed5c5SDimitry Andric } 1614444ed5c5SDimitry Andric } 1615444ed5c5SDimitry Andric 1616444ed5c5SDimitry Andric for (unsigned Reg : OutRegs) { 1617444ed5c5SDimitry Andric // For now only track virtual registers. 1618444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1619444ed5c5SDimitry Andric continue; 1620444ed5c5SDimitry Andric PSetIterator PSetI = DAG->getMRI()->getPressureSets(Reg); 1621444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1622444ed5c5SDimitry Andric DiffSetPressure[*PSetI] += PSetI.getWeight(); 1623444ed5c5SDimitry Andric } 1624444ed5c5SDimitry Andric } 1625444ed5c5SDimitry Andric 1626444ed5c5SDimitry Andric return DiffSetPressure; 1627444ed5c5SDimitry Andric } 1628444ed5c5SDimitry Andric 1629444ed5c5SDimitry Andric // SIScheduler // 1630444ed5c5SDimitry Andric 1631444ed5c5SDimitry Andric struct SIScheduleBlockResult 1632444ed5c5SDimitry Andric SIScheduler::scheduleVariant(SISchedulerBlockCreatorVariant BlockVariant, 1633444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant ScheduleVariant) { 1634444ed5c5SDimitry Andric SIScheduleBlocks Blocks = BlockCreator.getBlocks(BlockVariant); 1635444ed5c5SDimitry Andric SIScheduleBlockScheduler Scheduler(DAG, ScheduleVariant, Blocks); 1636444ed5c5SDimitry Andric std::vector<SIScheduleBlock*> ScheduledBlocks; 1637444ed5c5SDimitry Andric struct SIScheduleBlockResult Res; 1638444ed5c5SDimitry Andric 1639444ed5c5SDimitry Andric ScheduledBlocks = Scheduler.getBlocks(); 1640444ed5c5SDimitry Andric 1641444ed5c5SDimitry Andric for (unsigned b = 0; b < ScheduledBlocks.size(); ++b) { 1642444ed5c5SDimitry Andric SIScheduleBlock *Block = ScheduledBlocks[b]; 1643444ed5c5SDimitry Andric std::vector<SUnit*> SUs = Block->getScheduledUnits(); 1644444ed5c5SDimitry Andric 1645444ed5c5SDimitry Andric for (SUnit* SU : SUs) 1646444ed5c5SDimitry Andric Res.SUs.push_back(SU->NodeNum); 1647444ed5c5SDimitry Andric } 1648444ed5c5SDimitry Andric 1649444ed5c5SDimitry Andric Res.MaxSGPRUsage = Scheduler.getSGPRUsage(); 1650444ed5c5SDimitry Andric Res.MaxVGPRUsage = Scheduler.getVGPRUsage(); 1651444ed5c5SDimitry Andric return Res; 1652444ed5c5SDimitry Andric } 1653444ed5c5SDimitry Andric 1654444ed5c5SDimitry Andric // SIScheduleDAGMI // 1655444ed5c5SDimitry Andric 1656444ed5c5SDimitry Andric SIScheduleDAGMI::SIScheduleDAGMI(MachineSchedContext *C) : 1657444ed5c5SDimitry Andric ScheduleDAGMILive(C, make_unique<GenericScheduler>(C)) { 1658444ed5c5SDimitry Andric SITII = static_cast<const SIInstrInfo*>(TII); 1659444ed5c5SDimitry Andric SITRI = static_cast<const SIRegisterInfo*>(TRI); 1660444ed5c5SDimitry Andric 1661444ed5c5SDimitry Andric VGPRSetID = SITRI->getVGPR32PressureSet(); 1662444ed5c5SDimitry Andric SGPRSetID = SITRI->getSGPR32PressureSet(); 1663444ed5c5SDimitry Andric } 1664444ed5c5SDimitry Andric 1665444ed5c5SDimitry Andric SIScheduleDAGMI::~SIScheduleDAGMI() { 1666444ed5c5SDimitry Andric } 1667444ed5c5SDimitry Andric 1668444ed5c5SDimitry Andric ScheduleDAGInstrs *llvm::createSIMachineScheduler(MachineSchedContext *C) { 1669444ed5c5SDimitry Andric return new SIScheduleDAGMI(C); 1670444ed5c5SDimitry Andric } 1671444ed5c5SDimitry Andric 1672444ed5c5SDimitry Andric // Code adapted from scheduleDAG.cpp 1673444ed5c5SDimitry Andric // Does a topological sort over the SUs. 1674444ed5c5SDimitry Andric // Both TopDown and BottomUp 1675444ed5c5SDimitry Andric void SIScheduleDAGMI::topologicalSort() { 16763ca95b02SDimitry Andric Topo.InitDAGTopologicalSorting(); 1677444ed5c5SDimitry Andric 16783ca95b02SDimitry Andric TopDownIndex2SU = std::vector<int>(Topo.begin(), Topo.end()); 16793ca95b02SDimitry Andric BottomUpIndex2SU = std::vector<int>(Topo.rbegin(), Topo.rend()); 1680444ed5c5SDimitry Andric } 1681444ed5c5SDimitry Andric 1682444ed5c5SDimitry Andric // Move low latencies further from their user without 1683444ed5c5SDimitry Andric // increasing SGPR usage (in general) 1684444ed5c5SDimitry Andric // This is to be replaced by a better pass that would 1685444ed5c5SDimitry Andric // take into account SGPR usage (based on VGPR Usage 1686444ed5c5SDimitry Andric // and the corresponding wavefront count), that would 1687444ed5c5SDimitry Andric // try to merge groups of loads if it make sense, etc 1688444ed5c5SDimitry Andric void SIScheduleDAGMI::moveLowLatencies() { 1689444ed5c5SDimitry Andric unsigned DAGSize = SUnits.size(); 1690444ed5c5SDimitry Andric int LastLowLatencyUser = -1; 1691444ed5c5SDimitry Andric int LastLowLatencyPos = -1; 1692444ed5c5SDimitry Andric 1693444ed5c5SDimitry Andric for (unsigned i = 0, e = ScheduledSUnits.size(); i != e; ++i) { 1694444ed5c5SDimitry Andric SUnit *SU = &SUnits[ScheduledSUnits[i]]; 1695444ed5c5SDimitry Andric bool IsLowLatencyUser = false; 1696444ed5c5SDimitry Andric unsigned MinPos = 0; 1697444ed5c5SDimitry Andric 1698444ed5c5SDimitry Andric for (SDep& PredDep : SU->Preds) { 1699444ed5c5SDimitry Andric SUnit *Pred = PredDep.getSUnit(); 17003ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*Pred->getInstr())) { 1701444ed5c5SDimitry Andric IsLowLatencyUser = true; 1702444ed5c5SDimitry Andric } 1703444ed5c5SDimitry Andric if (Pred->NodeNum >= DAGSize) 1704444ed5c5SDimitry Andric continue; 1705444ed5c5SDimitry Andric unsigned PredPos = ScheduledSUnitsInv[Pred->NodeNum]; 1706444ed5c5SDimitry Andric if (PredPos >= MinPos) 1707444ed5c5SDimitry Andric MinPos = PredPos + 1; 1708444ed5c5SDimitry Andric } 1709444ed5c5SDimitry Andric 17103ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*SU->getInstr())) { 1711444ed5c5SDimitry Andric unsigned BestPos = LastLowLatencyUser + 1; 1712444ed5c5SDimitry Andric if ((int)BestPos <= LastLowLatencyPos) 1713444ed5c5SDimitry Andric BestPos = LastLowLatencyPos + 1; 1714444ed5c5SDimitry Andric if (BestPos < MinPos) 1715444ed5c5SDimitry Andric BestPos = MinPos; 1716444ed5c5SDimitry Andric if (BestPos < i) { 1717444ed5c5SDimitry Andric for (unsigned u = i; u > BestPos; --u) { 1718444ed5c5SDimitry Andric ++ScheduledSUnitsInv[ScheduledSUnits[u-1]]; 1719444ed5c5SDimitry Andric ScheduledSUnits[u] = ScheduledSUnits[u-1]; 1720444ed5c5SDimitry Andric } 1721444ed5c5SDimitry Andric ScheduledSUnits[BestPos] = SU->NodeNum; 1722444ed5c5SDimitry Andric ScheduledSUnitsInv[SU->NodeNum] = BestPos; 1723444ed5c5SDimitry Andric } 1724444ed5c5SDimitry Andric LastLowLatencyPos = BestPos; 1725444ed5c5SDimitry Andric if (IsLowLatencyUser) 1726444ed5c5SDimitry Andric LastLowLatencyUser = BestPos; 1727444ed5c5SDimitry Andric } else if (IsLowLatencyUser) { 1728444ed5c5SDimitry Andric LastLowLatencyUser = i; 1729444ed5c5SDimitry Andric // Moves COPY instructions on which depends 1730444ed5c5SDimitry Andric // the low latency instructions too. 1731444ed5c5SDimitry Andric } else if (SU->getInstr()->getOpcode() == AMDGPU::COPY) { 1732444ed5c5SDimitry Andric bool CopyForLowLat = false; 1733444ed5c5SDimitry Andric for (SDep& SuccDep : SU->Succs) { 1734444ed5c5SDimitry Andric SUnit *Succ = SuccDep.getSUnit(); 17353ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*Succ->getInstr())) { 1736444ed5c5SDimitry Andric CopyForLowLat = true; 1737444ed5c5SDimitry Andric } 1738444ed5c5SDimitry Andric } 1739444ed5c5SDimitry Andric if (!CopyForLowLat) 1740444ed5c5SDimitry Andric continue; 1741444ed5c5SDimitry Andric if (MinPos < i) { 1742444ed5c5SDimitry Andric for (unsigned u = i; u > MinPos; --u) { 1743444ed5c5SDimitry Andric ++ScheduledSUnitsInv[ScheduledSUnits[u-1]]; 1744444ed5c5SDimitry Andric ScheduledSUnits[u] = ScheduledSUnits[u-1]; 1745444ed5c5SDimitry Andric } 1746444ed5c5SDimitry Andric ScheduledSUnits[MinPos] = SU->NodeNum; 1747444ed5c5SDimitry Andric ScheduledSUnitsInv[SU->NodeNum] = MinPos; 1748444ed5c5SDimitry Andric } 1749444ed5c5SDimitry Andric } 1750444ed5c5SDimitry Andric } 1751444ed5c5SDimitry Andric } 1752444ed5c5SDimitry Andric 1753444ed5c5SDimitry Andric void SIScheduleDAGMI::restoreSULinksLeft() { 1754444ed5c5SDimitry Andric for (unsigned i = 0, e = SUnits.size(); i != e; ++i) { 1755444ed5c5SDimitry Andric SUnits[i].isScheduled = false; 1756444ed5c5SDimitry Andric SUnits[i].WeakPredsLeft = SUnitsLinksBackup[i].WeakPredsLeft; 1757444ed5c5SDimitry Andric SUnits[i].NumPredsLeft = SUnitsLinksBackup[i].NumPredsLeft; 1758444ed5c5SDimitry Andric SUnits[i].WeakSuccsLeft = SUnitsLinksBackup[i].WeakSuccsLeft; 1759444ed5c5SDimitry Andric SUnits[i].NumSuccsLeft = SUnitsLinksBackup[i].NumSuccsLeft; 1760444ed5c5SDimitry Andric } 1761444ed5c5SDimitry Andric } 1762444ed5c5SDimitry Andric 1763444ed5c5SDimitry Andric // Return the Vgpr and Sgpr usage corresponding to some virtual registers. 1764444ed5c5SDimitry Andric template<typename _Iterator> void 1765444ed5c5SDimitry Andric SIScheduleDAGMI::fillVgprSgprCost(_Iterator First, _Iterator End, 1766444ed5c5SDimitry Andric unsigned &VgprUsage, unsigned &SgprUsage) { 1767444ed5c5SDimitry Andric VgprUsage = 0; 1768444ed5c5SDimitry Andric SgprUsage = 0; 1769444ed5c5SDimitry Andric for (_Iterator RegI = First; RegI != End; ++RegI) { 1770444ed5c5SDimitry Andric unsigned Reg = *RegI; 1771444ed5c5SDimitry Andric // For now only track virtual registers 1772444ed5c5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1773444ed5c5SDimitry Andric continue; 1774444ed5c5SDimitry Andric PSetIterator PSetI = MRI.getPressureSets(Reg); 1775444ed5c5SDimitry Andric for (; PSetI.isValid(); ++PSetI) { 1776444ed5c5SDimitry Andric if (*PSetI == VGPRSetID) 1777444ed5c5SDimitry Andric VgprUsage += PSetI.getWeight(); 1778444ed5c5SDimitry Andric else if (*PSetI == SGPRSetID) 1779444ed5c5SDimitry Andric SgprUsage += PSetI.getWeight(); 1780444ed5c5SDimitry Andric } 1781444ed5c5SDimitry Andric } 1782444ed5c5SDimitry Andric } 1783444ed5c5SDimitry Andric 1784444ed5c5SDimitry Andric void SIScheduleDAGMI::schedule() 1785444ed5c5SDimitry Andric { 1786444ed5c5SDimitry Andric SmallVector<SUnit*, 8> TopRoots, BotRoots; 1787444ed5c5SDimitry Andric SIScheduleBlockResult Best, Temp; 1788444ed5c5SDimitry Andric DEBUG(dbgs() << "Preparing Scheduling\n"); 1789444ed5c5SDimitry Andric 1790444ed5c5SDimitry Andric buildDAGWithRegPressure(); 1791444ed5c5SDimitry Andric DEBUG( 1792444ed5c5SDimitry Andric for(SUnit& SU : SUnits) 1793444ed5c5SDimitry Andric SU.dumpAll(this) 1794444ed5c5SDimitry Andric ); 1795444ed5c5SDimitry Andric 1796444ed5c5SDimitry Andric topologicalSort(); 1797444ed5c5SDimitry Andric findRootsAndBiasEdges(TopRoots, BotRoots); 1798444ed5c5SDimitry Andric // We reuse several ScheduleDAGMI and ScheduleDAGMILive 1799444ed5c5SDimitry Andric // functions, but to make them happy we must initialize 1800444ed5c5SDimitry Andric // the default Scheduler implementation (even if we do not 1801444ed5c5SDimitry Andric // run it) 1802444ed5c5SDimitry Andric SchedImpl->initialize(this); 1803444ed5c5SDimitry Andric initQueues(TopRoots, BotRoots); 1804444ed5c5SDimitry Andric 1805444ed5c5SDimitry Andric // Fill some stats to help scheduling. 1806444ed5c5SDimitry Andric 1807444ed5c5SDimitry Andric SUnitsLinksBackup = SUnits; 1808444ed5c5SDimitry Andric IsLowLatencySU.clear(); 1809444ed5c5SDimitry Andric LowLatencyOffset.clear(); 1810444ed5c5SDimitry Andric IsHighLatencySU.clear(); 1811444ed5c5SDimitry Andric 1812444ed5c5SDimitry Andric IsLowLatencySU.resize(SUnits.size(), 0); 1813444ed5c5SDimitry Andric LowLatencyOffset.resize(SUnits.size(), 0); 1814444ed5c5SDimitry Andric IsHighLatencySU.resize(SUnits.size(), 0); 1815444ed5c5SDimitry Andric 1816444ed5c5SDimitry Andric for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) { 1817444ed5c5SDimitry Andric SUnit *SU = &SUnits[i]; 18183ca95b02SDimitry Andric unsigned BaseLatReg; 18193ca95b02SDimitry Andric int64_t OffLatReg; 18203ca95b02SDimitry Andric if (SITII->isLowLatencyInstruction(*SU->getInstr())) { 1821444ed5c5SDimitry Andric IsLowLatencySU[i] = 1; 18223ca95b02SDimitry Andric if (SITII->getMemOpBaseRegImmOfs(*SU->getInstr(), BaseLatReg, OffLatReg, 18233ca95b02SDimitry Andric TRI)) 1824444ed5c5SDimitry Andric LowLatencyOffset[i] = OffLatReg; 18253ca95b02SDimitry Andric } else if (SITII->isHighLatencyInstruction(*SU->getInstr())) 1826444ed5c5SDimitry Andric IsHighLatencySU[i] = 1; 1827444ed5c5SDimitry Andric } 1828444ed5c5SDimitry Andric 1829444ed5c5SDimitry Andric SIScheduler Scheduler(this); 1830444ed5c5SDimitry Andric Best = Scheduler.scheduleVariant(SISchedulerBlockCreatorVariant::LatenciesAlone, 1831444ed5c5SDimitry Andric SISchedulerBlockSchedulerVariant::BlockLatencyRegUsage); 18323ca95b02SDimitry Andric 1833444ed5c5SDimitry Andric // if VGPR usage is extremely high, try other good performing variants 1834444ed5c5SDimitry Andric // which could lead to lower VGPR usage 1835444ed5c5SDimitry Andric if (Best.MaxVGPRUsage > 180) { 1836444ed5c5SDimitry Andric std::vector<std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant>> Variants = { 1837444ed5c5SDimitry Andric { LatenciesAlone, BlockRegUsageLatency }, 1838444ed5c5SDimitry Andric // { LatenciesAlone, BlockRegUsage }, 1839444ed5c5SDimitry Andric { LatenciesGrouped, BlockLatencyRegUsage }, 1840444ed5c5SDimitry Andric // { LatenciesGrouped, BlockRegUsageLatency }, 1841444ed5c5SDimitry Andric // { LatenciesGrouped, BlockRegUsage }, 1842444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage }, 1843444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockRegUsageLatency }, 1844444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockRegUsage } 1845444ed5c5SDimitry Andric }; 1846444ed5c5SDimitry Andric for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) { 1847444ed5c5SDimitry Andric Temp = Scheduler.scheduleVariant(v.first, v.second); 1848444ed5c5SDimitry Andric if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage) 1849444ed5c5SDimitry Andric Best = Temp; 1850444ed5c5SDimitry Andric } 1851444ed5c5SDimitry Andric } 1852444ed5c5SDimitry Andric // if VGPR usage is still extremely high, we may spill. Try other variants 1853444ed5c5SDimitry Andric // which are less performing, but that could lead to lower VGPR usage. 1854444ed5c5SDimitry Andric if (Best.MaxVGPRUsage > 200) { 1855444ed5c5SDimitry Andric std::vector<std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant>> Variants = { 1856444ed5c5SDimitry Andric // { LatenciesAlone, BlockRegUsageLatency }, 1857444ed5c5SDimitry Andric { LatenciesAlone, BlockRegUsage }, 1858444ed5c5SDimitry Andric // { LatenciesGrouped, BlockLatencyRegUsage }, 1859444ed5c5SDimitry Andric { LatenciesGrouped, BlockRegUsageLatency }, 1860444ed5c5SDimitry Andric { LatenciesGrouped, BlockRegUsage }, 1861444ed5c5SDimitry Andric // { LatenciesAlonePlusConsecutive, BlockLatencyRegUsage }, 1862444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockRegUsageLatency }, 1863444ed5c5SDimitry Andric { LatenciesAlonePlusConsecutive, BlockRegUsage } 1864444ed5c5SDimitry Andric }; 1865444ed5c5SDimitry Andric for (std::pair<SISchedulerBlockCreatorVariant, SISchedulerBlockSchedulerVariant> v : Variants) { 1866444ed5c5SDimitry Andric Temp = Scheduler.scheduleVariant(v.first, v.second); 1867444ed5c5SDimitry Andric if (Temp.MaxVGPRUsage < Best.MaxVGPRUsage) 1868444ed5c5SDimitry Andric Best = Temp; 1869444ed5c5SDimitry Andric } 1870444ed5c5SDimitry Andric } 18713ca95b02SDimitry Andric 1872444ed5c5SDimitry Andric ScheduledSUnits = Best.SUs; 1873444ed5c5SDimitry Andric ScheduledSUnitsInv.resize(SUnits.size()); 1874444ed5c5SDimitry Andric 1875444ed5c5SDimitry Andric for (unsigned i = 0, e = (unsigned)SUnits.size(); i != e; ++i) { 1876444ed5c5SDimitry Andric ScheduledSUnitsInv[ScheduledSUnits[i]] = i; 1877444ed5c5SDimitry Andric } 1878444ed5c5SDimitry Andric 1879444ed5c5SDimitry Andric moveLowLatencies(); 1880444ed5c5SDimitry Andric 1881444ed5c5SDimitry Andric // Tell the outside world about the result of the scheduling. 1882444ed5c5SDimitry Andric 1883444ed5c5SDimitry Andric assert(TopRPTracker.getPos() == RegionBegin && "bad initial Top tracker"); 1884444ed5c5SDimitry Andric TopRPTracker.setPos(CurrentTop); 1885444ed5c5SDimitry Andric 1886444ed5c5SDimitry Andric for (std::vector<unsigned>::iterator I = ScheduledSUnits.begin(), 1887444ed5c5SDimitry Andric E = ScheduledSUnits.end(); I != E; ++I) { 1888444ed5c5SDimitry Andric SUnit *SU = &SUnits[*I]; 1889444ed5c5SDimitry Andric 1890444ed5c5SDimitry Andric scheduleMI(SU, true); 1891444ed5c5SDimitry Andric 1892444ed5c5SDimitry Andric DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " 1893444ed5c5SDimitry Andric << *SU->getInstr()); 1894444ed5c5SDimitry Andric } 1895444ed5c5SDimitry Andric 1896444ed5c5SDimitry Andric assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone."); 1897444ed5c5SDimitry Andric 1898444ed5c5SDimitry Andric placeDebugValues(); 1899444ed5c5SDimitry Andric 1900444ed5c5SDimitry Andric DEBUG({ 1901444ed5c5SDimitry Andric unsigned BBNum = begin()->getParent()->getNumber(); 1902444ed5c5SDimitry Andric dbgs() << "*** Final schedule for BB#" << BBNum << " ***\n"; 1903444ed5c5SDimitry Andric dumpSchedule(); 1904444ed5c5SDimitry Andric dbgs() << '\n'; 1905444ed5c5SDimitry Andric }); 1906444ed5c5SDimitry Andric } 1907