1 //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===// 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 GAS-format SPARC assembly language. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "Sparc.h" 16 #include "InstPrinter/SparcInstPrinter.h" 17 #include "MCTargetDesc/SparcMCExpr.h" 18 #include "SparcInstrInfo.h" 19 #include "SparcTargetMachine.h" 20 #include "SparcTargetStreamer.h" 21 #include "llvm/ADT/SmallString.h" 22 #include "llvm/CodeGen/AsmPrinter.h" 23 #include "llvm/CodeGen/MachineInstr.h" 24 #include "llvm/CodeGen/MachineModuleInfoImpls.h" 25 #include "llvm/CodeGen/MachineRegisterInfo.h" 26 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 27 #include "llvm/IR/Mangler.h" 28 #include "llvm/MC/MCAsmInfo.h" 29 #include "llvm/MC/MCContext.h" 30 #include "llvm/MC/MCInst.h" 31 #include "llvm/MC/MCStreamer.h" 32 #include "llvm/MC/MCSymbol.h" 33 #include "llvm/Support/TargetRegistry.h" 34 #include "llvm/Support/raw_ostream.h" 35 using namespace llvm; 36 37 #define DEBUG_TYPE "asm-printer" 38 39 namespace { 40 class SparcAsmPrinter : public AsmPrinter { 41 SparcTargetStreamer &getTargetStreamer() { 42 return static_cast<SparcTargetStreamer &>( 43 *OutStreamer.getTargetStreamer()); 44 } 45 public: 46 explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) 47 : AsmPrinter(TM, Streamer) {} 48 49 const char *getPassName() const override { 50 return "Sparc Assembly Printer"; 51 } 52 53 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 54 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, 55 const char *Modifier = nullptr); 56 void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 57 58 void EmitFunctionBodyStart() override; 59 void EmitInstruction(const MachineInstr *MI) override; 60 void EmitEndOfAsmFile(Module &M) override; 61 62 static const char *getRegisterName(unsigned RegNo) { 63 return SparcInstPrinter::getRegisterName(RegNo); 64 } 65 66 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 67 unsigned AsmVariant, const char *ExtraCode, 68 raw_ostream &O) override; 69 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 70 unsigned AsmVariant, const char *ExtraCode, 71 raw_ostream &O) override; 72 73 void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, 74 const MCSubtargetInfo &STI); 75 76 }; 77 } // end of anonymous namespace 78 79 static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind, 80 MCSymbol *Sym, MCContext &OutContext) { 81 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Sym, 82 OutContext); 83 const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, OutContext); 84 return MCOperand::CreateExpr(expr); 85 86 } 87 static MCOperand createPCXCallOP(MCSymbol *Label, 88 MCContext &OutContext) { 89 return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext); 90 } 91 92 static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, 93 MCSymbol *GOTLabel, MCSymbol *StartLabel, 94 MCSymbol *CurLabel, 95 MCContext &OutContext) 96 { 97 const MCSymbolRefExpr *GOT = MCSymbolRefExpr::Create(GOTLabel, OutContext); 98 const MCSymbolRefExpr *Start = MCSymbolRefExpr::Create(StartLabel, 99 OutContext); 100 const MCSymbolRefExpr *Cur = MCSymbolRefExpr::Create(CurLabel, 101 OutContext); 102 103 const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Cur, Start, OutContext); 104 const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(GOT, Sub, OutContext); 105 const SparcMCExpr *expr = SparcMCExpr::Create(Kind, 106 Add, OutContext); 107 return MCOperand::CreateExpr(expr); 108 } 109 110 static void EmitCall(MCStreamer &OutStreamer, 111 MCOperand &Callee, 112 const MCSubtargetInfo &STI) 113 { 114 MCInst CallInst; 115 CallInst.setOpcode(SP::CALL); 116 CallInst.addOperand(Callee); 117 OutStreamer.EmitInstruction(CallInst, STI); 118 } 119 120 static void EmitSETHI(MCStreamer &OutStreamer, 121 MCOperand &Imm, MCOperand &RD, 122 const MCSubtargetInfo &STI) 123 { 124 MCInst SETHIInst; 125 SETHIInst.setOpcode(SP::SETHIi); 126 SETHIInst.addOperand(RD); 127 SETHIInst.addOperand(Imm); 128 OutStreamer.EmitInstruction(SETHIInst, STI); 129 } 130 131 static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode, 132 MCOperand &RS1, MCOperand &Src2, MCOperand &RD, 133 const MCSubtargetInfo &STI) 134 { 135 MCInst Inst; 136 Inst.setOpcode(Opcode); 137 Inst.addOperand(RD); 138 Inst.addOperand(RS1); 139 Inst.addOperand(Src2); 140 OutStreamer.EmitInstruction(Inst, STI); 141 } 142 143 static void EmitOR(MCStreamer &OutStreamer, 144 MCOperand &RS1, MCOperand &Imm, MCOperand &RD, 145 const MCSubtargetInfo &STI) { 146 EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI); 147 } 148 149 static void EmitADD(MCStreamer &OutStreamer, 150 MCOperand &RS1, MCOperand &RS2, MCOperand &RD, 151 const MCSubtargetInfo &STI) { 152 EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI); 153 } 154 155 static void EmitSHL(MCStreamer &OutStreamer, 156 MCOperand &RS1, MCOperand &Imm, MCOperand &RD, 157 const MCSubtargetInfo &STI) { 158 EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI); 159 } 160 161 162 static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, 163 SparcMCExpr::VariantKind HiKind, 164 SparcMCExpr::VariantKind LoKind, 165 MCOperand &RD, 166 MCContext &OutContext, 167 const MCSubtargetInfo &STI) { 168 169 MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext); 170 MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext); 171 EmitSETHI(OutStreamer, hi, RD, STI); 172 EmitOR(OutStreamer, RD, lo, RD, STI); 173 } 174 175 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, 176 const MCSubtargetInfo &STI) 177 { 178 MCSymbol *GOTLabel = 179 OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_")); 180 181 const MachineOperand &MO = MI->getOperand(0); 182 assert(MO.getReg() != SP::O7 && 183 "%o7 is assigned as destination for getpcx!"); 184 185 MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg()); 186 187 188 if (TM.getRelocationModel() != Reloc::PIC_) { 189 // Just load the address of GOT to MCRegOP. 190 switch(TM.getCodeModel()) { 191 default: 192 llvm_unreachable("Unsupported absolute code model"); 193 case CodeModel::Small: 194 EmitHiLo(OutStreamer, GOTLabel, 195 SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, 196 MCRegOP, OutContext, STI); 197 break; 198 case CodeModel::Medium: { 199 EmitHiLo(OutStreamer, GOTLabel, 200 SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44, 201 MCRegOP, OutContext, STI); 202 MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12, 203 OutContext)); 204 EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP, STI); 205 MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44, 206 GOTLabel, OutContext); 207 EmitOR(OutStreamer, MCRegOP, lo, MCRegOP, STI); 208 break; 209 } 210 case CodeModel::Large: { 211 EmitHiLo(OutStreamer, GOTLabel, 212 SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM, 213 MCRegOP, OutContext, STI); 214 MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32, 215 OutContext)); 216 EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP, STI); 217 // Use register %o7 to load the lower 32 bits. 218 MCOperand RegO7 = MCOperand::CreateReg(SP::O7); 219 EmitHiLo(OutStreamer, GOTLabel, 220 SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, 221 RegO7, OutContext, STI); 222 EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP, STI); 223 } 224 } 225 return; 226 } 227 228 MCSymbol *StartLabel = OutContext.CreateTempSymbol(); 229 MCSymbol *EndLabel = OutContext.CreateTempSymbol(); 230 MCSymbol *SethiLabel = OutContext.CreateTempSymbol(); 231 232 MCOperand RegO7 = MCOperand::CreateReg(SP::O7); 233 234 // <StartLabel>: 235 // call <EndLabel> 236 // <SethiLabel>: 237 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO> 238 // <EndLabel>: 239 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO> 240 // add <MO>, %o7, <MO> 241 242 OutStreamer.EmitLabel(StartLabel); 243 MCOperand Callee = createPCXCallOP(EndLabel, OutContext); 244 EmitCall(OutStreamer, Callee, STI); 245 OutStreamer.EmitLabel(SethiLabel); 246 MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22, 247 GOTLabel, StartLabel, SethiLabel, 248 OutContext); 249 EmitSETHI(OutStreamer, hiImm, MCRegOP, STI); 250 OutStreamer.EmitLabel(EndLabel); 251 MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10, 252 GOTLabel, StartLabel, EndLabel, 253 OutContext); 254 EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP, STI); 255 EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP, STI); 256 } 257 258 void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI) 259 { 260 261 switch (MI->getOpcode()) { 262 default: break; 263 case TargetOpcode::DBG_VALUE: 264 // FIXME: Debug Value. 265 return; 266 case SP::GETPCX: 267 LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo()); 268 return; 269 } 270 MachineBasicBlock::const_instr_iterator I = MI; 271 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); 272 do { 273 MCInst TmpInst; 274 LowerSparcMachineInstrToMCInst(I, TmpInst, *this); 275 EmitToStreamer(OutStreamer, TmpInst); 276 } while ((++I != E) && I->isInsideBundle()); // Delay slot check. 277 } 278 279 void SparcAsmPrinter::EmitFunctionBodyStart() { 280 if (!TM.getSubtarget<SparcSubtarget>().is64Bit()) 281 return; 282 283 const MachineRegisterInfo &MRI = MF->getRegInfo(); 284 const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 }; 285 for (unsigned i = 0; globalRegs[i] != 0; ++i) { 286 unsigned reg = globalRegs[i]; 287 if (MRI.use_empty(reg)) 288 continue; 289 290 if (reg == SP::G6 || reg == SP::G7) 291 getTargetStreamer().emitSparcRegisterIgnore(reg); 292 else 293 getTargetStreamer().emitSparcRegisterScratch(reg); 294 } 295 } 296 297 void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 298 raw_ostream &O) { 299 const DataLayout *DL = TM.getDataLayout(); 300 const MachineOperand &MO = MI->getOperand (opNum); 301 SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags(); 302 303 #ifndef NDEBUG 304 // Verify the target flags. 305 if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { 306 if (MI->getOpcode() == SP::CALL) 307 assert(TF == SparcMCExpr::VK_Sparc_None && 308 "Cannot handle target flags on call address"); 309 else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi) 310 assert((TF == SparcMCExpr::VK_Sparc_HI 311 || TF == SparcMCExpr::VK_Sparc_H44 312 || TF == SparcMCExpr::VK_Sparc_HH 313 || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22 314 || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22 315 || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22 316 || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22 317 || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) && 318 "Invalid target flags for address operand on sethi"); 319 else if (MI->getOpcode() == SP::TLS_CALL) 320 assert((TF == SparcMCExpr::VK_Sparc_None 321 || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL 322 || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) && 323 "Cannot handle target flags on tls call address"); 324 else if (MI->getOpcode() == SP::TLS_ADDrr) 325 assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD 326 || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD 327 || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD 328 || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) && 329 "Cannot handle target flags on add for TLS"); 330 else if (MI->getOpcode() == SP::TLS_LDrr) 331 assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD && 332 "Cannot handle target flags on ld for TLS"); 333 else if (MI->getOpcode() == SP::TLS_LDXrr) 334 assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX && 335 "Cannot handle target flags on ldx for TLS"); 336 else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri) 337 assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10 338 || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) && 339 "Cannot handle target flags on xor for TLS"); 340 else 341 assert((TF == SparcMCExpr::VK_Sparc_LO 342 || TF == SparcMCExpr::VK_Sparc_M44 343 || TF == SparcMCExpr::VK_Sparc_L44 344 || TF == SparcMCExpr::VK_Sparc_HM 345 || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10 346 || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10 347 || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) && 348 "Invalid target flags for small address operand"); 349 } 350 #endif 351 352 353 bool CloseParen = SparcMCExpr::printVariantKind(O, TF); 354 355 switch (MO.getType()) { 356 case MachineOperand::MO_Register: 357 O << "%" << StringRef(getRegisterName(MO.getReg())).lower(); 358 break; 359 360 case MachineOperand::MO_Immediate: 361 O << (int)MO.getImm(); 362 break; 363 case MachineOperand::MO_MachineBasicBlock: 364 O << *MO.getMBB()->getSymbol(); 365 return; 366 case MachineOperand::MO_GlobalAddress: 367 O << *getSymbol(MO.getGlobal()); 368 break; 369 case MachineOperand::MO_BlockAddress: 370 O << GetBlockAddressSymbol(MO.getBlockAddress())->getName(); 371 break; 372 case MachineOperand::MO_ExternalSymbol: 373 O << MO.getSymbolName(); 374 break; 375 case MachineOperand::MO_ConstantPoolIndex: 376 O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" 377 << MO.getIndex(); 378 break; 379 default: 380 llvm_unreachable("<unknown operand type>"); 381 } 382 if (CloseParen) O << ")"; 383 } 384 385 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, 386 raw_ostream &O, const char *Modifier) { 387 printOperand(MI, opNum, O); 388 389 // If this is an ADD operand, emit it like normal operands. 390 if (Modifier && !strcmp(Modifier, "arith")) { 391 O << ", "; 392 printOperand(MI, opNum+1, O); 393 return; 394 } 395 396 if (MI->getOperand(opNum+1).isReg() && 397 MI->getOperand(opNum+1).getReg() == SP::G0) 398 return; // don't print "+%g0" 399 if (MI->getOperand(opNum+1).isImm() && 400 MI->getOperand(opNum+1).getImm() == 0) 401 return; // don't print "+0" 402 403 O << "+"; 404 printOperand(MI, opNum+1, O); 405 } 406 407 /// PrintAsmOperand - Print out an operand for an inline asm expression. 408 /// 409 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 410 unsigned AsmVariant, 411 const char *ExtraCode, 412 raw_ostream &O) { 413 if (ExtraCode && ExtraCode[0]) { 414 if (ExtraCode[1] != 0) return true; // Unknown modifier. 415 416 switch (ExtraCode[0]) { 417 default: 418 // See if this is a generic print operand 419 return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); 420 case 'r': 421 break; 422 } 423 } 424 425 printOperand(MI, OpNo, O); 426 427 return false; 428 } 429 430 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 431 unsigned OpNo, unsigned AsmVariant, 432 const char *ExtraCode, 433 raw_ostream &O) { 434 if (ExtraCode && ExtraCode[0]) 435 return true; // Unknown modifier 436 437 O << '['; 438 printMemOperand(MI, OpNo, O); 439 O << ']'; 440 441 return false; 442 } 443 444 void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) { 445 const TargetLoweringObjectFileELF &TLOFELF = 446 static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); 447 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); 448 449 // Generate stubs for global variables. 450 MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); 451 if (!Stubs.empty()) { 452 OutStreamer.SwitchSection(TLOFELF.getDataSection()); 453 unsigned PtrSize = TM.getDataLayout()->getPointerSize(0); 454 for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { 455 OutStreamer.EmitLabel(Stubs[i].first); 456 OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize); 457 } 458 } 459 } 460 461 // Force static initialization. 462 extern "C" void LLVMInitializeSparcAsmPrinter() { 463 RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget); 464 RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target); 465 } 466