[llvm] XCOFF associated metadata (PR #159096)
Sean Fertile via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 18 08:26:08 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/4] 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/4] 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/4] 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/4] 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
More information about the llvm-commits
mailing list