//===- RuntimeLibcalls.cpp - Interface for runtime libcalls -----*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #include "llvm/IR/RuntimeLibcalls.h" #include "llvm/Support/CommandLine.h" using namespace llvm; using namespace RTLIB; static cl::opt HexagonEnableFastMathRuntimeCalls("hexagon-fast-math", cl::Hidden, cl::desc("Enable Fast Math processing")); static void setAArch64LibcallNames(RuntimeLibcallsInfo &Info, const Triple &TT) { if (TT.isWindowsArm64EC()) { // FIXME: are there calls we need to exclude from this? #define HANDLE_LIBCALL(code, name) \ { \ const char *libcallName = Info.getLibcallName(RTLIB::code); \ if (libcallName && libcallName[0] != '#') \ Info.setLibcallName(RTLIB::code, "#" #name); \ } #include "llvm/IR/RuntimeLibcalls.def" #undef HANDLE_LIBCALL } } /// Set default libcall names. If a target wants to opt-out of a libcall it /// should be placed here. void RuntimeLibcallsInfo::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 if (TT.isX86() && 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::ASIN_F128, "asinf128"); setLibcallName(RTLIB::ACOS_F128, "acosf128"); setLibcallName(RTLIB::ATAN_F128, "atanf128"); setLibcallName(RTLIB::ATAN2_F128, "atan2f128"); setLibcallName(RTLIB::SINH_F128, "sinhf128"); setLibcallName(RTLIB::COSH_F128, "coshf128"); setLibcallName(RTLIB::TANH_F128, "tanhf128"); 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::FMINIMUM_F128, "fminimumf128"); setLibcallName(RTLIB::FMAXIMUM_F128, "fmaximumf128"); setLibcallName(RTLIB::FMINIMUM_NUM_F128, "fminimum_numf128"); setLibcallName(RTLIB::FMAXIMUM_NUM_F128, "fmaximum_numf128"); 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"); setLibcallName(RTLIB::MODF_F128, "modff128"); } // 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_F16, "__trunckfhf2"); 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: if (TT.isOSVersionLT(7, 0)) { setLibcallName(RTLIB::EXP10_F32, nullptr); setLibcallName(RTLIB::EXP10_F64, nullptr); break; } [[fallthrough]]; case Triple::DriverKit: case Triple::TvOS: case Triple::WatchOS: case Triple::XROS: setLibcallName(RTLIB::EXP10_F32, "__exp10f"); setLibcallName(RTLIB::EXP10_F64, "__exp10"); break; default: break; } } else if (TT.getOS() == Triple::BridgeOS) { // TODO: BridgeOS should be included in isOSDarwin. setLibcallName(RTLIB::EXP10_F32, "__exp10f"); setLibcallName(RTLIB::EXP10_F64, "__exp10"); } 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); } // Disable most libcalls on AMDGPU and NVPTX. if (TT.isAMDGPU() || TT.isNVPTX()) { for (RTLIB::Libcall LC : RTLIB::libcalls()) { if (LC < RTLIB::ATOMIC_LOAD || LC > RTLIB::ATOMIC_FETCH_NAND_16) setLibcallName(LC, nullptr); } } if (TT.isOSMSVCRT()) { // MSVCRT doesn't have powi; fall back to pow setLibcallName(RTLIB::POWI_F32, nullptr); setLibcallName(RTLIB::POWI_F64, nullptr); } // Setup Windows compiler runtime calls. if (TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment()) { static const struct { const RTLIB::Libcall Op; const char *const Name; const CallingConv::ID CC; } LibraryCalls[] = { {RTLIB::SDIV_I64, "_alldiv", CallingConv::X86_StdCall}, {RTLIB::UDIV_I64, "_aulldiv", CallingConv::X86_StdCall}, {RTLIB::SREM_I64, "_allrem", CallingConv::X86_StdCall}, {RTLIB::UREM_I64, "_aullrem", CallingConv::X86_StdCall}, {RTLIB::MUL_I64, "_allmul", CallingConv::X86_StdCall}, }; for (const auto &LC : LibraryCalls) { setLibcallName(LC.Op, LC.Name); setLibcallCallingConv(LC.Op, LC.CC); } } if (TT.getArch() == Triple::ArchType::aarch64) setAArch64LibcallNames(*this, TT); 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); // Division and modulus rtlib functions setLibcallName(RTLIB::SDIVREM_I8, "__divmodqi4"); setLibcallName(RTLIB::SDIVREM_I16, "__divmodhi4"); setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4"); setLibcallName(RTLIB::UDIVREM_I8, "__udivmodqi4"); setLibcallName(RTLIB::UDIVREM_I16, "__udivmodhi4"); setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4"); // 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 setLibcallName(RTLIB::SIN_F32, "sin"); setLibcallName(RTLIB::COS_F32, "cos"); } if (!TT.isWasm()) { // These libcalls are only available in compiler-rt, not libgcc. if (TT.isArch32Bit()) { 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.isSystemZ() && TT.isOSzOS()) { struct RTLibCallMapping { RTLIB::Libcall Code; const char *Name; }; static RTLibCallMapping RTLibCallCommon[] = { #define HANDLE_LIBCALL(code, name) {RTLIB::code, name}, #include "ZOSLibcallNames.def" }; for (auto &E : RTLibCallCommon) setLibcallName(E.Code, E.Name); } if (TT.getArch() == Triple::ArchType::hexagon) { setLibcallName(RTLIB::SDIV_I32, "__hexagon_divsi3"); setLibcallName(RTLIB::SDIV_I64, "__hexagon_divdi3"); setLibcallName(RTLIB::UDIV_I32, "__hexagon_udivsi3"); setLibcallName(RTLIB::UDIV_I64, "__hexagon_udivdi3"); setLibcallName(RTLIB::SREM_I32, "__hexagon_modsi3"); setLibcallName(RTLIB::SREM_I64, "__hexagon_moddi3"); setLibcallName(RTLIB::UREM_I32, "__hexagon_umodsi3"); setLibcallName(RTLIB::UREM_I64, "__hexagon_umoddi3"); const bool FastMath = HexagonEnableFastMathRuntimeCalls; // This is the only fast library function for sqrtd. if (FastMath) setLibcallName(RTLIB::SQRT_F64, "__hexagon_fast2_sqrtdf2"); // Prefix is: nothing for "slow-math", // "fast2_" for V5+ fast-math double-precision // (actually, keep fast-math and fast-math2 separate for now) if (FastMath) { setLibcallName(RTLIB::ADD_F64, "__hexagon_fast_adddf3"); setLibcallName(RTLIB::SUB_F64, "__hexagon_fast_subdf3"); setLibcallName(RTLIB::MUL_F64, "__hexagon_fast_muldf3"); setLibcallName(RTLIB::DIV_F64, "__hexagon_fast_divdf3"); setLibcallName(RTLIB::DIV_F32, "__hexagon_fast_divsf3"); } else { setLibcallName(RTLIB::ADD_F64, "__hexagon_adddf3"); setLibcallName(RTLIB::SUB_F64, "__hexagon_subdf3"); setLibcallName(RTLIB::MUL_F64, "__hexagon_muldf3"); setLibcallName(RTLIB::DIV_F64, "__hexagon_divdf3"); setLibcallName(RTLIB::DIV_F32, "__hexagon_divsf3"); } if (FastMath) setLibcallName(RTLIB::SQRT_F32, "__hexagon_fast2_sqrtf"); else setLibcallName(RTLIB::SQRT_F32, "__hexagon_sqrtf"); } }