[lld] [llvm] [LLVM][LTO] Factor out RTLib calls and allow them to be dropped (PR #98512)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 11 11:02:38 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
@llvm/pr-subscribers-platform-windows

@llvm/pr-subscribers-lld-wasm

Author: Joseph Huber (jhuber6)

<details>
<summary>Changes</summary>

Summary:
The LTO pass and LLD linker have logic in them that forces extraction
and prevent internalization of needed runtime calls. However, these
currently take all RTLibcalls into account, even if the target does not
support them. The target opts-out of a libcall if it sets its name to
nullptr. This patch pulls this logic out into a class in the header so
that LTO / lld can use it to determine if a symbol actually needs to be
kept.

This is important for targets like AMDGPU that want to be able to use
`lld` to perform the final link step, but cannot maintain the overhead
of several unused function calls.


---

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


9 Files Affected:

- (modified) lld/COFF/Driver.cpp (+5-2) 
- (modified) lld/ELF/Driver.cpp (+4-2) 
- (modified) lld/wasm/Driver.cpp (+4-2) 
- (modified) llvm/include/llvm/CodeGen/TargetLowering.h (+440-24) 
- (modified) llvm/include/llvm/LTO/LTO.h (+1-1) 
- (modified) llvm/lib/CodeGen/TargetLoweringBase.cpp (+2-371) 
- (modified) llvm/lib/LTO/LTO.cpp (+8-7) 
- (modified) llvm/lib/Object/IRSymtab.cpp (+13-7) 
- (modified) llvm/tools/lto/lto.cpp (+1-1) 


``````````diff
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index cef6271e4c8f8..9e28b1c50be50 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2428,9 +2428,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
       // file's symbol table. If any of those library functions are defined in a
       // bitcode file in an archive member, we need to arrange to use LTO to
       // compile those archive members by adding them to the link beforehand.
-      if (!ctx.bitcodeFileInstances.empty())
-        for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
+      if (!ctx.bitcodeFileInstances.empty()) {
+        llvm::Triple TT(
+            ctx.bitcodeFileInstances.front()->obj->getTargetTriple());
+        for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))
           ctx.symtab.addLibcall(s);
+      }
 
       // Windows specific -- if __load_config_used can be resolved, resolve it.
       if (ctx.symtab.findUnderscore("_load_config_used"))
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index abfa313bfef0e..5c7ff8dcda945 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2883,9 +2883,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
   // to, i.e. if the symbol's definition is in bitcode. Any other required
   // libcall symbols will be added to the link after LTO when we add the LTO
   // object file to the link.
-  if (!ctx.bitcodeFiles.empty())
-    for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
+  if (!ctx.bitcodeFiles.empty()) {
+    llvm::Triple TT(ctx.bitcodeFiles.front()->obj->getTargetTriple());
+    for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))
       handleLibcall(s);
+  }
 
   // Archive members defining __wrap symbols may be extracted.
   std::vector<WrappedSymbol> wrapped = addWrappedSymbols(args);
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index d099689911fc6..1d545420e182c 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -1319,9 +1319,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   // We only need to add libcall symbols to the link before LTO if the symbol's
   // definition is in bitcode. Any other required libcall symbols will be added
   // to the link after LTO when we add the LTO object file to the link.
-  if (!ctx.bitcodeFiles.empty())
-    for (auto *s : lto::LTO::getRuntimeLibcallSymbols())
+  if (!ctx.bitcodeFiles.empty()) {
+    llvm::Triple TT(ctx.bitcodeFiles.front()->obj->getTargetTriple());
+    for (auto *s : lto::LTO::getRuntimeLibcallSymbols(TT))
       handleLibcall(s);
+  }
   if (errorCount())
     return;
 
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 55b60b01e5827..bda55ab1402be 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -189,6 +189,436 @@ struct MemOp {
   }
 };
 
+struct LibcallsInfo {
+  explicit LibcallsInfo(const Triple &TT) {
+    initLibcalls(TT);
+    initCmpLibcallCCs();
+  }
+
+  /// Rename the default libcall routine name for the specified libcall.
+  void setLibcallName(RTLIB::Libcall Call, const char *Name) {
+    LibcallRoutineNames[Call] = Name;
+  }
+
+  void setLibcallName(ArrayRef<RTLIB::Libcall> Calls, const char *Name) {
+    for (auto Call : Calls)
+      setLibcallName(Call, Name);
+  }
+
+  /// Get the libcall routine name for the specified libcall.
+  const char *getLibcallName(RTLIB::Libcall Call) const {
+    return LibcallRoutineNames[Call];
+  }
+
+  /// Override the default CondCode to be used to test the result of the
+  /// comparison libcall against zero.
+  void setCmpLibcallCC(RTLIB::Libcall Call, ISD::CondCode CC) {
+    CmpLibcallCCs[Call] = CC;
+  }
+
+  /// Get the CondCode that's to be used to test the result of the comparison
+  /// libcall against zero.
+  ISD::CondCode getCmpLibcallCC(RTLIB::Libcall Call) const {
+    return CmpLibcallCCs[Call];
+  }
+
+  /// Set the CallingConv that should be used for the specified libcall.
+  void setLibcallCallingConv(RTLIB::Libcall Call, CallingConv::ID CC) {
+    LibcallCallingConvs[Call] = CC;
+  }
+
+  /// Get the CallingConv that should be used for the specified libcall.
+  CallingConv::ID getLibcallCallingConv(RTLIB::Libcall Call) const {
+    return LibcallCallingConvs[Call];
+  }
+
+  iterator_range<const char **> getLibcallNames() {
+    return llvm::make_range(LibcallRoutineNames,
+                            LibcallRoutineNames + RTLIB::UNKNOWN_LIBCALL);
+  }
+
+private:
+  /// Stores the name each libcall.
+  const char *LibcallRoutineNames[RTLIB::UNKNOWN_LIBCALL + 1];
+
+  /// The ISD::CondCode that should be used to test the result of each of the
+  /// comparison libcall against zero.
+  ISD::CondCode CmpLibcallCCs[RTLIB::UNKNOWN_LIBCALL];
+
+  /// Stores the CallingConv that should be used for each libcall.
+  CallingConv::ID LibcallCallingConvs[RTLIB::UNKNOWN_LIBCALL];
+
+  static bool darwinHasSinCos(const Triple &TT) {
+    assert(TT.isOSDarwin() && "should be called with darwin triple");
+    // Don't bother with 32 bit x86.
+    if (TT.getArch() == Triple::x86)
+      return false;
+    // Macos < 10.9 has no sincos_stret.
+    if (TT.isMacOSX())
+      return !TT.isMacOSXVersionLT(10, 9) && TT.isArch64Bit();
+    // iOS < 7.0 has no sincos_stret.
+    if (TT.isiOS())
+      return !TT.isOSVersionLT(7, 0);
+    // Any other darwin such as WatchOS/TvOS is new enough.
+    return true;
+  }
+
+  /// Sets default libcall calling conventions.
+  void initCmpLibcallCCs() {
+    std::fill(CmpLibcallCCs, CmpLibcallCCs + RTLIB::UNKNOWN_LIBCALL,
+              ISD::SETCC_INVALID);
+    CmpLibcallCCs[RTLIB::OEQ_F32] = ISD::SETEQ;
+    CmpLibcallCCs[RTLIB::OEQ_F64] = ISD::SETEQ;
+    CmpLibcallCCs[RTLIB::OEQ_F128] = ISD::SETEQ;
+    CmpLibcallCCs[RTLIB::OEQ_PPCF128] = ISD::SETEQ;
+    CmpLibcallCCs[RTLIB::UNE_F32] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::UNE_F64] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::UNE_F128] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::UNE_PPCF128] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::OGE_F32] = ISD::SETGE;
+    CmpLibcallCCs[RTLIB::OGE_F64] = ISD::SETGE;
+    CmpLibcallCCs[RTLIB::OGE_F128] = ISD::SETGE;
+    CmpLibcallCCs[RTLIB::OGE_PPCF128] = ISD::SETGE;
+    CmpLibcallCCs[RTLIB::OLT_F32] = ISD::SETLT;
+    CmpLibcallCCs[RTLIB::OLT_F64] = ISD::SETLT;
+    CmpLibcallCCs[RTLIB::OLT_F128] = ISD::SETLT;
+    CmpLibcallCCs[RTLIB::OLT_PPCF128] = ISD::SETLT;
+    CmpLibcallCCs[RTLIB::OLE_F32] = ISD::SETLE;
+    CmpLibcallCCs[RTLIB::OLE_F64] = ISD::SETLE;
+    CmpLibcallCCs[RTLIB::OLE_F128] = ISD::SETLE;
+    CmpLibcallCCs[RTLIB::OLE_PPCF128] = ISD::SETLE;
+    CmpLibcallCCs[RTLIB::OGT_F32] = ISD::SETGT;
+    CmpLibcallCCs[RTLIB::OGT_F64] = ISD::SETGT;
+    CmpLibcallCCs[RTLIB::OGT_F128] = ISD::SETGT;
+    CmpLibcallCCs[RTLIB::OGT_PPCF128] = ISD::SETGT;
+    CmpLibcallCCs[RTLIB::UO_F32] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::UO_F64] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::UO_F128] = ISD::SETNE;
+    CmpLibcallCCs[RTLIB::UO_PPCF128] = ISD::SETNE;
+  }
+
+  /// Set default libcall names.
+  void initLibcalls(const Triple &TT) {
+    std::fill(std::begin(LibcallRoutineNames), std::end(LibcallRoutineNames),
+              nullptr);
+
+#define HANDLE_LIBCALL(code, name) setLibcallName(RTLIB::code, name);
+#include "llvm/IR/RuntimeLibcalls.def"
+#undef HANDLE_LIBCALL
+
+    // Initialize calling conventions to their default.
+    for (int LC = 0; LC < RTLIB::UNKNOWN_LIBCALL; ++LC)
+      setLibcallCallingConv((RTLIB::Libcall)LC, CallingConv::C);
+
+    // Use the f128 variants of math functions on x86_64
+    if (TT.getArch() == Triple::ArchType::x86_64 && TT.isGNUEnvironment()) {
+      setLibcallName(RTLIB::REM_F128, "fmodf128");
+      setLibcallName(RTLIB::FMA_F128, "fmaf128");
+      setLibcallName(RTLIB::SQRT_F128, "sqrtf128");
+      setLibcallName(RTLIB::CBRT_F128, "cbrtf128");
+      setLibcallName(RTLIB::LOG_F128, "logf128");
+      setLibcallName(RTLIB::LOG_FINITE_F128, "__logf128_finite");
+      setLibcallName(RTLIB::LOG2_F128, "log2f128");
+      setLibcallName(RTLIB::LOG2_FINITE_F128, "__log2f128_finite");
+      setLibcallName(RTLIB::LOG10_F128, "log10f128");
+      setLibcallName(RTLIB::LOG10_FINITE_F128, "__log10f128_finite");
+      setLibcallName(RTLIB::EXP_F128, "expf128");
+      setLibcallName(RTLIB::EXP_FINITE_F128, "__expf128_finite");
+      setLibcallName(RTLIB::EXP2_F128, "exp2f128");
+      setLibcallName(RTLIB::EXP2_FINITE_F128, "__exp2f128_finite");
+      setLibcallName(RTLIB::EXP10_F128, "exp10f128");
+      setLibcallName(RTLIB::SIN_F128, "sinf128");
+      setLibcallName(RTLIB::COS_F128, "cosf128");
+      setLibcallName(RTLIB::TAN_F128, "tanf128");
+      setLibcallName(RTLIB::SINCOS_F128, "sincosf128");
+      setLibcallName(RTLIB::POW_F128, "powf128");
+      setLibcallName(RTLIB::POW_FINITE_F128, "__powf128_finite");
+      setLibcallName(RTLIB::CEIL_F128, "ceilf128");
+      setLibcallName(RTLIB::TRUNC_F128, "truncf128");
+      setLibcallName(RTLIB::RINT_F128, "rintf128");
+      setLibcallName(RTLIB::NEARBYINT_F128, "nearbyintf128");
+      setLibcallName(RTLIB::ROUND_F128, "roundf128");
+      setLibcallName(RTLIB::ROUNDEVEN_F128, "roundevenf128");
+      setLibcallName(RTLIB::FLOOR_F128, "floorf128");
+      setLibcallName(RTLIB::COPYSIGN_F128, "copysignf128");
+      setLibcallName(RTLIB::FMIN_F128, "fminf128");
+      setLibcallName(RTLIB::FMAX_F128, "fmaxf128");
+      setLibcallName(RTLIB::LROUND_F128, "lroundf128");
+      setLibcallName(RTLIB::LLROUND_F128, "llroundf128");
+      setLibcallName(RTLIB::LRINT_F128, "lrintf128");
+      setLibcallName(RTLIB::LLRINT_F128, "llrintf128");
+      setLibcallName(RTLIB::LDEXP_F128, "ldexpf128");
+      setLibcallName(RTLIB::FREXP_F128, "frexpf128");
+    }
+
+    // For IEEE quad-precision libcall names, PPC uses "kf" instead of "tf".
+    if (TT.isPPC()) {
+      setLibcallName(RTLIB::ADD_F128, "__addkf3");
+      setLibcallName(RTLIB::SUB_F128, "__subkf3");
+      setLibcallName(RTLIB::MUL_F128, "__mulkf3");
+      setLibcallName(RTLIB::DIV_F128, "__divkf3");
+      setLibcallName(RTLIB::POWI_F128, "__powikf2");
+      setLibcallName(RTLIB::FPEXT_F32_F128, "__extendsfkf2");
+      setLibcallName(RTLIB::FPEXT_F64_F128, "__extenddfkf2");
+      setLibcallName(RTLIB::FPROUND_F128_F32, "__trunckfsf2");
+      setLibcallName(RTLIB::FPROUND_F128_F64, "__trunckfdf2");
+      setLibcallName(RTLIB::FPTOSINT_F128_I32, "__fixkfsi");
+      setLibcallName(RTLIB::FPTOSINT_F128_I64, "__fixkfdi");
+      setLibcallName(RTLIB::FPTOSINT_F128_I128, "__fixkfti");
+      setLibcallName(RTLIB::FPTOUINT_F128_I32, "__fixunskfsi");
+      setLibcallName(RTLIB::FPTOUINT_F128_I64, "__fixunskfdi");
+      setLibcallName(RTLIB::FPTOUINT_F128_I128, "__fixunskfti");
+      setLibcallName(RTLIB::SINTTOFP_I32_F128, "__floatsikf");
+      setLibcallName(RTLIB::SINTTOFP_I64_F128, "__floatdikf");
+      setLibcallName(RTLIB::SINTTOFP_I128_F128, "__floattikf");
+      setLibcallName(RTLIB::UINTTOFP_I32_F128, "__floatunsikf");
+      setLibcallName(RTLIB::UINTTOFP_I64_F128, "__floatundikf");
+      setLibcallName(RTLIB::UINTTOFP_I128_F128, "__floatuntikf");
+      setLibcallName(RTLIB::OEQ_F128, "__eqkf2");
+      setLibcallName(RTLIB::UNE_F128, "__nekf2");
+      setLibcallName(RTLIB::OGE_F128, "__gekf2");
+      setLibcallName(RTLIB::OLT_F128, "__ltkf2");
+      setLibcallName(RTLIB::OLE_F128, "__lekf2");
+      setLibcallName(RTLIB::OGT_F128, "__gtkf2");
+      setLibcallName(RTLIB::UO_F128, "__unordkf2");
+    }
+
+    // A few names are different on particular architectures or environments.
+    if (TT.isOSDarwin()) {
+      // For f16/f32 conversions, Darwin uses the standard naming scheme,
+      // instead of the gnueabi-style __gnu_*_ieee.
+      // FIXME: What about other targets?
+      setLibcallName(RTLIB::FPEXT_F16_F32, "__extendhfsf2");
+      setLibcallName(RTLIB::FPROUND_F32_F16, "__truncsfhf2");
+
+      // Some darwins have an optimized __bzero/bzero function.
+      switch (TT.getArch()) {
+      case Triple::x86:
+      case Triple::x86_64:
+        if (TT.isMacOSX() && !TT.isMacOSXVersionLT(10, 6))
+          setLibcallName(RTLIB::BZERO, "__bzero");
+        break;
+      case Triple::aarch64:
+      case Triple::aarch64_32:
+        setLibcallName(RTLIB::BZERO, "bzero");
+        break;
+      default:
+        break;
+      }
+
+      if (darwinHasSinCos(TT)) {
+        setLibcallName(RTLIB::SINCOS_STRET_F32, "__sincosf_stret");
+        setLibcallName(RTLIB::SINCOS_STRET_F64, "__sincos_stret");
+        if (TT.isWatchABI()) {
+          setLibcallCallingConv(RTLIB::SINCOS_STRET_F32,
+                                CallingConv::ARM_AAPCS_VFP);
+          setLibcallCallingConv(RTLIB::SINCOS_STRET_F64,
+                                CallingConv::ARM_AAPCS_VFP);
+        }
+      }
+
+      switch (TT.getOS()) {
+      case Triple::MacOSX:
+        if (TT.isMacOSXVersionLT(10, 9)) {
+          setLibcallName(RTLIB::EXP10_F32, nullptr);
+          setLibcallName(RTLIB::EXP10_F64, nullptr);
+        } else {
+          setLibcallName(RTLIB::EXP10_F32, "__exp10f");
+          setLibcallName(RTLIB::EXP10_F64, "__exp10");
+        }
+        break;
+      case Triple::IOS:
+      case Triple::TvOS:
+      case Triple::WatchOS:
+      case Triple::XROS:
+        if (!TT.isWatchOS() && (TT.isOSVersionLT(7, 0) ||
+                                (TT.isOSVersionLT(9, 0) && TT.isX86()))) {
+          setLibcallName(RTLIB::EXP10_F32, nullptr);
+          setLibcallName(RTLIB::EXP10_F64, nullptr);
+        } else {
+          setLibcallName(RTLIB::EXP10_F32, "__exp10f");
+          setLibcallName(RTLIB::EXP10_F64, "__exp10");
+        }
+
+        break;
+      default:
+        break;
+      }
+    } else {
+      setLibcallName(RTLIB::FPEXT_F16_F32, "__gnu_h2f_ieee");
+      setLibcallName(RTLIB::FPROUND_F32_F16, "__gnu_f2h_ieee");
+    }
+
+    if (TT.isGNUEnvironment() || TT.isOSFuchsia() ||
+        (TT.isAndroid() && !TT.isAndroidVersionLT(9))) {
+      setLibcallName(RTLIB::SINCOS_F32, "sincosf");
+      setLibcallName(RTLIB::SINCOS_F64, "sincos");
+      setLibcallName(RTLIB::SINCOS_F80, "sincosl");
+      setLibcallName(RTLIB::SINCOS_F128, "sincosl");
+      setLibcallName(RTLIB::SINCOS_PPCF128, "sincosl");
+    }
+
+    if (TT.isPS()) {
+      setLibcallName(RTLIB::SINCOS_F32, "sincosf");
+      setLibcallName(RTLIB::SINCOS_F64, "sincos");
+    }
+
+    if (TT.isOSOpenBSD()) {
+      setLibcallName(RTLIB::STACKPROTECTOR_CHECK_FAIL, nullptr);
+    }
+
+    if (TT.isOSWindows() && !TT.isOSCygMing()) {
+      setLibcallName(RTLIB::LDEXP_F32, nullptr);
+      setLibcallName(RTLIB::LDEXP_F80, nullptr);
+      setLibcallName(RTLIB::LDEXP_F128, nullptr);
+      setLibcallName(RTLIB::LDEXP_PPCF128, nullptr);
+
+      setLibcallName(RTLIB::FREXP_F32, nullptr);
+      setLibcallName(RTLIB::FREXP_F80, nullptr);
+      setLibcallName(RTLIB::FREXP_F128, nullptr);
+      setLibcallName(RTLIB::FREXP_PPCF128, nullptr);
+    }
+
+    if (TT.isAArch64()) {
+      if (TT.isOSMSVCRT()) {
+        // MSVCRT doesn't have powi; fall back to pow
+        setLibcallName(RTLIB::POWI_F32, nullptr);
+        setLibcallName(RTLIB::POWI_F64, nullptr);
+      }
+    }
+
+    // Disable most libcalls on AMDGPU.
+    if (TT.isAMDGPU()) {
+      for (int I = 0; I < RTLIB::UNKNOWN_LIBCALL; ++I) {
+        if (I < RTLIB::ATOMIC_LOAD || I > RTLIB::ATOMIC_FETCH_NAND_16)
+          setLibcallName(static_cast<RTLIB::Libcall>(I), nullptr);
+      }
+    }
+
+    if (TT.isARM() || TT.isThumb()) {
+      // These libcalls are not available in 32-bit.
+      setLibcallName(RTLIB::SHL_I128, nullptr);
+      setLibcallName(RTLIB::SRL_I128, nullptr);
+      setLibcallName(RTLIB::SRA_I128, nullptr);
+      setLibcallName(RTLIB::MUL_I128, nullptr);
+      setLibcallName(RTLIB::MULO_I64, nullptr);
+      setLibcallName(RTLIB::MULO_I128, nullptr);
+
+      if (TT.isOSMSVCRT()) {
+        // MSVCRT doesn't have powi; fall back to pow
+        setLibcallName(RTLIB::POWI_F32, nullptr);
+        setLibcallName(RTLIB::POWI_F64, nullptr);
+      }
+    }
+
+    if (TT.getArch() == Triple::ArchType::avr) {
+      // Division rtlib functions (not supported), use divmod functions instead
+      setLibcallName(RTLIB::SDIV_I8, nullptr);
+      setLibcallName(RTLIB::SDIV_I16, nullptr);
+      setLibcallName(RTLIB::SDIV_I32, nullptr);
+      setLibcallName(RTLIB::UDIV_I8, nullptr);
+      setLibcallName(RTLIB::UDIV_I16, nullptr);
+      setLibcallName(RTLIB::UDIV_I32, nullptr);
+
+      // Modulus rtlib functions (not supported), use divmod functions instead
+      setLibcallName(RTLIB::SREM_I8, nullptr);
+      setLibcallName(RTLIB::SREM_I16, nullptr);
+      setLibcallName(RTLIB::SREM_I32, nullptr);
+      setLibcallName(RTLIB::UREM_I8, nullptr);
+      setLibcallName(RTLIB::UREM_I16, nullptr);
+      setLibcallName(RTLIB::UREM_I32, nullptr);
+    }
+
+    if (TT.getArch() == Triple::ArchType::hexagon) {
+      // These cause problems when the shift amount is non-constant.
+      setLibcallName(RTLIB::SHL_I128, nullptr);
+      setLibcallName(RTLIB::SRL_I128, nullptr);
+      setLibcallName(RTLIB::SRA_I128, nullptr);
+    }
+
+    if (TT.isLoongArch()) {
+      if (!TT.isLoongArch64()) {
+        // Set libcalls.
+        setLibcallName(RTLIB::MUL_I128, nullptr);
+        // The MULO libcall is not part of libgcc, only compiler-rt.
+        setLibcallName(RTLIB::MULO_I64, nullptr);
+      }
+      // The MULO libcall is not part of libgcc, only compiler-rt.
+      setLibcallName(RTLIB::MULO_I128, nullptr);
+    }
+
+    if (TT.isMIPS32()) {
+      // These libcalls are not available in 32-bit.
+      setLibcallName(RTLIB::SHL_I128, nullptr);
+      setLibcallName(RTLIB::SRL_I128, nullptr);
+      setLibcallName(RTLIB::SRA_I128, nullptr);
+      setLibcallName(RTLIB::MUL_I128, nullptr);
+      setLibcallName(RTLIB::MULO_I64, nullptr);
+      setLibcallName(RTLIB::MULO_I128, nullptr);
+    }
+
+    if (TT.isPPC()) {
+      if (!TT.isPPC64()) {
+        // These libcalls are not available in 32-bit.
+        setLibcallName(RTLIB::SHL_I128, nullptr);
+        setLibcallName(RTLIB::SRL_I128, nullptr);
+        setLibcallName(RTLIB::SRA_I128, nullptr);
+        setLibcallName(RTLIB::MUL_I128, nullptr);
+        setLibcallName(RTLIB::MULO_I64, nullptr);
+      }
+      setLibcallName(RTLIB::MULO_I128, nullptr);
+    }
+
+    if (TT.isRISCV32()) {
+      // These libcalls are not available in 32-bit.
+      setLibcallName(RTLIB::SHL_I128, nullptr);
+      setLibcallName(RTLIB::SRL_I128, nullptr);
+      setLibcallName(RTLIB::SRA_I128, nullptr);
+      setLibcallName(RTLIB::MUL_I128, nullptr);
+      setLibcallName(RTLIB::MULO_I64, nullptr);
+    }
+
+    if (TT.isSPARC()) {
+      if (!TT.isSPARC64()) {
+        // These libcalls are not available in 32-bit.
+        setLibcallName(RTLIB::MULO_I64, nullptr);
+        setLibcallName(RTLIB::MUL_I128, nullptr);
+        setLibcallName(RTLIB::SHL_I128, nullptr);
+        setLibcallName(RTLIB::SRL_I128, nullptr);
+        setLibcallName(RTLIB::SRA_I128, nullptr);
+      }
+      setLibcallName(RTLIB::MULO_I128, nullptr);
+    }
+
+    if (TT.isSystemZ()) {
+      setLibcallName(RTLIB::SRL_I128, nullptr);
+      setLibcallName(RTLIB::SHL_I128, nullptr);
+      setLibcallName(RTLIB::SRA_I128, nullptr);
+    }
+
+    if (TT.isX86()) {
+      if (TT.getArch() == Triple::ArchType::x86) {
+        // These libcalls are not available in 32-bit.
+        setLibcallName(RTLIB::SHL_I128, nullptr);
+        setLibcallName(RTLIB::SRL_I128, nullptr);
+        setLibcallName(RTLIB::SRA_I128, nullptr);
+        setLibcallName(RTLIB::MUL_I128, nullptr);
+        // The MULO libcall is not part of libgcc, only compiler-rt.
+        setLibcallName(RTLIB::MULO_I64, nullptr);
+      }
+
+      // The MULO libcall is not part of libgcc, only compiler-rt.
+      setLibcallName(RTLIB::MULO_I128, nullptr);
+
+      if (TT.isOSMSVCRT()) {
+        // MSVCRT doesn't have powi; fall back to pow
+        setLibcallName(RTLIB::POWI_F32, nullptr);
+        setLibcallName(RTLIB::POWI_F64, nullptr);
+      }
+    }
+  }
+};
+
 /// This base class for TargetLowering contains the SelectionDAG-independent
 /// parts that can be used from the rest of CodeGen.
 class TargetLoweringBase {
@@ -3410,44 +3840,40 @@ class TargetLoweringBase {
     return nullptr;
   }
 
-  //===--...
[truncated]

``````````

</details>


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


More information about the llvm-commits mailing list