[llvm] RuntimeLibcalls: Add methods to recognize libcall names (PR #149001)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 15 18:02:38 PDT 2025
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/149001
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.
>From ea25857926ac3f38490d828a3e417e4a76905a84 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
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 | 20 ++++++++-
5 files changed, 107 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<ArrayRef<uint16_t>::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<uint16_t> RuntimeLibcallNameOffsets(
+ RuntimeLibcallNameOffsetTable);
+
+ iterator_range<ArrayRef<uint16_t>::const_iterator> Range =
+ getRecognizedLibcallImpls(FuncName);
+
+ for (auto I = Range.begin(); I != Range.end(); ++I) {
+ RTLIB::LibcallImpl Impl =
+ static_cast<RTLIB::LibcallImpl>(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<ArrayRef<uint16_t>::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>());
+
+ uint16_t IndexVal = It.offset().value();
+ const ArrayRef<uint16_t> TableRef(RuntimeLibcallNameOffsetTable);
+
+ ArrayRef<uint16_t>::const_iterator E = TableRef.end();
+ ArrayRef<uint16_t>::const_iterator EntriesBegin =
+ std::lower_bound(TableRef.begin(), E, IndexVal);
+ ArrayRef<uint16_t>::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<char, 0> &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<const Comdat *, int> ComdatMap;
Mangler Mang;
- Triple TT;
+ const Triple &TT;
+
+ // FIXME: This shouldn't be here.
+ RTLIB::RuntimeLibcallsInfo Libcalls;
std::vector<storage::Comdat> Comdats;
std::vector<storage::Module> Mods;
@@ -98,6 +107,10 @@ struct Builder {
std::vector<storage::Str> 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<int> Builder::getComdatIndex(const Comdat *C, const Module *M) {
return P.first->second;
}
-static DenseSet<StringRef> buildPreservedSymbolsSet(const Triple &TT) {
- DenseSet<StringRef> 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<GlobalValue *, 4> &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<StringRef> 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<Module *> 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<Module *> IRMods) {
Error irsymtab::build(ArrayRef<Module *> Mods, SmallVector<char, 0> &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..1f6f023bb56a5 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -236,8 +236,18 @@ class RuntimeLibcallEmitter {
for (RuntimeLibcall &LibCall : RuntimeLibcallDefList)
Def2RuntimeLibcall[LibCall.getDef()] = &LibCall;
- ArrayRef<const Record *> AllRuntimeLibcallImpls =
+ ArrayRef<const Record *> AllRuntimeLibcallImplsRaw =
Records.getAllDerivedDefinitions("RuntimeLibcallImpl");
+
+ SmallVector<const Record *, 1024> AllRuntimeLibcallImpls(
+ AllRuntimeLibcallImplsRaw);
+
+ // Sort by libcall impl name, not the enum name. This simplifies generating
+ llvm::sort(AllRuntimeLibcallImpls, [](const Record *A, const Record *B) {
+ return A->getValueAsString("LibCallFuncName") <
+ B->getValueAsString("LibCallFuncName");
+ });
+
RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size());
size_t LibCallImplEnumVal = 1;
@@ -259,6 +269,14 @@ class RuntimeLibcallEmitter {
LibCallToDefaultImpl[Provides] = &LibCallImpl;
}
}
+
+#if 0
+ // Sort by libcall impl name, not the enum name. This simplifies generating
+ llvm::sort(RuntimeLibcallImplDefList,
+ [](const RuntimeLibcallImpl &A, const RuntimeLibcallImpl &B) {
+ return A.getLibcallFuncName() < B.getLibcallFuncName();
+ });
+#endif
}
const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
More information about the llvm-commits
mailing list