1 //===-- SPUAsmPrinter.cpp - Print machine instrs to Cell SPU assembly -------=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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'.
14 //===----------------------------------------------------------------------===//
16 #define DEBUG_TYPE "asmprinter"
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/Target/TargetRegistry.h"
33 #include "llvm/ADT/SmallString.h"
34 #include "llvm/ADT/StringExtras.h"
35 #include "llvm/Support/ErrorHandling.h"
36 #include "llvm/Support/raw_ostream.h"
40 class SPUAsmPrinter
: public AsmPrinter
{
42 explicit SPUAsmPrinter(TargetMachine
&TM
, MCStreamer
&Streamer
) :
43 AsmPrinter(TM
, Streamer
) {}
45 virtual const char *getPassName() const {
46 return "STI CBEA SPU Assembly Printer";
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
);
55 void EmitInstruction(const MachineInstr
*MI
) {
57 raw_svector_ostream
OS(Str
);
58 printInstruction(MI
, OS
);
59 OutStreamer
.EmitRawText(OS
.str());
61 void printOp(const MachineOperand
&MO
, raw_ostream
&OS
);
63 void printOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
64 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
66 O
<< getRegisterName(MO
.getReg());
67 } else if (MO
.isImm()) {
74 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
75 unsigned AsmVariant
, const char *ExtraCode
,
77 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNo
,
78 unsigned AsmVariant
, const char *ExtraCode
,
83 printU7ImmOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
85 unsigned int value
= MI
->getOperand(OpNo
).getImm();
86 assert(value
< (1 << 8) && "Invalid u7 argument");
91 printShufAddr(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
93 char value
= MI
->getOperand(OpNo
).getImm();
96 printOperand(MI
, OpNo
+1, O
);
101 printS16ImmOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
103 O
<< (short) MI
->getOperand(OpNo
).getImm();
107 printU16ImmOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
109 O
<< (unsigned short)MI
->getOperand(OpNo
).getImm();
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
);
123 printU18ImmOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
125 unsigned int value
= MI
->getOperand(OpNo
).getImm();
126 assert(value
<= (1 << 19) - 1 && "Invalid u18 argument");
131 printS10ImmOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
133 short value
= (short) (((int) MI
->getOperand(OpNo
).getImm() << 16)
135 assert((value
>= -(1 << 9) && value
<= (1 << 9) - 1)
136 && "Invalid s10 argument");
141 printU10ImmOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
143 short value
= (short) (((int) MI
->getOperand(OpNo
).getImm() << 16)
145 assert((value
<= (1 << 10) - 1) && "Invalid u10 argument");
150 printDFormAddr(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
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
);
164 printAddr256K(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
)
166 /* Note: operand 1 is an offset or symbol name. */
167 if (MI
->getOperand(OpNo
).isImm()) {
168 printS16ImmOperand(MI
, OpNo
, O
);
170 printOp(MI
->getOperand(OpNo
), O
);
171 if (MI
->getOperand(OpNo
+1).isImm()) {
172 int displ
= int(MI
->getOperand(OpNo
+1).getImm());
181 void printCallOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
182 printOp(MI
->getOperand(OpNo
), O
);
185 void printHBROperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
186 printOp(MI
->getOperand(OpNo
), 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.
193 // N.B.: This operand is used for call targets. Branch hints are another
195 printOp(MI
->getOperand(OpNo
), O
);
198 void printSymbolHi(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
199 if (MI
->getOperand(OpNo
).isImm()) {
200 printS16ImmOperand(MI
, OpNo
, O
);
202 printOp(MI
->getOperand(OpNo
), O
);
207 void printSymbolLo(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
208 if (MI
->getOperand(OpNo
).isImm()) {
209 printS16ImmOperand(MI
, OpNo
, O
);
211 printOp(MI
->getOperand(OpNo
), O
);
216 /// Print local store address
217 void printSymbolLSA(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
218 printOp(MI
->getOperand(OpNo
), O
);
221 void printROTHNeg7Imm(const MachineInstr
*MI
, unsigned OpNo
,
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");
229 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
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");
242 } // end of anonymous namespace
244 // Include the auto-generated portion of the assembly writer
245 #include "SPUGenAsmWriter.inc"
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");
253 case MachineOperand::MO_MachineBasicBlock
:
254 O
<< *MO
.getMBB()->getSymbol();
256 case MachineOperand::MO_JumpTableIndex
:
257 O
<< MAI
->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
258 << '_' << MO
.getIndex();
260 case MachineOperand::MO_ConstantPoolIndex
:
261 O
<< MAI
->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
262 << '_' << MO
.getIndex();
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()
271 O
<< *GetExternalSymbolSymbol(MO
.getSymbolName());
273 case MachineOperand::MO_GlobalAddress
:
274 // External or weakly linked global variables need non-lazily-resolved
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");
284 O
<< *Mang
->getSymbol(MO
.getGlobal());
286 case MachineOperand::MO_MCSymbol
:
287 O
<< *(MO
.getMCSymbol());
290 O
<< "<unknown operand type: " << MO
.getType() << ">";
295 /// PrintAsmOperand - Print out an operand for an inline asm expression.
297 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
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.
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())
312 ++OpNo
; // Return the high-part.
317 printOperand(MI
, OpNo
, O
);
321 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
322 unsigned OpNo
, unsigned AsmVariant
,
323 const char *ExtraCode
,
325 if (ExtraCode
&& ExtraCode
[0])
326 return true; // Unknown modifier.
327 printMemRegReg(MI
, OpNo
, O
);
331 // Force static initialization.
332 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
333 RegisterAsmPrinter
<SPUAsmPrinter
> X(TheCellSPUTarget
);