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