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 @@ -661,7 +661,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; @@ -501,6 +505,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/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h --- a/llvm/include/llvm/MC/MCDirectives.h +++ b/llvm/include/llvm/MC/MCDirectives.h @@ -29,6 +29,7 @@ MCSA_ELF_TypeGnuUniqueObject, /// .type _foo, @gnu_unique_object MCSA_Global, ///< .globl MCSA_LGlobal, ///< .lglobl (XCOFF) + MCSA_Extern, ///< .extern (XCOFF) MCSA_Hidden, ///< .hidden (ELF) MCSA_IndirectSymbol, ///< .indirect_symbol (MachO) MCSA_Internal, ///< .internal (ELF) 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 @@ -566,6 +566,10 @@ 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/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -26,6 +26,9 @@ uint64_t Size = 0, unsigned ByteAlignment = 0, SMLoc Loc = SMLoc()) override; void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; + void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Linkage, + MCSymbolAttr Visibility) override; void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; 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 @@ -683,7 +683,8 @@ // Print the 'header' of function. OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(&F, TM)); - emitVisibility(CurrentFnSym, F.getVisibility()); + if (!MAI->hasVisibilityOnlyWithLinkage()) + emitVisibility(CurrentFnSym, F.getVisibility()); if (MAI->needsFunctionDescriptors() && F.getLinkage() != GlobalValue::InternalLinkage) @@ -1459,7 +1460,15 @@ continue; MCSymbol *Name = getSymbol(&F); - emitVisibility(Name, V, false); + if (MAI->needsFunctionDescriptors()) { + // Get the function entry point symbol. + Name = OutContext.getOrCreateSymbol("." + Name->getName()); + } + + if (MAI->hasVisibilityOnlyWithLinkage()) + emitLinkage(&F, Name); + else + emitVisibility(Name, V, false); } // 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 @@ -16,6 +16,7 @@ IsLittleEndian = false; HasDotTypeDotSizeDirective = false; COMMDirectiveAlignmentIsInBytes = false; + HasVisibilityOnlyWithLinkage = true; LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; UseDotAlignForAlignment = true; AsciiDirective = nullptr; // not supported 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,9 @@ 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; @@ -661,6 +667,9 @@ 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; + case MCSA_Extern: + OS << "\t.extern\t"; + break; case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; case MCSA_Local: OS << "\t.local\t"; break; case MCSA_NoDeadStrip: @@ -788,6 +797,51 @@ 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->hasContainingCsect()) { + MCSymbolXCOFF *QualName = + XCOFFSym->getContainingCsect()->getQualNameSymbol(); + if (Symbol->getName() == QualName->getUnqualifiedName() && + XCOFFSym->getContainingCsect()->getMappingClass() != XCOFF::XMC_PR) + QualName->print(OS, MAI); + else + Symbol->print(OS, MAI); + } else + Symbol->print(OS, MAI); + + switch (Visibility) { + default: + break; + 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 @@ -1066,6 +1066,12 @@ 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 @@ -35,6 +35,7 @@ switch (Attribute) { case MCSA_Global: + case MCSA_Extern: Symbol->setStorageClass(XCOFF::C_EXT); Symbol->setExternal(true); break; @@ -48,6 +49,18 @@ return true; } +void MCXCOFFStreamer::emitXCOFFSymbolLinkageWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Linkage, MCSymbolAttr Visibility) { + + emitSymbolAttribute(Symbol, Linkage); + + ///< Not emit default visibility. + 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 @@ -1539,6 +1541,38 @@ } } +void PPCAIXAsmPrinter::emitLinkage(const GlobalValue *GV, + MCSymbol *GVSym) const { + MCSymbolAttr VisibilityAttr = MCSA_Invalid; + + switch (GV->getVisibility()) { + case GlobalValue::DefaultVisibility: + break; + + case GlobalValue::HiddenVisibility: + VisibilityAttr = MAI->getHiddenVisibilityAttr(); + break; + case GlobalValue::ProtectedVisibility: + VisibilityAttr = MAI->getProtectedVisibilityAttr(); + break; + } + + switch (GV->getLinkage()) { + case GlobalValue::ExternalLinkage: + if (GV->isDeclaration()) + OutStreamer->emitXCOFFSymbolLinkageWithVisibility(GVSym, MCSA_Extern, + VisibilityAttr); + else + OutStreamer->emitXCOFFSymbolLinkageWithVisibility(GVSym, MCSA_Global, + VisibilityAttr); + return; + default: + //TODO:Need to deal with CommonLinkage, CommonLinkage etc. + AsmPrinter::emitLinkage(GV, GVSym); + return; + } +} + void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { // Get the function descriptor symbol. CurrentFnDescSym = getSymbol(&MF.getFunction()); 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,44 @@ +; 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 i32 @main() #0 { +entry: + %call1= call i32 @bar_h(i32* @b_h) + 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: .globl b +; CHECK: .globl b_h, hidden +; CHECK: .extern .bar_h, hidden