From 7150eaa7d19048c9395488e175871e764e7b3795 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 15 Jul 2025 22:14:08 +0900 Subject: [PATCH] RuntimeLibcalls: Add methods to recognize libcall names Also replace the current static DenseMap of preserved symbol names in the Symtab hack with this. That was broken statefulness across compiles, so this at least fixes that. However this is still broken, llvm-as shouldn't really depend on the triple. --- llvm/include/llvm/ADT/StringTable.h | 9 ++++ llvm/include/llvm/IR/RuntimeLibcalls.h | 12 +++++ llvm/lib/IR/RuntimeLibcalls.cpp | 45 +++++++++++++++++++ llvm/lib/Object/IRSymtab.cpp | 45 +++++++++---------- .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 13 +++++- 5 files changed, 100 insertions(+), 24 deletions(-) diff --git a/llvm/include/llvm/ADT/StringTable.h b/llvm/include/llvm/ADT/StringTable.h index c089a070d4b57..575b3c929e40c 100644 --- a/llvm/include/llvm/ADT/StringTable.h +++ b/llvm/include/llvm/ADT/StringTable.h @@ -118,6 +118,13 @@ class StringTable { constexpr Iterator(const Iterator &RHS) = default; constexpr Iterator(Iterator &&RHS) = default; + Iterator &operator=(const Iterator &RHS) { + Table = RHS.Table; + O = RHS.O; + S = RHS.S; + return *this; + } + bool operator==(const Iterator &RHS) const { assert(Table == RHS.Table && "Compared iterators for unrelated tables!"); return O == RHS.O; @@ -132,6 +139,8 @@ class StringTable { O = O.value() + (*Table)[O].size() + 1; return *this; } + + Offset offset() const { return O; } }; constexpr Iterator begin() const { return Iterator(*this, 0); } diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h index 8058c8a4c5510..89ad4e5bc6ca4 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.h +++ b/llvm/include/llvm/IR/RuntimeLibcalls.h @@ -132,6 +132,10 @@ struct RuntimeLibcallsInfo { return ImplToLibcall[Impl]; } + /// Check if this is valid libcall for the current module, otherwise + /// RTLIB::Unsupported. + RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const; + private: static const RTLIB::LibcallImpl DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1]; @@ -156,6 +160,14 @@ struct RuntimeLibcallsInfo { /// Map from a concrete LibcallImpl implementation to its RTLIB::Libcall kind. LLVM_ABI static const RTLIB::Libcall ImplToLibcall[RTLIB::NumLibcallImpls]; + /// Check if a function name is a recognized runtime call of any kind. This + /// does not consider if this call is available for any current compilation, + /// just that it is a known call somewhere. This returns the set of all + /// LibcallImpls which match the name; multiple implementations with the same + /// name may exist but differ in interpretation based on the target context. + LLVM_ABI static iterator_range::const_iterator> + getRecognizedLibcallImpls(StringRef FuncName); + static bool darwinHasSinCosStret(const Triple &TT) { if (!TT.isOSDarwin()) return false; diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp index b1864897dafa6..5936ac7d0287f 100644 --- a/llvm/lib/IR/RuntimeLibcalls.cpp +++ b/llvm/lib/IR/RuntimeLibcalls.cpp @@ -135,6 +135,51 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, } } +RTLIB::LibcallImpl +RuntimeLibcallsInfo::getSupportedLibcallImpl(StringRef FuncName) const { + const ArrayRef RuntimeLibcallNameOffsets( + RuntimeLibcallNameOffsetTable); + + iterator_range::const_iterator> Range = + getRecognizedLibcallImpls(FuncName); + + for (auto I = Range.begin(); I != Range.end(); ++I) { + RTLIB::LibcallImpl Impl = + static_cast(I - RuntimeLibcallNameOffsets.begin()); + + // FIXME: This should not depend on looking up ImplToLibcall, only the list + // of libcalls for the module. + RTLIB::LibcallImpl Recognized = LibcallImpls[ImplToLibcall[Impl]]; + if (Recognized != RTLIB::Unsupported) + return Recognized; + } + + return RTLIB::Unsupported; +} + +iterator_range::const_iterator> +RuntimeLibcallsInfo::getRecognizedLibcallImpls(StringRef FuncName) { + StringTable::Iterator It = lower_bound(RuntimeLibcallImplNameTable, FuncName); + if (It == RuntimeLibcallImplNameTable.end() || *It != FuncName) + return iterator_range(ArrayRef()); + + uint16_t IndexVal = It.offset().value(); + const ArrayRef TableRef(RuntimeLibcallNameOffsetTable); + + ArrayRef::const_iterator E = TableRef.end(); + ArrayRef::const_iterator EntriesBegin = + std::lower_bound(TableRef.begin(), E, IndexVal); + ArrayRef::const_iterator EntriesEnd = EntriesBegin; + + while (EntriesEnd != E && *EntriesEnd == IndexVal) + ++EntriesEnd; + + assert(EntriesBegin != E && + "libcall found in name table but not offset table"); + + return make_range(EntriesBegin, EntriesEnd); +} + bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) { switch (TT.getOS()) { case Triple::MacOSX: diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp index 2579fa37935f0..79eeb08cddeef 100644 --- a/llvm/lib/Object/IRSymtab.cpp +++ b/llvm/lib/Object/IRSymtab.cpp @@ -54,6 +54,11 @@ static const char *PreservedSymbols[] = { "__stack_chk_guard", }; +static bool isPreservedGlobalVarName(StringRef Name) { + return StringRef(PreservedSymbols[0]) == Name || + StringRef(PreservedSymbols[1]) == Name; +} + namespace { const char *getExpectedProducerName() { @@ -81,12 +86,16 @@ struct Builder { // The StringTableBuilder does not create a copy of any strings added to it, // so this provides somewhere to store any strings that we create. Builder(SmallVector &Symtab, StringTableBuilder &StrtabBuilder, - BumpPtrAllocator &Alloc) - : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {} + BumpPtrAllocator &Alloc, const Triple &TT) + : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT), + Libcalls(TT) {} DenseMap ComdatMap; Mangler Mang; - Triple TT; + const Triple &TT; + + // FIXME: This shouldn't be here. + RTLIB::RuntimeLibcallsInfo Libcalls; std::vector Comdats; std::vector Mods; @@ -98,6 +107,10 @@ struct Builder { std::vector DependentLibraries; + bool isPreservedLibFuncName(StringRef Name) { + return Libcalls.getSupportedLibcallImpl(Name) != RTLIB::Unsupported; + } + void setStr(storage::Str &S, StringRef Value) { S.Offset = StrtabBuilder.add(Value); S.Size = Value.size(); @@ -213,18 +226,6 @@ Expected Builder::getComdatIndex(const Comdat *C, const Module *M) { return P.first->second; } -static DenseSet buildPreservedSymbolsSet(const Triple &TT) { - DenseSet PreservedSymbolSet(std::begin(PreservedSymbols), - std::end(PreservedSymbols)); - // FIXME: Do we need to pass in ABI fields from TargetOptions? - RTLIB::RuntimeLibcallsInfo Libcalls(TT); - for (RTLIB::LibcallImpl Impl : Libcalls.getLibcallImpls()) { - if (Impl != RTLIB::Unsupported) - PreservedSymbolSet.insert(Libcalls.getLibcallImplName(Impl)); - } - return PreservedSymbolSet; -} - Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, const SmallPtrSet &Used, ModuleSymbolTable::Symbol Msym) { @@ -278,13 +279,11 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, return Error::success(); } - setStr(Sym.IRName, GV->getName()); - - static const DenseSet PreservedSymbolsSet = - buildPreservedSymbolsSet(GV->getParent()->getTargetTriple()); - bool IsPreservedSymbol = PreservedSymbolsSet.contains(GV->getName()); + StringRef GVName = GV->getName(); + setStr(Sym.IRName, GVName); - if (Used.count(GV) || IsPreservedSymbol) + if (Used.count(GV) || isPreservedLibFuncName(GVName) || + isPreservedGlobalVarName(GVName)) Sym.Flags |= 1 << storage::Symbol::FB_used; if (GV->isThreadLocal()) Sym.Flags |= 1 << storage::Symbol::FB_tls; @@ -351,7 +350,6 @@ Error Builder::build(ArrayRef IRMods) { setStr(Hdr.Producer, kExpectedProducerName); setStr(Hdr.TargetTriple, IRMods[0]->getTargetTriple().str()); setStr(Hdr.SourceFileName, IRMods[0]->getSourceFileName()); - TT = IRMods[0]->getTargetTriple(); for (auto *M : IRMods) if (Error Err = addModule(M)) @@ -377,7 +375,8 @@ Error Builder::build(ArrayRef IRMods) { Error irsymtab::build(ArrayRef Mods, SmallVector &Symtab, StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc) { - return Builder(Symtab, StrtabBuilder, Alloc).build(Mods); + const Triple &TT = Mods[0]->getTargetTriple(); + return Builder(Symtab, StrtabBuilder, Alloc, TT).build(Mods); } // Upgrade a vector of bitcode modules created by an old version of LLVM by diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp index 652bea9dc7f65..7f90d6b4fdacc 100644 --- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp +++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp @@ -236,8 +236,19 @@ class RuntimeLibcallEmitter { for (RuntimeLibcall &LibCall : RuntimeLibcallDefList) Def2RuntimeLibcall[LibCall.getDef()] = &LibCall; - ArrayRef AllRuntimeLibcallImpls = + ArrayRef AllRuntimeLibcallImplsRaw = Records.getAllDerivedDefinitions("RuntimeLibcallImpl"); + + SmallVector AllRuntimeLibcallImpls( + AllRuntimeLibcallImplsRaw); + + // Sort by libcall impl name, not the enum name. This keeps the order + // suitable for using the name table for libcall recognition binary search. + llvm::sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) { + return A->getValueAsString("LibCallFuncName") < + B->getValueAsString("LibCallFuncName"); + }); + RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size()); size_t LibCallImplEnumVal = 1;