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/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 1d3c379f461fa..59e3b31f8e291 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -997,6 +997,18 @@ 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!", 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 {