LLVM API Documentation
00001 //===-- NVPTXReplaceImageHandles.cpp - Replace image handles for Fermi ----===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // On Fermi, image handles are not supported. To work around this, we traverse 00011 // the machine code and replace image handles with concrete symbols. For this 00012 // to work reliably, inlining of all function call must be performed. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "NVPTX.h" 00017 #include "NVPTXMachineFunctionInfo.h" 00018 #include "NVPTXSubtarget.h" 00019 #include "llvm/CodeGen/MachineFunction.h" 00020 #include "llvm/CodeGen/MachineFunctionPass.h" 00021 #include "llvm/CodeGen/MachineRegisterInfo.h" 00022 #include "llvm/Support/raw_ostream.h" 00023 #include "llvm/ADT/DenseSet.h" 00024 00025 using namespace llvm; 00026 00027 namespace { 00028 class NVPTXReplaceImageHandles : public MachineFunctionPass { 00029 private: 00030 static char ID; 00031 DenseSet<MachineInstr *> InstrsToRemove; 00032 00033 public: 00034 NVPTXReplaceImageHandles(); 00035 00036 bool runOnMachineFunction(MachineFunction &MF) override; 00037 00038 const char *getPassName() const override { 00039 return "NVPTX Replace Image Handles"; 00040 } 00041 private: 00042 bool processInstr(MachineInstr &MI); 00043 void replaceImageHandle(MachineOperand &Op, MachineFunction &MF); 00044 bool findIndexForHandle(MachineOperand &Op, MachineFunction &MF, 00045 unsigned &Idx); 00046 }; 00047 } 00048 00049 char NVPTXReplaceImageHandles::ID = 0; 00050 00051 NVPTXReplaceImageHandles::NVPTXReplaceImageHandles() 00052 : MachineFunctionPass(ID) {} 00053 00054 bool NVPTXReplaceImageHandles::runOnMachineFunction(MachineFunction &MF) { 00055 bool Changed = false; 00056 InstrsToRemove.clear(); 00057 00058 for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); BI != BE; 00059 ++BI) { 00060 for (MachineBasicBlock::iterator I = (*BI).begin(), E = (*BI).end(); 00061 I != E; ++I) { 00062 MachineInstr &MI = *I; 00063 Changed |= processInstr(MI); 00064 } 00065 } 00066 00067 // Now clean up any handle-access instructions 00068 // This is needed in debug mode when code cleanup passes are not executed, 00069 // but we need the handle access to be eliminated because they are not 00070 // valid instructions when image handles are disabled. 00071 for (DenseSet<MachineInstr *>::iterator I = InstrsToRemove.begin(), 00072 E = InstrsToRemove.end(); I != E; ++I) { 00073 (*I)->eraseFromParent(); 00074 } 00075 return Changed; 00076 } 00077 00078 bool NVPTXReplaceImageHandles::processInstr(MachineInstr &MI) { 00079 MachineFunction &MF = *MI.getParent()->getParent(); 00080 const MCInstrDesc &MCID = MI.getDesc(); 00081 00082 if (MCID.TSFlags & NVPTXII::IsTexFlag) { 00083 // This is a texture fetch, so operand 4 is a texref and operand 5 is 00084 // a samplerref 00085 MachineOperand &TexHandle = MI.getOperand(4); 00086 replaceImageHandle(TexHandle, MF); 00087 00088 if (!(MCID.TSFlags & NVPTXII::IsTexModeUnifiedFlag)) { 00089 MachineOperand &SampHandle = MI.getOperand(5); 00090 replaceImageHandle(SampHandle, MF); 00091 } 00092 00093 return true; 00094 } else if (MCID.TSFlags & NVPTXII::IsSuldMask) { 00095 unsigned VecSize = 00096 1 << (((MCID.TSFlags & NVPTXII::IsSuldMask) >> NVPTXII::IsSuldShift) - 1); 00097 00098 // For a surface load of vector size N, the Nth operand will be the surfref 00099 MachineOperand &SurfHandle = MI.getOperand(VecSize); 00100 00101 replaceImageHandle(SurfHandle, MF); 00102 00103 return true; 00104 } else if (MCID.TSFlags & NVPTXII::IsSustFlag) { 00105 // This is a surface store, so operand 0 is a surfref 00106 MachineOperand &SurfHandle = MI.getOperand(0); 00107 00108 replaceImageHandle(SurfHandle, MF); 00109 00110 return true; 00111 } else if (MCID.TSFlags & NVPTXII::IsSurfTexQueryFlag) { 00112 // This is a query, so operand 1 is a surfref/texref 00113 MachineOperand &Handle = MI.getOperand(1); 00114 00115 replaceImageHandle(Handle, MF); 00116 00117 return true; 00118 } 00119 00120 return false; 00121 } 00122 00123 void NVPTXReplaceImageHandles:: 00124 replaceImageHandle(MachineOperand &Op, MachineFunction &MF) { 00125 unsigned Idx; 00126 if (findIndexForHandle(Op, MF, Idx)) { 00127 Op.ChangeToImmediate(Idx); 00128 } 00129 } 00130 00131 bool NVPTXReplaceImageHandles:: 00132 findIndexForHandle(MachineOperand &Op, MachineFunction &MF, unsigned &Idx) { 00133 const MachineRegisterInfo &MRI = MF.getRegInfo(); 00134 NVPTXMachineFunctionInfo *MFI = MF.getInfo<NVPTXMachineFunctionInfo>(); 00135 00136 assert(Op.isReg() && "Handle is not in a reg?"); 00137 00138 // Which instruction defines the handle? 00139 MachineInstr &TexHandleDef = *MRI.getVRegDef(Op.getReg()); 00140 00141 switch (TexHandleDef.getOpcode()) { 00142 case NVPTX::LD_i64_avar: { 00143 // The handle is a parameter value being loaded, replace with the 00144 // parameter symbol 00145 const NVPTXSubtarget &ST = MF.getTarget().getSubtarget<NVPTXSubtarget>(); 00146 if (ST.getDrvInterface() == NVPTX::CUDA) { 00147 // For CUDA, we preserve the param loads coming from function arguments 00148 return false; 00149 } 00150 00151 assert(TexHandleDef.getOperand(6).isSymbol() && "Load is not a symbol!"); 00152 StringRef Sym = TexHandleDef.getOperand(6).getSymbolName(); 00153 std::string ParamBaseName = MF.getName(); 00154 ParamBaseName += "_param_"; 00155 assert(Sym.startswith(ParamBaseName) && "Invalid symbol reference"); 00156 unsigned Param = atoi(Sym.data()+ParamBaseName.size()); 00157 std::string NewSym; 00158 raw_string_ostream NewSymStr(NewSym); 00159 NewSymStr << MF.getFunction()->getName() << "_param_" << Param; 00160 00161 InstrsToRemove.insert(&TexHandleDef); 00162 Idx = MFI->getImageHandleSymbolIndex(NewSymStr.str().c_str()); 00163 return true; 00164 } 00165 case NVPTX::texsurf_handles: { 00166 // The handle is a global variable, replace with the global variable name 00167 assert(TexHandleDef.getOperand(1).isGlobal() && "Load is not a global!"); 00168 const GlobalValue *GV = TexHandleDef.getOperand(1).getGlobal(); 00169 assert(GV->hasName() && "Global sampler must be named!"); 00170 InstrsToRemove.insert(&TexHandleDef); 00171 Idx = MFI->getImageHandleSymbolIndex(GV->getName().data()); 00172 return true; 00173 } 00174 case NVPTX::nvvm_move_i64: 00175 case TargetOpcode::COPY: { 00176 bool Res = findIndexForHandle(TexHandleDef.getOperand(1), MF, Idx); 00177 if (Res) { 00178 InstrsToRemove.insert(&TexHandleDef); 00179 } 00180 return Res; 00181 } 00182 default: 00183 llvm_unreachable("Unknown instruction operating on handle"); 00184 } 00185 } 00186 00187 MachineFunctionPass *llvm::createNVPTXReplaceImageHandlesPass() { 00188 return new NVPTXReplaceImageHandles(); 00189 }