• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
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 Cell SPU assembly language. This printer
12 // is the output mechanism used by `llc'.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #define DEBUG_TYPE "asmprinter"
17 #include "SPU.h"
18 #include "SPUTargetMachine.h"
19 #include "llvm/Constants.h"
20 #include "llvm/DerivedTypes.h"
21 #include "llvm/Module.h"
22 #include "llvm/CodeGen/AsmPrinter.h"
23 #include "llvm/CodeGen/MachineModuleInfo.h"
24 #include "llvm/MC/MCStreamer.h"
25 #include "llvm/MC/MCAsmInfo.h"
26 #include "llvm/MC/MCSymbol.h"
27 #include "llvm/Target/Mangler.h"
28 #include "llvm/Target/TargetLoweringObjectFile.h"
29 #include "llvm/Target/TargetInstrInfo.h"
30 #include "llvm/Target/TargetOptions.h"
31 #include "llvm/Target/TargetRegisterInfo.h"
32 #include "llvm/ADT/SmallString.h"
33 #include "llvm/ADT/StringExtras.h"
34 #include "llvm/Support/ErrorHandling.h"
35 #include "llvm/Support/TargetRegistry.h"
36 #include "llvm/Support/raw_ostream.h"
37 using namespace llvm;
38 
39 namespace {
40   class SPUAsmPrinter : public AsmPrinter {
41   public:
SPUAsmPrinter(TargetMachine & TM,MCStreamer & Streamer)42     explicit SPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) :
43       AsmPrinter(TM, Streamer) {}
44 
getPassName() const45     virtual const char *getPassName() const {
46       return "STI CBEA SPU Assembly Printer";
47     }
48 
49     /// printInstruction - This method is automatically generated by tablegen
50     /// from the instruction set description.
51     void printInstruction(const MachineInstr *MI, raw_ostream &OS);
52     static const char *getRegisterName(unsigned RegNo);
53 
54 
EmitInstruction(const MachineInstr * MI)55     void EmitInstruction(const MachineInstr *MI) {
56       SmallString<128> Str;
57       raw_svector_ostream OS(Str);
58       printInstruction(MI, OS);
59       OutStreamer.EmitRawText(OS.str());
60     }
61     void printOp(const MachineOperand &MO, raw_ostream &OS);
62 
printOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)63     void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
64       const MachineOperand &MO = MI->getOperand(OpNo);
65       if (MO.isReg()) {
66         O << getRegisterName(MO.getReg());
67       } else if (MO.isImm()) {
68         O << MO.getImm();
69       } else {
70         printOp(MO, O);
71       }
72     }
73 
74     bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
75                          unsigned AsmVariant, const char *ExtraCode,
76                          raw_ostream &O);
77     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
78                                unsigned AsmVariant, const char *ExtraCode,
79                                raw_ostream &O);
80 
81 
82     void
printU7ImmOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)83     printU7ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
84     {
85       unsigned int value = MI->getOperand(OpNo).getImm();
86       assert(value < (1 << 8) && "Invalid u7 argument");
87       O << value;
88     }
89 
90     void
printShufAddr(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)91     printShufAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
92     {
93       char value = MI->getOperand(OpNo).getImm();
94       O << (int) value;
95       O << "(";
96       printOperand(MI, OpNo+1, O);
97       O << ")";
98     }
99 
100     void
printS16ImmOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)101     printS16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
102     {
103       O << (short) MI->getOperand(OpNo).getImm();
104     }
105 
106     void
printU16ImmOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)107     printU16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
108     {
109       O << (unsigned short)MI->getOperand(OpNo).getImm();
110     }
111 
112     void
printMemRegReg(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)113     printMemRegReg(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
114       // When used as the base register, r0 reads constant zero rather than
115       // the value contained in the register.  For this reason, the darwin
116       // assembler requires that we print r0 as 0 (no r) when used as the base.
117       const MachineOperand &MO = MI->getOperand(OpNo);
118       O << getRegisterName(MO.getReg()) << ", ";
119       printOperand(MI, OpNo+1, O);
120     }
121 
122     void
printU18ImmOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)123     printU18ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
124     {
125       unsigned int value = MI->getOperand(OpNo).getImm();
126       assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
127       O << value;
128     }
129 
130     void
printS10ImmOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)131     printS10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
132     {
133       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
134                              >> 16);
135       assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
136              && "Invalid s10 argument");
137       O << value;
138     }
139 
140     void
printU10ImmOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)141     printU10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
142     {
143       short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
144                              >> 16);
145       assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
146       O << value;
147     }
148 
149     void
printDFormAddr(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)150     printDFormAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
151     {
152       assert(MI->getOperand(OpNo).isImm() &&
153              "printDFormAddr first operand is not immediate");
154       int64_t value = int64_t(MI->getOperand(OpNo).getImm());
155       int16_t value16 = int16_t(value);
156       assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
157              && "Invalid dform s10 offset argument");
158       O << (value16 & ~0xf) << "(";
159       printOperand(MI, OpNo+1, O);
160       O << ")";
161     }
162 
163     void
printAddr256K(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)164     printAddr256K(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
165     {
166       /* Note: operand 1 is an offset or symbol name. */
167       if (MI->getOperand(OpNo).isImm()) {
168         printS16ImmOperand(MI, OpNo, O);
169       } else {
170         printOp(MI->getOperand(OpNo), O);
171         if (MI->getOperand(OpNo+1).isImm()) {
172           int displ = int(MI->getOperand(OpNo+1).getImm());
173           if (displ > 0)
174             O << "+" << displ;
175           else if (displ < 0)
176             O << displ;
177         }
178       }
179     }
180 
printCallOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)181     void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
182       printOp(MI->getOperand(OpNo), O);
183     }
184 
printHBROperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)185     void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
186       printOp(MI->getOperand(OpNo), O);
187     }
188 
printPCRelativeOperand(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)189     void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
190       // Used to generate a ".-<target>", but it turns out that the assembler
191       // really wants the target.
192       //
193       // N.B.: This operand is used for call targets. Branch hints are another
194       // animal entirely.
195       printOp(MI->getOperand(OpNo), O);
196     }
197 
printSymbolHi(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)198     void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
199       if (MI->getOperand(OpNo).isImm()) {
200         printS16ImmOperand(MI, OpNo, O);
201       } else {
202         printOp(MI->getOperand(OpNo), O);
203         O << "@h";
204       }
205     }
206 
printSymbolLo(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)207     void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
208       if (MI->getOperand(OpNo).isImm()) {
209         printS16ImmOperand(MI, OpNo, O);
210       } else {
211         printOp(MI->getOperand(OpNo), O);
212         O << "@l";
213       }
214     }
215 
216     /// Print local store address
printSymbolLSA(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)217     void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
218       printOp(MI->getOperand(OpNo), O);
219     }
220 
printROTHNeg7Imm(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)221     void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo,
222                           raw_ostream &O) {
223       if (MI->getOperand(OpNo).isImm()) {
224         int value = (int) MI->getOperand(OpNo).getImm();
225         assert((value >= 0 && value < 16)
226                && "Invalid negated immediate rotate 7-bit argument");
227         O << -value;
228       } else {
229         llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
230       }
231     }
232 
printROTNeg7Imm(const MachineInstr * MI,unsigned OpNo,raw_ostream & O)233     void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O){
234       assert(MI->getOperand(OpNo).isImm() &&
235              "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
236       int value = (int) MI->getOperand(OpNo).getImm();
237       assert((value >= 0 && value <= 32)
238              && "Invalid negated immediate rotate 7-bit argument");
239       O << -value;
240     }
241   };
242 } // end of anonymous namespace
243 
244 // Include the auto-generated portion of the assembly writer
245 #include "SPUGenAsmWriter.inc"
246 
printOp(const MachineOperand & MO,raw_ostream & O)247 void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
248   switch (MO.getType()) {
249   case MachineOperand::MO_Immediate:
250     report_fatal_error("printOp() does not handle immediate values");
251     return;
252 
253   case MachineOperand::MO_MachineBasicBlock:
254     O << *MO.getMBB()->getSymbol();
255     return;
256   case MachineOperand::MO_JumpTableIndex:
257     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
258       << '_' << MO.getIndex();
259     return;
260   case MachineOperand::MO_ConstantPoolIndex:
261     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
262       << '_' << MO.getIndex();
263     return;
264   case MachineOperand::MO_ExternalSymbol:
265     // Computing the address of an external symbol, not calling it.
266     if (TM.getRelocationModel() != Reloc::Static) {
267       O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName()
268         << "$non_lazy_ptr";
269       return;
270     }
271     O << *GetExternalSymbolSymbol(MO.getSymbolName());
272     return;
273   case MachineOperand::MO_GlobalAddress:
274     // External or weakly linked global variables need non-lazily-resolved
275     // stubs
276     if (TM.getRelocationModel() != Reloc::Static) {
277       const GlobalValue *GV = MO.getGlobal();
278       if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
279             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
280         O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
281         return;
282       }
283     }
284     O << *Mang->getSymbol(MO.getGlobal());
285     return;
286   case MachineOperand::MO_MCSymbol:
287     O << *(MO.getMCSymbol());
288     return;
289   default:
290     O << "<unknown operand type: " << MO.getType() << ">";
291     return;
292   }
293 }
294 
295 /// PrintAsmOperand - Print out an operand for an inline asm expression.
296 ///
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,unsigned AsmVariant,const char * ExtraCode,raw_ostream & O)297 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
298                                     unsigned AsmVariant,
299                                     const char *ExtraCode, raw_ostream &O) {
300   // Does this asm operand have a single letter operand modifier?
301   if (ExtraCode && ExtraCode[0]) {
302     if (ExtraCode[1] != 0) return true; // Unknown modifier.
303 
304     switch (ExtraCode[0]) {
305     default: return true;  // Unknown modifier.
306     case 'L': // Write second word of DImode reference.
307       // Verify that this operand has two consecutive registers.
308       if (!MI->getOperand(OpNo).isReg() ||
309           OpNo+1 == MI->getNumOperands() ||
310           !MI->getOperand(OpNo+1).isReg())
311         return true;
312       ++OpNo;   // Return the high-part.
313       break;
314     }
315   }
316 
317   printOperand(MI, OpNo, O);
318   return false;
319 }
320 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,unsigned AsmVariant,const char * ExtraCode,raw_ostream & O)321 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
322                                           unsigned OpNo, unsigned AsmVariant,
323                                           const char *ExtraCode,
324                                           raw_ostream &O) {
325   if (ExtraCode && ExtraCode[0])
326     return true; // Unknown modifier.
327   printMemRegReg(MI, OpNo, O);
328   return false;
329 }
330 
331 // Force static initialization.
LLVMInitializeCellSPUAsmPrinter()332 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
333   RegisterAsmPrinter<SPUAsmPrinter> X(TheCellSPUTarget);
334 }
335