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 LLVM_LIB_TARGET_NVPTX_NVPTXASMPRINTER_H 16 #define LLVM_LIB_TARGET_NVPTX_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 namespace llvm { 43 class MCOperand; 44 45 class LineReader { 46 private: 47 unsigned theCurLine; 48 std::ifstream fstr; 49 char buff[512]; 50 std::string theFileName; 51 SmallVector<unsigned, 32> lineOffset; 52 public: 53 LineReader(std::string filename) { 54 theCurLine = 0; 55 fstr.open(filename.c_str()); 56 theFileName = filename; 57 } 58 std::string fileName() { return theFileName; } 59 ~LineReader() { fstr.close(); } 60 std::string readLine(unsigned line); 61 }; 62 63 class LLVM_LIBRARY_VISIBILITY NVPTXAsmPrinter : public AsmPrinter { 64 65 class AggBuffer { 66 // Used to buffer the emitted string for initializing global 67 // aggregates. 68 // 69 // Normally an aggregate (array, vector or structure) is emitted 70 // as a u8[]. However, if one element/field of the aggregate 71 // is a non-NULL address, then the aggregate is emitted as u32[] 72 // or u64[]. 73 // 74 // We first layout the aggregate in 'buffer' in bytes, except for 75 // those symbol addresses. For the i-th symbol address in the 76 //aggregate, its corresponding 4-byte or 8-byte elements in 'buffer' 77 // are filled with 0s. symbolPosInBuffer[i-1] records its position 78 // in 'buffer', and Symbols[i-1] records the Value*. 79 // 80 // Once we have this AggBuffer setup, we can choose how to print 81 // it out. 82 public: 83 unsigned numSymbols; // number of symbol addresses 84 85 private: 86 const unsigned size; // size of the buffer in bytes 87 std::vector<unsigned char> buffer; // the buffer 88 SmallVector<unsigned, 4> symbolPosInBuffer; 89 SmallVector<const Value *, 4> Symbols; 90 // SymbolsBeforeStripping[i] is the original form of Symbols[i] before 91 // stripping pointer casts, i.e., 92 // Symbols[i] == SymbolsBeforeStripping[i]->stripPointerCasts(). 93 // 94 // We need to keep these values because AggBuffer::print decides whether to 95 // emit a "generic()" cast for Symbols[i] depending on the address space of 96 // SymbolsBeforeStripping[i]. 97 SmallVector<const Value *, 4> SymbolsBeforeStripping; 98 unsigned curpos; 99 raw_ostream &O; 100 NVPTXAsmPrinter &AP; 101 bool EmitGeneric; 102 103 public: 104 AggBuffer(unsigned size, raw_ostream &O, NVPTXAsmPrinter &AP) 105 : size(size), buffer(size), O(O), AP(AP) { 106 curpos = 0; 107 numSymbols = 0; 108 EmitGeneric = AP.EmitGeneric; 109 } 110 unsigned addBytes(unsigned char *Ptr, int Num, int Bytes) { 111 assert((curpos + Num) <= size); 112 assert((curpos + Bytes) <= size); 113 for (int i = 0; i < Num; ++i) { 114 buffer[curpos] = Ptr[i]; 115 curpos++; 116 } 117 for (int i = Num; i < Bytes; ++i) { 118 buffer[curpos] = 0; 119 curpos++; 120 } 121 return curpos; 122 } 123 unsigned addZeros(int Num) { 124 assert((curpos + Num) <= size); 125 for (int i = 0; i < Num; ++i) { 126 buffer[curpos] = 0; 127 curpos++; 128 } 129 return curpos; 130 } 131 void addSymbol(const Value *GVar, const Value *GVarBeforeStripping) { 132 symbolPosInBuffer.push_back(curpos); 133 Symbols.push_back(GVar); 134 SymbolsBeforeStripping.push_back(GVarBeforeStripping); 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 (static_cast<const NVPTXTargetMachine &>(AP.TM).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 const Value *v0 = SymbolsBeforeStripping[nSym]; 159 if (const GlobalValue *GVar = dyn_cast<GlobalValue>(v)) { 160 MCSymbol *Name = AP.getSymbol(GVar); 161 PointerType *PTy = dyn_cast<PointerType>(v0->getType()); 162 bool IsNonGenericPointer = false; // Is v0 a non-generic pointer? 163 if (PTy && PTy->getAddressSpace() != 0) { 164 IsNonGenericPointer = true; 165 } 166 if (EmitGeneric && !isa<Function>(v) && !IsNonGenericPointer) { 167 O << "generic("; 168 Name->print(O, AP.MAI); 169 O << ")"; 170 } else { 171 Name->print(O, AP.MAI); 172 } 173 } else if (const ConstantExpr *CExpr = dyn_cast<ConstantExpr>(v0)) { 174 const MCExpr *Expr = 175 AP.lowerConstantForGV(cast<Constant>(CExpr), false); 176 AP.printMCExpr(*Expr, O); 177 } else 178 llvm_unreachable("symbol type unknown"); 179 nSym++; 180 if (nSym >= numSymbols) 181 nextSymbolPos = size + 1; 182 else 183 nextSymbolPos = symbolPosInBuffer[nSym]; 184 } else if (nBytes == 4) 185 O << *(unsigned int *)(&buffer[pos]); 186 else 187 O << *(unsigned long long *)(&buffer[pos]); 188 } 189 } 190 } 191 }; 192 193 friend class AggBuffer; 194 195 void emitSrcInText(StringRef filename, unsigned line); 196 197 private: 198 const char *getPassName() const override { return "NVPTX Assembly Printer"; } 199 200 const Function *F; 201 std::string CurrentFnName; 202 203 void EmitBasicBlockStart(const MachineBasicBlock &MBB) const override; 204 void EmitFunctionEntryLabel() override; 205 void EmitFunctionBodyStart() override; 206 void EmitFunctionBodyEnd() override; 207 void emitImplicitDef(const MachineInstr *MI) const override; 208 209 void EmitInstruction(const MachineInstr *) override; 210 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI); 211 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); 212 MCOperand GetSymbolRef(const MCSymbol *Symbol); 213 unsigned encodeVirtualRegister(unsigned Reg); 214 215 void printVecModifiedImmediate(const MachineOperand &MO, const char *Modifier, 216 raw_ostream &O); 217 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 218 const char *Modifier = nullptr); 219 void printModuleLevelGV(const GlobalVariable *GVar, raw_ostream &O, 220 bool = false); 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, const NVPTXSubtarget &STI); 225 void emitKernelFunctionDirectives(const Function &F, raw_ostream &O) const; 226 void emitVirtualRegister(unsigned int vr, raw_ostream &); 227 void emitFunctionParamList(const Function *, raw_ostream &O); 228 void emitFunctionParamList(const MachineFunction &MF, raw_ostream &O); 229 void setAndEmitFunctionVirtualRegisters(const MachineFunction &MF); 230 void printReturnValStr(const Function *, raw_ostream &O); 231 void printReturnValStr(const MachineFunction &MF, raw_ostream &O); 232 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 233 unsigned AsmVariant, const char *ExtraCode, 234 raw_ostream &) override; 235 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 236 const char *Modifier = nullptr); 237 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 238 unsigned AsmVariant, const char *ExtraCode, 239 raw_ostream &) override; 240 241 const MCExpr *lowerConstantForGV(const Constant *CV, bool ProcessingGeneric); 242 void printMCExpr(const MCExpr &Expr, raw_ostream &OS); 243 244 protected: 245 bool doInitialization(Module &M) override; 246 bool doFinalization(Module &M) override; 247 248 private: 249 std::string CurrentBankselLabelInBasicBlock; 250 251 bool GlobalsEmitted; 252 253 // This is specific per MachineFunction. 254 const MachineRegisterInfo *MRI; 255 // The contents are specific for each 256 // MachineFunction. But the size of the 257 // array is not. 258 typedef DenseMap<unsigned, unsigned> VRegMap; 259 typedef DenseMap<const TargetRegisterClass *, VRegMap> VRegRCMap; 260 VRegRCMap VRegMapping; 261 262 // Cache the subtarget here. 263 const NVPTXSubtarget *nvptxSubtarget; 264 265 // Build the map between type name and ID based on module's type 266 // symbol table. 267 std::map<Type *, std::string> TypeNameMap; 268 269 // List of variables demoted to a function scope. 270 std::map<const Function *, std::vector<const GlobalVariable *> > localDecls; 271 272 // To record filename to ID mapping 273 std::map<std::string, unsigned> filenameMap; 274 void recordAndEmitFilenames(Module &); 275 276 void emitPTXGlobalVariable(const GlobalVariable *GVar, raw_ostream &O); 277 void emitPTXAddressSpace(unsigned int AddressSpace, raw_ostream &O) const; 278 std::string getPTXFundamentalTypeStr(Type *Ty, bool = true) const; 279 void printScalarConstant(const Constant *CPV, raw_ostream &O); 280 void printFPConstant(const ConstantFP *Fp, raw_ostream &O); 281 void bufferLEByte(const Constant *CPV, int Bytes, AggBuffer *aggBuffer); 282 void bufferAggregateConstant(const Constant *CV, AggBuffer *aggBuffer); 283 284 void emitLinkageDirective(const GlobalValue *V, raw_ostream &O); 285 void emitDeclarations(const Module &, raw_ostream &O); 286 void emitDeclaration(const Function *, raw_ostream &O); 287 void emitDemotedVars(const Function *, raw_ostream &); 288 289 bool lowerImageHandleOperand(const MachineInstr *MI, unsigned OpNo, 290 MCOperand &MCOp); 291 void lowerImageHandleSymbol(unsigned Index, MCOperand &MCOp); 292 293 bool isLoopHeaderOfNoUnroll(const MachineBasicBlock &MBB) const; 294 295 LineReader *reader; 296 LineReader *getReader(std::string); 297 298 // Used to control the need to emit .generic() in the initializer of 299 // module scope variables. 300 // Although ptx supports the hybrid mode like the following, 301 // .global .u32 a; 302 // .global .u32 b; 303 // .global .u32 addr[] = {a, generic(b)} 304 // we have difficulty representing the difference in the NVVM IR. 305 // 306 // Since the address value should always be generic in CUDA C and always 307 // be specific in OpenCL, we use this simple control here. 308 // 309 bool EmitGeneric; 310 311 public: 312 NVPTXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 313 : AsmPrinter(TM, std::move(Streamer)), 314 EmitGeneric(static_cast<NVPTXTargetMachine &>(TM).getDrvInterface() == 315 NVPTX::CUDA) { 316 CurrentBankselLabelInBasicBlock = ""; 317 reader = nullptr; 318 } 319 320 ~NVPTXAsmPrinter() { 321 if (!reader) 322 delete reader; 323 } 324 325 bool runOnMachineFunction(MachineFunction &F) override { 326 nvptxSubtarget = &F.getSubtarget<NVPTXSubtarget>(); 327 return AsmPrinter::runOnMachineFunction(F); 328 } 329 void getAnalysisUsage(AnalysisUsage &AU) const override { 330 AU.addRequired<MachineLoopInfo>(); 331 AsmPrinter::getAnalysisUsage(AU); 332 } 333 334 bool ignoreLoc(const MachineInstr &); 335 336 std::string getVirtualRegisterName(unsigned) const; 337 338 DebugLoc prevDebugLoc; 339 void emitLineNumberAsDotLoc(const MachineInstr &); 340 }; 341 } // end of namespace 342 343 #endif 344