[llvm] [IR] enable attaching metadata on ifuncs (PR #158732)

Wael Yehia via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 17 19:56:28 PDT 2025


https://github.com/w2yehia updated https://github.com/llvm/llvm-project/pull/158732

>From 81a9c979385b5d368fcdcf36332ad506d97e1365 Mon Sep 17 00:00:00 2001
From: Wael Yehia <wyehia at ca.ibm.com>
Date: Wed, 3 Sep 2025 19:22:15 +0000
Subject: [PATCH 1/3] [IR] enable attaching metadata on ifuncs

In PR #153049, we have a use case of attaching the !associated metadata to an ifunc.
Since an ifunc is similar to a function declaration, it seems natural to allow metadata on ifuncs.
Currently, the metadata API allows adding Metadata to llvm::Values, so the in-memory IR allows for
metadata on ifuncs, but the IR reader/writer is not aware of that.

Teach the IR parser and writer to support metadata on ifuncs, and update documentation.
---
 llvm/docs/LangRef.rst                       | 7 ++++---
 llvm/lib/AsmParser/LLParser.cpp             | 3 +++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp   | 3 +++
 llvm/lib/Bitcode/Writer/ValueEnumerator.cpp | 6 ++++++
 llvm/lib/IR/AsmWriter.cpp                   | 6 ++++++
 llvm/test/Assembler/metadata.ll             | 8 ++++++++
 6 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 6ba3759080cc3..d6b472af033f8 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -1020,13 +1020,14 @@ On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On
 Mach-O platforms, they are lowered in terms of ``.symbol_resolver`` functions,
 which lazily resolve the callee the first time they are called.
 
-IFunc may have an optional :ref:`linkage type <linkage>` and an optional
-:ref:`visibility style <visibility>`.
+IFunc may have an optional :ref:`linkage type <linkage>`, an optional
+:ref:`visibility style <visibility>`, an option partition, and an optional
+list of attached :ref:`metadata <metadata>`.
 
 Syntax::
 
     @<Name> = [Linkage] [PreemptionSpecifier] [Visibility] ifunc <IFuncTy>, <ResolverTy>* @<Resolver>
-              [, partition "name"]
+              [, partition "name"] (, !name !N)*
 
 
 .. _langref_comdats:
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index 1bc2906f63b07..8739b24d4b74b 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -1258,6 +1258,9 @@ bool LLParser::parseAliasOrIFunc(const std::string &Name, unsigned NameID,
       GV->setPartition(Lex.getStrVal());
       if (parseToken(lltok::StringConstant, "expected partition string"))
         return true;
+    } else if (!IsAlias && Lex.getKind() == lltok::MetadataVar) {
+      if (parseGlobalObjectMetadataAttachment(*GI.get()))
+        return true;
     } else {
       return tokError("unknown alias or ifunc property!");
     }
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index a3f825408d0c2..d9e138edb8ce2 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -2630,6 +2630,9 @@ void ModuleBitcodeWriter::writeModuleMetadata() {
   for (const Function &F : M)
     if (F.isDeclaration() && F.hasMetadata())
       AddDeclAttachedMetadata(F);
+  for (const GlobalIFunc &GI : M.ifuncs())
+    if (GI.hasMetadata())
+      AddDeclAttachedMetadata(GI);
   // FIXME: Only store metadata for declarations here, and move data for global
   // variable definitions to a separate block (PR28134).
   for (const GlobalVariable &GV : M.globals())
diff --git a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
index e133abe577c22..f497c574ee75d 100644
--- a/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
+++ b/llvm/lib/Bitcode/Writer/ValueEnumerator.cpp
@@ -495,6 +495,12 @@ ValueEnumerator::ValueEnumerator(const Module &M,
             EnumerateMetadata(&F, Op);
       }
   }
+  for (const GlobalIFunc &GIF : M.ifuncs()) {
+    MDs.clear();
+    GIF.getAllMetadata(MDs);
+    for (const auto &I : MDs)
+      EnumerateMetadata(nullptr, I.second);
+  }
 
   // Optimize constant ordering.
   OptimizeConstants(FirstConstant, Values.size());
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index dc6d599fa9585..690dac4e6133b 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -1078,6 +1078,7 @@ void SlotTracker::processModule() {
   for (const GlobalIFunc &I : TheModule->ifuncs()) {
     if (!I.hasName())
       CreateModuleSlot(&I);
+    processGlobalObjectMetadata(I);
   }
 
   // Add metadata used by named metadata.
@@ -4077,6 +4078,11 @@ void AssemblyWriter::printIFunc(const GlobalIFunc *GI) {
     printEscapedString(GI->getPartition(), Out);
     Out << '"';
   }
+  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+  GI->getAllMetadata(MDs);
+  if (!MDs.empty()) {
+    printMetadataAttachments(MDs, ", ");
+  }
 
   printInfoComment(*GI);
   Out << '\n';
diff --git a/llvm/test/Assembler/metadata.ll b/llvm/test/Assembler/metadata.ll
index 5b62bfafa6d7d..b1fb720eb31f9 100644
--- a/llvm/test/Assembler/metadata.ll
+++ b/llvm/test/Assembler/metadata.ll
@@ -5,6 +5,14 @@
 ; CHECK-UNMAT: @global = global i32 0, !foo [[M2:![0-9]+]], !foo [[M3:![0-9]+]], !baz [[M3]]
 @global = global i32 0, !foo !2, !foo !3, !baz !3
 
+; CHECK-UNMAT: @ifunc_func = ifunc void (...), ptr @resolver, !foo [[M2]]
+ at ifunc_func = ifunc void (...), ptr @resolver, !foo !2
+
+define internal ptr @resolver() {
+entry:
+  ret ptr @test
+}
+
 ; CHECK-LABEL: @test
 ; CHECK: ret void, !foo [[M0:![0-9]+]], !bar [[M1:![0-9]+]]
 define void @test() !dbg !1 {

>From 28bb942fa3b10ccbfc6a9a37e2bd58b240009cca Mon Sep 17 00:00:00 2001
From: Wael Yehia <wyehia at ca.ibm.com>
Date: Mon, 15 Sep 2025 22:34:05 +0000
Subject: [PATCH 2/3] call visitGlobalValue from visitGlobalIFunc

---
 llvm/lib/IR/Verifier.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 1d3c379f461fa..82be6f203cae2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -997,6 +997,8 @@ void Verifier::visitGlobalAlias(const GlobalAlias &GA) {
 }
 
 void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) {
+  visitGlobalValue(GI);
+
   Check(GlobalIFunc::isValidLinkage(GI.getLinkage()),
         "IFunc should have private, internal, linkonce, weak, linkonce_odr, "
         "weak_odr, or external linkage!",

>From cfd36f1e979a1785ed41a86c41135897de62a5dd Mon Sep 17 00:00:00 2001
From: Wael Yehia <wyehia at ca.ibm.com>
Date: Thu, 18 Sep 2025 02:44:04 +0000
Subject: [PATCH 3/3] disallow !dbg and !prof metadata on ifuncs

---
 llvm/lib/IR/Verifier.cpp | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 82be6f203cae2..59e3b31f8e291 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -999,6 +999,16 @@ void Verifier::visitGlobalAlias(const GlobalAlias &GA) {
 void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) {
   visitGlobalValue(GI);
 
+  SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
+  GI.getAllMetadata(MDs);
+  for (const auto &I : MDs) {
+    CheckDI(I.first != LLVMContext::MD_dbg,
+            "an ifunc may not have a !dbg attachment", &GI);
+    Check(I.first != LLVMContext::MD_prof,
+          "an ifunc may not have a !prof attachment", &GI);
+    visitMDNode(*I.second, AreDebugLocsAllowed::No);
+  }
+
   Check(GlobalIFunc::isValidLinkage(GI.getLinkage()),
         "IFunc should have private, internal, linkonce, weak, linkonce_odr, "
         "weak_odr, or external linkage!",



More information about the llvm-commits mailing list