From bd3a5998c903a2ce2e9269229b2f26c66afe02a3 Mon Sep 17 00:00:00 2001 From: Gulfem Savrun Yeniceri Date: Fri, 15 Aug 2025 12:44:19 -0700 Subject: [PATCH] Revert "RuntimeLibcalls: Generate table of libcall name lengths (#153210)" This reverts commit 9a14b1d254a43dc0d4445c3ffa3d393bca007ba3. Revert "RuntimeLibcalls: Return StringRef for libcall names (#153209)" This reverts commit cb1228fbd535b8f9fe78505a15292b0ba23b17de. Revert "TableGen: Emit statically generated hash table for runtime libcalls (#150192)" This reverts commit 769a9058c8d04fc920994f6a5bbb03c8a4fbcd05. Reverted three changes because of a CMake error while building llvm-nm as reported in the following PR: https://github.com/llvm/llvm-project/pull/150192#issuecomment-3192223073 --- llvm/benchmarks/CMakeLists.txt | 17 -- llvm/benchmarks/RuntimeLibcalls.cpp | 114 ---------- llvm/include/llvm/CodeGen/TargetLowering.h | 12 +- llvm/include/llvm/IR/RuntimeLibcalls.h | 64 ++---- llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp | 2 +- llvm/lib/IR/RuntimeLibcalls.cpp | 59 +++-- llvm/lib/LTO/LTO.cpp | 2 +- llvm/lib/Object/IRSymtab.cpp | 47 ++-- .../WebAssemblyRuntimeLibcallSignatures.cpp | 4 +- .../Utils/DeclareRuntimeLibcalls.cpp | 2 +- llvm/test/TableGen/RuntimeLibcallEmitter.td | 39 ---- llvm/unittests/IR/CMakeLists.txt | 1 - llvm/unittests/IR/RuntimeLibcallsTest.cpp | 63 ------ .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 208 +----------------- 14 files changed, 100 insertions(+), 534 deletions(-) delete mode 100644 llvm/benchmarks/RuntimeLibcalls.cpp delete mode 100644 llvm/unittests/IR/RuntimeLibcallsTest.cpp diff --git a/llvm/benchmarks/CMakeLists.txt b/llvm/benchmarks/CMakeLists.txt index 9613678d2e0ac..1078efa55f497 100644 --- a/llvm/benchmarks/CMakeLists.txt +++ b/llvm/benchmarks/CMakeLists.txt @@ -11,20 +11,3 @@ add_benchmark(FormatVariadicBM FormatVariadicBM.cpp PARTIAL_SOURCES_INTENDED) add_benchmark(GetIntrinsicInfoTableEntriesBM GetIntrinsicInfoTableEntriesBM.cpp PARTIAL_SOURCES_INTENDED) add_benchmark(SandboxIRBench SandboxIRBench.cpp PARTIAL_SOURCES_INTENDED) -# Extract the list of symbols in a random utility as sample data. -set(SYMBOL_TEST_DATA_FILE "sample_symbol_list.txt") -set(SYMBOL_TEST_DATA_SOURCE_BINARY $) - -add_custom_command(OUTPUT ${SYMBOL_TEST_DATA_FILE} - COMMAND $ --no-demangle --no-sort - --format=just-symbols - ${SYMBOL_TEST_DATA_SOURCE_BINARY} > ${SYMBOL_TEST_DATA_FILE} - DEPENDS "$" "$") - -add_custom_target(generate-runtime-libcalls-sample-symbol-list - DEPENDS ${SYMBOL_TEST_DATA_FILE}) -add_benchmark(RuntimeLibcallsBench RuntimeLibcalls.cpp PARTIAL_SOURCES_INTENDED) - -add_dependencies(RuntimeLibcallsBench generate-runtime-libcalls-sample-symbol-list) -target_compile_definitions(RuntimeLibcallsBench PRIVATE - -DSYMBOL_TEST_DATA_FILE="${CMAKE_CURRENT_BINARY_DIR}/${SYMBOL_TEST_DATA_FILE}") diff --git a/llvm/benchmarks/RuntimeLibcalls.cpp b/llvm/benchmarks/RuntimeLibcalls.cpp deleted file mode 100644 index 81a5a24ec8f93..0000000000000 --- a/llvm/benchmarks/RuntimeLibcalls.cpp +++ /dev/null @@ -1,114 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/RuntimeLibcalls.h" -#include "benchmark/benchmark.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/LineIterator.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/TargetParser/Triple.h" -#include -#include -using namespace llvm; - -static constexpr unsigned MaxFuncNameSize = 53; - -static std::vector getLibcallNameStringRefs() { - std::vector Names(RTLIB::NumLibcallImpls); - // Keep the strlens on the StringRef construction out of the benchmark loop. - for (RTLIB::LibcallImpl LC : RTLIB::libcall_impls()) - Names[LC] = RTLIB::RuntimeLibcallsInfo::getLibcallImplName(LC); - - return Names; -} - -static std::vector getRandomFuncNames() { - std::mt19937_64 Rng; - std::uniform_int_distribution<> StringLengthDistribution(1, MaxFuncNameSize); - std::uniform_int_distribution<> CharDistribution(1, 255); - int NumTestFuncs = 1 << 10; - std::vector TestFuncNames(NumTestFuncs); - - for (std::string &TestFuncName : TestFuncNames) { - for (int I = 0, E = StringLengthDistribution(Rng); I != E; ++I) - TestFuncName += static_cast(CharDistribution(Rng)); - } - - return TestFuncNames; -} - -static std::vector readSymbolsFromFile(StringRef InputFile) { - auto BufOrError = MemoryBuffer::getFileOrSTDIN(InputFile, /*IsText=*/true); - if (!BufOrError) { - reportFatalUsageError("failed to open \'" + Twine(InputFile) + - "\': " + BufOrError.getError().message()); - } - - // Hackily figure out if there's a prefix on the symbol names - llvm-nm - // appears to not have a flag to skip this. - llvm::Triple HostTriple(LLVM_HOST_TRIPLE); - std::string DummyDatalayout = "e"; - DummyDatalayout += DataLayout::getManglingComponent(HostTriple); - - DataLayout DL(DummyDatalayout); - char GlobalPrefix = DL.getGlobalPrefix(); - - std::vector Lines; - for (line_iterator LineIt(**BufOrError, /*SkipBlanks=*/true); - !LineIt.is_at_eof(); ++LineIt) { - StringRef SymbolName = *LineIt; - SymbolName.consume_front(StringRef(&GlobalPrefix, 1)); - - Lines.push_back(SymbolName.str()); - } - return Lines; -} - -static void BM_LookupRuntimeLibcallByNameKnownCalls(benchmark::State &State) { - std::vector Names = getLibcallNameStringRefs(); - - for (auto _ : State) { - for (StringRef Name : Names) { - benchmark::DoNotOptimize( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(Name).empty()); - } - } -} - -static void BM_LookupRuntimeLibcallByNameRandomCalls(benchmark::State &State) { - std::vector TestFuncNames = getRandomFuncNames(); - - for (auto _ : State) { - for (const std::string &Name : TestFuncNames) { - benchmark::DoNotOptimize( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(StringRef(Name)) - .empty()); - } - } -} - -// This isn't fully representative, it doesn't include any anonymous functions. -// nm -n --no-demangle --format=just-symbols sample-binary > sample.txt -static void BM_LookupRuntimeLibcallByNameSampleData(benchmark::State &State) { - std::vector TestFuncNames = - readSymbolsFromFile(SYMBOL_TEST_DATA_FILE); - for (auto _ : State) { - for (const std::string &Name : TestFuncNames) { - benchmark::DoNotOptimize( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(StringRef(Name)) - .empty()); - } - } -} - -BENCHMARK(BM_LookupRuntimeLibcallByNameKnownCalls); -BENCHMARK(BM_LookupRuntimeLibcallByNameRandomCalls); -BENCHMARK(BM_LookupRuntimeLibcallByNameSampleData); - -BENCHMARK_MAIN(); diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 272d7dd5f45e8..ec3104799bfb5 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -3557,19 +3557,15 @@ class LLVM_ABI TargetLoweringBase { /// Get the libcall routine name for the specified libcall. const char *getLibcallName(RTLIB::Libcall Call) const { - // FIXME: Return StringRef - return Libcalls.getLibcallName(Call).data(); + return Libcalls.getLibcallName(Call); } /// Get the libcall routine name for the specified libcall implementation - static StringRef getLibcallImplName(RTLIB::LibcallImpl Call) { - return RTLIB::RuntimeLibcallsInfo::getLibcallImplName(Call); + const char *getLibcallImplName(RTLIB::LibcallImpl Call) const { + return Libcalls.getLibcallImplName(Call); } - const char *getMemcpyName() const { - // FIXME: Return StringRef - return Libcalls.getMemcpyName().data(); - } + const char *getMemcpyName() const { return Libcalls.getMemcpyName(); } /// Get the comparison predicate that's to be used to test the result of the /// comparison libcall against zero. This should only be used with diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h index 308be543de2bd..2d1d07c5fd81b 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.h +++ b/llvm/include/llvm/IR/RuntimeLibcalls.h @@ -77,17 +77,17 @@ struct RuntimeLibcallsInfo { /// Get the libcall routine name for the specified libcall. // FIXME: This should be removed. Only LibcallImpl should have a name. - StringRef getLibcallName(RTLIB::Libcall Call) const { + const char *getLibcallName(RTLIB::Libcall Call) const { return getLibcallImplName(LibcallImpls[Call]); } /// Get the libcall routine name for the specified libcall implementation. - static StringRef getLibcallImplName(RTLIB::LibcallImpl CallImpl) { + // FIXME: Change to return StringRef + static const char *getLibcallImplName(RTLIB::LibcallImpl CallImpl) { if (CallImpl == RTLIB::Unsupported) - return StringRef(); - return StringRef(RuntimeLibcallImplNameTable.getCString( - RuntimeLibcallNameOffsetTable[CallImpl]), - RuntimeLibcallNameSizeTable[CallImpl]); + return nullptr; + return RuntimeLibcallImplNameTable[RuntimeLibcallNameOffsetTable[CallImpl]] + .data(); } /// Return the lowering's selection of implementation call for \p Call @@ -119,10 +119,9 @@ struct RuntimeLibcallsInfo { /// Return a function name compatible with RTLIB::MEMCPY, or nullptr if fully /// unsupported. - StringRef getMemcpyName() const { - RTLIB::LibcallImpl Memcpy = getLibcallImpl(RTLIB::MEMCPY); - if (Memcpy != RTLIB::Unsupported) - return getLibcallImplName(Memcpy); + const char *getMemcpyName() const { + if (const char *Memcpy = getLibcallName(RTLIB::MEMCPY)) + return Memcpy; // Fallback to memmove if memcpy isn't available. return getLibcallName(RTLIB::MEMMOVE); @@ -133,41 +132,11 @@ struct RuntimeLibcallsInfo { return ImplToLibcall[Impl]; } - /// 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. - /// - /// Generated by tablegen. - LLVM_ABI static inline iota_range - lookupLibcallImplName(StringRef Name){ - // Inlining the early exit on the string name appears to be worthwhile when - // querying a real set of symbols -#define GET_LOOKUP_LIBCALL_IMPL_NAME_BODY -#include "llvm/IR/RuntimeLibcalls.inc" -#undef GET_LOOKUP_LIBCALL_IMPL_NAME_BODY - } - /// Check if this is valid libcall for the current module, otherwise /// RTLIB::Unsupported. - LLVM_ABI RTLIB::LibcallImpl - getSupportedLibcallImpl(StringRef FuncName) const { - for (RTLIB::LibcallImpl Impl : lookupLibcallImplName(FuncName)) { - // 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; - } + LLVM_ABI RTLIB::LibcallImpl getSupportedLibcallImpl(StringRef FuncName) const; private: - LLVM_ABI static iota_range - lookupLibcallImplNameImpl(StringRef Name); - /// Stores the implementation choice for each each libcall. RTLIB::LibcallImpl LibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1] = { RTLIB::Unsupported}; @@ -184,16 +153,17 @@ struct RuntimeLibcallsInfo { LLVM_ABI static const char RuntimeLibcallImplNameTableStorage[]; LLVM_ABI static const StringTable RuntimeLibcallImplNameTable; LLVM_ABI static const uint16_t RuntimeLibcallNameOffsetTable[]; - LLVM_ABI static const uint8_t RuntimeLibcallNameSizeTable[]; /// Map from a concrete LibcallImpl implementation to its RTLIB::Libcall kind. LLVM_ABI static const RTLIB::Libcall ImplToLibcall[RTLIB::NumLibcallImpls]; - /// Utility function for tablegenerated lookup function. Return a range of - /// enum values that apply for the function name at \p NameOffsetEntry with - /// the value \p StrOffset. - static inline iota_range - libcallImplNameHit(uint16_t NameOffsetEntry, uint16_t StrOffset); + /// 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()) diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp index 96c9cde622b45..9fa96e7372961 100644 --- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp @@ -145,7 +145,7 @@ static bool lowerObjCCall(Function &F, RTLIB::LibcallImpl NewFn, // FIXME: When RuntimeLibcalls is an analysis, check if the function is really // supported, and go through RTLIB::Libcall. - StringRef NewFnName = RTLIB::RuntimeLibcallsInfo::getLibcallImplName(NewFn); + const char *NewFnName = RTLIB::RuntimeLibcallsInfo::getLibcallImplName(NewFn); // If we haven't already looked up this function, check to see if the // program already contains a function with this name. diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp index 88cb192c08781..ac845c4998783 100644 --- a/llvm/lib/IR/RuntimeLibcalls.cpp +++ b/llvm/lib/IR/RuntimeLibcalls.cpp @@ -9,7 +9,6 @@ #include "llvm/IR/RuntimeLibcalls.h" #include "llvm/ADT/StringTable.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/xxhash.h" #include "llvm/TargetParser/ARMTargetParser.h" #define DEBUG_TYPE "runtime-libcalls-info" @@ -19,11 +18,9 @@ using namespace RTLIB; #define GET_INIT_RUNTIME_LIBCALL_NAMES #define GET_SET_TARGET_RUNTIME_LIBCALL_SETS -#define DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME #include "llvm/IR/RuntimeLibcalls.inc" #undef GET_INIT_RUNTIME_LIBCALL_NAMES #undef GET_SET_TARGET_RUNTIME_LIBCALL_SETS -#undef DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME /// Set default libcall names. If a target wants to opt-out of a libcall it /// should be placed here. @@ -61,23 +58,49 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, } } -LLVM_ATTRIBUTE_ALWAYS_INLINE -iota_range -RuntimeLibcallsInfo::libcallImplNameHit(uint16_t NameOffsetEntry, - uint16_t StrOffset) { - int NumAliases = 1; - for (uint16_t Entry : ArrayRef(RuntimeLibcallNameOffsetTable) - .drop_front(NameOffsetEntry + 1)) { - if (Entry != StrOffset) - break; - ++NumAliases; +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; } - RTLIB::LibcallImpl ImplStart = static_cast( - &RuntimeLibcallNameOffsetTable[NameOffsetEntry] - - &RuntimeLibcallNameOffsetTable[0]); - return enum_seq(ImplStart, - static_cast(ImplStart + NumAliases)); + 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::isAAPCS_ABI(const Triple &TT, StringRef ABIName) { diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 35d24c17bbd93..0323b4d433b87 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1422,7 +1422,7 @@ SmallVector LTO::getRuntimeLibcallSymbols(const Triple &TT) { for (RTLIB::LibcallImpl Impl : LibcallImpls) { if (Impl != RTLIB::Unsupported) - LibcallSymbols.push_back(Libcalls.getLibcallImplName(Impl).data()); + LibcallSymbols.push_back(Libcalls.getLibcallImplName(Impl)); } return LibcallSymbols; diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp index 0043f02107fb8..0f194953787e6 100644 --- a/llvm/lib/Object/IRSymtab.cpp +++ b/llvm/lib/Object/IRSymtab.cpp @@ -46,7 +46,7 @@ static cl::opt DisableBitcodeVersionUpgrade( "disable-bitcode-version-upgrade", cl::Hidden, cl::desc("Disable automatic bitcode upgrade for version mismatch")); -static constexpr StringLiteral PreservedSymbols[] = { +static const char *PreservedSymbols[] = { // There are global variables, so put it here instead of in // RuntimeLibcalls.td. // TODO: Are there similar such variables? @@ -54,10 +54,6 @@ static constexpr StringLiteral PreservedSymbols[] = { "__stack_chk_guard", }; -static bool isPreservedGlobalVarName(StringRef Name) { - return PreservedSymbols[0] == Name || PreservedSymbols[1] == Name; -} - namespace { const char *getExpectedProducerName() { @@ -85,16 +81,12 @@ 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, const Triple &TT) - : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc), TT(TT), - Libcalls(TT) {} + BumpPtrAllocator &Alloc) + : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {} DenseMap ComdatMap; Mangler Mang; - const Triple &TT; - - // FIXME: This shouldn't be here. - RTLIB::RuntimeLibcallsInfo Libcalls; + Triple TT; std::vector Comdats; std::vector Mods; @@ -106,10 +98,6 @@ 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(); @@ -225,6 +213,19 @@ Expected Builder::getComdatIndex(const Comdat *C, const Module *M) { return P.first->second; } +static StringSet<> buildPreservedSymbolsSet(const Triple &TT) { + StringSet<> PreservedSymbolSet; + PreservedSymbolSet.insert(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,11 +279,13 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, return Error::success(); } - StringRef GVName = GV->getName(); - setStr(Sym.IRName, GVName); + setStr(Sym.IRName, GV->getName()); + + static const StringSet<> PreservedSymbolsSet = + buildPreservedSymbolsSet(GV->getParent()->getTargetTriple()); + bool IsPreservedSymbol = PreservedSymbolsSet.contains(GV->getName()); - if (Used.count(GV) || isPreservedLibFuncName(GVName) || - isPreservedGlobalVarName(GVName)) + if (Used.count(GV) || IsPreservedSymbol) Sym.Flags |= 1 << storage::Symbol::FB_used; if (GV->isThreadLocal()) Sym.Flags |= 1 << storage::Symbol::FB_tls; @@ -349,6 +352,7 @@ 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)) @@ -374,8 +378,7 @@ Error Builder::build(ArrayRef IRMods) { Error irsymtab::build(ArrayRef Mods, SmallVector &Symtab, StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc) { - const Triple &TT = Mods[0]->getTargetTriple(); - return Builder(Symtab, StrtabBuilder, Alloc, TT).build(Mods); + return Builder(Symtab, StrtabBuilder, Alloc).build(Mods); } // Upgrade a vector of bitcode modules created by an old version of LLVM by diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp index 45b0e7dc12263..4548a7520b3b4 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp @@ -533,8 +533,8 @@ struct StaticLibcallNameMap { // different libcalls. RTLIB::RuntimeLibcallsInfo RTCI(TT); for (RTLIB::Libcall LC : RTLIB::libcalls()) { - StringRef NameLibcall = RTCI.getLibcallName(LC); - if (!NameLibcall.empty() && + const char *NameLibcall = RTCI.getLibcallName(LC); + if (NameLibcall != nullptr && getRuntimeLibcallSignatures().Table[LC] != unsupported) { assert(!Map.contains(NameLibcall) && "duplicate libcall names in name map"); diff --git a/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp b/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp index 0642d51cd2c21..540039b7d2cbd 100644 --- a/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp +++ b/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp @@ -30,7 +30,7 @@ PreservedAnalyses DeclareRuntimeLibcallsPass::run(Module &M, FunctionType *FuncTy = FunctionType::get(Type::getVoidTy(Ctx), {}, /*IsVarArgs=*/true); - StringRef FuncName = RTLCI.getLibcallImplName(Impl); + const char *FuncName = RTLCI.getLibcallImplName(Impl); M.getOrInsertFunction(FuncName, FuncTy); } diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td index 7c62402227f7d..a2d946f3aa84f 100644 --- a/llvm/test/TableGen/RuntimeLibcallEmitter.td +++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td @@ -137,19 +137,6 @@ def BlahLibrary : SystemRuntimeLibrary 9) -// CHECK-NEXT: return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported); -// CHECK-NEXT: return lookupLibcallImplNameImpl(Name); -// CHECK-NEXT: #endif - -// CHECK: #ifdef DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME -// CHECK-NEXT: static inline uint64_t hash(StringRef Str) { -// CHECK-NEXT: return static_cast(xxh3_64bits(Str)); -// CHECK-NEXT: } - -// CHECK: iota_range RTLIB::RuntimeLibcallsInfo::lookupLibcallImplNameImpl(StringRef Name) { -// CHECK: static constexpr uint16_t HashTableNameToEnum[16] = { -// CHECK: 2, // 0x000000705301b8, ___memset -// CHECK: 0, -// CHECK: 6, // 0x0000001417a2af, calloc -// CHECK: 0, -// CHECK: }; - -// CHECK: unsigned Idx = (hash(Name) % 8) * 2; -// CHECK: for (int I = 0; I != 2; ++I) { -// CHECK: return libcallImplNameHit(Entry, StrOffset); - -// CHECK: return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported); -// CHECK-NEXT: } // CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(const llvm::Triple &TT, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName) { // CHECK-NEXT: struct LibcallImplPair { diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt index 8b7bd3997ea27..b66eae93f9339 100644 --- a/llvm/unittests/IR/CMakeLists.txt +++ b/llvm/unittests/IR/CMakeLists.txt @@ -43,7 +43,6 @@ add_llvm_unittest(IRTests PatternMatch.cpp ShuffleVectorInstTest.cpp StructuralHashTest.cpp - RuntimeLibcallsTest.cpp TimePassesTest.cpp TypesTest.cpp UseTest.cpp diff --git a/llvm/unittests/IR/RuntimeLibcallsTest.cpp b/llvm/unittests/IR/RuntimeLibcallsTest.cpp deleted file mode 100644 index 012316801859c..0000000000000 --- a/llvm/unittests/IR/RuntimeLibcallsTest.cpp +++ /dev/null @@ -1,63 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/RuntimeLibcalls.h" -#include "llvm/ADT/STLExtras.h" -#include "gtest/gtest.h" -using namespace llvm; - -namespace { - -TEST(RuntimeLibcallsTest, LibcallImplByName) { - EXPECT_TRUE(RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("").empty()); - EXPECT_TRUE( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("unknown").empty()); - EXPECT_TRUE( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("Unsupported").empty()); - EXPECT_TRUE( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("unsupported").empty()); - - for (RTLIB::LibcallImpl LC : RTLIB::libcall_impls()) { - StringRef Name = RTLIB::RuntimeLibcallsInfo::getLibcallImplName(LC); - EXPECT_TRUE(is_contained( - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName(Name), LC)); - } - - // Test first libcall name - EXPECT_EQ( - RTLIB::arm64ec__Unwind_Resume, - *RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("#_Unwind_Resume") - .begin()); - // Test longest libcall names - EXPECT_EQ(RTLIB::__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes, - *RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName( - "__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes") - .begin()); - - { - auto SquirtleSquad = - RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("sqrtl"); - ASSERT_EQ(size(SquirtleSquad), 3); - auto I = SquirtleSquad.begin(); - EXPECT_EQ(*I++, RTLIB::sqrt_f128); - EXPECT_EQ(*I++, RTLIB::sqrt_f80); - EXPECT_EQ(*I++, RTLIB::sqrt_ppcf128); - } - - // Last libcall - { - auto Truncs = RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("truncl"); - ASSERT_EQ(size(Truncs), 3); - auto I = Truncs.begin(); - EXPECT_EQ(*I++, RTLIB::trunc_f128); - EXPECT_EQ(*I++, RTLIB::trunc_f80); - EXPECT_EQ(*I++, RTLIB::trunc_ppcf128); - } -} - -} // namespace diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp index c305e6323ca9d..0fc230c4714f0 100644 --- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp +++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp @@ -6,15 +6,10 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "runtime-libcall-emitter" - -#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/xxhash.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/SetTheory.h" @@ -220,9 +215,6 @@ class RuntimeLibcallEmitter { private: void emitGetRuntimeLibcallEnum(raw_ostream &OS) const; - void emitNameMatchHashTable(raw_ostream &OS, - StringToOffsetTable &OffsetTable) const; - void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const; void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const; @@ -263,9 +255,12 @@ class RuntimeLibcallEmitter { RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall, LibCallImplEnumVal++); - const RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back(); + RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back(); + Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl; + // const RuntimeLibcallImpl &LibCallImpl = + // RuntimeLibcallImplDefList.back(); if (LibCallImpl.isDefault()) { const RuntimeLibcall *Provides = LibCallImpl.getProvides(); if (!Provides) @@ -287,13 +282,6 @@ class RuntimeLibcallEmitter { void run(raw_ostream &OS); }; -/// Helper struct for the name hash table. -struct LookupEntry { - StringRef FuncName; - uint64_t Hash = 0; - unsigned TableValue = 0; -}; - } // End anonymous namespace. void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const { @@ -307,6 +295,8 @@ void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const { OS << " " << Name << " = " << LibCall.getEnumVal() << ",\n"; } + // TODO: Emit libcall names as string offset table. + OS << " UNKNOWN_LIBCALL = " << RuntimeLibcallDefList.size() << "\n};\n\n" "enum LibcallImpl : unsigned short {\n" @@ -325,179 +315,8 @@ void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const { "#endif\n\n"; } -// StringMap uses xxh3_64bits, truncated to uint32_t. -static uint64_t hash(StringRef Str) { - return static_cast(xxh3_64bits(Str)); -} - -static void emitHashFunction(raw_ostream &OS) { - OS << "static inline uint64_t hash(StringRef Str) {\n" - " return static_cast(xxh3_64bits(Str));\n" - "}\n\n"; -} - -/// Return the table size, maximum number of collisions for the set of hashes -static std::pair -computePerfectHashParameters(ArrayRef Hashes) { - const int SizeOverhead = 10; - const int NumHashes = Hashes.size(); - - // Index derived from hash -> number of collisions. - DenseMap Table; - - for (int MaxCollisions = 1;; ++MaxCollisions) { - for (int N = NumHashes; N < SizeOverhead * NumHashes; ++N) { - Table.clear(); - - bool NeedResize = false; - for (uint64_t H : Hashes) { - uint64_t Idx = H % static_cast(N); - if (++Table[Idx] > MaxCollisions) { - // Need to resize the final table if we increased the collision count. - NeedResize = true; - break; - } - } - - if (!NeedResize) - return {N, MaxCollisions}; - } - } -} - -static std::vector -constructPerfectHashTable(ArrayRef Keywords, - ArrayRef Hashes, int Size, int Collisions, - StringToOffsetTable &OffsetTable) { - DenseSet Seen; - std::vector Lookup(Size * Collisions); - - for (const RuntimeLibcallImpl &LibCallImpl : Keywords) { - StringRef ImplName = LibCallImpl.getLibcallFuncName(); - - // We do not want to add repeated entries for cases with the same name, only - // an entry for the first, with the name collision enum values immediately - // following. - if (!Seen.insert(ImplName).second) - continue; - - uint64_t HashValue = Hashes[LibCallImpl.getEnumVal() - 1]; - - uint64_t Idx = (HashValue % static_cast(Size)) * - static_cast(Collisions); - - bool Found = false; - for (int J = 0; J < Collisions; ++J) { - LookupEntry &Entry = Lookup[Idx + J]; - if (Entry.TableValue == 0) { - Entry.FuncName = ImplName; - Entry.TableValue = LibCallImpl.getEnumVal(); - Entry.Hash = HashValue; - Found = true; - break; - } - } - - if (!Found) - reportFatalInternalError("failure to hash " + ImplName); - } - - return Lookup; -} - -/// Generate hash table based lookup by name. -void RuntimeLibcallEmitter::emitNameMatchHashTable( - raw_ostream &OS, StringToOffsetTable &OffsetTable) const { - std::vector Hashes(RuntimeLibcallImplDefList.size()); - - size_t MaxFuncNameSize = 0; - size_t Index = 0; - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) { - StringRef ImplName = LibCallImpl.getLibcallFuncName(); - MaxFuncNameSize = std::max(MaxFuncNameSize, ImplName.size()); - Hashes[Index++] = hash(ImplName); - } - - LLVM_DEBUG({ - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) { - StringRef ImplName = LibCallImpl.getLibcallFuncName(); - if (ImplName.size() == MaxFuncNameSize) { - dbgs() << "Maximum runtime libcall name size: " << ImplName << '(' - << MaxFuncNameSize << ")\n"; - } - } - }); - - // Early exiting on the symbol name provides a significant speedup in the miss - // case on the set of symbols in a clang binary. Emit this as an inlinable - // precondition in the header. - // - // The empty check is also used to get sensible behavior on anonymous - // functions. - // - // TODO: It may make more sense to split the search by string size more. There - // are a few outliers, most call names are small. - OS << "#ifdef GET_LOOKUP_LIBCALL_IMPL_NAME_BODY\n" - " size_t Size = Name.size();\n" - " if (Size == 0 || Size > " - << MaxFuncNameSize - << ")\n" - " return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported);\n" - " return lookupLibcallImplNameImpl(Name);\n" - "#endif\n"; - - auto [Size, Collisions] = computePerfectHashParameters(Hashes); - std::vector Lookup = constructPerfectHashTable( - RuntimeLibcallImplDefList, Hashes, Size, Collisions, OffsetTable); - - LLVM_DEBUG(dbgs() << "Runtime libcall perfect hashing parameters: Size = " - << Size << ", maximum collisions = " << Collisions << '\n'); - - OS << "#ifdef DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME\n"; - emitHashFunction(OS); - - OS << "iota_range RTLIB::RuntimeLibcallsInfo::" - "lookupLibcallImplNameImpl(StringRef Name) {\n"; - - // Emit RTLIB::LibcallImpl values - OS << " static constexpr uint16_t HashTableNameToEnum[" << Lookup.size() - << "] = {\n"; - - for (auto [FuncName, Hash, TableVal] : Lookup) { - OS << " " << TableVal << ','; - if (TableVal != 0) - OS << " // " << format_hex(Hash, 16) << ", " << FuncName; - - OS << '\n'; - } - - OS << " };\n\n"; - - OS << " unsigned Idx = (hash(Name) % " << Size << ") * " << Collisions - << ";\n\n" - " for (int I = 0; I != " - << Collisions << R"(; ++I) { - const uint16_t Entry = HashTableNameToEnum[Idx + I]; - const uint16_t StrOffset = RuntimeLibcallNameOffsetTable[Entry]; - const uint8_t StrSize = RuntimeLibcallNameSizeTable[Entry]; - StringRef Str( - &RTLIB::RuntimeLibcallsInfo::RuntimeLibcallImplNameTableStorage[StrOffset], - StrSize); - if (Str == Name) - return libcallImplNameHit(Entry, StrOffset); - } - - return enum_seq(RTLIB::Unsupported, RTLIB::Unsupported); -} -)"; - - OS << "#endif\n\n"; -} - void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames( raw_ostream &OS) const { - OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n"; - // Emit the implementation names StringToOffsetTable Table(/*AppendZero=*/true, "RTLIB::RuntimeLibcallsInfo::"); @@ -518,15 +337,6 @@ const uint16_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameOffsetTable[] = { } OS << "};\n"; - OS << R"( -const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = { -)"; - - OS << " 0,\n"; - for (const RuntimeLibcallImpl &LibCallImpl : RuntimeLibcallImplDefList) - OS << " " << LibCallImpl.getLibcallFuncName().size() << ",\n"; - OS << "};\n\n"; - // Emit the reverse mapping from implementation libraries to RTLIB::Libcall OS << "const RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::" "ImplToLibcall[RTLIB::NumLibcallImpls] = {\n" @@ -541,10 +351,6 @@ const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = { OS << '\n'; } OS << "};\n\n"; - - OS << "#endif\n\n"; - - emitNameMatchHashTable(OS, Table); } void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( @@ -725,7 +531,9 @@ void RuntimeLibcallEmitter::run(raw_ostream &OS) { emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records); emitGetRuntimeLibcallEnum(OS); + OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n"; emitGetInitRuntimeLibcallNames(OS); + OS << "#endif\n\n"; OS << "#ifdef GET_SET_TARGET_RUNTIME_LIBCALL_SETS\n"; emitSystemRuntimeLibrarySetCalls(OS);