diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -572,6 +572,15 @@ // Use alias_size() to get the size of AliasList. // Use aliases() to get a range of all Alias objects in AliasList. + /// Detach \p IFunc from the list but don't delete it. + void removeIFunc(GlobalIFunc *IFunc) { IFuncList.remove(IFunc); } + /// Remove \p IFunc from the list and delete it. + void eraseIFunc(GlobalIFunc *IFunc) { IFuncList.erase(IFunc); } + /// Insert \p IFunc at the end of the alias list and take ownership. + void insertIFunc(GlobalIFunc *IFunc) { IFuncList.push_back(IFunc); } + // Use ifunc_size() to get the number of functions in IFuncList. + // Use ifuncs() to get the range of all IFuncs. + private: // Please use functions like insertAlias(), removeAlias() etc. /// Get the Module's list of aliases (constant). const AliasListType &getAliasList() const { return AliasList; } @@ -592,7 +601,9 @@ static IFuncListType Module::*getSublistAccess(GlobalIFunc*) { return &Module::IFuncList; } + friend class llvm::SymbolTableListTraits; +public: /// Get the Module's list of named metadata (constant). const NamedMDListType &getNamedMDList() const { return NamedMDList; } /// Get the Module's list of named metadata. diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -1143,7 +1143,7 @@ if (IsAlias) M->insertAlias(GA.release()); else - M->getIFuncList().push_back(GI.release()); + M->insertIFunc(GI.release()); assert(GV->getName() == Name && "Should not be a name conflict!"); return false; diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -575,7 +575,7 @@ AddressSpace) { setResolver(Resolver); if (ParentModule) - ParentModule->getIFuncList().push_back(this); + ParentModule->insertIFunc(this); } GlobalIFunc *GlobalIFunc::create(Type *Ty, unsigned AddressSpace, @@ -584,13 +584,9 @@ return new GlobalIFunc(Ty, AddressSpace, Link, Name, Resolver, ParentModule); } -void GlobalIFunc::removeFromParent() { - getParent()->getIFuncList().remove(getIterator()); -} +void GlobalIFunc::removeFromParent() { getParent()->removeIFunc(this); } -void GlobalIFunc::eraseFromParent() { - getParent()->getIFuncList().erase(getIterator()); -} +void GlobalIFunc::eraseFromParent() { getParent()->eraseIFunc(this); } const Function *GlobalIFunc::getResolverFunction() const { return dyn_cast(getResolver()->stripPointerCastsAndAliases()); diff --git a/llvm/unittests/IR/ModuleTest.cpp b/llvm/unittests/IR/ModuleTest.cpp --- a/llvm/unittests/IR/ModuleTest.cpp +++ b/llvm/unittests/IR/ModuleTest.cpp @@ -199,4 +199,44 @@ EXPECT_EQ(M->alias_size(), 1u); } +TEST(ModuleTest, IFuncList) { + // This tests all Module's functions that interact with Module::IFuncList. + LLVMContext C; + SMDiagnostic Err; + LLVMContext Context; + std::unique_ptr M = parseAssemblyString(R"( +declare void @Foo() +@GIF = ifunc void (), ptr @Foo +)", + Err, Context); + Function *Foo = M->getFunction("Foo"); + auto *GIF = M->getNamedIFunc("GIF"); + EXPECT_EQ(M->ifunc_size(), 1u); + auto *NewGIF = + GlobalIFunc::create(Foo->getType(), 0, GlobalValue::ExternalLinkage, + "NewGIF", Foo, /*Parent=*/nullptr); + EXPECT_EQ(M->ifunc_size(), 1u); + + M->insertIFunc(NewGIF); + EXPECT_EQ(&*std::prev(M->ifuncs().end()), NewGIF); + + M->removeIFunc(NewGIF); + EXPECT_EQ(M->ifunc_size(), 1u); + M->insertIFunc(NewGIF); + EXPECT_EQ(M->ifunc_size(), 2u); + EXPECT_EQ(&*std::prev(M->ifuncs().end()), NewGIF); + + auto Range = M->ifuncs(); + EXPECT_EQ(&*Range.begin(), GIF); + EXPECT_EQ(&*std::next(Range.begin()), NewGIF); + EXPECT_EQ(std::next(Range.begin(), 2), Range.end()); + + M->removeIFunc(NewGIF); + EXPECT_EQ(M->ifunc_size(), 1u); + + M->insertIFunc(NewGIF); + M->eraseIFunc(NewGIF); + EXPECT_EQ(M->ifunc_size(), 1u); +} + } // end namespace