mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-05 02:07:56 +00:00
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:
parent
c0e6994e99
commit
1d01050ac2
@ -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
|
||||
=====================
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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) {
|
||||
|
39
test/CodeGen/X86/elf-associated.ll
Normal file
39
test/CodeGen/X86/elf-associated.ll
Normal 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
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user