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" 37using namespace llvm; 38 39namespace { 40 class SPUAsmPrinter : public AsmPrinter { 41 public: 42 explicit SPUAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) : 43 AsmPrinter(TM, Streamer) {} 44 45 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 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 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 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 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 101 printS16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) 102 { 103 O << (short) MI->getOperand(OpNo).getImm(); 104 } 105 106 void 107 printU16ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) 108 { 109 O << (unsigned short)MI->getOperand(OpNo).getImm(); 110 } 111 112 void 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 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 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 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 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 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 181 void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 182 printOp(MI->getOperand(OpNo), O); 183 } 184 185 void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 186 printOp(MI->getOperand(OpNo), O); 187 } 188 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 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 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 217 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 218 printOp(MI->getOperand(OpNo), O); 219 } 220 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 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 247void 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/// 297bool 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 321bool 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. 332extern "C" void LLVMInitializeCellSPUAsmPrinter() { 333 RegisterAsmPrinter<SPUAsmPrinter> X(TheCellSPUTarget); 334} 335