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" 35using namespace llvm; 36 37#define DEBUG_TYPE "asm-printer" 38 39namespace { 40 class SparcAsmPrinter : public AsmPrinter { 41 SparcTargetStreamer &getTargetStreamer() { 42 return static_cast<SparcTargetStreamer &>( 43 *OutStreamer->getTargetStreamer()); 44 } 45 public: 46 explicit SparcAsmPrinter(TargetMachine &TM, 47 std::unique_ptr<MCStreamer> Streamer) 48 : AsmPrinter(TM, std::move(Streamer)) {} 49 50 const char *getPassName() const override { 51 return "Sparc Assembly Printer"; 52 } 53 54 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 55 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, 56 const char *Modifier = nullptr); 57 void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 58 59 void EmitFunctionBodyStart() override; 60 void EmitInstruction(const MachineInstr *MI) 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 79static 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} 87static MCOperand createPCXCallOP(MCSymbol *Label, 88 MCContext &OutContext) { 89 return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext); 90} 91 92static 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 110static 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 120static 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 131static 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 143static 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 149static 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 155static 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 162static 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 175void 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 258void 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->getIterator(); 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 279void SparcAsmPrinter::EmitFunctionBodyStart() { 280 if (!MF->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 297void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 298 raw_ostream &O) { 299 const DataLayout &DL = 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 MO.getMBB()->getSymbol()->print(O, MAI); 365 return; 366 case MachineOperand::MO_GlobalAddress: 367 getSymbol(MO.getGlobal())->print(O, MAI); 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 385void 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/// 409bool 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 430bool 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// Force static initialization. 445extern "C" void LLVMInitializeSparcAsmPrinter() { 446 RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget); 447 RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target); 448 RegisterAsmPrinter<SparcAsmPrinter> Z(TheSparcelTarget); 449} 450