[llvm-branch-commits] [llvm] RuntimeLibcalls: Introduce LibcallLibrary schema (PR #217592)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Aug 20 04:09:22 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

Currently the set of system libraries calls is flat and
disorganized. Begin organizing this per-provider library.
The goal is to organize groups of functions by named sets,
corresponding to the underlying library which will be linked.

A LibcallLibrary is a named runtime library whose impls are made
available as a unit; its members use the same dag vocabulary as
LibcallImpls. The emitter emits one setAvailableLibFuncs_<name>
per distinct library name, merging same-named libraries under their
per-variant availability predicates. isLibraryAvailable()
is added as a stub for a future dispatch driver. No target
defines a LibcallLibrary, so generated output is mostly unchanged
(there are some incidental enum reorderings).

Reorganizing all of the library functions require a good bit more
infrastructure to be practical, but this is a minimally functional
piece to start the review.

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

---

Patch is 26.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/217592.diff


7 Files Affected:

- (modified) llvm/include/llvm/IR/RuntimeLibcalls.h (+4) 
- (modified) llvm/include/llvm/IR/RuntimeLibcallsImpl.td (+12) 
- (modified) llvm/lib/IR/RuntimeLibcalls.cpp (+6) 
- (added) llvm/test/TableGen/RuntimeLibcallEmitter-library-grouping.td (+80) 
- (added) llvm/test/TableGen/RuntimeLibcallEmitter-library-name-merge.td (+102) 
- (modified) llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td (+2-2) 
- (modified) llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp (+253-83) 


``````````diff
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 4def7c6db3d50..e7dfec449a842 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -234,6 +234,10 @@ struct RuntimeLibcallsInfo {
   LLVM_READONLY
   static bool isAAPCS_ABI(const Triple &TT, StringRef ABIName);
 
+  /// Return whether the runtime library \p LibraryName is available for the
+  /// current module.
+  bool isLibraryAvailable(StringRef LibraryName) const;
+
   /// Generated by tablegen.
   void setTargetRuntimeLibcallSets(const Triple &TT,
                                    ExceptionHandling ExceptionModel,
diff --git a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
index 1c49959285f08..59616efb41c57 100644
--- a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
+++ b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
@@ -113,6 +113,18 @@ class LibcallsWithCC<dag funcList, LibcallCallingConv CC,
   LibcallCallingConv CallingConv = CC;
 }
 
+// A named runtime library whose Impls are made available as a unit. Impls use
+// the same dag vocabulary as SystemRuntimeLibrary.
+class LibcallLibrary<string name, dag impls,
+                     RuntimeLibcallAvailability pred = AlwaysAvailable> {
+  string LibraryName = name;
+  dag Impls = impls;
+
+  // Availability guard for the library. Libraries sharing a LibraryName merge
+  // into one function, each variant under its own Pred.
+  RuntimeLibcallAvailability Pred = pred;
+}
+
 /// Define a complete top level set of runtime libcalls for a target.
 class SystemRuntimeLibrary<RuntimeLibcallAvailability Pred, dag funcList> {
   /// Set the default calling convention assumed for RuntimeLibcallImpl members.
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 1befff9d5f00e..67e1bacdb329d 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -113,6 +113,12 @@ RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Module &M,
     : RuntimeLibcallsInfo(M.getTargetTriple(), ExceptionModel, M.getFloatABI(),
                           EABIVersion, ABIName, VecLib) {}
 
+bool RuntimeLibcallsInfo::isLibraryAvailable(StringRef LibraryName) const {
+  // TODO: Drive this from module-level state (e.g. the linked runtime). For now
+  // every named library is reported as available.
+  return true;
+}
+
 /// Set default libcall names. If a target wants to opt-out of a libcall it
 /// should be placed here.
 void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-library-grouping.td b/llvm/test/TableGen/RuntimeLibcallEmitter-library-grouping.td
new file mode 100644
index 0000000000000..6937b935e7494
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-library-grouping.td
@@ -0,0 +1,80 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s | FileCheck %s
+
+// Check that each LibcallLibrary emits a standalone implementation function
+// (suffixed by the library name) that makes the library's members available,
+// with per-member triple predicates nested inside.
+
+include "llvm/IR/RuntimeLibcallsImpl.td"
+
+def MEMCPY : RuntimeLibcall;
+def MEMSET : RuntimeLibcall;
+def SQRT_F64 : RuntimeLibcall;
+def SINCOS_F64 : RuntimeLibcall;
+
+def memcpy : RuntimeLibcallImpl<MEMCPY>;
+def memset_pattern : RuntimeLibcallImpl<MEMSET, "memset_pattern">;
+def sqrt : RuntimeLibcallImpl<SQRT_F64, "sqrt">;
+def sincos : RuntimeLibcallImpl<SINCOS_F64, "sincos">;
+
+def IsDarwin : LibcallPredicate<[{TT.isOSDarwin()}]>;
+def IsX86 : LibcallPredicate<[{TT.isX86()}]>;
+def isDarwin : RuntimeLibcallAvailability<(all_of IsDarwin)>;
+def isX86 : RuntimeLibcallAvailability<(all_of IsX86)>;
+
+// libc: memcpy is universal; memset_pattern only on Darwin.
+def Libc : LibcallLibrary<"libc", (add memcpy,
+                                       LibcallImpls<(add memset_pattern), isDarwin>)>;
+
+// libm: sqrt is universal; sincos only on x86.
+def Libm : LibcallLibrary<"libm", (add sqrt,
+                                       LibcallImpls<(add sincos), isX86>)>;
+
+// One standalone implementation function is emitted per LibcallLibrary.
+
+// CHECK: static void setAvailableLibFuncs_libc(llvm::RTLIB::RuntimeLibcallsInfo &Info, const llvm::Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName, LongDoubleFormat LongDoubleFormat) {
+// CHECK-NEXT:   {
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:         RTLIB::impl_memcpy, // memcpy
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:       Info.setAvailable(Impl);
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:     if (TT.isOSDarwin()) {
+// CHECK-NEXT:       static const RTLIB::LibcallImpl LibraryCalls_isDarwin[] = {
+// CHECK-NEXT:           RTLIB::impl_memset_pattern, // memset_pattern
+// CHECK-NEXT:       };
+// CHECK-EMPTY:
+// CHECK-NEXT:       for (const RTLIB::LibcallImpl Impl : LibraryCalls_isDarwin) {
+// CHECK-NEXT:         Info.setAvailable(Impl);
+// CHECK-NEXT:       }
+// CHECK-EMPTY:
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+// CHECK: static void setAvailableLibFuncs_libm(llvm::RTLIB::RuntimeLibcallsInfo &Info, const llvm::Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName, LongDoubleFormat LongDoubleFormat) {
+// CHECK-NEXT:   {
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:         RTLIB::impl_sqrt, // sqrt
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:       Info.setAvailable(Impl);
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:     if (TT.isX86()) {
+// CHECK-NEXT:       static const RTLIB::LibcallImpl LibraryCalls_isX86[] = {
+// CHECK-NEXT:           RTLIB::impl_sincos, // sincos
+// CHECK-NEXT:       };
+// CHECK-EMPTY:
+// CHECK-NEXT:       for (const RTLIB::LibcallImpl Impl : LibraryCalls_isX86) {
+// CHECK-NEXT:         Info.setAvailable(Impl);
+// CHECK-NEXT:       }
+// CHECK-EMPTY:
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-library-name-merge.td b/llvm/test/TableGen/RuntimeLibcallEmitter-library-name-merge.td
new file mode 100644
index 0000000000000..06b900025d230
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-library-name-merge.td
@@ -0,0 +1,102 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s | FileCheck %s
+
+// Several libraries sharing one linker name (a GNU and a Darwin "libc") merge
+// into a single setAvailableLibFuncs_libc. The shared core is emitted once,
+// unguarded; each variant's guarded block carries only its own extras.
+
+include "llvm/IR/RuntimeLibcallsImpl.td"
+
+def MEMCPY : RuntimeLibcall;
+def MEMSET : RuntimeLibcall;
+def BZERO : RuntimeLibcall;
+def STPCPY : RuntimeLibcall;
+
+def memcpy : RuntimeLibcallImpl<MEMCPY>;
+def memset : RuntimeLibcallImpl<MEMSET>;
+def bzero : RuntimeLibcallImpl<BZERO>;
+def stpcpy : RuntimeLibcallImpl<STPCPY>;
+
+def IsDarwin : LibcallPredicate<[{TT.isOSDarwin()}]>;
+def IsLinux : LibcallPredicate<[{TT.isOSLinux()}]>;
+def isDarwin : RuntimeLibcallAvailability<(all_of IsDarwin)>;
+def isLinux : RuntimeLibcallAvailability<(all_of IsLinux)>;
+
+def SQRT_F64 : RuntimeLibcall;
+def sqrt : RuntimeLibcallImpl<SQRT_F64, "sqrt">;
+
+// The core libc functions shared by every libc variant.
+defvar CoreLibc = (add memcpy, memset);
+
+// Each system's libc = the common core + its own extras, selected by Pred.
+def GnuLibc : LibcallLibrary<"libc", (add CoreLibc, stpcpy)> { let Pred = isLinux; }
+def DarwinLibc : LibcallLibrary<"libc", (add CoreLibc, bzero)> { let Pred = isDarwin; }
+
+// sqrt appears in both variants but with a different calling convention
+// (ARM_AAPCS on GNU, default on Darwin), so it must not be hoisted into the
+// shared core (that would drop the per-target CC).
+def GnuLibm : LibcallLibrary<"libm", (add LibcallsWithCC<(add sqrt), ARM_AAPCS>)> {
+  let Pred = isLinux;
+}
+def DarwinLibm : LibcallLibrary<"libm", (add sqrt)> { let Pred = isDarwin; }
+
+// The shared core (memcpy, memset) is emitted once and unguarded; each variant's
+// guarded block carries only its own extras (bzero for Darwin, stpcpy for GNU).
+
+// CHECK: static void setAvailableLibFuncs_libc(llvm::RTLIB::RuntimeLibcallsInfo &Info, const llvm::Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName, LongDoubleFormat LongDoubleFormat) {
+// CHECK-NEXT:   static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:       RTLIB::impl_memcpy, // memcpy
+// CHECK-NEXT:       RTLIB::impl_memset, // memset
+// CHECK-NEXT:   };
+// CHECK-EMPTY:
+// CHECK-NEXT:   for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:     Info.setAvailable(Impl);
+// CHECK-NEXT:   }
+// CHECK-EMPTY:
+// CHECK-NEXT:   if (TT.isOSDarwin()) {
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:         RTLIB::impl_bzero, // bzero
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:       Info.setAvailable(Impl);
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   if (TT.isOSLinux()) {
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:         RTLIB::impl_stpcpy, // stpcpy
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:       Info.setAvailable(Impl);
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+// sqrt differs in calling convention between the two libm variants, so it stays
+// per-variant: no shared-core hoist, and the GNU variant keeps its ARM_AAPCS.
+
+// CHECK: static void setAvailableLibFuncs_libm(llvm::RTLIB::RuntimeLibcallsInfo &Info, const llvm::Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName, LongDoubleFormat LongDoubleFormat) {
+// CHECK-NEXT:   if (TT.isOSDarwin()) {
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
+// CHECK-NEXT:         RTLIB::impl_sqrt, // sqrt
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
+// CHECK-NEXT:       Info.setAvailable(Impl);
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:   }
+// CHECK-NEXT:   if (TT.isOSLinux()) {
+// CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls_AlwaysAvailable_ARM_AAPCS[] = {
+// CHECK-NEXT:         RTLIB::impl_sqrt, // sqrt
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls_AlwaysAvailable_ARM_AAPCS) {
+// CHECK-NEXT:       Info.setAvailable(Impl);
+// CHECK-NEXT:       Info.setLibcallImplCallingConv(Impl, CallingConv::ARM_AAPCS);
+// CHECK-NEXT:     }
+// CHECK-EMPTY:
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td b/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td
index 640b3ba7e5435..4fd713bd158dc 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td
@@ -37,8 +37,8 @@ def dup1 : RuntimeLibcallImpl<ANOTHER_DUP>;
 // CHECK-EMPTY:
 
 // CHECK-NEXT:    static const RTLIB::LibcallImpl LibraryCalls[] = {
-// CHECK-NEXT:        RTLIB::impl_func_b, // func_b
 // CHECK-NEXT:        RTLIB::impl_func_a, // func_a
+// CHECK-NEXT:        RTLIB::impl_func_b, // func_b
 // CHECK-NEXT:    };
 // CHECK-EMPTY:
 // CHECK-NEXT:    for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
@@ -82,8 +82,8 @@ def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
 // CHECK-NEXT: AvailableLibcallImpls = SystemAvailableImpls;
 // CHECK-EMPTY:
 // CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
-// CHECK-NEXT:         RTLIB::impl_dup1, // dup1
 // CHECK-NEXT:         RTLIB::impl_dup0, // dup0
+// CHECK-NEXT:         RTLIB::impl_dup1, // dup1
 // CHECK-NEXT:         RTLIB::impl_other_func, // other_func
 // CHECK-NEXT:         RTLIB::impl_func_a, // func_a
 // CHECK-NEXT:         RTLIB::impl_func_b, // func_b
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 7a76c1740b53b..2dbff92f623c0 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Format.h"
@@ -87,6 +88,21 @@ class RuntimeLibcallEmitter {
 
   void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const;
 
+  // Emit the sorted per-predicate `setAvailable` tables/loops. The
+  // always-available bucket emits at \p BaseIndent; each predicated bucket is
+  // wrapped in `if (pred)`. \p Receiver prefixes the calls ("Info." for the
+  // standalone library functions, empty otherwise).
+  void
+  emitPredicateGroups(raw_ostream &OS, const Record *R,
+                      DenseMap<PredicateWithCC, LibcallsWithCC> &Pred2Funcs,
+                      SetVector<PredicateWithCC> &PredicateSorter,
+                      unsigned BaseIndent, StringRef Receiver) const;
+
+  // Emit a file-local `setAvailableLibFuncs_<name>` for all LibcallLibrary defs
+  // sharing \p Name, each gated by its own availability predicate.
+  void emitLibraryFunction(raw_ostream &OS, StringRef Name,
+                           ArrayRef<const Record *> Libs) const;
+
   void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const;
 
   DenseSet<StringRef> collectLibcallNames() const;
@@ -371,16 +387,248 @@ const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = {
   emitNameMatchHashTable(OS, Table);
 }
 
+void RuntimeLibcallEmitter::emitPredicateGroups(
+    raw_ostream &OS, const Record *R,
+    DenseMap<PredicateWithCC, LibcallsWithCC> &Pred2Funcs,
+    SetVector<PredicateWithCC> &PredicateSorter, unsigned BaseIndent,
+    StringRef Receiver) const {
+  SmallVector<PredicateWithCC, 0> SortedPredicates =
+      PredicateSorter.takeVector();
+
+  llvm::sort(SortedPredicates, [](PredicateWithCC A, PredicateWithCC B) {
+    StringRef AName = A.Availability ? A.Availability->getName() : "";
+    StringRef BName = B.Availability ? B.Availability->getName() : "";
+    if (AName != BName)
+      return AName < BName;
+    // Break name ties on the calling convention for a deterministic order.
+    StringRef ACC = A.CallingConv ? A.CallingConv->getName() : "";
+    StringRef BCC = B.CallingConv ? B.CallingConv->getName() : "";
+    return ACC < BCC;
+  });
+
+  for (PredicateWithCC Entry : SortedPredicates) {
+    AvailabilityPredicate SubsetPredicate(Entry.Availability);
+    unsigned IndentDepth = BaseIndent;
+
+    auto It = Pred2Funcs.find(Entry);
+    if (It == Pred2Funcs.end())
+      continue;
+
+    // Shared-core deduplication can empty a bucket.
+    if (It->second.LibcallImpls.empty())
+      continue;
+
+    if (!SubsetPredicate.isAlwaysAvailable()) {
+      IndentDepth = BaseIndent + 2;
+
+      OS << indent(IndentDepth);
+      SubsetPredicate.emitIf(OS);
+    }
+
+    LibcallsWithCC &FuncsWithCC = It->second;
+
+    std::vector<const RuntimeLibcallImpl *> &Funcs = FuncsWithCC.LibcallImpls;
+
+    // Records which impls are available, not which is selected, so a libcall
+    // may have more than one. Order is irrelevant (each entry is a setAvailable
+    // call); sort by the provided libcall, breaking ties on the impl enum for a
+    // deterministic total order.
+    sort(Funcs, [](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) {
+      return std::make_pair(A->getProvides()->getEnumVal(), A->getEnumVal()) <
+             std::make_pair(B->getProvides()->getEnumVal(), B->getEnumVal());
+    });
+
+    OS << indent(IndentDepth + 2)
+       << "static const RTLIB::LibcallImpl LibraryCalls";
+    SubsetPredicate.emitTableVariableNameSuffix(OS);
+    if (FuncsWithCC.CallingConv)
+      OS << '_' << FuncsWithCC.CallingConv->getName();
+
+    OS << "[] = {\n";
+    for (const RuntimeLibcallImpl *LibCallImpl : Funcs) {
+      OS << indent(IndentDepth + 6);
+      LibCallImpl->emitEnumEntry(OS);
+      OS << ", // " << LibCallImpl->getLibcallFuncName() << '\n';
+    }
+
+    OS << indent(IndentDepth + 2) << "};\n\n"
+       << indent(IndentDepth + 2)
+       << "for (const RTLIB::LibcallImpl Impl : LibraryCalls";
+    SubsetPredicate.emitTableVariableNameSuffix(OS);
+    if (FuncsWithCC.CallingConv)
+      OS << '_' << FuncsWithCC.CallingConv->getName();
+
+    OS << ") {\n"
+       << indent(IndentDepth + 4) << Receiver << "setAvailable(Impl);\n";
+
+    if (FuncsWithCC.CallingConv) {
+      StringRef CCEnum =
+          FuncsWithCC.CallingConv->getValueAsString("CallingConv");
+      OS << indent(IndentDepth + 4) << Receiver
+         << "setLibcallImplCallingConv(Impl, " << CCEnum << ");\n";
+    }
+
+    OS << indent(IndentDepth + 2) << "}\n";
+    OS << '\n';
+
+    if (!SubsetPredicate.isAlwaysAvailable()) {
+      OS << indent(IndentDepth);
+      SubsetPredicate.emitEndIf(OS);
+      OS << '\n';
+    }
+  }
+}
+
+// Emit the linker name \p Name as a C++ identifier suffix, replacing characters
+// invalid in an identifier (e.g. the '-' in "compiler-rt") with '_'.
+static void emitLibFuncSuffix(raw_ostream &OS, StringRef Name) {
+  for (char C : Name)
+    OS << (isAlnum(C) || C == '_' ? C : '_');
+}
+
+void RuntimeLibcallEmitter::emitLibraryFunction(
+    raw_ostream &OS, StringRef Name, ArrayRef<const Record *> Libs) const {
+  // File-local; referenced only from the driver in the same fragment.
+  OS << "static void setAvailableLibFuncs_";
+  emitLibFuncSuffix(OS, Name);
+  OS << "(llvm::RTLIB::RuntimeLibcallsInfo &Info, const llvm::Triple &TT, "
+        "ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, "
+        "EABI EABIVersion, StringRef ABIName, "
+        "LongDoubleFormat LongDoubleFormat) {\n";
+
+  // Per-variant expansion. Unconditional impls are tracked separately for
+  // cross-variant deduplication.
+  struct ExpandedLibrary {
+    const Record *Lib;
+    DenseMap<PredicateWithCC, LibcallsWithCC> Pred2Funcs;
+    SetVector<PredicateWithCC> PredicateSorter;
+    SetVector<const RuntimeLibcallImpl *> Unconditional;
+  };
+
+  SmallVector<ExpandedLibrary, 2> Expanded;
+  for (const Record *Lib : Libs) {
+    ExpandedLibrary EL;
+    EL.Lib = Lib;
+
+    // Expand this library's members with a library-local Func2Preds.
+    SetTheory Sets;
+    DenseMap<const RuntimeLibcallImpl *,
+             std::pair<std::vector<const Record *>, const Record *>>
+        Func2Preds;
+    Sets.addExpander("LibcallImpls", std::make_unique<LibcallPredicateExpander>(
+                                         Libcalls, Func2Preds));
+
+    SetTheory::RecSet Elements;
+    Sets.evaluate(Lib->getValueInit("Impls"), Elements, Lib->getLoc());
+
+    EL.PredicateSorter.insert(
+        PredicateWithCC()); // No predicate or CC override first.
+
+    for (const Record *Elt : Elements) {
+      const RuntimeLibcallImpl *LibCallImpl =
+          Libcalls.getRuntimeLibcallImpl(Elt);
+      if (!LibCallImpl) {
+        PrintError(Lib, "entry for LibcallLibrary is not a RuntimeLibcallImpl");
+        PrintNote(Elt->getLoc(), "invalid entry `" + Elt->getName() + "`");
+        continue;
+      }
+
+      auto It = Func2Preds.find(LibCallImpl);
+      if (It == Func2Preds.end()) {
+        EL.Pred2Funcs[PredicateWithCC()].LibcallImpls.push_back(LibCallImpl);
+        EL.Unconditional.insert(LibCallImpl);
+        continue;
+      }
+
+      for (const Record *Pred : It->second.first) {
+        const Record *CC = It->second.second;
+        PredicateWithCC Key(Pred, CC);
+        auto &Entry = EL.Pred2Funcs[Key];
+        Entry.LibcallImpls.push_back(LibCallImpl);
+        Entry.CallingConv = CC;
+        EL.PredicateSorter.insert(Key);
+      }
+    }
+
+    Expanded.pus...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/217592


More information about the llvm-branch-commits mailing list