| //===- 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/FloatingPointMode.h" |
| #include "llvm/ADT/StringTable.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/SystemLibraries.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/xxhash.h" |
| #include "llvm/TargetParser/ARMTargetParser.h" |
| |
| #define DEBUG_TYPE "runtime-libcalls-info" |
| |
| using namespace llvm; |
| using namespace RTLIB; |
| |
| #define GET_RUNTIME_LIBCALLS_INFO |
| #define GET_INIT_RUNTIME_LIBCALL_NAMES |
| #define GET_SET_TARGET_RUNTIME_LIBCALL_SETS |
| #define DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME |
| #include "llvm/IR/RuntimeLibcalls.inc" |
| |
| RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Triple &TT, |
| ExceptionHandling ExceptionModel, |
| FloatABI::ABIType FloatABI, |
| EABI EABIVersion, StringRef ABIName, |
| VectorLibrary VecLib) { |
| // FIXME: The ExceptionModel parameter is to handle the field in |
| // TargetOptions. This interface fails to distinguish the forced disable |
| // case for targets which support exceptions by default. This should |
| // probably be a module flag and removed from TargetOptions. |
| if (ExceptionModel == ExceptionHandling::None) |
| ExceptionModel = TT.getDefaultExceptionHandling(); |
| |
| initLibcalls(TT, ExceptionModel, FloatABI, EABIVersion, ABIName); |
| |
| // TODO: Tablegen should generate these sets |
| switch (VecLib) { |
| case VectorLibrary::SLEEFGNUABI: |
| for (RTLIB::LibcallImpl Impl : |
| {RTLIB::impl__ZGVnN2vv_fmod, RTLIB::impl__ZGVnN4vv_fmodf, |
| RTLIB::impl__ZGVsMxvv_fmod, RTLIB::impl__ZGVsMxvv_fmodf, |
| RTLIB::impl__ZGVnN2vl8_modf, RTLIB::impl__ZGVnN4vl4_modff, |
| RTLIB::impl__ZGVsNxvl8_modf, RTLIB::impl__ZGVsNxvl4_modff, |
| RTLIB::impl__ZGVnN2vl8l8_sincos, RTLIB::impl__ZGVnN4vl4l4_sincosf, |
| RTLIB::impl__ZGVsNxvl8l8_sincos, RTLIB::impl__ZGVsNxvl4l4_sincosf, |
| RTLIB::impl__ZGVnN4vl4l4_sincospif, RTLIB::impl__ZGVnN2vl8l8_sincospi, |
| RTLIB::impl__ZGVsNxvl4l4_sincospif, |
| RTLIB::impl__ZGVsNxvl8l8_sincospi}) |
| setAvailable(Impl); |
| break; |
| case VectorLibrary::ArmPL: |
| for (RTLIB::LibcallImpl Impl : |
| {RTLIB::impl_armpl_svfmod_f32_x, RTLIB::impl_armpl_svfmod_f64_x, |
| RTLIB::impl_armpl_vfmodq_f32, RTLIB::impl_armpl_vfmodq_f64, |
| RTLIB::impl_armpl_vmodfq_f64, RTLIB::impl_armpl_vmodfq_f32, |
| RTLIB::impl_armpl_svmodf_f64_x, RTLIB::impl_armpl_svmodf_f32_x, |
| RTLIB::impl_armpl_vsincosq_f64, RTLIB::impl_armpl_vsincosq_f32, |
| RTLIB::impl_armpl_svsincos_f64_x, RTLIB::impl_armpl_svsincos_f32_x, |
| RTLIB::impl_armpl_vsincospiq_f32, RTLIB::impl_armpl_vsincospiq_f64, |
| RTLIB::impl_armpl_svsincospi_f32_x, |
| RTLIB::impl_armpl_svsincospi_f64_x}) |
| setAvailable(Impl); |
| |
| for (RTLIB::LibcallImpl Impl : |
| {RTLIB::impl_armpl_vfmodq_f32, RTLIB::impl_armpl_vfmodq_f64, |
| RTLIB::impl_armpl_vsincosq_f64, RTLIB::impl_armpl_vsincosq_f32}) |
| setLibcallImplCallingConv(Impl, CallingConv::AArch64_VectorCall); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Module &M) |
| : RuntimeLibcallsInfo(M.getTargetTriple()) { |
| // TODO: Consider module flags |
| } |
| |
| /// 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, ExceptionModel, FloatABI, EABIVersion, |
| ABIName); |
| } |
| |
| LLVM_ATTRIBUTE_ALWAYS_INLINE |
| iota_range<RTLIB::LibcallImpl> |
| RuntimeLibcallsInfo::libcallImplNameHit(uint16_t NameOffsetEntry, |
| uint16_t StrOffset) { |
| int NumAliases = 1; |
| for (uint16_t Entry : ArrayRef(RuntimeLibcallNameOffsetTable) |
| .drop_front(NameOffsetEntry + 1)) { |
| if (Entry != StrOffset) |
| break; |
| ++NumAliases; |
| } |
| |
| RTLIB::LibcallImpl ImplStart = static_cast<RTLIB::LibcallImpl>( |
| &RuntimeLibcallNameOffsetTable[NameOffsetEntry] - |
| &RuntimeLibcallNameOffsetTable[0]); |
| return enum_seq(ImplStart, |
| static_cast<RTLIB::LibcallImpl>(ImplStart + NumAliases)); |
| } |
| |
| 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; |
| } |
| } |
| |
| /// TODO: There is really no guarantee that sizeof(size_t) is equal to the index |
| /// size of the default address space. This matches TargetLibraryInfo and should |
| /// be kept in sync. |
| static IntegerType *getSizeTType(LLVMContext &Ctx, const DataLayout &DL) { |
| return DL.getIndexType(Ctx, /*AddressSpace=*/0); |
| } |
| |
| std::pair<FunctionType *, AttributeList> |
| RuntimeLibcallsInfo::getFunctionTy(LLVMContext &Ctx, const Triple &TT, |
| const DataLayout &DL, |
| RTLIB::LibcallImpl LibcallImpl) const { |
| // TODO: NoCallback probably unsafe in general |
| static constexpr Attribute::AttrKind CommonFnAttrs[] = { |
| Attribute::MustProgress, Attribute::NoCallback, Attribute::NoFree, |
| Attribute::NoSync, Attribute::NoUnwind, Attribute::WillReturn}; |
| static constexpr Attribute::AttrKind MemoryFnAttrs[] = { |
| Attribute::MustProgress, Attribute::NoUnwind, Attribute::WillReturn}; |
| static constexpr Attribute::AttrKind CommonPtrArgAttrs[] = { |
| Attribute::NoAlias, Attribute::WriteOnly, Attribute::NonNull}; |
| |
| switch (LibcallImpl) { |
| case RTLIB::impl___sincos_stret: |
| case RTLIB::impl___sincosf_stret: { |
| if (!darwinHasSinCosStret(TT)) // Non-darwin currently unexpected |
| return {}; |
| |
| Type *ScalarTy = LibcallImpl == RTLIB::impl___sincosf_stret |
| ? Type::getFloatTy(Ctx) |
| : Type::getDoubleTy(Ctx); |
| |
| AttrBuilder FuncAttrBuilder(Ctx); |
| for (Attribute::AttrKind Attr : CommonFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| |
| const bool UseSret = |
| TT.isX86_32() || ((TT.isARM() || TT.isThumb()) && |
| ARM::computeTargetABI(TT) == ARM::ARM_ABI_APCS); |
| |
| FuncAttrBuilder.addMemoryAttr(MemoryEffects::argumentOrErrnoMemOnly( |
| UseSret ? ModRefInfo::Mod : ModRefInfo::NoModRef, ModRefInfo::Mod)); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| if (UseSret) { |
| AttrBuilder AttrBuilder(Ctx); |
| StructType *StructTy = StructType::get(ScalarTy, ScalarTy); |
| AttrBuilder.addStructRetAttr(StructTy); |
| AttrBuilder.addAlignmentAttr(DL.getABITypeAlign(StructTy)); |
| FunctionType *FuncTy = FunctionType::get( |
| Type::getVoidTy(Ctx), {DL.getAllocaPtrType(Ctx), ScalarTy}, false); |
| |
| return {FuncTy, Attrs.addParamAttributes(Ctx, 0, AttrBuilder)}; |
| } |
| |
| Type *RetTy = |
| LibcallImpl == RTLIB::impl___sincosf_stret && TT.isX86_64() |
| ? static_cast<Type *>(FixedVectorType::get(ScalarTy, 2)) |
| : static_cast<Type *>(StructType::get(ScalarTy, ScalarTy)); |
| |
| return {FunctionType::get(RetTy, {ScalarTy}, false), Attrs}; |
| } |
| case RTLIB::impl_malloc: |
| case RTLIB::impl_calloc: { |
| AttrBuilder FuncAttrBuilder(Ctx); |
| for (Attribute::AttrKind Attr : MemoryFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| FuncAttrBuilder.addAttribute(Attribute::NoFree); |
| |
| AllocFnKind AllocKind = AllocFnKind::Alloc; |
| if (LibcallImpl == RTLIB::impl_malloc) |
| AllocKind |= AllocFnKind::Uninitialized; |
| |
| // TODO: Set memory attribute |
| FuncAttrBuilder.addAllocKindAttr(AllocKind); |
| FuncAttrBuilder.addAttribute("alloc-family", "malloc"); |
| FuncAttrBuilder.addAllocSizeAttr(0, LibcallImpl == RTLIB::impl_malloc |
| ? std::nullopt |
| : std::make_optional(1)); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| { |
| AttrBuilder ArgAttrBuilder(Ctx); |
| for (Attribute::AttrKind AK : CommonPtrArgAttrs) |
| ArgAttrBuilder.addAttribute(AK); |
| |
| Attrs = Attrs.addRetAttribute(Ctx, Attribute::NoUndef); |
| Attrs = Attrs.addRetAttribute(Ctx, Attribute::NoAlias); |
| Attrs = Attrs.addParamAttribute(Ctx, 0, Attribute::NoUndef); |
| if (LibcallImpl == RTLIB::impl_calloc) |
| Attrs = Attrs.addParamAttribute(Ctx, 1, Attribute::NoUndef); |
| } |
| |
| IntegerType *SizeT = getSizeTType(Ctx, DL); |
| PointerType *PtrTy = PointerType::get(Ctx, 0); |
| SmallVector<Type *, 2> ArgTys = {SizeT}; |
| if (LibcallImpl == RTLIB::impl_calloc) |
| ArgTys.push_back(SizeT); |
| |
| return {FunctionType::get(PtrTy, ArgTys, false), Attrs}; |
| } |
| case RTLIB::impl_free: { |
| // TODO: Set memory attribute |
| AttrBuilder FuncAttrBuilder(Ctx); |
| for (Attribute::AttrKind Attr : MemoryFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| |
| FuncAttrBuilder.addAllocKindAttr(AllocFnKind::Free); |
| FuncAttrBuilder.addAttribute("alloc-family", "malloc"); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| { |
| AttrBuilder ArgAttrBuilder(Ctx); |
| ArgAttrBuilder.addAttribute(Attribute::NoUndef); |
| ArgAttrBuilder.addAttribute(Attribute::AllocatedPointer); |
| ArgAttrBuilder.addCapturesAttr(CaptureInfo::none()); |
| Attrs = Attrs.addParamAttributes(Ctx, 0, ArgAttrBuilder); |
| } |
| |
| return {FunctionType::get(Type::getVoidTy(Ctx), {PointerType::get(Ctx, 0)}, |
| false), |
| Attrs}; |
| } |
| case RTLIB::impl_sqrtf: |
| case RTLIB::impl_sqrt: { |
| AttrBuilder FuncAttrBuilder(Ctx); |
| |
| for (Attribute::AttrKind Attr : CommonFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| FuncAttrBuilder.addMemoryAttr(MemoryEffects::errnoMemOnly(ModRefInfo::Mod)); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| Type *ScalarTy = LibcallImpl == RTLIB::impl_sqrtf ? Type::getFloatTy(Ctx) |
| : Type::getDoubleTy(Ctx); |
| FunctionType *FuncTy = FunctionType::get(ScalarTy, {ScalarTy}, false); |
| |
| Attrs = Attrs.addRetAttribute( |
| Ctx, Attribute::getWithNoFPClass(Ctx, fcNegInf | fcNegSubnormal | |
| fcNegNormal)); |
| return {FuncTy, Attrs}; |
| } |
| case RTLIB::impl__ZGVnN2vv_fmod: |
| case RTLIB::impl__ZGVnN4vv_fmodf: |
| case RTLIB::impl__ZGVsMxvv_fmod: |
| case RTLIB::impl__ZGVsMxvv_fmodf: |
| case RTLIB::impl_armpl_vfmodq_f32: |
| case RTLIB::impl_armpl_vfmodq_f64: |
| case RTLIB::impl_armpl_svfmod_f32_x: |
| case RTLIB::impl_armpl_svfmod_f64_x: { |
| bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vv_fmodf || |
| LibcallImpl == RTLIB::impl__ZGVsMxvv_fmodf || |
| LibcallImpl == RTLIB::impl_armpl_svfmod_f32_x || |
| LibcallImpl == RTLIB::impl_armpl_vfmodq_f32; |
| |
| bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsMxvv_fmod || |
| LibcallImpl == RTLIB::impl__ZGVsMxvv_fmodf || |
| LibcallImpl == RTLIB::impl_armpl_svfmod_f32_x || |
| LibcallImpl == RTLIB::impl_armpl_svfmod_f64_x; |
| |
| AttrBuilder FuncAttrBuilder(Ctx); |
| |
| for (Attribute::AttrKind Attr : CommonFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| Type *ScalarTy = IsF32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx); |
| unsigned EC = IsF32 ? 4 : 2; |
| VectorType *VecTy = VectorType::get(ScalarTy, EC, IsScalable); |
| |
| SmallVector<Type *, 3> ArgTys = {VecTy, VecTy}; |
| if (hasVectorMaskArgument(LibcallImpl)) |
| ArgTys.push_back(VectorType::get(Type::getInt1Ty(Ctx), EC, IsScalable)); |
| |
| FunctionType *FuncTy = FunctionType::get(VecTy, ArgTys, false); |
| return {FuncTy, Attrs}; |
| } |
| case RTLIB::impl__ZGVnN2vl8_modf: |
| case RTLIB::impl__ZGVnN4vl4_modff: |
| case RTLIB::impl__ZGVsNxvl8_modf: |
| case RTLIB::impl__ZGVsNxvl4_modff: |
| case RTLIB::impl_armpl_vmodfq_f64: |
| case RTLIB::impl_armpl_vmodfq_f32: |
| case RTLIB::impl_armpl_svmodf_f64_x: |
| case RTLIB::impl_armpl_svmodf_f32_x: { |
| AttrBuilder FuncAttrBuilder(Ctx); |
| |
| bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vl4_modff || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl4_modff || |
| LibcallImpl == RTLIB::impl_armpl_vmodfq_f32 || |
| LibcallImpl == RTLIB::impl_armpl_svmodf_f32_x; |
| |
| bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsNxvl8_modf || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl4_modff || |
| LibcallImpl == RTLIB::impl_armpl_svmodf_f64_x || |
| LibcallImpl == RTLIB::impl_armpl_svmodf_f32_x; |
| |
| Type *ScalarTy = IsF32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx); |
| unsigned EC = IsF32 ? 4 : 2; |
| VectorType *VecTy = VectorType::get(ScalarTy, EC, IsScalable); |
| |
| for (Attribute::AttrKind Attr : CommonFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| FuncAttrBuilder.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Mod)); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| { |
| AttrBuilder ArgAttrBuilder(Ctx); |
| for (Attribute::AttrKind AK : CommonPtrArgAttrs) |
| ArgAttrBuilder.addAttribute(AK); |
| ArgAttrBuilder.addAlignmentAttr(DL.getABITypeAlign(VecTy)); |
| Attrs = Attrs.addParamAttributes(Ctx, 1, ArgAttrBuilder); |
| } |
| |
| PointerType *PtrTy = PointerType::get(Ctx, 0); |
| SmallVector<Type *, 4> ArgTys = {VecTy, PtrTy}; |
| if (hasVectorMaskArgument(LibcallImpl)) |
| ArgTys.push_back(VectorType::get(Type::getInt1Ty(Ctx), EC, IsScalable)); |
| |
| return {FunctionType::get(VecTy, ArgTys, false), Attrs}; |
| } |
| case RTLIB::impl__ZGVnN2vl8l8_sincos: |
| case RTLIB::impl__ZGVnN4vl4l4_sincosf: |
| case RTLIB::impl__ZGVsNxvl8l8_sincos: |
| case RTLIB::impl__ZGVsNxvl4l4_sincosf: |
| case RTLIB::impl_armpl_vsincosq_f64: |
| case RTLIB::impl_armpl_vsincosq_f32: |
| case RTLIB::impl_armpl_svsincos_f64_x: |
| case RTLIB::impl_armpl_svsincos_f32_x: |
| case RTLIB::impl__ZGVnN4vl4l4_sincospif: |
| case RTLIB::impl__ZGVnN2vl8l8_sincospi: |
| case RTLIB::impl__ZGVsNxvl4l4_sincospif: |
| case RTLIB::impl__ZGVsNxvl8l8_sincospi: |
| case RTLIB::impl_armpl_vsincospiq_f32: |
| case RTLIB::impl_armpl_vsincospiq_f64: |
| case RTLIB::impl_armpl_svsincospi_f32_x: |
| case RTLIB::impl_armpl_svsincospi_f64_x: { |
| AttrBuilder FuncAttrBuilder(Ctx); |
| |
| bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vl4l4_sincospif || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincospif || |
| LibcallImpl == RTLIB::impl_armpl_vsincospiq_f32 || |
| LibcallImpl == RTLIB::impl_armpl_svsincospi_f32_x || |
| LibcallImpl == RTLIB::impl__ZGVnN4vl4l4_sincosf || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincosf || |
| LibcallImpl == RTLIB::impl_armpl_vsincosq_f32 || |
| LibcallImpl == RTLIB::impl_armpl_svsincos_f32_x; |
| |
| Type *ScalarTy = IsF32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx); |
| unsigned EC = IsF32 ? 4 : 2; |
| |
| bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsNxvl8l8_sincos || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincosf || |
| LibcallImpl == RTLIB::impl_armpl_svsincos_f32_x || |
| LibcallImpl == RTLIB::impl_armpl_svsincos_f64_x || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincospif || |
| LibcallImpl == RTLIB::impl__ZGVsNxvl8l8_sincospi || |
| LibcallImpl == RTLIB::impl_armpl_svsincospi_f32_x || |
| LibcallImpl == RTLIB::impl_armpl_svsincospi_f64_x; |
| VectorType *VecTy = VectorType::get(ScalarTy, EC, IsScalable); |
| |
| for (Attribute::AttrKind Attr : CommonFnAttrs) |
| FuncAttrBuilder.addAttribute(Attr); |
| FuncAttrBuilder.addMemoryAttr(MemoryEffects::argMemOnly(ModRefInfo::Mod)); |
| |
| AttributeList Attrs; |
| Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder); |
| |
| { |
| AttrBuilder ArgAttrBuilder(Ctx); |
| for (Attribute::AttrKind AK : CommonPtrArgAttrs) |
| ArgAttrBuilder.addAttribute(AK); |
| ArgAttrBuilder.addAlignmentAttr(DL.getABITypeAlign(VecTy)); |
| Attrs = Attrs.addParamAttributes(Ctx, 1, ArgAttrBuilder); |
| Attrs = Attrs.addParamAttributes(Ctx, 2, ArgAttrBuilder); |
| } |
| |
| PointerType *PtrTy = PointerType::get(Ctx, 0); |
| SmallVector<Type *, 4> ArgTys = {VecTy, PtrTy, PtrTy}; |
| if (hasVectorMaskArgument(LibcallImpl)) |
| ArgTys.push_back(VectorType::get(Type::getInt1Ty(Ctx), EC, IsScalable)); |
| |
| return {FunctionType::get(Type::getVoidTy(Ctx), ArgTys, false), Attrs}; |
| } |
| default: |
| return {}; |
| } |
| |
| return {}; |
| } |
| |
| bool RuntimeLibcallsInfo::hasVectorMaskArgument(RTLIB::LibcallImpl Impl) { |
| /// FIXME: This should be generated by tablegen and support the argument at an |
| /// arbitrary position |
| switch (Impl) { |
| case RTLIB::impl_armpl_svfmod_f32_x: |
| case RTLIB::impl_armpl_svfmod_f64_x: |
| case RTLIB::impl_armpl_svmodf_f64_x: |
| case RTLIB::impl_armpl_svmodf_f32_x: |
| case RTLIB::impl_armpl_svsincos_f32_x: |
| case RTLIB::impl_armpl_svsincos_f64_x: |
| case RTLIB::impl_armpl_svsincospi_f32_x: |
| case RTLIB::impl_armpl_svsincospi_f64_x: |
| case RTLIB::impl__ZGVsMxvv_fmod: |
| case RTLIB::impl__ZGVsMxvv_fmodf: |
| return true; |
| default: |
| return false; |
| } |
| } |