LLVM API Documentation

NVPTXAsmPrinter.h
Go to the documentation of this file.
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