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 @@ -649,7 +649,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 a XCOFF target that supports visibility attribute in + /// .global, .weak, .extern ,.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; @@ -492,6 +496,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,9 @@ MCSymbol *CsectSym, unsigned ByteAlignment); + virtual void EmitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily); /// 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 @@ -29,6 +29,9 @@ void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; + void EmitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily) 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 @@ -665,7 +665,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) @@ -1419,7 +1420,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" @@ -169,6 +172,9 @@ void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; + void EmitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -658,6 +664,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: @@ -785,6 +794,52 @@ EmitEOL(); } +void MCAsmStreamer::EmitXCOFFSymbolLinkageWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Attribute, MCSymbolAttr Visibilitily) { + + switch (Attribute) { + case MCSA_Global: + OS << MAI->getGlobalDirective(); + break; + case MCSA_Weak: + OS << MAI->getWeakDirective(); + break; + case MCSA_Extern: + OS << "\t.extern\t"; + break; + default: + EmitSymbolAttribute(Symbol, Attribute); + 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 (Visibilitily) { + default: + break; + case MCSA_Hidden: + OS << ", hidden"; + break; + case MCSA_Protected: + OS << ", protected"; + break; + } + + EmitEOL(); + return; +} + 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 @@ -1069,6 +1069,12 @@ unsigned ByteAlign) { llvm_unreachable("this directive only supported on XCOFF targets"); } +void MCStreamer::EmitXCOFFSymbolLinkageWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Attribute, MCSymbolAttr Visibilitily) { + llvm_unreachable( + "The 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 @@ -34,6 +34,7 @@ switch (Attribute) { case MCSA_Global: + case MCSA_Extern: Symbol->setStorageClass(XCOFF::C_EXT); Symbol->setExternal(true); break; @@ -43,6 +44,16 @@ return true; } +void MCXCOFFStreamer::EmitXCOFFSymbolLinkageWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Attribute, MCSymbolAttr Visibility) { + EmitSymbolAttribute(Symbol, Attribute); + + 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 @@ -1579,6 +1581,45 @@ } } +void PPCAIXAsmPrinter::EmitLinkage(const GlobalValue *GV, + MCSymbol *GVSym) const { + GlobalValue::LinkageTypes Linkage = GV->getLinkage(); + GlobalValue::VisibilityTypes Visibiltiy = GV->getVisibility(); + MCSymbolAttr VisibilityAttr = MCSA_Invalid; + + switch (Visibiltiy) { + default: + break; + case GlobalValue::HiddenVisibility: + VisibilityAttr = MAI->getHiddenVisibilityAttr(); + break; + case GlobalValue::ProtectedVisibility: + VisibilityAttr = MAI->getProtectedVisibilityAttr(); + break; + } + + switch (Linkage) { + default: + AsmPrinter::EmitLinkage(GV, GVSym); + return; + case GlobalValue::ExternalLinkage: + // If external, declare as a global symbol: .globl _foo + if (GV->isDeclaration()) + OutStreamer->EmitXCOFFSymbolLinkageWithVisibility(GVSym, MCSA_Extern, + VisibilityAttr); + else + OutStreamer->EmitXCOFFSymbolLinkageWithVisibility(GVSym, MCSA_Global, + VisibilityAttr); + return; + case GlobalValue::InternalLinkage: + if (MAI->hasDotLGloblDirective()) + OutStreamer->EmitSymbolAttribute(GVSym, MCSA_LGlobal); + return; + } + + llvm_unreachable("Unknown linkage type!"); +} + 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