diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index d61ea07830123..eec3b7e56dfdf 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -8441,6 +8441,29 @@ The ``nofree`` metadata indicates the memory pointed by the pointer will not be freed after the attached instruction. +'``rename``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^ +The rename key may be attached to a global variable definition that has an +explicit section attribute. It is used as a flag so the associated node +must be empty. It only takes effect when function sections is enabled, and +only on XCOFF targets. The metadata will cause the global to be emitted to a +control section (CSECT) with a name that is an amalgamation of both the section +attribute and the global variables identifier. After the control section is +defined it will be renamed to match the name of the section attribute. This +allows the linker to aggressively garbage collect the symbol if unreferenced, +while directing the linker to merge any control sections with the same name +that remain after garbage collecting into the same CSECT in the output binary. +Commonly used where there is a feature that uses a runtime to walk over a +section using the linker-defined encapsulation symbols +``__start_`` and ``__stop_``. + +Example: + +.. code-block:: llvm + + @a = global i32 1, section "abc", !rename !0 + !0 = !{} + Module Flags Metadata ===================== diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def index d09cc15d65ff6..3b532317fa32f 100644 --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -55,3 +55,4 @@ LLVM_FIXED_MD_KIND(MD_mmra, "mmra", 40) LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41) LLVM_FIXED_MD_KIND(MD_callee_type, "callee_type", 42) LLVM_FIXED_MD_KIND(MD_nofree, "nofree", 43) +LLVM_FIXED_MD_KIND(MD_rename, "rename", 44) diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index ae681b9aebdfb..a9377866d661d 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2431,16 +2431,23 @@ MCSection *TargetLoweringObjectFileXCOFF::getExplicitSectionGlobal( if (!GO->hasSection()) report_fatal_error("#pragma clang section is not yet supported"); - StringRef SectionName = GO->getSection(); + std::string SectionName(GO->getSection()); - // Handle the XCOFF::TD case first, then deal with the rest. - if (const GlobalVariable *GVar = dyn_cast(GO)) + // Have to check for either attributes or metadata that can affect the + // section type or section name. + if (const GlobalVariable *GVar = dyn_cast(GO)) { if (GVar->hasAttribute("toc-data")) return getContext().getXCOFFSection( SectionName, Kind, XCOFF::CsectProperties(/*MappingClass*/ XCOFF::XMC_TD, XCOFF::XTY_SD), /* MultiSymbolsAllowed*/ true); + if (TM.getFunctionSections() && GVar->hasMetadata(LLVMContext::MD_rename)) { + SectionName += "."; + SectionName += GO->getName(); + } + } + XCOFF::StorageMappingClass MappingClass; if (Kind.isText()) MappingClass = XCOFF::XMC_PR; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index c06b60fd2d9a9..7dd3e46c59963 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -766,6 +766,19 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) { DL.getIntPtrType(GO->getType()), RangeLikeMetadataKind::AbsoluteSymbol); } + + if (GO->hasMetadata(LLVMContext::MD_rename)) { + SmallVector MDs; + GO->getMetadata(LLVMContext::MD_rename, MDs); + Check(MDs.size() == 1, + "global value cannot have more then 1 rename metadata", GO); + Check(MDs[0]->getNumOperands() == 0, + "rename metadata must have no operands", GO, MDs[0]); + + Check(GO->hasSection(), + "global value with rename metadata must have section attribute", + GO); + } } Check(!GV.hasAppendingLinkage() || isa(GV), diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 023fd147535ec..8cc93ba522486 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -2970,58 +2970,80 @@ void PPCAIXAsmPrinter::emitGCOVRefs() { } void PPCAIXAsmPrinter::emitEndOfAsmFile(Module &M) { - // If there are no functions and there are no toc-data definitions in this - // module, we will never need to reference the TOC base. - if (M.empty() && TOCDataGlobalVars.empty()) - return; emitPGORefs(M); emitGCOVRefs(); - // Switch to section to emit TOC base. - OutStreamer->switchSection(getObjFileLowering().getTOCBaseSection()); + // If there are no functions and there are no toc-data definitions in this + // module, we will never need to reference the TOC base. + if (!M.empty() || !TOCDataGlobalVars.empty()) { + // Switch to section to emit TOC base. + OutStreamer->switchSection(getObjFileLowering().getTOCBaseSection()); - PPCTargetStreamer *TS = - static_cast(OutStreamer->getTargetStreamer()); + PPCTargetStreamer *TS = + static_cast(OutStreamer->getTargetStreamer()); + + for (auto &I : TOC) { + MCSectionXCOFF *TCEntry; + // Setup the csect for the current TC entry. If the variant kind is + // VK_AIX_TLSGDM the entry represents the region handle, we create a + // new symbol to prefix the name with a dot. + // If TLS model opt is turned on, create a new symbol to prefix the name + // with a dot. + if (I.first.second == PPC::S_AIX_TLSGDM || + (Subtarget->hasAIXShLibTLSModelOpt() && + I.first.second == PPC::S_AIX_TLSLD)) { + SmallString<128> Name; + StringRef Prefix = "."; + Name += Prefix; + Name += static_cast(I.first.first) + ->getSymbolTableName(); + MCSymbol *S = OutContext.getOrCreateSymbol(Name); + TCEntry = static_cast( + getObjFileLowering().getSectionForTOCEntry(S, TM)); + } else { + TCEntry = static_cast( + getObjFileLowering().getSectionForTOCEntry(I.first.first, TM)); + } + OutStreamer->switchSection(TCEntry); - for (auto &I : TOC) { - MCSectionXCOFF *TCEntry; - // Setup the csect for the current TC entry. If the variant kind is - // VK_AIX_TLSGDM the entry represents the region handle, we create a - // new symbol to prefix the name with a dot. - // If TLS model opt is turned on, create a new symbol to prefix the name - // with a dot. - if (I.first.second == PPC::S_AIX_TLSGDM || - (Subtarget->hasAIXShLibTLSModelOpt() && - I.first.second == PPC::S_AIX_TLSLD)) { - SmallString<128> Name; - StringRef Prefix = "."; - Name += Prefix; - Name += static_cast(I.first.first) - ->getSymbolTableName(); - MCSymbol *S = OutContext.getOrCreateSymbol(Name); - TCEntry = static_cast( - getObjFileLowering().getSectionForTOCEntry(S, TM)); - } else { - TCEntry = static_cast( - getObjFileLowering().getSectionForTOCEntry(I.first.first, TM)); + OutStreamer->emitLabel(I.second); + TS->emitTCEntry(*I.first.first, I.first.second); } - OutStreamer->switchSection(TCEntry); - OutStreamer->emitLabel(I.second); - TS->emitTCEntry(*I.first.first, I.first.second); + // Traverse the list of global variables twice, emitting all of the + // non-common global variables before the common ones, as emitting a + // .comm directive changes the scope from .toc to the common symbol. + for (const auto *GV : TOCDataGlobalVars) { + if (!GV->hasCommonLinkage()) + emitGlobalVariableHelper(GV); + } + for (const auto *GV : TOCDataGlobalVars) { + if (GV->hasCommonLinkage()) + emitGlobalVariableHelper(GV); + } } - // Traverse the list of global variables twice, emitting all of the - // non-common global variables before the common ones, as emitting a - // .comm directive changes the scope from .toc to the common symbol. - for (const auto *GV : TOCDataGlobalVars) { - if (!GV->hasCommonLinkage()) - emitGlobalVariableHelper(GV); - } - for (const auto *GV : TOCDataGlobalVars) { - if (GV->hasCommonLinkage()) - emitGlobalVariableHelper(GV); + // Renames only take effect when function sections is enabled. + if (!TM.getFunctionSections()) + return; + + for (const GlobalVariable &GV : M.globals()) { + if (GV.hasMetadata(LLVMContext::MD_rename)) { + // Get orginal csect. + SectionKind GVKind = getObjFileLowering().getKindForGlobal(&GV, TM); + auto *CSect = static_cast( + getObjFileLowering().SectionForGlobal(&GV, GVKind, TM)); + + // Get the section to rename to. + if (!GV.hasSection()) + reportFatalInternalError( + "rename.key metadata used without a section attribute"); + + StringRef SectionName = GV.getSection(); + OutStreamer->emitXCOFFRenameDirective(CSect->getQualNameSymbol(), + SectionName); + } } } diff --git a/llvm/test/CodeGen/PowerPC/aix-rename.ll b/llvm/test/CodeGen/PowerPC/aix-rename.ll new file mode 100644 index 0000000000000..6f5b7c1fd616d --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-rename.ll @@ -0,0 +1,38 @@ +; RUN: llc --function-sections -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck --check-prefix=NOFUNCSECT %s + +@a = global i32 1, section "abcd", !rename !0 +@b = global i32 2, section "abcd", !rename !0 +@c = global i32 3, section "abcd", !rename !0 +@d = global i32 4, section "abcd", !rename !0 + +!0 = !{} + +;CHECK: .csect abcd.a[RW] +;CHECK: .globl a + +;CHECK: .csect abcd.b[RW] +;CHECK: .globl b + +;CHECK: .csect abcd.c[RW] +;CHECK: .globl c + +;CHECK: .csect abcd.d[RW] +;CHECK: .globl d + +;CHECK: .rename abcd.a[RW],"abcd" +;CHECK: .rename abcd.b[RW],"abcd" +;CHECK: .rename abcd.c[RW],"abcd" +;CHECK: .rename abcd.d[RW],"abcd" + +;NOFUNCSECT: .csect abcd[RW],2 +;NOFUNCSECT-NOT: .csect +;NOFUNCSECT: .globl a +;NOFUNCSECT-NOT: .csect +;NOFUNCSECT: .globl b +;NOFUNCSECT-NOT: .csect +;NOFUNCSECT: .globl c +;NOFUNCSECT-NOT: .csect +;NOFUNCSECT: .globl d + +;NOFUNCSECT-NOT: .rename diff --git a/llvm/test/Verifier/PowerPC/lit.local.cfg b/llvm/test/Verifier/PowerPC/lit.local.cfg new file mode 100644 index 0000000000000..bb982488eb15e --- /dev/null +++ b/llvm/test/Verifier/PowerPC/lit.local.cfg @@ -0,0 +1,2 @@ +if not "PowerPC" in config.root.targets: + config.unsupported = True diff --git a/llvm/test/Verifier/PowerPC/multiple_rename.ll b/llvm/test/Verifier/PowerPC/multiple_rename.ll new file mode 100644 index 0000000000000..deb9665bf9a63 --- /dev/null +++ b/llvm/test/Verifier/PowerPC/multiple_rename.ll @@ -0,0 +1,8 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +@a = global i32 1, section "abc", !rename !0, !rename !1 + +!0 = !{} +!1 = !{} + +; CHECK: global value cannot have more then 1 rename metadata diff --git a/llvm/test/Verifier/PowerPC/rename_no_section.ll b/llvm/test/Verifier/PowerPC/rename_no_section.ll new file mode 100644 index 0000000000000..2a709fecb06b2 --- /dev/null +++ b/llvm/test/Verifier/PowerPC/rename_no_section.ll @@ -0,0 +1,8 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +@a = global i32 1, !rename !0 + +!0 = !{} + +; CHECK: global value with rename metadata must have section attribute +; CHECK: ptr @a diff --git a/llvm/test/Verifier/PowerPC/rename_operands.ll b/llvm/test/Verifier/PowerPC/rename_operands.ll new file mode 100644 index 0000000000000..7044b29709af9 --- /dev/null +++ b/llvm/test/Verifier/PowerPC/rename_operands.ll @@ -0,0 +1,8 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +@a = global i32 1, section "abc", !rename !0 + +!0 = !{!"Hello World!"} +; CHECK: rename metadata must have no operands +; CHECK: ptr @a +; CHECK: !0 = !{!"Hello World!"}