X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FPowerPC%2FPPCAsmPrinter.cpp;h=79ece1733209fb8813c596a0c5943ae56dba3075;hb=1d1d5f60906cc89e0e46dbd51e85f622dc806a65;hp=e4a631a9cf367dfdbab9edbdbd8e3c56d1c67634;hpb=9bc94276e796d644cb425a7c7d38cc44dbf4e9c1;p=oota-llvm.git diff --git a/lib/Target/PowerPC/PPCAsmPrinter.cpp b/lib/Target/PowerPC/PPCAsmPrinter.cpp index e4a631a9cf3..79ece173320 100644 --- a/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -16,26 +16,30 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "asmprinter" #include "PPC.h" #include "InstPrinter/PPCInstPrinter.h" -#include "MCTargetDesc/PPCPredicates.h" #include "MCTargetDesc/PPCMCExpr.h" +#include "MCTargetDesc/PPCPredicates.h" +#include "PPCMachineFunctionInfo.h" #include "PPCSubtarget.h" #include "PPCTargetMachine.h" +#include "PPCTargetStreamer.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Assembly/Writer.h" #include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/StackMaps.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" -#include "llvm/DebugInfo.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -45,7 +49,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" @@ -53,71 +57,89 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; -namespace { - class PPCAsmPrinter : public AsmPrinter { - protected: - MapVector TOC; - const PPCSubtarget &Subtarget; - uint64_t TOCLabelID; - public: - explicit PPCAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : AsmPrinter(TM, Streamer), - Subtarget(TM.getSubtarget()), TOCLabelID(0) {} +#define DEBUG_TYPE "asmprinter" - virtual const char *getPassName() const { - return "PowerPC Assembly Printer"; - } +namespace { +class PPCAsmPrinter : public AsmPrinter { +protected: + MapVector TOC; + const PPCSubtarget *Subtarget; + StackMaps SM; + +public: + explicit PPCAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)), SM(*this) {} + + const char *getPassName() const override { + return "PowerPC Assembly Printer"; + } MCSymbol *lookUpOrCreateTOCEntry(MCSymbol *Sym); - virtual void EmitInstruction(const MachineInstr *MI); + void EmitInstruction(const MachineInstr *MI) override; void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O); + raw_ostream &O) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O); + raw_ostream &O) override; + + void EmitEndOfAsmFile(Module &M) override; + + void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, + const MachineInstr &MI); + void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, + const MachineInstr &MI); + void EmitTlsCall(const MachineInstr *MI, MCSymbolRefExpr::VariantKind VK); + bool runOnMachineFunction(MachineFunction &MF) override { + Subtarget = &MF.getSubtarget(); + return AsmPrinter::runOnMachineFunction(MF); + } }; /// PPCLinuxAsmPrinter - PowerPC assembly printer, customized for Linux class PPCLinuxAsmPrinter : public PPCAsmPrinter { public: - explicit PPCLinuxAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : PPCAsmPrinter(TM, Streamer) {} + explicit PPCLinuxAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) + : PPCAsmPrinter(TM, std::move(Streamer)) {} - virtual const char *getPassName() const { + const char *getPassName() const override { return "Linux PPC Assembly Printer"; } - bool doFinalization(Module &M); + bool doFinalization(Module &M) override; + void EmitStartOfAsmFile(Module &M) override; - virtual void EmitFunctionEntryLabel(); + void EmitFunctionEntryLabel() override; - void EmitFunctionBodyEnd(); + void EmitFunctionBodyStart() override; + void EmitFunctionBodyEnd() override; }; /// PPCDarwinAsmPrinter - PowerPC assembly printer, customized for Darwin/Mac /// OS X class PPCDarwinAsmPrinter : public PPCAsmPrinter { public: - explicit PPCDarwinAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : PPCAsmPrinter(TM, Streamer) {} + explicit PPCDarwinAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) + : PPCAsmPrinter(TM, std::move(Streamer)) {} - virtual const char *getPassName() const { + const char *getPassName() const override { return "Darwin PPC Assembly Printer"; } - bool doFinalization(Module &M); - void EmitStartOfAsmFile(Module &M); + bool doFinalization(Module &M) override; + void EmitStartOfAsmFile(Module &M) override; void EmitFunctionStubs(const MachineModuleInfoMachO::SymbolListTy &Stubs); }; @@ -129,23 +151,29 @@ static const char *stripRegisterPrefix(const char *RegName) { switch (RegName[0]) { case 'r': case 'f': - case 'v': return RegName + 1; + case 'q': // for QPX + case 'v': + if (RegName[1] == 's') + return RegName + 2; + return RegName + 1; case 'c': if (RegName[1] == 'r') return RegName + 2; } - + return RegName; } void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { + const DataLayout &DL = getDataLayout(); const MachineOperand &MO = MI->getOperand(OpNo); - + switch (MO.getType()) { case MachineOperand::MO_Register: { const char *RegName = PPCInstPrinter::getRegisterName(MO.getReg()); // Linux assembler (Others?) does not take register mnemonics. // FIXME - What about special registers used in mfspr/mtspr? - if (!Subtarget.isDarwin()) RegName = stripRegisterPrefix(RegName); + if (!Subtarget->isDarwin()) + RegName = stripRegisterPrefix(RegName); O << RegName; return; } @@ -154,39 +182,15 @@ void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, return; case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(); - return; - case MachineOperand::MO_JumpTableIndex: - O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() - << '_' << MO.getIndex(); - // FIXME: PIC relocation model + MO.getMBB()->getSymbol()->print(O, MAI); return; case MachineOperand::MO_ConstantPoolIndex: - O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() - << '_' << MO.getIndex(); + O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' + << MO.getIndex(); return; case MachineOperand::MO_BlockAddress: - O << *GetBlockAddressSymbol(MO.getBlockAddress()); + GetBlockAddressSymbol(MO.getBlockAddress())->print(O, MAI); return; - case MachineOperand::MO_ExternalSymbol: { - // Computing the address of an external symbol, not calling it. - if (TM.getRelocationModel() == Reloc::Static) { - O << *GetExternalSymbolSymbol(MO.getSymbolName()); - return; - } - - MCSymbol *NLPSym = - OutContext.GetOrCreateSymbol(StringRef(MAI->getGlobalPrefix())+ - MO.getSymbolName()+"$non_lazy_ptr"); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo().getGVStubEntry(NLPSym); - if (StubSym.getPointer() == 0) - StubSym = MachineModuleInfoImpl:: - StubValueTy(GetExternalSymbolSymbol(MO.getSymbolName()), true); - - O << *NLPSym; - return; - } case MachineOperand::MO_GlobalAddress: { // Computing the address of a global symbol, not calling it. const GlobalValue *GV = MO.getGlobal(); @@ -194,40 +198,40 @@ void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, // External or weakly linked global variables need non-lazily-resolved stubs if (TM.getRelocationModel() != Reloc::Static && - (GV->isDeclaration() || GV->isWeakForLinker())) { + !GV->isStrongDefinitionForLinker()) { if (!GV->hasHiddenVisibility()) { - SymToPrint = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo() - .getGVStubEntry(SymToPrint); - if (StubSym.getPointer() == 0) + SymToPrint = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getGVStubEntry( + SymToPrint); + if (!StubSym.getPointer()) StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + StubValueTy(getSymbol(GV), !GV->hasInternalLinkage()); } else if (GV->isDeclaration() || GV->hasCommonLinkage() || GV->hasAvailableExternallyLinkage()) { - SymToPrint = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo(). - getHiddenGVStubEntry(SymToPrint); - if (StubSym.getPointer() == 0) + SymToPrint = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getHiddenGVStubEntry( + SymToPrint); + if (!StubSym.getPointer()) StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + StubValueTy(getSymbol(GV), !GV->hasInternalLinkage()); } else { - SymToPrint = Mang->getSymbol(GV); + SymToPrint = getSymbol(GV); } } else { - SymToPrint = Mang->getSymbol(GV); + SymToPrint = getSymbol(GV); } - - O << *SymToPrint; + + SymToPrint->print(O, MAI); printOffset(MO.getOffset(), O); return; } default: - O << ""; + O << ""; return; } } @@ -284,11 +288,24 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, case 'y': // A memory reference for an X-form instruction { const char *RegName = "r0"; - if (!Subtarget.isDarwin()) RegName = stripRegisterPrefix(RegName); + if (!Subtarget->isDarwin()) + RegName = stripRegisterPrefix(RegName); O << RegName << ", "; printOperand(MI, OpNo, O); return false; } + case 'U': // Print 'u' for update form. + case 'X': // Print 'x' for indexed form. + { + // FIXME: Currently for PowerPC memory operands are always loaded + // into a register, so we never get an update or indexed form. + // This is bad even for offset forms, since even if we know we + // have a value in -16(r1), we will generate a load into r + // and then load from 0(r). Until that issue is fixed, + // tolerate 'U' and 'X' but don't output anything. + assert(MI->getOperand(OpNo).isReg()); + return false; + } } } @@ -299,60 +316,317 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, return false; } - /// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry /// exists for it. If not, create one. Then return a symbol that references /// the TOC entry. MCSymbol *PPCAsmPrinter::lookUpOrCreateTOCEntry(MCSymbol *Sym) { - MCSymbol *&TOCEntry = TOC[Sym]; + if (!TOCEntry) + TOCEntry = createTempSymbol("C"); + return TOCEntry; +} - // To avoid name clash check if the name already exists. - while (TOCEntry == 0) { - if (OutContext.LookupSymbol(Twine(MAI->getPrivateGlobalPrefix()) + - "C" + Twine(TOCLabelID++)) == 0) { - TOCEntry = GetTempSymbol("C", TOCLabelID); +void PPCAsmPrinter::EmitEndOfAsmFile(Module &M) { + SM.serializeToStackMapSection(); +} + +void PPCAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, + const MachineInstr &MI) { + unsigned NumNOPBytes = MI.getOperand(1).getImm(); + + SM.recordStackMap(MI); + assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); + + // Scan ahead to trim the shadow. + const MachineBasicBlock &MBB = *MI.getParent(); + MachineBasicBlock::const_iterator MII(MI); + ++MII; + while (NumNOPBytes > 0) { + if (MII == MBB.end() || MII->isCall() || + MII->getOpcode() == PPC::DBG_VALUE || + MII->getOpcode() == TargetOpcode::PATCHPOINT || + MII->getOpcode() == TargetOpcode::STACKMAP) + break; + ++MII; + NumNOPBytes -= 4; + } + + // Emit nops. + for (unsigned i = 0; i < NumNOPBytes; i += 4) + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::NOP)); +} + +// Lower a patchpoint of the form: +// [], , , , +void PPCAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, + const MachineInstr &MI) { + SM.recordPatchPoint(MI); + PatchPointOpers Opers(&MI); + + unsigned EncodedBytes = 0; + const MachineOperand &CalleeMO = + Opers.getMetaOper(PatchPointOpers::TargetPos); + + if (CalleeMO.isImm()) { + int64_t CallTarget = Opers.getMetaOper(PatchPointOpers::TargetPos).getImm(); + if (CallTarget) { + assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget && + "High 16 bits of call target should be zero."); + unsigned ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg(); + EncodedBytes = 0; + // Materialize the jump address: + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::LI8) + .addReg(ScratchReg) + .addImm((CallTarget >> 32) & 0xFFFF)); + ++EncodedBytes; + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::RLDIC) + .addReg(ScratchReg) + .addReg(ScratchReg) + .addImm(32).addImm(16)); + ++EncodedBytes; + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::ORIS8) + .addReg(ScratchReg) + .addReg(ScratchReg) + .addImm((CallTarget >> 16) & 0xFFFF)); + ++EncodedBytes; + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::ORI8) + .addReg(ScratchReg) + .addReg(ScratchReg) + .addImm(CallTarget & 0xFFFF)); + + // Save the current TOC pointer before the remote call. + int TOCSaveOffset = Subtarget->isELFv2ABI() ? 24 : 40; + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::STD) + .addReg(PPC::X2) + .addImm(TOCSaveOffset) + .addReg(PPC::X1)); + ++EncodedBytes; + + // If we're on ELFv1, then we need to load the actual function pointer + // from the function descriptor. + if (!Subtarget->isELFv2ABI()) { + // Load the new TOC pointer and the function address, but not r11 + // (needing this is rare, and loading it here would prevent passing it + // via a 'nest' parameter. + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::LD) + .addReg(PPC::X2) + .addImm(8) + .addReg(ScratchReg)); + ++EncodedBytes; + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::LD) + .addReg(ScratchReg) + .addImm(0) + .addReg(ScratchReg)); + ++EncodedBytes; + } + + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::MTCTR8) + .addReg(ScratchReg)); + ++EncodedBytes; + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::BCTRL8)); + ++EncodedBytes; + + // Restore the TOC pointer after the call. + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::LD) + .addReg(PPC::X2) + .addImm(TOCSaveOffset) + .addReg(PPC::X1)); + ++EncodedBytes; } + } else if (CalleeMO.isGlobal()) { + const GlobalValue *GValue = CalleeMO.getGlobal(); + MCSymbol *MOSymbol = getSymbol(GValue); + const MCExpr *SymVar = MCSymbolRefExpr::create(MOSymbol, OutContext); + + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::BL8_NOP) + .addExpr(SymVar)); + EncodedBytes += 2; } - return TOCEntry; + // Each instruction is 4 bytes. + EncodedBytes *= 4; + + // Emit padding. + unsigned NumBytes = Opers.getMetaOper(PatchPointOpers::NBytesPos).getImm(); + assert(NumBytes >= EncodedBytes && + "Patchpoint can't request size less than the length of a call."); + assert((NumBytes - EncodedBytes) % 4 == 0 && + "Invalid number of NOP bytes requested!"); + for (unsigned i = EncodedBytes; i < NumBytes; i += 4) + EmitToStreamer(OutStreamer, MCInstBuilder(PPC::NOP)); } +/// EmitTlsCall -- Given a GETtls[ld]ADDR[32] instruction, print a +/// call to __tls_get_addr to the current output stream. +void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI, + MCSymbolRefExpr::VariantKind VK) { + StringRef Name = "__tls_get_addr"; + MCSymbol *TlsGetAddr = OutContext.getOrCreateSymbol(Name); + MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; + + assert(MI->getOperand(0).isReg() && + ((Subtarget->isPPC64() && MI->getOperand(0).getReg() == PPC::X3) || + (!Subtarget->isPPC64() && MI->getOperand(0).getReg() == PPC::R3)) && + "GETtls[ld]ADDR[32] must define GPR3"); + assert(MI->getOperand(1).isReg() && + ((Subtarget->isPPC64() && MI->getOperand(1).getReg() == PPC::X3) || + (!Subtarget->isPPC64() && MI->getOperand(1).getReg() == PPC::R3)) && + "GETtls[ld]ADDR[32] must read GPR3"); + + if (!Subtarget->isPPC64() && !Subtarget->isDarwin() && + TM.getRelocationModel() == Reloc::PIC_) + Kind = MCSymbolRefExpr::VK_PLT; + const MCSymbolRefExpr *TlsRef = + MCSymbolRefExpr::create(TlsGetAddr, Kind, OutContext); + const MachineOperand &MO = MI->getOperand(2); + const GlobalValue *GValue = MO.getGlobal(); + MCSymbol *MOSymbol = getSymbol(GValue); + const MCExpr *SymVar = MCSymbolRefExpr::create(MOSymbol, VK, OutContext); + EmitToStreamer(*OutStreamer, + MCInstBuilder(Subtarget->isPPC64() ? + PPC::BL8_NOP_TLS : PPC::BL_TLS) + .addExpr(TlsRef) + .addExpr(SymVar)); +} /// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to /// the current output stream. /// void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { MCInst TmpInst; - + bool isPPC64 = Subtarget->isPPC64(); + bool isDarwin = TM.getTargetTriple().isOSDarwin(); + const Module *M = MF->getFunction()->getParent(); + PICLevel::Level PL = M->getPICLevel(); + // Lower multi-instruction pseudo operations. switch (MI->getOpcode()) { default: break; case TargetOpcode::DBG_VALUE: llvm_unreachable("Should be handled target independently"); + case TargetOpcode::STACKMAP: + return LowerSTACKMAP(*OutStreamer, SM, *MI); + case TargetOpcode::PATCHPOINT: + return LowerPATCHPOINT(*OutStreamer, SM, *MI); + + case PPC::MoveGOTtoLR: { + // Transform %LR = MoveGOTtoLR + // Into this: bl _GLOBAL_OFFSET_TABLE_@local-4 + // _GLOBAL_OFFSET_TABLE_@local-4 (instruction preceding + // _GLOBAL_OFFSET_TABLE_) has exactly one instruction: + // blrl + // This will return the pointer to _GLOBAL_OFFSET_TABLE_@local + MCSymbol *GOTSymbol = + OutContext.getOrCreateSymbol(StringRef("_GLOBAL_OFFSET_TABLE_")); + const MCExpr *OffsExpr = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(GOTSymbol, + MCSymbolRefExpr::VK_PPC_LOCAL, + OutContext), + MCConstantExpr::create(4, OutContext), + OutContext); + + // Emit the 'bl'. + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL).addExpr(OffsExpr)); + return; + } case PPC::MovePCtoLR: case PPC::MovePCtoLR8: { // Transform %LR = MovePCtoLR - // Into this, where the label is the PIC base: + // Into this, where the label is the PIC base: // bl L1$pb // L1$pb: MCSymbol *PICBase = MF->getPICBaseSymbol(); - + // Emit the 'bl'. - OutStreamer.EmitInstruction(MCInstBuilder(PPC::BL) - // FIXME: We would like an efficient form for this, so we don't have to do - // a lot of extra uniquing. - .addExpr(MCSymbolRefExpr::Create(PICBase, OutContext))); - + EmitToStreamer(*OutStreamer, + MCInstBuilder(PPC::BL) + // FIXME: We would like an efficient form for this, so we + // don't have to do a lot of extra uniquing. + .addExpr(MCSymbolRefExpr::create(PICBase, OutContext))); + // Emit the label. - OutStreamer.EmitLabel(PICBase); + OutStreamer->EmitLabel(PICBase); + return; + } + case PPC::UpdateGBR: { + // Transform %Rd = UpdateGBR(%Rt, %Ri) + // Into: lwz %Rt, .L0$poff - .L0$pb(%Ri) + // add %Rd, %Rt, %Ri + // Get the offset from the GOT Base Register to the GOT + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); + MCSymbol *PICOffset = + MF->getInfo()->getPICOffsetSymbol(); + TmpInst.setOpcode(PPC::LWZ); + const MCExpr *Exp = + MCSymbolRefExpr::create(PICOffset, MCSymbolRefExpr::VK_None, OutContext); + const MCExpr *PB = + MCSymbolRefExpr::create(MF->getPICBaseSymbol(), + MCSymbolRefExpr::VK_None, + OutContext); + const MCOperand TR = TmpInst.getOperand(1); + const MCOperand PICR = TmpInst.getOperand(0); + + // Step 1: lwz %Rt, .L$poff - .L$pb(%Ri) + TmpInst.getOperand(1) = + MCOperand::createExpr(MCBinaryExpr::createSub(Exp, PB, OutContext)); + TmpInst.getOperand(0) = TR; + TmpInst.getOperand(2) = PICR; + EmitToStreamer(*OutStreamer, TmpInst); + + TmpInst.setOpcode(PPC::ADD4); + TmpInst.getOperand(0) = PICR; + TmpInst.getOperand(1) = TR; + TmpInst.getOperand(2) = PICR; + EmitToStreamer(*OutStreamer, TmpInst); + return; + } + case PPC::LWZtoc: { + // Transform %R3 = LWZtoc , %R2 + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); + + // Change the opcode to LWZ, and the global address operand to be a + // reference to the GOT entry we will synthesize later. + TmpInst.setOpcode(PPC::LWZ); + const MachineOperand &MO = MI->getOperand(1); + + // Map symbol -> label of TOC entry + assert(MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()); + MCSymbol *MOSymbol = nullptr; + if (MO.isGlobal()) + MOSymbol = getSymbol(MO.getGlobal()); + else if (MO.isCPI()) + MOSymbol = GetCPISymbol(MO.getIndex()); + else if (MO.isJTI()) + MOSymbol = GetJTISymbol(MO.getIndex()); + else if (MO.isBlockAddress()) + MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); + + if (PL == PICLevel::Small) { + const MCExpr *Exp = + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_GOT, + OutContext); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + } else { + MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); + + const MCExpr *Exp = + MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_None, + OutContext); + const MCExpr *PB = + MCSymbolRefExpr::create(OutContext.getOrCreateSymbol(Twine(".LTOC")), + OutContext); + Exp = MCBinaryExpr::createSub(Exp, PB, OutContext); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + } + EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::LDtocJTI: case PPC::LDtocCPT: + case PPC::LDtocBA: case PPC::LDtoc: { // Transform %X3 = LDtoc , %X2 - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin()); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); // Change the opcode to LD, and the global address operand to be a // reference to the TOC entry we will synthesize later. @@ -360,109 +634,118 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { const MachineOperand &MO = MI->getOperand(1); // Map symbol -> label of TOC entry - assert(MO.isGlobal() || MO.isCPI() || MO.isJTI()); - MCSymbol *MOSymbol = 0; + assert(MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()); + MCSymbol *MOSymbol = nullptr; if (MO.isGlobal()) - MOSymbol = Mang->getSymbol(MO.getGlobal()); + MOSymbol = getSymbol(MO.getGlobal()); else if (MO.isCPI()) MOSymbol = GetCPISymbol(MO.getIndex()); else if (MO.isJTI()) MOSymbol = GetJTISymbol(MO.getIndex()); + else if (MO.isBlockAddress()) + MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); const MCExpr *Exp = - MCSymbolRefExpr::Create(TOCEntry, MCSymbolRefExpr::VK_PPC_TOC, + MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_PPC_TOC, OutContext); - TmpInst.getOperand(1) = MCOperand::CreateExpr(Exp); - OutStreamer.EmitInstruction(TmpInst); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); return; } - + case PPC::ADDIStocHA: { // Transform %Xd = ADDIStocHA %X2, - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin()); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); - // Change the opcode to ADDIS8. If the global address is external, - // has common linkage, is a function address, or is a jump table + // Change the opcode to ADDIS8. If the global address is external, has + // common linkage, is a non-local function address, or is a jump table // address, then generate a TOC entry and reference that. Otherwise // reference the symbol directly. TmpInst.setOpcode(PPC::ADDIS8); const MachineOperand &MO = MI->getOperand(2); - assert((MO.isGlobal() || MO.isCPI() || MO.isJTI()) && + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || + MO.isBlockAddress()) && "Invalid operand for ADDIStocHA!"); - MCSymbol *MOSymbol = 0; + MCSymbol *MOSymbol = nullptr; bool IsExternal = false; - bool IsFunction = false; + bool IsNonLocalFunction = false; bool IsCommon = false; bool IsAvailExt = false; if (MO.isGlobal()) { - const GlobalValue *GValue = MO.getGlobal(); - const GlobalAlias *GAlias = dyn_cast(GValue); - const GlobalValue *RealGValue = GAlias ? - GAlias->resolveAliasedGlobal(false) : GValue; - MOSymbol = Mang->getSymbol(RealGValue); - const GlobalVariable *GVar = dyn_cast(RealGValue); - IsExternal = GVar && !GVar->hasInitializer(); - IsCommon = GVar && RealGValue->hasCommonLinkage(); - IsFunction = !GVar; - IsAvailExt = GVar && RealGValue->hasAvailableExternallyLinkage(); + const GlobalValue *GV = MO.getGlobal(); + MOSymbol = getSymbol(GV); + IsExternal = GV->isDeclaration(); + IsCommon = GV->hasCommonLinkage(); + IsNonLocalFunction = GV->getType()->getElementType()->isFunctionTy() && + !GV->isStrongDefinitionForLinker(); + IsAvailExt = GV->hasAvailableExternallyLinkage(); } else if (MO.isCPI()) MOSymbol = GetCPISymbol(MO.getIndex()); else if (MO.isJTI()) MOSymbol = GetJTISymbol(MO.getIndex()); + else if (MO.isBlockAddress()) + MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); - if (IsExternal || IsFunction || IsCommon || IsAvailExt || MO.isJTI()) + if (IsExternal || IsNonLocalFunction || IsCommon || IsAvailExt || + MO.isJTI() || MO.isBlockAddress() || + TM.getCodeModel() == CodeModel::Large) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); const MCExpr *Exp = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_HA, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_HA, OutContext); - TmpInst.getOperand(2) = MCOperand::CreateExpr(Exp); - OutStreamer.EmitInstruction(TmpInst); + TmpInst.getOperand(2) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::LDtocL: { // Transform %Xd = LDtocL , %Xs - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin()); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); // Change the opcode to LD. If the global address is external, has // common linkage, or is a jump table address, then reference the // associated TOC entry. Otherwise reference the symbol directly. TmpInst.setOpcode(PPC::LD); const MachineOperand &MO = MI->getOperand(1); - assert((MO.isGlobal() || MO.isJTI() || MO.isCPI()) && + assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || + MO.isBlockAddress()) && "Invalid operand for LDtocL!"); - MCSymbol *MOSymbol = 0; + MCSymbol *MOSymbol = nullptr; if (MO.isJTI()) MOSymbol = lookUpOrCreateTOCEntry(GetJTISymbol(MO.getIndex())); - else if (MO.isCPI()) + else if (MO.isBlockAddress()) { + MOSymbol = GetBlockAddressSymbol(MO.getBlockAddress()); + MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); + } + else if (MO.isCPI()) { MOSymbol = GetCPISymbol(MO.getIndex()); + if (TM.getCodeModel() == CodeModel::Large) + MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); + } else if (MO.isGlobal()) { const GlobalValue *GValue = MO.getGlobal(); - const GlobalAlias *GAlias = dyn_cast(GValue); - const GlobalValue *RealGValue = GAlias ? - GAlias->resolveAliasedGlobal(false) : GValue; - MOSymbol = Mang->getSymbol(RealGValue); - const GlobalVariable *GVar = dyn_cast(RealGValue); - - if (!GVar || !GVar->hasInitializer() || RealGValue->hasCommonLinkage() || - RealGValue->hasAvailableExternallyLinkage()) + MOSymbol = getSymbol(GValue); + if (GValue->getType()->getElementType()->isFunctionTy() || + GValue->isDeclaration() || GValue->hasCommonLinkage() || + GValue->hasAvailableExternallyLinkage() || + TM.getCodeModel() == CodeModel::Large) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); } const MCExpr *Exp = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_LO, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext); - TmpInst.getOperand(1) = MCOperand::CreateExpr(Exp); - OutStreamer.EmitInstruction(TmpInst); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::ADDItocL: { // Transform %Xd = ADDItocL %Xs, - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin()); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); // Change the opcode to ADDI8. If the global address is external, then // generate a TOC entry and reference that. Otherwise reference the @@ -470,235 +753,265 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { TmpInst.setOpcode(PPC::ADDI8); const MachineOperand &MO = MI->getOperand(2); assert((MO.isGlobal() || MO.isCPI()) && "Invalid operand for ADDItocL"); - MCSymbol *MOSymbol = 0; + MCSymbol *MOSymbol = nullptr; bool IsExternal = false; - bool IsFunction = false; + bool IsNonLocalFunction = false; if (MO.isGlobal()) { - const GlobalValue *GValue = MO.getGlobal(); - const GlobalAlias *GAlias = dyn_cast(GValue); - const GlobalValue *RealGValue = GAlias ? - GAlias->resolveAliasedGlobal(false) : GValue; - MOSymbol = Mang->getSymbol(RealGValue); - const GlobalVariable *GVar = dyn_cast(RealGValue); - IsExternal = GVar && !GVar->hasInitializer(); - IsFunction = !GVar; + const GlobalValue *GV = MO.getGlobal(); + MOSymbol = getSymbol(GV); + IsExternal = GV->isDeclaration(); + IsNonLocalFunction = GV->getType()->getElementType()->isFunctionTy() && + !GV->isStrongDefinitionForLinker(); } else if (MO.isCPI()) MOSymbol = GetCPISymbol(MO.getIndex()); - if (IsFunction || IsExternal) + if (IsNonLocalFunction || IsExternal || + TM.getCodeModel() == CodeModel::Large) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); const MCExpr *Exp = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_LO, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext); - TmpInst.getOperand(2) = MCOperand::CreateExpr(Exp); - OutStreamer.EmitInstruction(TmpInst); + TmpInst.getOperand(2) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::ADDISgotTprelHA: { // Transform: %Xd = ADDISgotTprelHA %X2, // Into: %Xd = ADDIS8 %X2, sym@got@tlsgd@ha - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + assert(Subtarget->isPPC64() && "Not supported for 32-bit PowerPC"); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); + MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTprel = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS8) - .addReg(MI->getOperand(0).getReg()) - .addReg(PPC::X2) - .addExpr(SymGotTprel)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymGotTprel)); return; } - case PPC::LDgotTprelL: { + case PPC::LDgotTprelL: + case PPC::LDgotTprelL32: { // Transform %Xd = LDgotTprelL , %Xs - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin()); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); // Change the opcode to LD. - TmpInst.setOpcode(PPC::LD); + TmpInst.setOpcode(isPPC64 ? PPC::LD : PPC::LWZ); const MachineOperand &MO = MI->getOperand(1); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); + MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *Exp = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO, OutContext); - TmpInst.getOperand(1) = MCOperand::CreateExpr(Exp); - OutStreamer.EmitInstruction(TmpInst); + TmpInst.getOperand(1) = MCOperand::createExpr(Exp); + EmitToStreamer(*OutStreamer, TmpInst); + return; + } + + case PPC::PPC32PICGOT: { + MCSymbol *GOTSymbol = OutContext.getOrCreateSymbol(StringRef("_GLOBAL_OFFSET_TABLE_")); + MCSymbol *GOTRef = OutContext.createTempSymbol(); + MCSymbol *NextInstr = OutContext.createTempSymbol(); + + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL) + // FIXME: We would like an efficient form for this, so we don't have to do + // a lot of extra uniquing. + .addExpr(MCSymbolRefExpr::create(NextInstr, OutContext))); + const MCExpr *OffsExpr = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(GOTSymbol, OutContext), + MCSymbolRefExpr::create(GOTRef, OutContext), + OutContext); + OutStreamer->EmitLabel(GOTRef); + OutStreamer->EmitValue(OffsExpr, 4); + OutStreamer->EmitLabel(NextInstr); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR) + .addReg(MI->getOperand(0).getReg())); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LWZ) + .addReg(MI->getOperand(1).getReg()) + .addImm(0) + .addReg(MI->getOperand(0).getReg())); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADD4) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addReg(MI->getOperand(0).getReg())); + return; + } + case PPC::PPC32GOT: { + MCSymbol *GOTSymbol = + OutContext.getOrCreateSymbol(StringRef("_GLOBAL_OFFSET_TABLE_")); + const MCExpr *SymGotTlsL = MCSymbolRefExpr::create( + GOTSymbol, MCSymbolRefExpr::VK_PPC_LO, OutContext); + const MCExpr *SymGotTlsHA = MCSymbolRefExpr::create( + GOTSymbol, MCSymbolRefExpr::VK_PPC_HA, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LI) + .addReg(MI->getOperand(0).getReg()) + .addExpr(SymGotTlsL)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(0).getReg()) + .addExpr(SymGotTlsHA)); return; } case PPC::ADDIStlsgdHA: { // Transform: %Xd = ADDIStlsgdHA %X2, // Into: %Xd = ADDIS8 %X2, sym@got@tlsgd@ha - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + assert(Subtarget->isPPC64() && "Not supported for 32-bit PowerPC"); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); + MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTlsGD = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS8) - .addReg(MI->getOperand(0).getReg()) - .addReg(PPC::X2) - .addExpr(SymGotTlsGD)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymGotTlsGD)); return; } - case PPC::ADDItlsgdL: { + case PPC::ADDItlsgdL: // Transform: %Xd = ADDItlsgdL %Xs, // Into: %Xd = ADDI8 %Xs, sym@got@tlsgd@l - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + case PPC::ADDItlsgdL32: { + // Transform: %Rd = ADDItlsgdL32 %Rs, + // Into: %Rd = ADDI %Rs, sym@got@tlsgd const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); - const MCExpr *SymGotTlsGD = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO, - OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDI8) - .addReg(MI->getOperand(0).getReg()) - .addReg(MI->getOperand(1).getReg()) - .addExpr(SymGotTlsGD)); + MCSymbol *MOSymbol = getSymbol(GValue); + const MCExpr *SymGotTlsGD = MCSymbolRefExpr::create( + MOSymbol, Subtarget->isPPC64() ? MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO + : MCSymbolRefExpr::VK_PPC_GOT_TLSGD, + OutContext); + EmitToStreamer(*OutStreamer, + MCInstBuilder(Subtarget->isPPC64() ? PPC::ADDI8 : PPC::ADDI) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymGotTlsGD)); return; } - case PPC::GETtlsADDR: { + case PPC::GETtlsADDR: // Transform: %X3 = GETtlsADDR %X3, - // Into: BL8_NOP_TLS __tls_get_addr(sym@tlsgd) - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); - - StringRef Name = "__tls_get_addr"; - MCSymbol *TlsGetAddr = OutContext.GetOrCreateSymbol(Name); - const MCSymbolRefExpr *TlsRef = - MCSymbolRefExpr::Create(TlsGetAddr, MCSymbolRefExpr::VK_None, OutContext); - const MachineOperand &MO = MI->getOperand(2); - const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); - const MCExpr *SymVar = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_TLSGD, - OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::BL8_NOP_TLS) - .addExpr(TlsRef) - .addExpr(SymVar)); + // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsgd) + case PPC::GETtlsADDR32: { + // Transform: %R3 = GETtlsADDR32 %R3, + // Into: BL_TLS __tls_get_addr(sym at tlsgd)@PLT + EmitTlsCall(MI, MCSymbolRefExpr::VK_PPC_TLSGD); return; } case PPC::ADDIStlsldHA: { // Transform: %Xd = ADDIStlsldHA %X2, // Into: %Xd = ADDIS8 %X2, sym@got@tlsld@ha - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + assert(Subtarget->isPPC64() && "Not supported for 32-bit PowerPC"); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); + MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTlsLD = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS8) - .addReg(MI->getOperand(0).getReg()) - .addReg(PPC::X2) - .addExpr(SymGotTlsLD)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymGotTlsLD)); return; } - case PPC::ADDItlsldL: { + case PPC::ADDItlsldL: // Transform: %Xd = ADDItlsldL %Xs, // Into: %Xd = ADDI8 %Xs, sym@got@tlsld@l - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + case PPC::ADDItlsldL32: { + // Transform: %Rd = ADDItlsldL32 %Rs, + // Into: %Rd = ADDI %Rs, sym@got@tlsld const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); - const MCExpr *SymGotTlsLD = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO, - OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDI8) - .addReg(MI->getOperand(0).getReg()) - .addReg(MI->getOperand(1).getReg()) - .addExpr(SymGotTlsLD)); + MCSymbol *MOSymbol = getSymbol(GValue); + const MCExpr *SymGotTlsLD = MCSymbolRefExpr::create( + MOSymbol, Subtarget->isPPC64() ? MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO + : MCSymbolRefExpr::VK_PPC_GOT_TLSLD, + OutContext); + EmitToStreamer(*OutStreamer, + MCInstBuilder(Subtarget->isPPC64() ? PPC::ADDI8 : PPC::ADDI) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymGotTlsLD)); return; } - case PPC::GETtlsldADDR: { + case PPC::GETtlsldADDR: // Transform: %X3 = GETtlsldADDR %X3, - // Into: BL8_NOP_TLS __tls_get_addr(sym@tlsld) - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); - - StringRef Name = "__tls_get_addr"; - MCSymbol *TlsGetAddr = OutContext.GetOrCreateSymbol(Name); - const MCSymbolRefExpr *TlsRef = - MCSymbolRefExpr::Create(TlsGetAddr, MCSymbolRefExpr::VK_None, OutContext); - const MachineOperand &MO = MI->getOperand(2); - const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); - const MCExpr *SymVar = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_TLSLD, - OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::BL8_NOP_TLS) - .addExpr(TlsRef) - .addExpr(SymVar)); + // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsld) + case PPC::GETtlsldADDR32: { + // Transform: %R3 = GETtlsldADDR32 %R3, + // Into: BL_TLS __tls_get_addr(sym at tlsld)@PLT + EmitTlsCall(MI, MCSymbolRefExpr::VK_PPC_TLSLD); return; } - case PPC::ADDISdtprelHA: { - // Transform: %Xd = ADDISdtprelHA %X3, - // Into: %Xd = ADDIS8 %X3, sym@dtprel@ha - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + case PPC::ADDISdtprelHA: + // Transform: %Xd = ADDISdtprelHA %Xs, + // Into: %Xd = ADDIS8 %Xs, sym@dtprel@ha + case PPC::ADDISdtprelHA32: { + // Transform: %Rd = ADDISdtprelHA32 %Rs, + // Into: %Rd = ADDIS %Rs, sym@dtprel@ha const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); + MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymDtprel = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL_HA, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL_HA, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS8) - .addReg(MI->getOperand(0).getReg()) - .addReg(PPC::X3) - .addExpr(SymDtprel)); + EmitToStreamer( + *OutStreamer, + MCInstBuilder(Subtarget->isPPC64() ? PPC::ADDIS8 : PPC::ADDIS) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymDtprel)); return; } - case PPC::ADDIdtprelL: { + case PPC::ADDIdtprelL: // Transform: %Xd = ADDIdtprelL %Xs, // Into: %Xd = ADDI8 %Xs, sym@dtprel@l - assert(Subtarget.isPPC64() && "Not supported for 32-bit PowerPC"); + case PPC::ADDIdtprelL32: { + // Transform: %Rd = ADDIdtprelL32 %Rs, + // Into: %Rd = ADDI %Rs, sym@dtprel@l const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); - MCSymbol *MOSymbol = Mang->getSymbol(GValue); + MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymDtprel = - MCSymbolRefExpr::Create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL_LO, + MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL_LO, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDI8) - .addReg(MI->getOperand(0).getReg()) - .addReg(MI->getOperand(1).getReg()) - .addExpr(SymDtprel)); + EmitToStreamer(*OutStreamer, + MCInstBuilder(Subtarget->isPPC64() ? PPC::ADDI8 : PPC::ADDI) + .addReg(MI->getOperand(0).getReg()) + .addReg(MI->getOperand(1).getReg()) + .addExpr(SymDtprel)); return; } case PPC::MFOCRF: case PPC::MFOCRF8: - if (!Subtarget.hasMFOCRF()) { + if (!Subtarget->hasMFOCRF()) { // Transform: %R3 = MFOCRF %CR7 // Into: %R3 = MFCR ;; cr7 unsigned NewOpcode = MI->getOpcode() == PPC::MFOCRF ? PPC::MFCR : PPC::MFCR8; - OutStreamer.AddComment(PPCInstPrinter:: - getRegisterName(MI->getOperand(1).getReg())); - OutStreamer.EmitInstruction(MCInstBuilder(NewOpcode) + OutStreamer->AddComment(PPCInstPrinter:: + getRegisterName(MI->getOperand(1).getReg())); + EmitToStreamer(*OutStreamer, MCInstBuilder(NewOpcode) .addReg(MI->getOperand(0).getReg())); return; } break; case PPC::MTOCRF: case PPC::MTOCRF8: - if (!Subtarget.hasMFOCRF()) { + if (!Subtarget->hasMFOCRF()) { // Transform: %CR7 = MTOCRF %R3 // Into: MTCRF mask, %R3 ;; cr7 unsigned NewOpcode = MI->getOpcode() == PPC::MTOCRF ? PPC::MTCRF : PPC::MTCRF8; unsigned Mask = 0x80 >> OutContext.getRegisterInfo() ->getEncodingValue(MI->getOperand(0).getReg()); - OutStreamer.AddComment(PPCInstPrinter:: - getRegisterName(MI->getOperand(0).getReg())); - OutStreamer.EmitInstruction(MCInstBuilder(NewOpcode) - .addImm(Mask) - .addReg(MI->getOperand(1).getReg())); - return; - } - break; - case PPC::SYNC: - // In Book E sync is called msync, handle this special case here... - if (Subtarget.isBookE()) { - OutStreamer.EmitRawText(StringRef("\tmsync")); + OutStreamer->AddComment(PPCInstPrinter:: + getRegisterName(MI->getOperand(0).getReg())); + EmitToStreamer(*OutStreamer, MCInstBuilder(NewOpcode) + .addImm(Mask) + .addReg(MI->getOperand(1).getReg())); return; } break; @@ -712,7 +1025,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { // suite shows a handful of test cases that fail this check for // Darwin. Those need to be investigated before this sanity test // can be enabled for those subtargets. - if (!Subtarget.isDarwin()) { + if (!Subtarget->isDarwin()) { unsigned OpNum = (MI->getOpcode() == PPC::STD) ? 2 : 1; const MachineOperand &MO = MI->getOperand(OpNum); if (MO.isGlobal() && MO.getGlobal()->getAlignment() < 4) @@ -723,83 +1036,192 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { } } - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin()); - OutStreamer.EmitInstruction(TmpInst); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, isDarwin); + EmitToStreamer(*OutStreamer, TmpInst); +} + +void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) { + if (static_cast(TM).isELFv2ABI()) { + PPCTargetStreamer *TS = + static_cast(OutStreamer->getTargetStreamer()); + + if (TS) + TS->emitAbiVersion(2); + } + + if (static_cast(TM).isPPC64() || + TM.getRelocationModel() != Reloc::PIC_) + return AsmPrinter::EmitStartOfAsmFile(M); + + if (M.getPICLevel() == PICLevel::Small) + return AsmPrinter::EmitStartOfAsmFile(M); + + OutStreamer->SwitchSection(OutContext.getELFSection( + ".got2", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC)); + + MCSymbol *TOCSym = OutContext.getOrCreateSymbol(Twine(".LTOC")); + MCSymbol *CurrentPos = OutContext.createTempSymbol(); + + OutStreamer->EmitLabel(CurrentPos); + + // The GOT pointer points to the middle of the GOT, in order to reference the + // entire 64kB range. 0x8000 is the midpoint. + const MCExpr *tocExpr = + MCBinaryExpr::createAdd(MCSymbolRefExpr::create(CurrentPos, OutContext), + MCConstantExpr::create(0x8000, OutContext), + OutContext); + + OutStreamer->EmitAssignment(TOCSym, tocExpr); + + OutStreamer->SwitchSection(getObjFileLowering().getTextSection()); } void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { - if (!Subtarget.isPPC64()) // linux/ppc32 - Normal entry label. + // linux/ppc32 - Normal entry label. + if (!Subtarget->isPPC64() && + (TM.getRelocationModel() != Reloc::PIC_ || + MF->getFunction()->getParent()->getPICLevel() == PICLevel::Small)) return AsmPrinter::EmitFunctionEntryLabel(); - + + if (!Subtarget->isPPC64()) { + const PPCFunctionInfo *PPCFI = MF->getInfo(); + if (PPCFI->usesPICBase()) { + MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol(); + MCSymbol *PICBase = MF->getPICBaseSymbol(); + OutStreamer->EmitLabel(RelocSymbol); + + const MCExpr *OffsExpr = + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(OutContext.getOrCreateSymbol(Twine(".LTOC")), + OutContext), + MCSymbolRefExpr::create(PICBase, OutContext), + OutContext); + OutStreamer->EmitValue(OffsExpr, 4); + OutStreamer->EmitLabel(CurrentFnSym); + return; + } else + return AsmPrinter::EmitFunctionEntryLabel(); + } + + // ELFv2 ABI - Normal entry label. + if (Subtarget->isELFv2ABI()) + return AsmPrinter::EmitFunctionEntryLabel(); + // Emit an official procedure descriptor. - MCSectionSubPair Current = OutStreamer.getCurrentSection(); - const MCSectionELF *Section = OutStreamer.getContext().getELFSection(".opd", - ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC, - SectionKind::getReadOnly()); - OutStreamer.SwitchSection(Section); - OutStreamer.EmitLabel(CurrentFnSym); - OutStreamer.EmitValueToAlignment(8); - MCSymbol *Symbol1 = - OutContext.GetOrCreateSymbol(".L." + Twine(CurrentFnSym->getName())); + MCSectionSubPair Current = OutStreamer->getCurrentSection(); + MCSectionELF *Section = OutStreamer->getContext().getELFSection( + ".opd", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); + OutStreamer->SwitchSection(Section); + OutStreamer->EmitLabel(CurrentFnSym); + OutStreamer->EmitValueToAlignment(8); + MCSymbol *Symbol1 = CurrentFnSymForSize; // Generates a R_PPC64_ADDR64 (from FK_DATA_8) relocation for the function // entry point. - OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol1, OutContext), - 8 /*size*/); - MCSymbol *Symbol2 = OutContext.GetOrCreateSymbol(StringRef(".TOC.")); + OutStreamer->EmitValue(MCSymbolRefExpr::create(Symbol1, OutContext), + 8 /*size*/); + MCSymbol *Symbol2 = OutContext.getOrCreateSymbol(StringRef(".TOC.")); // Generates a R_PPC64_TOC relocation for TOC base insertion. - OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol2, - MCSymbolRefExpr::VK_PPC_TOCBASE, OutContext), - 8/*size*/); + OutStreamer->EmitValue( + MCSymbolRefExpr::create(Symbol2, MCSymbolRefExpr::VK_PPC_TOCBASE, OutContext), + 8/*size*/); // Emit a null environment pointer. - OutStreamer.EmitIntValue(0, 8 /* size */); - OutStreamer.SwitchSection(Current.first, Current.second); - - MCSymbol *RealFnSym = OutContext.GetOrCreateSymbol( - ".L." + Twine(CurrentFnSym->getName())); - OutStreamer.EmitLabel(RealFnSym); - CurrentFnSymForSize = RealFnSym; + OutStreamer->EmitIntValue(0, 8 /* size */); + OutStreamer->SwitchSection(Current.first, Current.second); } - bool PPCLinuxAsmPrinter::doFinalization(Module &M) { - const DataLayout *TD = TM.getDataLayout(); + const DataLayout &DL = getDataLayout(); - bool isPPC64 = TD->getPointerSizeInBits() == 64; + bool isPPC64 = DL.getPointerSizeInBits() == 64; - if (isPPC64 && !TOC.empty()) { - const MCSectionELF *Section = OutStreamer.getContext().getELFSection(".toc", - ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC, - SectionKind::getReadOnly()); - OutStreamer.SwitchSection(Section); + PPCTargetStreamer &TS = + static_cast(*OutStreamer->getTargetStreamer()); + + if (!TOC.empty()) { + MCSectionELF *Section; + + if (isPPC64) + Section = OutStreamer->getContext().getELFSection( + ".toc", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); + else + Section = OutStreamer->getContext().getELFSection( + ".got2", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); + OutStreamer->SwitchSection(Section); for (MapVector::iterator I = TOC.begin(), E = TOC.end(); I != E; ++I) { - OutStreamer.EmitLabel(I->second); - MCSymbol *S = OutContext.GetOrCreateSymbol(I->first->getName()); - OutStreamer.EmitTCEntry(*S); + OutStreamer->EmitLabel(I->second); + MCSymbol *S = I->first; + if (isPPC64) + TS.emitTCEntry(*S); + else + OutStreamer->EmitSymbolValue(S, 4); } } - MachineModuleInfoELF &MMIELF = - MMI->getObjFileInfo(); - - MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); - if (!Stubs.empty()) { - OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - // L_foo$stub: - OutStreamer.EmitLabel(Stubs[i].first); - // .long _foo - OutStreamer.EmitValue(MCSymbolRefExpr::Create(Stubs[i].second.getPointer(), - OutContext), - isPPC64 ? 8 : 4/*size*/); - } + return AsmPrinter::doFinalization(M); +} - Stubs.clear(); - OutStreamer.AddBlankLine(); +/// EmitFunctionBodyStart - Emit a global entry point prefix for ELFv2. +void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { + // In the ELFv2 ABI, in functions that use the TOC register, we need to + // provide two entry points. The ABI guarantees that when calling the + // local entry point, r2 is set up by the caller to contain the TOC base + // for this function, and when calling the global entry point, r12 is set + // up by the caller to hold the address of the global entry point. We + // thus emit a prefix sequence along the following lines: + // + // func: + // # global entry point + // addis r2,r12,(.TOC.-func)@ha + // addi r2,r2,(.TOC.-func)@l + // .localentry func, .-func + // # local entry point, followed by function body + // + // This ensures we have r2 set up correctly while executing the function + // body, no matter which entry point is called. + if (Subtarget->isELFv2ABI() + // Only do all that if the function uses r2 in the first place. + && !MF->getRegInfo().use_empty(PPC::X2)) { + + MCSymbol *GlobalEntryLabel = OutContext.createTempSymbol(); + OutStreamer->EmitLabel(GlobalEntryLabel); + const MCSymbolRefExpr *GlobalEntryLabelExp = + MCSymbolRefExpr::create(GlobalEntryLabel, OutContext); + + MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC.")); + const MCExpr *TOCDeltaExpr = + MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext), + GlobalEntryLabelExp, OutContext); + + const MCExpr *TOCDeltaHi = + PPCMCExpr::createHa(TOCDeltaExpr, false, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) + .addReg(PPC::X2) + .addReg(PPC::X12) + .addExpr(TOCDeltaHi)); + + const MCExpr *TOCDeltaLo = + PPCMCExpr::createLo(TOCDeltaExpr, false, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI) + .addReg(PPC::X2) + .addReg(PPC::X2) + .addExpr(TOCDeltaLo)); + + MCSymbol *LocalEntryLabel = OutContext.createTempSymbol(); + OutStreamer->EmitLabel(LocalEntryLabel); + const MCSymbolRefExpr *LocalEntryLabelExp = + MCSymbolRefExpr::create(LocalEntryLabel, OutContext); + const MCExpr *LocalOffsetExp = + MCBinaryExpr::createSub(LocalEntryLabelExp, + GlobalEntryLabelExp, OutContext); + + PPCTargetStreamer *TS = + static_cast(OutStreamer->getTargetStreamer()); + + if (TS) + TS->emitLocalEntry(cast(CurrentFnSym), LocalOffsetExp); } - - return AsmPrinter::doFinalization(M); } /// EmitFunctionBodyEnd - Print the traceback table before the .size @@ -813,9 +1235,9 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyEnd() { // FIXME: We should fill in the eight-byte mandatory fields as described in // the PPC64 ELF ABI (this is a low-priority item because GDB does not // currently make use of these fields). - if (Subtarget.isPPC64()) { - OutStreamer.EmitIntValue(0, 4/*size*/); - OutStreamer.EmitIntValue(0, 8/*size*/); + if (Subtarget->isPPC64()) { + OutStreamer->EmitIntValue(0, 4/*size*/); + OutStreamer->EmitIntValue(0, 8/*size*/); } } @@ -844,200 +1266,214 @@ void PPCDarwinAsmPrinter::EmitStartOfAsmFile(Module &M) { "ppc64le" }; - unsigned Directive = Subtarget.getDarwinDirective(); - if (Subtarget.hasMFOCRF() && Directive < PPC::DIR_970) - Directive = PPC::DIR_970; - if (Subtarget.hasAltivec() && Directive < PPC::DIR_7400) - Directive = PPC::DIR_7400; - if (Subtarget.isPPC64() && Directive < PPC::DIR_64) - Directive = PPC::DIR_64; - assert(Directive <= PPC::DIR_64 && "Directive out of range."); - - // FIXME: This is a total hack, finish mc'izing the PPC backend. - if (OutStreamer.hasRawTextSupport()) { - assert(Directive < array_lengthof(CPUDirectives) && - "CPUDirectives[] might not be up-to-date!"); - OutStreamer.EmitRawText("\t.machine " + Twine(CPUDirectives[Directive])); + // Get the numerically largest directive. + // FIXME: How should we merge darwin directives? + unsigned Directive = PPC::DIR_NONE; + for (const Function &F : M) { + const PPCSubtarget &STI = TM.getSubtarget(F); + unsigned FDir = STI.getDarwinDirective(); + Directive = Directive > FDir ? FDir : STI.getDarwinDirective(); + if (STI.hasMFOCRF() && Directive < PPC::DIR_970) + Directive = PPC::DIR_970; + if (STI.hasAltivec() && Directive < PPC::DIR_7400) + Directive = PPC::DIR_7400; + if (STI.isPPC64() && Directive < PPC::DIR_64) + Directive = PPC::DIR_64; } + assert(Directive <= PPC::DIR_64 && "Directive out of range."); + + assert(Directive < array_lengthof(CPUDirectives) && + "CPUDirectives[] might not be up-to-date!"); + PPCTargetStreamer &TStreamer = + *static_cast(OutStreamer->getTargetStreamer()); + TStreamer.emitMachine(CPUDirectives[Directive]); + // Prime text sections so they are adjacent. This reduces the likelihood a // large data or debug section causes a branch to exceed 16M limit. - const TargetLoweringObjectFileMachO &TLOFMacho = - static_cast(getObjFileLowering()); - OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection()); + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast(getObjFileLowering()); + OutStreamer->SwitchSection(TLOFMacho.getTextCoalSection()); if (TM.getRelocationModel() == Reloc::PIC_) { - OutStreamer.SwitchSection( + OutStreamer->SwitchSection( OutContext.getMachOSection("__TEXT", "__picsymbolstub1", - MCSectionMachO::S_SYMBOL_STUBS | - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + MachO::S_SYMBOL_STUBS | + MachO::S_ATTR_PURE_INSTRUCTIONS, 32, SectionKind::getText())); } else if (TM.getRelocationModel() == Reloc::DynamicNoPIC) { - OutStreamer.SwitchSection( + OutStreamer->SwitchSection( OutContext.getMachOSection("__TEXT","__symbol_stub1", - MCSectionMachO::S_SYMBOL_STUBS | - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + MachO::S_SYMBOL_STUBS | + MachO::S_ATTR_PURE_INSTRUCTIONS, 16, SectionKind::getText())); } - OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); + OutStreamer->SwitchSection(getObjFileLowering().getTextSection()); } static MCSymbol *GetLazyPtr(MCSymbol *Sym, MCContext &Ctx) { // Remove $stub suffix, add $lazy_ptr. StringRef NoStub = Sym->getName().substr(0, Sym->getName().size()-5); - return Ctx.GetOrCreateSymbol(NoStub + "$lazy_ptr"); + return Ctx.getOrCreateSymbol(NoStub + "$lazy_ptr"); } static MCSymbol *GetAnonSym(MCSymbol *Sym, MCContext &Ctx) { // Add $tmp suffix to $stub, yielding $stub$tmp. - return Ctx.GetOrCreateSymbol(Sym->getName() + "$tmp"); + return Ctx.getOrCreateSymbol(Sym->getName() + "$tmp"); } void PPCDarwinAsmPrinter:: EmitFunctionStubs(const MachineModuleInfoMachO::SymbolListTy &Stubs) { - bool isPPC64 = TM.getDataLayout()->getPointerSizeInBits() == 64; - bool isDarwin = Subtarget.isDarwin(); - - const TargetLoweringObjectFileMachO &TLOFMacho = - static_cast(getObjFileLowering()); + bool isPPC64 = getDataLayout().getPointerSizeInBits() == 64; + + // Construct a local MCSubtargetInfo and shadow EmitToStreamer here. + // This is because the MachineFunction won't exist (but have not yet been + // freed) and since we're at the global level we can use the default + // constructed subtarget. + std::unique_ptr STI(TM.getTarget().createMCSubtargetInfo( + TM.getTargetTriple().str(), TM.getTargetCPU(), + TM.getTargetFeatureString())); + auto EmitToStreamer = [&STI] (MCStreamer &S, const MCInst &Inst) { + S.EmitInstruction(Inst, *STI); + }; + + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast(getObjFileLowering()); // .lazy_symbol_pointer - const MCSection *LSPSection = TLOFMacho.getLazySymbolPointerSection(); - + MCSection *LSPSection = TLOFMacho.getLazySymbolPointerSection(); + // Output stubs for dynamically-linked functions if (TM.getRelocationModel() == Reloc::PIC_) { - const MCSection *StubSection = - OutContext.getMachOSection("__TEXT", "__picsymbolstub1", - MCSectionMachO::S_SYMBOL_STUBS | - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 32, SectionKind::getText()); + MCSection *StubSection = OutContext.getMachOSection( + "__TEXT", "__picsymbolstub1", + MachO::S_SYMBOL_STUBS | MachO::S_ATTR_PURE_INSTRUCTIONS, 32, + SectionKind::getText()); for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - OutStreamer.SwitchSection(StubSection); + OutStreamer->SwitchSection(StubSection); EmitAlignment(4); - + MCSymbol *Stub = Stubs[i].first; MCSymbol *RawSym = Stubs[i].second.getPointer(); MCSymbol *LazyPtr = GetLazyPtr(Stub, OutContext); MCSymbol *AnonSymbol = GetAnonSym(Stub, OutContext); - - OutStreamer.EmitLabel(Stub); - OutStreamer.EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); - const MCExpr *Anon = MCSymbolRefExpr::Create(AnonSymbol, OutContext); - const MCExpr *LazyPtrExpr = MCSymbolRefExpr::Create(LazyPtr, OutContext); + OutStreamer->EmitLabel(Stub); + OutStreamer->EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); + + const MCExpr *Anon = MCSymbolRefExpr::create(AnonSymbol, OutContext); + const MCExpr *LazyPtrExpr = MCSymbolRefExpr::create(LazyPtr, OutContext); const MCExpr *Sub = - MCBinaryExpr::CreateSub(LazyPtrExpr, Anon, OutContext); + MCBinaryExpr::createSub(LazyPtrExpr, Anon, OutContext); // mflr r0 - OutStreamer.EmitInstruction(MCInstBuilder(PPC::MFLR).addReg(PPC::R0)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR).addReg(PPC::R0)); // bcl 20, 31, AnonSymbol - OutStreamer.EmitInstruction(MCInstBuilder(PPC::BCLalways).addExpr(Anon)); - OutStreamer.EmitLabel(AnonSymbol); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BCLalways).addExpr(Anon)); + OutStreamer->EmitLabel(AnonSymbol); // mflr r11 - OutStreamer.EmitInstruction(MCInstBuilder(PPC::MFLR).addReg(PPC::R11)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR).addReg(PPC::R11)); // addis r11, r11, ha16(LazyPtr - AnonSymbol) - const MCExpr *SubHa16 = PPCMCExpr::CreateHa(Sub, isDarwin, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::ADDIS) + const MCExpr *SubHa16 = PPCMCExpr::createHa(Sub, true, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) .addReg(PPC::R11) .addReg(PPC::R11) .addExpr(SubHa16)); // mtlr r0 - OutStreamer.EmitInstruction(MCInstBuilder(PPC::MTLR).addReg(PPC::R0)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR).addReg(PPC::R0)); // ldu r12, lo16(LazyPtr - AnonSymbol)(r11) // lwzu r12, lo16(LazyPtr - AnonSymbol)(r11) - const MCExpr *SubLo16 = PPCMCExpr::CreateLo(Sub, isDarwin, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(isPPC64 ? PPC::LDU : PPC::LWZU) + const MCExpr *SubLo16 = PPCMCExpr::createLo(Sub, true, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(isPPC64 ? PPC::LDU : PPC::LWZU) .addReg(PPC::R12) .addExpr(SubLo16).addExpr(SubLo16) .addReg(PPC::R11)); // mtctr r12 - OutStreamer.EmitInstruction(MCInstBuilder(PPC::MTCTR).addReg(PPC::R12)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTCTR).addReg(PPC::R12)); // bctr - OutStreamer.EmitInstruction(MCInstBuilder(PPC::BCTR)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BCTR)); - OutStreamer.SwitchSection(LSPSection); - OutStreamer.EmitLabel(LazyPtr); - OutStreamer.EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); + OutStreamer->SwitchSection(LSPSection); + OutStreamer->EmitLabel(LazyPtr); + OutStreamer->EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); MCSymbol *DyldStubBindingHelper = - OutContext.GetOrCreateSymbol(StringRef("dyld_stub_binding_helper")); + OutContext.getOrCreateSymbol(StringRef("dyld_stub_binding_helper")); if (isPPC64) { // .quad dyld_stub_binding_helper - OutStreamer.EmitSymbolValue(DyldStubBindingHelper, 8); + OutStreamer->EmitSymbolValue(DyldStubBindingHelper, 8); } else { // .long dyld_stub_binding_helper - OutStreamer.EmitSymbolValue(DyldStubBindingHelper, 4); + OutStreamer->EmitSymbolValue(DyldStubBindingHelper, 4); } } - OutStreamer.AddBlankLine(); + OutStreamer->AddBlankLine(); return; } - - const MCSection *StubSection = - OutContext.getMachOSection("__TEXT","__symbol_stub1", - MCSectionMachO::S_SYMBOL_STUBS | - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 16, SectionKind::getText()); + + MCSection *StubSection = OutContext.getMachOSection( + "__TEXT", "__symbol_stub1", + MachO::S_SYMBOL_STUBS | MachO::S_ATTR_PURE_INSTRUCTIONS, 16, + SectionKind::getText()); for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { MCSymbol *Stub = Stubs[i].first; MCSymbol *RawSym = Stubs[i].second.getPointer(); MCSymbol *LazyPtr = GetLazyPtr(Stub, OutContext); - const MCExpr *LazyPtrExpr = MCSymbolRefExpr::Create(LazyPtr, OutContext); + const MCExpr *LazyPtrExpr = MCSymbolRefExpr::create(LazyPtr, OutContext); - OutStreamer.SwitchSection(StubSection); + OutStreamer->SwitchSection(StubSection); EmitAlignment(4); - OutStreamer.EmitLabel(Stub); - OutStreamer.EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); + OutStreamer->EmitLabel(Stub); + OutStreamer->EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); // lis r11, ha16(LazyPtr) const MCExpr *LazyPtrHa16 = - PPCMCExpr::CreateHa(LazyPtrExpr, isDarwin, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(PPC::LIS) + PPCMCExpr::createHa(LazyPtrExpr, true, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LIS) .addReg(PPC::R11) .addExpr(LazyPtrHa16)); // ldu r12, lo16(LazyPtr)(r11) // lwzu r12, lo16(LazyPtr)(r11) const MCExpr *LazyPtrLo16 = - PPCMCExpr::CreateLo(LazyPtrExpr, isDarwin, OutContext); - OutStreamer.EmitInstruction(MCInstBuilder(isPPC64 ? PPC::LDU : PPC::LWZU) + PPCMCExpr::createLo(LazyPtrExpr, true, OutContext); + EmitToStreamer(*OutStreamer, MCInstBuilder(isPPC64 ? PPC::LDU : PPC::LWZU) .addReg(PPC::R12) .addExpr(LazyPtrLo16).addExpr(LazyPtrLo16) .addReg(PPC::R11)); // mtctr r12 - OutStreamer.EmitInstruction(MCInstBuilder(PPC::MTCTR).addReg(PPC::R12)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTCTR).addReg(PPC::R12)); // bctr - OutStreamer.EmitInstruction(MCInstBuilder(PPC::BCTR)); + EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BCTR)); - OutStreamer.SwitchSection(LSPSection); - OutStreamer.EmitLabel(LazyPtr); - OutStreamer.EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); + OutStreamer->SwitchSection(LSPSection); + OutStreamer->EmitLabel(LazyPtr); + OutStreamer->EmitSymbolAttribute(RawSym, MCSA_IndirectSymbol); MCSymbol *DyldStubBindingHelper = - OutContext.GetOrCreateSymbol(StringRef("dyld_stub_binding_helper")); + OutContext.getOrCreateSymbol(StringRef("dyld_stub_binding_helper")); if (isPPC64) { // .quad dyld_stub_binding_helper - OutStreamer.EmitSymbolValue(DyldStubBindingHelper, 8); + OutStreamer->EmitSymbolValue(DyldStubBindingHelper, 8); } else { // .long dyld_stub_binding_helper - OutStreamer.EmitSymbolValue(DyldStubBindingHelper, 4); + OutStreamer->EmitSymbolValue(DyldStubBindingHelper, 4); } } - - OutStreamer.AddBlankLine(); -} + OutStreamer->AddBlankLine(); +} bool PPCDarwinAsmPrinter::doFinalization(Module &M) { - bool isPPC64 = TM.getDataLayout()->getPointerSizeInBits() == 64; + bool isPPC64 = getDataLayout().getPointerSizeInBits() == 64; // Darwin/PPC always uses mach-o. - const TargetLoweringObjectFileMachO &TLOFMacho = - static_cast(getObjFileLowering()); + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast(getObjFileLowering()); MachineModuleInfoMachO &MMIMacho = - MMI->getObjFileInfo(); - + MMI->getObjFileInfo(); + MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetFnStubList(); if (!Stubs.empty()) EmitFunctionStubs(Stubs); @@ -1045,37 +1481,37 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { if (MAI->doesSupportExceptionHandling() && MMI) { // Add the (possibly multiple) personalities to the set of global values. // Only referenced functions get into the Personalities list. - const std::vector &Personalities = MMI->getPersonalities(); - for (std::vector::const_iterator I = Personalities.begin(), - E = Personalities.end(); I != E; ++I) { - if (*I) { - MCSymbol *NLPSym = GetSymbolWithGlobalValueBase(*I, "$non_lazy_ptr"); + for (const Function *Personality : MMI->getPersonalities()) { + if (Personality) { + MCSymbol *NLPSym = + getSymbolWithGlobalValueBase(Personality, "$non_lazy_ptr"); MachineModuleInfoImpl::StubValueTy &StubSym = - MMIMacho.getGVStubEntry(NLPSym); - StubSym = MachineModuleInfoImpl::StubValueTy(Mang->getSymbol(*I), true); + MMIMacho.getGVStubEntry(NLPSym); + StubSym = + MachineModuleInfoImpl::StubValueTy(getSymbol(Personality), true); } } } // Output stubs for dynamically-linked functions. Stubs = MMIMacho.GetGVStubList(); - + // Output macho stubs for external and common global variables. if (!Stubs.empty()) { // Switch with ".non_lazy_symbol_pointer" directive. - OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); + OutStreamer->SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); EmitAlignment(isPPC64 ? 3 : 2); - + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { // L_foo$stub: - OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer->EmitLabel(Stubs[i].first); // .indirect_symbol _foo MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; - OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol); + OutStreamer->EmitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol); if (MCSym.getInt()) // External to current translation unit. - OutStreamer.EmitIntValue(0, isPPC64 ? 8 : 4/*size*/); + OutStreamer->EmitIntValue(0, isPPC64 ? 8 : 4/*size*/); else // Internal to current translation unit. // @@ -1083,32 +1519,32 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { // need to be indirect and pc-rel. We accomplish this by using NLPs. // However, sometimes the types are local to the file. So we need to // fill in the value for the NLP in those cases. - OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), - OutContext), + OutStreamer->EmitValue(MCSymbolRefExpr::create(MCSym.getPointer(), + OutContext), isPPC64 ? 8 : 4/*size*/); } Stubs.clear(); - OutStreamer.AddBlankLine(); + OutStreamer->AddBlankLine(); } Stubs = MMIMacho.GetHiddenGVStubList(); if (!Stubs.empty()) { - OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); + OutStreamer->SwitchSection(getObjFileLowering().getDataSection()); EmitAlignment(isPPC64 ? 3 : 2); - + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { // L_foo$stub: - OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer->EmitLabel(Stubs[i].first); // .long _foo - OutStreamer.EmitValue(MCSymbolRefExpr:: - Create(Stubs[i].second.getPointer(), - OutContext), - isPPC64 ? 8 : 4/*size*/); + OutStreamer->EmitValue(MCSymbolRefExpr:: + create(Stubs[i].second.getPointer(), + OutContext), + isPPC64 ? 8 : 4/*size*/); } Stubs.clear(); - OutStreamer.AddBlankLine(); + OutStreamer->AddBlankLine(); } // Funny Darwin hack: This flag tells the linker that no global symbols @@ -1116,7 +1552,7 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never generates // code that does this, it is always safe to set. - OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); + OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); return AsmPrinter::doFinalization(M); } @@ -1125,17 +1561,17 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) { /// for a MachineFunction to the given output stream, in a format that the /// Darwin assembler can deal with. /// -static AsmPrinter *createPPCAsmPrinterPass(TargetMachine &tm, - MCStreamer &Streamer) { - const PPCSubtarget *Subtarget = &tm.getSubtarget(); - - if (Subtarget->isDarwin()) - return new PPCDarwinAsmPrinter(tm, Streamer); - return new PPCLinuxAsmPrinter(tm, Streamer); +static AsmPrinter * +createPPCAsmPrinterPass(TargetMachine &tm, + std::unique_ptr &&Streamer) { + if (tm.getTargetTriple().isMacOSX()) + return new PPCDarwinAsmPrinter(tm, std::move(Streamer)); + return new PPCLinuxAsmPrinter(tm, std::move(Streamer)); } // Force static initialization. -extern "C" void LLVMInitializePowerPCAsmPrinter() { +extern "C" void LLVMInitializePowerPCAsmPrinter() { TargetRegistry::RegisterAsmPrinter(ThePPC32Target, createPPCAsmPrinterPass); TargetRegistry::RegisterAsmPrinter(ThePPC64Target, createPPCAsmPrinterPass); + TargetRegistry::RegisterAsmPrinter(ThePPC64LETarget, createPPCAsmPrinterPass); }