Add !associated metadata.

This is an ELF-specific thing that adds SHF_LINK_ORDER to the global's section
pointing to the metadata argument's section. The effect of that is a reverse dependency
between sections for the linker GC.

!associated does not change the behavior of global-dce. The global
may also need to be added to llvm.compiler.used.

Since SHF_LINK_ORDER is per-section, !associated effectively enables
fdata-sections for the affected globals, the same as comdats do.

Differential Revision: https://reviews.llvm.org/D29104

llvm-svn: 298157
This commit is contained in:
Evgeniy Stepanov 2017-03-17 22:17:24 +00:00
parent c0e6994e99
commit 1d01050ac2
6 changed files with 119 additions and 16 deletions

View File

@ -5106,6 +5106,31 @@ Examples:
See :doc:`TypeMetadata`.
'``associated``' Metadata
^^^^^^^^^^^^^^^^^^^
The ``associated`` metadata may be attached to a global object
declaration with a single argument that references another global object.
This metadata prevents discarding of the global object in linker GC
unless the referenced object is also discarded. The linker support for
this feature is spotty. For best compatibility, globals carrying this
metadata may also:
- Be in a comdat with the referenced global.
- Be in @llvm.compiler.used.
- Have an explicit section with a name which is a valid C identifier.
It does not have any effect on non-ELF targets.
Example:
.. code-block:: llvm
$a = comdat any
@a = global i32 1, comdat $a
@b = internal global i32 2, comdat $a, section "abc", !associated !0
!0 = !{i32* @a}
Module Flags Metadata
=====================

View File

@ -78,6 +78,7 @@ public:
MD_type = 19, // "type"
MD_section_prefix = 20, // "section_prefix"
MD_absolute_symbol = 21, // "absolute_symbol"
MD_associated = 22, // "associated"
};
/// Known operand bundle tag IDs, which always have the same value. All

View File

@ -225,6 +225,20 @@ static const Comdat *getELFComdat(const GlobalValue *GV) {
return C;
}
static const MCSymbolELF *getAssociatedSymbol(const GlobalObject *GO,
const TargetMachine &TM) {
MDNode *MD = GO->getMetadata(LLVMContext::MD_associated);
if (!MD)
return nullptr;
auto *VM = dyn_cast<ValueAsMetadata>(MD->getOperand(0));
if (!VM)
report_fatal_error("MD_associated operand is not ValueAsMetadata");
GlobalObject *OtherGO = dyn_cast<GlobalObject>(VM->getValue());
return OtherGO ? dyn_cast<MCSymbolELF>(TM.getSymbol(OtherGO)) : nullptr;
}
MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
StringRef SectionName = GO->getSection();
@ -238,9 +252,23 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
Group = C->getName();
Flags |= ELF::SHF_GROUP;
}
return getContext().getELFSection(SectionName,
getELFSectionType(SectionName, Kind), Flags,
/*EntrySize=*/0, Group);
// A section can have at most one associated section. Put each global with
// MD_associated in a unique section.
unsigned UniqueID = MCContext::GenericSectionID;
const MCSymbolELF *AssociatedSymbol = getAssociatedSymbol(GO, TM);
if (AssociatedSymbol) {
UniqueID = NextUniqueID++;
Flags |= ELF::SHF_LINK_ORDER;
}
MCSectionELF *Section = getContext().getELFSection(
SectionName, getELFSectionType(SectionName, Kind), Flags,
/*EntrySize=*/0, Group, UniqueID, AssociatedSymbol);
// Make sure that we did not get some other section with incompatible sh_link.
// This should not be possible due to UniqueID code above.
assert(Section->getAssociatedSymbol() == AssociatedSymbol);
return Section;
}
/// Return the section prefix name used by options FunctionsSections and
@ -262,11 +290,10 @@ static StringRef getSectionPrefixForGlobal(SectionKind Kind) {
return ".data.rel.ro";
}
static MCSectionELF *
selectELFSectionForGlobal(MCContext &Ctx, const GlobalObject *GO,
SectionKind Kind, Mangler &Mang,
const TargetMachine &TM, bool EmitUniqueSection,
unsigned Flags, unsigned *NextUniqueID) {
static MCSectionELF *selectELFSectionForGlobal(
MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang,
const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags,
unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) {
unsigned EntrySize = 0;
if (Kind.isMergeableCString()) {
if (Kind.isMergeable2ByteCString()) {
@ -333,7 +360,7 @@ selectELFSectionForGlobal(MCContext &Ctx, const GlobalObject *GO,
if (Kind.isExecuteOnly())
UniqueID = 0;
return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags,
EntrySize, Group, UniqueID);
EntrySize, Group, UniqueID, AssociatedSymbol);
}
MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
@ -351,8 +378,17 @@ MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal(
}
EmitUniqueSection |= GO->hasComdat();
return selectELFSectionForGlobal(getContext(), GO, Kind, getMangler(), TM,
EmitUniqueSection, Flags, &NextUniqueID);
const MCSymbolELF *AssociatedSymbol = getAssociatedSymbol(GO, TM);
if (AssociatedSymbol) {
EmitUniqueSection = true;
Flags |= ELF::SHF_LINK_ORDER;
}
MCSectionELF *Section = selectELFSectionForGlobal(
getContext(), GO, Kind, getMangler(), TM, EmitUniqueSection, Flags,
&NextUniqueID, AssociatedSymbol);
assert(Section->getAssociatedSymbol() == AssociatedSymbol);
return Section;
}
MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(
@ -365,8 +401,9 @@ MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(
return ReadOnlySection;
return selectELFSectionForGlobal(getContext(), &F, SectionKind::getReadOnly(),
getMangler(), TM, EmitUniqueSection, ELF::SHF_ALLOC,
&NextUniqueID);
getMangler(), TM, EmitUniqueSection,
ELF::SHF_ALLOC, &NextUniqueID,
/* AssociatedSymbol */ nullptr);
}
bool TargetLoweringObjectFileELF::shouldPutJumpTableInFunctionSection(

View File

@ -58,6 +58,7 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
{MD_type, "type"},
{MD_section_prefix, "section_prefix"},
{MD_absolute_symbol, "absolute_symbol"},
{MD_associated, "associated"},
};
for (auto &MDKind : MDKinds) {

View File

@ -0,0 +1,39 @@
; RUN: llc -data-sections=1 -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s
; RUN: llc -data-sections=0 -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s
@a = global i32 1
@b = global i32 2, !associated !0
!0 = !{i32* @a}
; CHECK-DAG: .section .data.b,"awm",@progbits,a
; Loop is OK. Also, normally -data-sections=0 would place @c and @d in the same section. !associated prevents that.
@c = global i32 2, !associated !2
@d = global i32 2, !associated !1
!1 = !{i32* @c}
!2 = !{i32* @d}
; CHECK-DAG: .section .data.c,"awm",@progbits,d
; CHECK-DAG: .section .data.d,"awm",@progbits,c
; BSS is OK.
@e = global i32 0
@f = global i32 0, !associated !3
@g = global i32 1, !associated !3
!3 = !{i32* @e}
; CHECK-DAG: .section .bss.f,"awm",@nobits,e
; CHECK-DAG: .section .data.g,"awm",@progbits,e
; Explicit sections.
@h = global i32 1, section "aaa"
@i = global i32 1, section "bbb", !associated !4
@j = global i32 1, section "bbb", !associated !4
@k = global i32 1, !associated !4
!4 = !{i32* @h}
; CHECK-DAG: .section aaa,"aw",@progbits
; CHECK-DAG: .section bbb,"awm",@progbits,h,unique,1
; CHECK-DAG: .section bbb,"awm",@progbits,h,unique,2
; CHECK-DAG: .section .data.k,"awm",@progbits,h
; Non-GlobalObject metadata.
@l = global i32 1, section "ccc", !associated !5
!5 = !{i32* null}
; CHECK-DAG: .section ccc,"aw",@progbits

View File

@ -10,13 +10,13 @@
; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
; RUN: -o /dev/null -stats \
; RUN: 2>&1 | FileCheck %s -check-prefix=LAZY
; LAZY: 49 bitcode-reader - Number of Metadata records loaded
; LAZY: 51 bitcode-reader - Number of Metadata records loaded
; LAZY: 2 bitcode-reader - Number of MDStrings loaded
; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
; RUN: -o /dev/null -disable-ondemand-mds-loading -stats \
; RUN: 2>&1 | FileCheck %s -check-prefix=NOTLAZY
; NOTLAZY: 58 bitcode-reader - Number of Metadata records loaded
; NOTLAZY: 60 bitcode-reader - Number of Metadata records loaded
; NOTLAZY: 7 bitcode-reader - Number of MDStrings loaded
@ -55,4 +55,4 @@ declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
!6 = !{!9}
!7 = !{!"7"}
!8 = !{!"8"}
!9 = !{!6}
!9 = !{!6}