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 = (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 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"); 251 252 case MachineOperand::MO_MachineBasicBlock: 253 O << *MO.getMBB()->getSymbol(); 254 return; 255 case MachineOperand::MO_JumpTableIndex: 256 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() 257 << '_' << MO.getIndex(); 258 return; 259 case MachineOperand::MO_ConstantPoolIndex: 260 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() 261 << '_' << MO.getIndex(); 262 return; 263 case MachineOperand::MO_ExternalSymbol: 264 // Computing the address of an external symbol, not calling it. 265 if (TM.getRelocationModel() != Reloc::Static) { 266 O << "L" << MAI->getGlobalPrefix() << MO.getSymbolName() 267 << "$non_lazy_ptr"; 268 return; 269 } 270 O << *GetExternalSymbolSymbol(MO.getSymbolName()); 271 return; 272 case MachineOperand::MO_GlobalAddress: 273 // External or weakly linked global variables need non-lazily-resolved 274 // stubs 275 if (TM.getRelocationModel() != Reloc::Static) { 276 const GlobalValue *GV = MO.getGlobal(); 277 if (((GV->isDeclaration() || GV->hasWeakLinkage() || 278 GV->hasLinkOnceLinkage() || GV->hasCommonLinkage()))) { 279 O << *GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); 280 return; 281 } 282 } 283 O << *Mang->getSymbol(MO.getGlobal()); 284 return; 285 case MachineOperand::MO_MCSymbol: 286 O << *(MO.getMCSymbol()); 287 return; 288 default: 289 O << "<unknown operand type: " << MO.getType() << ">"; 290 return; 291 } 292 } 293 294 /// PrintAsmOperand - Print out an operand for an inline asm expression. 295 /// 296 bool SPUAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 297 unsigned AsmVariant, 298 const char *ExtraCode, raw_ostream &O) { 299 // Does this asm operand have a single letter operand modifier? 300 if (ExtraCode && ExtraCode[0]) { 301 if (ExtraCode[1] != 0) return true; // Unknown modifier. 302 303 switch (ExtraCode[0]) { 304 default: return true; // Unknown modifier. 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