[llvm] XCOFF associated metadata (PR #159096)
Sean Fertile via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 30 08:07:14 PDT 2025
https://github.com/mandlebug updated https://github.com/llvm/llvm-project/pull/159096
>From 59348a2b49970ec42069eff375eeeed5d67918ad Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Mon, 15 Sep 2025 15:46:17 -0400
Subject: [PATCH 1/7] Extend the associated metadata node impl for XCOFF.
Add support for the associated metadata node for AIX.. Map it to
the .ref assembly directive. Placing the node on a symbol will cause
the back end to emit a .ref directive in the section of the global the
metadata is placed on. the .ref will refrence the associated symbol
which will keep it alive if the section is not garbage collected.
---
llvm/docs/LangRef.rst | 30 +++++++++++++++----
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 19 ++++++++++++
.../PowerPC/aix-associated-metadata.ll | 23 ++++++++++++++
3 files changed, 66 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index d61ea07830123..f89ffd7118869 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8124,6 +8124,13 @@ See :doc:`CalleeTypeMetadata`.
The ``associated`` metadata may be attached to a global variable definition with
a single argument that references a global object (optionally through an alias).
+The metadata is often used with an explicit section consisting of valid C
+identifiers so that the runtime can find the metadata section with
+linker-defined encapsulation symbols ``__start_<section_name>`` and
+``__stop_<section_name>``.
+
+ELF Targets
+"""""""""""
This metadata lowers to the ELF section flag ``SHF_LINK_ORDER`` which prevents
discarding of the global variable in linker GC unless the referenced object is
@@ -8141,12 +8148,6 @@ alive, but this many-to-one relationship is not representable. Moreover, if the
metadata is retained while the function is discarded, the linker will report an
error of a relocation referencing a discarded section.
-The metadata is often used with an explicit section consisting of valid C
-identifiers so that the runtime can find the metadata section with
-linker-defined encapsulation symbols ``__start_<section_name>`` and
-``__stop_<section_name>``.
-
-It does not have any effect on non-ELF targets.
Example:
@@ -8157,6 +8158,23 @@ Example:
@b = internal global i32 2, comdat $a, section "abc", !associated !0
!0 = !{ptr @a}
+XCOFF Targets
+"""""""""""""
+
+This metadata lowers to the .ref assembly directive which will add a relocation
+representing an implicit reference from the section the global belongs to, to
+the associated symbol. This link will keep the associated symbol alive if the
+section is not garbage collected. More than one associated node can be attached
+to the same global variable.
+
+Example:
+.. code-block:: text
+
+ @a = global i32 1
+ @b = global i32 2
+ @c = global i32 3, section "abc", !associated !0, !associated !1
+ !0 = !{ptr @a}
+ !1 = !{ptr @b}
'``prof``' Metadata
^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 023fd147535ec..d403811327667 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -305,6 +305,8 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
void emitTTypeReference(const GlobalValue *GV, unsigned Encoding) override;
void emitModuleCommandLines(Module &M) override;
+
+ void emitAssociatedMetadata(const GlobalObject *);
};
} // end anonymous namespace
@@ -2797,6 +2799,10 @@ void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) {
// Switch to the containing csect.
OutStreamer->switchSection(Csect);
+ if (GV->hasMetadata(LLVMContext::MD_associated)) {
+ emitAssociatedMetadata(GV);
+ }
+
const DataLayout &DL = GV->getDataLayout();
// Handle common and zero-initialized local symbols.
@@ -3332,6 +3338,19 @@ void PPCAIXAsmPrinter::emitTTypeReference(const GlobalValue *GV,
OutStreamer->emitIntValue(0, GetSizeOfEncodedValue(Encoding));
}
+void PPCAIXAsmPrinter::emitAssociatedMetadata(const GlobalObject *GO) {
+ SmallVector< MDNode * > MDs;
+ GO->getMetadata(LLVMContext::MD_associated, MDs);
+ assert(MDs.size() && "Expected asscoiated metadata nodes");
+
+ for (const MDNode *MD : MDs) {
+ const ValueAsMetadata *VAM = cast<ValueAsMetadata>(MD->getOperand(0).get());
+ const GlobalValue *Associated = cast<GlobalValue>(VAM->getValue());
+ MCSymbol *Referenced = TM.getSymbol(Associated);
+ OutStreamer->emitXCOFFRefDirective(Referenced);
+ }
+}
+
// Return a pass that prints the PPC assembly code for a MachineFunction to the
// given output stream.
static AsmPrinter *
diff --git a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
new file mode 100644
index 0000000000000..edf157934b205
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
@@ -0,0 +1,23 @@
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s
+
+ at a = global i32 1
+ at b = global i32 2
+ at c = global i32 3, section "custom_section_c"
+ at d = global i32 4, !associated !0
+ at e = constant i32 5, !associated !1, !associated !2
+ at f = global i32 6, section "custom_section_f", !associated !1
+
+
+!0 = !{ptr @a}
+!1 = !{ptr @b}
+!2 = !{ptr @c}
+
+; CHECK: .csect d[RW]
+; CHECK: .ref a[RW]
+
+; CHECK: .csect e[RO]
+; CHECK: .ref b[RW]
+; CHECK: .ref c
+
+; CHECK: .csect custom_section_f[RW]
+; CHECK: .ref b[RW]
>From a774cee70c5b804571b7164df1728cb2dd9963ff Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Tue, 16 Sep 2025 09:37:13 -0400
Subject: [PATCH 2/7] Run clang-format over changes.
---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index d403811327667..be99346752cb2 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -3339,7 +3339,7 @@ void PPCAIXAsmPrinter::emitTTypeReference(const GlobalValue *GV,
}
void PPCAIXAsmPrinter::emitAssociatedMetadata(const GlobalObject *GO) {
- SmallVector< MDNode * > MDs;
+ SmallVector<MDNode *> MDs;
GO->getMetadata(LLVMContext::MD_associated, MDs);
assert(MDs.size() && "Expected asscoiated metadata nodes");
>From 35b959b73b32f26565d86262aaa5ec1346c9f394 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Thu, 18 Sep 2025 10:38:07 -0400
Subject: [PATCH 3/7] Test .ref impl with data sections disabled.
---
.../PowerPC/aix-associated-metadata.ll | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
index edf157934b205..8a5c36fd2b4b8 100644
--- a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
@@ -1,4 +1,5 @@
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s
+; RUN: llc -data-sections=false -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck -check-prefix=NODATA %s
@a = global i32 1
@b = global i32 2
@@ -21,3 +22,21 @@
; CHECK: .csect custom_section_f[RW]
; CHECK: .ref b[RW]
+
+; NODATA: .csect .data[RW]
+; NODATA-NOT: .csect
+; NODATA: .globl a
+; NODATA-NOT: .csect
+; NODATA: .globl b
+; NODATA: .csect custom_section_c[RW]
+; NODATA: .globl c
+; NODATA: .csect .data[RW]
+; NODATA: .ref a
+; NODATA: .globl d
+; NODATA: .csect .rodata[RO]
+; NODATA: .ref b
+; NODATA: .ref c
+; NODATA: .globl e
+; NODATA: .csect custom_section_f[RW]
+; NODATA: .ref b
+; NODATA: .globl f
>From 57d9cdc70e207b40cb98ccfce1e34b26b2aa23ab Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Thu, 18 Sep 2025 11:03:20 -0400
Subject: [PATCH 4/7] Check multiple associated metadata nodes in the verifier.
---
llvm/lib/IR/Verifier.cpp | 47 ++++++++++++++---------
llvm/test/Verifier/associated-multiple.ll | 13 +++++++
2 files changed, 42 insertions(+), 18 deletions(-)
create mode 100644 llvm/test/Verifier/associated-multiple.ll
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index c06b60fd2d9a9..19e92a1404705 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -737,25 +737,36 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
"Global is external, but doesn't have external or weak linkage!", &GV);
if (const GlobalObject *GO = dyn_cast<GlobalObject>(&GV)) {
- if (const MDNode *Associated =
- GO->getMetadata(LLVMContext::MD_associated)) {
- Check(Associated->getNumOperands() == 1,
- "associated metadata must have one operand", &GV, Associated);
- const Metadata *Op = Associated->getOperand(0).get();
- Check(Op, "associated metadata must have a global value", GO, Associated);
-
- const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
- Check(VM, "associated metadata must be ValueAsMetadata", GO, Associated);
- if (VM) {
- Check(isa<PointerType>(VM->getValue()->getType()),
- "associated value must be pointer typed", GV, Associated);
-
- const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases();
- Check(isa<GlobalObject>(Stripped) || isa<Constant>(Stripped),
- "associated metadata must point to a GlobalObject", GO, Stripped);
- Check(Stripped != GO,
- "global values should not associate to themselves", GO,
+ if (GO->hasMetadata(LLVMContext::MD_associated)) {
+ SmallVector<MDNode *, 1> MDs;
+ GO->getMetadata(LLVMContext::MD_associated, MDs);
+
+ if (TT.isOSBinFormatELF())
+ Check(MDs.size() == 1, "only a single associated metadata is supported",
+ &GV);
+
+ for (const MDNode *Associated : MDs) {
+ Check(Associated->getNumOperands() == 1,
+ "associated metadata must have one operand", &GV, Associated);
+ const Metadata *Op = Associated->getOperand(0).get();
+ Check(Op, "associated metadata must have a global value", GO,
Associated);
+
+ const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
+ Check(VM, "associated metadata must be ValueAsMetadata", GO,
+ Associated);
+ if (VM) {
+ Check(isa<PointerType>(VM->getValue()->getType()),
+ "associated value must be pointer typed", GV, Associated);
+
+ const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases();
+ Check(isa<GlobalObject>(Stripped) || isa<Constant>(Stripped),
+ "associated metadata must point to a GlobalObject", GO,
+ Stripped);
+ Check(Stripped != GO,
+ "global values should not associate to themselves", GO,
+ Associated);
+ }
}
}
diff --git a/llvm/test/Verifier/associated-multiple.ll b/llvm/test/Verifier/associated-multiple.ll
new file mode 100644
index 0000000000000..5a640fbe5efed
--- /dev/null
+++ b/llvm/test/Verifier/associated-multiple.ll
@@ -0,0 +1,13 @@
+; RUN: not llvm-as -disable-output < %s -o /dev/null 2>&1 | FileCheck %s
+
+target triple = "unknown-unknown-linux-gnu"
+
+ at a = global i32 1
+ at b = global i32 2
+ at c = global i32 3, !associated !0, !associated !1
+
+!0 = !{ptr @a}
+!1 = !{ptr @b}
+
+; CHECK: only a single associated metadata is supported
+; CHECK: ptr @c
>From 05ca043f5fc312416ac74047036c707fda3d31f7 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Thu, 18 Sep 2025 16:31:35 -0400
Subject: [PATCH 5/7] Add testing of the integrated assembler path.
---
.../PowerPC/aix-associated-metadata.ll | 35 +++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
index 8a5c36fd2b4b8..8613b32f06e05 100644
--- a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
@@ -1,6 +1,12 @@
; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s
; RUN: llc -data-sections=false -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck -check-prefix=NODATA %s
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
+; RUN: llvm-objdump -D -r --symbol-description %t.o | FileCheck -check-prefix=OBJ %s
+
+; RUN: llc -data-sections=false -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -filetype=obj -o %t.o < %s
+; RUN: llvm-objdump -D -r --symbol-description %t.o | FileCheck -check-prefix=OBJ-NODATA %s
+
@a = global i32 1
@b = global i32 2
@c = global i32 3, section "custom_section_c"
@@ -40,3 +46,32 @@
; NODATA: .csect custom_section_f[RW]
; NODATA: .ref b
; NODATA: .globl f
+
+; OBJ: Disassembly of section .text:
+
+; OBJ: e[RO]:
+; OBJ: R_REF {{.*}} b[RW]
+; OBJ: R_REF {{.*}} c
+
+; OBJ: Disassembly of section .data:
+; OBJ: a[RW]:
+; OBJ: b[RW]:
+; OBJ: c:
+; OBJ: d[RW]:
+; OBJ: R_REF {{.*}} a[RW]
+; OBJ: f:
+; OBJ: R_REF {{.*}} b[RW]
+
+; OBJ-NODATA: Disassembly of section .text:
+; OBJ-NODATA: e:
+; OBJ-NODATA: R_REF {{.*}} b
+; OBJ-NODATA: R_REF {{.*}} c
+
+; OBJ-NODATA: Disassembly of section .data:
+; OBJ-NODATA: a:
+; OBJ-NODATA: R_REF {{.*}} a
+; OBJ-NODATA: b:
+; OBJ-NODATA: d:
+; OBJ-NODATA: c:
+; OBJ-NODATA: f:
+; OBJ-NODATA: R_REF {{.*}} b
>From 25e67fb468fa28295b23a8a66d16b5a91c4f2447 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Wed, 24 Sep 2025 14:27:56 -0400
Subject: [PATCH 6/7] Add a new metadata node rather then piggybacking on
associated.
---
llvm/docs/LangRef.rst | 59 ++++++++-------
llvm/include/llvm/IR/FixedMetadataKinds.def | 1 +
llvm/lib/IR/Verifier.cpp | 71 +++++++++++--------
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 14 ++--
.../PowerPC/aix-associated-metadata.ll | 6 +-
llvm/test/Verifier/associated-multiple.ll | 13 ----
llvm/test/Verifier/ref.ll | 28 ++++++++
7 files changed, 116 insertions(+), 76 deletions(-)
delete mode 100644 llvm/test/Verifier/associated-multiple.ll
create mode 100644 llvm/test/Verifier/ref.ll
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index f89ffd7118869..3ae3c5e63b971 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8124,13 +8124,6 @@ See :doc:`CalleeTypeMetadata`.
The ``associated`` metadata may be attached to a global variable definition with
a single argument that references a global object (optionally through an alias).
-The metadata is often used with an explicit section consisting of valid C
-identifiers so that the runtime can find the metadata section with
-linker-defined encapsulation symbols ``__start_<section_name>`` and
-``__stop_<section_name>``.
-
-ELF Targets
-"""""""""""
This metadata lowers to the ELF section flag ``SHF_LINK_ORDER`` which prevents
discarding of the global variable in linker GC unless the referenced object is
@@ -8148,6 +8141,12 @@ alive, but this many-to-one relationship is not representable. Moreover, if the
metadata is retained while the function is discarded, the linker will report an
error of a relocation referencing a discarded section.
+The metadata is often used with an explicit section consisting of valid C
+identifiers so that the runtime can find the metadata section with
+linker-defined encapsulation symbols ``__start_<section_name>`` and
+``__stop_<section_name>``.
+
+It does not have any effect on non-ELF targets.
Example:
@@ -8158,23 +8157,6 @@ Example:
@b = internal global i32 2, comdat $a, section "abc", !associated !0
!0 = !{ptr @a}
-XCOFF Targets
-"""""""""""""
-
-This metadata lowers to the .ref assembly directive which will add a relocation
-representing an implicit reference from the section the global belongs to, to
-the associated symbol. This link will keep the associated symbol alive if the
-section is not garbage collected. More than one associated node can be attached
-to the same global variable.
-
-Example:
-.. code-block:: text
-
- @a = global i32 1
- @b = global i32 2
- @c = global i32 3, section "abc", !associated !0, !associated !1
- !0 = !{ptr @a}
- !1 = !{ptr @b}
'``prof``' Metadata
^^^^^^^^^^^^^^^^^^^
@@ -8458,6 +8440,35 @@ Example:
The ``nofree`` metadata indicates the memory pointed by the pointer will not be
freed after the attached instruction.
+'``ref``' Metadata
+^^^^^^^^^^^^^^^^^^
+
+The ``ref`` metadata may be attached to a global variable definition with a
+single argument that references a global object. The metadata is lowered to a
+.ref directive which will emit a relocation introducing an explicit dependence
+to the referenced symbol. This is typically used when there is some implicit
+dependence between the symbols that is otherwise opaque to the linker. One such
+example is metadata which is accessed by a runtime with associated
+``__start_<section_name>`` and ``__stop_<section_name>`` symbols.
+
+This metadata lowers to the .ref assembly directive which will add a relocation
+representing an implicit reference from the section the global belongs to, to
+the associated symbol. This link will keep the associated symbol alive if the
+section is not garbage collected. More than one associated node can be attached
+to the same global variable.
+
+It does not have any effect on non-XCOFF targets.
+
+Example:
+
+.. code-block:: text
+
+ @a = global i32 1
+ @b = global i32 2
+ @c = global i32 3, section "abc", !ref !0, !ref !1
+ !0 = !{ptr @a}
+ !1 = !{ptr @b}
+
Module Flags Metadata
=====================
diff --git a/llvm/include/llvm/IR/FixedMetadataKinds.def b/llvm/include/llvm/IR/FixedMetadataKinds.def
index d09cc15d65ff6..d9cc802446654 100644
--- a/llvm/include/llvm/IR/FixedMetadataKinds.def
+++ b/llvm/include/llvm/IR/FixedMetadataKinds.def
@@ -55,3 +55,4 @@ LLVM_FIXED_MD_KIND(MD_mmra, "mmra", 40)
LLVM_FIXED_MD_KIND(MD_noalias_addrspace, "noalias.addrspace", 41)
LLVM_FIXED_MD_KIND(MD_callee_type, "callee_type", 42)
LLVM_FIXED_MD_KIND(MD_nofree, "nofree", 43)
+LLVM_FIXED_MD_KIND(MD_ref, "ref", 44)
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 19e92a1404705..08822e8ffbc85 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -737,36 +737,25 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
"Global is external, but doesn't have external or weak linkage!", &GV);
if (const GlobalObject *GO = dyn_cast<GlobalObject>(&GV)) {
- if (GO->hasMetadata(LLVMContext::MD_associated)) {
- SmallVector<MDNode *, 1> MDs;
- GO->getMetadata(LLVMContext::MD_associated, MDs);
-
- if (TT.isOSBinFormatELF())
- Check(MDs.size() == 1, "only a single associated metadata is supported",
- &GV);
-
- for (const MDNode *Associated : MDs) {
- Check(Associated->getNumOperands() == 1,
- "associated metadata must have one operand", &GV, Associated);
- const Metadata *Op = Associated->getOperand(0).get();
- Check(Op, "associated metadata must have a global value", GO,
+ if (const MDNode *Associated =
+ GO->getMetadata(LLVMContext::MD_associated)) {
+ Check(Associated->getNumOperands() == 1,
+ "associated metadata must have one operand", &GV, Associated);
+ const Metadata *Op = Associated->getOperand(0).get();
+ Check(Op, "associated metadata must have a global value", GO, Associated);
+
+ const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
+ Check(VM, "associated metadata must be ValueAsMetadata", GO, Associated);
+ if (VM) {
+ Check(isa<PointerType>(VM->getValue()->getType()),
+ "associated value must be pointer typed", GV, Associated);
+
+ const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases();
+ Check(isa<GlobalObject>(Stripped) || isa<Constant>(Stripped),
+ "associated metadata must point to a GlobalObject", GO, Stripped);
+ Check(Stripped != GO,
+ "global values should not associate to themselves", GO,
Associated);
-
- const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
- Check(VM, "associated metadata must be ValueAsMetadata", GO,
- Associated);
- if (VM) {
- Check(isa<PointerType>(VM->getValue()->getType()),
- "associated value must be pointer typed", GV, Associated);
-
- const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases();
- Check(isa<GlobalObject>(Stripped) || isa<Constant>(Stripped),
- "associated metadata must point to a GlobalObject", GO,
- Stripped);
- Check(Stripped != GO,
- "global values should not associate to themselves", GO,
- Associated);
- }
}
}
@@ -777,6 +766,30 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
DL.getIntPtrType(GO->getType()),
RangeLikeMetadataKind::AbsoluteSymbol);
}
+
+ if (GO->hasMetadata(LLVMContext::MD_ref)) {
+ SmallVector<MDNode *> MDs;
+ GO->getMetadata(LLVMContext::MD_ref, MDs);
+ for (const MDNode *MD : MDs) {
+ Check(MD->getNumOperands() == 1, "ref metadata must have one operand",
+ &GV, MD);
+ const Metadata *Op = MD->getOperand(0).get();
+ Check(Op, "ref metadata must have a global value", GO, MD);
+
+ const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
+ Check(VM, "ref metadata must be ValueAsMetadata", GO, MD);
+ if (VM) {
+ Check(isa<PointerType>(VM->getValue()->getType()),
+ "ref value must be pointer typed", GV, MD);
+
+ const Value *Stripped = VM->getValue()->stripPointerCastsAndAliases();
+ Check(isa<GlobalObject>(Stripped) || isa<Constant>(Stripped),
+ "ref metadata must point to a GlobalObject", GO, Stripped);
+ Check(Stripped != GO, "values should not reference themselves", GO,
+ MD);
+ }
+ }
+ }
}
Check(!GV.hasAppendingLinkage() || isa<GlobalVariable>(GV),
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index be99346752cb2..652fe7e16f840 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -306,7 +306,7 @@ class PPCAIXAsmPrinter : public PPCAsmPrinter {
void emitModuleCommandLines(Module &M) override;
- void emitAssociatedMetadata(const GlobalObject *);
+ void emitRefMetadata(const GlobalObject *);
};
} // end anonymous namespace
@@ -2799,8 +2799,8 @@ void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) {
// Switch to the containing csect.
OutStreamer->switchSection(Csect);
- if (GV->hasMetadata(LLVMContext::MD_associated)) {
- emitAssociatedMetadata(GV);
+ if (GV->hasMetadata(LLVMContext::MD_ref)) {
+ emitRefMetadata(GV);
}
const DataLayout &DL = GV->getDataLayout();
@@ -3338,15 +3338,15 @@ void PPCAIXAsmPrinter::emitTTypeReference(const GlobalValue *GV,
OutStreamer->emitIntValue(0, GetSizeOfEncodedValue(Encoding));
}
-void PPCAIXAsmPrinter::emitAssociatedMetadata(const GlobalObject *GO) {
+void PPCAIXAsmPrinter::emitRefMetadata(const GlobalObject *GO) {
SmallVector<MDNode *> MDs;
- GO->getMetadata(LLVMContext::MD_associated, MDs);
+ GO->getMetadata(LLVMContext::MD_ref, MDs);
assert(MDs.size() && "Expected asscoiated metadata nodes");
for (const MDNode *MD : MDs) {
const ValueAsMetadata *VAM = cast<ValueAsMetadata>(MD->getOperand(0).get());
- const GlobalValue *Associated = cast<GlobalValue>(VAM->getValue());
- MCSymbol *Referenced = TM.getSymbol(Associated);
+ const GlobalValue *GV = cast<GlobalValue>(VAM->getValue());
+ MCSymbol *Referenced = TM.getSymbol(GV);
OutStreamer->emitXCOFFRefDirective(Referenced);
}
}
diff --git a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
index 8613b32f06e05..1eb7eaa3c58d2 100644
--- a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
@@ -10,9 +10,9 @@
@a = global i32 1
@b = global i32 2
@c = global i32 3, section "custom_section_c"
- at d = global i32 4, !associated !0
- at e = constant i32 5, !associated !1, !associated !2
- at f = global i32 6, section "custom_section_f", !associated !1
+ at d = global i32 4, !ref !0
+ at e = constant i32 5, !ref !1, !ref!2
+ at f = global i32 6, section "custom_section_f", !ref !1
!0 = !{ptr @a}
diff --git a/llvm/test/Verifier/associated-multiple.ll b/llvm/test/Verifier/associated-multiple.ll
deleted file mode 100644
index 5a640fbe5efed..0000000000000
--- a/llvm/test/Verifier/associated-multiple.ll
+++ /dev/null
@@ -1,13 +0,0 @@
-; RUN: not llvm-as -disable-output < %s -o /dev/null 2>&1 | FileCheck %s
-
-target triple = "unknown-unknown-linux-gnu"
-
- at a = global i32 1
- at b = global i32 2
- at c = global i32 3, !associated !0, !associated !1
-
-!0 = !{ptr @a}
-!1 = !{ptr @b}
-
-; CHECK: only a single associated metadata is supported
-; CHECK: ptr @c
diff --git a/llvm/test/Verifier/ref.ll b/llvm/test/Verifier/ref.ll
new file mode 100644
index 0000000000000..5f5dca0f965d6
--- /dev/null
+++ b/llvm/test/Verifier/ref.ll
@@ -0,0 +1,28 @@
+; RUN: not llvm-as -disable-output < %s -o /dev/null 2>&1 | FileCheck %s
+
+ at a = global i32 1, !ref !0
+ at b = global i32 2, !ref !1
+ at c = global i32 3, !ref !1, !ref !2
+ at d = global i32 4, !ref !3
+
+!0 = !{i32 1}
+!1 = !{ptr @b}
+!2 = !{!"Hello World!"}
+!3 = !{ptr @c, ptr @a}
+
+; CHECK: ref value must be pointer typed
+; CHECK: ptr @a
+; CHECK: !0 = !{i32 1}
+
+; CHECK: values should not reference themselves
+; CHECK: ptr @b
+; CHECK: !1 = !{ptr @b}
+
+; CHECK: ref metadata must be ValueAsMetadata
+; CHECK: ptr @c
+; CHECK: !2 = !{!"Hello World!"}
+
+; CHECK: ref metadata must have one operand
+; CHECK: ptr @d
+; CHECK: !3 = !{ptr @c, ptr @a}
+
>From 98e6e43e8da33ebfd88d20cd16bbfa66c68901ed Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Tue, 30 Sep 2025 11:04:49 -0400
Subject: [PATCH 7/7] Address review comments and minor cleanup.
* Added support for emitting ref metadata on functions.
* Added testing for ref metadata on functions.
* Fixed up lang ref description.
* Renamed tests to match metadatas nameing.
---
llvm/docs/LangRef.rst | 22 ++++++-------
llvm/lib/IR/Verifier.cpp | 2 --
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 8 ++++-
llvm/test/CodeGen/PowerPC/aix-func-ref.ll | 31 +++++++++++++++++++
...ciated-metadata.ll => aix-ref-metadata.ll} | 0
llvm/test/Verifier/ref-func.ll | 12 +++++++
llvm/test/Verifier/ref.ll | 1 -
7 files changed, 61 insertions(+), 15 deletions(-)
create mode 100644 llvm/test/CodeGen/PowerPC/aix-func-ref.ll
rename llvm/test/CodeGen/PowerPC/{aix-associated-metadata.ll => aix-ref-metadata.ll} (100%)
create mode 100644 llvm/test/Verifier/ref-func.ll
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 3ae3c5e63b971..3bd9b82dc9f68 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -8443,21 +8443,21 @@ freed after the attached instruction.
'``ref``' Metadata
^^^^^^^^^^^^^^^^^^
-The ``ref`` metadata may be attached to a global variable definition with a
-single argument that references a global object. The metadata is lowered to a
-.ref directive which will emit a relocation introducing an explicit dependence
-to the referenced symbol. This is typically used when there is some implicit
-dependence between the symbols that is otherwise opaque to the linker. One such
-example is metadata which is accessed by a runtime with associated
-``__start_<section_name>`` and ``__stop_<section_name>`` symbols.
+The ``ref`` metadata may be attached to a function or global variable
+definition with a single argument that references a global object.
+This is typically used when there is some implicit dependence between the
+symbols that is otherwise opaque to the linker. One such example is metadata
+which is accessed by a runtime with associated ``__start_<section_name>`` and
+``__stop_<section_name>`` symbols.
+
+It does not have any effect on non-XCOFF targets.
This metadata lowers to the .ref assembly directive which will add a relocation
representing an implicit reference from the section the global belongs to, to
-the associated symbol. This link will keep the associated symbol alive if the
-section is not garbage collected. More than one associated node can be attached
-to the same global variable.
+the associated symbol. This link will keep the referenced symbol alive if the
+section is not garbage collected. More than one ref node can be attached
+to the same function or global variable.
-It does not have any effect on non-XCOFF targets.
Example:
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 08822e8ffbc85..cdd0a15f8e115 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -774,8 +774,6 @@ void Verifier::visitGlobalValue(const GlobalValue &GV) {
Check(MD->getNumOperands() == 1, "ref metadata must have one operand",
&GV, MD);
const Metadata *Op = MD->getOperand(0).get();
- Check(Op, "ref metadata must have a global value", GO, MD);
-
const auto *VM = dyn_cast_or_null<ValueAsMetadata>(Op);
Check(VM, "ref metadata must be ValueAsMetadata", GO, MD);
if (VM) {
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 652fe7e16f840..c477df952b82b 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2895,10 +2895,16 @@ void PPCAIXAsmPrinter::emitFunctionEntryLabel() {
if (!TM.getFunctionSections() || MF->getFunction().hasSection())
PPCAsmPrinter::emitFunctionEntryLabel();
+ const Function *F = &MF->getFunction();
+
// Emit aliasing label for function entry point label.
- for (const GlobalAlias *Alias : GOAliasMap[&MF->getFunction()])
+ for (const GlobalAlias *Alias : GOAliasMap[F])
OutStreamer->emitLabel(
getObjFileLowering().getFunctionEntryPointSymbol(Alias, TM));
+
+ if (F->hasMetadata(LLVMContext::MD_ref)) {
+ emitRefMetadata(F);
+ }
}
void PPCAIXAsmPrinter::emitPGORefs(Module &M) {
diff --git a/llvm/test/CodeGen/PowerPC/aix-func-ref.ll b/llvm/test/CodeGen/PowerPC/aix-func-ref.ll
new file mode 100644
index 0000000000000..d4a47fdafa781
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-func-ref.ll
@@ -0,0 +1,31 @@
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | \
+; RUN: FileCheck %s -check-prefixes=NOFSECTS,CHECK
+
+; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff --function-sections < %s | \
+; RUN: FileCheck %s -check-prefixes=FSECTS,CHECK
+
+ at a = global i32 1
+ at b = global i32 2
+ at c = global i32 3
+
+define i32 @foo() !ref !0 {
+ ret i32 0
+}
+
+define i32 @bar() !ref !1 !ref !2 {
+ ret i32 0
+}
+
+!0 = !{ptr @a}
+!1 = !{ptr @b}
+!2 = !{ptr @c}
+
+; NOFSECTS: .foo:
+; FSECTS: .csect .foo[PR]
+; CHECK: .ref a[RW]
+
+; NOFSECTS: .bar:
+; FSECTS: .csect .bar[PR]
+; CHECK: .ref b[RW]
+; CHECK: .ref c[RW]
+
diff --git a/llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll b/llvm/test/CodeGen/PowerPC/aix-ref-metadata.ll
similarity index 100%
rename from llvm/test/CodeGen/PowerPC/aix-associated-metadata.ll
rename to llvm/test/CodeGen/PowerPC/aix-ref-metadata.ll
diff --git a/llvm/test/Verifier/ref-func.ll b/llvm/test/Verifier/ref-func.ll
new file mode 100644
index 0000000000000..9a7c7b5d3405e
--- /dev/null
+++ b/llvm/test/Verifier/ref-func.ll
@@ -0,0 +1,12 @@
+; RUN: llvm-as < %s -o /dev/null 2>&1
+
+ at a = global i32 1
+ at b = global i32 2
+ at c = global i32 3, !ref !0
+
+define i32 @foo() !ref !1 {
+ ret i32 0
+}
+
+!0 = !{ptr @a}
+!1 = !{ptr @b}
diff --git a/llvm/test/Verifier/ref.ll b/llvm/test/Verifier/ref.ll
index 5f5dca0f965d6..c00b4bf7577ab 100644
--- a/llvm/test/Verifier/ref.ll
+++ b/llvm/test/Verifier/ref.ll
@@ -25,4 +25,3 @@
; CHECK: ref metadata must have one operand
; CHECK: ptr @d
; CHECK: !3 = !{ptr @c, ptr @a}
-
More information about the llvm-commits
mailing list