diff options
Diffstat (limited to 'llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp')
-rw-r--r-- | llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 593 |
1 files changed, 309 insertions, 284 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 4311df5dbeb8..bf5fe741bac8 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -83,8 +83,6 @@ protected: const PPCSubtarget *Subtarget = nullptr; StackMaps SM; - virtual MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO); - public: explicit PPCAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) @@ -100,7 +98,7 @@ public: return AsmPrinter::doInitialization(M); } - void EmitInstruction(const MachineInstr *MI) override; + void emitInstruction(const MachineInstr *MI) override; /// This function is for PrintAsmOperand and PrintAsmMemoryOperand, /// invoked by EmitMSInlineAsmStr and EmitGCCInlineAsmStr only. @@ -113,7 +111,7 @@ public: bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) override; - void EmitEndOfAsmFile(Module &M) override; + void emitEndOfAsmFile(Module &M) override; void LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI); void LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI); @@ -137,37 +135,41 @@ public: return "Linux PPC Assembly Printer"; } - bool doFinalization(Module &M) override; - void EmitStartOfAsmFile(Module &M) override; + void emitStartOfAsmFile(Module &M) override; + void emitEndOfAsmFile(Module &) override; - void EmitFunctionEntryLabel() override; + void emitFunctionEntryLabel() override; - void EmitFunctionBodyStart() override; - void EmitFunctionBodyEnd() override; - void EmitInstruction(const MachineInstr *MI) override; + void emitFunctionBodyStart() override; + void emitFunctionBodyEnd() override; + void emitInstruction(const MachineInstr *MI) override; }; class PPCAIXAsmPrinter : public PPCAsmPrinter { private: static void ValidateGV(const GlobalVariable *GV); -protected: - MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO) override; public: PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) - : PPCAsmPrinter(TM, std::move(Streamer)) {} + : PPCAsmPrinter(TM, std::move(Streamer)) { + if (MAI->isLittleEndian()) + report_fatal_error( + "cannot create AIX PPC Assembly Printer for a little-endian target"); + } StringRef getPassName() const override { return "AIX PPC Assembly Printer"; } + bool doInitialization(Module &M) override; + void SetupMachineFunction(MachineFunction &MF) override; - const MCExpr *lowerConstant(const Constant *CV) override; + void emitGlobalVariable(const GlobalVariable *GV) override; - void EmitGlobalVariable(const GlobalVariable *GV) override; + void emitFunctionDescriptor() override; - void EmitFunctionDescriptor() override; + void emitEndOfAsmFile(Module &) override; - void EmitEndOfAsmFile(Module &) override; + void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override; }; } // end anonymous namespace @@ -176,23 +178,7 @@ void PPCAsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) { // Computing the address of a global symbol, not calling it. const GlobalValue *GV = MO.getGlobal(); - MCSymbol *SymToPrint; - - // External or weakly linked global variables need non-lazily-resolved stubs - if (Subtarget->hasLazyResolverStub(GV)) { - SymToPrint = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry( - SymToPrint); - if (!StubSym.getPointer()) - StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV), - !GV->hasInternalLinkage()); - } else { - SymToPrint = getSymbol(GV); - } - - SymToPrint->print(O, MAI); - + getSymbol(GV)->print(O, MAI); printOffset(MO.getOffset(), O); } @@ -208,9 +194,7 @@ void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, // Linux assembler (Others?) does not take register mnemonics. // FIXME - What about special registers used in mfspr/mtspr? - if (!Subtarget->isDarwin()) - RegName = PPCRegisterInfo::stripRegisterPrefix(RegName); - O << RegName; + O << PPCRegisterInfo::stripRegisterPrefix(RegName); return; } case MachineOperand::MO_Immediate: @@ -298,18 +282,17 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, switch (ExtraCode[0]) { default: return true; // Unknown modifier. + case 'L': // A memory reference to the upper word of a double word op. + O << getDataLayout().getPointerSize() << "("; + printOperand(MI, OpNo, O); + O << ")"; + return false; case 'y': // A memory reference for an X-form instruction - { - const char *RegName = "r0"; - if (!Subtarget->isDarwin()) - RegName = PPCRegisterInfo::stripRegisterPrefix(RegName); - O << RegName << ", "; - printOperand(MI, OpNo, O); - return false; - } + O << "0, "; + 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 @@ -319,7 +302,6 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, assert(MI->getOperand(OpNo).isReg()); return false; } - } } assert(MI->getOperand(OpNo).isReg()); @@ -339,7 +321,7 @@ MCSymbol *PPCAsmPrinter::lookUpOrCreateTOCEntry(const MCSymbol *Sym) { return TOCEntry; } -void PPCAsmPrinter::EmitEndOfAsmFile(Module &M) { +void PPCAsmPrinter::emitEndOfAsmFile(Module &M) { emitStackMaps(SM); } @@ -348,7 +330,7 @@ void PPCAsmPrinter::LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI) { auto &Ctx = OutStreamer->getContext(); MCSymbol *MILabel = Ctx.createTempSymbol(); - OutStreamer->EmitLabel(MILabel); + OutStreamer->emitLabel(MILabel); SM.recordStackMap(*MILabel, MI); assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); @@ -377,7 +359,7 @@ void PPCAsmPrinter::LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI) { void PPCAsmPrinter::LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI) { auto &Ctx = OutStreamer->getContext(); MCSymbol *MILabel = Ctx.createTempSymbol(); - OutStreamer->EmitLabel(MILabel); + OutStreamer->emitLabel(MILabel); SM.recordPatchPoint(*MILabel, MI); PatchPointOpers Opers(&MI); @@ -516,16 +498,17 @@ void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI, /// Map a machine operand for a TOC pseudo-machine instruction to its /// corresponding MCSymbol. -MCSymbol *PPCAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) { +static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO, + AsmPrinter &AP) { switch (MO.getType()) { case MachineOperand::MO_GlobalAddress: - return getSymbol(MO.getGlobal()); + return AP.getSymbol(MO.getGlobal()); case MachineOperand::MO_ConstantPoolIndex: - return GetCPISymbol(MO.getIndex()); + return AP.GetCPISymbol(MO.getIndex()); case MachineOperand::MO_JumpTableIndex: - return GetJTISymbol(MO.getIndex()); + return AP.GetJTISymbol(MO.getIndex()); case MachineOperand::MO_BlockAddress: - return GetBlockAddressSymbol(MO.getBlockAddress()); + return AP.GetBlockAddressSymbol(MO.getBlockAddress()); default: llvm_unreachable("Unexpected operand type to get symbol."); } @@ -534,9 +517,8 @@ MCSymbol *PPCAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) { /// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to /// the current output stream. /// -void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { +void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { MCInst TmpInst; - const bool IsDarwin = TM.getTargetTriple().isOSDarwin(); const bool IsPPC64 = Subtarget->isPPC64(); const bool IsAIX = Subtarget->isAIXABI(); const Module *M = MF->getFunction().getParent(); @@ -614,7 +596,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { .addExpr(MCSymbolRefExpr::create(PICBase, OutContext))); // Emit the label. - OutStreamer->EmitLabel(PICBase); + OutStreamer->emitLabel(PICBase); return; } case PPC::UpdateGBR: { @@ -625,7 +607,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { // addis r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@ha // addi r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@l // Get the offset from the GOT Base Register to the GOT - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); if (Subtarget->isSecurePlt() && isPositionIndependent() ) { unsigned PICR = TmpInst.getOperand(0).getReg(); MCSymbol *BaseSymbol = OutContext.getOrCreateSymbol( @@ -637,19 +619,19 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { const MCExpr *DeltaExpr = MCBinaryExpr::createSub( MCSymbolRefExpr::create(BaseSymbol, OutContext), PB, OutContext); - const MCExpr *DeltaHi = PPCMCExpr::createHa(DeltaExpr, false, OutContext); + const MCExpr *DeltaHi = PPCMCExpr::createHa(DeltaExpr, OutContext); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::ADDIS).addReg(PICR).addReg(PICR).addExpr(DeltaHi)); - const MCExpr *DeltaLo = PPCMCExpr::createLo(DeltaExpr, false, OutContext); + const MCExpr *DeltaLo = PPCMCExpr::createLo(DeltaExpr, OutContext); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::ADDI).addReg(PICR).addReg(PICR).addExpr(DeltaLo)); return; } else { MCSymbol *PICOffset = - MF->getInfo<PPCFunctionInfo>()->getPICOffsetSymbol(); + MF->getInfo<PPCFunctionInfo>()->getPICOffsetSymbol(*MF); TmpInst.setOpcode(PPC::LWZ); const MCExpr *Exp = MCSymbolRefExpr::create(PICOffset, MCSymbolRefExpr::VK_None, OutContext); @@ -676,10 +658,8 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { } } case PPC::LWZtoc: { - assert(!IsDarwin && "TOC is an ELF/XCOFF construct."); - // Transform %rN = LWZtoc @op1, %r2 - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to LWZ. TmpInst.setOpcode(PPC::LWZ); @@ -689,7 +669,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { "Invalid operand for LWZtoc."); // Map the operand to its corresponding MCSymbol. - const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO); + const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); // Create a reference to the GOT entry for the symbol. The GOT entry will be // synthesized later. @@ -734,10 +714,8 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { case PPC::LDtocCPT: case PPC::LDtocBA: case PPC::LDtoc: { - assert(!IsDarwin && "TOC is an ELF/XCOFF construct"); - // Transform %x3 = LDtoc @min1, %x2 - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to LD. TmpInst.setOpcode(PPC::LD); @@ -750,7 +728,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { // global address operand to be a reference to the TOC entry we will // synthesize later. MCSymbol *TOCEntry = - lookUpOrCreateTOCEntry(getMCSymbolForTOCPseudoMO(MO)); + lookUpOrCreateTOCEntry(getMCSymbolForTOCPseudoMO(MO, *this)); const MCSymbolRefExpr::VariantKind VK = IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC; @@ -766,7 +744,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { " AIX."); // Transform %rd = ADDIStocHA %rA, @sym(%r2) - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to ADDIS. TmpInst.setOpcode(PPC::ADDIS); @@ -776,7 +754,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { "Invalid operand for ADDIStocHA."); // Map the machine operand to its corresponding MCSymbol. - MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); // Always use TOC on AIX. Map the global address operand to be a reference // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to @@ -796,7 +774,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { " AIX."); // Transform %rd = LWZtocL @sym, %rs. - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to lwz. TmpInst.setOpcode(PPC::LWZ); @@ -806,7 +784,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { "Invalid operand for LWZtocL."); // Map the machine operand to its corresponding MCSymbol. - MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); + MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); // Always use TOC on AIX. Map the global address operand to be a reference // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to @@ -821,10 +799,8 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { return; } case PPC::ADDIStocHA8: { - assert(!IsDarwin && "TOC is an ELF/XCOFF construct"); - // Transform %xd = ADDIStocHA8 %x2, @sym - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to ADDIS8. If the global address is the address of // an external symbol, is a jump table address, is a block address, or is a @@ -836,7 +812,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand for ADDIStocHA8!"); - const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); + const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); const bool GlobalToc = MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal()); @@ -861,10 +837,8 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { return; } case PPC::LDtocL: { - assert(!IsDarwin && "TOC is an ELF/XCOFF construct"); - // Transform %xd = LDtocL @sym, %xs - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to LD. If the global address is the address of // an external symbol, is a jump table address, is a block address, or is @@ -882,7 +856,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { "LDtocL used on symbol that could be accessed directly is " "invalid. Must match ADDIStocHA8.")); - const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); + const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this); if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); @@ -897,7 +871,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { } case PPC::ADDItocL: { // Transform %xd = ADDItocL %xs, @sym - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to ADDI8. If the global address is external, then // generate a TOC entry and reference that. Otherwise, reference the @@ -912,7 +886,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { "Interposable definitions must use indirect access.")); const MCExpr *Exp = - MCSymbolRefExpr::create(getMCSymbolForTOCPseudoMO(MO), + MCSymbolRefExpr::create(getMCSymbolForTOCPseudoMO(MO, *this), MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext); TmpInst.getOperand(2) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); @@ -937,7 +911,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { case PPC::LDgotTprelL: case PPC::LDgotTprelL32: { // Transform %xd = LDgotTprelL @sym, %xs - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); // Change the opcode to LD. TmpInst.setOpcode(IsPPC64 ? PPC::LD : PPC::LWZ); @@ -966,9 +940,9 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { MCBinaryExpr::createSub(MCSymbolRefExpr::create(GOTSymbol, OutContext), MCSymbolRefExpr::create(GOTRef, OutContext), OutContext); - OutStreamer->EmitLabel(GOTRef); - OutStreamer->EmitValue(OffsExpr, 4); - OutStreamer->EmitLabel(NextInstr); + 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) @@ -1167,10 +1141,11 @@ 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 (!IsDarwin) { - unsigned OpNum = (MI->getOpcode() == PPC::STD) ? 2 : 1; - const MachineOperand &MO = MI->getOperand(OpNum); - if (MO.isGlobal() && MO.getGlobal()->getAlignment() < 4) + unsigned OpNum = (MI->getOpcode() == PPC::STD) ? 2 : 1; + const MachineOperand &MO = MI->getOperand(OpNum); + if (MO.isGlobal()) { + const DataLayout &DL = MO.getGlobal()->getParent()->getDataLayout(); + if (MO.getGlobal()->getPointerAlignment(DL) < 4) llvm_unreachable("Global must be word-aligned for LD, STD, LWA!"); } // Now process the instruction normally. @@ -1178,17 +1153,17 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { } } - LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); + LowerPPCMachineInstrToMCInst(MI, TmpInst, *this); EmitToStreamer(*OutStreamer, TmpInst); } -void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { +void PPCLinuxAsmPrinter::emitInstruction(const MachineInstr *MI) { if (!Subtarget->isPPC64()) - return PPCAsmPrinter::EmitInstruction(MI); + return PPCAsmPrinter::emitInstruction(MI); switch (MI->getOpcode()) { default: - return PPCAsmPrinter::EmitInstruction(MI); + return PPCAsmPrinter::emitInstruction(MI); case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { // .begin: // b .end # lis 0, FuncId[16..32] @@ -1203,7 +1178,7 @@ void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { // of instructions change. MCSymbol *BeginOfSled = OutContext.createTempSymbol(); MCSymbol *EndOfSled = OutContext.createTempSymbol(); - OutStreamer->EmitLabel(BeginOfSled); + OutStreamer->emitLabel(BeginOfSled); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::B).addExpr( MCSymbolRefExpr::create(EndOfSled, OutContext))); @@ -1218,8 +1193,8 @@ void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { OutContext.getOrCreateSymbol("__xray_FunctionEntry"), OutContext))); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR8).addReg(PPC::X0)); - OutStreamer->EmitLabel(EndOfSled); - recordSled(BeginOfSled, *MI, SledKind::FUNCTION_ENTER); + OutStreamer->emitLabel(EndOfSled); + recordSled(BeginOfSled, *MI, SledKind::FUNCTION_ENTER, 2); break; } case TargetOpcode::PATCHABLE_RET: { @@ -1229,7 +1204,7 @@ void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { for (const auto &MO : make_range(std::next(MI->operands_begin()), MI->operands_end())) { MCOperand MCOp; - if (LowerPPCMachineOperandToMCOperand(MO, MCOp, *this, false)) + if (LowerPPCMachineOperandToMCOperand(MO, MCOp, *this)) RetInst.addOperand(MCOp); } @@ -1289,9 +1264,9 @@ void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { // // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number // of instructions change. - OutStreamer->EmitCodeAlignment(8); + OutStreamer->emitCodeAlignment(8); MCSymbol *BeginOfSled = OutContext.createTempSymbol(); - OutStreamer->EmitLabel(BeginOfSled); + OutStreamer->emitLabel(BeginOfSled); EmitToStreamer(*OutStreamer, RetInst); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); EmitToStreamer( @@ -1306,8 +1281,8 @@ void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR8).addReg(PPC::X0)); EmitToStreamer(*OutStreamer, RetInst); if (IsConditional) - OutStreamer->EmitLabel(FallthroughLabel); - recordSled(BeginOfSled, *MI, SledKind::FUNCTION_EXIT); + OutStreamer->emitLabel(FallthroughLabel); + recordSled(BeginOfSled, *MI, SledKind::FUNCTION_EXIT, 2); break; } case TargetOpcode::PATCHABLE_FUNCTION_EXIT: @@ -1320,7 +1295,7 @@ void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { } } -void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) { +void PPCLinuxAsmPrinter::emitStartOfAsmFile(Module &M) { if (static_cast<const PPCTargetMachine &>(TM).isELFv2ABI()) { PPCTargetStreamer *TS = static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); @@ -1331,10 +1306,10 @@ void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) { if (static_cast<const PPCTargetMachine &>(TM).isPPC64() || !isPositionIndependent()) - return AsmPrinter::EmitStartOfAsmFile(M); + return AsmPrinter::emitStartOfAsmFile(M); if (M.getPICLevel() == PICLevel::SmallPIC) - return AsmPrinter::EmitStartOfAsmFile(M); + return AsmPrinter::emitStartOfAsmFile(M); OutStreamer->SwitchSection(OutContext.getELFSection( ".got2", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC)); @@ -1342,7 +1317,7 @@ void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) { MCSymbol *TOCSym = OutContext.getOrCreateSymbol(Twine(".LTOC")); MCSymbol *CurrentPos = OutContext.createTempSymbol(); - OutStreamer->EmitLabel(CurrentPos); + 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. @@ -1351,24 +1326,24 @@ void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) { MCConstantExpr::create(0x8000, OutContext), OutContext); - OutStreamer->EmitAssignment(TOCSym, tocExpr); + OutStreamer->emitAssignment(TOCSym, tocExpr); OutStreamer->SwitchSection(getObjFileLowering().getTextSection()); } -void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { +void PPCLinuxAsmPrinter::emitFunctionEntryLabel() { // linux/ppc32 - Normal entry label. if (!Subtarget->isPPC64() && (!isPositionIndependent() || MF->getFunction().getParent()->getPICLevel() == PICLevel::SmallPIC)) - return AsmPrinter::EmitFunctionEntryLabel(); + return AsmPrinter::emitFunctionEntryLabel(); if (!Subtarget->isPPC64()) { const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); if (PPCFI->usesPICBase() && !Subtarget->isSecurePlt()) { - MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol(); + MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol(*MF); MCSymbol *PICBase = MF->getPICBaseSymbol(); - OutStreamer->EmitLabel(RelocSymbol); + OutStreamer->emitLabel(RelocSymbol); const MCExpr *OffsExpr = MCBinaryExpr::createSub( @@ -1376,11 +1351,11 @@ void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { OutContext), MCSymbolRefExpr::create(PICBase, OutContext), OutContext); - OutStreamer->EmitValue(OffsExpr, 4); - OutStreamer->EmitLabel(CurrentFnSym); + OutStreamer->emitValue(OffsExpr, 4); + OutStreamer->emitLabel(CurrentFnSym); return; } else - return AsmPrinter::EmitFunctionEntryLabel(); + return AsmPrinter::emitFunctionEntryLabel(); } // ELFv2 ABI - Normal entry label. @@ -1394,17 +1369,17 @@ void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC.")); - MCSymbol *GlobalEPSymbol = PPCFI->getGlobalEPSymbol(); + MCSymbol *GlobalEPSymbol = PPCFI->getGlobalEPSymbol(*MF); const MCExpr *TOCDeltaExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext), MCSymbolRefExpr::create(GlobalEPSymbol, OutContext), OutContext); - OutStreamer->EmitLabel(PPCFI->getTOCOffsetSymbol()); - OutStreamer->EmitValue(TOCDeltaExpr, 8); + OutStreamer->emitLabel(PPCFI->getTOCOffsetSymbol(*MF)); + OutStreamer->emitValue(TOCDeltaExpr, 8); } - return AsmPrinter::EmitFunctionEntryLabel(); + return AsmPrinter::emitFunctionEntryLabel(); } // Emit an official procedure descriptor. @@ -1412,61 +1387,56 @@ void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { MCSectionELF *Section = OutStreamer->getContext().getELFSection( ".opd", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); OutStreamer->SwitchSection(Section); - OutStreamer->EmitLabel(CurrentFnSym); - OutStreamer->EmitValueToAlignment(8); + 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), + 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( + OutStreamer->emitValue( MCSymbolRefExpr::create(Symbol2, MCSymbolRefExpr::VK_PPC_TOCBASE, OutContext), 8/*size*/); // Emit a null environment pointer. - OutStreamer->EmitIntValue(0, 8 /* size */); + OutStreamer->emitIntValue(0, 8 /* size */); OutStreamer->SwitchSection(Current.first, Current.second); } -bool PPCLinuxAsmPrinter::doFinalization(Module &M) { +void PPCLinuxAsmPrinter::emitEndOfAsmFile(Module &M) { const DataLayout &DL = getDataLayout(); bool isPPC64 = DL.getPointerSizeInBits() == 64; - PPCTargetStreamer &TS = - static_cast<PPCTargetStreamer &>(*OutStreamer->getTargetStreamer()); + PPCTargetStreamer *TS = + static_cast<PPCTargetStreamer *>(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); + const char *Name = isPPC64 ? ".toc" : ".got2"; + MCSectionELF *Section = OutContext.getELFSection( + Name, ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); OutStreamer->SwitchSection(Section); + if (!isPPC64) + OutStreamer->emitValueToAlignment(4); for (const auto &TOCMapPair : TOC) { const MCSymbol *const TOCEntryTarget = TOCMapPair.first; MCSymbol *const TOCEntryLabel = TOCMapPair.second; - OutStreamer->EmitLabel(TOCEntryLabel); - if (isPPC64) { - TS.emitTCEntry(*TOCEntryTarget); - } else { - OutStreamer->EmitValueToAlignment(4); - OutStreamer->EmitSymbolValue(TOCEntryTarget, 4); - } + OutStreamer->emitLabel(TOCEntryLabel); + if (isPPC64 && TS != nullptr) + TS->emitTCEntry(*TOCEntryTarget); + else + OutStreamer->emitSymbolValue(TOCEntryTarget, 4); } } - return AsmPrinter::doFinalization(M); + PPCAsmPrinter::emitEndOfAsmFile(M); } /// EmitFunctionBodyStart - Emit a global entry point prefix for ELFv2. -void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { +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 @@ -1498,16 +1468,23 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { // // 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)) { + const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); + const bool UsesX2OrR2 = !MF->getRegInfo().use_empty(PPC::X2) || + !MF->getRegInfo().use_empty(PPC::R2); + const bool PCrelGEPRequired = Subtarget->isUsingPCRelativeCalls() && + UsesX2OrR2 && PPCFI->usesTOCBasePtr(); + const bool NonPCrelGEPRequired = !Subtarget->isUsingPCRelativeCalls() && + Subtarget->isELFv2ABI() && UsesX2OrR2; + + // Only do all that if the function uses R2 as the TOC pointer + // in the first place. We don't need the global entry point if the + // function uses R2 as an allocatable register. + if (NonPCrelGEPRequired || PCrelGEPRequired) { // Note: The logic here must be synchronized with the code in the // branch-selection pass which sets the offset of the first block in the // function. This matters because it affects the alignment. - const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>(); - - MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol(); - OutStreamer->EmitLabel(GlobalEntryLabel); + MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol(*MF); + OutStreamer->emitLabel(GlobalEntryLabel); const MCSymbolRefExpr *GlobalEntryLabelExp = MCSymbolRefExpr::create(GlobalEntryLabel, OutContext); @@ -1517,21 +1494,19 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext), GlobalEntryLabelExp, OutContext); - const MCExpr *TOCDeltaHi = - PPCMCExpr::createHa(TOCDeltaExpr, false, OutContext); + const MCExpr *TOCDeltaHi = PPCMCExpr::createHa(TOCDeltaExpr, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) .addReg(PPC::X2) .addReg(PPC::X12) .addExpr(TOCDeltaHi)); - const MCExpr *TOCDeltaLo = - PPCMCExpr::createLo(TOCDeltaExpr, false, OutContext); + const MCExpr *TOCDeltaLo = PPCMCExpr::createLo(TOCDeltaExpr, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI) .addReg(PPC::X2) .addReg(PPC::X2) .addExpr(TOCDeltaLo)); } else { - MCSymbol *TOCOffset = PPCFI->getTOCOffsetSymbol(); + MCSymbol *TOCOffset = PPCFI->getTOCOffsetSymbol(*MF); const MCExpr *TOCOffsetDeltaExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCOffset, OutContext), GlobalEntryLabelExp, OutContext); @@ -1546,8 +1521,8 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { .addReg(PPC::X12)); } - MCSymbol *LocalEntryLabel = PPCFI->getLocalEPSymbol(); - OutStreamer->EmitLabel(LocalEntryLabel); + MCSymbol *LocalEntryLabel = PPCFI->getLocalEPSymbol(*MF); + OutStreamer->emitLabel(LocalEntryLabel); const MCSymbolRefExpr *LocalEntryLabelExp = MCSymbolRefExpr::create(LocalEntryLabel, OutContext); const MCExpr *LocalOffsetExp = @@ -1559,13 +1534,43 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { if (TS) TS->emitLocalEntry(cast<MCSymbolELF>(CurrentFnSym), LocalOffsetExp); + } else if (Subtarget->isUsingPCRelativeCalls()) { + // When generating the entry point for a function we have a few scenarios + // based on whether or not that function uses R2 and whether or not that + // function makes calls (or is a leaf function). + // 1) A leaf function that does not use R2 (or treats it as callee-saved + // and preserves it). In this case st_other=0 and both + // the local and global entry points for the function are the same. + // No special entry point code is required. + // 2) A function uses the TOC pointer R2. This function may or may not have + // calls. In this case st_other=[2,6] and the global and local entry + // points are different. Code to correctly setup the TOC pointer in R2 + // is put between the global and local entry points. This case is + // covered by the if statatement above. + // 3) A function does not use the TOC pointer R2 but does have calls. + // In this case st_other=1 since we do not know whether or not any + // of the callees clobber R2. This case is dealt with in this else if + // block. Tail calls are considered calls and the st_other should also + // be set to 1 in that case as well. + // 4) The function does not use the TOC pointer but R2 is used inside + // the function. In this case st_other=1 once again. + // 5) This function uses inline asm. We mark R2 as reserved if the function + // has inline asm as we have to assume that it may be used. + if (MF->getFrameInfo().hasCalls() || MF->getFrameInfo().hasTailCall() || + MF->hasInlineAsm() || (!PPCFI->usesTOCBasePtr() && UsesX2OrR2)) { + PPCTargetStreamer *TS = + static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); + if (TS) + TS->emitLocalEntry(cast<MCSymbolELF>(CurrentFnSym), + MCConstantExpr::create(1, OutContext)); + } } } /// EmitFunctionBodyEnd - Print the traceback table before the .size /// directive. /// -void PPCLinuxAsmPrinter::EmitFunctionBodyEnd() { +void PPCLinuxAsmPrinter::emitFunctionBodyEnd() { // Only the 64-bit target requires a traceback table. For now, // we only emit the word of zeroes that GDB requires to find // the end of the function, and zeroes for the eight-byte @@ -1574,19 +1579,73 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyEnd() { // 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*/); + OutStreamer->emitIntValue(0, 4/*size*/); + OutStreamer->emitIntValue(0, 8/*size*/); + } +} + +void PPCAIXAsmPrinter::emitLinkage(const GlobalValue *GV, + MCSymbol *GVSym) const { + + assert(MAI->hasVisibilityOnlyWithLinkage() && + "AIX's linkage directives take a visibility setting."); + + MCSymbolAttr LinkageAttr = MCSA_Invalid; + switch (GV->getLinkage()) { + case GlobalValue::ExternalLinkage: + LinkageAttr = GV->isDeclaration() ? MCSA_Extern : MCSA_Global; + break; + case GlobalValue::LinkOnceAnyLinkage: + case GlobalValue::LinkOnceODRLinkage: + case GlobalValue::WeakAnyLinkage: + case GlobalValue::WeakODRLinkage: + case GlobalValue::ExternalWeakLinkage: + LinkageAttr = MCSA_Weak; + break; + case GlobalValue::AvailableExternallyLinkage: + LinkageAttr = MCSA_Extern; + break; + case GlobalValue::PrivateLinkage: + return; + case GlobalValue::InternalLinkage: + assert(GV->getVisibility() == GlobalValue::DefaultVisibility && + "InternalLinkage should not have other visibility setting."); + LinkageAttr = MCSA_LGlobal; + break; + case GlobalValue::AppendingLinkage: + llvm_unreachable("Should never emit this"); + case GlobalValue::CommonLinkage: + llvm_unreachable("CommonLinkage of XCOFF should not come to this path"); } + + assert(LinkageAttr != MCSA_Invalid && "LinkageAttr should not MCSA_Invalid."); + + MCSymbolAttr VisibilityAttr = MCSA_Invalid; + switch (GV->getVisibility()) { + + // TODO: "exported" and "internal" Visibility needs to go here. + case GlobalValue::DefaultVisibility: + break; + case GlobalValue::HiddenVisibility: + VisibilityAttr = MAI->getHiddenVisibilityAttr(); + break; + case GlobalValue::ProtectedVisibility: + VisibilityAttr = MAI->getProtectedVisibilityAttr(); + break; + } + + OutStreamer->emitXCOFFSymbolLinkageWithVisibility(GVSym, LinkageAttr, + VisibilityAttr); } void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { - // Get the function descriptor symbol. - CurrentFnDescSym = getSymbol(&MF.getFunction()); - // Set the containing csect. - MCSectionXCOFF *FnDescSec = OutStreamer->getContext().getXCOFFSection( - CurrentFnDescSym->getName(), XCOFF::XMC_DS, XCOFF::XTY_SD, - XCOFF::C_HIDEXT, SectionKind::getData()); - cast<MCSymbolXCOFF>(CurrentFnDescSym)->setContainingCsect(FnDescSec); + // Setup CurrentFnDescSym and its containing csect. + MCSectionXCOFF *FnDescSec = + cast<MCSectionXCOFF>(getObjFileLowering().getSectionForFunctionDescriptor( + &MF.getFunction(), TM)); + FnDescSec->setAlignment(Align(Subtarget->isPPC64() ? 8 : 4)); + + CurrentFnDescSym = FnDescSec->getQualNameSymbol(); return AsmPrinter::SetupMachineFunction(MF); } @@ -1603,31 +1662,20 @@ void PPCAIXAsmPrinter::ValidateGV(const GlobalVariable *GV) { report_fatal_error("COMDAT not yet supported by AIX."); } -const MCExpr *PPCAIXAsmPrinter::lowerConstant(const Constant *CV) { - if (const Function *F = dyn_cast<Function>(CV)) { - MCSymbolXCOFF *FSym = cast<MCSymbolXCOFF>(getSymbol(F)); - if (!FSym->hasContainingCsect()) { - const XCOFF::StorageClass SC = - F->isDeclaration() - ? TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F) - : XCOFF::C_HIDEXT; - MCSectionXCOFF *Csect = OutStreamer->getContext().getXCOFFSection( - FSym->getName(), XCOFF::XMC_DS, - F->isDeclaration() ? XCOFF::XTY_ER : XCOFF::XTY_SD, SC, - SectionKind::getData()); - FSym->setContainingCsect(Csect); - } - return MCSymbolRefExpr::create( - FSym->getContainingCsect()->getQualNameSymbol(), OutContext); - } - return PPCAsmPrinter::lowerConstant(CV); +static bool isSpecialLLVMGlobalArrayForStaticInit(const GlobalVariable *GV) { + return StringSwitch<bool>(GV->getName()) + .Cases("llvm.global_ctors", "llvm.global_dtors", true) + .Default(false); } -void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { +void PPCAIXAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { ValidateGV(GV); - // External global variables are already handled. - if (!GV->hasInitializer()) + // TODO: Update the handling of global arrays for static init when we support + // the ".ref" directive. + // Otherwise, we can skip these arrays, because the AIX linker collects + // static init functions simply based on their name. + if (isSpecialLLVMGlobalArrayForStaticInit(GV)) return; // Create the symbol, set its storage class. @@ -1635,156 +1683,133 @@ void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { GVSym->setStorageClass( TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); + if (GV->isDeclarationForLinker()) { + emitLinkage(GV, GVSym); + return; + } + SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM); - if ((!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly()) || - GVKind.isMergeable2ByteCString() || GVKind.isMergeable4ByteCString()) + if (!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly()) report_fatal_error("Encountered a global variable kind that is " "not supported yet."); - // Create the containing csect and switch to it. MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( getObjFileLowering().SectionForGlobal(GV, GVKind, TM)); + + // Switch to the containing csect. OutStreamer->SwitchSection(Csect); - GVSym->setContainingCsect(Csect); const DataLayout &DL = GV->getParent()->getDataLayout(); // Handle common symbols. if (GVKind.isCommon() || GVKind.isBSSLocal()) { - unsigned Align = - GV->getAlignment() ? GV->getAlignment() : DL.getPreferredAlignment(GV); + Align Alignment = GV->getAlign().getValueOr(DL.getPreferredAlign(GV)); uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); if (GVKind.isBSSLocal()) - OutStreamer->EmitXCOFFLocalCommonSymbol( - GVSym, Size, Csect->getQualNameSymbol(), Align); + OutStreamer->emitXCOFFLocalCommonSymbol( + OutContext.getOrCreateSymbol(GVSym->getUnqualifiedName()), Size, + GVSym, Alignment.value()); else - OutStreamer->EmitCommonSymbol(Csect->getQualNameSymbol(), Size, Align); + OutStreamer->emitCommonSymbol(GVSym, Size, Alignment.value()); return; } MCSymbol *EmittedInitSym = GVSym; - EmitLinkage(GV, EmittedInitSym); - EmitAlignment(getGVAlignment(GV, DL), GV); - OutStreamer->EmitLabel(EmittedInitSym); - EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); + emitLinkage(GV, EmittedInitSym); + emitAlignment(getGVAlignment(GV, DL), GV); + OutStreamer->emitLabel(EmittedInitSym); + emitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); } -void PPCAIXAsmPrinter::EmitFunctionDescriptor() { +void PPCAIXAsmPrinter::emitFunctionDescriptor() { const DataLayout &DL = getDataLayout(); const unsigned PointerSize = DL.getPointerSizeInBits() == 64 ? 8 : 4; MCSectionSubPair Current = OutStreamer->getCurrentSection(); // Emit function descriptor. OutStreamer->SwitchSection( - cast<MCSymbolXCOFF>(CurrentFnDescSym)->getContainingCsect()); - OutStreamer->EmitLabel(CurrentFnDescSym); + cast<MCSymbolXCOFF>(CurrentFnDescSym)->getRepresentedCsect()); // Emit function entry point address. - OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext), + OutStreamer->emitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext), PointerSize); // Emit TOC base address. - const MCSectionXCOFF *TOCBaseSec = OutStreamer->getContext().getXCOFFSection( - StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT, - SectionKind::getData()); - const MCSymbol *TOCBaseSym = TOCBaseSec->getQualNameSymbol(); - OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext), + const MCSymbol *TOCBaseSym = + cast<MCSectionXCOFF>(getObjFileLowering().getTOCBaseSection()) + ->getQualNameSymbol(); + OutStreamer->emitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext), PointerSize); // Emit a null environment pointer. - OutStreamer->EmitIntValue(0, PointerSize); + OutStreamer->emitIntValue(0, PointerSize); OutStreamer->SwitchSection(Current.first, Current.second); } -void PPCAIXAsmPrinter::EmitEndOfAsmFile(Module &M) { +void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) { // If there are no functions in this module, we will never need to reference // the TOC base. if (M.empty()) return; - // Emit TOC base. - MCSectionXCOFF *TOCBaseSection = OutStreamer->getContext().getXCOFFSection( - StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT, - SectionKind::getData()); - // The TOC-base always has 0 size, but 4 byte alignment. - TOCBaseSection->setAlignment(Align(4)); // Switch to section to emit TOC base. - OutStreamer->SwitchSection(TOCBaseSection); + OutStreamer->SwitchSection(getObjFileLowering().getTOCBaseSection()); - PPCTargetStreamer &TS = - static_cast<PPCTargetStreamer &>(*OutStreamer->getTargetStreamer()); + PPCTargetStreamer *TS = + static_cast<PPCTargetStreamer *>(OutStreamer->getTargetStreamer()); + + const unsigned EntryByteSize = Subtarget->isPPC64() ? 8 : 4; + const unsigned TOCEntriesByteSize = TOC.size() * EntryByteSize; + // TODO: If TOC entries' size is larger than 32768, then we run out of + // positive displacement to reach the TOC entry. We need to decide how to + // handle entries' size larger than that later. + if (TOCEntriesByteSize > 32767) { + report_fatal_error("Handling of TOC entry displacement larger than 32767 " + "is not yet implemented."); + } for (auto &I : TOC) { // Setup the csect for the current TC entry. - MCSectionXCOFF *TCEntry = OutStreamer->getContext().getXCOFFSection( - cast<MCSymbolXCOFF>(I.first)->getUnqualifiedName(), XCOFF::XMC_TC, - XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); - cast<MCSymbolXCOFF>(I.second)->setContainingCsect(TCEntry); + MCSectionXCOFF *TCEntry = cast<MCSectionXCOFF>( + getObjFileLowering().getSectionForTOCEntry(I.first)); OutStreamer->SwitchSection(TCEntry); - OutStreamer->EmitLabel(I.second); - TS.emitTCEntry(*I.first); + OutStreamer->emitLabel(I.second); + if (TS != nullptr) + TS->emitTCEntry(*I.first); } } -MCSymbol * -PPCAIXAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) { - const GlobalObject *GO = nullptr; - - // If the MO is a function or certain kind of globals, we want to make sure to - // refer to the csect symbol, otherwise we can just do the default handling. - if (MO.getType() != MachineOperand::MO_GlobalAddress || - !(GO = dyn_cast<const GlobalObject>(MO.getGlobal()))) - return PPCAsmPrinter::getMCSymbolForTOCPseudoMO(MO); - - // Do an early error check for globals we don't support. This will go away - // eventually. - const auto *GV = dyn_cast<const GlobalVariable>(GO); - if (GV) { - ValidateGV(GV); - } +bool PPCAIXAsmPrinter::doInitialization(Module &M) { + if (M.alias_size() > 0u) + report_fatal_error( + "module has aliases, which LLVM does not yet support for AIX"); - MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(getSymbol(GO)); - - // If the global object is a global variable without initializer or is a - // declaration of a function, then XSym is an external referenced symbol. - // Hence we may need to explictly create a MCSectionXCOFF for it so that we - // can return its symbol later. - if (GO->isDeclaration()) { - if (!XSym->hasContainingCsect()) { - // Make sure the storage class is set. - const XCOFF::StorageClass SC = - TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO); - XSym->setStorageClass(SC); - - MCSectionXCOFF *Csect = OutStreamer->getContext().getXCOFFSection( - XSym->getName(), isa<Function>(GO) ? XCOFF::XMC_DS : XCOFF::XMC_UA, - XCOFF::XTY_ER, SC, SectionKind::getMetadata()); - XSym->setContainingCsect(Csect); - } + const bool Result = PPCAsmPrinter::doInitialization(M); - return XSym->getContainingCsect()->getQualNameSymbol(); - } + auto setCsectAlignment = [this](const GlobalObject *GO) { + // Declarations have 0 alignment which is set by default. + if (GO->isDeclarationForLinker()) + return; - // Handle initialized global variables and defined functions. - SectionKind GOKind = getObjFileLowering().getKindForGlobal(GO, TM); - - if (GOKind.isText()) { - // If the MO is a function, we want to make sure to refer to the function - // descriptor csect. - return OutStreamer->getContext() - .getXCOFFSection(XSym->getName(), XCOFF::XMC_DS, XCOFF::XTY_SD, - XCOFF::C_HIDEXT, SectionKind::getData()) - ->getQualNameSymbol(); - } else if (GOKind.isCommon() || GOKind.isBSSLocal()) { - // If the operand is a common then we should refer to the csect symbol. - return cast<MCSectionXCOFF>( - getObjFileLowering().SectionForGlobal(GO, GOKind, TM)) - ->getQualNameSymbol(); - } + SectionKind GOKind = getObjFileLowering().getKindForGlobal(GO, TM); + MCSectionXCOFF *Csect = cast<MCSectionXCOFF>( + getObjFileLowering().SectionForGlobal(GO, GOKind, TM)); + + Align GOAlign = getGVAlignment(GO, GO->getParent()->getDataLayout()); + if (GOAlign > Csect->getAlignment()) + Csect->setAlignment(GOAlign); + }; + + // We need to know, up front, the alignment of csects for the assembly path, + // because once a .csect directive gets emitted, we could not change the + // alignment value on it. + for (const auto &G : M.globals()) + setCsectAlignment(&G); + + for (const auto &F : M) + setCsectAlignment(&F); - // Other global variables are refered to by labels inside of a single csect, - // so refer to the label directly. - return getSymbol(GV); + return Result; } /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code |