[llvm] [LLVM] Move fp libcall selection into TableGen (PR #204029)

Joseph Huber via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 08:47:10 PDT 2026


https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/204029

>From 8b3763cd4792fb8e28dbde4b3ea85b4b7845f872 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Mon, 15 Jun 2026 16:37:54 -0500
Subject: [PATCH 1/3] [LLVM] Move libcall <-> intrinsic association into
 libcall tablegen

Summary:
Currently we maintain several different spaces that want to ask which
libcall an intrinsic / type value lowers to. This PR consolidates this
into tablegen by emitting floating point families. The intention is to
cover the common set of LLVM intrinsics which end up mapping to libcall
functions. This is done by updating the tablegen with the list of FP
libcalls, generating two functions (libcall -> intrinsic and the
reverse) and just calling these instead.

This resolves some outstanding TODOs. The main motivation is a follow-up
where we use this information to augment the LTO pass to more
intentionally extract symbols. I.e. if we see `llvm.sin.f64` we should
extract `sin` from an LTO library.
---
 .../include/llvm/CodeGen/RuntimeLibcallUtil.h |  68 +--
 llvm/include/llvm/IR/RuntimeLibcalls.h        |  18 +
 llvm/include/llvm/IR/RuntimeLibcalls.td       |  59 +++
 llvm/include/llvm/IR/RuntimeLibcallsImpl.td   |  11 +
 llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 147 ++-----
 .../SelectionDAG/LegalizeFloatTypes.cpp       | 394 ++++--------------
 llvm/lib/CodeGen/TargetLoweringBase.cpp       | 233 +----------
 llvm/lib/IR/RuntimeLibcalls.cpp               |   3 +
 ...timeLibcallEmitter-intrinsic-to-libcall.td |  55 +++
 llvm/unittests/IR/RuntimeLibcallsTest.cpp     |  63 +++
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 157 +++++++
 11 files changed, 488 insertions(+), 720 deletions(-)
 create mode 100644 llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td

diff --git a/llvm/include/llvm/CodeGen/RuntimeLibcallUtil.h b/llvm/include/llvm/CodeGen/RuntimeLibcallUtil.h
index 898d19d1fc292..2be7263cabdf0 100644
--- a/llvm/include/llvm/CodeGen/RuntimeLibcallUtil.h
+++ b/llvm/include/llvm/CodeGen/RuntimeLibcallUtil.h
@@ -92,69 +92,11 @@ LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT);
 /// UNKNOWN_LIBCALL if there is none.
 LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT);
 
-/// getPOWI - Return the POWI_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getPOWI(EVT RetVT);
-
-/// getPOW - Return the POW_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getPOW(EVT RetVT);
-
-/// getCBRT - Return the CBRT_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getCBRT(EVT RetVT);
-
-/// getLDEXP - Return the LDEXP_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getLDEXP(EVT RetVT);
-
-/// getFREXP - Return the FREXP_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getFREXP(EVT RetVT);
-
-/// Return the SIN_* value for the given types, or UNKNOWN_LIBCALL if there is
-/// none.
-LLVM_ABI Libcall getSIN(EVT RetVT);
-
-/// Return the COS_* value for the given types, or UNKNOWN_LIBCALL if there is
-/// none.
-LLVM_ABI Libcall getCOS(EVT RetVT);
-
-/// getSINCOS - Return the SINCOS_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getSINCOS(EVT RetVT);
-
-/// getSINCOSPI - Return the SINCOSPI_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getSINCOSPI(EVT RetVT);
-
-/// Return the SINCOS_STRET_ value for the given types, or UNKNOWN_LIBCALL if
-/// there is none.
-LLVM_ABI Libcall getSINCOS_STRET(EVT RetVT);
-
-/// getMODF - Return the MODF_* value for the given types, or
-/// UNKNOWN_LIBCALL if there is none.
-LLVM_ABI Libcall getMODF(EVT VT);
-
-/// \return the REM_* value for the given types, or UNKNOWN_LIBCALL if there is
-/// none.
-LLVM_ABI Libcall getREM(EVT VT);
-
-/// \return the LROUND_* value for the given types, or UNKNOWN_LIBCALL if there
-/// is none.
-LLVM_ABI Libcall getLROUND(EVT VT);
-
-/// \return the LLROUND_* value for the given types, or UNKNOWN_LIBCALL if there
-/// is none.
-LLVM_ABI Libcall getLLROUND(EVT VT);
-
-/// \return the LRINT_* value for the given types, or UNKNOWN_LIBCALL if there
-/// is none.
-LLVM_ABI Libcall getLRINT(EVT RetVT);
-
-/// \return the LLRINT_* value for the given types, or UNKNOWN_LIBCALL if there
-/// is none.
-LLVM_ABI Libcall getLLRINT(EVT RetVT);
+/// The floating-point selectors get<OP>(EVT) return the <OP>_* libcall for the
+/// given type, or UNKNOWN_LIBCALL. Generated from the RuntimeLibcallFamily
+/// table in RuntimeLibcalls.td.
+#define GET_RUNTIME_LIBCALL_FP_SELECTOR_DECLS
+#include "llvm/IR/RuntimeLibcalls.inc"
 
 /// Return the SYNC_FETCH_AND_* value for the given opcode and type, or
 /// UNKNOWN_LIBCALL if there is none.
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 78b75f3e81c3b..86fdd5776176e 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -47,6 +47,11 @@ template <> struct enum_iteration_traits<RTLIB::LibcallImpl> {
 };
 
 class LibcallLoweringInfo;
+class Type;
+
+namespace Intrinsic {
+typedef unsigned ID;
+}
 
 namespace RTLIB {
 
@@ -117,6 +122,19 @@ struct RuntimeLibcallsInfo {
     return ImplToLibcall[Impl];
   }
 
+  /// Return the runtime libcall that the floating-point math intrinsic \p ID
+  /// operating on type \p Ty may be lowered to, or RTLIB::UNKNOWN_LIBCALL if
+  /// there is no such mapping.
+  ///
+  /// \p Ty must be the floating-point operand type, which is not always the
+  /// intrinsic's primary/overloaded type. E.g. lround/llround/lrint/llrint are
+  /// overloaded on the integer result, powi on the integer exponent, and
+  /// frexp/modf/sincos return an aggregate. For these, pass the floating-point
+  /// argument type (e.g. the type of operand 0), not the intrinsic's return
+  /// type.
+  LLVM_ABI static RTLIB::Libcall getLibcallForIntrinsic(Intrinsic::ID ID,
+                                                        Type *Ty);
+
   unsigned getNumAvailableLibcallImpls() const {
     return AvailableLibcallImpls.count();
   }
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index b0d9663cca395..67d89da24266b 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -304,6 +304,65 @@ foreach FPTy = ["F32", "F64", "F80", "F128", "PPCF128"] in {
   def TGAMMA_#FPTy : RuntimeLibcall;
 }
 
+// Floating-point libcall families. Each generates the backend selector
+// RTLIB::get<base>(EVT) and, for families with an intrinsic, the IR-level
+// getLibcallForIntrinsic() mapping. See RuntimeLibcallFamily.
+defvar Vec4F32_2F64 = ["V4F32", "V2F64", "NXV4F32", "NXV2F64"];
+
+class StrictFP<string base> {
+  list<string> ret = [base, "experimental_constrained_"#base];
+}
+
+def : RuntimeLibcallFamily<"POWI", StrictFP<"powi">.ret>;
+def : RuntimeLibcallFamily<"POW", StrictFP<"pow">.ret, Vec4F32_2F64>;
+def : RuntimeLibcallFamily<"CBRT", [], Vec4F32_2F64>;
+def : RuntimeLibcallFamily<"LDEXP", StrictFP<"ldexp">.ret>;
+def : RuntimeLibcallFamily<"FREXP", ["frexp"]>;
+def : RuntimeLibcallFamily<"SIN", StrictFP<"sin">.ret>;
+def : RuntimeLibcallFamily<"COS", StrictFP<"cos">.ret>;
+def : RuntimeLibcallFamily<"SINCOS", ["sincos"],
+    ["V4F32", "V8F32", "V16F32", "V2F64", "V4F64", "V8F64", "NXV4F32",
+     "NXV2F64"]>;
+def : RuntimeLibcallFamily<"SINCOSPI", ["sincospi"], Vec4F32_2F64>;
+def : RuntimeLibcallFamily<"SINCOS_STRET">;
+def : RuntimeLibcallFamily<"MODF", ["modf"], Vec4F32_2F64>;
+def : RuntimeLibcallFamily<"REM", [], Vec4F32_2F64>;
+def : RuntimeLibcallFamily<"LROUND", StrictFP<"lround">.ret>;
+def : RuntimeLibcallFamily<"LLROUND", StrictFP<"llround">.ret>;
+def : RuntimeLibcallFamily<"LRINT", StrictFP<"lrint">.ret>;
+def : RuntimeLibcallFamily<"LLRINT", StrictFP<"llrint">.ret>;
+
+def : RuntimeLibcallFamily<"SQRT", StrictFP<"sqrt">.ret>;
+def : RuntimeLibcallFamily<"FMA", StrictFP<"fma">.ret>;
+def : RuntimeLibcallFamily<"TAN", StrictFP<"tan">.ret>;
+def : RuntimeLibcallFamily<"ASIN", StrictFP<"asin">.ret>;
+def : RuntimeLibcallFamily<"ACOS", StrictFP<"acos">.ret>;
+def : RuntimeLibcallFamily<"ATAN", StrictFP<"atan">.ret>;
+def : RuntimeLibcallFamily<"ATAN2", StrictFP<"atan2">.ret>;
+def : RuntimeLibcallFamily<"SINH", StrictFP<"sinh">.ret>;
+def : RuntimeLibcallFamily<"COSH", StrictFP<"cosh">.ret>;
+def : RuntimeLibcallFamily<"TANH", StrictFP<"tanh">.ret>;
+def : RuntimeLibcallFamily<"LOG", StrictFP<"log">.ret>;
+def : RuntimeLibcallFamily<"LOG2", StrictFP<"log2">.ret>;
+def : RuntimeLibcallFamily<"LOG10", StrictFP<"log10">.ret>;
+def : RuntimeLibcallFamily<"EXP", StrictFP<"exp">.ret>;
+def : RuntimeLibcallFamily<"EXP2", StrictFP<"exp2">.ret>;
+def : RuntimeLibcallFamily<"EXP10", ["exp10"]>;
+def : RuntimeLibcallFamily<"TRUNC", StrictFP<"trunc">.ret>;
+def : RuntimeLibcallFamily<"FLOOR", StrictFP<"floor">.ret>;
+def : RuntimeLibcallFamily<"CEIL", StrictFP<"ceil">.ret>;
+def : RuntimeLibcallFamily<"RINT", StrictFP<"rint">.ret>;
+def : RuntimeLibcallFamily<"NEARBYINT", StrictFP<"nearbyint">.ret>;
+def : RuntimeLibcallFamily<"ROUND", StrictFP<"round">.ret>;
+def : RuntimeLibcallFamily<"ROUNDEVEN", StrictFP<"roundeven">.ret>;
+def : RuntimeLibcallFamily<"FMIN", StrictFP<"minnum">.ret>;
+def : RuntimeLibcallFamily<"FMAX", StrictFP<"maxnum">.ret>;
+def : RuntimeLibcallFamily<"FMINIMUM", StrictFP<"minimum">.ret>;
+def : RuntimeLibcallFamily<"FMAXIMUM", StrictFP<"maximum">.ret>;
+def : RuntimeLibcallFamily<"FMINIMUM_NUM", ["minimumnum"]>;
+def : RuntimeLibcallFamily<"FMAXIMUM_NUM", ["maximumnum"]>;
+def : RuntimeLibcallFamily<"COPYSIGN", ["copysign"]>;
+
 defvar F32VectorSuffixes = ["V2F32", "V4F32", "V8F32", "V16F32", "NXV4F32"];
 defvar F64VectorSuffixes = ["V2F64", "V4F64", "V8F64", "NXV2F64"];
 
diff --git a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
index 11958be8cf05f..1c49959285f08 100644
--- a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
+++ b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
@@ -80,6 +80,17 @@ class RuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME> {
   bit IsDefault = false;
 }
 
+/// 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>`
+/// (e.g. SIN_F64).
+class RuntimeLibcallFamily<string base, list<string> intrinsics = [],
+                           list<string> vectorSuffixes = []> {
+  string LibcallBase = base;
+  list<string> Intrinsics = intrinsics;
+  list<string> VectorSuffixes = vectorSuffixes;
+}
+
 class LibcallImpls<dag funcList,
                    RuntimeLibcallAvailability Pred = AlwaysAvailable> {
   // Function of the triple where this applies
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 1903ea89e4af8..a7fb6d22c0484 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -136,11 +136,6 @@ class SelectionDAGLegalize {
 
   void ExpandFPLibCall(SDNode *Node, RTLIB::Libcall LC,
                        SmallVectorImpl<SDValue> &Results);
-  void ExpandFPLibCall(SDNode *Node, RTLIB::Libcall Call_F32,
-                       RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80,
-                       RTLIB::Libcall Call_F128,
-                       RTLIB::Libcall Call_PPCF128,
-                       SmallVectorImpl<SDValue> &Results);
 
   void
   ExpandFastFPLibCall(SDNode *Node, bool IsFast,
@@ -2230,19 +2225,6 @@ void SelectionDAGLegalize::ExpandFPLibCall(SDNode* Node,
 }
 
 /// Expand the node to a libcall based on the result type.
-void SelectionDAGLegalize::ExpandFPLibCall(SDNode* Node,
-                                           RTLIB::Libcall Call_F32,
-                                           RTLIB::Libcall Call_F64,
-                                           RTLIB::Libcall Call_F80,
-                                           RTLIB::Libcall Call_F128,
-                                           RTLIB::Libcall Call_PPCF128,
-                                           SmallVectorImpl<SDValue> &Results) {
-  RTLIB::Libcall LC = RTLIB::getFPLibCall(Node->getSimpleValueType(0),
-                                          Call_F32, Call_F64, Call_F80,
-                                          Call_F128, Call_PPCF128);
-  ExpandFPLibCall(Node, LC, Results);
-}
-
 void SelectionDAGLegalize::ExpandFastFPLibCall(
     SDNode *Node, bool IsFast,
     std::pair<RTLIB::Libcall, RTLIB::Libcall> Call_F32,
@@ -4837,28 +4819,22 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
   }
   case ISD::FMINNUM:
   case ISD::STRICT_FMINNUM:
-    ExpandFPLibCall(Node, RTLIB::FMIN_F32, RTLIB::FMIN_F64,
-                    RTLIB::FMIN_F80, RTLIB::FMIN_F128,
-                    RTLIB::FMIN_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getFMIN(Node->getSimpleValueType(0)), Results);
     break;
   // FIXME: We do not have libcalls for FMAXIMUM and FMINIMUM. So, we cannot use
   // libcall legalization for these nodes, but there is no default expasion for
   // these nodes either (see PR63267 for example).
   case ISD::FMAXNUM:
   case ISD::STRICT_FMAXNUM:
-    ExpandFPLibCall(Node, RTLIB::FMAX_F32, RTLIB::FMAX_F64,
-                    RTLIB::FMAX_F80, RTLIB::FMAX_F128,
-                    RTLIB::FMAX_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getFMAX(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FMINIMUMNUM:
-    ExpandFPLibCall(Node, RTLIB::FMINIMUM_NUM_F32, RTLIB::FMINIMUM_NUM_F64,
-                    RTLIB::FMINIMUM_NUM_F80, RTLIB::FMINIMUM_NUM_F128,
-                    RTLIB::FMINIMUM_NUM_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getFMINIMUM_NUM(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FMAXIMUMNUM:
-    ExpandFPLibCall(Node, RTLIB::FMAXIMUM_NUM_F32, RTLIB::FMAXIMUM_NUM_F64,
-                    RTLIB::FMAXIMUM_NUM_F80, RTLIB::FMAXIMUM_NUM_F128,
-                    RTLIB::FMAXIMUM_NUM_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getFMAXIMUM_NUM(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FSQRT:
   case ISD::STRICT_FSQRT: {
@@ -4874,61 +4850,48 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
     break;
   }
   case ISD::FCBRT:
-    ExpandFPLibCall(Node, RTLIB::CBRT_F32, RTLIB::CBRT_F64,
-                    RTLIB::CBRT_F80, RTLIB::CBRT_F128,
-                    RTLIB::CBRT_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getCBRT(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FSIN:
   case ISD::STRICT_FSIN:
-    ExpandFPLibCall(Node, RTLIB::SIN_F32, RTLIB::SIN_F64,
-                    RTLIB::SIN_F80, RTLIB::SIN_F128,
-                    RTLIB::SIN_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getSIN(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FCOS:
   case ISD::STRICT_FCOS:
-    ExpandFPLibCall(Node, RTLIB::COS_F32, RTLIB::COS_F64,
-                    RTLIB::COS_F80, RTLIB::COS_F128,
-                    RTLIB::COS_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getCOS(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FTAN:
   case ISD::STRICT_FTAN:
-    ExpandFPLibCall(Node, RTLIB::TAN_F32, RTLIB::TAN_F64, RTLIB::TAN_F80,
-                    RTLIB::TAN_F128, RTLIB::TAN_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getTAN(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FASIN:
   case ISD::STRICT_FASIN:
-    ExpandFPLibCall(Node, RTLIB::ASIN_F32, RTLIB::ASIN_F64, RTLIB::ASIN_F80,
-                    RTLIB::ASIN_F128, RTLIB::ASIN_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getASIN(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FACOS:
   case ISD::STRICT_FACOS:
-    ExpandFPLibCall(Node, RTLIB::ACOS_F32, RTLIB::ACOS_F64, RTLIB::ACOS_F80,
-                    RTLIB::ACOS_F128, RTLIB::ACOS_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getACOS(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FATAN:
   case ISD::STRICT_FATAN:
-    ExpandFPLibCall(Node, RTLIB::ATAN_F32, RTLIB::ATAN_F64, RTLIB::ATAN_F80,
-                    RTLIB::ATAN_F128, RTLIB::ATAN_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getATAN(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FATAN2:
   case ISD::STRICT_FATAN2:
-    ExpandFPLibCall(Node, RTLIB::ATAN2_F32, RTLIB::ATAN2_F64, RTLIB::ATAN2_F80,
-                    RTLIB::ATAN2_F128, RTLIB::ATAN2_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getATAN2(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FSINH:
   case ISD::STRICT_FSINH:
-    ExpandFPLibCall(Node, RTLIB::SINH_F32, RTLIB::SINH_F64, RTLIB::SINH_F80,
-                    RTLIB::SINH_F128, RTLIB::SINH_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getSINH(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FCOSH:
   case ISD::STRICT_FCOSH:
-    ExpandFPLibCall(Node, RTLIB::COSH_F32, RTLIB::COSH_F64, RTLIB::COSH_F80,
-                    RTLIB::COSH_F128, RTLIB::COSH_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getCOSH(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FTANH:
   case ISD::STRICT_FTANH:
-    ExpandFPLibCall(Node, RTLIB::TANH_F32, RTLIB::TANH_F64, RTLIB::TANH_F80,
-                    RTLIB::TANH_F128, RTLIB::TANH_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getTANH(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FSINCOS:
   case ISD::FSINCOSPI: {
@@ -4961,85 +4924,66 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
   }
   case ISD::FLOG:
   case ISD::STRICT_FLOG:
-    ExpandFPLibCall(Node, RTLIB::LOG_F32, RTLIB::LOG_F64, RTLIB::LOG_F80,
-                    RTLIB::LOG_F128, RTLIB::LOG_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getLOG(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FLOG2:
   case ISD::STRICT_FLOG2:
-    ExpandFPLibCall(Node, RTLIB::LOG2_F32, RTLIB::LOG2_F64, RTLIB::LOG2_F80,
-                    RTLIB::LOG2_F128, RTLIB::LOG2_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getLOG2(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FLOG10:
   case ISD::STRICT_FLOG10:
-    ExpandFPLibCall(Node, RTLIB::LOG10_F32, RTLIB::LOG10_F64, RTLIB::LOG10_F80,
-                    RTLIB::LOG10_F128, RTLIB::LOG10_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getLOG10(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FEXP:
   case ISD::STRICT_FEXP:
-    ExpandFPLibCall(Node, RTLIB::EXP_F32, RTLIB::EXP_F64, RTLIB::EXP_F80,
-                    RTLIB::EXP_F128, RTLIB::EXP_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getEXP(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FEXP2:
   case ISD::STRICT_FEXP2:
-    ExpandFPLibCall(Node, RTLIB::EXP2_F32, RTLIB::EXP2_F64, RTLIB::EXP2_F80,
-                    RTLIB::EXP2_F128, RTLIB::EXP2_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getEXP2(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FEXP10:
-    ExpandFPLibCall(Node, RTLIB::EXP10_F32, RTLIB::EXP10_F64, RTLIB::EXP10_F80,
-                    RTLIB::EXP10_F128, RTLIB::EXP10_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getEXP10(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FTRUNC:
   case ISD::STRICT_FTRUNC:
-    ExpandFPLibCall(Node, RTLIB::TRUNC_F32, RTLIB::TRUNC_F64,
-                    RTLIB::TRUNC_F80, RTLIB::TRUNC_F128,
-                    RTLIB::TRUNC_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getTRUNC(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FFLOOR:
   case ISD::STRICT_FFLOOR:
-    ExpandFPLibCall(Node, RTLIB::FLOOR_F32, RTLIB::FLOOR_F64,
-                    RTLIB::FLOOR_F80, RTLIB::FLOOR_F128,
-                    RTLIB::FLOOR_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getFLOOR(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FCEIL:
   case ISD::STRICT_FCEIL:
-    ExpandFPLibCall(Node, RTLIB::CEIL_F32, RTLIB::CEIL_F64,
-                    RTLIB::CEIL_F80, RTLIB::CEIL_F128,
-                    RTLIB::CEIL_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getCEIL(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FRINT:
   case ISD::STRICT_FRINT:
-    ExpandFPLibCall(Node, RTLIB::RINT_F32, RTLIB::RINT_F64,
-                    RTLIB::RINT_F80, RTLIB::RINT_F128,
-                    RTLIB::RINT_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getRINT(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FNEARBYINT:
   case ISD::STRICT_FNEARBYINT:
-    ExpandFPLibCall(Node, RTLIB::NEARBYINT_F32,
-                    RTLIB::NEARBYINT_F64,
-                    RTLIB::NEARBYINT_F80,
-                    RTLIB::NEARBYINT_F128,
-                    RTLIB::NEARBYINT_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getNEARBYINT(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FROUND:
   case ISD::STRICT_FROUND:
-    ExpandFPLibCall(Node, RTLIB::ROUND_F32,
-                    RTLIB::ROUND_F64,
-                    RTLIB::ROUND_F80,
-                    RTLIB::ROUND_F128,
-                    RTLIB::ROUND_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getROUND(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FROUNDEVEN:
   case ISD::STRICT_FROUNDEVEN:
-    ExpandFPLibCall(Node, RTLIB::ROUNDEVEN_F32,
-                    RTLIB::ROUNDEVEN_F64,
-                    RTLIB::ROUNDEVEN_F80,
-                    RTLIB::ROUNDEVEN_F128,
-                    RTLIB::ROUNDEVEN_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getROUNDEVEN(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FLDEXP:
   case ISD::STRICT_FLDEXP:
-    ExpandFPLibCall(Node, RTLIB::LDEXP_F32, RTLIB::LDEXP_F64, RTLIB::LDEXP_F80,
-                    RTLIB::LDEXP_F128, RTLIB::LDEXP_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getLDEXP(Node->getSimpleValueType(0)),
+                    Results);
     break;
   case ISD::FMODF:
   case ISD::FFREXP: {
@@ -5095,8 +5039,7 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
   }
   case ISD::FPOW:
   case ISD::STRICT_FPOW:
-    ExpandFPLibCall(Node, RTLIB::POW_F32, RTLIB::POW_F64, RTLIB::POW_F80,
-                    RTLIB::POW_F128, RTLIB::POW_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getPOW(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::LROUND:
   case ISD::STRICT_LROUND:
@@ -5138,15 +5081,11 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
   }
   case ISD::FREM:
   case ISD::STRICT_FREM:
-    ExpandFPLibCall(Node, RTLIB::REM_F32, RTLIB::REM_F64,
-                    RTLIB::REM_F80, RTLIB::REM_F128,
-                    RTLIB::REM_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getREM(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FMA:
   case ISD::STRICT_FMA:
-    ExpandFPLibCall(Node, RTLIB::FMA_F32, RTLIB::FMA_F64,
-                    RTLIB::FMA_F80, RTLIB::FMA_F128,
-                    RTLIB::FMA_PPCF128, Results);
+    ExpandFPLibCall(Node, RTLIB::getFMA(Node->getSimpleValueType(0)), Results);
     break;
   case ISD::FADD:
   case ISD::STRICT_FADD: {
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index d0a29b5365daa..727ca1013f48a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -341,51 +341,29 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FCANONICALIZE(SDNode *N) {
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMINNUM(SDNode *N) {
   if (SDValue SelCC = TLI.createSelectForFMINNUM_FMAXNUM(N, DAG))
     return SoftenFloatRes_SELECT_CC(SelCC.getNode());
-  return SoftenFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                               RTLIB::FMIN_F32,
-                                               RTLIB::FMIN_F64,
-                                               RTLIB::FMIN_F80,
-                                               RTLIB::FMIN_F128,
-                                               RTLIB::FMIN_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getFMIN(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMAXNUM(SDNode *N) {
   if (SDValue SelCC = TLI.createSelectForFMINNUM_FMAXNUM(N, DAG))
     return SoftenFloatRes_SELECT_CC(SelCC.getNode());
-  return SoftenFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                               RTLIB::FMAX_F32,
-                                               RTLIB::FMAX_F64,
-                                               RTLIB::FMAX_F80,
-                                               RTLIB::FMAX_F128,
-                                               RTLIB::FMAX_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getFMAX(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMINIMUMNUM(SDNode *N) {
-  return SoftenFloatRes_Binary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::FMINIMUM_NUM_F32,
-                      RTLIB::FMINIMUM_NUM_F64, RTLIB::FMINIMUM_NUM_F80,
-                      RTLIB::FMINIMUM_NUM_F128, RTLIB::FMINIMUM_NUM_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getFMINIMUM_NUM(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMAXIMUMNUM(SDNode *N) {
-  return SoftenFloatRes_Binary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::FMAXIMUM_NUM_F32,
-                      RTLIB::FMAXIMUM_NUM_F64, RTLIB::FMAXIMUM_NUM_F80,
-                      RTLIB::FMAXIMUM_NUM_F128, RTLIB::FMAXIMUM_NUM_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getFMAXIMUM_NUM(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMINIMUM(SDNode *N) {
-  return SoftenFloatRes_Binary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::FMINIMUM_F32,
-                      RTLIB::FMINIMUM_F64, RTLIB::FMINIMUM_F80,
-                      RTLIB::FMINIMUM_F128, RTLIB::FMINIMUM_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getFMINIMUM(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMAXIMUM(SDNode *N) {
-  return SoftenFloatRes_Binary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::FMAXIMUM_F32,
-                      RTLIB::FMAXIMUM_F64, RTLIB::FMAXIMUM_F80,
-                      RTLIB::FMAXIMUM_F128, RTLIB::FMAXIMUM_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getFMAXIMUM(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FADD(SDNode *N) {
@@ -398,46 +376,27 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FADD(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FACOS(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::ACOS_F32, RTLIB::ACOS_F64,
-                      RTLIB::ACOS_F80, RTLIB::ACOS_F128, RTLIB::ACOS_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getACOS(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FASIN(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::ASIN_F32, RTLIB::ASIN_F64,
-                      RTLIB::ASIN_F80, RTLIB::ASIN_F128, RTLIB::ASIN_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getASIN(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FATAN(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::ATAN_F32, RTLIB::ATAN_F64,
-                      RTLIB::ATAN_F80, RTLIB::ATAN_F128, RTLIB::ATAN_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getATAN(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FATAN2(SDNode *N) {
-  return SoftenFloatRes_Binary(
-      N,
-      GetFPLibCall(N->getValueType(0), RTLIB::ATAN2_F32, RTLIB::ATAN2_F64,
-                   RTLIB::ATAN2_F80, RTLIB::ATAN2_F128, RTLIB::ATAN2_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getATAN2(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FCBRT(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                           RTLIB::CBRT_F32,
-                                           RTLIB::CBRT_F64,
-                                           RTLIB::CBRT_F80,
-                                           RTLIB::CBRT_F128,
-                                           RTLIB::CBRT_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getCBRT(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FCEIL(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::CEIL_F32,
-                                              RTLIB::CEIL_F64,
-                                              RTLIB::CEIL_F80,
-                                              RTLIB::CEIL_F128,
-                                              RTLIB::CEIL_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getCEIL(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FCOPYSIGN(SDNode *N) {
@@ -489,18 +448,11 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FCOPYSIGN(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FCOS(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::COS_F32,
-                                              RTLIB::COS_F64,
-                                              RTLIB::COS_F80,
-                                              RTLIB::COS_F128,
-                                              RTLIB::COS_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getCOS(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FCOSH(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::COSH_F32, RTLIB::COSH_F64,
-                      RTLIB::COSH_F80, RTLIB::COSH_F128, RTLIB::COSH_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getCOSH(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FDIV(SDNode *N) {
@@ -513,64 +465,31 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FDIV(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FEXP(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::EXP_F32,
-                                              RTLIB::EXP_F64,
-                                              RTLIB::EXP_F80,
-                                              RTLIB::EXP_F128,
-                                              RTLIB::EXP_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getEXP(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FEXP2(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::EXP2_F32,
-                                              RTLIB::EXP2_F64,
-                                              RTLIB::EXP2_F80,
-                                              RTLIB::EXP2_F128,
-                                              RTLIB::EXP2_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getEXP2(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FEXP10(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N,
-      GetFPLibCall(N->getValueType(0), RTLIB::EXP10_F32, RTLIB::EXP10_F64,
-                   RTLIB::EXP10_F80, RTLIB::EXP10_F128, RTLIB::EXP10_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getEXP10(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FFLOOR(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::FLOOR_F32,
-                                              RTLIB::FLOOR_F64,
-                                              RTLIB::FLOOR_F80,
-                                              RTLIB::FLOOR_F128,
-                                              RTLIB::FLOOR_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getFLOOR(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FLOG(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::LOG_F32,
-                                              RTLIB::LOG_F64,
-                                              RTLIB::LOG_F80,
-                                              RTLIB::LOG_F128,
-                                              RTLIB::LOG_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getLOG(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FLOG2(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::LOG2_F32,
-                                              RTLIB::LOG2_F64,
-                                              RTLIB::LOG2_F80,
-                                              RTLIB::LOG2_F128,
-                                              RTLIB::LOG2_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getLOG2(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FLOG10(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::LOG10_F32,
-                                              RTLIB::LOG10_F64,
-                                              RTLIB::LOG10_F80,
-                                              RTLIB::LOG10_F128,
-                                              RTLIB::LOG10_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getLOG10(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FMA(SDNode *N) {
@@ -586,14 +505,9 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FMA(SDNode *N) {
                    N->getOperand(1 + Offset).getValueType(),
                    N->getOperand(2 + Offset).getValueType() };
   CallOptions.setTypeListBeforeSoften(OpsVT, N->getValueType(0));
-  std::pair<SDValue, SDValue> Tmp = TLI.makeLibCall(DAG,
-                                                    GetFPLibCall(N->getValueType(0),
-                                                                 RTLIB::FMA_F32,
-                                                                 RTLIB::FMA_F64,
-                                                                 RTLIB::FMA_F80,
-                                                                 RTLIB::FMA_F128,
-                                                                 RTLIB::FMA_PPCF128),
-                         NVT, Ops, CallOptions, SDLoc(N), Chain);
+  std::pair<SDValue, SDValue> Tmp =
+      TLI.makeLibCall(DAG, RTLIB::getFMA(N->getValueType(0)), NVT, Ops,
+                      CallOptions, SDLoc(N), Chain);
   if (IsStrict)
     ReplaceValueWith(SDValue(N, 1), Tmp.second);
   return Tmp.first;
@@ -609,12 +523,7 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FMUL(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FNEARBYINT(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::NEARBYINT_F32,
-                                              RTLIB::NEARBYINT_F64,
-                                              RTLIB::NEARBYINT_F80,
-                                              RTLIB::NEARBYINT_F128,
-                                              RTLIB::NEARBYINT_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getNEARBYINT(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FNEG(SDNode *N) {
@@ -916,63 +825,31 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FMODF(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FREM(SDNode *N) {
-  return SoftenFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                               RTLIB::REM_F32,
-                                               RTLIB::REM_F64,
-                                               RTLIB::REM_F80,
-                                               RTLIB::REM_F128,
-                                               RTLIB::REM_PPCF128));
+  return SoftenFloatRes_Binary(N, RTLIB::getREM(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FRINT(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::RINT_F32,
-                                              RTLIB::RINT_F64,
-                                              RTLIB::RINT_F80,
-                                              RTLIB::RINT_F128,
-                                              RTLIB::RINT_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getRINT(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FROUND(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::ROUND_F32,
-                                              RTLIB::ROUND_F64,
-                                              RTLIB::ROUND_F80,
-                                              RTLIB::ROUND_F128,
-                                              RTLIB::ROUND_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getROUND(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FROUNDEVEN(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::ROUNDEVEN_F32,
-                                              RTLIB::ROUNDEVEN_F64,
-                                              RTLIB::ROUNDEVEN_F80,
-                                              RTLIB::ROUNDEVEN_F128,
-                                              RTLIB::ROUNDEVEN_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getROUNDEVEN(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FSIN(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::SIN_F32,
-                                              RTLIB::SIN_F64,
-                                              RTLIB::SIN_F80,
-                                              RTLIB::SIN_F128,
-                                              RTLIB::SIN_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getSIN(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FSINH(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::SINH_F32, RTLIB::SINH_F64,
-                      RTLIB::SINH_F80, RTLIB::SINH_F128, RTLIB::SINH_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getSINH(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FSQRT(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::SQRT_F32,
-                                              RTLIB::SQRT_F64,
-                                              RTLIB::SQRT_F80,
-                                              RTLIB::SQRT_F128,
-                                              RTLIB::SQRT_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getSQRT(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FSUB(SDNode *N) {
@@ -985,24 +862,15 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FSUB(SDNode *N) {
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FTAN(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::TAN_F32, RTLIB::TAN_F64,
-                      RTLIB::TAN_F80, RTLIB::TAN_F128, RTLIB::TAN_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getTAN(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FTANH(SDNode *N) {
-  return SoftenFloatRes_Unary(
-      N, GetFPLibCall(N->getValueType(0), RTLIB::TANH_F32, RTLIB::TANH_F64,
-                      RTLIB::TANH_F80, RTLIB::TANH_F128, RTLIB::TANH_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getTANH(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_FTRUNC(SDNode *N) {
-  return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                              RTLIB::TRUNC_F32,
-                                              RTLIB::TRUNC_F64,
-                                              RTLIB::TRUNC_F80,
-                                              RTLIB::TRUNC_F128,
-                                              RTLIB::TRUNC_PPCF128));
+  return SoftenFloatRes_Unary(N, RTLIB::getTRUNC(N->getValueType(0)));
 }
 
 SDValue DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) {
@@ -1774,38 +1642,22 @@ void DAGTypeLegalizer::ExpandFloatRes_FABS(SDNode *N, SDValue &Lo,
 
 void DAGTypeLegalizer::ExpandFloatRes_FMINNUM(SDNode *N, SDValue &Lo,
                                               SDValue &Hi) {
-  ExpandFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::FMIN_F32, RTLIB::FMIN_F64,
-                                       RTLIB::FMIN_F80, RTLIB::FMIN_F128,
-                                       RTLIB::FMIN_PPCF128), Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getFMIN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FMAXNUM(SDNode *N, SDValue &Lo,
                                               SDValue &Hi) {
-  ExpandFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                        RTLIB::FMAX_F32, RTLIB::FMAX_F64,
-                                        RTLIB::FMAX_F80, RTLIB::FMAX_F128,
-                                        RTLIB::FMAX_PPCF128), Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getFMAX(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FMINIMUMNUM(SDNode *N, SDValue &Lo,
                                                   SDValue &Hi) {
-  ExpandFloatRes_Binary(
-      N,
-      GetFPLibCall(N->getValueType(0), RTLIB::FMINIMUM_NUM_F32,
-                   RTLIB::FMINIMUM_NUM_F64, RTLIB::FMINIMUM_NUM_F80,
-                   RTLIB::FMINIMUM_NUM_F128, RTLIB::FMINIMUM_NUM_PPCF128),
-      Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getFMINIMUM_NUM(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FMAXIMUMNUM(SDNode *N, SDValue &Lo,
                                                   SDValue &Hi) {
-  ExpandFloatRes_Binary(
-      N,
-      GetFPLibCall(N->getValueType(0), RTLIB::FMAXIMUM_NUM_F32,
-                   RTLIB::FMAXIMUM_NUM_F64, RTLIB::FMAXIMUM_NUM_F80,
-                   RTLIB::FMAXIMUM_NUM_F128, RTLIB::FMAXIMUM_NUM_PPCF128),
-      Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getFMAXIMUM_NUM(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FADD(SDNode *N, SDValue &Lo,
@@ -1818,81 +1670,47 @@ void DAGTypeLegalizer::ExpandFloatRes_FADD(SDNode *N, SDValue &Lo,
 
 void DAGTypeLegalizer::ExpandFloatRes_FACOS(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::ACOS_F32,
-                                    RTLIB::ACOS_F64, RTLIB::ACOS_F80,
-                                    RTLIB::ACOS_F128, RTLIB::ACOS_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getACOS(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FASIN(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::ASIN_F32,
-                                    RTLIB::ASIN_F64, RTLIB::ASIN_F80,
-                                    RTLIB::ASIN_F128, RTLIB::ASIN_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getASIN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FATAN(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::ATAN_F32,
-                                    RTLIB::ATAN_F64, RTLIB::ATAN_F80,
-                                    RTLIB::ATAN_F128, RTLIB::ATAN_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getATAN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FATAN2(SDNode *N, SDValue &Lo,
                                              SDValue &Hi) {
-  ExpandFloatRes_Binary(N,
-                        GetFPLibCall(N->getValueType(0), RTLIB::ATAN2_F32,
-                                     RTLIB::ATAN2_F64, RTLIB::ATAN2_F80,
-                                     RTLIB::ATAN2_F128, RTLIB::ATAN2_PPCF128),
-                        Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getATAN2(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FCBRT(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0), RTLIB::CBRT_F32,
-                                       RTLIB::CBRT_F64, RTLIB::CBRT_F80,
-                                       RTLIB::CBRT_F128,
-                                       RTLIB::CBRT_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getCBRT(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FCEIL(SDNode *N,
                                             SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::CEIL_F32, RTLIB::CEIL_F64,
-                                       RTLIB::CEIL_F80, RTLIB::CEIL_F128,
-                                       RTLIB::CEIL_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getCEIL(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FCOPYSIGN(SDNode *N,
                                                 SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                        RTLIB::COPYSIGN_F32,
-                                        RTLIB::COPYSIGN_F64,
-                                        RTLIB::COPYSIGN_F80,
-                                        RTLIB::COPYSIGN_F128,
-                                        RTLIB::COPYSIGN_PPCF128), Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getCOPYSIGN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FCOS(SDNode *N,
                                            SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::COS_F32, RTLIB::COS_F64,
-                                       RTLIB::COS_F80, RTLIB::COS_F128,
-                                       RTLIB::COS_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getCOS(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FCOSH(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::COSH_F32,
-                                    RTLIB::COSH_F64, RTLIB::COSH_F80,
-                                    RTLIB::COSH_F128, RTLIB::COSH_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getCOSH(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FDIV(SDNode *N, SDValue &Lo,
@@ -1907,59 +1725,37 @@ void DAGTypeLegalizer::ExpandFloatRes_FDIV(SDNode *N, SDValue &Lo,
 
 void DAGTypeLegalizer::ExpandFloatRes_FEXP(SDNode *N,
                                            SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::EXP_F32, RTLIB::EXP_F64,
-                                       RTLIB::EXP_F80, RTLIB::EXP_F128,
-                                       RTLIB::EXP_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getEXP(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FEXP2(SDNode *N,
                                             SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::EXP2_F32, RTLIB::EXP2_F64,
-                                       RTLIB::EXP2_F80, RTLIB::EXP2_F128,
-                                       RTLIB::EXP2_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getEXP2(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FEXP10(SDNode *N, SDValue &Lo,
                                              SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::EXP10_F32,
-                                    RTLIB::EXP10_F64, RTLIB::EXP10_F80,
-                                    RTLIB::EXP10_F128, RTLIB::EXP10_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getEXP10(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FFLOOR(SDNode *N,
                                              SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::FLOOR_F32, RTLIB::FLOOR_F64,
-                                       RTLIB::FLOOR_F80, RTLIB::FLOOR_F128,
-                                       RTLIB::FLOOR_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getFLOOR(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FLOG(SDNode *N,
                                            SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::LOG_F32, RTLIB::LOG_F64,
-                                       RTLIB::LOG_F80, RTLIB::LOG_F128,
-                                       RTLIB::LOG_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getLOG(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FLOG2(SDNode *N,
                                             SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::LOG2_F32, RTLIB::LOG2_F64,
-                                       RTLIB::LOG2_F80, RTLIB::LOG2_F128,
-                                       RTLIB::LOG2_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getLOG2(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FLOG10(SDNode *N,
                                              SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::LOG10_F32, RTLIB::LOG10_F64,
-                                       RTLIB::LOG10_F80, RTLIB::LOG10_F128,
-                                       RTLIB::LOG10_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getLOG10(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FMA(SDNode *N, SDValue &Lo,
@@ -1970,14 +1766,9 @@ void DAGTypeLegalizer::ExpandFloatRes_FMA(SDNode *N, SDValue &Lo,
                      N->getOperand(2 + Offset) };
   SDValue Chain = IsStrict ? N->getOperand(0) : SDValue();
   TargetLowering::MakeLibCallOptions CallOptions;
-  std::pair<SDValue, SDValue> Tmp = TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0),
-                                                   RTLIB::FMA_F32,
-                                                   RTLIB::FMA_F64,
-                                                   RTLIB::FMA_F80,
-                                                   RTLIB::FMA_F128,
-                                                   RTLIB::FMA_PPCF128),
-                                 N->getValueType(0), Ops, CallOptions,
-                                 SDLoc(N), Chain);
+  std::pair<SDValue, SDValue> Tmp =
+      TLI.makeLibCall(DAG, RTLIB::getFMA(N->getValueType(0)),
+                      N->getValueType(0), Ops, CallOptions, SDLoc(N), Chain);
   if (IsStrict)
     ReplaceValueWith(SDValue(N, 1), Tmp.second);
   GetPairElements(Tmp.first, Lo, Hi);
@@ -1995,12 +1786,7 @@ void DAGTypeLegalizer::ExpandFloatRes_FMUL(SDNode *N, SDValue &Lo,
 
 void DAGTypeLegalizer::ExpandFloatRes_FNEARBYINT(SDNode *N,
                                                  SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::NEARBYINT_F32,
-                                       RTLIB::NEARBYINT_F64,
-                                       RTLIB::NEARBYINT_F80,
-                                       RTLIB::NEARBYINT_F128,
-                                       RTLIB::NEARBYINT_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getNEARBYINT(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FNEG(SDNode *N, SDValue &Lo,
@@ -2048,10 +1834,7 @@ void DAGTypeLegalizer::ExpandFloatRes_FP_EXTEND(SDNode *N, SDValue &Lo,
 
 void DAGTypeLegalizer::ExpandFloatRes_FPOW(SDNode *N,
                                            SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                        RTLIB::POW_F32, RTLIB::POW_F64,
-                                        RTLIB::POW_F80, RTLIB::POW_F128,
-                                        RTLIB::POW_PPCF128), Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getPOW(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FPOWI(SDNode *N,
@@ -2077,63 +1860,37 @@ void DAGTypeLegalizer::ExpandFloatRes_FREEZE(SDNode *N,
 
 void DAGTypeLegalizer::ExpandFloatRes_FREM(SDNode *N,
                                            SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
-                                        RTLIB::REM_F32, RTLIB::REM_F64,
-                                        RTLIB::REM_F80, RTLIB::REM_F128,
-                                        RTLIB::REM_PPCF128), Lo, Hi);
+  ExpandFloatRes_Binary(N, RTLIB::getREM(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FRINT(SDNode *N,
                                             SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::RINT_F32, RTLIB::RINT_F64,
-                                       RTLIB::RINT_F80, RTLIB::RINT_F128,
-                                       RTLIB::RINT_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getRINT(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FROUND(SDNode *N,
                                              SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::ROUND_F32,
-                                       RTLIB::ROUND_F64,
-                                       RTLIB::ROUND_F80,
-                                       RTLIB::ROUND_F128,
-                                       RTLIB::ROUND_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getROUND(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FROUNDEVEN(SDNode *N,
                                              SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::ROUNDEVEN_F32,
-                                       RTLIB::ROUNDEVEN_F64,
-                                       RTLIB::ROUNDEVEN_F80,
-                                       RTLIB::ROUNDEVEN_F128,
-                                       RTLIB::ROUNDEVEN_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getROUNDEVEN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FSIN(SDNode *N,
                                            SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::SIN_F32, RTLIB::SIN_F64,
-                                       RTLIB::SIN_F80, RTLIB::SIN_F128,
-                                       RTLIB::SIN_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getSIN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FSINH(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::SINH_F32,
-                                    RTLIB::SINH_F64, RTLIB::SINH_F80,
-                                    RTLIB::SINH_F128, RTLIB::SINH_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getSINH(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FSQRT(SDNode *N,
                                             SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::SQRT_F32, RTLIB::SQRT_F64,
-                                       RTLIB::SQRT_F80, RTLIB::SQRT_F128,
-                                       RTLIB::SQRT_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getSQRT(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FSUB(SDNode *N, SDValue &Lo,
@@ -2148,28 +1905,17 @@ void DAGTypeLegalizer::ExpandFloatRes_FSUB(SDNode *N, SDValue &Lo,
 
 void DAGTypeLegalizer::ExpandFloatRes_FTAN(SDNode *N, SDValue &Lo,
                                            SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::TAN_F32,
-                                    RTLIB::TAN_F64, RTLIB::TAN_F80,
-                                    RTLIB::TAN_F128, RTLIB::TAN_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getTAN(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FTANH(SDNode *N, SDValue &Lo,
                                             SDValue &Hi) {
-  ExpandFloatRes_Unary(N,
-                       GetFPLibCall(N->getValueType(0), RTLIB::TANH_F32,
-                                    RTLIB::TANH_F64, RTLIB::TANH_F80,
-                                    RTLIB::TANH_F128, RTLIB::TANH_PPCF128),
-                       Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getTANH(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_FTRUNC(SDNode *N,
                                              SDValue &Lo, SDValue &Hi) {
-  ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
-                                       RTLIB::TRUNC_F32, RTLIB::TRUNC_F64,
-                                       RTLIB::TRUNC_F80, RTLIB::TRUNC_F128,
-                                       RTLIB::TRUNC_PPCF128), Lo, Hi);
+  ExpandFloatRes_Unary(N, RTLIB::getTRUNC(N->getValueType(0)), Lo, Hi);
 }
 
 void DAGTypeLegalizer::ExpandFloatRes_LOAD(SDNode *N, SDValue &Lo,
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 051ba4670be40..584bd63cd4fc2 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -533,235 +533,10 @@ RTLIB::Libcall RTLIB::getUINTTOFP(EVT OpVT, EVT RetVT) {
   return UNKNOWN_LIBCALL;
 }
 
-RTLIB::Libcall RTLIB::getPOWI(EVT RetVT) {
-  return getFPLibCall(RetVT, POWI_F32, POWI_F64, POWI_F80, POWI_F128,
-                      POWI_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getPOW(EVT RetVT) {
-  // TODO: Tablegen should generate this function
-  if (RetVT.isVector()) {
-    if (!RetVT.isSimple())
-      return RTLIB::UNKNOWN_LIBCALL;
-    switch (RetVT.getSimpleVT().SimpleTy) {
-    case MVT::v4f32:
-      return RTLIB::POW_V4F32;
-    case MVT::v2f64:
-      return RTLIB::POW_V2F64;
-    case MVT::nxv4f32:
-      return RTLIB::POW_NXV4F32;
-    case MVT::nxv2f64:
-      return RTLIB::POW_NXV2F64;
-    default:
-      return RTLIB::UNKNOWN_LIBCALL;
-    }
-  }
-
-  return getFPLibCall(RetVT, POW_F32, POW_F64, POW_F80, POW_F128, POW_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getLDEXP(EVT RetVT) {
-  return getFPLibCall(RetVT, LDEXP_F32, LDEXP_F64, LDEXP_F80, LDEXP_F128,
-                      LDEXP_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getFREXP(EVT RetVT) {
-  return getFPLibCall(RetVT, FREXP_F32, FREXP_F64, FREXP_F80, FREXP_F128,
-                      FREXP_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getSIN(EVT RetVT) {
-  return getFPLibCall(RetVT, SIN_F32, SIN_F64, SIN_F80, SIN_F128, SIN_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getCOS(EVT RetVT) {
-  return getFPLibCall(RetVT, COS_F32, COS_F64, COS_F80, COS_F128, COS_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getSINCOS(EVT RetVT) {
-  // TODO: Tablegen should generate this function
-  if (RetVT.isVector()) {
-    if (!RetVT.isSimple())
-      return RTLIB::UNKNOWN_LIBCALL;
-    switch (RetVT.getSimpleVT().SimpleTy) {
-    case MVT::v4f32:
-      return RTLIB::SINCOS_V4F32;
-    case MVT::v8f32:
-      return RTLIB::SINCOS_V8F32;
-    case MVT::v16f32:
-      return RTLIB::SINCOS_V16F32;
-    case MVT::v2f64:
-      return RTLIB::SINCOS_V2F64;
-    case MVT::v4f64:
-      return RTLIB::SINCOS_V4F64;
-    case MVT::v8f64:
-      return RTLIB::SINCOS_V8F64;
-    case MVT::nxv4f32:
-      return RTLIB::SINCOS_NXV4F32;
-    case MVT::nxv2f64:
-      return RTLIB::SINCOS_NXV2F64;
-    default:
-      return RTLIB::UNKNOWN_LIBCALL;
-    }
-  }
-
-  return getFPLibCall(RetVT, SINCOS_F32, SINCOS_F64, SINCOS_F80, SINCOS_F128,
-                      SINCOS_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getSINCOSPI(EVT RetVT) {
-  // TODO: Tablegen should generate this function
-  if (RetVT.isVector()) {
-    if (!RetVT.isSimple())
-      return RTLIB::UNKNOWN_LIBCALL;
-    switch (RetVT.getSimpleVT().SimpleTy) {
-    case MVT::v4f32:
-      return RTLIB::SINCOSPI_V4F32;
-    case MVT::v2f64:
-      return RTLIB::SINCOSPI_V2F64;
-    case MVT::nxv4f32:
-      return RTLIB::SINCOSPI_NXV4F32;
-    case MVT::nxv2f64:
-      return RTLIB::SINCOSPI_NXV2F64;
-    default:
-      return RTLIB::UNKNOWN_LIBCALL;
-    }
-  }
-
-  return getFPLibCall(RetVT, SINCOSPI_F32, SINCOSPI_F64, SINCOSPI_F80,
-                      SINCOSPI_F128, SINCOSPI_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getSINCOS_STRET(EVT RetVT) {
-  return getFPLibCall(RetVT, SINCOS_STRET_F32, SINCOS_STRET_F64,
-                      UNKNOWN_LIBCALL, UNKNOWN_LIBCALL, UNKNOWN_LIBCALL);
-}
-
-RTLIB::Libcall RTLIB::getREM(EVT VT) {
-  // TODO: Tablegen should generate this function
-  if (VT.isVector()) {
-    if (!VT.isSimple())
-      return RTLIB::UNKNOWN_LIBCALL;
-    switch (VT.getSimpleVT().SimpleTy) {
-    case MVT::v4f32:
-      return RTLIB::REM_V4F32;
-    case MVT::v2f64:
-      return RTLIB::REM_V2F64;
-    case MVT::nxv4f32:
-      return RTLIB::REM_NXV4F32;
-    case MVT::nxv2f64:
-      return RTLIB::REM_NXV2F64;
-    default:
-      return RTLIB::UNKNOWN_LIBCALL;
-    }
-  }
-
-  return getFPLibCall(VT, REM_F32, REM_F64, REM_F80, REM_F128, REM_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getCBRT(EVT VT) {
-  // TODO: Tablegen should generate this function
-  if (VT.isVector()) {
-    if (!VT.isSimple())
-      return RTLIB::UNKNOWN_LIBCALL;
-    switch (VT.getSimpleVT().SimpleTy) {
-    case MVT::v4f32:
-      return RTLIB::CBRT_V4F32;
-    case MVT::v2f64:
-      return RTLIB::CBRT_V2F64;
-    case MVT::nxv4f32:
-      return RTLIB::CBRT_NXV4F32;
-    case MVT::nxv2f64:
-      return RTLIB::CBRT_NXV2F64;
-    default:
-      return RTLIB::UNKNOWN_LIBCALL;
-    }
-  }
-
-  return getFPLibCall(VT, CBRT_F32, CBRT_F64, CBRT_F80, CBRT_F128,
-                      CBRT_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getMODF(EVT RetVT) {
-  // TODO: Tablegen should generate this function
-  if (RetVT.isVector()) {
-    if (!RetVT.isSimple())
-      return RTLIB::UNKNOWN_LIBCALL;
-    switch (RetVT.getSimpleVT().SimpleTy) {
-    case MVT::v4f32:
-      return RTLIB::MODF_V4F32;
-    case MVT::v2f64:
-      return RTLIB::MODF_V2F64;
-    case MVT::nxv4f32:
-      return RTLIB::MODF_NXV4F32;
-    case MVT::nxv2f64:
-      return RTLIB::MODF_NXV2F64;
-    default:
-      return RTLIB::UNKNOWN_LIBCALL;
-    }
-  }
-
-  return getFPLibCall(RetVT, MODF_F32, MODF_F64, MODF_F80, MODF_F128,
-                      MODF_PPCF128);
-}
-
-RTLIB::Libcall RTLIB::getLROUND(EVT VT) {
-  if (VT == MVT::f32)
-    return RTLIB::LROUND_F32;
-  if (VT == MVT::f64)
-    return RTLIB::LROUND_F64;
-  if (VT == MVT::f80)
-    return RTLIB::LROUND_F80;
-  if (VT == MVT::f128)
-    return RTLIB::LROUND_F128;
-  if (VT == MVT::ppcf128)
-    return RTLIB::LROUND_PPCF128;
-
-  return RTLIB::UNKNOWN_LIBCALL;
-}
-
-RTLIB::Libcall RTLIB::getLLROUND(EVT VT) {
-  if (VT == MVT::f32)
-    return RTLIB::LLROUND_F32;
-  if (VT == MVT::f64)
-    return RTLIB::LLROUND_F64;
-  if (VT == MVT::f80)
-    return RTLIB::LLROUND_F80;
-  if (VT == MVT::f128)
-    return RTLIB::LLROUND_F128;
-  if (VT == MVT::ppcf128)
-    return RTLIB::LLROUND_PPCF128;
-
-  return RTLIB::UNKNOWN_LIBCALL;
-}
-
-RTLIB::Libcall RTLIB::getLRINT(EVT VT) {
-  if (VT == MVT::f32)
-    return RTLIB::LRINT_F32;
-  if (VT == MVT::f64)
-    return RTLIB::LRINT_F64;
-  if (VT == MVT::f80)
-    return RTLIB::LRINT_F80;
-  if (VT == MVT::f128)
-    return RTLIB::LRINT_F128;
-  if (VT == MVT::ppcf128)
-    return RTLIB::LRINT_PPCF128;
-  return RTLIB::UNKNOWN_LIBCALL;
-}
-
-RTLIB::Libcall RTLIB::getLLRINT(EVT VT) {
-  if (VT == MVT::f32)
-    return RTLIB::LLRINT_F32;
-  if (VT == MVT::f64)
-    return RTLIB::LLRINT_F64;
-  if (VT == MVT::f80)
-    return RTLIB::LLRINT_F80;
-  if (VT == MVT::f128)
-    return RTLIB::LLRINT_F128;
-  if (VT == MVT::ppcf128)
-    return RTLIB::LLRINT_PPCF128;
-  return RTLIB::UNKNOWN_LIBCALL;
-}
+// The floating-point RTLIB::getXXX(EVT) selectors are generated from the
+// RuntimeLibcallFamily table in RuntimeLibcalls.td.
+#define GET_RUNTIME_LIBCALL_FP_SELECTORS
+#include "llvm/IR/RuntimeLibcalls.inc"
 
 RTLIB::Libcall RTLIB::getOutlineAtomicHelper(const Libcall (&LC)[5][4],
                                              AtomicOrdering Order,
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index ad7d3320f8928..4afb80d28bffe 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -9,8 +9,10 @@
 #include "llvm/IR/RuntimeLibcalls.h"
 #include "llvm/ADT/FloatingPointMode.h"
 #include "llvm/ADT/StringTable.h"
+#include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/SystemLibraries.h"
+#include "llvm/IR/Type.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/xxhash.h"
 #include "llvm/TargetParser/ARMTargetParser.h"
@@ -24,6 +26,7 @@ using namespace RTLIB;
 #define GET_INIT_RUNTIME_LIBCALL_NAMES
 #define GET_SET_TARGET_RUNTIME_LIBCALL_SETS
 #define DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME
+#define GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL
 #include "llvm/IR/RuntimeLibcalls.inc"
 
 RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Triple &TT,
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td
new file mode 100644
index 0000000000000..2951b20eccb54
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td
@@ -0,0 +1,55 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s | FileCheck %s
+
+include "llvm/IR/RuntimeLibcallsImpl.td"
+
+def SIN_F32 : RuntimeLibcall;
+def SIN_F64 : RuntimeLibcall;
+def SIN_F128 : RuntimeLibcall;
+def SIN_V4F32 : RuntimeLibcall;
+def SIN_V2F64 : RuntimeLibcall;
+def COS_F128 : RuntimeLibcall;
+def sinf : RuntimeLibcallImpl<SIN_F32, "sinf">;
+def : RuntimeLibcallFamily<"SIN", ["sin", "experimental_constrained_sin"],
+    ["V4F32", "V2F64"]>;
+def : RuntimeLibcallFamily<"COS", ["cos"]>;
+
+// CHECK: #ifdef GET_RUNTIME_LIBCALL_FP_SELECTORS
+// CHECK: RTLIB::Libcall llvm::RTLIB::getCOS(EVT VT) {
+// CHECK-NEXT:   return getFPLibCall(VT, RTLIB::UNKNOWN_LIBCALL, RTLIB::UNKNOWN_LIBCALL, RTLIB::UNKNOWN_LIBCALL, RTLIB::COS_F128, RTLIB::UNKNOWN_LIBCALL);
+// CHECK-NEXT: }
+// CHECK: RTLIB::Libcall llvm::RTLIB::getSIN(EVT VT) {
+// CHECK-NEXT:   if (VT.isVector()) {
+// CHECK-NEXT:     if (!VT.isSimple())
+// CHECK-NEXT:       return RTLIB::UNKNOWN_LIBCALL;
+// CHECK-NEXT:     switch (VT.getSimpleVT().SimpleTy) {
+// CHECK-NEXT:     case MVT::v4f32:
+// CHECK-NEXT:       return RTLIB::SIN_V4F32;
+// CHECK-NEXT:     case MVT::v2f64:
+// CHECK-NEXT:       return RTLIB::SIN_V2F64;
+// CHECK-NEXT:     default:
+// CHECK-NEXT:       return RTLIB::UNKNOWN_LIBCALL;
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT:   return getFPLibCall(VT, RTLIB::SIN_F32, RTLIB::SIN_F64, RTLIB::UNKNOWN_LIBCALL, RTLIB::SIN_F128, RTLIB::UNKNOWN_LIBCALL);
+// CHECK-NEXT: }
+
+// CHECK: #ifdef GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL
+// CHECK: RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::getLibcallForIntrinsic(Intrinsic::ID ID, Type *Ty) {
+// CHECK-NEXT:   switch (ID) {
+// CHECK-NEXT:   case Intrinsic::cos:
+// CHECK-NEXT:     if (Ty->isFP128Ty())
+// CHECK-NEXT:       return RTLIB::COS_F128;
+// CHECK-NEXT:     return RTLIB::UNKNOWN_LIBCALL;
+// CHECK-NEXT:   case Intrinsic::experimental_constrained_sin:
+// CHECK-NEXT:   case Intrinsic::sin:
+// CHECK-NEXT:     if (Ty->isFloatTy())
+// CHECK-NEXT:       return RTLIB::SIN_F32;
+// CHECK-NEXT:     if (Ty->isDoubleTy())
+// CHECK-NEXT:       return RTLIB::SIN_F64;
+// CHECK-NEXT:     if (Ty->isFP128Ty())
+// CHECK-NEXT:       return RTLIB::SIN_F128;
+// CHECK-NEXT:     return RTLIB::UNKNOWN_LIBCALL;
+// CHECK-NEXT:   default:
+// CHECK-NEXT:     return RTLIB::UNKNOWN_LIBCALL;
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
diff --git a/llvm/unittests/IR/RuntimeLibcallsTest.cpp b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
index 8925d2b1155e5..1745649c67ce0 100644
--- a/llvm/unittests/IR/RuntimeLibcallsTest.cpp
+++ b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
@@ -8,6 +8,9 @@
 
 #include "llvm/IR/RuntimeLibcalls.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Type.h"
 #include "gtest/gtest.h"
 using namespace llvm;
 
@@ -60,4 +63,64 @@ TEST(RuntimeLibcallsTest, LibcallImplByName) {
   }
 }
 
+TEST(RuntimeLibcallsTest, LibcallForIntrinsic) {
+  LLVMContext Ctx;
+  using Info = RTLIB::RuntimeLibcallsInfo;
+
+  // Per-type resolution.
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getFloatTy(Ctx)),
+            RTLIB::SIN_F32);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getDoubleTy(Ctx)),
+      RTLIB::SIN_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getFP128Ty(Ctx)),
+            RTLIB::SIN_F128);
+
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::cos, Type::getDoubleTy(Ctx)),
+      RTLIB::COS_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::pow, Type::getFloatTy(Ctx)),
+            RTLIB::POW_F32);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::ldexp, Type::getDoubleTy(Ctx)),
+      RTLIB::LDEXP_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::sqrt, Type::getFloatTy(Ctx)),
+      RTLIB::SQRT_F32);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::exp, Type::getDoubleTy(Ctx)),
+      RTLIB::EXP_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::log, Type::getX86_FP80Ty(Ctx)),
+      RTLIB::LOG_F80);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::copysign, Type::getDoubleTy(Ctx)),
+      RTLIB::COPYSIGN_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::maxnum, Type::getDoubleTy(Ctx)),
+      RTLIB::FMAX_F64);
+
+  // Constrained variants resolve to the same libcall as their plain twin.
+  EXPECT_EQ(Info::getLibcallForIntrinsic(
+                Intrinsic::experimental_constrained_sin, Type::getFloatTy(Ctx)),
+            RTLIB::SIN_F32);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::experimental_constrained_fma,
+                                   Type::getDoubleTy(Ctx)),
+      RTLIB::FMA_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::experimental_constrained_pow,
+                                   Type::getDoubleTy(Ctx)),
+      RTLIB::POW_F64);
+
+  // Unmapped intrinsic.
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::fabs, Type::getDoubleTy(Ctx)),
+      RTLIB::UNKNOWN_LIBCALL);
+
+  // Mapped intrinsic, but a type with no matching libcall.
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getHalfTy(Ctx)),
+            RTLIB::UNKNOWN_LIBCALL);
+}
+
 } // namespace
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 7a0bd4228117c..813ddc6310bbb 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -11,6 +11,7 @@
 #include "RuntimeLibcalls.h"
 
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Format.h"
@@ -47,6 +48,15 @@ inline bool operator==(PredicateWithCC LHS, PredicateWithCC RHS) {
 }
 } // namespace
 
+namespace {
+/// A floating-point libcall family parsed from a RuntimeLibcallFamily record.
+struct FPLibcallFamily {
+  StringRef Base;
+  std::vector<StringRef> Intrinsics;
+  std::vector<StringRef> VectorSuffixes;
+};
+} // namespace
+
 namespace llvm {
 template <> struct DenseMapInfo<PredicateWithCC, void> {
   static unsigned getHashValue(const PredicateWithCC Val) {
@@ -74,6 +84,15 @@ class RuntimeLibcallEmitter {
 
   void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const;
 
+  void emitFPLibcallSelectorDecls(raw_ostream &OS,
+                                  ArrayRef<FPLibcallFamily> Families) const;
+
+  void emitFPLibcallSelectors(raw_ostream &OS,
+                              ArrayRef<FPLibcallFamily> Families) const;
+
+  void emitGetLibcallForIntrinsic(raw_ostream &OS,
+                                  ArrayRef<FPLibcallFamily> Families) const;
+
 public:
   RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R), Libcalls(R) {}
 
@@ -534,6 +553,139 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
         "}\n\n";
 }
 
+// Scalar FP type suffixes in the argument order of RTLIB::getFPLibCall, paired
+// with the llvm::Type predicate used by the IR-level mapping.
+static constexpr std::pair<StringRef, StringRef> ScalarFPSuffixes[] = {
+    {"F32", "isFloatTy()"},         {"F64", "isDoubleTy()"},
+    {"F80", "isX86_FP80Ty()"},      {"F128", "isFP128Ty()"},
+    {"PPCF128", "isPPC_FP128Ty()"},
+};
+
+static std::vector<FPLibcallFamily>
+collectFPLibcallFamilies(const RecordKeeper &Records) {
+  std::vector<FPLibcallFamily> Families;
+  for (const Record *R :
+       Records.getAllDerivedDefinitions("RuntimeLibcallFamily")) {
+    FPLibcallFamily Family;
+    Family.Base = R->getValueAsString("LibcallBase");
+    Family.Intrinsics = R->getValueAsListOfStrings("Intrinsics");
+    Family.VectorSuffixes = R->getValueAsListOfStrings("VectorSuffixes");
+    Families.push_back(std::move(Family));
+  }
+  llvm::sort(Families, [](const FPLibcallFamily &A, const FPLibcallFamily &B) {
+    return A.Base < B.Base;
+  });
+  return Families;
+}
+
+/// Generate the declarations for the RTLIB::get<base>(EVT) selectors.
+void RuntimeLibcallEmitter::emitFPLibcallSelectorDecls(
+    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
+  IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_FP_SELECTOR_DECLS");
+  for (const FPLibcallFamily &Family : Families)
+    OS << "LLVM_ABI Libcall get" << Family.Base << "(EVT VT);\n";
+}
+
+/// Generate the backend RTLIB::get<base>(EVT) selectors from the floating-point
+/// libcall families.
+void RuntimeLibcallEmitter::emitFPLibcallSelectors(
+    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
+  IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_FP_SELECTORS");
+
+  // Only emit a libcall enumerator if it actually exists in the declared set.
+  DenseSet<StringRef> ExistingLibcalls;
+  for (const RuntimeLibcall &LC : Libcalls.getRuntimeLibcallDefList())
+    ExistingLibcalls.insert(LC.getName());
+
+  auto scalarEnum = [&](StringRef Base, StringRef Suffix) -> std::string {
+    if (ExistingLibcalls.contains((Base + "_" + Suffix).str()))
+      return ("RTLIB::" + Base + "_" + Suffix).str();
+    return "RTLIB::UNKNOWN_LIBCALL";
+  };
+
+  for (const FPLibcallFamily &Family : Families) {
+    StringRef Base = Family.Base;
+    OS << "RTLIB::Libcall llvm::RTLIB::get" << Base << "(EVT VT) {\n";
+
+    if (!Family.VectorSuffixes.empty()) {
+      OS << "  if (VT.isVector()) {\n"
+            "    if (!VT.isSimple())\n"
+            "      return RTLIB::UNKNOWN_LIBCALL;\n"
+            "    switch (VT.getSimpleVT().SimpleTy) {\n";
+      for (StringRef Suffix : Family.VectorSuffixes) {
+        OS << "    case MVT::" << Suffix.lower()
+           << ":\n      return RTLIB::" << Base << "_" << Suffix << ";\n";
+      }
+      OS << "    default:\n"
+            "      return RTLIB::UNKNOWN_LIBCALL;\n"
+            "    }\n"
+            "  }\n";
+    }
+
+    OS << "  return getFPLibCall(VT";
+    for (auto [Suffix, Pred] : ScalarFPSuffixes)
+      OS << ", " << scalarEnum(Base, Suffix);
+    OS << ");\n}\n\n";
+  }
+}
+
+/// Emit the mapping from floating-point math intrinsics to the runtime libcall
+/// they may lower to, keyed by intrinsic ID and floating-point type. This is
+/// the IR-level counterpart to the backend's RTLIB::getXXX(EVT) selectors.
+void RuntimeLibcallEmitter::emitGetLibcallForIntrinsic(
+    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
+  IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL");
+
+  DenseSet<StringRef> ExistingLibcalls;
+  for (const RuntimeLibcall &LC : Libcalls.getRuntimeLibcallDefList())
+    ExistingLibcalls.insert(LC.getName());
+
+  std::vector<std::pair<StringRef, StringRef>> IntrinsicToBase;
+  for (const FPLibcallFamily &Family : Families)
+    for (StringRef Intrinsic : Family.Intrinsics)
+      IntrinsicToBase.emplace_back(Intrinsic, Family.Base);
+  llvm::sort(IntrinsicToBase);
+
+  for (size_t I = 1, E = IntrinsicToBase.size(); I < E; ++I)
+    if (IntrinsicToBase[I].first == IntrinsicToBase[I - 1].first)
+      PrintFatalError(
+          "intrinsic '" + IntrinsicToBase[I].first +
+          "' is mapped by multiple RuntimeLibcallFamily records ('" +
+          IntrinsicToBase[I - 1].second + "' and '" +
+          IntrinsicToBase[I].second + "')");
+
+  MapVector<StringRef, SmallVector<StringRef, 2>> BaseToIntrinsics;
+  for (auto [Intrinsic, Base] : IntrinsicToBase)
+    BaseToIntrinsics[Base].push_back(Intrinsic);
+
+  OS << "RTLIB::Libcall "
+        "llvm::RTLIB::RuntimeLibcallsInfo::getLibcallForIntrinsic("
+        "Intrinsic::ID ID, Type *Ty) {\n"
+        "  switch (ID) {\n";
+
+  for (const auto &[Base, Intrinsics] : BaseToIntrinsics) {
+    SmallVector<std::pair<StringRef, StringRef>, 5> Arms;
+    for (auto [Suffix, Pred] : ScalarFPSuffixes)
+      if (ExistingLibcalls.contains((Base + "_" + Suffix).str()))
+        Arms.emplace_back(Suffix, Pred);
+
+    if (Arms.empty())
+      PrintFatalError("no runtime libcall found for base name '" + Base + "'");
+
+    for (StringRef Intrinsic : Intrinsics)
+      OS << "  case Intrinsic::" << Intrinsic << ":\n";
+    for (auto [Suffix, Pred] : Arms)
+      OS << "    if (Ty->" << Pred << ")\n      return RTLIB::" << Base << "_"
+         << Suffix << ";\n";
+    OS << "    return RTLIB::UNKNOWN_LIBCALL;\n";
+  }
+
+  OS << "  default:\n"
+        "    return RTLIB::UNKNOWN_LIBCALL;\n"
+        "  }\n"
+        "}\n";
+}
+
 void RuntimeLibcallEmitter::run(raw_ostream &OS) {
   emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records);
   emitGetRuntimeLibcallEnum(OS);
@@ -544,6 +696,11 @@ void RuntimeLibcallEmitter::run(raw_ostream &OS) {
     IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALLS_INFO");
     emitSystemRuntimeLibrarySetCalls(OS);
   }
+
+  std::vector<FPLibcallFamily> FPFamilies = collectFPLibcallFamilies(Records);
+  emitFPLibcallSelectorDecls(OS, FPFamilies);
+  emitFPLibcallSelectors(OS, FPFamilies);
+  emitGetLibcallForIntrinsic(OS, FPFamilies);
 }
 
 static TableGen::Emitter::OptClass<RuntimeLibcallEmitter>

>From 657725838ec23b074f65dfe717d66e5504157a7b Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Thu, 6 Aug 2026 10:26:11 -0500
Subject: [PATCH 2/3] Comments

---
 llvm/include/llvm/IR/RuntimeLibcalls.h        |   9 +-
 ...callEmitter-intrinsic-to-libcall-errors.td |  21 ++++
 ...timeLibcallEmitter-intrinsic-to-libcall.td |  13 ++-
 llvm/unittests/IR/RuntimeLibcallsTest.cpp     | 100 +++++++++++-------
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp |  30 ++++--
 5 files changed, 120 insertions(+), 53 deletions(-)
 create mode 100644 llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 86fdd5776176e..4a97f32e4fff2 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -126,14 +126,9 @@ struct RuntimeLibcallsInfo {
   /// operating on type \p Ty may be lowered to, or RTLIB::UNKNOWN_LIBCALL if
   /// there is no such mapping.
   ///
-  /// \p Ty must be the floating-point operand type, which is not always the
-  /// intrinsic's primary/overloaded type. E.g. lround/llround/lrint/llrint are
-  /// overloaded on the integer result, powi on the integer exponent, and
-  /// frexp/modf/sincos return an aggregate. For these, pass the floating-point
-  /// argument type (e.g. the type of operand 0), not the intrinsic's return
-  /// type.
+  /// \p FTy must be the intrinsic's call signature.
   LLVM_ABI static RTLIB::Libcall getLibcallForIntrinsic(Intrinsic::ID ID,
-                                                        Type *Ty);
+                                                        FunctionType *FTy);
 
   unsigned getNumAvailableLibcallImpls() const {
     return AvailableLibcallImpls.count();
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td
new file mode 100644
index 0000000000000..a7d8ef3c74a3b
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td
@@ -0,0 +1,21 @@
+// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include -DERR_DUP_INTRINSIC %s 2>&1 | FileCheck -check-prefix=ERR-DUP %s
+// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include -DERR_NO_LIBCALL %s 2>&1 | FileCheck -check-prefix=ERR-NO-LIBCALL %s
+
+include "llvm/IR/RuntimeLibcallsImpl.td"
+
+#ifdef ERR_DUP_INTRINSIC
+def SIN_F32 : RuntimeLibcall;
+def impl_sinf : RuntimeLibcallImpl<SIN_F32, "sinf">;
+def : RuntimeLibcallFamily<"SIN", ["sin"]>;
+def : RuntimeLibcallFamily<"COS", ["sin"]>;
+
+// ERR-DUP: error: intrinsic 'sin' is mapped by multiple RuntimeLibcallFamily records ('COS' and 'SIN')
+#endif
+
+#ifdef ERR_NO_LIBCALL
+def COS_F32 : RuntimeLibcall;
+def impl_cosf : RuntimeLibcallImpl<COS_F32, "cosf">;
+def : RuntimeLibcallFamily<"SIN", ["sin"]>;
+
+// ERR-NO-LIBCALL: error: no runtime libcall found for base name 'SIN'
+#endif
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td
index 2951b20eccb54..8465529e53768 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall.td
@@ -34,7 +34,18 @@ def : RuntimeLibcallFamily<"COS", ["cos"]>;
 // CHECK-NEXT: }
 
 // CHECK: #ifdef GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL
-// CHECK: RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::getLibcallForIntrinsic(Intrinsic::ID ID, Type *Ty) {
+// CHECK: RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::getLibcallForIntrinsic(Intrinsic::ID ID, FunctionType *FTy) {
+// CHECK-NEXT:   Type *Ty = FTy->getReturnType();
+// CHECK-NEXT:   if (!Ty->isFloatingPointTy()) {
+// CHECK-NEXT:     for (Type *ParamTy : FTy->params()) {
+// CHECK-NEXT:       if (ParamTy->isFloatingPointTy()) {
+// CHECK-NEXT:         Ty = ParamTy;
+// CHECK-NEXT:         break;
+// CHECK-NEXT:       }
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT:   if (!Ty->isFloatingPointTy())
+// CHECK-NEXT:     return RTLIB::UNKNOWN_LIBCALL;
 // CHECK-NEXT:   switch (ID) {
 // CHECK-NEXT:   case Intrinsic::cos:
 // CHECK-NEXT:     if (Ty->isFP128Ty())
diff --git a/llvm/unittests/IR/RuntimeLibcallsTest.cpp b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
index 1745649c67ce0..35f525f2b0c41 100644
--- a/llvm/unittests/IR/RuntimeLibcallsTest.cpp
+++ b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/IR/RuntimeLibcalls.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Type.h"
@@ -66,60 +67,87 @@ TEST(RuntimeLibcallsTest, LibcallImplByName) {
 TEST(RuntimeLibcallsTest, LibcallForIntrinsic) {
   LLVMContext Ctx;
   using Info = RTLIB::RuntimeLibcallsInfo;
+  auto UnarySig = [&](Type *Ty) { return FunctionType::get(Ty, {Ty}, false); };
+  auto BinarySig = [&](Type *Ty) {
+    return FunctionType::get(Ty, {Ty, Ty}, false);
+  };
+  auto FpIntSig = [&](Type *Ty) {
+    return FunctionType::get(Ty, {Ty, Type::getInt32Ty(Ctx)}, false);
+  };
+  auto ConstrainedUnarySig = [&](Type *Ty) {
+    return FunctionType::get(
+        Ty, {Ty, Type::getMetadataTy(Ctx), Type::getMetadataTy(Ctx)}, false);
+  };
+  auto ConstrainedFmaSig = [&](Type *Ty) {
+    return FunctionType::get(
+        Ty, {Ty, Ty, Ty, Type::getMetadataTy(Ctx), Type::getMetadataTy(Ctx)},
+        false);
+  };
 
   // Per-type resolution.
-  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getFloatTy(Ctx)),
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin,
+                                         UnarySig(Type::getFloatTy(Ctx))),
             RTLIB::SIN_F32);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getDoubleTy(Ctx)),
-      RTLIB::SIN_F64);
-  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getFP128Ty(Ctx)),
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin,
+                                         UnarySig(Type::getDoubleTy(Ctx))),
+            RTLIB::SIN_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin,
+                                         UnarySig(Type::getFP128Ty(Ctx))),
             RTLIB::SIN_F128);
 
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::cos, Type::getDoubleTy(Ctx)),
-      RTLIB::COS_F64);
-  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::pow, Type::getFloatTy(Ctx)),
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::cos,
+                                         UnarySig(Type::getDoubleTy(Ctx))),
+            RTLIB::COS_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::pow,
+                                         BinarySig(Type::getFloatTy(Ctx))),
             RTLIB::POW_F32);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::ldexp, Type::getDoubleTy(Ctx)),
-      RTLIB::LDEXP_F64);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::sqrt, Type::getFloatTy(Ctx)),
-      RTLIB::SQRT_F32);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::exp, Type::getDoubleTy(Ctx)),
-      RTLIB::EXP_F64);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::log, Type::getX86_FP80Ty(Ctx)),
-      RTLIB::LOG_F80);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::copysign, Type::getDoubleTy(Ctx)),
-      RTLIB::COPYSIGN_F64);
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::maxnum, Type::getDoubleTy(Ctx)),
-      RTLIB::FMAX_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::ldexp,
+                                         FpIntSig(Type::getDoubleTy(Ctx))),
+            RTLIB::LDEXP_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sqrt,
+                                         UnarySig(Type::getFloatTy(Ctx))),
+            RTLIB::SQRT_F32);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::exp,
+                                         UnarySig(Type::getDoubleTy(Ctx))),
+            RTLIB::EXP_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::log,
+                                         UnarySig(Type::getX86_FP80Ty(Ctx))),
+            RTLIB::LOG_F80);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::copysign,
+                                         BinarySig(Type::getDoubleTy(Ctx))),
+            RTLIB::COPYSIGN_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::maxnum,
+                                         BinarySig(Type::getDoubleTy(Ctx))),
+            RTLIB::FMAX_F64);
 
   // Constrained variants resolve to the same libcall as their plain twin.
-  EXPECT_EQ(Info::getLibcallForIntrinsic(
-                Intrinsic::experimental_constrained_sin, Type::getFloatTy(Ctx)),
-            RTLIB::SIN_F32);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(Intrinsic::experimental_constrained_sin,
+                                   ConstrainedUnarySig(Type::getFloatTy(Ctx))),
+      RTLIB::SIN_F32);
   EXPECT_EQ(
       Info::getLibcallForIntrinsic(Intrinsic::experimental_constrained_fma,
-                                   Type::getDoubleTy(Ctx)),
+                                   ConstrainedFmaSig(Type::getDoubleTy(Ctx))),
       RTLIB::FMA_F64);
   EXPECT_EQ(
       Info::getLibcallForIntrinsic(Intrinsic::experimental_constrained_pow,
-                                   Type::getDoubleTy(Ctx)),
+                                   ConstrainedUnarySig(Type::getDoubleTy(Ctx))),
       RTLIB::POW_F64);
 
   // Unmapped intrinsic.
-  EXPECT_EQ(
-      Info::getLibcallForIntrinsic(Intrinsic::fabs, Type::getDoubleTy(Ctx)),
-      RTLIB::UNKNOWN_LIBCALL);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::fabs,
+                                         UnarySig(Type::getDoubleTy(Ctx))),
+            RTLIB::UNKNOWN_LIBCALL);
 
   // Mapped intrinsic, but a type with no matching libcall.
-  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, Type::getHalfTy(Ctx)),
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin,
+                                         UnarySig(Type::getHalfTy(Ctx))),
+            RTLIB::UNKNOWN_LIBCALL);
+
+  // Mapped intrinsic, but a signature with no floating-point argument/result.
+  auto *NonFPSig =
+      FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, false);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::sin, NonFPSig),
             RTLIB::UNKNOWN_LIBCALL);
 }
 
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 813ddc6310bbb..b1bbf6b40d048 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -54,6 +54,11 @@ struct FPLibcallFamily {
   StringRef Base;
   std::vector<StringRef> Intrinsics;
   std::vector<StringRef> VectorSuffixes;
+
+  explicit FPLibcallFamily(const Record *R)
+      : Base(R->getValueAsString("LibcallBase")),
+        Intrinsics(R->getValueAsListOfStrings("Intrinsics")),
+        VectorSuffixes(R->getValueAsListOfStrings("VectorSuffixes")) {}
 };
 } // namespace
 
@@ -565,13 +570,8 @@ static std::vector<FPLibcallFamily>
 collectFPLibcallFamilies(const RecordKeeper &Records) {
   std::vector<FPLibcallFamily> Families;
   for (const Record *R :
-       Records.getAllDerivedDefinitions("RuntimeLibcallFamily")) {
-    FPLibcallFamily Family;
-    Family.Base = R->getValueAsString("LibcallBase");
-    Family.Intrinsics = R->getValueAsListOfStrings("Intrinsics");
-    Family.VectorSuffixes = R->getValueAsListOfStrings("VectorSuffixes");
-    Families.push_back(std::move(Family));
-  }
+       Records.getAllDerivedDefinitions("RuntimeLibcallFamily"))
+    Families.emplace_back(R);
   llvm::sort(Families, [](const FPLibcallFamily &A, const FPLibcallFamily &B) {
     return A.Base < B.Base;
   });
@@ -647,12 +647,13 @@ void RuntimeLibcallEmitter::emitGetLibcallForIntrinsic(
   llvm::sort(IntrinsicToBase);
 
   for (size_t I = 1, E = IntrinsicToBase.size(); I < E; ++I)
-    if (IntrinsicToBase[I].first == IntrinsicToBase[I - 1].first)
+    if (IntrinsicToBase[I].first == IntrinsicToBase[I - 1].first) {
       PrintFatalError(
           "intrinsic '" + IntrinsicToBase[I].first +
           "' is mapped by multiple RuntimeLibcallFamily records ('" +
           IntrinsicToBase[I - 1].second + "' and '" +
           IntrinsicToBase[I].second + "')");
+    }
 
   MapVector<StringRef, SmallVector<StringRef, 2>> BaseToIntrinsics;
   for (auto [Intrinsic, Base] : IntrinsicToBase)
@@ -660,7 +661,18 @@ void RuntimeLibcallEmitter::emitGetLibcallForIntrinsic(
 
   OS << "RTLIB::Libcall "
         "llvm::RTLIB::RuntimeLibcallsInfo::getLibcallForIntrinsic("
-        "Intrinsic::ID ID, Type *Ty) {\n"
+        "Intrinsic::ID ID, FunctionType *FTy) {\n"
+        "  Type *Ty = FTy->getReturnType();\n"
+        "  if (!Ty->isFloatingPointTy()) {\n"
+        "    for (Type *ParamTy : FTy->params()) {\n"
+        "      if (ParamTy->isFloatingPointTy()) {\n"
+        "        Ty = ParamTy;\n"
+        "        break;\n"
+        "      }\n"
+        "    }\n"
+        "  }\n"
+        "  if (!Ty->isFloatingPointTy())\n"
+        "    return RTLIB::UNKNOWN_LIBCALL;\n"
         "  switch (ID) {\n";
 
   for (const auto &[Base, Intrinsics] : BaseToIntrinsics) {

>From 0a240b606f66f2f70645a4660816edad1b9cdb28 Mon Sep 17 00:00:00 2001
From: Joseph Huber <huberjn at outlook.com>
Date: Thu, 6 Aug 2026 11:46:29 -0500
Subject: [PATCH 3/3] Fixup for missing fns and better error check

---
 llvm/include/llvm/IR/RuntimeLibcalls.h        |  3 +-
 ...callEmitter-intrinsic-to-libcall-errors.td | 11 +++
 llvm/unittests/IR/RuntimeLibcallsTest.cpp     | 34 ++++++++
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 86 ++++++++++++-------
 4 files changed, 103 insertions(+), 31 deletions(-)

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 4a97f32e4fff2..affc8545ef91b 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -123,8 +123,7 @@ struct RuntimeLibcallsInfo {
   }
 
   /// Return the runtime libcall that the floating-point math intrinsic \p ID
-  /// operating on type \p Ty may be lowered to, or RTLIB::UNKNOWN_LIBCALL if
-  /// there is no such mapping.
+  /// may be lowered to, or RTLIB::UNKNOWN_LIBCALL if there is no such mapping.
   ///
   /// \p FTy must be the intrinsic's call signature.
   LLVM_ABI static RTLIB::Libcall getLibcallForIntrinsic(Intrinsic::ID ID,
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td
index a7d8ef3c74a3b..5016c66318f45 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-intrinsic-to-libcall-errors.td
@@ -1,11 +1,14 @@
 // RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include -DERR_DUP_INTRINSIC %s 2>&1 | FileCheck -check-prefix=ERR-DUP %s
 // RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include -DERR_NO_LIBCALL %s 2>&1 | FileCheck -check-prefix=ERR-NO-LIBCALL %s
+// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include -DERR_NO_LIBCALL_NO_INTRINSIC %s 2>&1 | FileCheck -check-prefix=ERR-NO-LIBCALL-NO-INTRIN %s
 
 include "llvm/IR/RuntimeLibcallsImpl.td"
 
 #ifdef ERR_DUP_INTRINSIC
 def SIN_F32 : RuntimeLibcall;
 def impl_sinf : RuntimeLibcallImpl<SIN_F32, "sinf">;
+def COS_F32 : RuntimeLibcall;
+def impl_cosf : RuntimeLibcallImpl<COS_F32, "cosf">;
 def : RuntimeLibcallFamily<"SIN", ["sin"]>;
 def : RuntimeLibcallFamily<"COS", ["sin"]>;
 
@@ -19,3 +22,11 @@ def : RuntimeLibcallFamily<"SIN", ["sin"]>;
 
 // ERR-NO-LIBCALL: error: no runtime libcall found for base name 'SIN'
 #endif
+
+#ifdef ERR_NO_LIBCALL_NO_INTRINSIC
+def COS_F32 : RuntimeLibcall;
+def impl_cosf : RuntimeLibcallImpl<COS_F32, "cosf">;
+def : RuntimeLibcallFamily<"SIN">;
+
+// ERR-NO-LIBCALL-NO-INTRIN: error: no runtime libcall found for base name 'SIN'
+#endif
diff --git a/llvm/unittests/IR/RuntimeLibcallsTest.cpp b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
index 35f525f2b0c41..22cff2ddfa610 100644
--- a/llvm/unittests/IR/RuntimeLibcallsTest.cpp
+++ b/llvm/unittests/IR/RuntimeLibcallsTest.cpp
@@ -134,6 +134,34 @@ TEST(RuntimeLibcallsTest, LibcallForIntrinsic) {
                                    ConstrainedUnarySig(Type::getDoubleTy(Ctx))),
       RTLIB::POW_F64);
 
+  // Intrinsics whose result is not the floating-point type resolve from the
+  // first floating-point argument instead.
+  Type *Dbl = Type::getDoubleTy(Ctx);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(
+                Intrinsic::lround,
+                FunctionType::get(Type::getInt32Ty(Ctx), {Dbl}, false)),
+            RTLIB::LROUND_F64);
+  EXPECT_EQ(Info::getLibcallForIntrinsic(
+                Intrinsic::llround,
+                FunctionType::get(Type::getInt64Ty(Ctx), {Dbl}, false)),
+            RTLIB::LLROUND_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(
+          Intrinsic::frexp,
+          FunctionType::get(StructType::get(Ctx, {Dbl, Type::getInt32Ty(Ctx)}),
+                            {Dbl}, false)),
+      RTLIB::FREXP_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(
+          Intrinsic::sincos,
+          FunctionType::get(StructType::get(Ctx, {Dbl, Dbl}), {Dbl}, false)),
+      RTLIB::SINCOS_F64);
+  EXPECT_EQ(
+      Info::getLibcallForIntrinsic(
+          Intrinsic::modf,
+          FunctionType::get(StructType::get(Ctx, {Dbl, Dbl}), {Dbl}, false)),
+      RTLIB::MODF_F64);
+
   // Unmapped intrinsic.
   EXPECT_EQ(Info::getLibcallForIntrinsic(Intrinsic::fabs,
                                          UnarySig(Type::getDoubleTy(Ctx))),
@@ -144,6 +172,12 @@ TEST(RuntimeLibcallsTest, LibcallForIntrinsic) {
                                          UnarySig(Type::getHalfTy(Ctx))),
             RTLIB::UNKNOWN_LIBCALL);
 
+  // Vectors are not currently mapped.
+  EXPECT_EQ(Info::getLibcallForIntrinsic(
+                Intrinsic::sin,
+                UnarySig(FixedVectorType::get(Type::getFloatTy(Ctx), 4))),
+            RTLIB::UNKNOWN_LIBCALL);
+
   // Mapped intrinsic, but a signature with no floating-point argument/result.
   auto *NonFPSig =
       FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, false);
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index b1bbf6b40d048..f4d83e472bdc3 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -89,14 +89,22 @@ class RuntimeLibcallEmitter {
 
   void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const;
 
+  DenseSet<StringRef> collectLibcallNames() const;
+
+  void checkFPLibcallFamilies(ArrayRef<FPLibcallFamily> Families,
+                              const DenseSet<StringRef> &LibcallNames) const;
+
   void emitFPLibcallSelectorDecls(raw_ostream &OS,
                                   ArrayRef<FPLibcallFamily> Families) const;
 
   void emitFPLibcallSelectors(raw_ostream &OS,
-                              ArrayRef<FPLibcallFamily> Families) const;
+                              ArrayRef<FPLibcallFamily> Families,
+                              const DenseSet<StringRef> &LibcallNames) const;
 
-  void emitGetLibcallForIntrinsic(raw_ostream &OS,
-                                  ArrayRef<FPLibcallFamily> Families) const;
+  void
+  emitGetLibcallForIntrinsic(raw_ostream &OS,
+                             ArrayRef<FPLibcallFamily> Families,
+                             const DenseSet<StringRef> &LibcallNames) const;
 
 public:
   RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R), Libcalls(R) {}
@@ -578,6 +586,42 @@ collectFPLibcallFamilies(const RecordKeeper &Records) {
   return Families;
 }
 
+DenseSet<StringRef> RuntimeLibcallEmitter::collectLibcallNames() const {
+  DenseSet<StringRef> LibcallNames;
+  for (const RuntimeLibcall &LC : Libcalls.getRuntimeLibcallDefList())
+    LibcallNames.insert(LC.getName());
+  return LibcallNames;
+}
+
+void RuntimeLibcallEmitter::checkFPLibcallFamilies(
+    ArrayRef<FPLibcallFamily> Families,
+    const DenseSet<StringRef> &LibcallNames) const {
+  std::vector<std::pair<StringRef, StringRef>> IntrinsicToBase;
+  for (const FPLibcallFamily &Family : Families)
+    for (StringRef Intrinsic : Family.Intrinsics)
+      IntrinsicToBase.emplace_back(Intrinsic, Family.Base);
+  llvm::sort(IntrinsicToBase);
+
+  for (size_t I = 1, E = IntrinsicToBase.size(); I < E; ++I) {
+    if (IntrinsicToBase[I].first == IntrinsicToBase[I - 1].first)
+      PrintFatalError(
+          "intrinsic '" + IntrinsicToBase[I].first +
+          "' is mapped by multiple RuntimeLibcallFamily records ('" +
+          IntrinsicToBase[I - 1].second + "' and '" +
+          IntrinsicToBase[I].second + "')");
+  }
+
+  for (const FPLibcallFamily &Family : Families) {
+    bool AnyScalarLibcall = any_of(
+        ScalarFPSuffixes, [&](const std::pair<StringRef, StringRef> &Entry) {
+          return LibcallNames.contains((Family.Base + "_" + Entry.first).str());
+        });
+    if (!AnyScalarLibcall)
+      PrintFatalError("no runtime libcall found for base name '" + Family.Base +
+                      "'");
+  }
+}
+
 /// Generate the declarations for the RTLIB::get<base>(EVT) selectors.
 void RuntimeLibcallEmitter::emitFPLibcallSelectorDecls(
     raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
@@ -589,16 +633,13 @@ void RuntimeLibcallEmitter::emitFPLibcallSelectorDecls(
 /// Generate the backend RTLIB::get<base>(EVT) selectors from the floating-point
 /// libcall families.
 void RuntimeLibcallEmitter::emitFPLibcallSelectors(
-    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
+    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families,
+    const DenseSet<StringRef> &LibcallNames) const {
   IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_FP_SELECTORS");
 
   // Only emit a libcall enumerator if it actually exists in the declared set.
-  DenseSet<StringRef> ExistingLibcalls;
-  for (const RuntimeLibcall &LC : Libcalls.getRuntimeLibcallDefList())
-    ExistingLibcalls.insert(LC.getName());
-
   auto scalarEnum = [&](StringRef Base, StringRef Suffix) -> std::string {
-    if (ExistingLibcalls.contains((Base + "_" + Suffix).str()))
+    if (LibcallNames.contains((Base + "_" + Suffix).str()))
       return ("RTLIB::" + Base + "_" + Suffix).str();
     return "RTLIB::UNKNOWN_LIBCALL";
   };
@@ -633,28 +674,16 @@ void RuntimeLibcallEmitter::emitFPLibcallSelectors(
 /// they may lower to, keyed by intrinsic ID and floating-point type. This is
 /// the IR-level counterpart to the backend's RTLIB::getXXX(EVT) selectors.
 void RuntimeLibcallEmitter::emitGetLibcallForIntrinsic(
-    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families) const {
+    raw_ostream &OS, ArrayRef<FPLibcallFamily> Families,
+    const DenseSet<StringRef> &LibcallNames) const {
   IfDefEmitter IfDef(OS, "GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL");
 
-  DenseSet<StringRef> ExistingLibcalls;
-  for (const RuntimeLibcall &LC : Libcalls.getRuntimeLibcallDefList())
-    ExistingLibcalls.insert(LC.getName());
-
   std::vector<std::pair<StringRef, StringRef>> IntrinsicToBase;
   for (const FPLibcallFamily &Family : Families)
     for (StringRef Intrinsic : Family.Intrinsics)
       IntrinsicToBase.emplace_back(Intrinsic, Family.Base);
   llvm::sort(IntrinsicToBase);
 
-  for (size_t I = 1, E = IntrinsicToBase.size(); I < E; ++I)
-    if (IntrinsicToBase[I].first == IntrinsicToBase[I - 1].first) {
-      PrintFatalError(
-          "intrinsic '" + IntrinsicToBase[I].first +
-          "' is mapped by multiple RuntimeLibcallFamily records ('" +
-          IntrinsicToBase[I - 1].second + "' and '" +
-          IntrinsicToBase[I].second + "')");
-    }
-
   MapVector<StringRef, SmallVector<StringRef, 2>> BaseToIntrinsics;
   for (auto [Intrinsic, Base] : IntrinsicToBase)
     BaseToIntrinsics[Base].push_back(Intrinsic);
@@ -678,12 +707,9 @@ void RuntimeLibcallEmitter::emitGetLibcallForIntrinsic(
   for (const auto &[Base, Intrinsics] : BaseToIntrinsics) {
     SmallVector<std::pair<StringRef, StringRef>, 5> Arms;
     for (auto [Suffix, Pred] : ScalarFPSuffixes)
-      if (ExistingLibcalls.contains((Base + "_" + Suffix).str()))
+      if (LibcallNames.contains((Base + "_" + Suffix).str()))
         Arms.emplace_back(Suffix, Pred);
 
-    if (Arms.empty())
-      PrintFatalError("no runtime libcall found for base name '" + Base + "'");
-
     for (StringRef Intrinsic : Intrinsics)
       OS << "  case Intrinsic::" << Intrinsic << ":\n";
     for (auto [Suffix, Pred] : Arms)
@@ -710,9 +736,11 @@ void RuntimeLibcallEmitter::run(raw_ostream &OS) {
   }
 
   std::vector<FPLibcallFamily> FPFamilies = collectFPLibcallFamilies(Records);
+  DenseSet<StringRef> LibcallNames = collectLibcallNames();
+  checkFPLibcallFamilies(FPFamilies, LibcallNames);
   emitFPLibcallSelectorDecls(OS, FPFamilies);
-  emitFPLibcallSelectors(OS, FPFamilies);
-  emitGetLibcallForIntrinsic(OS, FPFamilies);
+  emitFPLibcallSelectors(OS, FPFamilies, LibcallNames);
+  emitGetLibcallForIntrinsic(OS, FPFamilies, LibcallNames);
 }
 
 static TableGen::Emitter::OptClass<RuntimeLibcallEmitter>



More information about the llvm-commits mailing list