[llvm-branch-commits] [llvm] TableGen: Handle setting runtime libcall calling conventions (PR #144980)

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


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

Allow associating a non-default CallingConv with a set of library
functions, and applying a default for a SystemLibrary.

I also wanted to be able to apply a default calling conv
to a RuntimeLibcallImpl, but that turned out to be annoying
so leave it for later.

>From f847af321a1fed66af72cd32e48aa3925d74805b Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 13 Jun 2025 15:54:41 +0900
Subject: [PATCH] TableGen: Handle setting runtime libcall calling conventions

Allow associating a non-default CallingConv with a set of library
functions, and applying a default for a SystemLibrary.

I also wanted to be able to apply a default calling conv
to a RuntimeLibcallImpl, but that turned out to be annoying
so leave it for later.
---
 llvm/include/llvm/IR/RuntimeLibcalls.td       | 140 +++++++++++++++--
 llvm/include/llvm/IR/RuntimeLibcallsImpl.td   |  26 +++-
 llvm/lib/IR/RuntimeLibcalls.cpp               | 141 ------------------
 .../RuntimeLibcallEmitter-calling-conv.td     |  85 +++++++++++
 llvm/test/TableGen/RuntimeLibcallEmitter.td   |  19 ++-
 .../TableGen/Basic/RuntimeLibcallsEmitter.cpp | 111 +++++++++++---
 6 files changed, 344 insertions(+), 178 deletions(-)
 create mode 100644 llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td

diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td
index e24b4c928b421..03ac9f5926f87 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.td
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.td
@@ -1254,11 +1254,12 @@ def __gnu_h2f_ieee : RuntimeLibcallImpl<FPEXT_F16_F32>;
 //===----------------------------------------------------------------------===//
 
 // Several of the runtime library functions use a special calling conv
-def __divmodqi4 : RuntimeLibcallImpl<SDIVREM_I8>; // CallingConv::AVR_BUILTIN
-def __divmodhi4 : RuntimeLibcallImpl<SDIVREM_I16>; // CallingConv::AVR_BUILTIN
+def __divmodqi4 : RuntimeLibcallImpl<SDIVREM_I8>;
+def __divmodhi4 : RuntimeLibcallImpl<SDIVREM_I16>;
+def __udivmodqi4 : RuntimeLibcallImpl<UDIVREM_I8>;
+def __udivmodhi4 : RuntimeLibcallImpl<UDIVREM_I16>;
+
 //def __divmodsi4 : RuntimeLibcallImpl<SDIVREM_I32>;
-def __udivmodqi4 : RuntimeLibcallImpl<UDIVREM_I8>; // CallingConv::AVR_BUILTIN
-def __udivmodhi4 : RuntimeLibcallImpl<UDIVREM_I16>; // CallingConv::AVR_BUILTIN
 //def __udivmodsi4 : RuntimeLibcallImpl<UDIVREM_I32>;
 
 // Standard sinf/cosf name replaced with "sin" and "cos". Define a
@@ -1284,9 +1285,12 @@ def AVRSystemLibrary
                // Standard f64 names are replaced
                sin, cos, sinf, cosf),
 
-              __divmodqi4, __divmodhi4, __divmodsi4, __udivmodqi4, __udivmodhi4,
-              __udivmodsi4,
-
+              // Several of the runtime library functions use a special calling
+              // conv
+              LibcallsWithCC<(add __divmodqi4, __divmodhi4, __udivmodqi4,
+                                 __udivmodhi4),
+                             AVR_BUILTIN>,
+              __divmodsi4, __udivmodsi4,
               // Trigonometric rtlib functions
               avr_sin, avr_cos)>;
 
@@ -1509,6 +1513,117 @@ def __mspabi_mpyll : RuntimeLibcallImpl<MUL_I64>;
 
 // setLibcallCallingConv(MUL_I64, CallingConv::MSP430_BUILTIN);
 
+def isMSP430 : RuntimeLibcallPredicate<"TT.getArch() == Triple::msp430">;
+
+defvar MSP430DefaultOptOut = [
+  __addsf3, __divsf3, __extendsfdf2, __truncdfsf2, __fixsfsi,
+  __fixsfdi, __fixunssfsi, __mulsf3, __eqsf2, __gesf2, __gtsf2,
+  __divhi3, __divsi3, __ashlsi3, __floatsidf, __floatsisf,
+  __ashrsi3, __modhi3, __udivsi3, __fixdfsi, __fixunssfdi,
+  __udivhi3, __umodsi3, __nesf2, __lesf2, __floatundisf,
+  __fixdfdi, __fixunsdfsi, __modsi3, __floatunsisf,
+  __fixunsdfdi, __ltsf2, __floatdisf, __floatdidf,
+  __lshrsi3, __subsf3, __umodhi3, __floatunsidf,
+  __floatundidf
+];
+
+// EABI Libcalls - EABI Section 6.2
+def MSP430SystemLibrary
+    : SystemRuntimeLibrary<isMSP430,
+    (add (sub DefaultRuntimeLibcallImpls, MSP430DefaultOptOut),
+
+      // Floating point conversions - EABI Table 6
+      __mspabi_cvtdf,
+      __mspabi_cvtfd,
+      // The following is NOT implemented in libgcc
+      //__mspabi_fixdi,
+      __mspabi_fixdli,
+      __mspabi_fixdlli,
+      // The following is NOT implemented in libgcc
+      // __mspabi_fixdu
+      __mspabi_fixdul,
+      __mspabi_fixdull,
+      // The following is NOT implemented in libgcc
+      //__mspabi_fixfi,
+      __mspabi_fixfli,
+      __mspabi_fixflli,
+      // The following is NOT implemented in libgcc
+      //__mspabi_fixfu,
+      __mspabi_fixful,
+      __mspabi_fixfull,
+      // TODO The following IS implemented in libgcc
+      //__mspabi_fltid
+      __mspabi_fltlid,
+      // TODO The following IS implemented in libgcc but is not in the EABI
+      __mspabi_fltllid,
+      // TODO The following IS implemented in libgcc
+      //__mspabi_fltud,
+      __mspabi_fltuld,
+      // The following IS implemented in libgcc but is not in the EABI
+      __mspabi_fltulld,
+      // TODO The following IS implemented in libgcc
+      //__mspabi_fltif,
+      __mspabi_fltlif,
+      // TODO The following IS implemented in libgcc but is not in the EABI
+      __mspabi_fltllif,
+      // TODO The following IS implemented in libgcc
+      //__mspabi_fltuf,
+      __mspabi_fltulf,
+      // The following IS implemented in libgcc but is not in the EABI
+      __mspabi_fltullf,
+
+      // Floating point comparisons - EABI Table 7
+      LibcallsWithCC<(add __mspabi_cmpd__oeq,
+                          __mspabi_cmpd__une,
+                          __mspabi_cmpd__oge,
+                          __mspabi_cmpd__olt,
+                          __mspabi_cmpd__ole,
+                          __mspabi_cmpd__ogt), MSP430_BUILTIN>,
+      __mspabi_cmpf__oeq,
+      __mspabi_cmpf__une,
+      __mspabi_cmpf__oge,
+      __mspabi_cmpf__olt,
+      __mspabi_cmpf__ole,
+      __mspabi_cmpf__ogt,
+
+      // Floating point arithmetic - EABI Table 8
+      LibcallsWithCC<(add __mspabi_addd,
+      __mspabi_subd,
+      __mspabi_mpyd,
+      __mspabi_divd), MSP430_BUILTIN>,
+
+      __mspabi_addf,
+      __mspabi_subf,
+      __mspabi_mpyf,
+      __mspabi_divf,
+
+      // The following are NOT implemented in libgcc
+      // __mspabi_negd,
+      // __mspabi_negf,
+
+      // Universal Integer Operations - EABI Table 9
+      __mspabi_divi,
+      __mspabi_divli,
+      LibcallsWithCC<(add __mspabi_divlli), MSP430_BUILTIN>,
+      __mspabi_divu,
+      __mspabi_divul,
+      LibcallsWithCC<(add __mspabi_divull), MSP430_BUILTIN>,
+      __mspabi_remi,
+      __mspabi_remli,
+      LibcallsWithCC<(add __mspabi_remlli), MSP430_BUILTIN>,
+      __mspabi_remu,
+      __mspabi_remul,
+      LibcallsWithCC<(add __mspabi_remull), MSP430_BUILTIN>,
+
+      // Bitwise Operations - EABI Table 10
+      // TODO: __mspabi_[srli/srai/slli] ARE implemented in libgcc
+      __mspabi_srll,
+      __mspabi_sral,
+      __mspabi_slll
+      // __mspabi_[srlll/srall/sllll/rlli/rlll] are NOT implemented in libgcc
+  )
+>;
+
 //===----------------------------------------------------------------------===//
 // NVPTX Runtime Libcalls
 //===----------------------------------------------------------------------===//
@@ -1655,11 +1770,12 @@ def _Q_ulltoq : RuntimeLibcallImpl<UINTTOFP_I64_F128>;
 //===----------------------------------------------------------------------===//
 
 // TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment()
-def _alldiv : RuntimeLibcallImpl<SDIV_I64>; // CallingConv::X86_StdCall
-def _aulldiv : RuntimeLibcallImpl<UDIV_I64>; // CallingConv::X86_StdCall
-def _allrem : RuntimeLibcallImpl<SREM_I64>; // CallingConv::X86_StdCall
-def _aullrem : RuntimeLibcallImpl<UREM_I64>; // CallingConv::X86_StdCall
-def _allmul : RuntimeLibcallImpl<MUL_I64>; // CallingConv::X86_StdCall
+
+def _alldiv : RuntimeLibcallImpl<SDIV_I64>;
+def _aulldiv : RuntimeLibcallImpl<UDIV_I64>;
+def _allrem : RuntimeLibcallImpl<SREM_I64>;
+def _aullrem : RuntimeLibcallImpl<UREM_I64>;
+def _allmul : RuntimeLibcallImpl<MUL_I64>;
 
 //===----------------------------------------------------------------------===//
 // XCore Runtime Libcalls
diff --git a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
index d64e0d0adfa75..00c2575b14a6e 100644
--- a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
+++ b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td
@@ -23,6 +23,19 @@ class LibcallLoweringPredicate<code cond> { code Cond = cond; }
 
 def AlwaysAvailable : RuntimeLibcallPredicate<[{}]>;
 
+class LibcallCallingConv<code CC = [{}]> {
+  // Enum value for the calling convention. Empty string defaults to
+  // CallingConv::C.
+  code CallingConv = CC;
+}
+
+def DefaultCC : LibcallCallingConv;
+def MSP430_BUILTIN : LibcallCallingConv<[{CallingConv::MSP430_BUILTIN}]>;
+def ARM_AAPCS : LibcallCallingConv<[{CallingConv::ARM_AAPCS}]>;
+def ARM_AAPCS_VFP : LibcallCallingConv<[{CallingConv::ARM_AAPCS_VFP}]>;
+def X86_STDCALL : LibcallCallingConv<[{CallingConv::X86_StdCall}]>;
+def AVR_BUILTIN : LibcallCallingConv<[{CallingConv::AVR_BUILTIN}]>;
+
 /// 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
@@ -41,7 +54,6 @@ class RuntimeLibcall {
 // Concrete implementation of a libcall, which may have a different
 // name and only be valid on some subset of targets.
 
-// TODO: Do we need a way to conditionally select calling convention?
 class RuntimeLibcallImpl<RuntimeLibcall P, string Name = NAME> {
   RuntimeLibcall Provides = P;
   string LibCallFuncName = Name;
@@ -54,6 +66,10 @@ class LibcallImpls<dag funcList,
   // Function of the triple where this applies
   RuntimeLibcallPredicate AvailabilityPredicate = Pred;
   dag MemberList = funcList;
+
+  // If set, applies calling convention to every entry instead of
+  // taking the system default.
+  LibcallCallingConv CallingConv = ?;
 }
 
 /// Convenience wrapper around LibcallImplSet to make a single libcall
@@ -61,8 +77,16 @@ class LibcallImpls<dag funcList,
 class AvailableIf<RuntimeLibcallImpl Impl, RuntimeLibcallPredicate Pred>
     : LibcallImpls<(add Impl), Pred>;
 
+class LibcallsWithCC<dag funcList, LibcallCallingConv CC,
+                     RuntimeLibcallPredicate Pred = AlwaysAvailable>
+    : LibcallImpls<funcList, Pred> {
+  LibcallCallingConv CallingConv = CC;
+}
+
 /// Define a complete top level set of runtime libcalls for a target.
 class SystemRuntimeLibrary<RuntimeLibcallPredicate Pred, dag funcList> {
+  /// Set the default calling convention assumed for RuntimeLibcallImpl members.
+  LibcallCallingConv DefaultLibcallCallingConv = DefaultCC;
   RuntimeLibcallPredicate TriplePred = Pred;
   LibcallImpls MemberList = LibcallImpls<funcList>;
 }
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 9492aef16e638..1e2ae4a6c69ef 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -100,137 +100,6 @@ static void setARMLibcallNames(RuntimeLibcallsInfo &Info, const Triple &TT,
   }
 }
 
-static void setMSP430Libcalls(RuntimeLibcallsInfo &Info, const Triple &TT) {
-  // EABI Libcalls - EABI Section 6.2
-  const struct {
-    const RTLIB::Libcall Op;
-    const RTLIB::LibcallImpl Impl;
-  } LibraryCalls[] = {
-      // Floating point conversions - EABI Table 6
-      {RTLIB::FPROUND_F64_F32, RTLIB::__mspabi_cvtdf},
-      {RTLIB::FPEXT_F32_F64, RTLIB::__mspabi_cvtfd},
-      // The following is NOT implemented in libgcc
-      //{ RTLIB::FPTOSINT_F64_I16,  RTLIB::__mspabi_fixdi },
-      {RTLIB::FPTOSINT_F64_I32, RTLIB::__mspabi_fixdli},
-      {RTLIB::FPTOSINT_F64_I64, RTLIB::__mspabi_fixdlli},
-      // The following is NOT implemented in libgcc
-      //{ RTLIB::FPTOUINT_F64_I16,  RTLIB::__mspabi_fixdu },
-      {RTLIB::FPTOUINT_F64_I32, RTLIB::__mspabi_fixdul},
-      {RTLIB::FPTOUINT_F64_I64, RTLIB::__mspabi_fixdull},
-      // The following is NOT implemented in libgcc
-      //{ RTLIB::FPTOSINT_F32_I16,  RTLIB::__mspabi_fixfi },
-      {RTLIB::FPTOSINT_F32_I32, RTLIB::__mspabi_fixfli},
-      {RTLIB::FPTOSINT_F32_I64, RTLIB::__mspabi_fixflli},
-      // The following is NOT implemented in libgcc
-      //{ RTLIB::FPTOUINT_F32_I16,  RTLIB::__mspabi_fixfu },
-      {RTLIB::FPTOUINT_F32_I32, RTLIB::__mspabi_fixful},
-      {RTLIB::FPTOUINT_F32_I64, RTLIB::__mspabi_fixfull},
-      // TODO The following IS implemented in libgcc
-      //{ RTLIB::SINTTOFP_I16_F64,  RTLIB::__mspabi_fltid },
-      {RTLIB::SINTTOFP_I32_F64, RTLIB::__mspabi_fltlid},
-      // TODO The following IS implemented in libgcc but is not in the EABI
-      {RTLIB::SINTTOFP_I64_F64, RTLIB::__mspabi_fltllid},
-      // TODO The following IS implemented in libgcc
-      //{ RTLIB::UINTTOFP_I16_F64,  RTLIB::__mspabi_fltud },
-      {RTLIB::UINTTOFP_I32_F64, RTLIB::__mspabi_fltuld},
-      // The following IS implemented in libgcc but is not in the EABI
-      {RTLIB::UINTTOFP_I64_F64, RTLIB::__mspabi_fltulld},
-      // TODO The following IS implemented in libgcc
-      //{ RTLIB::SINTTOFP_I16_F32,  RTLIB::__mspabi_fltif },
-      {RTLIB::SINTTOFP_I32_F32, RTLIB::__mspabi_fltlif},
-      // TODO The following IS implemented in libgcc but is not in the EABI
-      {RTLIB::SINTTOFP_I64_F32, RTLIB::__mspabi_fltllif},
-      // TODO The following IS implemented in libgcc
-      //{ RTLIB::UINTTOFP_I16_F32,  RTLIB::__mspabi_fltuf },
-      {RTLIB::UINTTOFP_I32_F32, RTLIB::__mspabi_fltulf},
-      // The following IS implemented in libgcc but is not in the EABI
-      {RTLIB::UINTTOFP_I64_F32, RTLIB::__mspabi_fltullf},
-
-      // Floating point comparisons - EABI Table 7
-      {RTLIB::OEQ_F64, RTLIB::__mspabi_cmpd__oeq},
-      {RTLIB::UNE_F64, RTLIB::__mspabi_cmpd__une},
-      {RTLIB::OGE_F64, RTLIB::__mspabi_cmpd__oge},
-      {RTLIB::OLT_F64, RTLIB::__mspabi_cmpd__olt},
-      {RTLIB::OLE_F64, RTLIB::__mspabi_cmpd__ole},
-      {RTLIB::OGT_F64, RTLIB::__mspabi_cmpd__ogt},
-      {RTLIB::OEQ_F32, RTLIB::__mspabi_cmpf__oeq},
-      {RTLIB::UNE_F32, RTLIB::__mspabi_cmpf__une},
-      {RTLIB::OGE_F32, RTLIB::__mspabi_cmpf__oge},
-      {RTLIB::OLT_F32, RTLIB::__mspabi_cmpf__olt},
-      {RTLIB::OLE_F32, RTLIB::__mspabi_cmpf__ole},
-      {RTLIB::OGT_F32, RTLIB::__mspabi_cmpf__ogt},
-
-      // Floating point arithmetic - EABI Table 8
-      {RTLIB::ADD_F64, RTLIB::__mspabi_addd},
-      {RTLIB::ADD_F32, RTLIB::__mspabi_addf},
-      {RTLIB::DIV_F64, RTLIB::__mspabi_divd},
-      {RTLIB::DIV_F32, RTLIB::__mspabi_divf},
-      {RTLIB::MUL_F64, RTLIB::__mspabi_mpyd},
-      {RTLIB::MUL_F32, RTLIB::__mspabi_mpyf},
-      {RTLIB::SUB_F64, RTLIB::__mspabi_subd},
-      {RTLIB::SUB_F32, RTLIB::__mspabi_subf},
-      // The following are NOT implemented in libgcc
-      // { RTLIB::NEG_F64,  RTLIB::__mspabi_negd },
-      // { RTLIB::NEG_F32,  RTLIB::__mspabi_negf },
-
-      // Universal Integer Operations - EABI Table 9
-      {RTLIB::SDIV_I16, RTLIB::__mspabi_divi},
-      {RTLIB::SDIV_I32, RTLIB::__mspabi_divli},
-      {RTLIB::SDIV_I64, RTLIB::__mspabi_divlli},
-      {RTLIB::UDIV_I16, RTLIB::__mspabi_divu},
-      {RTLIB::UDIV_I32, RTLIB::__mspabi_divul},
-      {RTLIB::UDIV_I64, RTLIB::__mspabi_divull},
-      {RTLIB::SREM_I16, RTLIB::__mspabi_remi},
-      {RTLIB::SREM_I32, RTLIB::__mspabi_remli},
-      {RTLIB::SREM_I64, RTLIB::__mspabi_remlli},
-      {RTLIB::UREM_I16, RTLIB::__mspabi_remu},
-      {RTLIB::UREM_I32, RTLIB::__mspabi_remul},
-      {RTLIB::UREM_I64, RTLIB::__mspabi_remull},
-
-      // Bitwise Operations - EABI Table 10
-      // TODO: __mspabi_[srli/srai/slli] ARE implemented in libgcc
-      {RTLIB::SRL_I32, RTLIB::__mspabi_srll},
-      {RTLIB::SRA_I32, RTLIB::__mspabi_sral},
-      {RTLIB::SHL_I32, RTLIB::__mspabi_slll},
-      // __mspabi_[srlll/srall/sllll/rlli/rlll] are NOT implemented in libgcc
-  };
-
-  for (const auto &LC : LibraryCalls)
-    Info.setLibcallImpl(LC.Op, LC.Impl);
-
-  // Several of the runtime library functions use a special calling conv
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_divull,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_remull,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_divlli,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_remlli,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_addd,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_subd,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_mpyd,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_divd,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_cmpd__oeq,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_cmpd__une,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_cmpd__oge,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_cmpd__olt,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_cmpd__ole,
-                                 CallingConv::MSP430_BUILTIN);
-  Info.setLibcallImplCallingConv(RTLIB::__mspabi_cmpd__ogt,
-                                 CallingConv::MSP430_BUILTIN);
-
-  // TODO: __mspabi_srall, __mspabi_srlll, __mspabi_sllll
-}
-
 void RuntimeLibcallsInfo::initSoftFloatCmpLibcallPredicates() {
   SoftFloatCompareLibcallPredicates[RTLIB::OEQ_F32] = CmpInst::ICMP_EQ;
   SoftFloatCompareLibcallPredicates[RTLIB::OEQ_F64] = CmpInst::ICMP_EQ;
@@ -473,13 +342,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
 
   if (TT.isARM() || TT.isThumb())
     setARMLibcallNames(*this, TT, FloatABI, EABIVersion);
-  else if (TT.getArch() == Triple::ArchType::avr) {
-    // Several of the runtime library functions use a special calling conv
-    setLibcallImplCallingConv(RTLIB::__divmodqi4, CallingConv::AVR_BUILTIN);
-    setLibcallImplCallingConv(RTLIB::__divmodhi4, CallingConv::AVR_BUILTIN);
-    setLibcallImplCallingConv(RTLIB::__udivmodqi4, CallingConv::AVR_BUILTIN);
-    setLibcallImplCallingConv(RTLIB::__udivmodhi4, CallingConv::AVR_BUILTIN);
-  }
 
   if (!TT.isWasm()) {
     // These libcalls are only available in compiler-rt, not libgcc.
@@ -535,7 +397,4 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
         RTLIB::HEXAGON_MEMCPY_LIKELY_ALIGNED_MIN32BYTES_MULT8BYTES,
         RTLIB::__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes);
   }
-
-  if (TT.getArch() == Triple::ArchType::msp430)
-    setMSP430Libcalls(*this, TT);
 }
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td b/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td
new file mode 100644
index 0000000000000..94c0caa2c2820
--- /dev/null
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter-calling-conv.td
@@ -0,0 +1,85 @@
+// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s | FileCheck %s
+
+include "llvm/IR/RuntimeLibCallsImpl.td"
+
+def SDIVREM_I8 : RuntimeLibcall;
+def UDIVREM_I16 : RuntimeLibcall;
+def MALLOC : RuntimeLibcall;
+def TARGET_OVERRIDE_CC : RuntimeLibcall;
+
+//let CallingConv = AVR_BUILTIN in {
+def __divmodqi4 : RuntimeLibcallImpl<SDIVREM_I8>;
+def __udivmodhi4 : RuntimeLibcallImpl<UDIVREM_I16>;
+//}
+
+// Test a case where a target wants to set a different calling
+// convention on a generic builtin
+def __target_override_cc : RuntimeLibcallImpl<TARGET_OVERRIDE_CC>;
+
+def malloc : RuntimeLibcallImpl<MALLOC>;
+
+def isAVR : RuntimeLibcallPredicate<[{TT.getArch() == Triple::avr}]>;
+
+def isAVRHurd : RuntimeLibcallPredicate<
+  [{TT.getArch() == Triple::avr && TT.isOSHurd()}]>;
+
+def AVRLibrary : SystemRuntimeLibrary<isAVR,
+  (add malloc, LibcallsWithCC<(add __divmodqi4, __udivmodhi4), AVR_BUILTIN>)
+>;
+
+// Test with default calling convention
+def AVRHurdLibrary : SystemRuntimeLibrary<isAVRHurd,
+  (add malloc, LibcallsWithCC<(add __divmodqi4, __udivmodhi4), AVR_BUILTIN>)> {
+  let DefaultLibcallCallingConv
+    = LibcallCallingConv<[{isFoo() ? CallingConv::Fast : CallingConv::GHC}]>;
+}
+
+// CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(const llvm::Triple &TT) {
+// CHECK: if (TT.getArch() == Triple::avr && TT.isOSHurd()) {
+// CHECK-NEXT:   const CallingConv::ID DefaultCC = isFoo() ? CallingConv::Fast : CallingConv::GHC;
+// CHECK-NEXT:   for (CallingConv::ID &Entry : LibcallImplCallingConvs) {
+// CHECK-NEXT:     Entry = isFoo() ? CallingConv::Fast : CallingConv::GHC;
+// CHECK-NEXT:   }
+// CHECK-EMPTY:
+// CHECK-NEXT:    static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:        {RTLIB::MALLOC, RTLIB::malloc}, // malloc
+// CHECK-NEXT:    };
+// CHECK-EMPTY:
+// CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:      setLibcallImpl(Func, Impl);
+// CHECK-NEXT:    }
+// CHECK-EMPTY:
+// CHECK-NEXT:    static const LibcallImplPair LibraryCalls_AlwaysAvailable[] = {
+// CHECK-NEXT:        {RTLIB::SDIVREM_I8, RTLIB::__divmodqi4}, // __divmodqi4
+// CHECK-NEXT:        {RTLIB::UDIVREM_I16, RTLIB::__udivmodhi4}, // __udivmodhi4
+// CHECK-NEXT:    };
+// CHECK-EMPTY:
+// CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls_AlwaysAvailable) {
+// CHECK-NEXT:      setLibcallImpl(Func, Impl);
+// CHECK-NEXT:      setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
+// CHECK-NEXT:    }
+// CHECK-EMPTY:
+// CHECK-NEXT:    return;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT: if (TT.getArch() == Triple::avr) {
+// CHECK-NEXT:   static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:       {RTLIB::MALLOC, RTLIB::malloc}, // malloc
+// CHECK-NEXT:   };
+// CHECK-EMPTY:
+// CHECK-NEXT:   for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:     setLibcallImpl(Func, Impl);
+// CHECK-NEXT:   }
+// CHECK-EMPTY:
+// CHECK-NEXT:   static const LibcallImplPair LibraryCalls_AlwaysAvailable[] = {
+// CHECK-NEXT:       {RTLIB::SDIVREM_I8, RTLIB::__divmodqi4}, // __divmodqi4
+// CHECK-NEXT:       {RTLIB::UDIVREM_I16, RTLIB::__udivmodhi4}, // __udivmodhi4
+// CHECK-NEXT:   };
+// CHECK-EMPTY:
+// CHECK-NEXT:   for (const auto [Func, Impl] : LibraryCalls_AlwaysAvailable) {
+// CHECK-NEXT:     setLibcallImpl(Func, Impl);
+// CHECK-NEXT:     setLibcallImplCallingConv(Impl, CallingConv::AVR_BUILTIN);
+// CHECK-NEXT:   }
+// CHECK-EMPTY:
+// CHECK-NEXT:   return;
+// CHECK-NEXT:  }
diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td
index d810ce3787703..02974233d04f9 100644
--- a/llvm/test/TableGen/RuntimeLibcallEmitter.td
+++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td
@@ -162,25 +162,28 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
 // CHECK-NEXT:     for (const auto [Func, Impl] : LibraryCalls) {
 // CHECK-NEXT:       setLibcallImpl(Func, Impl);
 // CHECK-NEXT:     }
+// CHECK-EMPTY:
 // CHECK-NEXT:    if (TT.hasCompilerRT()) {
-// CHECK-NEXT:      static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:      static const LibcallImplPair LibraryCalls_hasCompilerRT[] = {
 // 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:      for (const auto [Func, Impl] : LibraryCalls_hasCompilerRT) {
 // CHECK-NEXT:        setLibcallImpl(Func, Impl);
 // CHECK-NEXT:      }
+// CHECK-EMPTY:
 // CHECK-NEXT:    }
 // CHECK-EMPTY:
 // CHECK-NEXT:    if (TT.getOS() == Triple::bar) {
-// CHECK-NEXT:      static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:      static const LibcallImplPair LibraryCalls_isBarOS[] = {
 // CHECK-NEXT:          {RTLIB::MEMSET, RTLIB::___memset}, // ___memset
 // CHECK-NEXT:      };
 // CHECK-EMPTY:
-// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls_isBarOS) {
 // CHECK-NEXT:        setLibcallImpl(Func, Impl);
 // CHECK-NEXT:      }
+// CHECK-EMPTY:
 // CHECK-NEXT:    }
 // CHECK-EMPTY:
 // CHECK-NEXT:   return;
@@ -196,6 +199,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
 // CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
 // CHECK-NEXT:      setLibcallImpl(Func, Impl);
 // CHECK-NEXT:    }
+// CHECK-EMPTY:
 // CHECK-NEXT:   return;
 // CHECK-NEXT: }
 // CHECK-EMPTY:
@@ -208,14 +212,16 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
 // CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
 // CHECK-NEXT:      setLibcallImpl(Func, Impl);
 // CHECK-NEXT:    }
+// CHECK-EMPTY:
 // CHECK-NEXT:    if (TT.getOS() == Triple::bar) {
-// CHECK-NEXT:      static const LibcallImplPair LibraryCalls[] = {
+// CHECK-NEXT:      static const LibcallImplPair LibraryCalls_isBarOS[] = {
 // CHECK-NEXT:          {RTLIB::MEMSET, RTLIB::___memset}, // ___memset
 // CHECK-NEXT:      };
 // CHECK-EMPTY:
-// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls) {
+// CHECK-NEXT:      for (const auto [Func, Impl] : LibraryCalls_isBarOS) {
 // CHECK-NEXT:        setLibcallImpl(Func, Impl);
 // CHECK-NEXT:      }
+// CHECK-EMPTY:
 // CHECK-NEXT:    }
 // CHECK-EMPTY:
 // CHECK-NEXT:    return;
@@ -232,6 +238,7 @@ def BlahLibrary : SystemRuntimeLibrary<isBlahArch, (add calloc, LibraryWithCondi
 // CHECK-NEXT:    for (const auto [Func, Impl] : LibraryCalls) {
 // CHECK-NEXT:      setLibcallImpl(Func, Impl);
 // CHECK-NEXT:    }
+// CHECK-EMPTY:
 // CHECK-NEXT:   return;
 // CHECK-NEXT: }
 // CHECK-NEXT:  initDefaultLibCallImpls();
diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
index 30fcca47a4706..6d3d117737f37 100644
--- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp
@@ -37,6 +37,11 @@ class AvailabilityPredicate {
   }
 
   void emitEndIf(raw_ostream &OS) const { OS << "}\n"; }
+
+  void emitTableVariableNameSuffix(raw_ostream &OS) const {
+    if (TheDef)
+      OS << '_' << TheDef->getName();
+  }
 };
 
 class RuntimeLibcallEmitter;
@@ -45,11 +50,14 @@ 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;
+  DenseMap<const RuntimeLibcallImpl *,
+           std::pair<std::vector<const Record *>, const Record *>> &Func2Preds;
 
   LibcallPredicateExpander(
       const RuntimeLibcallEmitter &LibcallEmitter,
-      DenseMap<const Record *, std::vector<const Record *>> &Func2Preds)
+      DenseMap<const RuntimeLibcallImpl *,
+               std::pair<std::vector<const Record *>, const Record *>>
+          &Func2Preds)
       : LibcallEmitter(LibcallEmitter), Func2Preds(Func2Preds) {}
 
   void expand(SetTheory &ST, const Record *Def,
@@ -109,6 +117,10 @@ class RuntimeLibcallImpl {
     return TheDef->getValueAsString("LibCallFuncName");
   }
 
+  const Record *getCallingConv() const {
+    return TheDef->getValueAsOptionalDef("CallingConv");
+  }
+
   void emitQuotedLibcallFuncName(raw_ostream &OS) const {
     OS << '\"' << getLibcallFuncName() << '\"';
   }
@@ -134,6 +146,13 @@ class RuntimeLibcallImpl {
     emitEnumEntry(OS);
     OS << "}, // " << getLibcallFuncName() << '\n';
   }
+
+  void emitSetCallingConv(raw_ostream &OS) const {}
+};
+
+struct LibcallsWithCC {
+  std::vector<const RuntimeLibcallImpl *> LibcallImpls;
+  const Record *CallingConv = nullptr;
 };
 
 class RuntimeLibcallEmitter {
@@ -346,32 +365,66 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
 
     OS << indent(2);
     TopLevelPredicate.emitIf(OS);
+
+    if (const Record *DefaultCCClass =
+            R->getValueAsDef("DefaultLibcallCallingConv")) {
+      StringRef DefaultCC =
+          DefaultCCClass->getValueAsString("CallingConv").trim();
+
+      if (!DefaultCC.empty()) {
+        OS << "    const CallingConv::ID DefaultCC = " << DefaultCC << ";\n"
+           << "    for (CallingConv::ID &Entry : LibcallImplCallingConvs) {\n"
+              "      Entry = "
+           << DefaultCC
+           << ";\n"
+              "    }\n\n";
+      }
+    }
+
     SetTheory Sets;
 
-    DenseMap<const Record *, std::vector<const Record *>> Func2Preds;
+    DenseMap<const RuntimeLibcallImpl *,
+             std::pair<std::vector<const Record *>, const Record *>>
+        Func2Preds;
     Sets.addExpander(
         "LibcallImpls",
         std::make_unique<LibcallPredicateExpander>(*this, Func2Preds));
+    //    Sets.addFieldExpander("LibcallWithCC", "Libcall");
+    //    Sets.addFieldExpander("LibcallWithCC", "CallingConv");
 
     const SetTheory::RecVec *Elements =
         Sets.expand(R->getValueAsDef("MemberList"));
 
+    //    const SetTheory::RecVec *CallingConvElements =
+    //      Sets.expand(R->getValueAsDef("CallingConvList"));
+    //    const SetTheory::RecVec *CallingConvElements =
+    //      Sets.expand(R);
+
+#if 0
+    for (const Record *CCElt : *CallingConvElements) {
+      dbgs() << "CC Elt: ";
+      CCElt->dump();
+      dbgs() << '\n';
+    }
+#endif
+
     // Sort to get deterministic output
     SetVector<const Record *> PredicateSorter;
     PredicateSorter.insert(nullptr); // No predicate first.
 
-    DenseMap<const Record *, std::vector<const RuntimeLibcallImpl *>>
-        Pred2Funcs;
+    DenseMap<const Record *, LibcallsWithCC> Pred2Funcs;
     for (const Record *Elt : *Elements) {
       const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt);
-      auto It = Func2Preds.find(Elt);
+      auto It = Func2Preds.find(LibCallImpl);
       if (It == Func2Preds.end()) {
-        Pred2Funcs[nullptr].push_back(LibCallImpl);
+        Pred2Funcs[nullptr].LibcallImpls.push_back(LibCallImpl);
+        // Pred2Funcs[nullptr].CallingConv =
         continue;
       }
 
-      for (const Record *Pred : It->second) {
-        Pred2Funcs[Pred].push_back(LibCallImpl);
+      for (const Record *Pred : It->second.first) {
+        Pred2Funcs[Pred].LibcallImpls.push_back(LibCallImpl);
+        Pred2Funcs[Pred].CallingConv = It->second.second;
         PredicateSorter.insert(Pred);
       }
     }
@@ -402,7 +455,9 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
         SubsetPredicate.emitIf(OS);
       }
 
-      std::vector<const RuntimeLibcallImpl *> &Funcs = It->second;
+      LibcallsWithCC &FuncsWithCC = It->second;
+
+      std::vector<const RuntimeLibcallImpl *> &Funcs = FuncsWithCC.LibcallImpls;
 
       // Ensure we only emit a unique implementation per libcall in the
       // selection table.
@@ -434,7 +489,9 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
       Funcs.erase(UniqueI, Funcs.end());
 
       OS << indent(IndentDepth + 2)
-         << "static const LibcallImplPair LibraryCalls[] = {\n";
+         << "static const LibcallImplPair LibraryCalls";
+      SubsetPredicate.emitTableVariableNameSuffix(OS);
+      OS << "[] = {\n";
       for (const RuntimeLibcallImpl *LibCallImpl : Funcs) {
         OS << indent(IndentDepth + 6);
         LibCallImpl->emitTableEntry(OS);
@@ -442,9 +499,20 @@ void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls(
 
       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";
+         << "for (const auto [Func, Impl] : LibraryCalls";
+      SubsetPredicate.emitTableVariableNameSuffix(OS);
+      OS << ") {\n"
+         << indent(IndentDepth + 4) << "setLibcallImpl(Func, Impl);\n";
+
+      if (FuncsWithCC.CallingConv) {
+        StringRef CCEnum =
+            FuncsWithCC.CallingConv->getValueAsString("CallingConv");
+        OS << indent(IndentDepth + 4) << "setLibcallImplCallingConv(Impl, "
+           << CCEnum << ");\n";
+      }
+
+      OS << indent(IndentDepth + 2) << "}\n";
+      OS << '\n';
 
       if (!SubsetPredicate.isAlwaysAvailable()) {
         OS << indent(IndentDepth);
@@ -490,16 +558,23 @@ void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def,
   Elts.insert(TmpElts.begin(), TmpElts.end());
 
   AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate"));
+  const Record *CCClass = Def->getValueAsOptionalDef("CallingConv");
+
+  // This is assuming we aren't conditionally applying a calling convention to
+  // some subsets, and not another, but this doesn't appear to be used.
 
-  for (const Record *LibcallImpl : TmpElts) {
-    if (!AP.isAlwaysAvailable()) {
-      auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {}});
+  for (const Record *LibcallImplDef : TmpElts) {
+    const RuntimeLibcallImpl *LibcallImpl =
+        LibcallEmitter.getRuntimeLibcallImpl(LibcallImplDef);
+    if (!AP.isAlwaysAvailable() || CCClass) {
+      auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {{}, CCClass}});
       if (!Inserted) {
         PrintError(
             Def, "combining nested libcall set predicates currently unhandled");
       }
 
-      It->second.push_back(AP.getDef());
+      It->second.first.push_back(AP.getDef());
+      It->second.second = CCClass;
     }
   }
 }



More information about the llvm-branch-commits mailing list