Skip to content

Commit

Permalink
Add !associated metadata.
Browse files Browse the repository at this point in the history
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298157 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
eugenis committed Mar 17, 2017
1 parent 87552d6 commit df808fe
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 16 deletions.
25 changes: 25 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=====================
Expand Down
1 change: 1 addition & 0 deletions include/llvm/IR/LLVMContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class LLVMContext {
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
Expand Down
63 changes: 50 additions & 13 deletions lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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
Expand All @@ -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()) {
Expand Down Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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(
Expand Down
1 change: 1 addition & 0 deletions lib/IR/LLVMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
39 changes: 39 additions & 0 deletions test/CodeGen/X86/elf-associated.ll
Original file line number Diff line number Diff line change
@@ -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
6 changes: 3 additions & 3 deletions test/ThinLTO/X86/lazyload_metadata.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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}

0 comments on commit df808fe

Please sign in to comment.