MC: Make TargetAsmBackend available to the AsmStreamer.
[oota-llvm.git] / lib / Target / PTX / PTXAsmPrinter.cpp
1 //===-- PTXAsmPrinter.cpp - PTX 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 PTX assembly language.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #define DEBUG_TYPE "ptx-asm-printer"
16
17 #include "PTX.h"
18 #include "PTXMachineFunctionInfo.h"
19 #include "PTXTargetMachine.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/StringExtras.h"
23 #include "llvm/ADT/Twine.h"
24 #include "llvm/CodeGen/AsmPrinter.h"
25 #include "llvm/CodeGen/MachineInstr.h"
26 #include "llvm/MC/MCStreamer.h"
27 #include "llvm/MC/MCSymbol.h"
28 #include "llvm/Target/TargetLoweringObjectFile.h"
29 #include "llvm/Target/TargetRegistry.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Support/Debug.h"
32 #include "llvm/Support/ErrorHandling.h"
33 #include "llvm/Support/raw_ostream.h"
34
35 using namespace llvm;
36
37 static cl::opt<std::string>
38 OptPTXVersion("ptx-version", cl::desc("Set PTX version"),
39            cl::init("1.4"));
40
41 static cl::opt<std::string>
42 OptPTXTarget("ptx-target", cl::desc("Set GPU target (comma-separated list)"),
43            cl::init("sm_10"));
44
45 namespace {
46 class PTXAsmPrinter : public AsmPrinter {
47 public:
48   explicit PTXAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
49     : AsmPrinter(TM, Streamer) {}
50
51   const char *getPassName() const { return "PTX Assembly Printer"; }
52
53   virtual void EmitStartOfAsmFile(Module &M);
54
55   virtual bool runOnMachineFunction(MachineFunction &MF);
56
57   virtual void EmitFunctionBodyStart();
58   virtual void EmitFunctionBodyEnd() { OutStreamer.EmitRawText(Twine("}")); }
59
60   virtual void EmitInstruction(const MachineInstr *MI);
61
62   void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
63   void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,
64                        const char *Modifier = 0);
65
66   // autogen'd.
67   void printInstruction(const MachineInstr *MI, raw_ostream &OS);
68   static const char *getRegisterName(unsigned RegNo);
69
70 private:
71   void EmitFunctionDeclaration();
72 }; // class PTXAsmPrinter
73 } // namespace
74
75 static const char PARAM_PREFIX[] = "__param_";
76
77 static const char *getRegisterTypeName(unsigned RegNo) {
78 #define TEST_REGCLS(cls, clsstr) \
79   if (PTX::cls ## RegisterClass->contains(RegNo)) return # clsstr;
80   TEST_REGCLS(RRegs32, s32);
81   TEST_REGCLS(Preds, pred);
82 #undef TEST_REGCLS
83
84   llvm_unreachable("Not in any register class!");
85   return NULL;
86 }
87
88 static const char *getInstructionTypeName(const MachineInstr *MI) {
89   for (int i = 0, e = MI->getNumOperands(); i != e; ++i) {
90     const MachineOperand &MO = MI->getOperand(i);
91     if (MO.getType() == MachineOperand::MO_Register)
92       return getRegisterTypeName(MO.getReg());
93   }
94
95   llvm_unreachable("No reg operand found in instruction!");
96   return NULL;
97 }
98
99 void PTXAsmPrinter::EmitStartOfAsmFile(Module &M)
100 {
101   OutStreamer.EmitRawText(Twine("\t.version " + OptPTXVersion));
102   OutStreamer.EmitRawText(Twine("\t.target " + OptPTXTarget));
103   OutStreamer.AddBlankLine();
104 }
105
106 bool PTXAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
107   SetupMachineFunction(MF);
108   EmitFunctionDeclaration();
109   EmitFunctionBody();
110   return false;
111 }
112
113 void PTXAsmPrinter::EmitFunctionBodyStart() {
114   OutStreamer.EmitRawText(Twine("{"));
115
116   const PTXMachineFunctionInfo *MFI = MF->getInfo<PTXMachineFunctionInfo>();
117
118   // Print local variable definition
119   for (PTXMachineFunctionInfo::reg_iterator
120        i = MFI->localVarRegBegin(), e = MFI->localVarRegEnd(); i != e; ++ i) {
121     unsigned reg = *i;
122
123     std::string def = "\t.reg .";
124     def += getRegisterTypeName(reg);
125     def += ' ';
126     def += getRegisterName(reg);
127     def += ';';
128     OutStreamer.EmitRawText(Twine(def));
129   }
130 }
131
132 void PTXAsmPrinter::EmitInstruction(const MachineInstr *MI) {
133   std::string str;
134   str.reserve(64);
135
136   // Write instruction to str
137   raw_string_ostream OS(str);
138   printInstruction(MI, OS);
139   OS << ';';
140   OS.flush();
141
142   // Replace "%type" if found
143   size_t pos;
144   if ((pos = str.find("%type")) != std::string::npos)
145     str.replace(pos, /*strlen("%type")==*/5, getInstructionTypeName(MI));
146
147   StringRef strref = StringRef(str);
148   OutStreamer.EmitRawText(strref);
149 }
150
151 void PTXAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
152                                  raw_ostream &OS) {
153   const MachineOperand &MO = MI->getOperand(opNum);
154
155   switch (MO.getType()) {
156     default:
157       llvm_unreachable("<unknown operand type>");
158       break;
159     case MachineOperand::MO_Register:
160       OS << getRegisterName(MO.getReg());
161       break;
162     case MachineOperand::MO_Immediate:
163       OS << (int) MO.getImm();
164       break;
165   }
166 }
167
168 void PTXAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
169                                     raw_ostream &OS, const char *Modifier) {
170   printOperand(MI, opNum, OS);
171
172   if (MI->getOperand(opNum+1).isImm() && MI->getOperand(opNum+1).getImm() == 0)
173     return; // don't print "+0"
174
175   OS << "+";
176   printOperand(MI, opNum+1, OS);
177 }
178
179 void PTXAsmPrinter::EmitFunctionDeclaration() {
180   // The function label could have already been emitted if two symbols end up
181   // conflicting due to asm renaming.  Detect this and emit an error.
182   if (!CurrentFnSym->isUndefined()) {
183     report_fatal_error("'" + Twine(CurrentFnSym->getName()) +
184                        "' label emitted multiple times to assembly file");
185     return;
186   }
187
188   const PTXMachineFunctionInfo *MFI = MF->getInfo<PTXMachineFunctionInfo>();
189   const bool isKernel = MFI->isKernel();
190   unsigned reg;
191
192   std::string decl = isKernel ? ".entry" : ".func";
193
194   // Print return register
195   reg = MFI->retReg();
196   if (!isKernel && reg != PTX::NoRegister) {
197     decl += " (.reg ."; // FIXME: could it return in .param space?
198     decl += getRegisterTypeName(reg);
199     decl += " ";
200     decl += getRegisterName(reg);
201     decl += ")";
202   }
203
204   // Print function name
205   decl += " ";
206   decl += CurrentFnSym->getName().str();
207
208   // Print parameter list
209   if (!MFI->argRegEmpty()) {
210     decl += " (";
211     if (isKernel) {
212       for (int i = 0, e = MFI->getNumArg(); i != e; ++i) {
213         if (i != 0)
214           decl += ", ";
215         decl += ".param .s32 "; // TODO: param's type
216         decl += PARAM_PREFIX;
217         decl += utostr(i + 1);
218       }
219     } else {
220       for (PTXMachineFunctionInfo::reg_iterator
221            i = MFI->argRegBegin(), e = MFI->argRegEnd(), b = i; i != e; ++i) {
222         reg = *i;
223         assert(reg != PTX::NoRegister && "Not a valid register!");
224         if (i != b)
225           decl += ", ";
226         decl += ".reg .";
227         decl += getRegisterTypeName(reg);
228         decl += " ";
229         decl += getRegisterName(reg);
230       }
231     }
232     decl += ")";
233   }
234
235   OutStreamer.EmitRawText(Twine(decl));
236 }
237
238 #include "PTXGenAsmWriter.inc"
239
240 // Force static initialization.
241 extern "C" void LLVMInitializePTXAsmPrinter() {
242   RegisterAsmPrinter<PTXAsmPrinter> X(ThePTXTarget);
243 }