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