diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -6553,6 +6553,27 @@ @b = internal global i32 2, comdat $a, section "abc", !associated !0 !0 = !{i32* @a} +'``retain``' Metadata +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``retain`` metadata may be attached to a global object definition. This +metadata marks the section of the global object as a linker GC root. + +If an explicit section is specified, a unique section will be created to not +lose linker GC precision. + +This metadata only has effects on ELF targets. + +Example: + +.. code-block:: llvm + + @a = global i32 1, !retain !{} + @b = constant i32 2, !retain !{} + + define void @f() !retain !{} { + ... + } '``prof``' Metadata ^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def --- a/llvm/include/llvm/IR/FixedMetadataKinds.def +++ b/llvm/include/llvm/IR/FixedMetadataKinds.def @@ -42,3 +42,4 @@ LLVM_FIXED_MD_KIND(MD_vcall_visibility, "vcall_visibility", 28) LLVM_FIXED_MD_KIND(MD_noundef, "noundef", 29) LLVM_FIXED_MD_KIND(MD_annotation, "annotation", 30) +LLVM_FIXED_MD_KIND(MD_retain, "retain", 31) diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -685,9 +685,15 @@ // MD_associated in a unique section. unsigned UniqueID = MCContext::GenericSectionID; const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM); - if (GO->getMetadata(LLVMContext::MD_associated)) { + const bool Associated = GO->getMetadata(LLVMContext::MD_associated); + const bool Retain = GO->getMetadata(LLVMContext::MD_retain); + if (Associated || Retain) { UniqueID = NextUniqueID++; - Flags |= ELF::SHF_LINK_ORDER; + if (Associated) + Flags |= ELF::SHF_LINK_ORDER; + if (Retain && (getContext().getAsmInfo()->useIntegratedAssembler() || + getContext().getAsmInfo()->binutilsIsAtLeast(2, 36))) + Flags |= ELF::SHF_GNU_RETAIN; } else { if (getContext().getAsmInfo()->useIntegratedAssembler() || getContext().getAsmInfo()->binutilsIsAtLeast(2, 35)) { @@ -807,6 +813,12 @@ EmitUniqueSection = true; Flags |= ELF::SHF_LINK_ORDER; } + if (GO->getMetadata(LLVMContext::MD_retain) && + (Ctx.getAsmInfo()->useIntegratedAssembler() || + Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36))) { + EmitUniqueSection = true; + Flags |= ELF::SHF_GNU_RETAIN; + } MCSectionELF *Section = selectELFSectionForGlobal( Ctx, GO, Kind, Mang, TM, EmitUniqueSection, Flags, diff --git a/llvm/test/CodeGen/X86/elf-retain.ll b/llvm/test/CodeGen/X86/elf-retain.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/elf-retain.ll @@ -0,0 +1,52 @@ +; RUN: llc -mtriple=x86_64 < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -data-sections=1 < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -no-integrated-as -binutils-version=2.36 < %s | FileCheck %s +; RUN: llc -mtriple=x86_64 -no-integrated-as -binutils-version=2.35 < %s | FileCheck %s --check-prefix=OLDGAS + +; RUN: llc -mtriple=x86_64 -data-sections=1 -unique-section-names=0 < %s | FileCheck %s --check-prefix=NOUNIQUE + +; CHECK: .section .text.fa,"axR",@progbits{{$}} +; OLDGAS-NOT: .section .text +; NOUNIQUE: .section .text,"axR",@progbits,unique +define dso_local void @fa() !retain !{} { +entry: + ret void +} + +;; Explicit section. +; CHECK: .section bbb,"axR",@progbits,unique,1 +; OLDGAS: .section bbb,"ax",@progbits,unique,1 +; NOUNIQUE: .section bbb,"axR",@progbits,unique +define dso_local void @fb() section "bbb" !retain !{} { +entry: + ret void +} + +; CHECK: .section .data.a,"awR",@progbits{{$}} +; OLDGAS: .data{{$}} +; NOUNIQUE: .section .data,"awR",@progbits,unique,3 +@a = global i32 2, !retain !{} + +; CHECK: .section .bss.b,"awR",@nobits{{$}} +; OLDGAS: .bss{{$}} +; NOUNIQUE: .section .bss,"awR",@nobits,unique,4 +@b = global i32 0, !retain !{} + +; CHECK: .section .rodata.c,"aR",@progbits{{$}} +; OLDGAS: .section .rodata,"a",@progbits{{$}} +; NOUNIQUE: .section .rodata,"aR",@progbits,unique,5 +@c = constant i32 3, !retain !{} + +;; Explicit section. +; CHECK: .section ddd,"awR",@progbits,unique,2 +; OLDGAS: .section ddd,"aw",@progbits,unique,2 +; NOUNIQUE: .section ddd,"awR",@progbits,unique,6 +@d = global i32 1, section "ddd", !retain !{} + +;; Used together with !associated. +; CHECK: .section .data.e,"awoR",@progbits,c +; OLDGAS: .section .data.e,"awo",@progbits,c +; NOUNIQUE: .section .data,"awoR",@progbits,c,unique,7 +@e = global i32 1, !associated !0, !retain !{} + +!0 = !{i32* @c}