1 1.1 joerg //===-- GCNNSAReassign.cpp - Reassign registers in NSA unstructions -------===// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg /// \file 10 1.1 joerg /// \brief Try to reassign registers on GFX10+ from non-sequential to sequential 11 1.1 joerg /// in NSA image instructions. Later SIShrinkInstructions pass will relace NSA 12 1.1 joerg /// with sequential versions where possible. 13 1.1 joerg /// 14 1.1 joerg //===----------------------------------------------------------------------===// 15 1.1 joerg 16 1.1 joerg #include "AMDGPU.h" 17 1.1.1.2 joerg #include "GCNSubtarget.h" 18 1.1 joerg #include "SIMachineFunctionInfo.h" 19 1.1 joerg #include "llvm/ADT/Statistic.h" 20 1.1 joerg #include "llvm/CodeGen/LiveIntervals.h" 21 1.1 joerg #include "llvm/CodeGen/LiveRegMatrix.h" 22 1.1 joerg #include "llvm/CodeGen/MachineFunctionPass.h" 23 1.1.1.2 joerg #include "llvm/InitializePasses.h" 24 1.1 joerg 25 1.1 joerg using namespace llvm; 26 1.1 joerg 27 1.1 joerg #define DEBUG_TYPE "amdgpu-nsa-reassign" 28 1.1 joerg 29 1.1 joerg STATISTIC(NumNSAInstructions, 30 1.1 joerg "Number of NSA instructions with non-sequential address found"); 31 1.1 joerg STATISTIC(NumNSAConverted, 32 1.1 joerg "Number of NSA instructions changed to sequential"); 33 1.1 joerg 34 1.1 joerg namespace { 35 1.1 joerg 36 1.1 joerg class GCNNSAReassign : public MachineFunctionPass { 37 1.1 joerg public: 38 1.1 joerg static char ID; 39 1.1 joerg 40 1.1 joerg GCNNSAReassign() : MachineFunctionPass(ID) { 41 1.1 joerg initializeGCNNSAReassignPass(*PassRegistry::getPassRegistry()); 42 1.1 joerg } 43 1.1 joerg 44 1.1 joerg bool runOnMachineFunction(MachineFunction &MF) override; 45 1.1 joerg 46 1.1 joerg StringRef getPassName() const override { return "GCN NSA Reassign"; } 47 1.1 joerg 48 1.1 joerg void getAnalysisUsage(AnalysisUsage &AU) const override { 49 1.1 joerg AU.addRequired<LiveIntervals>(); 50 1.1 joerg AU.addRequired<VirtRegMap>(); 51 1.1 joerg AU.addRequired<LiveRegMatrix>(); 52 1.1 joerg AU.setPreservesAll(); 53 1.1 joerg MachineFunctionPass::getAnalysisUsage(AU); 54 1.1 joerg } 55 1.1 joerg 56 1.1 joerg private: 57 1.1 joerg typedef enum { 58 1.1 joerg NOT_NSA, // Not an NSA instruction 59 1.1 joerg FIXED, // NSA which we cannot modify 60 1.1 joerg NON_CONTIGUOUS, // NSA with non-sequential address which we can try 61 1.1 joerg // to optimize. 62 1.1 joerg CONTIGUOUS // NSA with all sequential address registers 63 1.1 joerg } NSA_Status; 64 1.1 joerg 65 1.1 joerg const GCNSubtarget *ST; 66 1.1 joerg 67 1.1 joerg const MachineRegisterInfo *MRI; 68 1.1 joerg 69 1.1 joerg const SIRegisterInfo *TRI; 70 1.1 joerg 71 1.1 joerg VirtRegMap *VRM; 72 1.1 joerg 73 1.1 joerg LiveRegMatrix *LRM; 74 1.1 joerg 75 1.1 joerg LiveIntervals *LIS; 76 1.1 joerg 77 1.1 joerg unsigned MaxNumVGPRs; 78 1.1 joerg 79 1.1 joerg const MCPhysReg *CSRegs; 80 1.1 joerg 81 1.1 joerg NSA_Status CheckNSA(const MachineInstr &MI, bool Fast = false) const; 82 1.1 joerg 83 1.1 joerg bool tryAssignRegisters(SmallVectorImpl<LiveInterval *> &Intervals, 84 1.1 joerg unsigned StartReg) const; 85 1.1 joerg 86 1.1 joerg bool canAssign(unsigned StartReg, unsigned NumRegs) const; 87 1.1 joerg 88 1.1 joerg bool scavengeRegs(SmallVectorImpl<LiveInterval *> &Intervals) const; 89 1.1 joerg }; 90 1.1 joerg 91 1.1 joerg } // End anonymous namespace. 92 1.1 joerg 93 1.1 joerg INITIALIZE_PASS_BEGIN(GCNNSAReassign, DEBUG_TYPE, "GCN NSA Reassign", 94 1.1 joerg false, false) 95 1.1 joerg INITIALIZE_PASS_DEPENDENCY(LiveIntervals) 96 1.1 joerg INITIALIZE_PASS_DEPENDENCY(VirtRegMap) 97 1.1 joerg INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix) 98 1.1 joerg INITIALIZE_PASS_END(GCNNSAReassign, DEBUG_TYPE, "GCN NSA Reassign", 99 1.1 joerg false, false) 100 1.1 joerg 101 1.1 joerg 102 1.1 joerg char GCNNSAReassign::ID = 0; 103 1.1 joerg 104 1.1 joerg char &llvm::GCNNSAReassignID = GCNNSAReassign::ID; 105 1.1 joerg 106 1.1 joerg bool 107 1.1 joerg GCNNSAReassign::tryAssignRegisters(SmallVectorImpl<LiveInterval *> &Intervals, 108 1.1 joerg unsigned StartReg) const { 109 1.1 joerg unsigned NumRegs = Intervals.size(); 110 1.1 joerg 111 1.1 joerg for (unsigned N = 0; N < NumRegs; ++N) 112 1.1.1.2 joerg if (VRM->hasPhys(Intervals[N]->reg())) 113 1.1 joerg LRM->unassign(*Intervals[N]); 114 1.1 joerg 115 1.1 joerg for (unsigned N = 0; N < NumRegs; ++N) 116 1.1.1.2 joerg if (LRM->checkInterference(*Intervals[N], MCRegister::from(StartReg + N))) 117 1.1 joerg return false; 118 1.1 joerg 119 1.1 joerg for (unsigned N = 0; N < NumRegs; ++N) 120 1.1.1.2 joerg LRM->assign(*Intervals[N], MCRegister::from(StartReg + N)); 121 1.1 joerg 122 1.1 joerg return true; 123 1.1 joerg } 124 1.1 joerg 125 1.1 joerg bool GCNNSAReassign::canAssign(unsigned StartReg, unsigned NumRegs) const { 126 1.1 joerg for (unsigned N = 0; N < NumRegs; ++N) { 127 1.1 joerg unsigned Reg = StartReg + N; 128 1.1 joerg if (!MRI->isAllocatable(Reg)) 129 1.1 joerg return false; 130 1.1 joerg 131 1.1 joerg for (unsigned I = 0; CSRegs[I]; ++I) 132 1.1 joerg if (TRI->isSubRegisterEq(Reg, CSRegs[I]) && 133 1.1 joerg !LRM->isPhysRegUsed(CSRegs[I])) 134 1.1 joerg return false; 135 1.1 joerg } 136 1.1 joerg 137 1.1 joerg return true; 138 1.1 joerg } 139 1.1 joerg 140 1.1 joerg bool 141 1.1 joerg GCNNSAReassign::scavengeRegs(SmallVectorImpl<LiveInterval *> &Intervals) const { 142 1.1 joerg unsigned NumRegs = Intervals.size(); 143 1.1 joerg 144 1.1 joerg if (NumRegs > MaxNumVGPRs) 145 1.1 joerg return false; 146 1.1 joerg unsigned MaxReg = MaxNumVGPRs - NumRegs + AMDGPU::VGPR0; 147 1.1 joerg 148 1.1 joerg for (unsigned Reg = AMDGPU::VGPR0; Reg <= MaxReg; ++Reg) { 149 1.1 joerg if (!canAssign(Reg, NumRegs)) 150 1.1 joerg continue; 151 1.1 joerg 152 1.1 joerg if (tryAssignRegisters(Intervals, Reg)) 153 1.1 joerg return true; 154 1.1 joerg } 155 1.1 joerg 156 1.1 joerg return false; 157 1.1 joerg } 158 1.1 joerg 159 1.1 joerg GCNNSAReassign::NSA_Status 160 1.1 joerg GCNNSAReassign::CheckNSA(const MachineInstr &MI, bool Fast) const { 161 1.1 joerg const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(MI.getOpcode()); 162 1.1 joerg if (!Info || Info->MIMGEncoding != AMDGPU::MIMGEncGfx10NSA) 163 1.1 joerg return NSA_Status::NOT_NSA; 164 1.1 joerg 165 1.1 joerg int VAddr0Idx = 166 1.1 joerg AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vaddr0); 167 1.1 joerg 168 1.1 joerg unsigned VgprBase = 0; 169 1.1 joerg bool NSA = false; 170 1.1 joerg for (unsigned I = 0; I < Info->VAddrDwords; ++I) { 171 1.1 joerg const MachineOperand &Op = MI.getOperand(VAddr0Idx + I); 172 1.1 joerg Register Reg = Op.getReg(); 173 1.1.1.2 joerg if (Reg.isPhysical() || !VRM->isAssignedReg(Reg)) 174 1.1 joerg return NSA_Status::FIXED; 175 1.1 joerg 176 1.1 joerg Register PhysReg = VRM->getPhys(Reg); 177 1.1 joerg 178 1.1 joerg if (!Fast) { 179 1.1 joerg if (!PhysReg) 180 1.1 joerg return NSA_Status::FIXED; 181 1.1 joerg 182 1.1 joerg // Bail if address is not a VGPR32. That should be possible to extend the 183 1.1 joerg // optimization to work with subregs of a wider register tuples, but the 184 1.1 joerg // logic to find free registers will be much more complicated with much 185 1.1 joerg // less chances for success. That seems reasonable to assume that in most 186 1.1 joerg // cases a tuple is used because a vector variable contains different 187 1.1 joerg // parts of an address and it is either already consequitive or cannot 188 1.1 joerg // be reassigned if not. If needed it is better to rely on register 189 1.1 joerg // coalescer to process such address tuples. 190 1.1 joerg if (MRI->getRegClass(Reg) != &AMDGPU::VGPR_32RegClass || Op.getSubReg()) 191 1.1 joerg return NSA_Status::FIXED; 192 1.1 joerg 193 1.1.1.2 joerg // InlineSpiller does not call LRM::assign() after an LI split leaving 194 1.1.1.2 joerg // it in an inconsistent state, so we cannot call LRM::unassign(). 195 1.1.1.2 joerg // See llvm bug #48911. 196 1.1.1.2 joerg // Skip reassign if a register has originated from such split. 197 1.1.1.2 joerg // FIXME: Remove the workaround when bug #48911 is fixed. 198 1.1.1.2 joerg if (VRM->getPreSplitReg(Reg)) 199 1.1.1.2 joerg return NSA_Status::FIXED; 200 1.1.1.2 joerg 201 1.1 joerg const MachineInstr *Def = MRI->getUniqueVRegDef(Reg); 202 1.1 joerg 203 1.1 joerg if (Def && Def->isCopy() && Def->getOperand(1).getReg() == PhysReg) 204 1.1 joerg return NSA_Status::FIXED; 205 1.1 joerg 206 1.1 joerg for (auto U : MRI->use_nodbg_operands(Reg)) { 207 1.1 joerg if (U.isImplicit()) 208 1.1 joerg return NSA_Status::FIXED; 209 1.1 joerg const MachineInstr *UseInst = U.getParent(); 210 1.1 joerg if (UseInst->isCopy() && UseInst->getOperand(0).getReg() == PhysReg) 211 1.1 joerg return NSA_Status::FIXED; 212 1.1 joerg } 213 1.1 joerg 214 1.1 joerg if (!LIS->hasInterval(Reg)) 215 1.1 joerg return NSA_Status::FIXED; 216 1.1 joerg } 217 1.1 joerg 218 1.1 joerg if (I == 0) 219 1.1 joerg VgprBase = PhysReg; 220 1.1 joerg else if (VgprBase + I != PhysReg) 221 1.1 joerg NSA = true; 222 1.1 joerg } 223 1.1 joerg 224 1.1 joerg return NSA ? NSA_Status::NON_CONTIGUOUS : NSA_Status::CONTIGUOUS; 225 1.1 joerg } 226 1.1 joerg 227 1.1 joerg bool GCNNSAReassign::runOnMachineFunction(MachineFunction &MF) { 228 1.1 joerg ST = &MF.getSubtarget<GCNSubtarget>(); 229 1.1 joerg if (ST->getGeneration() < GCNSubtarget::GFX10) 230 1.1 joerg return false; 231 1.1 joerg 232 1.1 joerg MRI = &MF.getRegInfo(); 233 1.1 joerg TRI = ST->getRegisterInfo(); 234 1.1 joerg VRM = &getAnalysis<VirtRegMap>(); 235 1.1 joerg LRM = &getAnalysis<LiveRegMatrix>(); 236 1.1 joerg LIS = &getAnalysis<LiveIntervals>(); 237 1.1 joerg 238 1.1 joerg const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); 239 1.1 joerg MaxNumVGPRs = ST->getMaxNumVGPRs(MF); 240 1.1 joerg MaxNumVGPRs = std::min(ST->getMaxNumVGPRs(MFI->getOccupancy()), MaxNumVGPRs); 241 1.1 joerg CSRegs = MRI->getCalleeSavedRegs(); 242 1.1 joerg 243 1.1 joerg using Candidate = std::pair<const MachineInstr*, bool>; 244 1.1 joerg SmallVector<Candidate, 32> Candidates; 245 1.1 joerg for (const MachineBasicBlock &MBB : MF) { 246 1.1 joerg for (const MachineInstr &MI : MBB) { 247 1.1 joerg switch (CheckNSA(MI)) { 248 1.1 joerg default: 249 1.1 joerg continue; 250 1.1 joerg case NSA_Status::CONTIGUOUS: 251 1.1 joerg Candidates.push_back(std::make_pair(&MI, true)); 252 1.1 joerg break; 253 1.1 joerg case NSA_Status::NON_CONTIGUOUS: 254 1.1 joerg Candidates.push_back(std::make_pair(&MI, false)); 255 1.1 joerg ++NumNSAInstructions; 256 1.1 joerg break; 257 1.1 joerg } 258 1.1 joerg } 259 1.1 joerg } 260 1.1 joerg 261 1.1 joerg bool Changed = false; 262 1.1 joerg for (auto &C : Candidates) { 263 1.1 joerg if (C.second) 264 1.1 joerg continue; 265 1.1 joerg 266 1.1 joerg const MachineInstr *MI = C.first; 267 1.1 joerg if (CheckNSA(*MI, true) == NSA_Status::CONTIGUOUS) { 268 1.1 joerg // Already happen to be fixed. 269 1.1 joerg C.second = true; 270 1.1 joerg ++NumNSAConverted; 271 1.1 joerg continue; 272 1.1 joerg } 273 1.1 joerg 274 1.1 joerg const AMDGPU::MIMGInfo *Info = AMDGPU::getMIMGInfo(MI->getOpcode()); 275 1.1 joerg int VAddr0Idx = 276 1.1 joerg AMDGPU::getNamedOperandIdx(MI->getOpcode(), AMDGPU::OpName::vaddr0); 277 1.1 joerg 278 1.1 joerg SmallVector<LiveInterval *, 16> Intervals; 279 1.1.1.2 joerg SmallVector<MCRegister, 16> OrigRegs; 280 1.1 joerg SlotIndex MinInd, MaxInd; 281 1.1 joerg for (unsigned I = 0; I < Info->VAddrDwords; ++I) { 282 1.1 joerg const MachineOperand &Op = MI->getOperand(VAddr0Idx + I); 283 1.1 joerg Register Reg = Op.getReg(); 284 1.1 joerg LiveInterval *LI = &LIS->getInterval(Reg); 285 1.1.1.2 joerg if (llvm::is_contained(Intervals, LI)) { 286 1.1 joerg // Same register used, unable to make sequential 287 1.1 joerg Intervals.clear(); 288 1.1 joerg break; 289 1.1 joerg } 290 1.1 joerg Intervals.push_back(LI); 291 1.1 joerg OrigRegs.push_back(VRM->getPhys(Reg)); 292 1.1.1.2 joerg if (LI->empty()) { 293 1.1.1.2 joerg // The address input is undef, so it doesn't contribute to the relevant 294 1.1.1.2 joerg // range. Seed a reasonable index range if required. 295 1.1.1.2 joerg if (I == 0) 296 1.1.1.2 joerg MinInd = MaxInd = LIS->getInstructionIndex(*MI); 297 1.1.1.2 joerg continue; 298 1.1.1.2 joerg } 299 1.1.1.2 joerg MinInd = I != 0 ? std::min(MinInd, LI->beginIndex()) : LI->beginIndex(); 300 1.1.1.2 joerg MaxInd = I != 0 ? std::max(MaxInd, LI->endIndex()) : LI->endIndex(); 301 1.1 joerg } 302 1.1 joerg 303 1.1 joerg if (Intervals.empty()) 304 1.1 joerg continue; 305 1.1 joerg 306 1.1 joerg LLVM_DEBUG(dbgs() << "Attempting to reassign NSA: " << *MI 307 1.1 joerg << "\tOriginal allocation:\t"; 308 1.1.1.2 joerg for (auto *LI 309 1.1.1.2 joerg : Intervals) dbgs() 310 1.1.1.2 joerg << " " << llvm::printReg((VRM->getPhys(LI->reg())), TRI); 311 1.1 joerg dbgs() << '\n'); 312 1.1 joerg 313 1.1 joerg bool Success = scavengeRegs(Intervals); 314 1.1 joerg if (!Success) { 315 1.1 joerg LLVM_DEBUG(dbgs() << "\tCannot reallocate.\n"); 316 1.1.1.2 joerg if (VRM->hasPhys(Intervals.back()->reg())) // Did not change allocation. 317 1.1 joerg continue; 318 1.1 joerg } else { 319 1.1 joerg // Check we did not make it worse for other instructions. 320 1.1 joerg auto I = std::lower_bound(Candidates.begin(), &C, MinInd, 321 1.1 joerg [this](const Candidate &C, SlotIndex I) { 322 1.1 joerg return LIS->getInstructionIndex(*C.first) < I; 323 1.1 joerg }); 324 1.1 joerg for (auto E = Candidates.end(); Success && I != E && 325 1.1 joerg LIS->getInstructionIndex(*I->first) < MaxInd; ++I) { 326 1.1 joerg if (I->second && CheckNSA(*I->first, true) < NSA_Status::CONTIGUOUS) { 327 1.1 joerg Success = false; 328 1.1 joerg LLVM_DEBUG(dbgs() << "\tNSA conversion conflict with " << *I->first); 329 1.1 joerg } 330 1.1 joerg } 331 1.1 joerg } 332 1.1 joerg 333 1.1 joerg if (!Success) { 334 1.1 joerg for (unsigned I = 0; I < Info->VAddrDwords; ++I) 335 1.1.1.2 joerg if (VRM->hasPhys(Intervals[I]->reg())) 336 1.1 joerg LRM->unassign(*Intervals[I]); 337 1.1 joerg 338 1.1 joerg for (unsigned I = 0; I < Info->VAddrDwords; ++I) 339 1.1 joerg LRM->assign(*Intervals[I], OrigRegs[I]); 340 1.1 joerg 341 1.1 joerg continue; 342 1.1 joerg } 343 1.1 joerg 344 1.1 joerg C.second = true; 345 1.1 joerg ++NumNSAConverted; 346 1.1.1.2 joerg LLVM_DEBUG( 347 1.1.1.2 joerg dbgs() << "\tNew allocation:\t\t [" 348 1.1.1.2 joerg << llvm::printReg((VRM->getPhys(Intervals.front()->reg())), TRI) 349 1.1.1.2 joerg << " : " 350 1.1.1.2 joerg << llvm::printReg((VRM->getPhys(Intervals.back()->reg())), TRI) 351 1.1.1.2 joerg << "]\n"); 352 1.1 joerg Changed = true; 353 1.1 joerg } 354 1.1 joerg 355 1.1 joerg return Changed; 356 1.1 joerg } 357