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 @@ -159,6 +159,13 @@ XTY_CM = 3 ///< Common csect definition. For uninitialized storage. }; +enum SymbolVisibilityType : uint16_t { + 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,9 @@ MCSymbol *CsectSym, unsigned ByteAlignment); + 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,15 @@ void setRepresentedCsect(MCSectionXCOFF *C); + void setVisibilityType(XCOFF::SymbolVisibilityType SVT) { + VisibilityType = SVT; + }; + XCOFF::SymbolVisibilityType getVisibilityType() { return VisibilityType; } + private: Optional StorageClass; MCSectionXCOFF *RepresentedCsect = nullptr; + XCOFF::SymbolVisibilityType VisibilityType = XCOFF::SYM_V_INTERNAL; }; } // 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 @@ -691,7 +691,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,6 +1518,7 @@ // Emit linkage for the function descriptor. emitLinkage(&F, Name); + continue; } GlobalValue::VisibilityTypes V = F.getVisibility(); 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; SupportsQuotedNames = false; UseDotAlignForAlignment = true; ZeroDirective = "\t.space\t"; 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 @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" @@ -27,7 +28,9 @@ #include "llvm/MC/MCRegister.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" @@ -171,6 +174,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 +798,50 @@ 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: + llvm_unreachable("Visibility is not a part of this linkage type."); + return; + } + + MCSymbolXCOFF *XCOFFSym = cast(Symbol); + + if (XCOFFSym->hasRepresentedCsectSet()) { + MCSymbolXCOFF *QualName = + XCOFFSym->getRepresentedCsect()->getQualNameSymbol(); + if (Symbol->getName() == QualName->getUnqualifiedName() && + XCOFFSym->getRepresentedCsect()->getMappingClass() != XCOFF::XMC_PR) + QualName->print(OS, MAI); + else + Symbol->print(OS, MAI); + } else + Symbol->print(OS, MAI); + + switch (Visibility) { + default: + llvm_unreachable("unexpected value for Visibility."); + case MCSA_Hidden: + OS << ", hidden"; + break; + case MCSA_Protected: + OS << ", protected"; + break; + } + 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 @@ -47,12 +47,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 @@ -162,6 +162,8 @@ void emitFunctionDescriptor() override; void emitEndOfAsmFile(Module &) override; + + void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override; }; } // end anonymous namespace @@ -1571,6 +1573,45 @@ } } +void PPCAIXAsmPrinter::emitLinkage(const GlobalValue *GV, + MCSymbol *GVSym) const { + + MCSymbolAttr VisibilityAttr = MCSA_Invalid; + switch (GV->getVisibility()) { + + // TODO: "exported" versus "unspecified" Visibility needs to go here. + + case GlobalValue::DefaultVisibility: + AsmPrinter::emitLinkage(GV, GVSym); + return; + case GlobalValue::HiddenVisibility: + VisibilityAttr = MAI->getHiddenVisibilityAttr(); + break; + case GlobalValue::ProtectedVisibility: + VisibilityAttr = MAI->getProtectedVisibilityAttr(); + break; + } + + switch (GV->getLinkage()) { + case GlobalValue::ExternalLinkage: + OutStreamer->emitXCOFFSymbolLinkageWithVisibility( + GVSym, GV->isDeclaration() ? MCSA_Extern : MCSA_Global, VisibilityAttr); + return; + case GlobalValue::LinkOnceAnyLinkage: + case GlobalValue::LinkOnceODRLinkage: + case GlobalValue::WeakAnyLinkage: + case GlobalValue::WeakODRLinkage: + case GlobalValue::ExternalWeakLinkage: + OutStreamer->emitXCOFFSymbolLinkageWithVisibility(GVSym, MCSA_Weak, + VisibilityAttr); + break; + default: + // TODO: Need to deal with other Linkages etc. + AsmPrinter::emitLinkage(GV, GVSym); + return; + } +} + void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { // Setup CurrentFnDescSym and its containing csect. MCSectionXCOFF *FnDescSec = diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-hidden.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-hidden.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-hidden.ll @@ -0,0 +1,65 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s + +@b = global i32 0, align 4 +@b_h = hidden global i32 0, align 4 + +define i32 @foo(i32* %ip) #0 { +entry: + %ip.addr = alloca i32*, align 4 + store i32* %ip, i32** %ip.addr, align 4 + %0 = load i32*, i32** %ip.addr, align 4 + %1 = load i32, i32* %0, align 4 + %inc = add nsw i32 %1, 1 + store i32 %inc, i32* %0, align 4 + ret i32 %1 +} + +define hidden i32 @foo_h(i32* %ip) #0 { +entry: + %ip.addr = alloca i32*, align 4 + store i32* %ip, i32** %ip.addr, align 4 + %0 = load i32*, i32** %ip.addr, align 4 + %1 = load i32, i32* %0, align 4 + %inc = add nsw i32 %1, 1 + store i32 %inc, i32* %0, align 4 + ret i32 %1 +} + +define weak hidden void @foo_weak_h(i32* %p) #0 { +entry: + %p.addr = alloca i32*, align 4 + store i32* %p, i32** %p.addr, align 4 + %0 = load i32*, i32** %p.addr, align 4 + %1 = load i32, i32* %0, align 4 + %inc = add nsw i32 %1, 1 + store i32 %inc, i32* %0, align 4 + ret void +} + +@foo_p = global void ()* @zoo_weak_extern_h, align 4 +declare extern_weak hidden void @zoo_weak_extern_h() + +define i32 @main() #0 { +entry: + %call1= call i32 @bar_h(i32* @b_h) + call void @foo_weak_h(i32* @b) + %0 = load void ()*, void ()** @foo_p, align 4 + call void %0() + ret i32 0 +} + +declare hidden i32 @bar_h(i32*) #1 + +; CHECK: .globl foo[DS] +; CHECK: .globl .foo +; CHECK: .globl foo_h[DS], hidden +; CHECK: .globl .foo_h, hidden +; CHECK: .weak foo_weak_h[DS], hidden +; CHECK: .weak .foo_weak_h, hidden + +; CHECK: .globl b +; CHECK: .globl b_h, hidden +; CHECK: .weak zoo_weak_extern_h[DS], hidden +; CHECK: .extern .bar_h, hidden +; CHECK: .extern bar_h[DS], hidden