summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2017-03-17 22:17:24 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2017-03-17 22:17:24 +0000
commit51c962f72e9569d54dc9c853abf99e2c34fc41cf (patch)
treed0dd2501c4b1c20925959248743eb309e431d5ae
parent46ddab38102b79a8e477a29e68e9441313bc1f86 (diff)
downloadbcm5719-llvm-51c962f72e9569d54dc9c853abf99e2c34fc41cf.tar.gz
bcm5719-llvm-51c962f72e9569d54dc9c853abf99e2c34fc41cf.zip
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
-rw-r--r--llvm/docs/LangRef.rst25
-rw-r--r--llvm/include/llvm/IR/LLVMContext.h1
-rw-r--r--llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp63
-rw-r--r--llvm/lib/IR/LLVMContext.cpp1
-rw-r--r--llvm/test/CodeGen/X86/elf-associated.ll39
-rw-r--r--llvm/test/ThinLTO/X86/lazyload_metadata.ll6
6 files changed, 119 insertions, 16 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index c5771ad5248..d68241f1ab0 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -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
=====================
diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h
index 7f43d5df3c3..d13d5ddaeb3 100644
--- a/llvm/include/llvm/IR/LLVMContext.h
+++ b/llvm/include/llvm/IR/LLVMContext.h
@@ -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
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index dab6231ee1b..1439ff2ad1a 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -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(
diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index dd66f144f04..6c6383c2225 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -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) {
diff --git a/llvm/test/CodeGen/X86/elf-associated.ll b/llvm/test/CodeGen/X86/elf-associated.ll
new file mode 100644
index 00000000000..20baa845277
--- /dev/null
+++ b/llvm/test/CodeGen/X86/elf-associated.ll
@@ -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
diff --git a/llvm/test/ThinLTO/X86/lazyload_metadata.ll b/llvm/test/ThinLTO/X86/lazyload_metadata.ll
index bddabcdf9e7..f5b6b96ebf0 100644
--- a/llvm/test/ThinLTO/X86/lazyload_metadata.ll
+++ b/llvm/test/ThinLTO/X86/lazyload_metadata.ll
@@ -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} \ No newline at end of file
+!9 = !{!6}
OpenPOWER on IntegriCloud