diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -178,6 +178,17 @@ XTY_CM = 3 ///< Common csect definition. For uninitialized storage. }; +/// Values for visibility as they would appear when encoded in the high 4 bits +/// of the 16-bit unsigned n_type field of symbol table entries. Valid for +/// 32-bit XCOFF only when the vstamp in the auxiliary header is greater than 1. +enum VisibilityType : uint16_t { + SYM_V_UNSPECIFIED = 0x0000, + SYM_V_INTERNAL = 0x1000, + SYM_V_HIDDEN = 0x2000, + SYM_V_PROTECTED = 0x3000, + SYM_V_EXPORTED = 0x4000 +}; + // Relocation types, defined in `/usr/include/reloc.h`. enum RelocationType : uint8_t { R_POS = 0x00, ///< Positive relocation. Provides the address of the referenced diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -659,7 +659,7 @@ /// This emits linkage information about \p GVSym based on \p GV, if this is /// supported by the target. - void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const; + virtual void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const; /// Return the alignment for the specified \p GV. static Align getGVAlignment(const GlobalValue *GV, const DataLayout &DL, diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -93,6 +93,10 @@ /// constants into comdat sections. bool HasCOFFComdatConstants = false; + /// True if this is an XCOFF target that supports visibility attributes as + /// part of .global, .weak, .extern, and .comm. Default is false. + bool HasVisibilityOnlyWithLinkage = false; + /// This is the maximum possible length of an instruction, which is needed to /// compute the size of an inline asm. Defaults to 4. unsigned MaxInstLength = 4; @@ -506,6 +510,9 @@ bool hasMachoTBSSDirective() const { return HasMachoTBSSDirective; } bool hasCOFFAssociativeComdats() const { return HasCOFFAssociativeComdats; } bool hasCOFFComdatConstants() const { return HasCOFFComdatConstants; } + bool hasVisibilityOnlyWithLinkage() const { + return HasVisibilityOnlyWithLinkage; + } /// Returns the maximum possible encoded instruction size in bytes. If \p STI /// is null, this should be the maximum size for any subtarget. diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -565,6 +565,15 @@ MCSymbol *CsectSym, unsigned ByteAlignment); + /// Emit a symbol's linkage and visibilty with a linkage directive for XCOFF. + /// + /// \param Symbol - The symbol to emit. + /// \param Linkage - The linkage of the symbol to emit. + /// \param Visibility - The visibility of the symbol to emit or MCSA_Invalid + /// if the symbol does not have an explicit visibility. + virtual void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Linkage, + MCSymbolAttr Visibility); /// Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: diff --git a/llvm/include/llvm/MC/MCSymbolXCOFF.h b/llvm/include/llvm/MC/MCSymbolXCOFF.h --- a/llvm/include/llvm/MC/MCSymbolXCOFF.h +++ b/llvm/include/llvm/MC/MCSymbolXCOFF.h @@ -53,9 +53,14 @@ void setRepresentedCsect(MCSectionXCOFF *C); + void setVisibilityType(XCOFF::VisibilityType SVT) { VisibilityType = SVT; }; + + XCOFF::VisibilityType getVisibilityType() const { return VisibilityType; } + private: Optional StorageClass; MCSectionXCOFF *RepresentedCsect = nullptr; + XCOFF::VisibilityType VisibilityType = XCOFF::SYM_V_UNSPECIFIED; }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -29,6 +29,9 @@ void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; + void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Linkage, + MCSymbolAttr Visibility) override; }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -700,7 +700,8 @@ MF->setSection(getObjFileLowering().SectionForGlobal(&F, TM)); OutStreamer->SwitchSection(MF->getSection()); - emitVisibility(CurrentFnSym, F.getVisibility()); + if (!MAI->hasVisibilityOnlyWithLinkage()) + emitVisibility(CurrentFnSym, F.getVisibility()); if (MAI->needsFunctionDescriptors() && F.getLinkage() != GlobalValue::InternalLinkage) @@ -1517,23 +1518,29 @@ MCSymbol *Name = getSymbol(&F); // Function getSymbol gives us the function descriptor symbol for XCOFF. - if (TM.getTargetTriple().isOSBinFormatXCOFF() && !F.isIntrinsic()) { - // Get the function entry point symbol. - MCSymbol *FnEntryPointSym = TLOF.getFunctionEntryPointSymbol(&F, TM); - if (cast(FnEntryPointSym)->hasRepresentedCsectSet()) - // Emit linkage for the function entry point. - emitLinkage(&F, FnEntryPointSym); + if (!TM.getTargetTriple().isOSBinFormatXCOFF()) { + GlobalValue::VisibilityTypes V = F.getVisibility(); + if (V == GlobalValue::DefaultVisibility) + continue; - // Emit linkage for the function descriptor. - emitLinkage(&F, Name); + emitVisibility(Name, V, false); + continue; } - GlobalValue::VisibilityTypes V = F.getVisibility(); - if (V == GlobalValue::DefaultVisibility) + if (F.isIntrinsic()) continue; - emitVisibility(Name, V, false); + // Handle the XCOFF case. + // Variable `Name` is the function descriptor symbol (see above). Get the + // function entry point symbol. + MCSymbol *FnEntryPointSym = TLOF.getFunctionEntryPointSymbol(&F, TM); + if (cast(FnEntryPointSym)->hasRepresentedCsectSet()) + // Emit linkage for the function entry point. + emitLinkage(&F, FnEntryPointSym); + + // Emit linkage for the function descriptor. + emitLinkage(&F, Name); } // Emit the remarks section contents. diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp --- a/llvm/lib/MC/MCAsmInfoXCOFF.cpp +++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -14,6 +14,7 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() { IsLittleEndian = false; + HasVisibilityOnlyWithLinkage = true; PrivateGlobalPrefix = "L.."; PrivateLabelPrefix = "L.."; SupportsQuotedNames = false; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -171,6 +171,10 @@ void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; + void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Linakge, + MCSymbolAttr Visibility) override; + void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -791,6 +795,41 @@ EmitEOL(); } +void MCAsmStreamer::emitXCOFFSymbolLinkageWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) { + + switch (Linkage) { + case MCSA_Global: + OS << MAI->getGlobalDirective(); + break; + case MCSA_Weak: + OS << MAI->getWeakDirective(); + break; + case MCSA_Extern: + OS << "\t.extern\t"; + break; + default: + report_fatal_error("unhandled linkage type"); + } + + Symbol->print(OS, MAI); + + switch (Visibility) { + case MCSA_Invalid: + // Nothing to do. + break; + case MCSA_Hidden: + OS << ",hidden"; + break; + case MCSA_Protected: + OS << ",protected"; + break; + default: + report_fatal_error("unexpected value for Visibility type"); + } + EmitEOL(); +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1063,6 +1063,14 @@ unsigned ByteAlign) { llvm_unreachable("this directive only supported on XCOFF targets"); } + +void MCStreamer::emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Linkage, + MCSymbolAttr Visibility) { + llvm_unreachable("emitXCOFFSymbolLinkageWithVisibility is only supported on " + "XCOFF targets"); +} + void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) {} diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -48,12 +48,30 @@ Symbol->setStorageClass(XCOFF::C_WEAKEXT); Symbol->setExternal(true); break; + case llvm::MCSA_Hidden: + Symbol->setVisibilityType(XCOFF::SYM_V_HIDDEN); + break; + case llvm::MCSA_Protected: + Symbol->setVisibilityType(XCOFF::SYM_V_PROTECTED); + break; default: report_fatal_error("Not implemented yet."); } return true; } +void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) { + + emitSymbolAttribute(Symbol, Linkage); + + // When the caller passes `MCSA_Invalid` for the visibility, do not emit one. + if (Visibility == MCSA_Invalid) + return; + + emitSymbolAttribute(Symbol, Visibility); +} + void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { getAssembler().registerSymbol(*Symbol); diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -168,6 +168,8 @@ void emitFunctionDescriptor() override; void emitEndOfAsmFile(Module &) override; + + void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override; }; } // end anonymous namespace @@ -1577,6 +1579,61 @@ } } +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(MAI->hasDotLGloblDirective() && + "Expecting .lglobl to be supported for AIX."); + OutStreamer->emitSymbolAttribute(GVSym, MCSA_LGlobal); + return; + 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) { // Setup CurrentFnDescSym and its containing csect. MCSectionXCOFF *FnDescSec =