| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 1 | //===-- SIPrepareScratchRegs.cpp - Use predicates for control flow --------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
|  | 10 | /// \file | 
|  | 11 | /// | 
|  | 12 | /// This pass loads scratch pointer and scratch offset into a register or a | 
|  | 13 | /// frame index which can be used anywhere in the program.  These values will | 
|  | 14 | /// be used for spilling VGPRs. | 
|  | 15 | /// | 
|  | 16 | //===----------------------------------------------------------------------===// | 
|  | 17 |  | 
|  | 18 | #include "AMDGPU.h" | 
|  | 19 | #include "AMDGPUSubtarget.h" | 
|  | 20 | #include "SIDefines.h" | 
|  | 21 | #include "SIInstrInfo.h" | 
|  | 22 | #include "SIMachineFunctionInfo.h" | 
|  | 23 | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | 24 | #include "llvm/CodeGen/MachineFunction.h" | 
|  | 25 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | 26 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | 27 | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | 28 | #include "llvm/CodeGen/RegisterScavenging.h" | 
|  | 29 | #include "llvm/IR/Function.h" | 
|  | 30 | #include "llvm/IR/LLVMContext.h" | 
|  | 31 |  | 
|  | 32 | using namespace llvm; | 
|  | 33 |  | 
|  | 34 | namespace { | 
|  | 35 |  | 
|  | 36 | class SIPrepareScratchRegs : public MachineFunctionPass { | 
|  | 37 |  | 
|  | 38 | private: | 
|  | 39 | static char ID; | 
|  | 40 |  | 
|  | 41 | public: | 
|  | 42 | SIPrepareScratchRegs() : MachineFunctionPass(ID) { } | 
|  | 43 |  | 
|  | 44 | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  | 45 |  | 
|  | 46 | const char *getPassName() const override { | 
|  | 47 | return "SI prepare scratch registers"; | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | }; | 
|  | 51 |  | 
|  | 52 | } // End anonymous namespace | 
|  | 53 |  | 
|  | 54 | char SIPrepareScratchRegs::ID = 0; | 
|  | 55 |  | 
|  | 56 | FunctionPass *llvm::createSIPrepareScratchRegs() { | 
|  | 57 | return new SIPrepareScratchRegs(); | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | bool SIPrepareScratchRegs::runOnMachineFunction(MachineFunction &MF) { | 
|  | 61 | SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); | 
|  | 62 | const SIInstrInfo *TII = | 
|  | 63 | static_cast<const SIInstrInfo *>(MF.getSubtarget().getInstrInfo()); | 
|  | 64 | const SIRegisterInfo *TRI = &TII->getRegisterInfo(); | 
|  | 65 | MachineRegisterInfo &MRI = MF.getRegInfo(); | 
|  | 66 | MachineFrameInfo *FrameInfo = MF.getFrameInfo(); | 
|  | 67 | MachineBasicBlock *Entry = MF.begin(); | 
|  | 68 | MachineBasicBlock::iterator I = Entry->begin(); | 
|  | 69 | DebugLoc DL = I->getDebugLoc(); | 
|  | 70 |  | 
|  | 71 | // FIXME: If we don't have enough VGPRs for SGPR spilling we will need to | 
|  | 72 | // run this pass. | 
|  | 73 | if (!MFI->hasSpilledVGPRs()) | 
|  | 74 | return false; | 
|  | 75 |  | 
|  | 76 | unsigned ScratchPtrPreloadReg = | 
|  | 77 | TRI->getPreloadedValue(MF, SIRegisterInfo::SCRATCH_PTR); | 
|  | 78 | unsigned ScratchOffsetPreloadReg = | 
|  | 79 | TRI->getPreloadedValue(MF, SIRegisterInfo::SCRATCH_WAVE_OFFSET); | 
|  | 80 |  | 
|  | 81 | if (!Entry->isLiveIn(ScratchPtrPreloadReg)) | 
|  | 82 | Entry->addLiveIn(ScratchPtrPreloadReg); | 
|  | 83 |  | 
|  | 84 | if (!Entry->isLiveIn(ScratchOffsetPreloadReg)) | 
|  | 85 | Entry->addLiveIn(ScratchOffsetPreloadReg); | 
|  | 86 |  | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 87 | // Load the scratch offset. | 
|  | 88 | unsigned ScratchOffsetReg = | 
|  | 89 | TRI->findUnusedRegister(MRI, &AMDGPU::SGPR_32RegClass); | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 90 | int ScratchOffsetFI = -1; | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 91 |  | 
|  | 92 | if (ScratchOffsetReg != AMDGPU::NoRegister) { | 
|  | 93 | // Found an SGPR to use | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 94 | BuildMI(*Entry, I, DL, TII->get(AMDGPU::S_MOV_B32), ScratchOffsetReg) | 
|  | 95 | .addReg(ScratchOffsetPreloadReg); | 
|  | 96 | } else { | 
|  | 97 | // No SGPR is available, we must spill. | 
|  | 98 | ScratchOffsetFI = FrameInfo->CreateSpillStackObject(4,4); | 
|  | 99 | BuildMI(*Entry, I, DL, TII->get(AMDGPU::SI_SPILL_S32_SAVE)) | 
|  | 100 | .addReg(ScratchOffsetPreloadReg) | 
| Tom Stellard | 021053f | 2015-01-20 19:33:02 +0000 | [diff] [blame] | 101 | .addFrameIndex(ScratchOffsetFI) | 
|  | 102 | .addReg(AMDGPU::SGPR0_SGPR1_SGPR2_SGPR3, RegState::Undef) | 
|  | 103 | .addReg(AMDGPU::SGPR0, RegState::Undef); | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 104 | } | 
|  | 105 |  | 
|  | 106 |  | 
|  | 107 | // Now that we have the scratch pointer and offset values, we need to | 
|  | 108 | // add them to all the SI_SPILL_V* instructions. | 
|  | 109 |  | 
|  | 110 | RegScavenger RS; | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 111 | unsigned ScratchRsrcFI = FrameInfo->CreateSpillStackObject(16, 4); | 
|  | 112 | RS.addScavengingFrameIndex(ScratchRsrcFI); | 
|  | 113 |  | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 114 | for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); | 
|  | 115 | BI != BE; ++BI) { | 
|  | 116 |  | 
|  | 117 | MachineBasicBlock &MBB = *BI; | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 118 | // Add the scratch offset reg as a live-in so that the register scavenger | 
|  | 119 | // doesn't re-use it. | 
| Tom Stellard | 021053f | 2015-01-20 19:33:02 +0000 | [diff] [blame] | 120 | if (!MBB.isLiveIn(ScratchOffsetReg) && | 
|  | 121 | ScratchOffsetReg != AMDGPU::NoRegister) | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 122 | MBB.addLiveIn(ScratchOffsetReg); | 
|  | 123 | RS.enterBasicBlock(&MBB); | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 124 |  | 
|  | 125 | for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); | 
|  | 126 | I != E; ++I) { | 
|  | 127 | MachineInstr &MI = *I; | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 128 | RS.forward(I); | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 129 | DebugLoc DL = MI.getDebugLoc(); | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 130 | if (!TII->isVGPRSpill(MI.getOpcode())) | 
|  | 131 | continue; | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 132 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 133 | // Scratch resource | 
|  | 134 | unsigned ScratchRsrcReg = | 
|  | 135 | RS.scavengeRegister(&AMDGPU::SReg_128RegClass, 0); | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 136 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 137 | uint64_t Rsrc = AMDGPU::RSRC_DATA_FORMAT | AMDGPU::RSRC_TID_ENABLE | | 
|  | 138 | 0xffffffff; // Size | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 139 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 140 | unsigned Rsrc0 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0); | 
|  | 141 | unsigned Rsrc1 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub1); | 
|  | 142 | unsigned Rsrc2 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub2); | 
|  | 143 | unsigned Rsrc3 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub3); | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 144 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 145 | BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), Rsrc0) | 
|  | 146 | .addExternalSymbol("SCRATCH_RSRC_DWORD0") | 
|  | 147 | .addReg(ScratchRsrcReg, RegState::ImplicitDefine); | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 148 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 149 | BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), Rsrc1) | 
|  | 150 | .addExternalSymbol("SCRATCH_RSRC_DWORD1") | 
|  | 151 | .addReg(ScratchRsrcReg, RegState::ImplicitDefine); | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 152 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 153 | BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), Rsrc2) | 
|  | 154 | .addImm(Rsrc & 0xffffffff) | 
|  | 155 | .addReg(ScratchRsrcReg, RegState::ImplicitDefine); | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 156 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 157 | BuildMI(MBB, I, DL, TII->get(AMDGPU::S_MOV_B32), Rsrc3) | 
|  | 158 | .addImm(Rsrc >> 32) | 
|  | 159 | .addReg(ScratchRsrcReg, RegState::ImplicitDefine); | 
| Tom Stellard | 95292bb | 2015-01-20 17:49:47 +0000 | [diff] [blame] | 160 |  | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 161 | // Scratch Offset | 
|  | 162 | if (ScratchOffsetReg == AMDGPU::NoRegister) { | 
|  | 163 | ScratchOffsetReg = RS.scavengeRegister(&AMDGPU::SGPR_32RegClass, 0); | 
|  | 164 | BuildMI(MBB, I, DL, TII->get(AMDGPU::SI_SPILL_S32_RESTORE), | 
|  | 165 | ScratchOffsetReg) | 
|  | 166 | .addFrameIndex(ScratchOffsetFI) | 
|  | 167 | .addReg(AMDGPU::SGPR0_SGPR1_SGPR2_SGPR3, RegState::Undef) | 
|  | 168 | .addReg(AMDGPU::SGPR0, RegState::Undef); | 
|  | 169 | } else if (!MBB.isLiveIn(ScratchOffsetReg)) { | 
|  | 170 | MBB.addLiveIn(ScratchOffsetReg); | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 171 | } | 
| Tom Stellard | a77c3f7 | 2015-05-12 18:59:17 +0000 | [diff] [blame] | 172 |  | 
|  | 173 | if (ScratchRsrcReg == AMDGPU::NoRegister || | 
|  | 174 | ScratchOffsetReg == AMDGPU::NoRegister) { | 
|  | 175 | LLVMContext &Ctx = MF.getFunction()->getContext(); | 
|  | 176 | Ctx.emitError("ran out of SGPRs for spilling VGPRs"); | 
|  | 177 | ScratchRsrcReg = AMDGPU::SGPR0; | 
|  | 178 | ScratchOffsetReg = AMDGPU::SGPR0; | 
|  | 179 | } | 
|  | 180 | MI.getOperand(2).setReg(ScratchRsrcReg); | 
|  | 181 | MI.getOperand(2).setIsKill(true); | 
|  | 182 | MI.getOperand(2).setIsUndef(false); | 
|  | 183 | MI.getOperand(3).setReg(ScratchOffsetReg); | 
|  | 184 | MI.getOperand(3).setIsUndef(false); | 
|  | 185 | MI.getOperand(3).setIsKill(false); | 
|  | 186 | MI.addOperand(MachineOperand::CreateReg(Rsrc0, false, true, true)); | 
|  | 187 | MI.addOperand(MachineOperand::CreateReg(Rsrc1, false, true, true)); | 
|  | 188 | MI.addOperand(MachineOperand::CreateReg(Rsrc2, false, true, true)); | 
|  | 189 | MI.addOperand(MachineOperand::CreateReg(Rsrc3, false, true, true)); | 
| Tom Stellard | 42fb60e | 2015-01-14 15:42:31 +0000 | [diff] [blame] | 190 | } | 
|  | 191 | } | 
|  | 192 | return true; | 
|  | 193 | } |