Index: llvm/trunk/include/llvm/CodeGen/AsmPrinter.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/AsmPrinter.h +++ llvm/trunk/include/llvm/CodeGen/AsmPrinter.h @@ -111,6 +111,10 @@ /// of each call to runOnMachineFunction(). MCSymbol *CurrentFnSym = nullptr; + /// The symbol for the current function descriptor on AIX. This is created + /// at the beginning of each call to SetupMachineFunction(). + MCSymbol *CurrentFnDescSym = nullptr; + /// The symbol used to represent the start of the current function for the /// purpose of calculating its size (e.g. using the .size directive). By /// default, this is equal to CurrentFnSym. @@ -304,7 +308,7 @@ /// This should be called when a new MachineFunction is being processed from /// runOnMachineFunction. - void SetupMachineFunction(MachineFunction &MF); + virtual void SetupMachineFunction(MachineFunction &MF); /// This method emits the body and trailer for a function. void EmitFunctionBody(); @@ -414,6 +418,10 @@ virtual void EmitFunctionEntryLabel(); + virtual void EmitFunctionDescriptor() { + llvm_unreachable("Function descriptor is target-specific."); + } + virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV); /// Targets can override this to change how global constants that are part of Index: llvm/trunk/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/trunk/include/llvm/MC/MCAsmInfo.h +++ llvm/trunk/include/llvm/MC/MCAsmInfo.h @@ -317,6 +317,10 @@ /// Defaults to false. bool HasLinkOnceDirective = false; + /// True if we have a .lglobl directive, which is used to emit the information + /// of a static symbol into the symbol table. Defaults to false. + bool HasDotLGloblDirective = false; + /// This attribute, if not MCSA_Invalid, is used to declare a symbol as having /// hidden visibility. Defaults to MCSA_Hidden. MCSymbolAttr HiddenVisibilityAttr = MCSA_Hidden; @@ -392,6 +396,9 @@ // %hi(), and similar unary operators. bool HasMipsExpressions = false; + // If true, emit function descriptor symbol on AIX. + bool NeedsFunctionDescriptors = false; + public: explicit MCAsmInfo(); virtual ~MCAsmInfo(); @@ -565,6 +572,8 @@ bool hasLinkOnceDirective() const { return HasLinkOnceDirective; } + bool hasDotLGloblDirective() const { return HasDotLGloblDirective; } + MCSymbolAttr getHiddenVisibilityAttr() const { return HiddenVisibilityAttr; } MCSymbolAttr getHiddenDeclarationVisibilityAttr() const { @@ -647,6 +656,7 @@ bool canRelaxRelocations() const { return RelaxELFRelocations; } void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; } bool hasMipsExpressions() const { return HasMipsExpressions; } + bool needsFunctionDescriptors() const { return NeedsFunctionDescriptors; } }; } // end namespace llvm Index: llvm/trunk/include/llvm/MC/MCAsmInfoXCOFF.h =================================================================== --- llvm/trunk/include/llvm/MC/MCAsmInfoXCOFF.h +++ llvm/trunk/include/llvm/MC/MCAsmInfoXCOFF.h @@ -18,6 +18,11 @@ protected: MCAsmInfoXCOFF(); + +public: + // Return true only when the identifier Name does not need quotes to be + // syntactically correct for XCOFF. + bool isValidUnquotedName(StringRef Name) const override; }; } // end namespace llvm Index: llvm/trunk/include/llvm/MC/MCDirectives.h =================================================================== --- llvm/trunk/include/llvm/MC/MCDirectives.h +++ llvm/trunk/include/llvm/MC/MCDirectives.h @@ -28,6 +28,7 @@ MCSA_ELF_TypeNoType, ///< .type _foo, STT_NOTYPE # aka @notype MCSA_ELF_TypeGnuUniqueObject, /// .type _foo, @gnu_unique_object MCSA_Global, ///< .globl + MCSA_LGlobal, ///< .lglobl (XCOFF) MCSA_Hidden, ///< .hidden (ELF) MCSA_IndirectSymbol, ///< .indirect_symbol (MachO) MCSA_Internal, ///< .internal (ELF) Index: llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h =================================================================== --- llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h +++ llvm/trunk/include/llvm/MC/MCSymbolXCOFF.h @@ -35,14 +35,14 @@ return StorageClass.getValue(); } - void setContainingCsect(const MCSectionXCOFF *C) { + void setContainingCsect(MCSectionXCOFF *C) { assert((!ContainingCsect || ContainingCsect == C) && "Trying to set a containing csect that doesn't match the one that" "this symbol is already mapped to."); ContainingCsect = C; } - const MCSectionXCOFF *getContainingCsect() const { + MCSectionXCOFF *getContainingCsect() const { assert(ContainingCsect && "Trying to get containing csect but none was set."); return ContainingCsect; @@ -50,7 +50,7 @@ private: Optional StorageClass; - const MCSectionXCOFF *ContainingCsect = nullptr; + MCSectionXCOFF *ContainingCsect = nullptr; }; } // end namespace llvm Index: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -91,10 +91,12 @@ #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/SectionKind.h" @@ -426,7 +428,10 @@ OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global); return; case GlobalValue::PrivateLinkage: + return; case GlobalValue::InternalLinkage: + if (MAI->hasDotLGloblDirective()) + OutStreamer->EmitSymbolAttribute(GVSym, MCSA_LGlobal); return; case GlobalValue::AppendingLinkage: case GlobalValue::AvailableExternallyLinkage: @@ -662,6 +667,10 @@ OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(&F, TM)); EmitVisibility(CurrentFnSym, F.getVisibility()); + if (MAI->needsFunctionDescriptors() && + F.getLinkage() != GlobalValue::InternalLinkage) + EmitLinkage(&F, CurrentFnDescSym); + EmitLinkage(&F, CurrentFnSym); if (MAI->hasFunctionAlignment()) EmitAlignment(MF->getAlignment(), &F); @@ -697,8 +706,13 @@ } } - // Emit the CurrentFnSym. This is a virtual function to allow targets to - // do their wild and crazy things as required. + // Emit the function descriptor. This is a virtual function to allow targets + // to emit their specific function descriptor. + if (MAI->needsFunctionDescriptors()) + EmitFunctionDescriptor(); + + // Emit the CurrentFnSym. This is a virtual function to allow targets to do + // their wild and crazy things as required. EmitFunctionEntryLabel(); // If the function had address-taken blocks that got deleted, then we have @@ -1644,8 +1658,27 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { this->MF = &MF; + // Get the function symbol. - CurrentFnSym = getSymbol(&MF.getFunction()); + if (MAI->needsFunctionDescriptors()) { + assert(TM.getTargetTriple().isOSAIX() && "Function descriptor is only" + " supported on AIX."); + assert(CurrentFnDescSym && "The function descriptor symbol needs to be" + " initalized first."); + + // Get the function entry point symbol. + CurrentFnSym = + OutContext.getOrCreateSymbol("." + CurrentFnDescSym->getName()); + + const Function &F = MF.getFunction(); + MCSectionXCOFF *FnEntryPointSec = + cast(getObjFileLowering().SectionForGlobal(&F, TM)); + // Set the containing csect. + cast(CurrentFnSym)->setContainingCsect(FnEntryPointSec); + } else { + CurrentFnSym = getSymbol(&MF.getFunction()); + } + CurrentFnSymForSize = CurrentFnSym; CurrentFnBegin = nullptr; CurExceptionSym = nullptr; Index: llvm/trunk/lib/MC/MCAsmInfoXCOFF.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmInfoXCOFF.cpp +++ llvm/trunk/lib/MC/MCAsmInfoXCOFF.cpp @@ -20,5 +20,16 @@ UseDotAlignForAlignment = true; AsciiDirective = nullptr; // not supported AscizDirective = nullptr; // not supported + NeedsFunctionDescriptors = true; + HasDotLGloblDirective = true; Data64bitsDirective = "\t.llong\t"; + SupportsQuotedNames = false; +} + +bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const { + // FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name. + if (Name.equals("TOC[TC0]")) + return true; + + return MCAsmInfo::isValidUnquotedName(Name); } Index: llvm/trunk/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmStreamer.cpp +++ llvm/trunk/lib/MC/MCAsmStreamer.cpp @@ -650,6 +650,7 @@ case MCSA_Global: // .globl/.global OS << MAI->getGlobalDirective(); break; + case MCSA_LGlobal: OS << "\t.lglobl\t"; break; case MCSA_Hidden: OS << "\t.hidden\t"; break; case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break; case MCSA_Internal: OS << "\t.internal\t"; break; Index: llvm/trunk/lib/MC/MCELFStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCELFStreamer.cpp +++ llvm/trunk/lib/MC/MCELFStreamer.cpp @@ -277,6 +277,9 @@ case MCSA_AltEntry: llvm_unreachable("ELF doesn't support the .alt_entry attribute"); + + case MCSA_LGlobal: + llvm_unreachable("ELF doesn't support the .lglobl attribute"); } return true; Index: llvm/trunk/lib/MC/MCMachOStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCMachOStreamer.cpp +++ llvm/trunk/lib/MC/MCMachOStreamer.cpp @@ -330,6 +330,7 @@ case MCSA_Protected: case MCSA_Weak: case MCSA_Local: + case MCSA_LGlobal: return false; case MCSA_Global: Index: llvm/trunk/lib/MC/MCSectionXCOFF.cpp =================================================================== --- llvm/trunk/lib/MC/MCSectionXCOFF.cpp +++ llvm/trunk/lib/MC/MCSectionXCOFF.cpp @@ -15,26 +15,46 @@ MCSectionXCOFF::~MCSectionXCOFF() = default; +static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) { + switch (SMC) { + case XCOFF::XMC_DS: + return "DS"; + case XCOFF::XMC_RW: + return "RW"; + case XCOFF::XMC_PR: + return "PR"; + default: + report_fatal_error("Unhandled storage-mapping class."); + } +} + void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, const MCExpr *Subsection) const { if (getKind().isText()) { if (getMappingClass() != XCOFF::XMC_PR) - llvm_unreachable("Unsupported storage-mapping class for .text csect"); + report_fatal_error("Unhandled storage-mapping class for .text csect"); OS << "\t.csect " << getSectionName() << "[" - << "PR" + << getMappingClassString(getMappingClass()) << "]" << '\n'; return; } if (getKind().isData()) { - assert(getMappingClass() == XCOFF::XMC_RW && - "Unhandled storage-mapping class for data section."); - - OS << "\t.csect " << getSectionName() << "[" - << "RW" - << "]" << '\n'; + switch (getMappingClass()) { + case XCOFF::XMC_RW: + case XCOFF::XMC_DS: + OS << "\t.csect " << getSectionName() << "[" + << getMappingClassString(getMappingClass()) << "]" << '\n'; + break; + case XCOFF::XMC_TC0: + OS << "\t.toc\n"; + break; + default: + report_fatal_error( + "Unhandled storage-mapping class for .data csect."); + } return; } Index: llvm/trunk/lib/MC/XCOFFObjectWriter.cpp =================================================================== --- llvm/trunk/lib/MC/XCOFFObjectWriter.cpp +++ llvm/trunk/lib/MC/XCOFFObjectWriter.cpp @@ -235,6 +235,9 @@ break; } report_fatal_error("Unhandled mapping of read-write csect to section."); + case XCOFF::XMC_TC0: + // TODO FIXME Handle emiting the TOC base. + break; case XCOFF::XMC_BS: assert(XCOFF::XTY_CM == MCSec->getCSectType() && "Mapping invalid csect. CSECT with bss storage class must be " Index: llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -167,7 +167,13 @@ StringRef getPassName() const override { return "AIX PPC Assembly Printer"; } + void SetupMachineFunction(MachineFunction &MF) override; + void EmitGlobalVariable(const GlobalVariable *GV) override; + + void EmitFunctionDescriptor() override; + + void EmitEndOfAsmFile(Module &) override; }; } // end anonymous namespace @@ -1669,6 +1675,18 @@ return AsmPrinter::doFinalization(M); } +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(CurrentFnDescSym)->setContainingCsect(FnDescSec); + + return AsmPrinter::SetupMachineFunction(MF); +} + void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // Early error checking limiting what is supported. if (GV->isThreadLocal()) @@ -1718,6 +1736,45 @@ EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); } +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(CurrentFnDescSym)->getContainingCsect()); + OutStreamer->EmitLabel(CurrentFnDescSym); + // Emit function entry point address. + OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext), + PointerSize); + // Emit TOC base address. + MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]")); + OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext), + PointerSize); + // Emit a null environment pointer. + OutStreamer->EmitIntValue(0, PointerSize); + + OutStreamer->SwitchSection(Current.first, Current.second); +} + +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. + MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]")); + MCSectionXCOFF *TOCBaseSection = OutStreamer->getContext().getXCOFFSection( + StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT, + SectionKind::getData()); + cast(TOCBaseSym)->setContainingCsect(TOCBaseSection); + // Switch to section to emit TOC base. + OutStreamer->SwitchSection(TOCBaseSection); +} + + /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code /// for a MachineFunction to the given output stream, in a format that the /// Darwin assembler can deal with. Index: llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll +++ llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-common.ll @@ -21,6 +21,8 @@ @array = common local_unnamed_addr global [33 x i8] zeroinitializer, align 1 +; CHECK-NOT: .toc + ; CHECK: .csect .text[PR] ; CHECK-NEXT: .file ; CHECK-NEXT: .comm a,4,2 Index: llvm/trunk/test/CodeGen/PowerPC/test_func_desc.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/test_func_desc.ll +++ llvm/trunk/test/CodeGen/PowerPC/test_func_desc.ll @@ -0,0 +1,74 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \ +; RUN: FileCheck --check-prefixes=CHECK,32BIT %s + +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \ +; RUN: FileCheck --check-prefixes=CHECK,64BIT %s + + +define i32 @foo() { +entry: + ret i32 3 +} + +define i32 @main() { +entry: + %0 = call i32 @foo() + %1 = call i32 bitcast (i32 (...)* @extern_foo to i32 ()*)() + %2 = call i32 @static_foo() + %3 = add nsw i32 %0, %1 + %4 = add nsw i32 %3, %2 + ret i32 %4 +} + +declare i32 @extern_foo(...) + +define internal i32 @static_foo() { +entry: + ret i32 3 +} + +; CHECK: .globl foo +; CHECK: .globl .foo +; CHECK: .csect foo[DS] +; CHECK-NEXT: foo: +; 32BIT: .long .foo +; 32BIT-NEXT: .long TOC[TC0] +; 32BIT-NEXT: .long 0 +; 64BIT: .llong .foo +; 64BIT-NEXT: .llong TOC[TC0] +; 64BIT-NEXT: .llong 0 +; CHECK-NEXT: .csect .text[PR] +; CHECK-LABEL: .foo: + +; CHECK: .globl main +; CHECK: .globl .main +; CHECK: .csect main[DS] +; CHECK-NEXT: main: +; 32BIT: .long .main +; 32BIT-NEXT: .long TOC[TC0] +; 32BIT-NEXT: .long 0 +; 64BIT: .llong .main +; 64BIT-NEXT: .llong TOC[TC0] +; 64BIT-NEXT: .llong 0 +; CHECK-NEXT: .csect .text[PR] +; CHECK-LABEL: .main: +; CHECK: bl .foo +; CHECK: bl .extern_foo +; CHECK: bl .static_foo + +; CHECK: .lglobl .static_foo +; CHECK: .csect static_foo[DS] +; CHECK-NEXT: static_foo: +; 32BIT: .long .static_foo +; 32BIT-NEXT: .long TOC[TC0] +; 32BIT-NEXT: .long 0 +; 64BIT: .llong .static_foo +; 64BIT-NEXT: .llong TOC[TC0] +; 64BIT-NEXT: .llong 0 +; CHECK-NEXT: .csect .text[PR] +; CHECK-LABEL: .static_foo: + +; CHECK-NOT: .csect extern_foo + +; CHECK: .toc +; CHECK-NOT: .tc