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 SPUTargetMachine &getTM() {
50 return static_cast<SPUTargetMachine&>(TM);
53 /// printInstruction - This method is automatically generated by tablegen
54 /// from the instruction set description.
55 void printInstruction(const MachineInstr *MI, raw_ostream &OS);
56 static const char *getRegisterName(unsigned RegNo);
59 void EmitInstruction(const MachineInstr *MI) {
61 raw_svector_ostream OS(Str);
62 printInstruction(MI, OS);
63 OutStreamer.EmitRawText(OS.str());
65 void printOp(const MachineOperand &MO, raw_ostream &OS);
67 /// printRegister - Print register according to target requirements.
69 void printRegister(const MachineOperand &MO, bool R0AsZero, raw_ostream &O){
70 unsigned RegNo = MO.getReg();
71 assert(TargetRegisterInfo::isPhysicalRegister(RegNo) &&
73 O << getRegisterName(RegNo);
76 void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
77 const MachineOperand &MO = MI->getOperand(OpNo);
79 O << getRegisterName(MO.getReg());
80 } else if (MO.isImm()) {
87 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
88 unsigned AsmVariant, const char *ExtraCode,
90 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
91 unsigned AsmVariant, const char *ExtraCode,
96 printS7ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
98 int value = MI->getOperand(OpNo).getImm();
99 value = (value << (32 - 7)) >> (32 - 7);
101 assert((value >= -(1 << 8) && value <= (1 << 7) - 1)
102 && "Invalid s7 argument");
107 printU7ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
109 unsigned int value = MI->getOperand(OpNo).getImm();
110 assert(value < (1 << 8) && "Invalid u7 argument");
115 printShufAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
117 char value = MI->getOperand(OpNo).getImm();
120 printOperand(MI, OpNo+1, O);
125 printS16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
127 O << (short) MI->getOperand(OpNo).getImm();
131 printU16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
133 O << (unsigned short)MI->getOperand(OpNo).getImm();
137 printU32ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
139 O << (unsigned)MI->getOperand(OpNo).getImm();
143 printMemRegReg(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
144 // When used as the base register, r0 reads constant zero rather than
145 // the value contained in the register. For this reason, the darwin
146 // assembler requires that we print r0 as 0 (no r) when used as the base.
147 const MachineOperand &MO = MI->getOperand(OpNo);
148 O << getRegisterName(MO.getReg()) << ", ";
149 printOperand(MI, OpNo+1, O);
153 printU18ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
155 unsigned int value = MI->getOperand(OpNo).getImm();
156 assert(value <= (1 << 19) - 1 && "Invalid u18 argument");
161 printS10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
163 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
165 assert((value >= -(1 << 9) && value <= (1 << 9) - 1)
166 && "Invalid s10 argument");
171 printU10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
173 short value = (short) (((int) MI->getOperand(OpNo).getImm() << 16)
175 assert((value <= (1 << 10) - 1) && "Invalid u10 argument");
180 printDFormAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
182 assert(MI->getOperand(OpNo).isImm() &&
183 "printDFormAddr first operand is not immediate");
184 int64_t value = int64_t(MI->getOperand(OpNo).getImm());
185 int16_t value16 = int16_t(value);
186 assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1)
187 && "Invalid dform s10 offset argument");
188 O << (value16 & ~0xf) << "(";
189 printOperand(MI, OpNo+1, O);
194 printAddr256K(const MachineInstr *MI, unsigned OpNo, raw_ostream &O)
196 /* Note: operand 1 is an offset or symbol name. */
197 if (MI->getOperand(OpNo).isImm()) {
198 printS16ImmOperand(MI, OpNo, O);
200 printOp(MI->getOperand(OpNo), O);
201 if (MI->getOperand(OpNo+1).isImm()) {
202 int displ = int(MI->getOperand(OpNo+1).getImm());
211 void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
212 printOp(MI->getOperand(OpNo), O);
215 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
216 // Used to generate a ".-<target>", but it turns out that the assembler
217 // really wants the target.
219 // N.B.: This operand is used for call targets. Branch hints are another
221 printOp(MI->getOperand(OpNo), O);
224 void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
225 // HBR operands are generated in front of branches, hence, the
226 // program counter plus the target.
228 printOp(MI->getOperand(OpNo), O);
231 void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
232 if (MI->getOperand(OpNo).isImm()) {
233 printS16ImmOperand(MI, OpNo, O);
235 printOp(MI->getOperand(OpNo), O);
240 void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
241 if (MI->getOperand(OpNo).isImm()) {
242 printS16ImmOperand(MI, OpNo, O);
244 printOp(MI->getOperand(OpNo), O);
249 /// Print local store address
250 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
251 printOp(MI->getOperand(OpNo), O);
254 void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo,
256 if (MI->getOperand(OpNo).isImm()) {
257 int value = (int) MI->getOperand(OpNo).getImm();
258 assert((value >= 0 && value < 16)
259 && "Invalid negated immediate rotate 7-bit argument");
262 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm");
266 void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O){
267 assert(MI->getOperand(OpNo).isImm() &&
268 "Invalid/non-immediate rotate amount in printRotateNeg7Imm");
269 int value = (int) MI->getOperand(OpNo).getImm();
270 assert((value >= 0 && value <= 32)
271 && "Invalid negated immediate rotate 7-bit argument");
275 } // end of anonymous namespace
277 // Include the auto-generated portion of the assembly writer
278 #include "SPUGenAsmWriter.inc"
280 void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
281 switch (MO.getType()) {
282 case MachineOperand::MO_Immediate:
283 report_fatal_error("printOp() does not handle immediate values");
286 case MachineOperand::MO_MachineBasicBlock:
287 O << *MO.getMBB()->getSymbol();
289 case MachineOperand::MO_JumpTableIndex:
290 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
291 << '_' << MO.getIndex();
293 case MachineOperand::MO_ConstantPoolIndex:
294 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
295 << '_' << MO.getIndex();
297 case MachineOperand::MO_ExternalSymbol:
298 // Computing the address of an external symbol, not calling it.
299 if (TM.getRelocationModel() != Reloc::Static) {
300 O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName()
304 O << *GetExternalSymbolSymbol(MO.getSymbolName());
306 case MachineOperand::MO_GlobalAddress:
307 // External or weakly linked global variables need non-lazily-resolved
309 if (TM.getRelocationModel() != Reloc::Static) {
310 const GlobalValue *GV = MO.getGlobal();
311 if (((GV->isDeclaration() || GV->hasWeakLinkage() ||
312 GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) {
313 O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
317 O << *Mang->getSymbol(MO.getGlobal());
320 O << "<unknown operand type: " << MO.getType() << ">";
325 /// PrintAsmOperand - Print out an operand for an inline asm expression.
327 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
329 const char *ExtraCode, raw_ostream &O) {
330 // Does this asm operand have a single letter operand modifier?
331 if (ExtraCode && ExtraCode[0]) {
332 if (ExtraCode[1] != 0) return true; // Unknown modifier.
334 switch (ExtraCode[0]) {
335 default: return true; // Unknown modifier.
336 case 'L': // Write second word of DImode reference.
337 // Verify that this operand has two consecutive registers.
338 if (!MI->getOperand(OpNo).isReg() ||
339 OpNo+1 == MI->getNumOperands() ||
340 !MI->getOperand(OpNo+1).isReg())
342 ++OpNo; // Return the high-part.
347 printOperand(MI, OpNo, O);
351 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
352 unsigned OpNo, unsigned AsmVariant,
353 const char *ExtraCode,
355 if (ExtraCode && ExtraCode[0])
356 return true; // Unknown modifier.
357 printMemRegReg(MI, OpNo, O);
361 // Force static initialization.
362 extern "C" void LLVMInitializeCellSPUAsmPrinter() {
363 RegisterAsmPrinter<SPUAsmPrinter> X(TheCellSPUTarget);