From 81a9c979385b5d368fcdcf36332ad506d97e1365 Mon Sep 17 00:00:00 2001 From: Wael Yehia 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 ` and an optional -:ref:`visibility style `. +IFunc may have an optional :ref:`linkage type `, an optional +:ref:`visibility style `, an option partition, and an optional +list of attached :ref:`metadata `. Syntax:: @ = [Linkage] [PreemptionSpecifier] [Visibility] ifunc , * @ - [, 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, 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]] +@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 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 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, 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!",