|  | //===-- NVPTXReplaceImageHandles.cpp - Replace image handles for Fermi ----===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // On Fermi, image handles are not supported. To work around this, we traverse | 
|  | // the machine code and replace image handles with concrete symbols. For this | 
|  | // to work reliably, inlining of all function call must be performed. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "NVPTX.h" | 
|  | #include "NVPTXMachineFunctionInfo.h" | 
|  | #include "NVPTXSubtarget.h" | 
|  | #include "NVPTXTargetMachine.h" | 
|  | #include "llvm/ADT/DenseSet.h" | 
|  | #include "llvm/CodeGen/MachineFunction.h" | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  | class NVPTXReplaceImageHandles : public MachineFunctionPass { | 
|  | private: | 
|  | static char ID; | 
|  | DenseSet<MachineInstr *> InstrsToRemove; | 
|  |  | 
|  | public: | 
|  | NVPTXReplaceImageHandles(); | 
|  |  | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | StringRef getPassName() const override { | 
|  | return "NVPTX Replace Image Handles"; | 
|  | } | 
|  | private: | 
|  | bool processInstr(MachineInstr &MI); | 
|  | void replaceImageHandle(MachineOperand &Op, MachineFunction &MF); | 
|  | bool findIndexForHandle(MachineOperand &Op, MachineFunction &MF, | 
|  | unsigned &Idx); | 
|  | }; | 
|  | } | 
|  |  | 
|  | char NVPTXReplaceImageHandles::ID = 0; | 
|  |  | 
|  | NVPTXReplaceImageHandles::NVPTXReplaceImageHandles() | 
|  | : MachineFunctionPass(ID) {} | 
|  |  | 
|  | bool NVPTXReplaceImageHandles::runOnMachineFunction(MachineFunction &MF) { | 
|  | bool Changed = false; | 
|  | InstrsToRemove.clear(); | 
|  |  | 
|  | for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); BI != BE; | 
|  | ++BI) { | 
|  | for (MachineBasicBlock::iterator I = (*BI).begin(), E = (*BI).end(); | 
|  | I != E; ++I) { | 
|  | MachineInstr &MI = *I; | 
|  | Changed |= processInstr(MI); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now clean up any handle-access instructions | 
|  | // This is needed in debug mode when code cleanup passes are not executed, | 
|  | // but we need the handle access to be eliminated because they are not | 
|  | // valid instructions when image handles are disabled. | 
|  | for (DenseSet<MachineInstr *>::iterator I = InstrsToRemove.begin(), | 
|  | E = InstrsToRemove.end(); I != E; ++I) { | 
|  | (*I)->eraseFromParent(); | 
|  | } | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | bool NVPTXReplaceImageHandles::processInstr(MachineInstr &MI) { | 
|  | MachineFunction &MF = *MI.getParent()->getParent(); | 
|  | const MCInstrDesc &MCID = MI.getDesc(); | 
|  |  | 
|  | if (MCID.TSFlags & NVPTXII::IsTexFlag) { | 
|  | // This is a texture fetch, so operand 4 is a texref and operand 5 is | 
|  | // a samplerref | 
|  | MachineOperand &TexHandle = MI.getOperand(4); | 
|  | replaceImageHandle(TexHandle, MF); | 
|  |  | 
|  | if (!(MCID.TSFlags & NVPTXII::IsTexModeUnifiedFlag)) { | 
|  | MachineOperand &SampHandle = MI.getOperand(5); | 
|  | replaceImageHandle(SampHandle, MF); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } else if (MCID.TSFlags & NVPTXII::IsSuldMask) { | 
|  | unsigned VecSize = | 
|  | 1 << (((MCID.TSFlags & NVPTXII::IsSuldMask) >> NVPTXII::IsSuldShift) - 1); | 
|  |  | 
|  | // For a surface load of vector size N, the Nth operand will be the surfref | 
|  | MachineOperand &SurfHandle = MI.getOperand(VecSize); | 
|  |  | 
|  | replaceImageHandle(SurfHandle, MF); | 
|  |  | 
|  | return true; | 
|  | } else if (MCID.TSFlags & NVPTXII::IsSustFlag) { | 
|  | // This is a surface store, so operand 0 is a surfref | 
|  | MachineOperand &SurfHandle = MI.getOperand(0); | 
|  |  | 
|  | replaceImageHandle(SurfHandle, MF); | 
|  |  | 
|  | return true; | 
|  | } else if (MCID.TSFlags & NVPTXII::IsSurfTexQueryFlag) { | 
|  | // This is a query, so operand 1 is a surfref/texref | 
|  | MachineOperand &Handle = MI.getOperand(1); | 
|  |  | 
|  | replaceImageHandle(Handle, MF); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void NVPTXReplaceImageHandles:: | 
|  | replaceImageHandle(MachineOperand &Op, MachineFunction &MF) { | 
|  | unsigned Idx; | 
|  | if (findIndexForHandle(Op, MF, Idx)) { | 
|  | Op.ChangeToImmediate(Idx); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool NVPTXReplaceImageHandles:: | 
|  | findIndexForHandle(MachineOperand &Op, MachineFunction &MF, unsigned &Idx) { | 
|  | const MachineRegisterInfo &MRI = MF.getRegInfo(); | 
|  | NVPTXMachineFunctionInfo *MFI = MF.getInfo<NVPTXMachineFunctionInfo>(); | 
|  |  | 
|  | assert(Op.isReg() && "Handle is not in a reg?"); | 
|  |  | 
|  | // Which instruction defines the handle? | 
|  | MachineInstr &TexHandleDef = *MRI.getVRegDef(Op.getReg()); | 
|  |  | 
|  | switch (TexHandleDef.getOpcode()) { | 
|  | case NVPTX::LD_i64_avar: { | 
|  | // The handle is a parameter value being loaded, replace with the | 
|  | // parameter symbol | 
|  | const NVPTXTargetMachine &TM = | 
|  | static_cast<const NVPTXTargetMachine &>(MF.getTarget()); | 
|  | if (TM.getDrvInterface() == NVPTX::CUDA) { | 
|  | // For CUDA, we preserve the param loads coming from function arguments | 
|  | return false; | 
|  | } | 
|  |  | 
|  | assert(TexHandleDef.getOperand(6).isSymbol() && "Load is not a symbol!"); | 
|  | StringRef Sym = TexHandleDef.getOperand(6).getSymbolName(); | 
|  | std::string ParamBaseName = MF.getName(); | 
|  | ParamBaseName += "_param_"; | 
|  | assert(Sym.startswith(ParamBaseName) && "Invalid symbol reference"); | 
|  | unsigned Param = atoi(Sym.data()+ParamBaseName.size()); | 
|  | std::string NewSym; | 
|  | raw_string_ostream NewSymStr(NewSym); | 
|  | NewSymStr << MF.getFunction()->getName() << "_param_" << Param; | 
|  |  | 
|  | InstrsToRemove.insert(&TexHandleDef); | 
|  | Idx = MFI->getImageHandleSymbolIndex(NewSymStr.str().c_str()); | 
|  | return true; | 
|  | } | 
|  | case NVPTX::texsurf_handles: { | 
|  | // The handle is a global variable, replace with the global variable name | 
|  | assert(TexHandleDef.getOperand(1).isGlobal() && "Load is not a global!"); | 
|  | const GlobalValue *GV = TexHandleDef.getOperand(1).getGlobal(); | 
|  | assert(GV->hasName() && "Global sampler must be named!"); | 
|  | InstrsToRemove.insert(&TexHandleDef); | 
|  | Idx = MFI->getImageHandleSymbolIndex(GV->getName().data()); | 
|  | return true; | 
|  | } | 
|  | case NVPTX::nvvm_move_i64: | 
|  | case TargetOpcode::COPY: { | 
|  | bool Res = findIndexForHandle(TexHandleDef.getOperand(1), MF, Idx); | 
|  | if (Res) { | 
|  | InstrsToRemove.insert(&TexHandleDef); | 
|  | } | 
|  | return Res; | 
|  | } | 
|  | default: | 
|  | llvm_unreachable("Unknown instruction operating on handle"); | 
|  | } | 
|  | } | 
|  |  | 
|  | MachineFunctionPass *llvm::createNVPTXReplaceImageHandlesPass() { | 
|  | return new NVPTXReplaceImageHandles(); | 
|  | } |