LLVM API Documentation

NVPTXReplaceImageHandles.cpp
Go to the documentation of this file.
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 }