| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 1 | //===-- NVPTXReplaceImageHandles.cpp - Replace image handles for Fermi ----===// | 
|  | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | 4 | // See https://llvm.org/LICENSE.txt for license information. | 
|  | 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
|  | 9 | // On Fermi, image handles are not supported. To work around this, we traverse | 
|  | 10 | // the machine code and replace image handles with concrete symbols. For this | 
|  | 11 | // to work reliably, inlining of all function call must be performed. | 
|  | 12 | // | 
|  | 13 | //===----------------------------------------------------------------------===// | 
|  | 14 |  | 
|  | 15 | #include "NVPTX.h" | 
|  | 16 | #include "NVPTXMachineFunctionInfo.h" | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 17 | #include "NVPTXSubtarget.h" | 
| Eric Christopher | beffc4e | 2015-02-19 00:08:23 +0000 | [diff] [blame] | 18 | #include "NVPTXTargetMachine.h" | 
| Dmitri Gribenko | 14c69fe | 2019-06-03 14:26:50 +0000 | [diff] [blame] | 19 | #include "MCTargetDesc/NVPTXBaseInfo.h" | 
| Chandler Carruth | d990388 | 2015-01-14 11:23:27 +0000 | [diff] [blame] | 20 | #include "llvm/ADT/DenseSet.h" | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 21 | #include "llvm/CodeGen/MachineFunction.h" | 
|  | 22 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | 23 | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | 24 | #include "llvm/Support/raw_ostream.h" | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 25 |  | 
|  | 26 | using namespace llvm; | 
|  | 27 |  | 
|  | 28 | namespace { | 
|  | 29 | class NVPTXReplaceImageHandles : public MachineFunctionPass { | 
|  | 30 | private: | 
|  | 31 | static char ID; | 
|  | 32 | DenseSet<MachineInstr *> InstrsToRemove; | 
|  | 33 |  | 
|  | 34 | public: | 
|  | 35 | NVPTXReplaceImageHandles(); | 
|  | 36 |  | 
| Benjamin Kramer | 8c90fd7 | 2014-09-03 11:41:21 +0000 | [diff] [blame] | 37 | bool runOnMachineFunction(MachineFunction &MF) override; | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 38 |  | 
| Mehdi Amini | 117296c | 2016-10-01 02:56:57 +0000 | [diff] [blame] | 39 | StringRef getPassName() const override { | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 40 | return "NVPTX Replace Image Handles"; | 
|  | 41 | } | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 42 | private: | 
|  | 43 | bool processInstr(MachineInstr &MI); | 
|  | 44 | void replaceImageHandle(MachineOperand &Op, MachineFunction &MF); | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 45 | bool findIndexForHandle(MachineOperand &Op, MachineFunction &MF, | 
|  | 46 | unsigned &Idx); | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 47 | }; | 
| Alexander Kornienko | f00654e | 2015-06-23 09:49:53 +0000 | [diff] [blame] | 48 | } | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 49 |  | 
|  | 50 | char NVPTXReplaceImageHandles::ID = 0; | 
|  | 51 |  | 
|  | 52 | NVPTXReplaceImageHandles::NVPTXReplaceImageHandles() | 
|  | 53 | : MachineFunctionPass(ID) {} | 
|  | 54 |  | 
|  | 55 | bool NVPTXReplaceImageHandles::runOnMachineFunction(MachineFunction &MF) { | 
|  | 56 | bool Changed = false; | 
|  | 57 | InstrsToRemove.clear(); | 
|  | 58 |  | 
|  | 59 | for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); BI != BE; | 
|  | 60 | ++BI) { | 
|  | 61 | for (MachineBasicBlock::iterator I = (*BI).begin(), E = (*BI).end(); | 
|  | 62 | I != E; ++I) { | 
|  | 63 | MachineInstr &MI = *I; | 
|  | 64 | Changed |= processInstr(MI); | 
|  | 65 | } | 
|  | 66 | } | 
|  | 67 |  | 
|  | 68 | // Now clean up any handle-access instructions | 
|  | 69 | // This is needed in debug mode when code cleanup passes are not executed, | 
|  | 70 | // but we need the handle access to be eliminated because they are not | 
|  | 71 | // valid instructions when image handles are disabled. | 
|  | 72 | for (DenseSet<MachineInstr *>::iterator I = InstrsToRemove.begin(), | 
|  | 73 | E = InstrsToRemove.end(); I != E; ++I) { | 
|  | 74 | (*I)->eraseFromParent(); | 
|  | 75 | } | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 76 | return Changed; | 
|  | 77 | } | 
|  | 78 |  | 
|  | 79 | bool NVPTXReplaceImageHandles::processInstr(MachineInstr &MI) { | 
|  | 80 | MachineFunction &MF = *MI.getParent()->getParent(); | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 81 | const MCInstrDesc &MCID = MI.getDesc(); | 
|  | 82 |  | 
|  | 83 | if (MCID.TSFlags & NVPTXII::IsTexFlag) { | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 84 | // This is a texture fetch, so operand 4 is a texref and operand 5 is | 
|  | 85 | // a samplerref | 
|  | 86 | MachineOperand &TexHandle = MI.getOperand(4); | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 87 | replaceImageHandle(TexHandle, MF); | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 88 |  | 
|  | 89 | if (!(MCID.TSFlags & NVPTXII::IsTexModeUnifiedFlag)) { | 
|  | 90 | MachineOperand &SampHandle = MI.getOperand(5); | 
|  | 91 | replaceImageHandle(SampHandle, MF); | 
|  | 92 | } | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 93 |  | 
|  | 94 | return true; | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 95 | } else if (MCID.TSFlags & NVPTXII::IsSuldMask) { | 
|  | 96 | unsigned VecSize = | 
|  | 97 | 1 << (((MCID.TSFlags & NVPTXII::IsSuldMask) >> NVPTXII::IsSuldShift) - 1); | 
|  | 98 |  | 
|  | 99 | // For a surface load of vector size N, the Nth operand will be the surfref | 
|  | 100 | MachineOperand &SurfHandle = MI.getOperand(VecSize); | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 101 |  | 
|  | 102 | replaceImageHandle(SurfHandle, MF); | 
|  | 103 |  | 
|  | 104 | return true; | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 105 | } else if (MCID.TSFlags & NVPTXII::IsSustFlag) { | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 106 | // This is a surface store, so operand 0 is a surfref | 
|  | 107 | MachineOperand &SurfHandle = MI.getOperand(0); | 
|  | 108 |  | 
|  | 109 | replaceImageHandle(SurfHandle, MF); | 
|  | 110 |  | 
|  | 111 | return true; | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 112 | } else if (MCID.TSFlags & NVPTXII::IsSurfTexQueryFlag) { | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 113 | // This is a query, so operand 1 is a surfref/texref | 
|  | 114 | MachineOperand &Handle = MI.getOperand(1); | 
|  | 115 |  | 
|  | 116 | replaceImageHandle(Handle, MF); | 
|  | 117 |  | 
| Eli Bendersky | 8e131f8 | 2015-07-08 16:33:21 +0000 | [diff] [blame] | 118 | return true; | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 119 | } | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 120 |  | 
|  | 121 | return false; | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 122 | } | 
|  | 123 |  | 
|  | 124 | void NVPTXReplaceImageHandles:: | 
|  | 125 | replaceImageHandle(MachineOperand &Op, MachineFunction &MF) { | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 126 | unsigned Idx; | 
|  | 127 | if (findIndexForHandle(Op, MF, Idx)) { | 
|  | 128 | Op.ChangeToImmediate(Idx); | 
|  | 129 | } | 
|  | 130 | } | 
|  | 131 |  | 
|  | 132 | bool NVPTXReplaceImageHandles:: | 
|  | 133 | findIndexForHandle(MachineOperand &Op, MachineFunction &MF, unsigned &Idx) { | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 134 | const MachineRegisterInfo &MRI = MF.getRegInfo(); | 
|  | 135 | NVPTXMachineFunctionInfo *MFI = MF.getInfo<NVPTXMachineFunctionInfo>(); | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 136 |  | 
|  | 137 | assert(Op.isReg() && "Handle is not in a reg?"); | 
|  | 138 |  | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 139 | // Which instruction defines the handle? | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 140 | MachineInstr &TexHandleDef = *MRI.getVRegDef(Op.getReg()); | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 141 |  | 
|  | 142 | switch (TexHandleDef.getOpcode()) { | 
|  | 143 | case NVPTX::LD_i64_avar: { | 
|  | 144 | // The handle is a parameter value being loaded, replace with the | 
|  | 145 | // parameter symbol | 
| Eric Christopher | beffc4e | 2015-02-19 00:08:23 +0000 | [diff] [blame] | 146 | const NVPTXTargetMachine &TM = | 
|  | 147 | static_cast<const NVPTXTargetMachine &>(MF.getTarget()); | 
|  | 148 | if (TM.getDrvInterface() == NVPTX::CUDA) { | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 149 | // For CUDA, we preserve the param loads coming from function arguments | 
|  | 150 | return false; | 
|  | 151 | } | 
|  | 152 |  | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 153 | assert(TexHandleDef.getOperand(6).isSymbol() && "Load is not a symbol!"); | 
|  | 154 | StringRef Sym = TexHandleDef.getOperand(6).getSymbolName(); | 
|  | 155 | std::string ParamBaseName = MF.getName(); | 
|  | 156 | ParamBaseName += "_param_"; | 
|  | 157 | assert(Sym.startswith(ParamBaseName) && "Invalid symbol reference"); | 
|  | 158 | unsigned Param = atoi(Sym.data()+ParamBaseName.size()); | 
|  | 159 | std::string NewSym; | 
|  | 160 | raw_string_ostream NewSymStr(NewSym); | 
| Matthias Braun | f1caa28 | 2017-12-15 22:22:58 +0000 | [diff] [blame] | 161 | NewSymStr << MF.getName() << "_param_" << Param; | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 162 |  | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 163 | InstrsToRemove.insert(&TexHandleDef); | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 164 | Idx = MFI->getImageHandleSymbolIndex(NewSymStr.str().c_str()); | 
|  | 165 | return true; | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 166 | } | 
|  | 167 | case NVPTX::texsurf_handles: { | 
|  | 168 | // The handle is a global variable, replace with the global variable name | 
|  | 169 | assert(TexHandleDef.getOperand(1).isGlobal() && "Load is not a global!"); | 
|  | 170 | const GlobalValue *GV = TexHandleDef.getOperand(1).getGlobal(); | 
|  | 171 | assert(GV->hasName() && "Global sampler must be named!"); | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 172 | InstrsToRemove.insert(&TexHandleDef); | 
| Justin Holewinski | 9a2350e | 2014-07-17 11:59:04 +0000 | [diff] [blame] | 173 | Idx = MFI->getImageHandleSymbolIndex(GV->getName().data()); | 
|  | 174 | return true; | 
|  | 175 | } | 
|  | 176 | case NVPTX::nvvm_move_i64: | 
|  | 177 | case TargetOpcode::COPY: { | 
|  | 178 | bool Res = findIndexForHandle(TexHandleDef.getOperand(1), MF, Idx); | 
|  | 179 | if (Res) { | 
|  | 180 | InstrsToRemove.insert(&TexHandleDef); | 
|  | 181 | } | 
|  | 182 | return Res; | 
| Justin Holewinski | 30d56a7 | 2014-04-09 15:39:15 +0000 | [diff] [blame] | 183 | } | 
|  | 184 | default: | 
|  | 185 | llvm_unreachable("Unknown instruction operating on handle"); | 
|  | 186 | } | 
|  | 187 | } | 
|  | 188 |  | 
|  | 189 | MachineFunctionPass *llvm::createNVPTXReplaceImageHandlesPass() { | 
|  | 190 | return new NVPTXReplaceImageHandles(); | 
|  | 191 | } |