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: 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 = MI->getOperand(OpNo).getImm(); 134 assert((value >= -(1 << 9) && value <= (1 << 9) - 1) 135 && "Invalid s10 argument"); 136 O << value; 137 } 138 139 void 140 printU10ImmOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) 141 { 142 short value = MI->getOperand(OpNo).getImm(); 143 assert((value <= (1 << 10) - 1) && "Invalid u10 argument"); 144 O << value; 145 } 146 147 void 148 printDFormAddr(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) 149 { 150 assert(MI->getOperand(OpNo).isImm() && 151 "printDFormAddr first operand is not immediate"); 152 int64_t value = int64_t(MI->getOperand(OpNo).getImm()); 153 int16_t value16 = int16_t(value); 154 assert((value16 >= -(1 << (9+4)) && value16 <= (1 << (9+4)) - 1) 155 && "Invalid dform s10 offset argument"); 156 O << (value16 & ~0xf) << "("; 157 printOperand(MI, OpNo+1, O); 158 O << ")"; 159 } 160 161 void 162 printAddr256K(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) 163 { 164 /* Note: operand 1 is an offset or symbol name. */ 165 if (MI->getOperand(OpNo).isImm()) { 166 printS16ImmOperand(MI, OpNo, O); 167 } else { 168 printOp(MI->getOperand(OpNo), O); 169 if (MI->getOperand(OpNo+1).isImm()) { 170 int displ = int(MI->getOperand(OpNo+1).getImm()); 171 if (displ > 0) 172 O << "+" << displ; 173 else if (displ < 0) 174 O << displ; 175 } 176 } 177 } 178 179 void printCallOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 180 printOp(MI->getOperand(OpNo), O); 181 } 182 183 void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 184 printOp(MI->getOperand(OpNo), O); 185 } 186 187 void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 188 // Used to generate a ".-<target>", but it turns out that the assembler 189 // really wants the target. 190 // 191 // N.B.: This operand is used for call targets. Branch hints are another 192 // animal entirely. 193 printOp(MI->getOperand(OpNo), O); 194 } 195 196 void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 197 if (MI->getOperand(OpNo).isImm()) { 198 printS16ImmOperand(MI, OpNo, O); 199 } else { 200 printOp(MI->getOperand(OpNo), O); 201 O << "@h"; 202 } 203 } 204 205 void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 206 if (MI->getOperand(OpNo).isImm()) { 207 printS16ImmOperand(MI, OpNo, O); 208 } else { 209 printOp(MI->getOperand(OpNo), O); 210 O << "@l"; 211 } 212 } 213 214 /// Print local store address 215 void printSymbolLSA(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { 216 printOp(MI->getOperand(OpNo), O); 217 } 218 219 void printROTHNeg7Imm(const MachineInstr *MI, unsigned OpNo, 220 raw_ostream &O) { 221 if (MI->getOperand(OpNo).isImm()) { 222 int value = (int) MI->getOperand(OpNo).getImm(); 223 assert((value >= 0 && value < 16) 224 && "Invalid negated immediate rotate 7-bit argument"); 225 O << -value; 226 } else { 227 llvm_unreachable("Invalid/non-immediate rotate amount in printRotateNeg7Imm"); 228 } 229 } 230 231 void printROTNeg7Imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O){ 232 assert(MI->getOperand(OpNo).isImm() && 233 "Invalid/non-immediate rotate amount in printRotateNeg7Imm"); 234 int value = (int) MI->getOperand(OpNo).getImm(); 235 assert((value >= 0 && value <= 32) 236 && "Invalid negated immediate rotate 7-bit argument"); 237 O << -value; 238 } 239 }; 240 } // end of anonymous namespace 241 242 // Include the auto-generated portion of the assembly writer 243 #include "SPUGenAsmWriter.inc" 244 245 void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) { 246 switch (MO.getType()) { 247 case MachineOperand::MO_Immediate: 248 report_fatal_error("printOp() does not handle immediate values"); 249 250 case MachineOperand::MO_MachineBasicBlock: 251 O << *MO.getMBB()->getSymbol(); 252 return; 253 case MachineOperand::MO_JumpTableIndex: 254 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() 255 << '_' << MO.getIndex(); 256 return; 257 case MachineOperand::MO_ConstantPoolIndex: 258 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() 259 << '_' << MO.getIndex(); 260 return; 261 case MachineOperand::MO_ExternalSymbol: 262 // Computing the address of an external symbol, not calling it. 263 if (TM.getRelocationModel() != Reloc::Static) { 264 O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName() 265 << "$non_lazy_ptr"; 266 return; 267 } 268 O << *GetExternalSymbolSymbol(MO.getSymbolName()); 269 return; 270 case MachineOperand::MO_GlobalAddress: 271 // External or weakly linked global variables need non-lazily-resolved 272 // stubs 273 if (TM.getRelocationModel() != Reloc::Static) { 274 const GlobalValue *GV = MO.getGlobal(); 275 if (((GV->isDeclaration() || GV->hasWeakLinkage() || 276 GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) { 277 O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); 278 return; 279 } 280 } 281 O << *Mang->getSymbol(MO.getGlobal()); 282 return; 283 case MachineOperand::MO_MCSymbol: 284 O << *(MO.getMCSymbol()); 285 return; 286 default: 287 O << "<unknown operand type: " << MO.getType() << ">"; 288 return; 289 } 290 } 291 292 /// PrintAsmOperand - Print out an operand for an inline asm expression. 293 /// 294 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 295 unsigned AsmVariant, 296 const char *ExtraCode, raw_ostream &O) { 297 // Does this asm operand have a single letter operand modifier? 298 if (ExtraCode && ExtraCode[0]) { 299 if (ExtraCode[1] != 0) return true; // Unknown modifier. 300 301 switch (ExtraCode[0]) { 302 default: 303 // See if this is a generic print operand 304 return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); 305 case 'L': // Write second word of DImode reference. 306 // Verify that this operand has two consecutive registers. 307 if (!MI->getOperand(OpNo).isReg() || 308 OpNo+1 == MI->getNumOperands() || 309 !MI->getOperand(OpNo+1).isReg()) 310 return true; 311 ++OpNo; // Return the high-part. 312 break; 313 } 314 } 315 316 printOperand(MI, OpNo, O); 317 return false; 318 } 319 320 bool SPUAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 321 unsigned OpNo, unsigned AsmVariant, 322 const char *ExtraCode, 323 raw_ostream &O) { 324 if (ExtraCode && ExtraCode[0]) 325 return true; // Unknown modifier. 326 printMemRegReg(MI, OpNo, O); 327 return false; 328 } 329 330 // Force static initialization. 331 extern "C" void LLVMInitializeCellSPUAsmPrinter() { 332 RegisterAsmPrinter<SPUAsmPrinter> X(TheCellSPUTarget); 333 } 334