[llvm-branch-commits] [llvm] TableGen: Allow defining sets of runtime libraries (PR #144978)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jun 19 19:50:40 PDT 2025


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

Add a way to define a SystemLibrary for a complete set of
libcalls, subdivided by a predicate based on the triple.
Libraries can be defined using dag set operations, and the
prior default set can be subtracted from and added to (though
I think eventually all targets should move to explicit opt-ins.
We're still doing things like reporting ppcf128 libcalls as
available dy default on all targets).

Start migrating some of the easier targets to only use the new
system. Targets that don't define a SystemLibrary are still
manually mutating a table set to the old defaults.

As a side effect, also fixes a missing # prefix for the windows
arm64ec case when emitting __arm_sc libcalls.

>From f5f142d6ecc0c42974023c1eb6294004ad192272 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sat, 7 Jun 2025 20:57:31 +0900
Subject: [PATCH] TableGen: Allow defining sets of runtime libraries

Add a way to define a SystemLibrary for a complete set of
libcalls, subdivided by a predicate based on the triple.
Libraries can be defined using dag set operations, and the
prior default set can be subtracted from and added to (though
I think eventually all targets should move to explicit opt-ins.
We're still doing things like reporting ppcf128 libcalls as
available dy default on all targets).

Start migrating some of the easier targets to only use the new
system. Targets that don't define a SystemLibrary are still
manually mutating a table set to the old defaults.
---
 llvm/include/llvm/IR/RuntimeLibcalls.h        |  10 +-
 llvm/include/llvm/IR/RuntimeLibcalls.td       | 493 +++++++++++-------
 llvm/include/llvm/IR/RuntimeLibcallsImpl.td   |  36 ++
 llvm/include/llvm/TableGen/SetTheory.td       |  27 +
 llvm/lib/IR/RuntimeLibcalls.cpp               | 127 +----
 .../RuntimeLibcallEmitter-conflict-warning.td |  60 +++
 ...eLibcallEmitter-nested-predicates-error.td |  18 +
 llvm/test/TableGen/RuntimeLibcallEmitter.td   | 185 ++++++-
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 351 +++++++++----
 9 files changed, 889 insertions(+), 418 deletions(-)
 create mode 100644 llvm/include/llvm/TableGen/SetTheory.td
 create mode 100644 llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
 create mode 100644 llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 912715fbf6b19..d69c23753da7a 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -52,7 +52,6 @@ struct RuntimeLibcallsInfo {
       FloatABI::ABIType FloatABI = FloatABI::Default,
       EABI EABIVersion = EABI::Default) {
     initSoftFloatCmpLibcallPredicates();
-    initDefaultLibCallImpls();
     initLibcalls(TT, ExceptionModel, FloatABI, EABIVersion);
   }
 
@@ -97,6 +96,7 @@ struct RuntimeLibcallsInfo {
   /// Get the comparison predicate that's to be used to test the result of the
   /// comparison libcall against zero. This should only be used with
   /// floating-point compare libcalls.
+  // FIXME: This should be a function of RTLIB::LibcallImpl
   CmpInst::Predicate
   getSoftFloatCmpLibcallPredicate(RTLIB::Libcall Call) const {
     return SoftFloatCompareLibcallPredicates[Call];
@@ -172,13 +172,7 @@ struct RuntimeLibcallsInfo {
   void initDefaultLibCallImpls();
 
   /// Generated by tablegen.
-  void setPPCLibCallNameOverrides();
-
-  /// Generated by tablegen.
-  void setZOSLibCallNameOverrides();
-
-  /// Generated by tablegen.
-  void setWindowsArm64LibCallNameOverrides();
+  void setTargetRuntimeLibcallSets(const Triple &TT);
 
   void initSoftFloatCmpLibcallPredicates();
 
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index 1d9f02dcf8ba8..e24b4c928b421 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -891,6 +891,17 @@ def calloc : RuntimeLibcallImpl<CALLOC>;
 } // End let IsDefault = true
 } // End defset DefaultRuntimeLibcallImpls
 
+defvar DefaultLibCalls =
+    !foreach(entry, DefaultRuntimeLibcallImpls, entry.Provides);
+
+defvar DefaultRuntimeLibcallImpls_f128 =
+    !filter(entry, DefaultRuntimeLibcallImpls,
+            !match(!cast<string>(entry.Provides), "_F128"));
+
+defvar DefaultRuntimeLibcallImpls_atomic =
+    !filter(entry, DefaultRuntimeLibcallImpls,
+            !match(!cast<string>(entry.Provides), "ATOMIC"));
+
 //--------------------------------------------------------------------
 // Define implementation other libcalls
 //--------------------------------------------------------------------
@@ -915,58 +926,61 @@ def _Unwind_SjLj_Resume : RuntimeLibcallImpl<UNWIND_RESUME>;
 // F128 libm Runtime Libcalls
 //===----------------------------------------------------------------------===//
 
-def logf128 : RuntimeLibcallImpl<LOG_F128>;
-def log2f128 : RuntimeLibcallImpl<LOG2_F128>;
-def log10f128 : RuntimeLibcallImpl<LOG10_F128>;
-def expf128 : RuntimeLibcallImpl<EXP_F128>;
-def exp2f128 : RuntimeLibcallImpl<EXP2_F128>;
-def exp10f128 : RuntimeLibcallImpl<EXP10_F128>;
-def sinf128 : RuntimeLibcallImpl<SIN_F128>;
-def cosf128 : RuntimeLibcallImpl<COS_F128>;
-def tanf128 : RuntimeLibcallImpl<TAN_F128>;
-def tanhf128 : RuntimeLibcallImpl<TANH_F128>;
-def sincosf128 : RuntimeLibcallImpl<SINCOS_F128>;
-def powf128 : RuntimeLibcallImpl<POW_F128>;
-def fminf128 : RuntimeLibcallImpl<FMIN_F128>;
-def fmaxf128 : RuntimeLibcallImpl<FMAX_F128>;
-def fmodf128 : RuntimeLibcallImpl<REM_F128>;
-def sqrtf128 : RuntimeLibcallImpl<SQRT_F128>;
-def ceilf128 : RuntimeLibcallImpl<CEIL_F128>;
-def floorf128 : RuntimeLibcallImpl<FLOOR_F128>;
-def truncf128 : RuntimeLibcallImpl<TRUNC_F128>;
-def roundf128 : RuntimeLibcallImpl<ROUND_F128>;
-def lroundf128 : RuntimeLibcallImpl<LROUND_F128>;
-def llroundf128 : RuntimeLibcallImpl<LLROUND_F128>;
-def rintf128 : RuntimeLibcallImpl<RINT_F128>;
-def lrintf128 : RuntimeLibcallImpl<LRINT_F128>;
-def llrintf128 : RuntimeLibcallImpl<LLRINT_F128>;
-def nearbyintf128 : RuntimeLibcallImpl<NEARBYINT_F128>;
-def fmaf128 : RuntimeLibcallImpl<FMA_F128>;
-def frexpf128 : RuntimeLibcallImpl<FREXP_F128>;
-
-def cbrtf128 : RuntimeLibcallImpl<CBRT_F128>;
-def fminimumf128 : RuntimeLibcallImpl<FMINIMUM_F128>;
-def fmaximumf128 : RuntimeLibcallImpl<FMAXIMUM_F128>;
-def fminimum_numf128 : RuntimeLibcallImpl<FMINIMUM_NUM_F128>;
-def fmaximum_numf128 : RuntimeLibcallImpl<FMAXIMUM_NUM_F128>;
-def asinf128 : RuntimeLibcallImpl<ASIN_F128>;
-def acosf128 : RuntimeLibcallImpl<ACOS_F128>;
-def atanf128 : RuntimeLibcallImpl<ATAN_F128>;
-def atan2f128 : RuntimeLibcallImpl<ATAN2_F128>;
-def ldexpf128 : RuntimeLibcallImpl<LDEXP_F128>;
-def roundevenf128 : RuntimeLibcallImpl<ROUNDEVEN_F128>;
-def modff128 : RuntimeLibcallImpl<MODF_F128>;
-def sinhf128 : RuntimeLibcallImpl<SINH_F128>;
-def coshf128 : RuntimeLibcallImpl<COSH_F128>;
-def copysignf128 : RuntimeLibcallImpl<COPYSIGN_F128>;
-
-def __logf128_finite : RuntimeLibcallImpl<LOG_FINITE_F128>;
-def __log2f128_finite : RuntimeLibcallImpl<LOG2_FINITE_F128>;
-def __log10f128_finite : RuntimeLibcallImpl<LOG10_FINITE_F128>;
-def __expf128_finite : RuntimeLibcallImpl<EXP_FINITE_F128>;
-def __exp2f128_finite : RuntimeLibcallImpl<EXP2_FINITE_F128>;
-def __exp10f128_finite : RuntimeLibcallImpl<EXP10_FINITE_F128>;
-def __powf128_finite : RuntimeLibcallImpl<POW_FINITE_F128>;
+defset list<RuntimeLibcallImpl> LibmF128Libcalls = {
+  def logf128 : RuntimeLibcallImpl<LOG_F128>;
+  def log2f128 : RuntimeLibcallImpl<LOG2_F128>;
+  def log10f128 : RuntimeLibcallImpl<LOG10_F128>;
+  def expf128 : RuntimeLibcallImpl<EXP_F128>;
+  def exp2f128 : RuntimeLibcallImpl<EXP2_F128>;
+  def exp10f128 : RuntimeLibcallImpl<EXP10_F128>;
+  def sinf128 : RuntimeLibcallImpl<SIN_F128>;
+  def cosf128 : RuntimeLibcallImpl<COS_F128>;
+  def tanf128 : RuntimeLibcallImpl<TAN_F128>;
+  def tanhf128 : RuntimeLibcallImpl<TANH_F128>;
+  def sincosf128 : RuntimeLibcallImpl<SINCOS_F128>;
+  def powf128 : RuntimeLibcallImpl<POW_F128>;
+  def fminf128 : RuntimeLibcallImpl<FMIN_F128>;
+  def fmaxf128 : RuntimeLibcallImpl<FMAX_F128>;
+  def fmodf128 : RuntimeLibcallImpl<REM_F128>;
+  def sqrtf128 : RuntimeLibcallImpl<SQRT_F128>;
+  def ceilf128 : RuntimeLibcallImpl<CEIL_F128>;
+  def floorf128 : RuntimeLibcallImpl<FLOOR_F128>;
+  def truncf128 : RuntimeLibcallImpl<TRUNC_F128>;
+  def roundf128 : RuntimeLibcallImpl<ROUND_F128>;
+  def lroundf128 : RuntimeLibcallImpl<LROUND_F128>;
+  def llroundf128 : RuntimeLibcallImpl<LLROUND_F128>;
+  def rintf128 : RuntimeLibcallImpl<RINT_F128>;
+  def lrintf128 : RuntimeLibcallImpl<LRINT_F128>;
+  def llrintf128 : RuntimeLibcallImpl<LLRINT_F128>;
+  def nearbyintf128 : RuntimeLibcallImpl<NEARBYINT_F128>;
+  def fmaf128 : RuntimeLibcallImpl<FMA_F128>;
+  def frexpf128 : RuntimeLibcallImpl<FREXP_F128>;
+  def cbrtf128 : RuntimeLibcallImpl<CBRT_F128>;
+  def fminimumf128 : RuntimeLibcallImpl<FMINIMUM_F128>;
+  def fmaximumf128 : RuntimeLibcallImpl<FMAXIMUM_F128>;
+  def fminimum_numf128 : RuntimeLibcallImpl<FMINIMUM_NUM_F128>;
+  def fmaximum_numf128 : RuntimeLibcallImpl<FMAXIMUM_NUM_F128>;
+  def asinf128 : RuntimeLibcallImpl<ASIN_F128>;
+  def acosf128 : RuntimeLibcallImpl<ACOS_F128>;
+  def atanf128 : RuntimeLibcallImpl<ATAN_F128>;
+  def atan2f128 : RuntimeLibcallImpl<ATAN2_F128>;
+  def ldexpf128 : RuntimeLibcallImpl<LDEXP_F128>;
+  def roundevenf128 : RuntimeLibcallImpl<ROUNDEVEN_F128>;
+  def modff128 : RuntimeLibcallImpl<MODF_F128>;
+  def sinhf128 : RuntimeLibcallImpl<SINH_F128>;
+  def coshf128 : RuntimeLibcallImpl<COSH_F128>;
+  def copysignf128 : RuntimeLibcallImpl<COPYSIGN_F128>;
+}
+
+defset list<RuntimeLibcallImpl> LibmF128FiniteLibcalls = {
+  def __logf128_finite : RuntimeLibcallImpl<LOG_FINITE_F128>;
+  def __log2f128_finite : RuntimeLibcallImpl<LOG2_FINITE_F128>;
+  def __log10f128_finite : RuntimeLibcallImpl<LOG10_FINITE_F128>;
+  def __expf128_finite : RuntimeLibcallImpl<EXP_FINITE_F128>;
+  def __exp2f128_finite : RuntimeLibcallImpl<EXP2_FINITE_F128>;
+  def __exp10f128_finite : RuntimeLibcallImpl<EXP10_FINITE_F128>;
+  def __powf128_finite : RuntimeLibcallImpl<POW_FINITE_F128>;
+}
 
 //===----------------------------------------------------------------------===//
 // AArch64 Runtime Libcalls
@@ -994,16 +1008,41 @@ defset list<RuntimeLibcallImpl> AArch64LibcallImpls = {
   def __arm_sc_memcpy : RuntimeLibcallImpl<SC_MEMCPY>;
   def __arm_sc_memmove : RuntimeLibcallImpl<SC_MEMMOVE>;
   def __arm_sc_memset : RuntimeLibcallImpl<SC_MEMSET>;
-}
+} // End AArch64LibcallImpls
 
-foreach libcall = AArch64LibcallImpls in {
-  def arm64ec_#libcall : DuplicateLibcallImplWithPrefix<libcall, "#">;
-}
+def isAArch64_ExceptArm64EC
+    : RuntimeLibcallPredicate<"(TT.isAArch64() && !TT.isWindowsArm64EC())">;
+def isWindowsArm64EC : RuntimeLibcallPredicate<"TT.isWindowsArm64EC()">;
+
+def AArch64SystemLibrary : SystemRuntimeLibrary<isAArch64_ExceptArm64EC,
+                                                (add DefaultRuntimeLibcallImpls,
+                                                    AArch64LibcallImpls)>;
 
-foreach libcall = DefaultRuntimeLibcallImpls in {
-  def arm64ec_#libcall : DuplicateLibcallImplWithPrefix<libcall, "#">;
+// Prepend a # to every name
+defset list<RuntimeLibcallImpl> WinArm64ECDefaultRuntimeLibcallImpls = {
+  foreach libcall = DefaultRuntimeLibcallImpls in {
+    def arm64ec_#libcall : DuplicateLibcallImplWithPrefix<libcall, "#">;
+  }
+
+  foreach libcall = AArch64LibcallImpls in {
+    def arm64ec_#libcall : DuplicateLibcallImplWithPrefix<libcall, "#">;
+  }
 }
 
+def WindowsARM64ECSystemLibrary
+    : SystemRuntimeLibrary<isWindowsArm64EC,
+                           (add WinArm64ECDefaultRuntimeLibcallImpls)>;
+
+//===----------------------------------------------------------------------===//
+// AMDGPU Runtime Libcalls
+//===----------------------------------------------------------------------===//
+
+def isAMDGPU : RuntimeLibcallPredicate<"TT.isAMDGPU()">;
+
+// No calls, except for dummy atomic calls to avoid crashes.
+def AMDGPUSystemLibrary
+    : SystemRuntimeLibrary<isAMDGPU, (add DefaultRuntimeLibcallImpls_atomic)>;
+
 //===----------------------------------------------------------------------===//
 // ARM Runtime Libcalls
 //===----------------------------------------------------------------------===//
@@ -1227,6 +1266,30 @@ def __udivmodhi4 : RuntimeLibcallImpl<UDIVREM_I16>; // CallingConv::AVR_BUILTIN
 def avr_sin : RuntimeLibcallImpl<SIN_F32, "sin">;
 def avr_cos : RuntimeLibcallImpl<COS_F32, "cos">;
 
+def isAVR : RuntimeLibcallPredicate<"TT.getArch() == Triple::avr">;
+
+def AVRSystemLibrary
+    : SystemRuntimeLibrary<
+          isAVR,
+          (add(sub DefaultRuntimeLibcallImpls,
+
+               // Division rtlib functions (not supported), use divmod
+               // functions instead
+               __divqi3, __divhi3, __divsi3, __udivqi3, __udivhi3, __udivsi3,
+
+               // Modulus rtlib functions (not supported), use divmod functions
+               // instead
+               __modqi3, __modhi3, __modsi3, __umodqi3, __umodhi3, __umodsi3,
+
+               // Standard f64 names are replaced
+               sin, cos, sinf, cosf),
+
+              __divmodqi4, __divmodhi4, __divmodsi4, __udivmodqi4, __udivmodhi4,
+              __udivmodsi4,
+
+              // Trigonometric rtlib functions
+              avr_sin, avr_cos)>;
+
 //===----------------------------------------------------------------------===//
 // Hexagon Runtime Libcalls
 //===----------------------------------------------------------------------===//
@@ -1447,52 +1510,94 @@ def __mspabi_mpyll : RuntimeLibcallImpl<MUL_I64>;
 // setLibcallCallingConv(MUL_I64, CallingConv::MSP430_BUILTIN);
 
 //===----------------------------------------------------------------------===//
-// PPC Runtime Libcalls
+// NVPTX Runtime Libcalls
 //===----------------------------------------------------------------------===//
 
-class PPCRuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME>
-    : RuntimeLibcallImpl<P, Name>;
+def isNVPTX : RuntimeLibcallPredicate<"TT.isNVPTX()">;
+
+// No calls, except for dummy atomic calls to avoid crashes.
+def NVPTXSystemLibrary
+    : SystemRuntimeLibrary<isNVPTX, (add DefaultRuntimeLibcallImpls_atomic)>;
+
+//===----------------------------------------------------------------------===//
+// PPC Runtime Libcalls
+//===----------------------------------------------------------------------===//
 
 // For IEEE quad-precision libcall names, PPC uses "kf" instead of "tf".
-def __addkf3 : PPCRuntimeLibcallImpl<ADD_F128>;
-def __subkf3 : PPCRuntimeLibcallImpl<SUB_F128>;
-def __mulkf3 : PPCRuntimeLibcallImpl<MUL_F128>;
-def __divkf3 : PPCRuntimeLibcallImpl<DIV_F128>;
-def __powikf2 : PPCRuntimeLibcallImpl<POWI_F128>;
-def __extendsfkf2 : PPCRuntimeLibcallImpl<FPEXT_F32_F128>;
-def __extenddfkf2 : PPCRuntimeLibcallImpl<FPEXT_F64_F128>;
-def __trunckfhf2 : PPCRuntimeLibcallImpl<FPROUND_F128_F16>;
-def __trunckfsf2 : PPCRuntimeLibcallImpl<FPROUND_F128_F32>;
-def __trunckfdf2 : PPCRuntimeLibcallImpl<FPROUND_F128_F64>;
-def __fixkfsi : PPCRuntimeLibcallImpl<FPTOSINT_F128_I32>;
-def __fixkfdi : PPCRuntimeLibcallImpl<FPTOSINT_F128_I64>;
-def __fixkfti : PPCRuntimeLibcallImpl<FPTOSINT_F128_I128>;
-def __fixunskfsi : PPCRuntimeLibcallImpl<FPTOUINT_F128_I32>;
-def __fixunskfdi : PPCRuntimeLibcallImpl<FPTOUINT_F128_I64>;
-def __fixunskfti : PPCRuntimeLibcallImpl<FPTOUINT_F128_I128>;
-def __floatsikf : PPCRuntimeLibcallImpl<SINTTOFP_I32_F128>;
-def __floatdikf : PPCRuntimeLibcallImpl<SINTTOFP_I64_F128>;
-def __floattikf : PPCRuntimeLibcallImpl<SINTTOFP_I128_F128>;
-def __floatunsikf : PPCRuntimeLibcallImpl<UINTTOFP_I32_F128>;
-def __floatundikf : PPCRuntimeLibcallImpl<UINTTOFP_I64_F128>;
-def __floatuntikf : PPCRuntimeLibcallImpl<UINTTOFP_I128_F128>;
-def __eqkf2 : PPCRuntimeLibcallImpl<OEQ_F128>;
-def __nekf2 : PPCRuntimeLibcallImpl<UNE_F128>;
-def __gekf2 : PPCRuntimeLibcallImpl<OGE_F128>;
-def __ltkf2 : PPCRuntimeLibcallImpl<OLT_F128>;
-def __lekf2 : PPCRuntimeLibcallImpl<OLE_F128>;
-def __gtkf2 : PPCRuntimeLibcallImpl<OGT_F128>;
-def __unordkf2 : PPCRuntimeLibcallImpl<UO_F128>;
-
-// PPC64 && Subtarget.isAIXABI()
-def ___memmove64 : RuntimeLibcallImpl<MEMCPY>;
-def ___memset64 : RuntimeLibcallImpl<MEMSET>;
-def ___bzero64 : RuntimeLibcallImpl<BZERO>;
-
-// !PPC64 && Subtarget.isAIXABI()
-def ___memmove : RuntimeLibcallImpl<MEMMOVE>;
-def ___memset : RuntimeLibcallImpl<MEMSET>;
-def ___bzero : RuntimeLibcallImpl<BZERO>;
+defset list<RuntimeLibcallImpl> PPCRuntimeLibcalls = {
+  def __addkf3 : RuntimeLibcallImpl<ADD_F128>;
+  def __subkf3 : RuntimeLibcallImpl<SUB_F128>;
+  def __mulkf3 : RuntimeLibcallImpl<MUL_F128>;
+  def __divkf3 : RuntimeLibcallImpl<DIV_F128>;
+  def __powikf2 : RuntimeLibcallImpl<POWI_F128>;
+  def __extendsfkf2 : RuntimeLibcallImpl<FPEXT_F32_F128>;
+  def __extenddfkf2 : RuntimeLibcallImpl<FPEXT_F64_F128>;
+  def __trunckfhf2 : RuntimeLibcallImpl<FPROUND_F128_F16>;
+  def __trunckfsf2 : RuntimeLibcallImpl<FPROUND_F128_F32>;
+  def __trunckfdf2 : RuntimeLibcallImpl<FPROUND_F128_F64>;
+  def __fixkfsi : RuntimeLibcallImpl<FPTOSINT_F128_I32>;
+  def __fixkfdi : RuntimeLibcallImpl<FPTOSINT_F128_I64>;
+  def __fixkfti : RuntimeLibcallImpl<FPTOSINT_F128_I128>;
+  def __fixunskfsi : RuntimeLibcallImpl<FPTOUINT_F128_I32>;
+  def __fixunskfdi : RuntimeLibcallImpl<FPTOUINT_F128_I64>;
+  def __fixunskfti : RuntimeLibcallImpl<FPTOUINT_F128_I128>;
+  def __floatsikf : RuntimeLibcallImpl<SINTTOFP_I32_F128>;
+  def __floatdikf : RuntimeLibcallImpl<SINTTOFP_I64_F128>;
+  def __floattikf : RuntimeLibcallImpl<SINTTOFP_I128_F128>;
+  def __floatunsikf : RuntimeLibcallImpl<UINTTOFP_I32_F128>;
+  def __floatundikf : RuntimeLibcallImpl<UINTTOFP_I64_F128>;
+  def __floatuntikf : RuntimeLibcallImpl<UINTTOFP_I128_F128>;
+  def __eqkf2 : RuntimeLibcallImpl<OEQ_F128>;
+  def __nekf2 : RuntimeLibcallImpl<UNE_F128>;
+  def __gekf2 : RuntimeLibcallImpl<OGE_F128>;
+  def __ltkf2 : RuntimeLibcallImpl<OLT_F128>;
+  def __lekf2 : RuntimeLibcallImpl<OLE_F128>;
+  def __gtkf2 : RuntimeLibcallImpl<OGT_F128>;
+  def __unordkf2 : RuntimeLibcallImpl<UO_F128>;
+}
+
+defset list<RuntimeLibcallImpl> PPC64AIXCallList = {
+  def ___memmove64 : RuntimeLibcallImpl<MEMCPY>;
+  def ___memset64 : RuntimeLibcallImpl<MEMSET>;
+  def ___bzero64 : RuntimeLibcallImpl<BZERO>;
+}
+
+defset list<RuntimeLibcallImpl> PPC32AIXCallList = {
+  def ___memmove : RuntimeLibcallImpl<MEMMOVE>;
+  def ___memset : RuntimeLibcallImpl<MEMSET>;
+  def ___bzero : RuntimeLibcallImpl<BZERO>;
+}
+
+defvar PPCOverrides = !foreach(entry, PPCRuntimeLibcalls, entry.Provides);
+
+defvar ToPrune = !listremove(DefaultLibCalls, PPCOverrides);
+//  DefaultLibcalls item.Provides
+//);
+
+// defvar PPCOverride = !foldl([], DefaultRuntimeLibcallImpls, acc, item,
+//     !eq(item.Provides,
+//);
+
+def isPPC : RuntimeLibcallPredicate<"TT.isPPC()">;
+def isAIX : RuntimeLibcallPredicate<"TT.isOSAIX()">;
+def isNotAIX : RuntimeLibcallPredicate<"!TT.isOSAIX()">;
+def isPPC32_AIX : RuntimeLibcallPredicate<"(TT.isPPC32() && TT.isOSAIX())">;
+def isPPC64_AIX : RuntimeLibcallPredicate<"(TT.isPPC64() && TT.isOSAIX())">;
+
+def AIX32Calls : LibcallImpls<(add PPC32AIXCallList), isPPC32_AIX>;
+def AIX64Calls : LibcallImpls<(add PPC64AIXCallList), isPPC64_AIX>;
+
+// FIXME: Current emission behavior with multiple implementations is
+// janky. We need to filter out the conflicting cases with different
+// f128 names, and then add the overrides. We should switch to
+// explicitly adding subsets of the default calls.
+def PPCSystemLibrary
+    : SystemRuntimeLibrary<isPPC, (add PPCRuntimeLibcalls,
+                                      (sub DefaultRuntimeLibcallImpls, memcpy,
+                                          DefaultRuntimeLibcallImpls_f128),
+                                      __extendkftf2, __trunctfkf2,
+                                      LibmF128Libcalls, AIX32Calls, AIX64Calls,
+                                      AvailableIf<memcpy, isNotAIX>)>;
 
 //===----------------------------------------------------------------------===//
 // SPARC Runtime Libcalls
@@ -1562,94 +1667,105 @@ def _allmul : RuntimeLibcallImpl<MUL_I64>; // CallingConv::X86_StdCall
 
 def __memcpy_4 : RuntimeLibcallImpl<MEMCPY_ALIGN_4>;
 
+def isXCore : RuntimeLibcallPredicate<"TT.getArch() == Triple::xcore">;
+def XCoreSystemLibrary
+    : SystemRuntimeLibrary<isXCore, (add DefaultRuntimeLibcallImpls,
+                                        __memcpy_4)>;
+
 //===----------------------------------------------------------------------===//
 // ZOS Runtime Libcalls
 //===----------------------------------------------------------------------===//
 
-class ZOSRuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME>
-    : RuntimeLibcallImpl<P, Name>;
-
-def zos___TRNC_B : ZOSRuntimeLibcallImpl<TRUNC_F64, "@@TRNC at B">;
-def zos___FTRC_B : ZOSRuntimeLibcallImpl<TRUNC_F32, "@@FTRC at B">;
-def zos___LTRC_B : ZOSRuntimeLibcallImpl<TRUNC_F128, "@@LTRC at B">;
-def zos___WSQT_B : ZOSRuntimeLibcallImpl<SQRT_F64, "@@WSQT at B">;
-def zos___FSQT_B : ZOSRuntimeLibcallImpl<SQRT_F32, "@@FSQT at B">;
-def zos___LSQT_B : ZOSRuntimeLibcallImpl<SQRT_F128, "@@LSQT at B">;
-def zos___SSIN_B : ZOSRuntimeLibcallImpl<SIN_F64, "@@SSIN at B">;
-def zos___FSIN_B : ZOSRuntimeLibcallImpl<SIN_F32, "@@FSIN at B">;
-def zos___LSIN_B : ZOSRuntimeLibcallImpl<SIN_F128, "@@LSIN at B">;
-def zos___ROUN_B : ZOSRuntimeLibcallImpl<ROUND_F64, "@@ROUN at B">;
-def zos___ROUNFB : ZOSRuntimeLibcallImpl<ROUND_F32, "@@ROUNFB">;
-def zos___ROUNLB : ZOSRuntimeLibcallImpl<ROUND_F128, "@@ROUNLB">;
-def zos___SRNT_B : ZOSRuntimeLibcallImpl<RINT_F64, "@@SRNT at B">;
-def zos___RINTFB : ZOSRuntimeLibcallImpl<RINT_F32, "@@RINTFB">;
-def zos___RINTLB : ZOSRuntimeLibcallImpl<RINT_F128, "@@RINTLB">;
-def zos___WFMD_B : ZOSRuntimeLibcallImpl<REM_F64, "@@WFMD at B">;
-def zos___FFMD_B : ZOSRuntimeLibcallImpl<REM_F32, "@@FFMD at B">;
-def zos___LFMD_B : ZOSRuntimeLibcallImpl<REM_F128, "@@LFMD at B">;
-def zos___WPOW_B : ZOSRuntimeLibcallImpl<POW_F64, "@@WPOW at B">;
-def zos___FPOW_B : ZOSRuntimeLibcallImpl<POW_F32, "@@FPOW at B">;
-def zos___LPOW_B : ZOSRuntimeLibcallImpl<POW_F128, "@@LPOW at B">;
-def zos___NBYI_B : ZOSRuntimeLibcallImpl<NEARBYINT_F64, "@@NBYI at B">;
-def zos___NBYIFB : ZOSRuntimeLibcallImpl<NEARBYINT_F32, "@@NBYIFB">;
-def zos___NBYILB : ZOSRuntimeLibcallImpl<NEARBYINT_F128, "@@NBYILB">;
-def zos___ROND_B : ZOSRuntimeLibcallImpl<LROUND_F64, "@@ROND at B">;
-def zos___FRND_B : ZOSRuntimeLibcallImpl<LROUND_F32, "@@FRND at B">;
-def zos___LRND_B : ZOSRuntimeLibcallImpl<LROUND_F128, "@@LRND at B">;
-def zos___LRNT_B : ZOSRuntimeLibcallImpl<LRINT_F64, "@@LRNT at B">;
-def zos___LRNTFB : ZOSRuntimeLibcallImpl<LRINT_F32, "@@LRNTFB">;
-def zos___LRNTLB : ZOSRuntimeLibcallImpl<LRINT_F128, "@@LRNTLB">;
-def zos___WLOG_B : ZOSRuntimeLibcallImpl<LOG_F64, "@@WLOG at B">;
-def zos___FLOG_B : ZOSRuntimeLibcallImpl<LOG_F32, "@@FLOG at B">;
-def zos___LLOG_B : ZOSRuntimeLibcallImpl<LOG_F128, "@@LLOG at B">;
-def zos___LOG2_B : ZOSRuntimeLibcallImpl<LOG2_F64, "@@LOG2 at B">;
-def zos___FLG2_B : ZOSRuntimeLibcallImpl<LOG2_F32, "@@FLG2 at B">;
-def zos___LLG2_B : ZOSRuntimeLibcallImpl<LOG2_F128, "@@LLG2 at B">;
-def zos___WLG1_B : ZOSRuntimeLibcallImpl<LOG10_F64, "@@WLG1 at B">;
-def zos___FLG1_B : ZOSRuntimeLibcallImpl<LOG10_F32, "@@FLG1 at B">;
-def zos___LLG1_B : ZOSRuntimeLibcallImpl<LOG10_F128, "@@LLG1 at B">;
-def zos___LLRD_B : ZOSRuntimeLibcallImpl<LLROUND_F64, "@@LLRD at B">;
-def zos___LLRDFB : ZOSRuntimeLibcallImpl<LLROUND_F32, "@@LLRDFB">;
-def zos___LLRDLB : ZOSRuntimeLibcallImpl<LLROUND_F128, "@@LLRDLB">;
-def zos___LLRT_B : ZOSRuntimeLibcallImpl<LLRINT_F64, "@@LLRT at B">;
-def zos___LLRTFB : ZOSRuntimeLibcallImpl<LLRINT_F32, "@@LLRTFB">;
-def zos___LLRTLB : ZOSRuntimeLibcallImpl<LLRINT_F128, "@@LLRTLB">;
-def zos___SLXP_B : ZOSRuntimeLibcallImpl<LDEXP_F64, "@@SLXP at B">;
-def zos___FLXP_B : ZOSRuntimeLibcallImpl<LDEXP_F32, "@@FLXP at B">;
-def zos___LLXP_B : ZOSRuntimeLibcallImpl<LDEXP_F128, "@@LLXP at B">;
-def zos___SFXP_B : ZOSRuntimeLibcallImpl<FREXP_F64, "@@SFXP at B">;
-def zos___FFXP_B : ZOSRuntimeLibcallImpl<FREXP_F32, "@@FFXP at B">;
-def zos___LFXP_B : ZOSRuntimeLibcallImpl<FREXP_F128, "@@LFXP at B">;
-def zos___FMIN_B : ZOSRuntimeLibcallImpl<FMIN_F64, "@@FMIN at B">;
-def zos___FMINFB : ZOSRuntimeLibcallImpl<FMIN_F32, "@@FMINFB">;
-def zos___FMINLB : ZOSRuntimeLibcallImpl<FMIN_F128, "@@FMINLB">;
-def zos___FMA_B : ZOSRuntimeLibcallImpl<FMA_F64, "@@FMA at B">;
-def zos___FMAFB : ZOSRuntimeLibcallImpl<FMA_F32, "@@FMAFB">;
-def zos___FMALB : ZOSRuntimeLibcallImpl<FMA_F128, "@@FMALB">;
-def zos___FMAX_B : ZOSRuntimeLibcallImpl<FMAX_F64, "@@FMAX at B">;
-def zos___FMAXFB : ZOSRuntimeLibcallImpl<FMAX_F32, "@@FMAXFB">;
-def zos___FMAXLB : ZOSRuntimeLibcallImpl<FMAX_F128, "@@FMAXLB">;
-def zos___SFLR_B : ZOSRuntimeLibcallImpl<FLOOR_F64, "@@SFLR at B">;
-def zos___FFLR_B : ZOSRuntimeLibcallImpl<FLOOR_F32, "@@FFLR at B">;
-def zos___LFLR_B : ZOSRuntimeLibcallImpl<FLOOR_F128, "@@LFLR at B">;
-def zos___WEXP_B : ZOSRuntimeLibcallImpl<EXP_F64, "@@WEXP at B">;
-def zos___FEXP_B : ZOSRuntimeLibcallImpl<EXP_F32, "@@FEXP at B">;
-def zos___LEXP_B : ZOSRuntimeLibcallImpl<EXP_F128, "@@LEXP at B">;
-def zos___EXP2_B : ZOSRuntimeLibcallImpl<EXP2_F64, "@@EXP2 at B">;
-def zos___FXP2_B : ZOSRuntimeLibcallImpl<EXP2_F32, "@@FXP2 at B">;
-def zos___LXP2_B : ZOSRuntimeLibcallImpl<EXP2_F128, "@@LXP2 at B">;
-def zos___SCOS_B : ZOSRuntimeLibcallImpl<COS_F64, "@@SCOS at B">;
-def zos___FCOS_B : ZOSRuntimeLibcallImpl<COS_F32, "@@FCOS at B">;
-def zos___LCOS_B : ZOSRuntimeLibcallImpl<COS_F128, "@@LCOS at B">;
-def zos___DCPY_B : ZOSRuntimeLibcallImpl<COPYSIGN_F64, "@@DCPY at B">;
-def zos___FCPY_B : ZOSRuntimeLibcallImpl<COPYSIGN_F32, "@@FCPY at B">;
-def zos___LCPY_B : ZOSRuntimeLibcallImpl<COPYSIGN_F128, "@@LCPY at B">;
-def zos___SCEL_B : ZOSRuntimeLibcallImpl<CEIL_F64, "@@SCEL at B">;
-def zos___FCEL_B : ZOSRuntimeLibcallImpl<CEIL_F32, "@@FCEL at B">;
-def zos___LCEL_B : ZOSRuntimeLibcallImpl<CEIL_F128, "@@LCEL at B">;
-def zos___SCRT_B : ZOSRuntimeLibcallImpl<CBRT_F64, "@@SCRT at B">;
-def zos___FCBT_B : ZOSRuntimeLibcallImpl<CBRT_F32, "@@FCBT at B">;
-def zos___LCBT_B : ZOSRuntimeLibcallImpl<CBRT_F128, "@@LCBT at B">;
+defset list<RuntimeLibcallImpl> ZOSRuntimeLibcalls = {
+  def zos___TRNC_B : RuntimeLibcallImpl<TRUNC_F64, "@@TRNC at B">;
+  def zos___FTRC_B : RuntimeLibcallImpl<TRUNC_F32, "@@FTRC at B">;
+  def zos___LTRC_B : RuntimeLibcallImpl<TRUNC_F128, "@@LTRC at B">;
+  def zos___WSQT_B : RuntimeLibcallImpl<SQRT_F64, "@@WSQT at B">;
+  def zos___FSQT_B : RuntimeLibcallImpl<SQRT_F32, "@@FSQT at B">;
+  def zos___LSQT_B : RuntimeLibcallImpl<SQRT_F128, "@@LSQT at B">;
+  def zos___SSIN_B : RuntimeLibcallImpl<SIN_F64, "@@SSIN at B">;
+  def zos___FSIN_B : RuntimeLibcallImpl<SIN_F32, "@@FSIN at B">;
+  def zos___LSIN_B : RuntimeLibcallImpl<SIN_F128, "@@LSIN at B">;
+  def zos___ROUN_B : RuntimeLibcallImpl<ROUND_F64, "@@ROUN at B">;
+  def zos___ROUNFB : RuntimeLibcallImpl<ROUND_F32, "@@ROUNFB">;
+  def zos___ROUNLB : RuntimeLibcallImpl<ROUND_F128, "@@ROUNLB">;
+  def zos___SRNT_B : RuntimeLibcallImpl<RINT_F64, "@@SRNT at B">;
+  def zos___RINTFB : RuntimeLibcallImpl<RINT_F32, "@@RINTFB">;
+  def zos___RINTLB : RuntimeLibcallImpl<RINT_F128, "@@RINTLB">;
+  def zos___WFMD_B : RuntimeLibcallImpl<REM_F64, "@@WFMD at B">;
+  def zos___FFMD_B : RuntimeLibcallImpl<REM_F32, "@@FFMD at B">;
+  def zos___LFMD_B : RuntimeLibcallImpl<REM_F128, "@@LFMD at B">;
+  def zos___WPOW_B : RuntimeLibcallImpl<POW_F64, "@@WPOW at B">;
+  def zos___FPOW_B : RuntimeLibcallImpl<POW_F32, "@@FPOW at B">;
+  def zos___LPOW_B : RuntimeLibcallImpl<POW_F128, "@@LPOW at B">;
+  def zos___NBYI_B : RuntimeLibcallImpl<NEARBYINT_F64, "@@NBYI at B">;
+  def zos___NBYIFB : RuntimeLibcallImpl<NEARBYINT_F32, "@@NBYIFB">;
+  def zos___NBYILB : RuntimeLibcallImpl<NEARBYINT_F128, "@@NBYILB">;
+  def zos___ROND_B : RuntimeLibcallImpl<LROUND_F64, "@@ROND at B">;
+  def zos___FRND_B : RuntimeLibcallImpl<LROUND_F32, "@@FRND at B">;
+  def zos___LRND_B : RuntimeLibcallImpl<LROUND_F128, "@@LRND at B">;
+  def zos___LRNT_B : RuntimeLibcallImpl<LRINT_F64, "@@LRNT at B">;
+  def zos___LRNTFB : RuntimeLibcallImpl<LRINT_F32, "@@LRNTFB">;
+  def zos___LRNTLB : RuntimeLibcallImpl<LRINT_F128, "@@LRNTLB">;
+  def zos___WLOG_B : RuntimeLibcallImpl<LOG_F64, "@@WLOG at B">;
+  def zos___FLOG_B : RuntimeLibcallImpl<LOG_F32, "@@FLOG at B">;
+  def zos___LLOG_B : RuntimeLibcallImpl<LOG_F128, "@@LLOG at B">;
+  def zos___LOG2_B : RuntimeLibcallImpl<LOG2_F64, "@@LOG2 at B">;
+  def zos___FLG2_B : RuntimeLibcallImpl<LOG2_F32, "@@FLG2 at B">;
+  def zos___LLG2_B : RuntimeLibcallImpl<LOG2_F128, "@@LLG2 at B">;
+  def zos___WLG1_B : RuntimeLibcallImpl<LOG10_F64, "@@WLG1 at B">;
+  def zos___FLG1_B : RuntimeLibcallImpl<LOG10_F32, "@@FLG1 at B">;
+  def zos___LLG1_B : RuntimeLibcallImpl<LOG10_F128, "@@LLG1 at B">;
+  def zos___LLRD_B : RuntimeLibcallImpl<LLROUND_F64, "@@LLRD at B">;
+  def zos___LLRDFB : RuntimeLibcallImpl<LLROUND_F32, "@@LLRDFB">;
+  def zos___LLRDLB : RuntimeLibcallImpl<LLROUND_F128, "@@LLRDLB">;
+  def zos___LLRT_B : RuntimeLibcallImpl<LLRINT_F64, "@@LLRT at B">;
+  def zos___LLRTFB : RuntimeLibcallImpl<LLRINT_F32, "@@LLRTFB">;
+  def zos___LLRTLB : RuntimeLibcallImpl<LLRINT_F128, "@@LLRTLB">;
+  def zos___SLXP_B : RuntimeLibcallImpl<LDEXP_F64, "@@SLXP at B">;
+  def zos___FLXP_B : RuntimeLibcallImpl<LDEXP_F32, "@@FLXP at B">;
+  def zos___LLXP_B : RuntimeLibcallImpl<LDEXP_F128, "@@LLXP at B">;
+  def zos___SFXP_B : RuntimeLibcallImpl<FREXP_F64, "@@SFXP at B">;
+  def zos___FFXP_B : RuntimeLibcallImpl<FREXP_F32, "@@FFXP at B">;
+  def zos___LFXP_B : RuntimeLibcallImpl<FREXP_F128, "@@LFXP at B">;
+  def zos___FMIN_B : RuntimeLibcallImpl<FMIN_F64, "@@FMIN at B">;
+  def zos___FMINFB : RuntimeLibcallImpl<FMIN_F32, "@@FMINFB">;
+  def zos___FMINLB : RuntimeLibcallImpl<FMIN_F128, "@@FMINLB">;
+  def zos___FMA_B : RuntimeLibcallImpl<FMA_F64, "@@FMA at B">;
+  def zos___FMAFB : RuntimeLibcallImpl<FMA_F32, "@@FMAFB">;
+  def zos___FMALB : RuntimeLibcallImpl<FMA_F128, "@@FMALB">;
+  def zos___FMAX_B : RuntimeLibcallImpl<FMAX_F64, "@@FMAX at B">;
+  def zos___FMAXFB : RuntimeLibcallImpl<FMAX_F32, "@@FMAXFB">;
+  def zos___FMAXLB : RuntimeLibcallImpl<FMAX_F128, "@@FMAXLB">;
+  def zos___SFLR_B : RuntimeLibcallImpl<FLOOR_F64, "@@SFLR at B">;
+  def zos___FFLR_B : RuntimeLibcallImpl<FLOOR_F32, "@@FFLR at B">;
+  def zos___LFLR_B : RuntimeLibcallImpl<FLOOR_F128, "@@LFLR at B">;
+  def zos___WEXP_B : RuntimeLibcallImpl<EXP_F64, "@@WEXP at B">;
+  def zos___FEXP_B : RuntimeLibcallImpl<EXP_F32, "@@FEXP at B">;
+  def zos___LEXP_B : RuntimeLibcallImpl<EXP_F128, "@@LEXP at B">;
+  def zos___EXP2_B : RuntimeLibcallImpl<EXP2_F64, "@@EXP2 at B">;
+  def zos___FXP2_B : RuntimeLibcallImpl<EXP2_F32, "@@FXP2 at B">;
+  def zos___LXP2_B : RuntimeLibcallImpl<EXP2_F128, "@@LXP2 at B">;
+  def zos___SCOS_B : RuntimeLibcallImpl<COS_F64, "@@SCOS at B">;
+  def zos___FCOS_B : RuntimeLibcallImpl<COS_F32, "@@FCOS at B">;
+  def zos___LCOS_B : RuntimeLibcallImpl<COS_F128, "@@LCOS at B">;
+  def zos___DCPY_B : RuntimeLibcallImpl<COPYSIGN_F64, "@@DCPY at B">;
+  def zos___FCPY_B : RuntimeLibcallImpl<COPYSIGN_F32, "@@FCPY at B">;
+  def zos___LCPY_B : RuntimeLibcallImpl<COPYSIGN_F128, "@@LCPY at B">;
+  def zos___SCEL_B : RuntimeLibcallImpl<CEIL_F64, "@@SCEL at B">;
+  def zos___FCEL_B : RuntimeLibcallImpl<CEIL_F32, "@@FCEL at B">;
+  def zos___LCEL_B : RuntimeLibcallImpl<CEIL_F128, "@@LCEL at B">;
+  def zos___SCRT_B : RuntimeLibcallImpl<CBRT_F64, "@@SCRT at B">;
+  def zos___FCBT_B : RuntimeLibcallImpl<CBRT_F32, "@@FCBT at B">;
+  def zos___LCBT_B : RuntimeLibcallImpl<CBRT_F128, "@@LCBT at B">;
+}
+
+def isSystemZZOS : RuntimeLibcallPredicate<"(TT.isSystemZ() && TT.isOSzOS())">;
+def isZOS : RuntimeLibcallPredicate<"TT.isOSzOS()">;
+def SystemZZOSSystemLibrary
+    : SystemRuntimeLibrary<
+          isSystemZZOS, (add DefaultRuntimeLibcallImpls,
+                            LibcallImpls<(add ZOSRuntimeLibcalls), isZOS>)>;
 
 //===----------------------------------------------------------------------===//
 // WebAssembly Runtime Libcalls
@@ -1659,3 +1775,12 @@ def zos___LCBT_B : ZOSRuntimeLibcallImpl<CBRT_F128, "@@LCBT at B">;
 // TODO: when implementing other Wasm backends, make this generic or only do
 // this on emscripten depending on what they end up doing.
 def emscripten_return_address : RuntimeLibcallImpl<RETURN_ADDRESS>;
+
+def isWasm : RuntimeLibcallPredicate<"TT.isWasm()">;
+
+// Define the emscripten name for return address helper.
+// TODO: when implementing other Wasm backends, make this generic or only do
+// this on emscripten depending on what they end up doing.
+def WasmSystemLibrary
+    : SystemRuntimeLibrary<isWasm,
+      (add DefaultRuntimeLibcallImpls, emscripten_return_address)>;
diff --git a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
index 9444a0a838cdd..d64e0d0adfa75 100644
--- a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
+++ b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
@@ -6,6 +6,23 @@
 //
 //===----------------------------------------------------------------------===//
 
+include "llvm/TableGen/SetTheory.td"
+
+// Predicate for whether a libcall exists for the target ABI. This is
+// a module level property that should only be computed based on the
+// triple.
+class RuntimeLibcallPredicate<code cond> {
+  // Expression of an llvm::Triple named TT for whether a libcall
+  // should exist.
+  code Cond = cond;
+}
+
+// Predicate for whether a libcall should be used for the current
+// function/subtarget.
+class LibcallLoweringPredicate<code cond> { code Cond = cond; }
+
+def AlwaysAvailable : RuntimeLibcallPredicate<[{}]>;
+
 /// Abstract definition for functionality the compiler may need to
 /// emit a call to. Emits the RTLIB::Libcall enum - This enum defines
 /// all of the runtime library calls the backend can emit. The various
@@ -28,5 +45,24 @@ class RuntimeLibcall {
 class RuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME> {
   RuntimeLibcall Provides = P;
   string LibCallFuncName = Name;
+  list<LibcallLoweringPredicate> LoweringPredicates;
   bit IsDefault = false;
 }
+
+class LibcallImpls<dag funcList,
+                   RuntimeLibcallPredicate Pred = AlwaysAvailable> {
+  // Function of the triple where this applies
+  RuntimeLibcallPredicate AvailabilityPredicate = Pred;
+  dag MemberList = funcList;
+}
+
+/// Convenience wrapper around LibcallImplSet to make a single libcall
+/// implementation conditionally conditionally available.
+class AvailableIf<RuntimeLibcallImpl Impl, RuntimeLibcallPredicate Pred>
+    : LibcallImpls<(add Impl), Pred>;
+
+/// Define a complete top level set of runtime libcalls for a target.
+class SystemRuntimeLibrary<RuntimeLibcallPredicate Pred, dag funcList> {
+  RuntimeLibcallPredicate TriplePred = Pred;
+  LibcallImpls MemberList = LibcallImpls<funcList>;
+}
diff --git a/llvm/include/llvm/TableGen/SetTheory.td b/llvm/include/llvm/TableGen/SetTheory.td
new file mode 100644
index 0000000000000..38b89671ee541
--- /dev/null
+++ b/llvm/include/llvm/TableGen/SetTheory.td
@@ -0,0 +1,27 @@
+//===- SetTheory.td - DAG set operator declarations --------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// FIXME: This is not used everywhere, and different files declare
+// different subsets of used operators.
+//
+// It just happens TargetSelectionDAG.td defines records with the same
+// names as the tablegen DAG operators for SelectionDAG operators.
+
+// Target.td separately declares the special set operators.
+
+def add; // Forward declare
+def sub;
+def and;
+def shl;
+// def trunc; // FIXME: Name collision
+def rotl;
+def rotr;
+
+def sequence;
+def decimate;
+def interleave;
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 67f872b4574b1..eaa2cf5100c77 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -12,51 +12,16 @@
 using namespace llvm;
 using namespace RTLIB;
 
-#define GET_INIT_RUNTIME_LIBCALL_UTILS
 #define GET_INIT_RUNTIME_LIBCALL_NAMES
+#define GET_SET_TARGET_RUNTIME_LIBCALL_SETS
 #include "llvm/IR/RuntimeLibcalls.inc"
-#undef GET_INIT_RUNTIME_LIBCALL_UTILS
 #undef GET_INIT_RUNTIME_LIBCALL_NAMES
+#undef GET_SET_TARGET_RUNTIME_LIBCALL_SETS
 
 static cl::opt<bool>
     HexagonEnableFastMathRuntimeCalls("hexagon-fast-math", cl::Hidden,
                                       cl::desc("Enable Fast Math processing"));
 
-static void setAArch64LibcallNames(RuntimeLibcallsInfo &Info,
-                                   const Triple &TT) {
-#define LCALLNAMES(A, B, N)                                                    \
-  Info.setLibcallImpl(A##N##_RELAX, B##N##_relax);                             \
-  Info.setLibcallImpl(A##N##_ACQ, B##N##_acq);                                 \
-  Info.setLibcallImpl(A##N##_REL, B##N##_rel);                                 \
-  Info.setLibcallImpl(A##N##_ACQ_REL, B##N##_acq_rel);
-#define LCALLNAME4(A, B)                                                       \
-  LCALLNAMES(A, B, 1)                                                          \
-  LCALLNAMES(A, B, 2) LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8)
-#define LCALLNAME5(A, B)                                                       \
-  LCALLNAMES(A, B, 1)                                                          \
-  LCALLNAMES(A, B, 2)                                                          \
-  LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8) LCALLNAMES(A, B, 16)
-
-  if (TT.isWindowsArm64EC()) {
-    LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::arm64ec___aarch64_cas)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::arm64ec___aarch64_swp)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::arm64ec___aarch64_ldadd)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::arm64ec___aarch64_ldset)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::arm64ec___aarch64_ldclr)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::arm64ec___aarch64_ldeor)
-  } else {
-    LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::__aarch64_cas)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::__aarch64_swp)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::__aarch64_ldadd)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::__aarch64_ldset)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::__aarch64_ldclr)
-    LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::__aarch64_ldeor)
-  }
-#undef LCALLNAMES
-#undef LCALLNAME4
-#undef LCALLNAME5
-}
-
 static void setARMLibcallNames(RuntimeLibcallsInfo &Info, const Triple &TT,
                                FloatABI::ABIType FloatABIType,
                                EABI EABIVersion) {
@@ -358,6 +323,8 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
                                        ExceptionHandling ExceptionModel,
                                        FloatABI::ABIType FloatABI,
                                        EABI EABIVersion) {
+  setTargetRuntimeLibcallSets(TT);
+
   // Use the f128 variants of math functions on x86
   if (TT.isX86() && TT.isGNUEnvironment())
     setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/true);
@@ -367,28 +334,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
       setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume);
   }
 
-  if (TT.isPPC()) {
-    setPPCLibCallNameOverrides();
-
-    // TODO: Do the finite only functions exist?
-    setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/false);
-
-    // TODO: Tablegen predicate support
-    if (TT.isOSAIX()) {
-      if (TT.isPPC64()) {
-        setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported);
-        setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove64);
-        setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset64);
-        setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero64);
-      } else {
-        setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported);
-        setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove);
-        setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset);
-        setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero);
-      }
-    }
-  }
-
   // A few names are different on particular architectures or environments.
   if (TT.isOSDarwin()) {
     // For f16/f32 conversions, Darwin uses the standard naming scheme,
@@ -485,14 +430,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
     setLibcallImpl(RTLIB::FREXP_PPCF128, RTLIB::Unsupported);
   }
 
-  // Disable most libcalls on AMDGPU and NVPTX.
-  if (TT.isAMDGPU() || TT.isNVPTX()) {
-    for (RTLIB::Libcall LC : RTLIB::libcalls()) {
-      if (!isAtomicLibCall(LC))
-        setLibcallImpl(LC, RTLIB::Unsupported);
-    }
-  }
-
   if (TT.isOSMSVCRT()) {
     // MSVCRT doesn't have powi; fall back to pow
     setLibcallImpl(RTLIB::POWI_F32, RTLIB::Unsupported);
@@ -520,55 +457,14 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
     }
   }
 
-  if (TT.isAArch64()) {
-    if (TT.isWindowsArm64EC()) {
-      setWindowsArm64LibCallNameOverrides();
-      setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::arm64ec___arm_sc_memcpy);
-      setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::arm64ec___arm_sc_memmove);
-      setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::arm64ec___arm_sc_memset);
-    } else {
-      setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::__arm_sc_memcpy);
-      setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::__arm_sc_memmove);
-      setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::__arm_sc_memset);
-    }
-
-    setAArch64LibcallNames(*this, TT);
-  } else if (TT.isARM() || TT.isThumb()) {
+  if (TT.isARM() || TT.isThumb())
     setARMLibcallNames(*this, TT, FloatABI, EABIVersion);
-  } else if (TT.getArch() == Triple::ArchType::avr) {
-    // Division rtlib functions (not supported), use divmod functions instead
-    setLibcallImpl(RTLIB::SDIV_I8, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::SDIV_I16, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::SDIV_I32, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::UDIV_I8, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::UDIV_I16, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::UDIV_I32, RTLIB::Unsupported);
-
-    // Modulus rtlib functions (not supported), use divmod functions instead
-    setLibcallImpl(RTLIB::SREM_I8, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::SREM_I16, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::SREM_I32, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::UREM_I8, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::UREM_I16, RTLIB::Unsupported);
-    setLibcallImpl(RTLIB::UREM_I32, RTLIB::Unsupported);
-
-    // Division and modulus rtlib functions
-    setLibcallImpl(RTLIB::SDIVREM_I8, RTLIB::__divmodqi4);
-    setLibcallImpl(RTLIB::SDIVREM_I16, RTLIB::__divmodhi4);
-    setLibcallImpl(RTLIB::SDIVREM_I32, RTLIB::__divmodsi4);
-    setLibcallImpl(RTLIB::UDIVREM_I8, RTLIB::__udivmodqi4);
-    setLibcallImpl(RTLIB::UDIVREM_I16, RTLIB::__udivmodhi4);
-    setLibcallImpl(RTLIB::UDIVREM_I32, RTLIB::__udivmodsi4);
-
+  else if (TT.getArch() == Triple::ArchType::avr) {
     // Several of the runtime library functions use a special calling conv
     setLibcallCallingConv(RTLIB::SDIVREM_I8, CallingConv::AVR_BUILTIN);
     setLibcallCallingConv(RTLIB::SDIVREM_I16, CallingConv::AVR_BUILTIN);
     setLibcallCallingConv(RTLIB::UDIVREM_I8, CallingConv::AVR_BUILTIN);
     setLibcallCallingConv(RTLIB::UDIVREM_I16, CallingConv::AVR_BUILTIN);
-
-    // Trigonometric rtlib functions
-    setLibcallImpl(RTLIB::SIN_F32, RTLIB::avr_sin);
-    setLibcallImpl(RTLIB::COS_F32, RTLIB::avr_cos);
   }
 
   if (!TT.isWasm()) {
@@ -582,11 +478,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
     }
 
     setLibcallImpl(RTLIB::MULO_I128, RTLIB::Unsupported);
-  } else {
-    // Define the emscripten name for return address helper.
-    // TODO: when implementing other Wasm backends, make this generic or only do
-    // this on emscripten depending on what they end up doing.
-    setLibcallImpl(RTLIB::RETURN_ADDRESS, RTLIB::emscripten_return_address);
   }
 
   if (TT.getArch() == Triple::ArchType::hexagon) {
@@ -633,10 +524,4 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
 
   if (TT.getArch() == Triple::ArchType::msp430)
     setMSP430Libcalls(*this, TT);
-
-  if (TT.isSystemZ() && TT.isOSzOS())
-    setZOSLibCallNameOverrides();
-
-  if (TT.getArch() == Triple::ArchType::xcore)
-    setLibcallImpl(RTLIB::MEMCPY_ALIGN_4, RTLIB::__memcpy_4);
 }
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td b/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
new file mode 100644
index 0000000000000..086edc79e3b36
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td
@@ -0,0 +1,60 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2> %t.err | FileCheck %s
+// RUN: FileCheck -check-prefix=ERR %s < %t.err
+
+// Check behavior of libcall emission when multiple RuntimeLibcallImpl
+// implementations provide the same RuntimeLibcall
+
+include "llvm/IR/RuntimeLibCallsImpl.td"
+
+def SOME_FUNC : RuntimeLibcall;
+def OTHER_FUNC : RuntimeLibcall;
+def ANOTHER_DUP : RuntimeLibcall;
+
+def isTargetArchA : RuntimeLibcallPredicate<[{isTargetArchA()}]>;
+def isTargetArchB : RuntimeLibcallPredicate<[{isTargetArchB()}]>;
+def isTargetArchC : RuntimeLibcallPredicate<[{isTargetArchC()}]>;
+
+def func_a : RuntimeLibcallImpl<SOME_FUNC>;
+def func_b : RuntimeLibcallImpl<SOME_FUNC>;
+def func_c : RuntimeLibcallImpl<SOME_FUNC>;
+def other_func : RuntimeLibcallImpl<OTHER_FUNC>;
+
+def dup0 : RuntimeLibcallImpl<ANOTHER_DUP>;
+def dup1 : RuntimeLibcallImpl<ANOTHER_DUP>;
+
+// func_a and func_b both provide SOME_FUNC.
+
+// CHECK: if (isTargetArchA()) {
+// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:   {RTLIB::SOME_FUNC, RTLIB::func_b}, // func_b
+// CHECK-NEXT: };
+
+// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_b, func_a
+def TheSystemLibraryA : SystemRuntimeLibrary<isTargetArchA,
+  (add func_b, func_a)
+>;
+
+// CHECK: if (isTargetArchB()) {
+// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:   {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
+// CHECK-NEXT:  {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
+// CHECK-NEXT: };
+
+// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
+def TheSystemLibraryB : SystemRuntimeLibrary<isTargetArchB,
+  (add func_a, other_func, func_b)
+>;
+
+// CHECK: if (isTargetArchC()) {
+// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:   {RTLIB::ANOTHER_DUP, RTLIB::dup1}, // dup1
+// CHECK-NEXT:   {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func
+// CHECK-NEXT:   {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a
+// CHECK-NEXT: };
+
+// ERR: :[[@LINE+3]]:5: warning: conflicting implementations for libcall ANOTHER_DUP: dup1, dup0
+// ERR: :[[@LINE+2]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b
+// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_c
+def TheSystemLibraryC : SystemRuntimeLibrary<isTargetArchC,
+  (add func_a, dup1, other_func, func_b, func_c, dup0)
+>;
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td b/llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td
new file mode 100644
index 0000000000000..a8b33e48613c3
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td
@@ -0,0 +1,18 @@
+// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2>&1 | FileCheck -check-prefix=ERR %s
+
+include "llvm/IR/RuntimeLibCallsImpl.td"
+
+def FUNC0 : RuntimeLibcall;
+def FUNC1 : RuntimeLibcall;
+
+def isFoo : RuntimeLibcallPredicate<[{isFoo()}]>;
+def isBar : RuntimeLibcallPredicate<[{isBar()}]>;
+def isTargetArch : RuntimeLibcallPredicate<[{isTargetArch()}]>;
+
+def func0 : RuntimeLibcallImpl<FUNC0>;
+def func1 : RuntimeLibcallImpl<FUNC1>;
+
+// ERR: :[[@LINE+2]]:8: error: combining nested libcall set predicates currently unhandled
+def TheSystemLibrary : SystemRuntimeLibrary<isTargetArch,
+  (add LibcallImpls<(add func0, LibcallImpls<(add func1), isBar>), isFoo>)
+>;
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td
index d4030dd0a7e95..d810ce3787703 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td
@@ -9,6 +9,9 @@ def SRL_I64 : RuntimeLibcall;
 def SQRT_F128 : RuntimeLibcall;
 def SQRT_F80 : RuntimeLibcall;
 def BZERO : RuntimeLibcall;
+def MEMCPY : RuntimeLibcall;
+def MEMSET : RuntimeLibcall;
+def CALLOC : RuntimeLibcall;
 
 // Test default names.
 let IsDefault = true in {
@@ -22,27 +25,84 @@ let IsDefault = true in {
 // Ignore non-default in initDefaultLibCallNames.
 def bzero : RuntimeLibcallImpl<BZERO>;
 
+def ___memset : RuntimeLibcallImpl<MEMSET, "___memset">;
+def ___memcpy : RuntimeLibcallImpl<MEMCPY, "___memcpy">;
+
+def calloc  : RuntimeLibcallImpl<CALLOC, "calloc">;
+
+def CompilerRTLibcalls : LibcallImpls<(add __ashlsi3, __lshrdi3)>;
+def LibmLibcalls : LibcallImpls<(add sqrtl_f80)>;
+
+//def AllCalls : LibcallImpls<(add CompilerRTLibcalls, LibmLibcalls, __ashlsi3)>;
+
+//def MostCalls : LibcallImpls<(sub AllCalls, __ashlsi3, sqrtl_f128)>;
+
+def isSimpleArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::simple}]>;
+def isFooArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::foo}]>;
+
+
+def isZOS : RuntimeLibcallPredicate<[{TT.getOS() == Triple::zos}]>;
+def isPPC : RuntimeLibcallPredicate<[{TT.getArch().isPPC()}]>;
+def isPPC64 : RuntimeLibcallPredicate<[{TT.getArch().isPPC64()}]>;
+
+
+def isFoo : RuntimeLibcallPredicate<[{isFOO()}]>;
+def isBarOS : RuntimeLibcallPredicate<[{TT.getOS() == Triple::bar}]>;
+def isBuzzArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::buzz}]>;
+def isBlahArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::blah}]>;
+
+def hasCompilerRT : RuntimeLibcallPredicate<[{TT.hasCompilerRT()}]>;
+
+
+
+def SimpleLibrary : SystemRuntimeLibrary<isSimpleArch,
+  (add LibmLibcalls, calloc, CompilerRTLibcalls)>;
+
+
+def LibraryWithConditionalFunc : LibcallImpls<(add sqrtl_f128, bzero, AvailableIf<___memset, isBarOS>)>;
+
+def FooLibrary : SystemRuntimeLibrary<isFooArch, (add LibraryWithConditionalFunc)>;
+
+def BuzzLibrary : SystemRuntimeLibrary<isBuzzArch, (add sqrtl_f80, CompilerRTLibcalls)>;
+
+
+
+def LibraryWithConditionalSet : LibcallImpls<(add sqrtl_f128, bzero,
+  LibcallImpls<(add CompilerRTLibcalls), hasCompilerRT>)>;
+
+
+
+def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithConditionalSet, AvailableIf<___memset, isBarOS>)>;
+
+
+
 // All entries should be emitted in Libcall enum.
 // CHECK: #ifdef GET_RUNTIME_LIBCALL_ENUM
 // CHECK-NEXT: namespace llvm {
 // CHECK-NEXT: namespace RTLIB {
 // CHECK-NEXT: enum Libcall : unsigned short {
 // CHECK-NEXT: BZERO = 0,
-// CHECK-NEXT: SHL_I32 = 1,
-// CHECK-NEXT: SQRT_F80 = 2,
-// CHECK-NEXT: SQRT_F128 = 3,
-// CHECK-NEXT: SRL_I64 = 4,
-// CHECK-NEXT: UNKNOWN_LIBCALL = 5
+// CHECK-NEXT: CALLOC = 1,
+// CHECK-NEXT: MEMCPY = 2,
+// CHECK-NEXT: MEMSET = 3,
+// CHECK-NEXT: SHL_I32 = 4,
+// CHECK-NEXT: SQRT_F80 = 5,
+// CHECK-NEXT: SQRT_F128 = 6,
+// CHECK-NEXT: SRL_I64 = 7,
+// CHECK-NEXT: UNKNOWN_LIBCALL = 8
 // CHECK-NEXT: };
 // CHECK-EMPTY:
 // CHECK-NEXT:enum LibcallImpl : unsigned short {
 // CHECK-NEXT:  Unsupported = 0,
-// CHECK-NEXT:  __ashlsi3 = 1, // __ashlsi3
-// CHECK-NEXT:  __lshrdi3 = 2, // __lshrdi3
-// CHECK-NEXT:  bzero = 3, // bzero
-// CHECK-NEXT:  sqrtl_f80 = 4, // sqrtl
-// CHECK-NEXT:  sqrtl_f128 = 5, // sqrtl
-// CHECK-NEXT:  NumLibcallImpls = 6
+// CHECK-NEXT:  ___memcpy = 1, // ___memcpy
+// CHECK-NEXT:  ___memset = 2, // ___memset
+// CHECK-NEXT:  __ashlsi3 = 3, // __ashlsi3
+// CHECK-NEXT:  __lshrdi3 = 4, // __lshrdi3
+// CHECK-NEXT:  bzero = 5, // bzero
+// CHECK-NEXT:  calloc = 6, // calloc
+// CHECK-NEXT:  sqrtl_f80 = 7, // sqrtl
+// CHECK-NEXT:  sqrtl_f128 = 8, // sqrtl
+// CHECK-NEXT:  NumLibcallImpls = 9
 // CHECK-NEXT: };
 // CHECK-NEXT: } // End namespace RTLIB
 // CHECK-NEXT: } // End namespace llvm
@@ -51,6 +111,9 @@ def bzero : RuntimeLibcallImpl<BZERO>;
 // CHECK: #ifdef GET_INIT_RUNTIME_LIBCALL_NAMES
 // CHECK-NEXT: const RTLIB::LibcallImpl llvm::RTLIB::RuntimeLibcallsInfo::DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1] = {
 // CHECK-NEXT:   RTLIB::Unsupported, // RTLIB::BZERO
+// CHECK-NEXT:   RTLIB::Unsupported, // RTLIB::CALLOC
+// CHECK-NEXT:   RTLIB::Unsupported, // RTLIB::MEMCPY
+// CHECK-NEXT:   RTLIB::Unsupported, // RTLIB::MEMSET
 // CHECK-NEXT:   RTLIB::__ashlsi3, // RTLIB::SHL_I32
 // CHECK-NEXT:   RTLIB::sqrtl_f80, // RTLIB::SQRT_F80
 // CHECK-NEXT:   RTLIB::sqrtl_f128, // RTLIB::SQRT_F128
@@ -60,18 +123,118 @@ def bzero : RuntimeLibcallImpl<BZERO>;
 // CHECK-EMPTY:
 // CHECK-NEXT: const char *const llvm::RTLIB::RuntimeLibcallsInfo::LibCallImplNames[RTLIB::NumLibcallImpls] = {
 // CHECK-NEXT: nullptr, // RTLIB::Unsupported
+// CHECK-NEXT: "___memcpy", // RTLIB::___memcpy
+// CHECK-NEXT: "___memset", // RTLIB::___memset
 // CHECK-NEXT: "__ashlsi3", // RTLIB::__ashlsi3
 // CHECK-NEXT: "__lshrdi3", // RTLIB::__lshrdi3
 // CHECK-NEXT: "bzero", // RTLIB::bzero
+// CHECK-NEXT: "calloc", // RTLIB::calloc
 // CHECK-NEXT: "sqrtl", // RTLIB::sqrtl_f80
 // CHECK-NEXT: "sqrtl", // RTLIB::sqrtl_f128
 // CHECK-NEXT: };
 
 // CHECK: const RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::ImplToLibcall[RTLIB::NumLibcallImpls] = {
 // CHECK-NEXT: RTLIB::UNKNOWN_LIBCALL, // RTLIB::Unsupported
+// CHECK-NEXT: RTLIB::MEMCPY, // RTLIB::___memcpy
+// CHECK-NEXT: RTLIB::MEMSET, // RTLIB::___memset
 // CHECK-NEXT: RTLIB::SHL_I32, // RTLIB::__ashlsi3
 // CHECK-NEXT: RTLIB::SRL_I64, // RTLIB::__lshrdi3
 // CHECK-NEXT: RTLIB::BZERO, // RTLIB::bzero
+// CHECK-NEXT: RTLIB::CALLOC, // RTLIB::calloc
 // CHECK-NEXT: RTLIB::SQRT_F80, // RTLIB::sqrtl_f80
 // CHECK-NEXT: RTLIB::SQRT_F128, // RTLIB::sqrtl_f128
 // CHECK-NEXT: };
+
+
+// CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(const llvm::Triple &TT) {
+// CHECK-NEXT:  struct LibcallImplPair {
+// CHECK-NEXT:    RTLIB::Libcall Func;
+// CHECK-NEXT:    RTLIB::LibcallImpl Impl;
+// CHECK-NEXT:  };
+// CHECK-EMPTY:
+// CHECK-NEXT: if (TT.getArch() == Triple::blah) {
+// CHECK-NEXT:     static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:         {RTLIB::BZERO, RTLIB::bzero}, // bzero
+// CHECK-NEXT:         {RTLIB::CALLOC, RTLIB::calloc}, // calloc
+// CHECK-NEXT:         {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl
+// CHECK-NEXT:     };
+// CHECK-EMPTY:
+// CHECK-NEXT:     for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:       setLibcallImpl(Func, Impl);
+// CHECK-NEXT:     }
+// CHECK-NEXT:    if (TT.hasCompilerRT()) {
+// CHECK-NEXT:      static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:          {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
+// CHECK-NEXT:          {RTLIB::SRL_I64, RTLIB::__lshrdi3}, // __lshrdi3
+// CHECK-NEXT:      };
+// CHECK-EMPTY:
+// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:        setLibcallImpl(Func, Impl);
+// CHECK-NEXT:      }
+// CHECK-NEXT:    }
+// CHECK-EMPTY:
+// CHECK-NEXT:    if (TT.getOS() == Triple::bar) {
+// CHECK-NEXT:      static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:          {RTLIB::MEMSET, RTLIB::___memset}, // ___memset
+// CHECK-NEXT:      };
+// CHECK-EMPTY:
+// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:        setLibcallImpl(Func, Impl);
+// CHECK-NEXT:      }
+// CHECK-NEXT:    }
+// CHECK-EMPTY:
+// CHECK-NEXT:   return;
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK-NEXT: if (TT.getArch() == Triple::buzz) {
+// CHECK-NEXT:    static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:        {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
+// CHECK-NEXT:        {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl
+// CHECK-NEXT:        {RTLIB::SRL_I64, RTLIB::__lshrdi3}, // __lshrdi3
+// CHECK-NEXT:    };
+// CHECK-EMPTY:
+// CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:      setLibcallImpl(Func, Impl);
+// CHECK-NEXT:    }
+// CHECK-NEXT:   return;
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK-NEXT: if (TT.getArch() == Triple::foo) {
+// CHECK-NEXT:    static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:        {RTLIB::BZERO, RTLIB::bzero}, // bzero
+// CHECK-NEXT:        {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl
+// CHECK-NEXT:    };
+// CHECK-EMPTY:
+// CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:      setLibcallImpl(Func, Impl);
+// CHECK-NEXT:    }
+// CHECK-NEXT:    if (TT.getOS() == Triple::bar) {
+// CHECK-NEXT:      static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:          {RTLIB::MEMSET, RTLIB::___memset}, // ___memset
+// CHECK-NEXT:      };
+// CHECK-EMPTY:
+// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:        setLibcallImpl(Func, Impl);
+// CHECK-NEXT:      }
+// CHECK-NEXT:    }
+// CHECK-EMPTY:
+// CHECK-NEXT:    return;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT: if (TT.getArch() == Triple::simple) {
+// CHECK-NEXT:    static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:        {RTLIB::CALLOC, RTLIB::calloc}, // calloc
+// CHECK-NEXT:        {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3
+// CHECK-NEXT:        {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl
+// CHECK-NEXT:        {RTLIB::SRL_I64, RTLIB::__lshrdi3}, // __lshrdi3
+// CHECK-NEXT:    };
+// CHECK-EMPTY:
+// CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:      setLibcallImpl(Func, Impl);
+// CHECK-NEXT:    }
+// CHECK-NEXT:   return;
+// CHECK-NEXT: }
+// CHECK-NEXT:  initDefaultLibCallImpls();
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK: #endif
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 9d77631862ee5..30fcca47a4706 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -11,17 +11,61 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/SetTheory.h"
 #include "llvm/TableGen/TableGenBackend.h"
+
 using namespace llvm;
 
 namespace {
 
+class AvailabilityPredicate {
+  const Record *TheDef;
+  StringRef PredicateString;
+
+public:
+  AvailabilityPredicate(const Record *Def) : TheDef(Def) {
+    if (TheDef)
+      PredicateString = TheDef->getValueAsString("Cond");
+  }
+
+  const Record *getDef() const { return TheDef; }
+
+  bool isAlwaysAvailable() const { return PredicateString.empty(); }
+
+  void emitIf(raw_ostream &OS) const {
+    OS << "if (" << PredicateString << ") {\n";
+  }
+
+  void emitEndIf(raw_ostream &OS) const { OS << "}\n"; }
+};
+
+class RuntimeLibcallEmitter;
+class RuntimeLibcallImpl;
+
+/// Used to apply predicates to nested sets of libcalls.
+struct LibcallPredicateExpander : SetTheory::Expander {
+  const RuntimeLibcallEmitter &LibcallEmitter;
+  DenseMap<const Record *, std::vector<const Record *>> &Func2Preds;
+
+  LibcallPredicateExpander(
+      const RuntimeLibcallEmitter &LibcallEmitter,
+      DenseMap<const Record *, std::vector<const Record *>> &Func2Preds)
+      : LibcallEmitter(LibcallEmitter), Func2Preds(Func2Preds) {}
+
+  void expand(SetTheory &ST, const Record *Def,
+              SetTheory::RecSet &Elts) override;
+};
+
 class RuntimeLibcall {
   const Record *TheDef = nullptr;
+  const size_t EnumVal;
 
 public:
   RuntimeLibcall() = delete;
-  RuntimeLibcall(const Record *Def) : TheDef(Def) { assert(Def); }
+  RuntimeLibcall(const Record *Def, size_t EnumVal)
+      : TheDef(Def), EnumVal(EnumVal) {
+    assert(Def);
+  }
 
   ~RuntimeLibcall() { assert(TheDef); }
 
@@ -29,6 +73,8 @@ class RuntimeLibcall {
 
   StringRef getName() const { return TheDef->getName(); }
 
+  size_t getEnumVal() const { return EnumVal; }
+
   void emitEnumEntry(raw_ostream &OS) const {
     OS << "RTLIB::" << TheDef->getValueAsString("Name");
   }
@@ -37,12 +83,14 @@ class RuntimeLibcall {
 class RuntimeLibcallImpl {
   const Record *TheDef;
   const RuntimeLibcall *Provides = nullptr;
+  const size_t EnumVal;
 
 public:
   RuntimeLibcallImpl(
       const Record *Def,
-      const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap)
-      : TheDef(Def) {
+      const DenseMap<const Record *, const RuntimeLibcall *> &ProvideMap,
+      size_t EnumVal)
+      : TheDef(Def), EnumVal(EnumVal) {
     if (const Record *ProvidesDef = Def->getValueAsDef("Provides"))
       Provides = ProvideMap.lookup(ProvidesDef);
   }
@@ -53,6 +101,8 @@ class RuntimeLibcallImpl {
 
   StringRef getName() const { return TheDef->getName(); }
 
+  size_t getEnumVal() const { return EnumVal; }
+
   const RuntimeLibcall *getProvides() const { return Provides; }
 
   StringRef getLibcallFuncName() const {
@@ -68,17 +118,29 @@ class RuntimeLibcallImpl {
   void emitEnumEntry(raw_ostream &OS) const {
     OS << "RTLIB::" << TheDef->getName();
   }
+
+  void emitSetImplCall(raw_ostream &OS) const {
+    OS << "setLibcallImpl(";
+    Provides->emitEnumEntry(OS);
+    OS << ", ";
+    emitEnumEntry(OS);
+    OS << "); // " << getLibcallFuncName() << '\n';
+  }
+
+  void emitTableEntry(raw_ostream &OS) const {
+    OS << '{';
+    Provides->emitEnumEntry(OS);
+    OS << ", ";
+    emitEnumEntry(OS);
+    OS << "}, // " << getLibcallFuncName() << '\n';
+  }
 };
 
 class RuntimeLibcallEmitter {
 private:
   const RecordKeeper &Records;
-
   DenseMap<const Record *, const RuntimeLibcall *> Def2RuntimeLibcall;
-
-  const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
-    return Def2RuntimeLibcall.lookup(Def);
-  }
+  DenseMap<const Record *, const RuntimeLibcallImpl *> Def2RuntimeLibcallImpl;
 
   std::vector<RuntimeLibcall> RuntimeLibcallDefList;
   std::vector<RuntimeLibcallImpl> RuntimeLibcallImplDefList;
@@ -86,16 +148,19 @@ class RuntimeLibcallEmitter {
   DenseMap<const RuntimeLibcall *, const RuntimeLibcallImpl *>
       LibCallToDefaultImpl;
 
+private:
   void
   emitTargetOverrideFunc(raw_ostream &OS, StringRef FuncName,
                          ArrayRef<RuntimeLibcallImpl> LibCallImplList) const;
 
-  void emitGetRuntimeLibcallEnum(raw_ostream &OS) const;
+  void emitTargetOverrideFunc(raw_ostream &OS, StringRef FuncName,
+                              ArrayRef<const Record *> LibCallImplList) const;
 
-  void emitWindowsArm64LibCallNameOverrides(raw_ostream &OS) const;
+  void emitGetRuntimeLibcallEnum(raw_ostream &OS) const;
 
   void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const;
-  void emitGetInitRuntimeLibcallUtils(raw_ostream &OS) const;
+
+  void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const;
 
 public:
   RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R) {
@@ -105,8 +170,9 @@ class RuntimeLibcallEmitter {
 
     RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size());
 
+    size_t CallTypeEnumVal = 0;
     for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) {
-      RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef);
+      RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++);
       Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back();
     }
 
@@ -117,12 +183,15 @@ class RuntimeLibcallEmitter {
         Records.getAllDerivedDefinitions("RuntimeLibcallImpl");
     RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size());
 
+    size_t LibCallImplEnumVal = 1;
     for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) {
-      RuntimeLibcallImplDefList.emplace_back(LibCallImplDef,
-                                             Def2RuntimeLibcall);
+      RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall,
+                                             LibCallImplEnumVal++);
 
       RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back();
 
+      Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl;
+
       // const RuntimeLibcallImpl &LibCallImpl =
       // RuntimeLibcallImplDefList.back();
       if (LibCallImpl.isDefault()) {
@@ -135,16 +204,12 @@ class RuntimeLibcallEmitter {
     }
   }
 
-  std::vector<RuntimeLibcallImpl>
-  getRuntimeLibcallImplSet(StringRef Name) const {
-    std::vector<RuntimeLibcallImpl> Result;
-    ArrayRef<const Record *> ImplSet =
-        Records.getAllDerivedDefinitionsIfDefined(Name);
-    Result.reserve(ImplSet.size());
+  const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const {
+    return Def2RuntimeLibcall.lookup(Def);
+  }
 
-    for (const Record *LibCallImplDef : ImplSet)
-      Result.emplace_back(LibCallImplDef, Def2RuntimeLibcall);
-    return Result;
+  const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const {
+    return Def2RuntimeLibcallImpl.lookup(Def);
   }
 
   void run(raw_ostream &OS);
@@ -182,72 +247,36 @@ void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const {
         "namespace RTLIB {\n"
         "enum Libcall : unsigned short {\n";
 
-  size_t CallTypeEnumVal = 0;
   for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
     StringRef Name = LibCall.getName();
-    OS << "  " << Name << " = " << CallTypeEnumVal++ << ",\n";
+    OS << "  " << Name << " = " << LibCall.getEnumVal() << ",\n";
   }
 
   // TODO: Emit libcall names as string offset table.
 
-  OS << "  UNKNOWN_LIBCALL = " << CallTypeEnumVal
+  OS << "  UNKNOWN_LIBCALL = " << RuntimeLibcallDefList.size()
      << "\n};\n\n"
         "enum LibcallImpl : unsigned short {\n"
         "  Unsupported = 0,\n";
 
   // FIXME: Emit this in a different namespace. And maybe use enum class.
-  size_t LibCallImplEnumVal = 1;
   for (const RuntimeLibcallImpl &LibCall : RuntimeLibcallImplDefList) {
-    OS << "  " << LibCall.getName() << " = " << LibCallImplEnumVal++ << ", // "
+    OS << "  " << LibCall.getName() << " = " << LibCall.getEnumVal() << ", // "
        << LibCall.getLibcallFuncName() << '\n';
   }
 
-  OS << "  NumLibcallImpls = " << LibCallImplEnumVal
+  OS << "  NumLibcallImpls = " << RuntimeLibcallImplDefList.size() + 1
      << "\n};\n"
         "} // End namespace RTLIB\n"
         "} // End namespace llvm\n"
         "#endif\n\n";
 }
 
-void RuntimeLibcallEmitter::emitWindowsArm64LibCallNameOverrides(
-    raw_ostream &OS) const {
-  // FIXME: Stop treating this as a special case
-  OS << "void "
-        "llvm::RTLIB::RuntimeLibcallsInfo::setWindowsArm64LibCallNameOverrides("
-        ") {\n"
-        "  static const RTLIB::LibcallImpl "
-        "WindowsArm64RoutineImpls[RTLIB::UNKNOWN_LIBCALL + 1] = {\n";
-  for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
-    auto I = LibCallToDefaultImpl.find(&LibCall);
-    if (I == LibCallToDefaultImpl.end())
-      OS << "    RTLIB::Unsupported,";
-    else {
-      const RuntimeLibcallImpl *LibCallImpl = I->second;
-      assert(LibCallImpl);
-      OS << "    RTLIB::arm64ec_" << LibCallImpl->getName() << ',';
-    }
-
-    OS << " // ";
-    LibCall.emitEnumEntry(OS);
-    OS << '\n';
-  }
-
-  OS << "    RTLIB::Unsupported // RTLIB::UNKNOWN_LIBCALL\n"
-        "  };\n\n"
-        "  std::memcpy(LibcallImpls, WindowsArm64RoutineImpls,\n"
-        "              sizeof(LibcallImpls));\n"
-        "  static_assert(sizeof(LibcallImpls) == "
-        "sizeof(WindowsArm64RoutineImpls),\n"
-        "                \"libcall array size should match\");\n"
-        "}\n#endif\n\n";
-}
-
 void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames(
     raw_ostream &OS) const {
   // TODO: Emit libcall names as string offset table.
 
-  OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n"
-        "const RTLIB::LibcallImpl "
+  OS << "const RTLIB::LibcallImpl "
         "llvm::RTLIB::RuntimeLibcallsInfo::"
         "DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1] = {\n";
 
@@ -259,7 +288,7 @@ void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames(
       const RuntimeLibcallImpl *LibCallImpl = I->second;
       OS << "  ";
       LibCallImpl->emitEnumEntry(OS);
-      OS << ",";
+      OS << ',';
     }
 
     OS << " // ";
@@ -297,48 +326,182 @@ void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames(
     OS << '\n';
   }
   OS << "};\n\n";
+}
 
-  std::vector<RuntimeLibcallImpl> ZOSRuntimeLibcallImplList =
-      getRuntimeLibcallImplSet("ZOSRuntimeLibcallImpl");
-  emitTargetOverrideFunc(OS, "setZOSLibCallNameOverrides",
-                         ZOSRuntimeLibcallImplList);
+void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
+    raw_ostream &OS) const {
+  OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets("
+        "const llvm::Triple &TT) {\n"
+        "  struct LibcallImplPair {\n"
+        "    RTLIB::Libcall Func;\n"
+        "    RTLIB::LibcallImpl Impl;\n"
+        "  };\n";
+  ArrayRef<const Record *> AllLibs =
+      Records.getAllDerivedDefinitions("SystemRuntimeLibrary");
+
+  for (const Record *R : AllLibs) {
+    OS << '\n';
 
-  std::vector<RuntimeLibcallImpl> PPCRuntimeLibcallImplList =
-      getRuntimeLibcallImplSet("PPCRuntimeLibcallImpl");
-  emitTargetOverrideFunc(OS, "setPPCLibCallNameOverrides",
-                         PPCRuntimeLibcallImplList);
+    AvailabilityPredicate TopLevelPredicate(R->getValueAsDef("TriplePred"));
 
-  emitWindowsArm64LibCallNameOverrides(OS);
-}
+    OS << indent(2);
+    TopLevelPredicate.emitIf(OS);
+    SetTheory Sets;
 
-void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallUtils(
-    raw_ostream &OS) const {
-  // FIXME: Hack we shouldn't really need
-  OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_UTILS\n"
-        "static inline bool isAtomicLibCall(llvm::RTLIB::Libcall LC) {\n"
-        "  switch (LC) {\n";
-  for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) {
-    StringRef Name = LibCall.getName();
-    if (Name.contains("ATOMIC")) {
-      OS << "  case ";
-      LibCall.emitEnumEntry(OS);
-      OS << ":\n";
+    DenseMap<const Record *, std::vector<const Record *>> Func2Preds;
+    Sets.addExpander(
+        "LibcallImpls",
+        std::make_unique<LibcallPredicateExpander>(*this, Func2Preds));
+
+    const SetTheory::RecVec *Elements =
+        Sets.expand(R->getValueAsDef("MemberList"));
+
+    // Sort to get deterministic output
+    SetVector<const Record *> PredicateSorter;
+    PredicateSorter.insert(nullptr); // No predicate first.
+
+    DenseMap<const Record *, std::vector<const RuntimeLibcallImpl *>>
+        Pred2Funcs;
+    for (const Record *Elt : *Elements) {
+      const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
+      auto It = Func2Preds.find(Elt);
+      if (It == Func2Preds.end()) {
+        Pred2Funcs[nullptr].push_back(LibCallImpl);
+        continue;
+      }
+
+      for (const Record *Pred : It->second) {
+        Pred2Funcs[Pred].push_back(LibCallImpl);
+        PredicateSorter.insert(Pred);
+      }
     }
+
+    SmallVector<const Record *, 0> SortedPredicates =
+        PredicateSorter.takeVector();
+
+    sort(SortedPredicates, [](const Record *A, const Record *B) {
+      if (!A)
+        return true;
+      if (!B)
+        return false;
+      return A->getName() < B->getName();
+    });
+
+    for (const Record *Pred : SortedPredicates) {
+      AvailabilityPredicate SubsetPredicate(Pred);
+      unsigned IndentDepth = 2;
+
+      auto It = Pred2Funcs.find(Pred);
+      if (It == Pred2Funcs.end())
+        continue;
+
+      if (!SubsetPredicate.isAlwaysAvailable()) {
+        IndentDepth = 4;
+
+        OS << indent(IndentDepth);
+        SubsetPredicate.emitIf(OS);
+      }
+
+      std::vector<const RuntimeLibcallImpl *> &Funcs = It->second;
+
+      // Ensure we only emit a unique implementation per libcall in the
+      // selection table.
+      //
+      // FIXME: We need to generate separate functions for
+      // is-libcall-available and should-libcall-be-used to avoid this.
+      //
+      // This also makes it annoying to make use of the default set, since the
+      // entries from the default set may win over the replacements unless
+      // they are explicitly removed.
+      sort(Funcs, [](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) {
+        return A->getProvides()->getEnumVal() < B->getProvides()->getEnumVal();
+      });
+
+      auto UniqueI = llvm::unique(
+          Funcs, [&](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) {
+            if (A->getProvides() == B->getProvides()) {
+              PrintWarning(R->getLoc(),
+                           Twine("conflicting implementations for libcall " +
+                                 A->getProvides()->getName() + ": " +
+                                 A->getLibcallFuncName() + ", " +
+                                 B->getLibcallFuncName()));
+              return true;
+            }
+
+            return false;
+          });
+
+      Funcs.erase(UniqueI, Funcs.end());
+
+      OS << indent(IndentDepth + 2)
+         << "static const LibcallImplPair LibraryCalls[] = {\n";
+      for (const RuntimeLibcallImpl *LibCallImpl : Funcs) {
+        OS << indent(IndentDepth + 6);
+        LibCallImpl->emitTableEntry(OS);
+      }
+
+      OS << indent(IndentDepth + 2) << "};\n\n"
+         << indent(IndentDepth + 2)
+         << "for (const auto [Func, Impl] : LibraryCalls) {\n"
+         << indent(IndentDepth + 2) << "  setLibcallImpl(Func, Impl);\n"
+         << indent(IndentDepth + 2) << "}\n";
+
+      if (!SubsetPredicate.isAlwaysAvailable()) {
+        OS << indent(IndentDepth);
+        SubsetPredicate.emitEndIf(OS);
+        OS << '\n';
+      }
+    }
+
+    OS << indent(4) << "return;\n" << indent(2);
+    TopLevelPredicate.emitEndIf(OS);
   }
 
-  OS << "    return true;\n"
-        "  default:\n"
-        "    return false;\n"
-        "  }\n\n"
-        "  llvm_unreachable(\"covered switch over libcalls\");\n"
-        "}\n#endif\n\n";
+  // Fallback to the old default set for manual table entries.
+  //
+  // TODO: Remove this when targets have switched to using generated tables by
+  // default.
+  OS << "  initDefaultLibCallImpls();\n";
+
+  OS << "}\n\n";
 }
 
 void RuntimeLibcallEmitter::run(raw_ostream &OS) {
   emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records);
   emitGetRuntimeLibcallEnum(OS);
+
+  OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n";
   emitGetInitRuntimeLibcallNames(OS);
-  emitGetInitRuntimeLibcallUtils(OS);
+  OS << "#endif\n\n";
+
+  OS << "#ifdef GET_SET_TARGET_RUNTIME_LIBCALL_SETS\n";
+  emitSystemRuntimeLibrarySetCalls(OS);
+  OS << "#endif\n\n";
+}
+
+void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def,
+                                      SetTheory::RecSet &Elts) {
+  assert(Def->isSubClassOf("LibcallImpls"));
+
+  SetTheory::RecSet TmpElts;
+
+  ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc());
+
+  Elts.insert(TmpElts.begin(), TmpElts.end());
+
+  AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate"));
+
+  for (const Record *LibcallImpl : TmpElts) {
+    if (!AP.isAlwaysAvailable()) {
+      auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {}});
+      if (!Inserted) {
+        PrintError(
+            Def, "combining nested libcall set predicates currently unhandled");
+      }
+
+      It->second.push_back(AP.getDef());
+    }
+  }
 }
 
 static TableGen::Emitter::OptClass<RuntimeLibcallEmitter>



More information about the llvm-branch-commits mailing list