Index: llvm/docs/BitCodeFormat.rst =================================================================== --- llvm/docs/BitCodeFormat.rst +++ llvm/docs/BitCodeFormat.rst @@ -730,6 +730,7 @@ * ``default``: code 0 * ``hidden``: code 1 * ``protected``: code 2 + * ``exported``: code 3 .. _bcthreadlocal: Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -481,7 +481,10 @@ means that the declaration is visible to other modules and, in shared libraries, means that the declared entity may be overridden. On Darwin, default visibility means that the declaration is visible - to other modules. Default visibility corresponds to "external + to other modules. On XCOFF, default visibility means no explicit + visibility bit will be set and whether the symbol is visible + (i.e "exported") to other modules depends primarily on export lists + provided to the linker. Default visibility corresponds to "external linkage" in the language. "``hidden``" - Hidden style Two declarations of an object with hidden visibility refer to the @@ -494,6 +497,10 @@ placed in the dynamic symbol table, but that references within the defining module will bind to the local symbol. That is, the symbol cannot be overridden by another module. +"``exported``" - Exported style + On XCOFF, exported visibility indicates that the symbol will be + made visible to other modules (i.e. "exported") by the linker and + thus placed in the loader section symbol table. A symbol with ``internal`` or ``private`` linkage must have ``default`` visibility. Index: llvm/include/llvm/AsmParser/LLToken.h =================================================================== --- llvm/include/llvm/AsmParser/LLToken.h +++ llvm/include/llvm/AsmParser/LLToken.h @@ -63,6 +63,7 @@ kw_default, kw_hidden, kw_protected, + kw_exported, kw_unnamed_addr, kw_local_unnamed_addr, kw_externally_initialized, Index: llvm/include/llvm/IR/GlobalValue.h =================================================================== --- llvm/include/llvm/IR/GlobalValue.h +++ llvm/include/llvm/IR/GlobalValue.h @@ -62,7 +62,8 @@ enum VisibilityTypes { DefaultVisibility = 0, ///< The GV is visible HiddenVisibility, ///< The GV is hidden - ProtectedVisibility ///< The GV is protected + ProtectedVisibility, ///< The GV is protected + ExportedVisibility ///< The GV is exported }; /// Storage classes of global values for PE targets. @@ -231,6 +232,9 @@ bool hasProtectedVisibility() const { return Visibility == ProtectedVisibility; } + bool hasExportedVisibility() const { + return Visibility == ExportedVisibility; + } void setVisibility(VisibilityTypes V) { assert((!hasLocalLinkage() || V == DefaultVisibility) && "local linkage requires default visibility"); Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -430,6 +430,10 @@ /// hidden visibility. Defaults to MCSA_Hidden. MCSymbolAttr HiddenVisibilityAttr = MCSA_Hidden; + /// This attribute, if not MCSA_Invalid, is used to declare a symbol as having + /// exported visibility. Defaults to MCSA_Exported. + MCSymbolAttr ExportedVisibilityAttr = MCSA_Exported; + /// This attribute, if not MCSA_Invalid, is used to declare an undefined /// symbol as having hidden visibility. Defaults to MCSA_Hidden. MCSymbolAttr HiddenDeclarationVisibilityAttr = MCSA_Hidden; @@ -750,6 +754,8 @@ MCSymbolAttr getHiddenVisibilityAttr() const { return HiddenVisibilityAttr; } + MCSymbolAttr getExportedVisibilityAttr() const { return ExportedVisibilityAttr; } + MCSymbolAttr getHiddenDeclarationVisibilityAttr() const { return HiddenDeclarationVisibilityAttr; } Index: llvm/include/llvm/MC/MCDirectives.h =================================================================== --- llvm/include/llvm/MC/MCDirectives.h +++ llvm/include/llvm/MC/MCDirectives.h @@ -31,6 +31,7 @@ MCSA_LGlobal, ///< .lglobl (XCOFF) MCSA_Extern, ///< .extern (XCOFF) MCSA_Hidden, ///< .hidden (ELF) + MCSA_Exported, ///< .globl _foo, exported (XCOFF) MCSA_IndirectSymbol, ///< .indirect_symbol (MachO) MCSA_Internal, ///< .internal (ELF) MCSA_LazyReference, ///< .lazy_reference (MachO) Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -518,6 +518,7 @@ KEYWORD(default); KEYWORD(hidden); KEYWORD(protected); + KEYWORD(exported); KEYWORD(unnamed_addr); KEYWORD(local_unnamed_addr); KEYWORD(externally_initialized); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1779,6 +1779,9 @@ case lltok::kw_protected: Res = GlobalValue::ProtectedVisibility; break; + case lltok::kw_exported: + Res = GlobalValue::ExportedVisibility; + break; } Lex.Lex(); } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1105,6 +1105,7 @@ case GlobalValue::DefaultVisibility: return 0; case GlobalValue::HiddenVisibility: return 1; case GlobalValue::ProtectedVisibility: return 2; + case GlobalValue::ExportedVisibility: return 3; } llvm_unreachable("Invalid visibility"); } Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -3151,6 +3151,8 @@ return "hidden"; case GlobalValue::ProtectedVisibility: return "protected"; + case GlobalValue::ExportedVisibility: + return "exported"; } llvm_unreachable("invalid visibility"); } @@ -3421,6 +3423,7 @@ case GlobalValue::DefaultVisibility: break; case GlobalValue::HiddenVisibility: Out << "hidden "; break; case GlobalValue::ProtectedVisibility: Out << "protected "; break; + case GlobalValue::ExportedVisibility: Out << "exported "; break; } } Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -762,6 +762,8 @@ case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break; case MCSA_Cold: // Assemblers currently do not support a .cold directive. + case MCSA_Exported: + // Non-AIX assemblers currently do not support exported visibility. return false; } @@ -904,6 +906,9 @@ case MCSA_Protected: OS << ",protected"; break; + case MCSA_Exported: + OS << ",exported"; + break; default: report_fatal_error("unexpected value for Visibility type"); } Index: llvm/lib/MC/MCELFStreamer.cpp =================================================================== --- llvm/lib/MC/MCELFStreamer.cpp +++ llvm/lib/MC/MCELFStreamer.cpp @@ -215,6 +215,7 @@ case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: case MCSA_IndirectSymbol: + case MCSA_Exported: return false; case MCSA_NoDeadStrip: Index: llvm/lib/MC/MCMachOStreamer.cpp =================================================================== --- llvm/lib/MC/MCMachOStreamer.cpp +++ llvm/lib/MC/MCMachOStreamer.cpp @@ -358,6 +358,7 @@ case MCSA_Weak: case MCSA_Local: case MCSA_LGlobal: + case MCSA_Exported: return false; case MCSA_Global: Index: llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1899,8 +1899,10 @@ MCSymbolAttr VisibilityAttr = MCSA_Invalid; if (!TM.getIgnoreXCOFFVisibility()) { switch (GV->getVisibility()) { - - // TODO: "exported" and "internal" Visibility needs to go here. + // TODO: "internal" Visibility needs to go here. + case GlobalValue::ExportedVisibility: + VisibilityAttr = MAI->getExportedVisibilityAttr(); + break; case GlobalValue::DefaultVisibility: break; case GlobalValue::HiddenVisibility: Index: llvm/test/CodeGen/PowerPC/aix-xcoff-visibility.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-xcoff-visibility.ll +++ llvm/test/CodeGen/PowerPC/aix-xcoff-visibility.ll @@ -5,6 +5,7 @@ @b = global i32 0, align 4 @b_h = hidden global i32 0, align 4 +@b_e = exported global i32 0, align 4 define void @foo() { entry: @@ -16,6 +17,11 @@ ret void } +define exported void @foo_e(i32* %ip) { +entry: + ret void +} + define protected void @foo_protected(i32* %ip) { entry: ret void @@ -26,8 +32,14 @@ ret void } +define weak exported void @foo_weak_e() { +entry: + ret void +} + @foo_p = global void ()* @zoo_weak_extern_h, align 4 declare extern_weak hidden void @zoo_weak_extern_h() +declare extern_weak exported void @zoo_weak_extern_e() define i32 @main() { entry: @@ -39,20 +51,30 @@ } declare hidden i32 @bar_h(i32*) +declare exported i32 @bar_e(i32*) ; CHECK: .globl foo[DS]{{[[:space:]]*([#].*)?$}} ; CHECK: .globl .foo{{[[:space:]]*([#].*)?$}} ; CHECK: .globl foo_h[DS],hidden ; CHECK: .globl .foo_h,hidden +; CHECK: .globl foo_e[DS],exported +; CHECK: .globl .foo_e,exported ; CHECK: .globl foo_protected[DS],protected ; CHECK: .globl .foo_protected,protected ; CHECK: .weak foo_weak_h[DS],hidden ; CHECK: .weak .foo_weak_h,hidden +; CHECK: .weak foo_weak_e[DS],exported +; CHECK: .weak .foo_weak_e,exported ; CHECK: .globl b{{[[:space:]]*([#].*)?$}} ; CHECK: .globl b_h,hidden +; CHECK: .globl b_e,exported ; CHECK: .weak .zoo_weak_extern_h[PR],hidden ; CHECK: .weak zoo_weak_extern_h[DS],hidden +; CHECK: .weak .zoo_weak_extern_e[PR],exported +; CHECK: .weak zoo_weak_extern_e[DS],exported ; CHECK: .extern .bar_h[PR],hidden ; CHECK: .extern bar_h[DS],hidden +; CHECK: .extern .bar_e[PR],exported +; CHECK: .extern bar_e[DS],exported Index: llvm/test/LTO/Resolution/X86/symtab.ll =================================================================== --- llvm/test/LTO/Resolution/X86/symtab.ll +++ llvm/test/LTO/Resolution/X86/symtab.ll @@ -26,6 +26,9 @@ ret i32 %add } +; CHECK: E------- _g0 +@g0 = exported global i32 0 + ; CHECK: H------- _g1 @g1 = hidden global i32 0 Index: llvm/tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- llvm/tools/llvm-lto2/llvm-lto2.cpp +++ llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -441,6 +441,9 @@ case GlobalValue::DefaultVisibility: outs() << 'D'; break; + case GlobalValue::ExportedVisibility: + outs() << 'E'; + break; } auto PrintBool = [&](char C, bool B) { outs() << (B ? C : '-'); }; Index: llvm/unittests/IR/CMakeLists.txt =================================================================== --- llvm/unittests/IR/CMakeLists.txt +++ llvm/unittests/IR/CMakeLists.txt @@ -44,6 +44,7 @@ VectorBuilderTest.cpp VectorTypesTest.cpp VerifierTest.cpp + VisibilityStyleTest.cpp VPIntrinsicTest.cpp ) Index: llvm/unittests/IR/VisibilityStyleTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/IR/VisibilityStyleTest.cpp @@ -0,0 +1,59 @@ +//===- VisibilityStyleTest.cpp - Visibility style unit tests ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "gtest/gtest.h" + +namespace { + +static void testVisibility(llvm::GlobalValue *value, + llvm::GlobalValue::VisibilityTypes vis, const char *str) { + value->setVisibility(vis); + std::string S; + llvm::raw_string_ostream OS(S); + value->print(OS); + EXPECT_EQ(S, str); +} + +TEST(Visibility, PrintFuncVisibility) { + llvm::LLVMContext C; + llvm::Module M("M", C); + llvm::Function *F = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(C), false), + llvm::GlobalValue::ExternalLinkage, "F", &M); + + testVisibility(F, llvm::GlobalValue::DefaultVisibility, + "declare void @F()\n"); + testVisibility(F, llvm::GlobalValue::ProtectedVisibility, + "declare protected void @F()\n"); + testVisibility(F, llvm::GlobalValue::HiddenVisibility, + "declare hidden void @F()\n"); + testVisibility(F, llvm::GlobalValue::ExportedVisibility, + "declare exported void @F()\n"); +} + +TEST(Visibility, PrintGVVisibility) { + llvm::LLVMContext C; + llvm::Module M("M", C); + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + M, llvm::Type::getFloatTy(C), false, llvm::GlobalValue::ExternalLinkage, + nullptr, "g"); + + testVisibility(GV, llvm::GlobalValue::DefaultVisibility, + "@g = external global float"); + testVisibility(GV, llvm::GlobalValue::ProtectedVisibility, + "@g = external protected global float"); + testVisibility(GV, llvm::GlobalValue::HiddenVisibility, + "@g = external hidden global float"); + testVisibility(GV, llvm::GlobalValue::ExportedVisibility, + "@g = external exported global float"); +} +} // namespace