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