LLVM API Documentation
00001 //===-- NVPTXAsmPrinter.h - NVPTX LLVM assembly writer --------------------===// 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 // This file contains a printer that converts from our internal representation 00011 // of machine-dependent LLVM code to NVPTX assembly language. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #ifndef LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H 00016 #define LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H 00017 00018 #include "NVPTX.h" 00019 #include "NVPTXSubtarget.h" 00020 #include "NVPTXTargetMachine.h" 00021 #include "llvm/ADT/SmallString.h" 00022 #include "llvm/ADT/StringExtras.h" 00023 #include "llvm/CodeGen/AsmPrinter.h" 00024 #include "llvm/IR/Function.h" 00025 #include "llvm/MC/MCAsmInfo.h" 00026 #include "llvm/MC/MCExpr.h" 00027 #include "llvm/MC/MCSymbol.h" 00028 #include "llvm/Support/CommandLine.h" 00029 #include "llvm/Support/FormattedStream.h" 00030 #include "llvm/Target/TargetMachine.h" 00031 #include <fstream> 00032 00033 // The ptx syntax and format is very different from that usually seem in a .s 00034 // file, 00035 // therefore we are not able to use the MCAsmStreamer interface here. 00036 // 00037 // We are handcrafting the output method here. 00038 // 00039 // A better approach is to clone the MCAsmStreamer to a MCPTXAsmStreamer 00040 // (subclass of MCStreamer). 00041 00042 // This is defined in AsmPrinter.cpp. 00043 // Used to process the constant expressions in initializers. 00044 namespace nvptx { 00045 const llvm::MCExpr * 00046 LowerConstant(const llvm::Constant *CV, llvm::AsmPrinter &AP); 00047 } 00048 00049 namespace llvm { 00050 00051 class LineReader { 00052 private: 00053 unsigned theCurLine; 00054 std::ifstream fstr; 00055 char buff[512]; 00056 std::string theFileName; 00057 SmallVector<unsigned, 32> lineOffset; 00058 public: 00059 LineReader(std::string filename) { 00060 theCurLine = 0; 00061 fstr.open(filename.c_str()); 00062 theFileName = filename; 00063 } 00064 std::string fileName() { return theFileName; } 00065 ~LineReader() { fstr.close(); } 00066 std::string readLine(unsigned line); 00067 }; 00068 00069 class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter { 00070 00071 class AggBuffer { 00072 // Used to buffer the emitted string for initializing global 00073 // aggregates. 00074 // 00075 // Normally an aggregate (array, vector or structure) is emitted 00076 // as a u8[]. However, if one element/field of the aggregate 00077 // is a non-NULL address, then the aggregate is emitted as u32[] 00078 // or u64[]. 00079 // 00080 // We first layout the aggregate in 'buffer' in bytes, except for 00081 // those symbol addresses. For the i-th symbol address in the 00082 //aggregate, its corresponding 4-byte or 8-byte elements in 'buffer' 00083 // are filled with 0s. symbolPosInBuffer[i-1] records its position 00084 // in 'buffer', and Symbols[i-1] records the Value*. 00085 // 00086 // Once we have this AggBuffer setup, we can choose how to print 00087 // it out. 00088 public: 00089 unsigned numSymbols; // number of symbol addresses 00090 00091 private: 00092 const unsigned size; // size of the buffer in bytes 00093 std::vector<unsigned char> buffer; // the buffer 00094 SmallVector<unsigned, 4> symbolPosInBuffer; 00095 SmallVector<const Value *, 4> Symbols; 00096 unsigned curpos; 00097 raw_ostream &O; 00098 NVPTXAsmPrinter &AP; 00099 bool EmitGeneric; 00100 00101 public: 00102 AggBuffer(unsigned _size, raw_ostream &_O, NVPTXAsmPrinter &_AP) 00103 : size(_size), buffer(_size), O(_O), AP(_AP) { 00104 curpos = 0; 00105 numSymbols = 0; 00106 EmitGeneric = AP.EmitGeneric; 00107 } 00108 unsigned addBytes(unsigned char *Ptr, int Num, int Bytes) { 00109 assert((curpos + Num) <= size); 00110 assert((curpos + Bytes) <= size); 00111 for (int i = 0; i < Num; ++i) { 00112 buffer[curpos] = Ptr[i]; 00113 curpos++; 00114 } 00115 for (int i = Num; i < Bytes; ++i) { 00116 buffer[curpos] = 0; 00117 curpos++; 00118 } 00119 return curpos; 00120 } 00121 unsigned addZeros(int Num) { 00122 assert((curpos + Num) <= size); 00123 for (int i = 0; i < Num; ++i) { 00124 buffer[curpos] = 0; 00125 curpos++; 00126 } 00127 return curpos; 00128 } 00129 void addSymbol(const Value *GVar) { 00130 symbolPosInBuffer.push_back(curpos); 00131 Symbols.push_back(GVar); 00132 numSymbols++; 00133 } 00134 void print() { 00135 if (numSymbols == 0) { 00136 // print out in bytes 00137 for (unsigned i = 0; i < size; i++) { 00138 if (i) 00139 O << ", "; 00140 O << (unsigned int) buffer[i]; 00141 } 00142 } else { 00143 // print out in 4-bytes or 8-bytes 00144 unsigned int pos = 0; 00145 unsigned int nSym = 0; 00146 unsigned int nextSymbolPos = symbolPosInBuffer[nSym]; 00147 unsigned int nBytes = 4; 00148 if (AP.nvptxSubtarget.is64Bit()) 00149 nBytes = 8; 00150 for (pos = 0; pos < size; pos += nBytes) { 00151 if (pos) 00152 O << ", "; 00153 if (pos == nextSymbolPos) { 00154 const Value *v = Symbols[nSym]; 00155 if (const GlobalValue *GVar = dyn_cast<GlobalValue>(v)) { 00156 MCSymbol *Name = AP.getSymbol(GVar); 00157 PointerType *PTy = dyn_cast<PointerType>(GVar->getType()); 00158 bool IsNonGenericPointer = false; 00159 if (PTy && PTy->getAddressSpace() != 0) { 00160 IsNonGenericPointer = true; 00161 } 00162 if (EmitGeneric && !isa<Function>(v) && !IsNonGenericPointer) { 00163 O << "generic("; 00164 O << *Name; 00165 O << ")"; 00166 } else { 00167 O << *Name; 00168 } 00169 } else if (const ConstantExpr *Cexpr = dyn_cast<ConstantExpr>(v)) { 00170 O << *nvptx::LowerConstant(Cexpr, AP); 00171 } else 00172 llvm_unreachable("symbol type unknown"); 00173 nSym++; 00174 if (nSym >= numSymbols) 00175 nextSymbolPos = size + 1; 00176 else 00177 nextSymbolPos = symbolPosInBuffer[nSym]; 00178 } else if (nBytes == 4) 00179 O << *(unsigned int *)(&buffer[pos]); 00180 else 00181 O << *(unsigned long long *)(&buffer[pos]); 00182 } 00183 } 00184 } 00185 }; 00186 00187 friend class AggBuffer; 00188 00189 void emitSrcInText(StringRef filename, unsigned line); 00190 00191 private: 00192 const char *getPassName() const override { return "NVPTX Assembly Printer"; } 00193 00194 const Function *F; 00195 std::string CurrentFnName; 00196 00197 void EmitFunctionEntryLabel() override; 00198 void EmitFunctionBodyStart() override; 00199 void EmitFunctionBodyEnd() override; 00200 void emitImplicitDef(const MachineInstr *MI) const override; 00201 00202 void EmitInstruction(const MachineInstr *) override; 00203 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI); 00204 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); 00205 MCOperand GetSymbolRef(const MCSymbol *Symbol); 00206 unsigned encodeVirtualRegister(unsigned Reg); 00207 00208 void EmitAlignment(unsigned NumBits, const GlobalValue *GV = nullptr) const {} 00209 00210 void printVecModifiedImmediate(const MachineOperand &MO, const char *Modifier, 00211 raw_ostream &O); 00212 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 00213 const char *Modifier = nullptr); 00214 void printImplicitDef(const MachineInstr *MI, raw_ostream &O) const; 00215 void printModuleLevelGV(const GlobalVariable *GVar, raw_ostream &O, 00216 bool = false); 00217 void printParamName(int paramIndex, raw_ostream &O); 00218 void printParamName(Function::const_arg_iterator I, int paramIndex, 00219 raw_ostream &O); 00220 void emitGlobals(const Module &M); 00221 void emitHeader(Module &M, raw_ostream &O); 00222 void emitKernelFunctionDirectives(const Function &F, raw_ostream &O) const; 00223 void emitVirtualRegister(unsigned int vr, raw_ostream &); 00224 void emitFunctionExternParamList(const MachineFunction &MF); 00225 void emitFunctionParamList(const Function *, raw_ostream &O); 00226 void emitFunctionParamList(const MachineFunction &MF, raw_ostream &O); 00227 void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF); 00228 void emitFunctionTempData(const MachineFunction &MF, unsigned &FrameSize); 00229 bool isImageType(const Type *Ty); 00230 void printReturnValStr(const Function *, raw_ostream &O); 00231 void printReturnValStr(const MachineFunction &MF, raw_ostream &O); 00232 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 00233 unsigned AsmVariant, const char *ExtraCode, 00234 raw_ostream &) override; 00235 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 00236 const char *Modifier = nullptr); 00237 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 00238 unsigned AsmVariant, const char *ExtraCode, 00239 raw_ostream &) override; 00240 protected: 00241 bool doInitialization(Module &M) override; 00242 bool doFinalization(Module &M) override; 00243 00244 private: 00245 std::string CurrentBankselLabelInBasicBlock; 00246 00247 bool GlobalsEmitted; 00248 00249 // This is specific per MachineFunction. 00250 const MachineRegisterInfo *MRI; 00251 // The contents are specific for each 00252 // MachineFunction. But the size of the 00253 // array is not. 00254 typedef DenseMap<unsigned, unsigned> VRegMap; 00255 typedef DenseMap<const TargetRegisterClass *, VRegMap> VRegRCMap; 00256 VRegRCMap VRegMapping; 00257 // cache the subtarget here. 00258 const NVPTXSubtarget &nvptxSubtarget; 00259 // Build the map between type name and ID based on module's type 00260 // symbol table. 00261 std::map<const Type *, std::string> TypeNameMap; 00262 00263 // List of variables demoted to a function scope. 00264 std::map<const Function *, std::vector<const GlobalVariable *> > localDecls; 00265 00266 // To record filename to ID mapping 00267 std::map<std::string, unsigned> filenameMap; 00268 void recordAndEmitFilenames(Module &); 00269 00270 void emitPTXGlobalVariable(const GlobalVariable *GVar, raw_ostream &O); 00271 void emitPTXAddressSpace(unsigned int AddressSpace, raw_ostream &O) const; 00272 std::string getPTXFundamentalTypeStr(const Type *Ty, bool = true) const; 00273 void printScalarConstant(const Constant *CPV, raw_ostream &O); 00274 void printFPConstant(const ConstantFP *Fp, raw_ostream &O); 00275 void bufferLEByte(const Constant *CPV, int Bytes, AggBuffer *aggBuffer); 00276 void bufferAggregateConstant(const Constant *CV, AggBuffer *aggBuffer); 00277 00278 void printOperandProper(const MachineOperand &MO); 00279 00280 void emitLinkageDirective(const GlobalValue *V, raw_ostream &O); 00281 void emitDeclarations(const Module &, raw_ostream &O); 00282 void emitDeclaration(const Function *, raw_ostream &O); 00283 00284 static const char *getRegisterName(unsigned RegNo); 00285 void emitDemotedVars(const Function *, raw_ostream &); 00286 00287 bool lowerImageHandleOperand(const MachineInstr *MI, unsigned OpNo, 00288 MCOperand &MCOp); 00289 void lowerImageHandleSymbol(unsigned Index, MCOperand &MCOp); 00290 00291 LineReader *reader; 00292 LineReader *getReader(std::string); 00293 00294 // Used to control the need to emit .generic() in the initializer of 00295 // module scope variables. 00296 // Although ptx supports the hybrid mode like the following, 00297 // .global .u32 a; 00298 // .global .u32 b; 00299 // .global .u32 addr[] = {a, generic(b)} 00300 // we have difficulty representing the difference in the NVVM IR. 00301 // 00302 // Since the address value should always be generic in CUDA C and always 00303 // be specific in OpenCL, we use this simple control here. 00304 // 00305 bool EmitGeneric; 00306 00307 public: 00308 NVPTXAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) 00309 : AsmPrinter(TM, Streamer), 00310 nvptxSubtarget(TM.getSubtarget<NVPTXSubtarget>()) { 00311 CurrentBankselLabelInBasicBlock = ""; 00312 reader = nullptr; 00313 EmitGeneric = (nvptxSubtarget.getDrvInterface() == NVPTX::CUDA); 00314 } 00315 00316 ~NVPTXAsmPrinter() { 00317 if (!reader) 00318 delete reader; 00319 } 00320 00321 bool ignoreLoc(const MachineInstr &); 00322 00323 std::string getVirtualRegisterName(unsigned) const; 00324 00325 DebugLoc prevDebugLoc; 00326 void emitLineNumberAsDotLoc(const MachineInstr &); 00327 }; 00328 } // end of namespace 00329 00330 #endif