1 //===-- NVPTXAsmPrinter.h - NVPTX LLVM assembly writer --------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains a printer that converts from our internal representation 11 // of machine-dependent LLVM code to NVPTX assembly language. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef NVPTXASMPRINTER_H 16 #define NVPTXASMPRINTER_H 17 18 #include "NVPTX.h" 19 #include "NVPTXSubtarget.h" 20 #include "NVPTXTargetMachine.h" 21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/ADT/StringExtras.h" 23 #include "llvm/CodeGen/AsmPrinter.h" 24 #include "llvm/IR/Function.h" 25 #include "llvm/MC/MCAsmInfo.h" 26 #include "llvm/MC/MCExpr.h" 27 #include "llvm/MC/MCSymbol.h" 28 #include "llvm/Support/CommandLine.h" 29 #include "llvm/Support/FormattedStream.h" 30 #include "llvm/Target/TargetMachine.h" 31 #include <fstream> 32 33 // The ptx syntax and format is very different from that usually seem in a .s 34 // file, 35 // therefore we are not able to use the MCAsmStreamer interface here. 36 // 37 // We are handcrafting the output method here. 38 // 39 // A better approach is to clone the MCAsmStreamer to a MCPTXAsmStreamer 40 // (subclass of MCStreamer). 41 42 // This is defined in AsmPrinter.cpp. 43 // Used to process the constant expressions in initializers. 44 namespace nvptx { 45 const llvm::MCExpr * 46 LowerConstant(const llvm::Constant *CV, llvm::AsmPrinter &AP); 47 } 48 49 namespace llvm { 50 51 class LineReader { 52 private: 53 unsigned theCurLine; 54 std::ifstream fstr; 55 char buff[512]; 56 std::string theFileName; 57 SmallVector<unsigned, 32> lineOffset; 58 public: 59 LineReader(std::string filename) { 60 theCurLine = 0; 61 fstr.open(filename.c_str()); 62 theFileName = filename; 63 } 64 std::string fileName() { return theFileName; } 65 ~LineReader() { fstr.close(); } 66 std::string readLine(unsigned line); 67 }; 68 69 class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter { 70 71 class AggBuffer { 72 // Used to buffer the emitted string for initializing global 73 // aggregates. 74 // 75 // Normally an aggregate (array, vector or structure) is emitted 76 // as a u8[]. However, if one element/field of the aggregate 77 // is a non-NULL address, then the aggregate is emitted as u32[] 78 // or u64[]. 79 // 80 // We first layout the aggregate in 'buffer' in bytes, except for 81 // those symbol addresses. For the i-th symbol address in the 82 //aggregate, its corresponding 4-byte or 8-byte elements in 'buffer' 83 // are filled with 0s. symbolPosInBuffer[i-1] records its position 84 // in 'buffer', and Symbols[i-1] records the Value*. 85 // 86 // Once we have this AggBuffer setup, we can choose how to print 87 // it out. 88 public: 89 unsigned size; // size of the buffer in bytes 90 unsigned char *buffer; // the buffer 91 unsigned numSymbols; // number of symbol addresses 92 SmallVector<unsigned, 4> symbolPosInBuffer; 93 SmallVector<const Value *, 4> Symbols; 94 95 private: 96 unsigned curpos; 97 raw_ostream &O; 98 NVPTXAsmPrinter &AP; 99 bool EmitGeneric; 100 101 public: 102 AggBuffer(unsigned _size, raw_ostream &_O, NVPTXAsmPrinter &_AP) 103 : O(_O), AP(_AP) { 104 buffer = new unsigned char[_size]; 105 size = _size; 106 curpos = 0; 107 numSymbols = 0; 108 EmitGeneric = AP.EmitGeneric; 109 } 110 ~AggBuffer() { delete[] buffer; } 111 unsigned addBytes(unsigned char *Ptr, int Num, int Bytes) { 112 assert((curpos + Num) <= size); 113 assert((curpos + Bytes) <= size); 114 for (int i = 0; i < Num; ++i) { 115 buffer[curpos] = Ptr[i]; 116 curpos++; 117 } 118 for (int i = Num; i < Bytes; ++i) { 119 buffer[curpos] = 0; 120 curpos++; 121 } 122 return curpos; 123 } 124 unsigned addZeros(int Num) { 125 assert((curpos + Num) <= size); 126 for (int i = 0; i < Num; ++i) { 127 buffer[curpos] = 0; 128 curpos++; 129 } 130 return curpos; 131 } 132 void addSymbol(const Value *GVar) { 133 symbolPosInBuffer.push_back(curpos); 134 Symbols.push_back(GVar); 135 numSymbols++; 136 } 137 void print() { 138 if (numSymbols == 0) { 139 // print out in bytes 140 for (unsigned i = 0; i < size; i++) { 141 if (i) 142 O << ", "; 143 O << (unsigned int) buffer[i]; 144 } 145 } else { 146 // print out in 4-bytes or 8-bytes 147 unsigned int pos = 0; 148 unsigned int nSym = 0; 149 unsigned int nextSymbolPos = symbolPosInBuffer[nSym]; 150 unsigned int nBytes = 4; 151 if (AP.nvptxSubtarget.is64Bit()) 152 nBytes = 8; 153 for (pos = 0; pos < size; pos += nBytes) { 154 if (pos) 155 O << ", "; 156 if (pos == nextSymbolPos) { 157 const Value *v = Symbols[nSym]; 158 if (const GlobalValue *GVar = dyn_cast<GlobalValue>(v)) { 159 MCSymbol *Name = AP.getSymbol(GVar); 160 PointerType *PTy = dyn_cast<PointerType>(GVar->getType()); 161 bool IsNonGenericPointer = false; 162 if (PTy && PTy->getAddressSpace() != 0) { 163 IsNonGenericPointer = true; 164 } 165 if (EmitGeneric && !isa<Function>(v) && !IsNonGenericPointer) { 166 O << "generic("; 167 O << *Name; 168 O << ")"; 169 } else { 170 O << *Name; 171 } 172 } else if (const ConstantExpr *Cexpr = dyn_cast<ConstantExpr>(v)) { 173 O << *nvptx::LowerConstant(Cexpr, AP); 174 } else 175 llvm_unreachable("symbol type unknown"); 176 nSym++; 177 if (nSym >= numSymbols) 178 nextSymbolPos = size + 1; 179 else 180 nextSymbolPos = symbolPosInBuffer[nSym]; 181 } else if (nBytes == 4) 182 O << *(unsigned int *)(buffer + pos); 183 else 184 O << *(unsigned long long *)(buffer + pos); 185 } 186 } 187 } 188 }; 189 190 friend class AggBuffer; 191 192 void emitSrcInText(StringRef filename, unsigned line); 193 194 private: 195 const char *getPassName() const override { return "NVPTX Assembly Printer"; } 196 197 const Function *F; 198 std::string CurrentFnName; 199 200 void EmitFunctionEntryLabel() override; 201 void EmitFunctionBodyStart() override; 202 void EmitFunctionBodyEnd() override; 203 void emitImplicitDef(const MachineInstr *MI) const override; 204 205 void EmitInstruction(const MachineInstr *) override; 206 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI); 207 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); 208 MCOperand GetSymbolRef(const MCSymbol *Symbol); 209 unsigned encodeVirtualRegister(unsigned Reg); 210 211 void EmitAlignment(unsigned NumBits, const GlobalValue *GV = nullptr) const {} 212 213 void printVecModifiedImmediate(const MachineOperand &MO, const char *Modifier, 214 raw_ostream &O); 215 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 216 const char *Modifier = nullptr); 217 void printImplicitDef(const MachineInstr *MI, raw_ostream &O) const; 218 void printModuleLevelGV(const GlobalVariable *GVar, raw_ostream &O, 219 bool = false); 220 void printParamName(int paramIndex, raw_ostream &O); 221 void printParamName(Function::const_arg_iterator I, int paramIndex, 222 raw_ostream &O); 223 void emitGlobals(const Module &M); 224 void emitHeader(Module &M, raw_ostream &O); 225 void emitKernelFunctionDirectives(const Function &F, raw_ostream &O) const; 226 void emitVirtualRegister(unsigned int vr, raw_ostream &); 227 void emitFunctionExternParamList(const MachineFunction &MF); 228 void emitFunctionParamList(const Function *, raw_ostream &O); 229 void emitFunctionParamList(const MachineFunction &MF, raw_ostream &O); 230 void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF); 231 void emitFunctionTempData(const MachineFunction &MF, unsigned &FrameSize); 232 bool isImageType(const Type *Ty); 233 void printReturnValStr(const Function *, raw_ostream &O); 234 void printReturnValStr(const MachineFunction &MF, raw_ostream &O); 235 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 236 unsigned AsmVariant, const char *ExtraCode, 237 raw_ostream &) override; 238 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 239 const char *Modifier = nullptr); 240 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 241 unsigned AsmVariant, const char *ExtraCode, 242 raw_ostream &) override; 243 protected: 244 bool doInitialization(Module &M) override; 245 bool doFinalization(Module &M) override; 246 247 private: 248 std::string CurrentBankselLabelInBasicBlock; 249 250 bool GlobalsEmitted; 251 252 // This is specific per MachineFunction. 253 const MachineRegisterInfo *MRI; 254 // The contents are specific for each 255 // MachineFunction. But the size of the 256 // array is not. 257 typedef DenseMap<unsigned, unsigned> VRegMap; 258 typedef DenseMap<const TargetRegisterClass *, VRegMap> VRegRCMap; 259 VRegRCMap VRegMapping; 260 // cache the subtarget here. 261 const NVPTXSubtarget &nvptxSubtarget; 262 // Build the map between type name and ID based on module's type 263 // symbol table. 264 std::map<const Type *, std::string> TypeNameMap; 265 266 // List of variables demoted to a function scope. 267 std::map<const Function *, std::vector<const GlobalVariable *> > localDecls; 268 269 // To record filename to ID mapping 270 std::map<std::string, unsigned> filenameMap; 271 void recordAndEmitFilenames(Module &); 272 273 void emitPTXGlobalVariable(const GlobalVariable *GVar, raw_ostream &O); 274 void emitPTXAddressSpace(unsigned int AddressSpace, raw_ostream &O) const; 275 std::string getPTXFundamentalTypeStr(const Type *Ty, bool = true) const; 276 void printScalarConstant(const Constant *CPV, raw_ostream &O); 277 void printFPConstant(const ConstantFP *Fp, raw_ostream &O); 278 void bufferLEByte(const Constant *CPV, int Bytes, AggBuffer *aggBuffer); 279 void bufferAggregateConstant(const Constant *CV, AggBuffer *aggBuffer); 280 281 void printOperandProper(const MachineOperand &MO); 282 283 void emitLinkageDirective(const GlobalValue *V, raw_ostream &O); 284 void emitDeclarations(const Module &, raw_ostream &O); 285 void emitDeclaration(const Function *, raw_ostream &O); 286 287 static const char *getRegisterName(unsigned RegNo); 288 void emitDemotedVars(const Function *, raw_ostream &); 289 290 bool lowerImageHandleOperand(const MachineInstr *MI, unsigned OpNo, 291 MCOperand &MCOp); 292 void lowerImageHandleSymbol(unsigned Index, MCOperand &MCOp); 293 294 LineReader *reader; 295 LineReader *getReader(std::string); 296 297 // Used to control the need to emit .generic() in the initializer of 298 // module scope variables. 299 // Although ptx supports the hybrid mode like the following, 300 // .global .u32 a; 301 // .global .u32 b; 302 // .global .u32 addr[] = {a, generic(b)} 303 // we have difficulty representing the difference in the NVVM IR. 304 // 305 // Since the address value should always be generic in CUDA C and always 306 // be specific in OpenCL, we use this simple control here. 307 // 308 bool EmitGeneric; 309 310 public: 311 NVPTXAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) 312 : AsmPrinter(TM, Streamer), 313 nvptxSubtarget(TM.getSubtarget<NVPTXSubtarget>()) { 314 CurrentBankselLabelInBasicBlock = ""; 315 reader = nullptr; 316 EmitGeneric = (nvptxSubtarget.getDrvInterface() == NVPTX::CUDA); 317 } 318 319 ~NVPTXAsmPrinter() { 320 if (!reader) 321 delete reader; 322 } 323 324 bool ignoreLoc(const MachineInstr &); 325 326 std::string getVirtualRegisterName(unsigned) const; 327 328 DebugLoc prevDebugLoc; 329 void emitLineNumberAsDotLoc(const MachineInstr &); 330 }; 331 } // end of namespace 332 333 #endif 334