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 printPCRelativeOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
186 // Used to generate a ".-<target>", but it turns out that the assembler
187 // really wants the target.
189 // N.B.: This operand is used for call targets. Branch hints are another
191 printOp(MI
->getOperand(OpNo
), O
);
194 void printSymbolHi(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
195 if (MI
->getOperand(OpNo
).isImm()) {
196 printS16ImmOperand(MI
, OpNo
, O
);
198 printOp(MI
->getOperand(OpNo
), O
);
203 void printSymbolLo(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
204 if (MI
->getOperand(OpNo
).isImm()) {
205 printS16ImmOperand(MI
, OpNo
, O
);
207 printOp(MI
->getOperand(OpNo
), O
);
212 /// Print local store address
213 void printSymbolLSA(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
) {
214 printOp(MI
->getOperand(OpNo
), O
);
217 void printROTHNeg7Imm(const MachineInstr
*MI
, unsigned OpNo
,
219 if (MI
->getOperand(OpNo
).isImm()) {
220 int value
= (int) MI
->getOperand(OpNo
).getImm();
221 assert((value
>= 0 && value
< 16)
222 && "Invalid negated immediate rotate 7-bit argument");
225 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
229 void printROTNeg7Imm(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
){
230 assert(MI
->getOperand(OpNo
).isImm() &&
231 "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
232 int value
= (int) MI
->getOperand(OpNo
).getImm();
233 assert((value
>= 0 && value
<= 32)
234 && "Invalid negated immediate rotate 7-bit argument");
238 } // end of anonymous namespace
240 // Include the auto-generated portion of the assembly writer
241 #include "SPUGenAsmWriter.inc"
243 void SPUAsmPrinter::printOp(const MachineOperand
&MO
, raw_ostream
&O
) {
244 switch (MO
.getType()) {
245 case MachineOperand::MO_Immediate
:
246 report_fatal_error("printOp() does not handle immediate values");
249 case MachineOperand::MO_MachineBasicBlock
:
250 O
<< *MO
.getMBB()->getSymbol();
252 case MachineOperand::MO_JumpTableIndex
:
253 O
<< MAI
->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
254 << '_' << MO
.getIndex();
256 case MachineOperand::MO_ConstantPoolIndex
:
257 O
<< MAI
->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
258 << '_' << MO
.getIndex();
260 case MachineOperand::MO_ExternalSymbol
:
261 // Computing the address of an external symbol, not calling it.
262 if (TM
.getRelocationModel() != Reloc::Static
) {
263 O
<< "L" << MAI
->getGlobalPrefix() << MO
.getSymbolName()
267 O
<< *GetExternalSymbolSymbol(MO
.getSymbolName());
269 case MachineOperand::MO_GlobalAddress
:
270 // External or weakly linked global variables need non-lazily-resolved
272 if (TM
.getRelocationModel() != Reloc::Static
) {
273 const GlobalValue
*GV
= MO
.getGlobal();
274 if (((GV
->isDeclaration() || GV
->hasWeakLinkage() ||
275 GV
->hasLinkOnceLinkage() || GV
->hasCommonLinkage()))) {
276 O
<< *GetSymbolWithGlobalValueBase(GV
, "$non_lazy_ptr");
280 O
<< *Mang
->getSymbol(MO
.getGlobal());
283 O
<< "<unknown operand type: " << MO
.getType() << ">";
288 /// PrintAsmOperand - Print out an operand for an inline asm expression.
290 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
292 const char *ExtraCode
, raw_ostream
&O
) {
293 // Does this asm operand have a single letter operand modifier?
294 if (ExtraCode
&& ExtraCode
[0]) {
295 if (ExtraCode
[1] != 0) return true; // Unknown modifier.
297 switch (ExtraCode
[0]) {
298 default: return true; // Unknown modifier.
299 case 'L': // Write second word of DImode reference.
300 // Verify that this operand has two consecutive registers.
301 if (!MI
->getOperand(OpNo
).isReg() ||
302 OpNo
+1 == MI
->getNumOperands() ||
303 !MI
->getOperand(OpNo
+1).isReg())
305 ++OpNo
; // Return the high-part.
310 printOperand(MI
, OpNo
, O
);
314 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
315 unsigned OpNo
, unsigned AsmVariant
,
316 const char *ExtraCode
,
318 if (ExtraCode
&& ExtraCode
[0])
319 return true; // Unknown modifier.
320 printMemRegReg(MI
, OpNo
, O
);
324 // Force static initialization.
325 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
326 RegisterAsmPrinter
<SPUAsmPrinter
> X(TheCellSPUTarget
);