From 567fe2bbca27a934afd4a020f0d56e85edc7bfb2 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh Date: Wed, 21 Jan 2026 11:32:33 -0800 Subject: [PATCH] [NFC][LTO] Move isPreservedName out of IRSymtab into LTO's Symbol as isLibcall (#177046) This resolves the FIXME in IRSymtab and cleans up the semantics of the IRSymtab. The list of preserved symbols really shouldn't be seen as a property of the IR symbol table, since it's an LTO-specific concern, and it's very tenuous to claim that this information is actually present in the bitcode file to be exposed through its symbol table. Instead, this PR moves this logic into LTO's view of the symbol, which allows consumers to determine preserved-ness themselves. This was broken out of #164916; this prevents that PR from introducing a circular dependency, but it still seems like an independently good idea by virtue of the above. --- lld/COFF/InputFiles.cpp | 5 ++++- llvm/include/llvm/LTO/LTO.h | 9 ++++++++- llvm/lib/LTO/LTO.cpp | 16 +++++++++++++--- llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 7 ++++--- llvm/lib/Object/IRSymtab.cpp | 13 ++----------- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index d415955b6093..492b2ad80166 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -25,6 +25,7 @@ #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/IR/Mangler.h" +#include "llvm/IR/RuntimeLibcalls.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" @@ -1395,6 +1396,8 @@ void BitcodeFile::parse() { // FIXME: Check nodeduplicate comdat[i] = symtab.addComdat(this, saver.save(obj->getComdatTable()[i].first)); + Triple tt(obj->getTargetTriple()); + RTLIB::RuntimeLibcallsInfo libcalls(tt); for (const lto::InputFile::Symbol &objSym : obj->symbols()) { StringRef symName = saver.save(objSym.getName()); int comdatIndex = objSym.getComdatIndex(); @@ -1444,7 +1447,7 @@ void BitcodeFile::parse() { symtab.addRegular(this, symName, nullptr, fakeSC, 0, objSym.isWeak()); } symbols.push_back(sym); - if (objSym.isUsed()) + if (objSym.isUsed() || objSym.isLibcall(libcalls)) symtab.ctx.config.gcroot.push_back(sym); } directives = saver.save(obj->getCOFFLinkerOpts()); diff --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h index cba5cf7eb9e6..4011065ec37a 100644 --- a/llvm/include/llvm/LTO/LTO.h +++ b/llvm/include/llvm/LTO/LTO.h @@ -16,6 +16,7 @@ #define LLVM_LTO_LTO_H #include "llvm/IR/LLVMRemarkStreamer.h" +#include "llvm/IR/RuntimeLibcalls.h" #include "llvm/Support/Compiler.h" #include @@ -167,6 +168,12 @@ public: using irsymtab::Symbol::getSectionName; using irsymtab::Symbol::isExecutable; using irsymtab::Symbol::isUsed; + + // Returns whether this symbol is a library call that LTO code generation + // may emit references to. Such symbols must be considered external, as + // removing them or modifying their interfaces would invalidate the code + // generator's knowledge about them. + bool isLibcall(const RTLIB::RuntimeLibcallsInfo &Libcalls) const; }; /// A range over the symbols in this InputFile. @@ -583,7 +590,7 @@ private: void addModuleToGlobalRes(ArrayRef Syms, ArrayRef Res, unsigned Partition, - bool InSummary); + bool InSummary, const Triple &TT); // These functions take a range of symbol resolutions and consume the // resolutions used by a single input module. Functions return ranges refering diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 955a19db4860..152b2beeae12 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -597,6 +597,11 @@ Expected> InputFile::create(MemoryBufferRef Object) { return std::move(File); } +bool InputFile::Symbol::isLibcall( + const RTLIB::RuntimeLibcallsInfo &Libcalls) const { + return Libcalls.getSupportedLibcallImpl(IRName) != RTLIB::Unsupported; +} + StringRef InputFile::getName() const { return Mods[0].getModuleIdentifier(); } @@ -642,11 +647,13 @@ LTO::~LTO() = default; // their partitions. void LTO::addModuleToGlobalRes(ArrayRef Syms, ArrayRef Res, - unsigned Partition, bool InSummary) { + unsigned Partition, bool InSummary, + const Triple &TT) { llvm::TimeTraceScope timeScope("LTO add module to global resolution"); auto *ResI = Res.begin(); auto *ResE = Res.end(); (void)ResE; + RTLIB::RuntimeLibcallsInfo Libcalls(TT); for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; @@ -689,11 +696,14 @@ void LTO::addModuleToGlobalRes(ArrayRef Syms, GlobalRes.VisibleOutsideSummary = true; } + bool IsLibcall = Sym.isLibcall(Libcalls); + // Set the partition to external if we know it is re-defined by the linker // with -defsym or -wrap options, used elsewhere, e.g. it is visible to a // regular object, is referenced from llvm.compiler.used/llvm.used, or was // already recorded as being referenced from a different partition. if (Res.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || + IsLibcall || (GlobalRes.Partition != GlobalResolution::Unknown && GlobalRes.Partition != Partition)) { GlobalRes.Partition = GlobalResolution::External; @@ -704,7 +714,7 @@ void LTO::addModuleToGlobalRes(ArrayRef Syms, // Flag as visible outside of summary if visible from a regular object or // from a module that does not have a summary. GlobalRes.VisibleOutsideSummary |= - (Res.VisibleToRegularObj || Sym.isUsed() || !InSummary); + (Res.VisibleToRegularObj || Sym.isUsed() || IsLibcall || !InSummary); GlobalRes.ExportDynamic |= Res.ExportDynamic; } @@ -811,7 +821,7 @@ LTO::addModule(InputFile &Input, ArrayRef InputRes, auto ModSyms = Input.module_symbols(ModI); addModuleToGlobalRes(ModSyms, Res, IsThinLTO ? ThinLTO.ModuleMap.size() + 1 : 0, - LTOInfo->HasSummary); + LTOInfo->HasSummary, Triple(Input.getTargetTriple())); if (IsThinLTO) return addThinLTO(BM, ModSyms, Res); diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index 961dd0ee4337..93b672ae7840 100644 --- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -290,11 +290,12 @@ static void optimizeModule(Module &TheModule, TargetMachine &TM, static void addUsedSymbolToPreservedGUID(const lto::InputFile &File, DenseSet &PreservedGUID) { - for (const auto &Sym : File.symbols()) { - if (Sym.isUsed()) + Triple TT(File.getTargetTriple()); + RTLIB::RuntimeLibcallsInfo Libcalls(TT); + for (const auto &Sym : File.symbols()) + if (Sym.isUsed() || Sym.isLibcall(Libcalls)) PreservedGUID.insert( GlobalValue::getGUIDAssumingExternalLinkage(Sym.getIRName())); - } } // Convert the PreservedSymbols map from "Name" based to "GUID" based. diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp index 20610262f6a1..878f4c911475 100644 --- a/llvm/lib/Object/IRSymtab.cpp +++ b/llvm/lib/Object/IRSymtab.cpp @@ -22,7 +22,6 @@ #include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" -#include "llvm/IR/RuntimeLibcalls.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Object/SymbolicFile.h" @@ -74,16 +73,12 @@ struct Builder { // so this provides somewhere to store any strings that we create. Builder(SmallVector &Symtab, StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc, const Triple &TT) - : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT), - Libcalls(TT) {} + : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT) {} DenseMap ComdatMap; Mangler Mang; const Triple &TT; - // FIXME: This shouldn't be here. - RTLIB::RuntimeLibcallsInfo Libcalls; - std::vector Comdats; std::vector Mods; std::vector Syms; @@ -94,10 +89,6 @@ struct Builder { std::vector DependentLibraries; - bool isPreservedName(StringRef Name) { - return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported; - } - void setStr(storage::Str &S, StringRef Value) { S.Offset = StrtabBuilder.add(Value); S.Size = Value.size(); @@ -269,7 +260,7 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, StringRef GVName = GV->getName(); setStr(Sym.IRName, GVName); - if (Used.count(GV) || isPreservedName(GVName)) + if (Used.count(GV)) Sym.Flags |= 1 << storage::Symbol::FB_used; if (GV->isThreadLocal()) Sym.Flags |= 1 << storage::Symbol::FB_tls;