[llvm-branch-commits] [llvm] RuntimeLibcalls: Use a single LibcallImpl for long double functions (PR #233872)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Oct 20 08:02:11 PDT 2026


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

Replace the per-format <func>l_{f80|f128|ppcf128} implementations with
a single <func>l implementaton. The concrete type is now derived from
the module/triple's LongDoubleFormat, so this is no longer a static
property.

On targets where long double is double, the l-suffixed functions do
not provide a libcall. This could be fixed in principle, but nothing
would use it in the compiler.

Co-authored-by: Claude Opus 5.5 <noreply at anthropic.com>

>From 319e9a6bc4b2d1bd4c386b16b32ca0b12be1ae4e Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 20 Oct 2026 13:51:34 +0200
Subject: [PATCH] RuntimeLibcalls: Use a single LibcallImpl for long double
 functions

Replace the per-format <func>l_{f80|f128|ppcf128} implementations with
a single <func>l implementaton. The concrete type is now derived from
the module/triple's LongDoubleFormat, so this is no longer a static
property.

On targets where long double is double, the l-suffixed functions do
not provide a libcall. This could be fixed in principle, but nothing
would use it in the compiler.

Co-authored-by: Claude Opus 5.5 <noreply at anthropic.com>
---
 llvm/include/llvm/IR/RuntimeLibcalls.h        |  10 +-
 llvm/include/llvm/IR/RuntimeLibcalls.td       | 116 ++++++------------
 llvm/include/llvm/IR/RuntimeLibcallsImpl.td   |  12 ++
 llvm/lib/Analysis/LibcallLoweringInfo.cpp     |   5 +-
 llvm/lib/IR/RuntimeLibcalls.cpp               |  20 +++
 .../Target/AArch64/AArch64SMEAttributes.cpp   |   2 +-
 llvm/lib/Target/Mips/MipsSubtarget.cpp        |   4 +-
 .../WebAssemblyRuntimeLibcallSignatures.cpp   |   4 +-
 .../RuntimeLibcallEmitter-multiple-impls.td   |   4 +-
 llvm/test/TableGen/RuntimeLibcallEmitter.td   |   6 +-
 llvm/unittests/IR/RuntimeLibcallsTest.cpp     |  14 +--
 llvm/utils/TableGen/Basic/RuntimeLibcalls.h   |  18 ++-
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp |  42 +++++--
 13 files changed, 143 insertions(+), 114 deletions(-)

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 4df5d865ab6cba..6a02329b68fc88 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -128,9 +128,7 @@ struct RuntimeLibcallsInfo {
   }
 
   /// Return the libcall provided by \p Impl
-  static RTLIB::Libcall getLibcallFromImpl(RTLIB::LibcallImpl Impl) {
-    return ImplToLibcall[Impl];
-  }
+  LLVM_ABI RTLIB::Libcall getLibcallFromImpl(RTLIB::LibcallImpl Impl) const;
 
   /// Return the runtime libcall that the floating-point math intrinsic \p ID
   /// may be lowered to, or RTLIB::UNKNOWN_LIBCALL if there is no such mapping.
@@ -212,7 +210,7 @@ struct RuntimeLibcallsInfo {
   /// Returns true if the function has a vector mask argument, which is assumed
   /// to be the last argument.
   static bool hasVectorMaskArgument(RTLIB::LibcallImpl Impl) {
-    return getUnmaskedVectorLibcall(getLibcallFromImpl(Impl)) !=
+    return getUnmaskedVectorLibcall(ImplToLibcall[Impl]) !=
            RTLIB::UNKNOWN_LIBCALL;
   }
 
@@ -246,6 +244,10 @@ struct RuntimeLibcallsInfo {
   /// Map from a concrete LibcallImpl implementation to its RTLIB::Libcall kind.
   LLVM_ABI static const RTLIB::Libcall ImplToLibcall[RTLIB::NumLibcallImpls];
 
+  RTLIB::Libcall selectLongDoubleLibcall(RTLIB::Libcall F80,
+                                         RTLIB::Libcall F128,
+                                         RTLIB::Libcall PPCF128) const;
+
   /// 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.
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index 52b3ce23b2916b..7ca9fa82fde47d 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -130,6 +130,8 @@ def isAArch64 : RuntimeLibcallAvailability<(all_of IsAArch64)>;
 def isLongDoubleX87 : RuntimeLibcallAvailability<(all_of IsLongDoubleX87)>;
 def isLongDoubleF128 : RuntimeLibcallAvailability<(all_of IsLongDoubleF128)>;
 def isLongDoublePPCF128 : RuntimeLibcallAvailability<(all_of IsLongDoublePPCF128)>;
+def isLongDoubleWide : RuntimeLibcallAvailability<
+  (any_of IsLongDoubleX87, IsLongDoubleF128, IsLongDoublePPCF128)>;
 
 // The l-suffixed sincos exists only when hasSinCos and the long double type
 // matches the width.
@@ -137,6 +139,9 @@ def isLongDoubleX87AndHasSinCos : RuntimeLibcallAvailability<
   (all_of IsLongDoubleX87, (any_of IsGNUEnv, IsOSFuchsia, IsAndroid))>;
 def isLongDoubleF128AndHasSinCos : RuntimeLibcallAvailability<
   (all_of IsLongDoubleF128, (any_of IsGNUEnv, IsOSFuchsia, IsAndroid))>;
+def isLongDoubleWideAndHasSinCos : RuntimeLibcallAvailability<
+  (all_of (any_of IsLongDoubleX87, IsLongDoubleF128, IsLongDoublePPCF128),
+          (any_of IsGNUEnv, IsOSFuchsia, IsAndroid))>;
 
 def isOSWindows : RuntimeLibcallAvailability<(all_of IsOSWindows)>;
 def isNotOSWindows : RuntimeLibcallAvailability<(not IsOSWindows)>;
@@ -196,11 +201,6 @@ def hasSinCos
 def hasSinCos_f32_f64
   : RuntimeLibcallAvailability<(any_of IsGNUEnv, IsOSFuchsia, IsAndroid, IsPS)>;
 
-// The ppcf128 l-suffixed sincos exists only when hasSinCos and long double is
-// ppcf128.
-def isLongDoublePPCF128AndHasSinCos : RuntimeLibcallAvailability<
-  (all_of IsLongDoublePPCF128, (any_of IsGNUEnv, IsOSFuchsia, IsAndroid))>;
-
 def IsExceptionModelNone
   : LibcallPredicate<[{ExceptionModel == ExceptionHandling::None}]>;
 def IsExceptionModelSjLj
@@ -758,15 +758,9 @@ multiclass LibmLibcallImpls<string libcall_basename = !toupper(NAME),
   def NAME#""
       : RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_F64"),
                            !subst("<typesuffix>", "", rtbasename)>;
-  def NAME#"l_f128"
-      : RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_F128"),
-                           !subst("<typesuffix>", "l", rtbasename)>;
-  def NAME#"l_ppcf128"
-      : RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_PPCF128"),
-                           !subst("<typesuffix>", "l", rtbasename)>;
-  def NAME#"l_f80"
-      : RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_F80"),
-                           !subst("<typesuffix>", "l", rtbasename)>;
+  def NAME#"l"
+      : LongDoubleLibcallImpl<libcall_basename,
+                              !subst("<typesuffix>", "l", rtbasename)>;
 }
 
 // AArch64 calls
@@ -2080,7 +2074,7 @@ def WindowsCRTLibcAArch64 : LibcallLibrary<"libc",
 def WindowsCRTLibcARM : LibcallLibrary<"libc", (add __chkstk), isWindowsARM>;
 
 defvar LibmHasSincoslF128 =
-    LibcallImpls<(add sincosl_f128), isLongDoubleF128AndHasSinCos>;
+    LibcallImpls<(add sincosl), isLongDoubleF128AndHasSinCos>;
 
 defvar LibmHasExp10F32 = LibcallImpls<(add exp10f), hasExp10>;
 defvar LibmHasExp10F64 = LibcallImpls<(add exp10), hasExp10>;
@@ -2088,9 +2082,6 @@ defvar LibmHasExp10F64 = LibcallImpls<(add exp10), hasExp10>;
 defvar LibmHasFrexpF32 = LibcallImpls<(add frexpf), isNotOSWindowsOrIsCygwinMinGW>;
 defvar LibmHasLdexpF32 = LibcallImpls<(add ldexpf), isNotOSWindowsOrIsCygwinMinGW>;
 
-defvar LibmHasFrexpF128 = LibcallImpls<(add frexpl_f128), isNotOSWindowsOrIsCygwinMinGW>;
-defvar LibmHasLdexpF128 = LibcallImpls<(add ldexpl_f128), isNotOSWindowsOrIsCygwinMinGW>;
-
 defvar has__stack_chk_fail = LibcallImpls<(add __stack_chk_fail), hasStackChkFail>;
 defvar has__stack_chk_guard =
     LibcallImpls<(add __stack_chk_guard), hasStackChkFail>;
@@ -2120,60 +2111,39 @@ def SafeStackRuntime : LibcallLibrary<"compiler-rt",
 // libm provider library
 //===----------------------------------------------------------------------===//
 
-// Width-specific slices of the libm body. The core holds the f32 and f64
+// The long double slice of the libm body. The core holds the f32 and f64
 // functions, as well as the complex and fenv entries.
-defvar LibmCoreImpls_f80 =
-    !filter(entry, LibmCoreImpls, !match(!cast<string>(entry.Provides), "F80"));
-defvar LibmCoreImpls_ppcf128 =
-    !filter(entry, LibmCoreImpls,
-            !match(!cast<string>(entry.Provides), "PPCF128"));
-defvar LibmCoreImpls_f128 =
-    !filter(entry, LibmCoreImpls, !match(!cast<string>(entry.Provides), "_F128"));
-defvar LibmCoreImpls_core =
-    !listremove(
-      !listremove(
-        !listremove(LibmCoreImpls, LibmCoreImpls_f80),
-                    LibmCoreImpls_ppcf128),
-                    LibmCoreImpls_f128);
+defvar LibmCoreImpls_ldbl =
+    !filter(entry, LibmCoreImpls, !isa<LongDoubleLibcallImpl>(entry));
+defvar LibmCoreImpls_core = !listremove(LibmCoreImpls, LibmCoreImpls_ldbl);
 
 // The Windows math runtime lacks frexp/ldexp except for f64, so the other widths
 // are pulled out of the slices and re-added under a Windows guard.
 defvar LibmFrexpLdexpF32 = [frexpf, ldexpf];
-defvar LibmFrexpLdexpF80 = [frexpl_f80, ldexpl_f80];
-defvar LibmFrexpLdexpF128 = [frexpl_f128, ldexpl_f128];
-defvar LibmFrexpLdexpPPCF128 = [frexpl_ppcf128, ldexpl_ppcf128];
+defvar LibmFrexpLdexpLDbl = [frexpl, ldexpl];
 
 // exp10 is absent from the Darwin math runtime, which uses __exp10 instead.
 defvar LibmExp10F32F64 = [exp10f, exp10];
-defvar LibmExp10F80 = [exp10l_f80];
-defvar LibmExp10F128 = [exp10l_f128];
-defvar LibmExp10PPCF128 = [exp10l_ppcf128];
+defvar LibmExp10LDbl = [exp10l];
 
 defvar LibmCoreImpls_core_noFrexpLdexp =
     !listremove(!listremove(LibmCoreImpls_core, LibmFrexpLdexpF32),
                 LibmExp10F32F64);
-defvar LibmCoreImpls_f80_noFrexpLdexp =
-    !listremove(!listremove(LibmCoreImpls_f80, LibmFrexpLdexpF80), LibmExp10F80);
-defvar LibmCoreImpls_f128_noFrexpLdexp =
-    !listremove(!listremove(LibmCoreImpls_f128, LibmFrexpLdexpF128),
-                LibmExp10F128);
-defvar LibmCoreImpls_ppcf128_noFrexpLdexp =
-    !listremove(!listremove(LibmCoreImpls_ppcf128, LibmFrexpLdexpPPCF128),
-                LibmExp10PPCF128);
-
-def isLongDoubleX87NotWinMath : RuntimeLibcallAvailability<
-  (all_of IsLongDoubleX87, (any_of (not IsOSWindows), IsOSCygMing))>;
+defvar LibmCoreImpls_ldbl_noFrexpLdexp =
+    !listremove(!listremove(LibmCoreImpls_ldbl, LibmFrexpLdexpLDbl),
+                LibmExp10LDbl);
+
+def isLongDoubleWideNotWinMath : RuntimeLibcallAvailability<
+  (all_of (any_of IsLongDoubleX87, IsLongDoubleF128, IsLongDoublePPCF128),
+          (any_of (not IsOSWindows), IsOSCygMing))>;
 def isLongDoubleF128NotWinMath : RuntimeLibcallAvailability<
   (all_of IsLongDoubleF128, (any_of (not IsOSWindows), IsOSCygMing))>;
-def isLongDoublePPCF128NotWinMath : RuntimeLibcallAvailability<
-  (all_of IsLongDoublePPCF128, (any_of (not IsOSWindows), IsOSCygMing))>;
 
-def isLongDoubleX87NotDarwin : RuntimeLibcallAvailability<
-  (all_of IsLongDoubleX87, (not IsOSDarwin))>;
+def isLongDoubleWideNotDarwin : RuntimeLibcallAvailability<
+  (all_of (any_of IsLongDoubleX87, IsLongDoubleF128, IsLongDoublePPCF128),
+          (not IsOSDarwin))>;
 def isLongDoubleF128NotDarwin : RuntimeLibcallAvailability<
   (all_of IsLongDoubleF128, (not IsOSDarwin))>;
-def isLongDoublePPCF128NotDarwin : RuntimeLibcallAvailability<
-  (all_of IsLongDoublePPCF128, (not IsOSDarwin))>;
 
 // The libm body shared by every libm variant. The `l`-suffixed functions are
 // selected by the module's long double format.
@@ -2181,19 +2151,11 @@ defvar LibmImpls =
   (add LibmCoreImpls_core_noFrexpLdexp,
        LibcallImpls<(add LibmFrexpLdexpF32), isNotOSWindowsOrIsCygwinMinGW>,
        LibcallImpls<(add LibmExp10F32F64), hasExp10>,
-       LibcallImpls<(add LibmCoreImpls_f80_noFrexpLdexp), isLongDoubleX87>,
-       LibcallImpls<(add LibmFrexpLdexpF80), isLongDoubleX87NotWinMath>,
-       LibcallImpls<(add LibmExp10F80), isLongDoubleX87NotDarwin>,
-       LibcallImpls<(add LibmCoreImpls_f128_noFrexpLdexp), isLongDoubleF128>,
-       LibcallImpls<(add LibmFrexpLdexpF128), isLongDoubleF128NotWinMath>,
-       LibcallImpls<(add LibmExp10F128), isLongDoubleF128NotDarwin>,
-       LibcallImpls<(add LibmCoreImpls_ppcf128_noFrexpLdexp), isLongDoublePPCF128>,
-       LibcallImpls<(add LibmFrexpLdexpPPCF128), isLongDoublePPCF128NotWinMath>,
-       LibcallImpls<(add LibmExp10PPCF128), isLongDoublePPCF128NotDarwin>,
+       LibcallImpls<(add LibmCoreImpls_ldbl_noFrexpLdexp), isLongDoubleWide>,
+       LibcallImpls<(add LibmFrexpLdexpLDbl), isLongDoubleWideNotWinMath>,
+       LibcallImpls<(add LibmExp10LDbl), isLongDoubleWideNotDarwin>,
        LibcallImpls<(add sincosf, sincos), hasSinCos>,
-       LibcallImpls<(add sincosl_f80), isLongDoubleX87AndHasSinCos>,
-       LibcallImpls<(add sincosl_f128), isLongDoubleF128AndHasSinCos>,
-       LibcallImpls<(add sincosl_ppcf128), isLongDoublePPCF128AndHasSinCos>);
+       LibcallImpls<(add sincosl), isLongDoubleWideAndHasSinCos>);
 
 def Libm : LibcallLibrary<"libm", LibmImpls>;
 
@@ -2336,18 +2298,17 @@ def isWindowsArm64EC : RuntimeLibcallAvailability<(all_of IsWindowsArm64EC)>;
 
 // frexpl/ldexpl/exp10l are added separately based on the Target Triple.
 defvar AArch64LongDoubleF128Body =
-    !listremove(LibmCoreImpls_f128,
-                [frexpl_f128, ldexpl_f128, exp10l_f128]);
+    !listremove(LibmCoreImpls_ldbl, [frexpl, ldexpl, exp10l]);
 
 // AArch64 libm extras.
 def AArch64Libm : LibcallLibrary<"libm",
   (add LibmHasFrexpF32, LibmHasLdexpF32, LibmHasSincoslF128,
        // The l-suffixed libm functions are fp128 only when long double is.
-       LibcallImpls<(add frexpl_f128, ldexpl_f128), isLongDoubleF128NotWinMath>,
+       LibcallImpls<(add frexpl, ldexpl), isLongDoubleF128NotWinMath>,
        LibcallImpls<(add AArch64LongDoubleF128Body), isLongDoubleF128>,
        LibmHasExp10F32, LibmHasExp10F64,
        // exp10l is fp128 only when long double is.
-       LibcallImpls<(add exp10l_f128), isLongDoubleF128NotDarwin>),
+       LibcallImpls<(add exp10l), isLongDoubleF128NotDarwin>),
   isAArch64_ExceptArm64EC>;
 
 // AArch64 outline atomics and streaming-mode mem* helpers.
@@ -2910,8 +2871,7 @@ def ARMCompilerRt : LibcallLibrary<"compiler-rt",
 
 // The l-suffixed libm functions are fp128 only when long double is.
 def ARMLibm : LibcallLibrary<"libm",
-  (add LibcallImpls<(add frexpl_f128, ldexpl_f128, sincosl_f128, exp10l_f128),
-                    isLongDoubleF128>),
+  (add LibcallImpls<(add frexpl, ldexpl, sincosl, exp10l), isLongDoubleF128>),
   isARMOrThumb>;
 
 def ARMSystemLibrary
@@ -3419,7 +3379,7 @@ def PPCLibc : LibcallLibrary<"libc",
 
 // PPC's f128 and ppcf128 math.
 def PPCLibm : LibcallLibrary<"libm",
-  (add LibmF128Libcalls, LibmCoreImpls_ppcf128), isPPC>;
+  (add LibmF128Libcalls, LibmCoreImpls_ldbl), isPPC>;
 
 // PPC's stack protector, which uses __ssp_canary_word on AIX.
 def PPCStackProtectorLibc : LibcallLibrary<"libc",
@@ -3629,8 +3589,8 @@ def X86Libm : LibcallLibrary<"libm",
   (add X86_F128_Libcalls,
        LibcallImpls<(add sincosf, sincos), hasSinCos_f32_f64>,
        // frexpl/ldexpl are available on Windows too.
-       LibcallImpls<(add frexpl_f80, ldexpl_f80), isLongDoubleX87>,
-       LibcallImpls<(add frexpl_f128, ldexpl_f128), isLongDoubleF128>), isX86>;
+       LibcallImpls<(add frexpl, ldexpl), isLongDoubleWide>,
+       LibcallImpls<(add sincosl), isLongDoubleX87AndHasSinCos>), isX86>;
 
 def X86SystemLibrary
     : SystemRuntimeLibrary<isX86,
@@ -3638,7 +3598,7 @@ def X86SystemLibrary
                       !listconcat(WindowsDivRemMulLibcallOverrides,
                                   [__powitf2_f128])>,
            // x86 has no fp128 sincosl, only the x87 one.
-           LibraryRef<Libm, [sincosl_f128]>,
+           LibraryRef<Libm, [sincosl]>,
            LibraryRef<Libc, !listconcat(MemChkLibcalls, [bzero])>,
            ExceptionRuntime, SafeStackRuntime)>;
 
@@ -3816,7 +3776,7 @@ def WasmExceptionRuntime : LibcallLibrary<"unwind",
 
 def WasmSystemLibrary
     : SystemRuntimeLibrary<isWasm,
-      (add CompilerRtLibgcc, LibraryRef<Libm, [sincos, sincosf, sincosl_f128]>,
+      (add CompilerRtLibgcc, LibraryRef<Libm, [sincos, sincosf, sincosl]>,
            Libc, WasmLibc, WasmCompilerRt,
            ExceptionRuntime, WasmExceptionRuntime)>;
 
diff --git a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
index 4ccb472995795c..81b652176c1c67 100644
--- a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
+++ b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
@@ -158,6 +158,18 @@ class RuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME> {
   list<FuncArgType> ArgumentTypes = P.ArgumentTypes;
 }
 
+// Implementation of a long double function, which provides the libcall
+// matching the module's long double format.
+class LongDoubleLibcallImpl<string libcall_basename, string Name = NAME>
+    : RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_F128"),
+                         Name> {
+  let Provides = ?;
+  RuntimeLibcall ProvidesF80 = !cast<RuntimeLibcall>(libcall_basename#"_F80");
+  RuntimeLibcall ProvidesF128 = !cast<RuntimeLibcall>(libcall_basename#"_F128");
+  RuntimeLibcall ProvidesPPCF128 =
+      !cast<RuntimeLibcall>(libcall_basename#"_PPCF128");
+}
+
 /// A family of runtime libcalls implementing one floating-point operation, used
 /// to generate both the backend selector RTLIB::get<base>(EVT) and the IR-level
 /// getLibcallForIntrinsic() mapping. The libcall for a type is `<base>_<suffix>`
diff --git a/llvm/lib/Analysis/LibcallLoweringInfo.cpp b/llvm/lib/Analysis/LibcallLoweringInfo.cpp
index 95b3b0fce6a8df..c6095ff75370b4 100644
--- a/llvm/lib/Analysis/LibcallLoweringInfo.cpp
+++ b/llvm/lib/Analysis/LibcallLoweringInfo.cpp
@@ -19,9 +19,10 @@ LibcallLoweringInfo::LibcallLoweringInfo(
   // call is available.
   for (RTLIB::LibcallImpl Impl : RTLIB::libcall_impls()) {
     if (RTLCI.isAvailable(Impl)) {
-      RTLIB::Libcall LC = RTLIB::RuntimeLibcallsInfo::getLibcallFromImpl(Impl);
+      RTLIB::Libcall LC = RTLCI.getLibcallFromImpl(Impl);
       // FIXME: Hack, assume the first available libcall wins.
-      if (LibcallImpls[LC] == RTLIB::Unsupported)
+      if (LC != RTLIB::UNKNOWN_LIBCALL &&
+          LibcallImpls[LC] == RTLIB::Unsupported)
         LibcallImpls[LC] = Impl;
     }
   }
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 4fc7ea7d0a6c90..62b0ff91f78ddd 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -79,6 +79,26 @@ RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Module &M, StringRef ABIName,
                           M.getFloatABI(), M.getLongDoubleFormat(), ABIName,
                           VecLib) {}
 
+RTLIB::Libcall RuntimeLibcallsInfo::selectLongDoubleLibcall(
+    RTLIB::Libcall F80, RTLIB::Libcall F128, RTLIB::Libcall PPCF128) const {
+  switch (LongDoubleFmt) {
+  case LongDoubleFormat::X87DoubleExtended:
+    return F80;
+  case LongDoubleFormat::IEEEquad:
+    return F128;
+  case LongDoubleFormat::PPCDoubleDouble:
+    return PPCF128;
+  case LongDoubleFormat::IEEEsingle:
+  case LongDoubleFormat::IEEEdouble:
+    // These long double formats aren't properly handled, but we also don't emit
+    // calls for them. TODO: We could fix the avr_sin/avr_cos hack if we handled
+    // the float case.
+    return RTLIB::UNKNOWN_LIBCALL;
+  }
+
+  llvm_unreachable("unhandled long double format");
+}
+
 bool RuntimeLibcallsInfo::isLibraryAvailable(RuntimeLibrary Library) const {
   // TODO: Drive this from module-level state (e.g. the linked runtime). For now
   // every named library is reported as available.
diff --git a/llvm/lib/Target/AArch64/AArch64SMEAttributes.cpp b/llvm/lib/Target/AArch64/AArch64SMEAttributes.cpp
index 0a5d475c211a7b..fa4732bf3e8b5f 100644
--- a/llvm/lib/Target/AArch64/AArch64SMEAttributes.cpp
+++ b/llvm/lib/Target/AArch64/AArch64SMEAttributes.cpp
@@ -79,7 +79,7 @@ void SMEAttrs::addKnownFunctionAttrs(StringRef FuncName,
   if (Impl == RTLIB::Unsupported)
     return;
   unsigned KnownAttrs = SMEAttrs::Normal;
-  RTLIB::Libcall LC = RTLIB::RuntimeLibcallsInfo::getLibcallFromImpl(Impl);
+  RTLIB::Libcall LC = RTLCI.getLibcallFromImpl(Impl);
   switch (LC) {
   case RTLIB::SMEABI_SME_STATE:
   case RTLIB::SMEABI_TPIDR2_SAVE:
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp b/llvm/lib/Target/Mips/MipsSubtarget.cpp
index f75a8c2c0e30ad..95f032c0f77500 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.cpp
+++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp
@@ -305,8 +305,8 @@ void MipsSubtarget::initLibcallLoweringInfo(LibcallLoweringInfo &Info) const {
     for (unsigned I = 0; I != std::size(HardFloatLibCalls); ++I) {
       assert((I == 0 || HardFloatLibCalls[I - 1] < HardFloatLibCalls[I]) &&
              "Array not sorted!");
-      RTLIB::Libcall LC =
-          RTLIB::RuntimeLibcallsInfo::getLibcallFromImpl(HardFloatLibCalls[I]);
+      RTLIB::Libcall LC = Info.getRuntimeLibcallsInfo().getLibcallFromImpl(
+          HardFloatLibCalls[I]);
       Info.setLibcallImpl(LC, HardFloatLibCalls[I]);
     }
   }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp
index 698b8084909cea..36bba46126c291 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp
@@ -562,8 +562,8 @@ struct StaticLibcallNameMap {
     for (RTLIB::LibcallImpl Impl : RTLIB::libcall_impls()) {
       if (!RTCI.isAvailable(Impl))
         continue;
-      RTLIB::Libcall LC = RTLIB::RuntimeLibcallsInfo::getLibcallFromImpl(Impl);
-      if (Table[LC] != unsupported) {
+      RTLIB::Libcall LC = RTCI.getLibcallFromImpl(Impl);
+      if (LC != RTLIB::UNKNOWN_LIBCALL && Table[LC] != unsupported) {
         StringRef NameLibcall =
             RTLIB::RuntimeLibcallsInfo::getLibcallImplName(Impl);
         // FIXME: Map should be to LibcallImpl
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td b/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td
index 815ebea4ec28af..c5232683a5b8c9 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-multiple-impls.td
@@ -40,9 +40,9 @@ def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA, (add LibA)>;
 
 // CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setAvailableLibFuncs_libb(
 // CHECK:    static const RTLIB::LibcallImpl LibraryCalls[] = {
-// CHECK-NEXT:        RTLIB::impl_other_func, // other_func
 // CHECK-NEXT:        RTLIB::impl_func_a, // func_a
 // CHECK-NEXT:        RTLIB::impl_func_b, // func_b
+// CHECK-NEXT:        RTLIB::impl_other_func, // other_func
 // CHECK-NEXT:    };
 
 def LibB : LibcallLibrary<"libb", (add func_a, other_func, func_b)>;
@@ -52,10 +52,10 @@ def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB, (add LibB)>;
 // CHECK:     static const RTLIB::LibcallImpl LibraryCalls[] = {
 // 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
 // CHECK-NEXT:         RTLIB::impl_func_c, // func_c
+// CHECK-NEXT:         RTLIB::impl_other_func, // other_func
 // CHECK-NEXT:     };
 
 def LibC : LibcallLibrary<"libc",
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td
index fa4a50ef029355..3150806a731797 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td
@@ -347,8 +347,8 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add BlahLibc)>;
 // CHECK-NEXT:   if (TT.getArch() == Triple::buzz) {
 // CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
 // CHECK-NEXT:         RTLIB::impl___ashlsi3, // __ashlsi3
-// CHECK-NEXT:         RTLIB::impl_sqrtl_f80, // sqrtl
 // CHECK-NEXT:         RTLIB::impl___lshrdi3, // __lshrdi3
+// CHECK-NEXT:         RTLIB::impl_sqrtl_f80, // sqrtl
 // CHECK-NEXT:     };
 // CHECK-EMPTY:
 // CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
@@ -380,10 +380,10 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add BlahLibc)>;
 // CHECK-NEXT:   }
 // CHECK-NEXT:   if (TT.getArch() == Triple::simple) {
 // CHECK-NEXT:     static const RTLIB::LibcallImpl LibraryCalls[] = {
-// CHECK-NEXT:         RTLIB::impl_calloc, // calloc
 // CHECK-NEXT:         RTLIB::impl___ashlsi3, // __ashlsi3
-// CHECK-NEXT:         RTLIB::impl_sqrtl_f80, // sqrtl
 // CHECK-NEXT:         RTLIB::impl___lshrdi3, // __lshrdi3
+// CHECK-NEXT:         RTLIB::impl_calloc, // calloc
+// CHECK-NEXT:         RTLIB::impl_sqrtl_f80, // sqrtl
 // CHECK-NEXT:     };
 // CHECK-EMPTY:
 // CHECK-NEXT:     for (const RTLIB::LibcallImpl Impl : LibraryCalls) {
diff --git a/llvm/unittests/IR/RuntimeLibcallsTest.cpp b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
index 22cff2ddfa610f..ae72fa75abfdb1 100644
--- a/llvm/unittests/IR/RuntimeLibcallsTest.cpp
+++ b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
@@ -46,21 +46,15 @@ TEST(RuntimeLibcallsTest, LibcallImplByName) {
   {
     auto SquirtleSquad =
         RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("sqrtl");
-    ASSERT_EQ(size(SquirtleSquad), 3);
-    auto I = SquirtleSquad.begin();
-    EXPECT_EQ(*I++, RTLIB::impl_sqrtl_f128);
-    EXPECT_EQ(*I++, RTLIB::impl_sqrtl_f80);
-    EXPECT_EQ(*I++, RTLIB::impl_sqrtl_ppcf128);
+    ASSERT_EQ(size(SquirtleSquad), 1);
+    EXPECT_EQ(*SquirtleSquad.begin(), RTLIB::impl_sqrtl);
   }
 
   // Last libcall
   {
     auto Truncs = RTLIB::RuntimeLibcallsInfo::lookupLibcallImplName("truncl");
-    ASSERT_EQ(size(Truncs), 3);
-    auto I = Truncs.begin();
-    EXPECT_EQ(*I++, RTLIB::impl_truncl_f128);
-    EXPECT_EQ(*I++, RTLIB::impl_truncl_f80);
-    EXPECT_EQ(*I++, RTLIB::impl_truncl_ppcf128);
+    ASSERT_EQ(size(Truncs), 1);
+    EXPECT_EQ(*Truncs.begin(), RTLIB::impl_truncl);
   }
 }
 
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcalls.h b/llvm/utils/TableGen/Basic/RuntimeLibcalls.h
index 5225a34eb71207..c5b783a3444806 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcalls.h
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcalls.h
@@ -101,6 +101,9 @@ class RuntimeLibcall {
 class RuntimeLibcallImpl {
   const Record *TheDef;
   const RuntimeLibcall *Provides = nullptr;
+  const RuntimeLibcall *ProvidesF80 = nullptr;
+  const RuntimeLibcall *ProvidesF128 = nullptr;
+  const RuntimeLibcall *ProvidesPPCF128 = nullptr;
   const size_t EnumVal;
 
 public:
@@ -109,8 +112,15 @@ class RuntimeLibcallImpl {
       const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap,
       size_t EnumVal)
       : TheDef(Def), EnumVal(EnumVal) {
-    if (const Record *ProvidesDef = Def->getValueAsDef("Provides"))
+    if (const Record *ProvidesDef = Def->getValueAsOptionalDef("Provides"))
       Provides = ProvideMap.lookup(ProvidesDef);
+
+    if (Def->isSubClassOf("LongDoubleLibcallImpl")) {
+      ProvidesF80 = ProvideMap.lookup(Def->getValueAsDef("ProvidesF80"));
+      ProvidesF128 = ProvideMap.lookup(Def->getValueAsDef("ProvidesF128"));
+      ProvidesPPCF128 =
+          ProvideMap.lookup(Def->getValueAsDef("ProvidesPPCF128"));
+    }
   }
 
   ~RuntimeLibcallImpl() = default;
@@ -123,6 +133,12 @@ class RuntimeLibcallImpl {
 
   const RuntimeLibcall *getProvides() const { return Provides; }
 
+  bool isLongDouble() const { return ProvidesF80 != nullptr; }
+
+  const RuntimeLibcall *getProvidesF80() const { return ProvidesF80; }
+  const RuntimeLibcall *getProvidesF128() const { return ProvidesF128; }
+  const RuntimeLibcall *getProvidesPPCF128() const { return ProvidesPPCF128; }
+
   StringRef getLibcallFuncName() const {
     return TheDef->getValueAsString("LibCallFuncName");
   }
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index fc7db67120317a..acc06ac12606cf 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -459,15 +459,41 @@ const uint8_t RTLIB::RuntimeLibcallsInfo::RuntimeLibcallNameSizeTable[] = {
 
     for (const RuntimeLibcallImpl &LibCallImpl :
          Libcalls.getRuntimeLibcallImplDefList()) {
-      const RuntimeLibcall *Provides = LibCallImpl.getProvides();
       OS << "  ";
-      Provides->emitEnumEntry(OS);
+      if (const RuntimeLibcall *Provides = LibCallImpl.getProvides())
+        Provides->emitEnumEntry(OS);
+      else
+        OS << "RTLIB::UNKNOWN_LIBCALL";
       OS << ", // ";
       LibCallImpl.emitEnumEntry(OS);
       OS << '\n';
     }
 
     OS << "};\n\n";
+
+    OS << "RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::getLibcallFromImpl("
+          "RTLIB::LibcallImpl Impl) const {\n"
+          "  switch (Impl) {\n";
+    for (const RuntimeLibcallImpl &LibCallImpl :
+         Libcalls.getRuntimeLibcallImplDefList()) {
+      if (!LibCallImpl.isLongDouble())
+        continue;
+
+      OS << "  case ";
+      LibCallImpl.emitEnumEntry(OS);
+      OS << ":\n    return selectLongDoubleLibcall(";
+      LibCallImpl.getProvidesF80()->emitEnumEntry(OS);
+      OS << ", ";
+      LibCallImpl.getProvidesF128()->emitEnumEntry(OS);
+      OS << ", ";
+      LibCallImpl.getProvidesPPCF128()->emitEnumEntry(OS);
+      OS << ");\n";
+    }
+
+    OS << "  default:\n"
+          "    return ImplToLibcall[Impl];\n"
+          "  }\n"
+          "}\n\n";
   }
 
   emitNameMatchHashTable(OS, Table);
@@ -614,13 +640,11 @@ void RuntimeLibcallEmitter::emitPredicateGroups(
 
     // 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.
-    llvm::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());
-    });
+    // call); sort by the impl enum for a deterministic order.
+    llvm::sort(Funcs,
+               [](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) {
+                 return A->getEnumVal() < B->getEnumVal();
+               });
 
     OS << indent(IndentDepth + 2)
        << "static const RTLIB::LibcallImpl LibraryCalls";



More information about the llvm-branch-commits mailing list