//===- 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/ADT/StringTable.h" #include "llvm/Support/Debug.h" #include "llvm/TargetParser/ARMTargetParser.h" #define DEBUG_TYPE "runtime-libcalls-info" using namespace llvm; using namespace RTLIB; #define GET_INIT_RUNTIME_LIBCALL_NAMES #define GET_SET_TARGET_RUNTIME_LIBCALL_SETS #include "llvm/IR/RuntimeLibcalls.inc" #undef GET_INIT_RUNTIME_LIBCALL_NAMES #undef GET_SET_TARGET_RUNTIME_LIBCALL_SETS /// 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, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion, StringRef ABIName) { setTargetRuntimeLibcallSets(TT, FloatABI, EABIVersion, ABIName); if (ExceptionModel == ExceptionHandling::SjLj) setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume); if (TT.isARM() || TT.isThumb()) { // The half <-> float conversion functions are always soft-float on // non-watchos platforms, but are needed for some targets which use a // hard-float calling convention by default. if (!TT.isWatchABI()) { if (isAAPCS_ABI(TT, ABIName)) { setLibcallImplCallingConv(RTLIB::__truncsfhf2, CallingConv::ARM_AAPCS); setLibcallImplCallingConv(RTLIB::__truncdfhf2, CallingConv::ARM_AAPCS); setLibcallImplCallingConv(RTLIB::__extendhfsf2, CallingConv::ARM_AAPCS); } else { setLibcallImplCallingConv(RTLIB::__truncsfhf2, CallingConv::ARM_APCS); setLibcallImplCallingConv(RTLIB::__truncdfhf2, CallingConv::ARM_APCS); setLibcallImplCallingConv(RTLIB::__extendhfsf2, CallingConv::ARM_APCS); } } return; } if (TT.getArch() == Triple::ArchType::msp430) { setLibcallImplCallingConv(RTLIB::__mspabi_mpyll, CallingConv::MSP430_BUILTIN); } } RTLIB::LibcallImpl RuntimeLibcallsInfo::getSupportedLibcallImpl(StringRef FuncName) const { const ArrayRef RuntimeLibcallNameOffsets( RuntimeLibcallNameOffsetTable); iterator_range::const_iterator> Range = getRecognizedLibcallImpls(FuncName); for (auto I = Range.begin(); I != Range.end(); ++I) { RTLIB::LibcallImpl Impl = static_cast(I - RuntimeLibcallNameOffsets.begin()); // FIXME: This should not depend on looking up ImplToLibcall, only the list // of libcalls for the module. RTLIB::LibcallImpl Recognized = LibcallImpls[ImplToLibcall[Impl]]; if (Recognized != RTLIB::Unsupported) return Recognized; } return RTLIB::Unsupported; } iterator_range::const_iterator> RuntimeLibcallsInfo::getRecognizedLibcallImpls(StringRef FuncName) { StringTable::Iterator It = lower_bound(RuntimeLibcallImplNameTable, FuncName); if (It == RuntimeLibcallImplNameTable.end() || *It != FuncName) return iterator_range(ArrayRef()); uint16_t IndexVal = It.offset().value(); const ArrayRef TableRef(RuntimeLibcallNameOffsetTable); ArrayRef::const_iterator E = TableRef.end(); ArrayRef::const_iterator EntriesBegin = std::lower_bound(TableRef.begin(), E, IndexVal); ArrayRef::const_iterator EntriesEnd = EntriesBegin; while (EntriesEnd != E && *EntriesEnd == IndexVal) ++EntriesEnd; assert(EntriesBegin != E && "libcall found in name table but not offset table"); return make_range(EntriesBegin, EntriesEnd); } bool RuntimeLibcallsInfo::isAAPCS_ABI(const Triple &TT, StringRef ABIName) { const ARM::ARMABI TargetABI = ARM::computeTargetABI(TT, ABIName); return TargetABI == ARM::ARM_ABI_AAPCS || TargetABI == ARM::ARM_ABI_AAPCS16; } bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) { switch (TT.getOS()) { case Triple::MacOSX: return !TT.isMacOSXVersionLT(10, 9); case Triple::IOS: return !TT.isOSVersionLT(7, 0); case Triple::DriverKit: case Triple::TvOS: case Triple::WatchOS: case Triple::XROS: case Triple::BridgeOS: return true; default: return false; } }