[llvm-branch-commits] [llvm] RuntimeLibcalls: Dispatch to library functions from SystemRuntimeLibrary (PR #217593)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Aug 20 04:10:56 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/217593

When a SystemRuntimeLibrary names LibcallLibrary defs, setTargetRuntimeLibcallSets
now dispatches each under an isLibraryAvailable guard, so an impl can be homed
into a library without dropping it from the target. Non-library members keep the
inline path. No target names a library yet, so output is unchanged.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>

>From 5a4699f6078d43ea95c4381ace08bb91fb0e0ab7 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 13 Aug 2026 16:11:18 +0200
Subject: [PATCH] RuntimeLibcalls: Dispatch to library functions from
 SystemRuntimeLibrary

When a SystemRuntimeLibrary names LibcallLibrary defs, setTargetRuntimeLibcallSets
now dispatches each under an isLibraryAvailable guard, so an impl can be homed
into a library without dropping it from the target. Non-library members keep the
inline path. No target names a library yet, so output is unchanged.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply at anthropic.com>
---
 .../RuntimeLibcallEmitter-library-dispatch.td | 52 +++++++++++++++++++
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 41 ++++++++++++++-
 2 files changed, 91 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/TableGen/RuntimeLibcallEmitter-library-dispatch.td

diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-library-dispatch.td b/llvm/test/TableGen/RuntimeLibcallEmitter-library-dispatch.td
new file mode 100644
index 0000000000000..7705dde4fafbb
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-library-dispatch.td
@@ -0,0 +1,52 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s | FileCheck %s
+
+// Check that a SystemRuntimeLibrary naming LibcallLibrary defs dispatches to
+// their setAvailableLibFuncs_<name> functions under an isLibraryAvailable guard,
+// inside the target's triple block, while bare (non-library) members are still
+// emitted inline via the flat path.
+
+include "llvm/IR/RuntimeLibcallsImpl.td"
+
+def MEMCPY : RuntimeLibcall;
+def SQRT_F64 : RuntimeLibcall;
+def EXTRA : RuntimeLibcall;
+
+def memcpy : RuntimeLibcallImpl<MEMCPY>;
+def sqrt : RuntimeLibcallImpl<SQRT_F64, "sqrt">;
+def extra : RuntimeLibcallImpl<EXTRA>;
+
+def IsX86 : LibcallPredicate<[{TT.isX86()}]>;
+def isX86 : RuntimeLibcallAvailability<(all_of IsX86)>;
+
+def Libc : LibcallLibrary<"libc", (add memcpy)>;
+def Libm : LibcallLibrary<"libm", (add sqrt)>;
+
+// Pulls two named libraries plus one bare inline member.
+def X86System : SystemRuntimeLibrary<isX86, (add Libc, Libm, extra)>;
+
+// The named libraries still get their standalone implementation functions.
+
+// CHECK: static void setAvailableLibFuncs_libc(
+// CHECK: static void setAvailableLibFuncs_libm(
+
+// The driver dispatches to each named library under its presence guard, then
+// emits the bare member (extra) inline.
+
+// CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(const llvm::Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName, LongDoubleFormat LongDoubleFormat) {
+// CHECK:   if (TT.isX86()) {
+// CHECK-NEXT:     static constexpr LibcallImplBitset SystemAvailableImpls({
+// CHECK: AvailableLibcallImpls = SystemAvailableImpls;
+// CHECK-EMPTY:
+// CHECK-NEXT:     if (isLibraryAvailable("libc"))
+// CHECK-NEXT:       setAvailableLibFuncs_libc(*this, TT, ExceptionModel, FloatABI, EABIVersion, ABIName, LongDoubleFormat);
+// CHECK-NEXT:     if (isLibraryAvailable("libm"))
+// CHECK-NEXT:       setAvailableLibFuncs_libm(*this, TT, ExceptionModel, FloatABI, EABIVersion, ABIName, LongDoubleFormat);
+// CHECK-EMPTY:
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:         RTLIB::impl_extra, // extra
+// CHECK-NEXT:     };
+// CHECK: for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:       setAvailable(Impl);
+// CHECK-NEXT:     }
+// CHECK:     return;
+// CHECK-NEXT:   }
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 2dbff92f623c0..1a90c36f2a879 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -650,6 +650,29 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
       }
     }
 
+    // Split the top-level member list into named LibcallLibrary references,
+    // which are dispatched to their own setAvailableLibFuncs_<name> function
+    // under an isLibraryAvailable guard, and the remaining (bare impl /
+    // LibcallImpls) members, which are emitted inline via the flat path below.
+    const DagInit *MemberDag =
+        R->getValueAsDef("MemberList")->getValueAsDag("MemberList");
+    SmallVector<StringRef, 4> DispatchLibs;
+    SmallVector<const Init *, 16> InlineArgs;
+    SmallVector<const StringInit *, 16> InlineArgNames;
+    for (auto [Arg, ArgName] :
+         zip_equal(MemberDag->getArgs(), MemberDag->getArgNames())) {
+      if (const auto *DI = dyn_cast<DefInit>(Arg);
+          DI && DI->getDef()->isSubClassOf("LibcallLibrary")) {
+        DispatchLibs.push_back(DI->getDef()->getValueAsString("LibraryName"));
+        continue;
+      }
+      InlineArgs.push_back(Arg);
+      InlineArgNames.push_back(ArgName);
+    }
+
+    const DagInit *InlineDag =
+        DagInit::get(MemberDag->getOperator(), InlineArgs, InlineArgNames);
+
     SetTheory Sets;
 
     DenseMap<const RuntimeLibcallImpl *,
@@ -658,8 +681,9 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
     Sets.addExpander("LibcallImpls", std::make_unique<LibcallPredicateExpander>(
                                          Libcalls, Func2Preds));
 
-    const SetTheory::RecVec *Elements =
-        Sets.expand(R->getValueAsDef("MemberList"));
+    SetTheory::RecSet ElementsSet;
+    Sets.evaluate(InlineDag, ElementsSet, R->getLoc());
+    const SetTheory::RecSet *Elements = &ElementsSet;
 
     // Sort to get deterministic output
     SetVector<PredicateWithCC> PredicateSorter;
@@ -722,6 +746,19 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
     OS << "\n    });\n"
           "    AvailableLibcallImpls = SystemAvailableImpls;\n\n";
 
+    // Dispatch to each named library's setup function. This must come after the
+    // SystemAvailableImpls assignment above (which overwrites the bitset); the
+    // library functions union their members in on top via setAvailable.
+    for (StringRef LibName : DispatchLibs) {
+      OS << indent(4) << "if (isLibraryAvailable(\"" << LibName << "\"))\n"
+         << indent(6) << "setAvailableLibFuncs_";
+      emitLibFuncSuffix(OS, LibName);
+      OS << "(*this, TT, ExceptionModel, FloatABI, EABIVersion, ABIName, "
+            "LongDoubleFormat);\n";
+    }
+    if (!DispatchLibs.empty())
+      OS << '\n';
+
     emitPredicateGroups(OS, R, Pred2Funcs, PredicateSorter, /*BaseIndent=*/2,
                         /*Receiver=*/"");
 



More information about the llvm-branch-commits mailing list