diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h index 912715fbf6b19..d69c23753da7a 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.h +++ b/llvm/include/llvm/IR/RuntimeLibcalls.h @@ -52,7 +52,6 @@ struct RuntimeLibcallsInfo { FloatABI::ABIType FloatABI = FloatABI::Default, EABI EABIVersion = EABI::Default) { initSoftFloatCmpLibcallPredicates(); - initDefaultLibCallImpls(); initLibcalls(TT, ExceptionModel, FloatABI, EABIVersion); } @@ -97,6 +96,7 @@ struct RuntimeLibcallsInfo { /// Get the comparison predicate that's to be used to test the result of the /// comparison libcall against zero. This should only be used with /// floating-point compare libcalls. + // FIXME: This should be a function of RTLIB::LibcallImpl CmpInst::Predicate getSoftFloatCmpLibcallPredicate(RTLIB::Libcall Call) const { return SoftFloatCompareLibcallPredicates[Call]; @@ -172,13 +172,7 @@ struct RuntimeLibcallsInfo { void initDefaultLibCallImpls(); /// Generated by tablegen. - void setPPCLibCallNameOverrides(); - - /// Generated by tablegen. - void setZOSLibCallNameOverrides(); - - /// Generated by tablegen. - void setWindowsArm64LibCallNameOverrides(); + void setTargetRuntimeLibcallSets(const Triple &TT); void initSoftFloatCmpLibcallPredicates(); diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td index 1d9f02dcf8ba8..e24b4c928b421 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -891,6 +891,17 @@ def calloc : RuntimeLibcallImpl; } // End let IsDefault = true } // End defset DefaultRuntimeLibcallImpls +defvar DefaultLibCalls = + !foreach(entry, DefaultRuntimeLibcallImpls, entry.Provides); + +defvar DefaultRuntimeLibcallImpls_f128 = + !filter(entry, DefaultRuntimeLibcallImpls, + !match(!cast(entry.Provides), "_F128")); + +defvar DefaultRuntimeLibcallImpls_atomic = + !filter(entry, DefaultRuntimeLibcallImpls, + !match(!cast(entry.Provides), "ATOMIC")); + //-------------------------------------------------------------------- // Define implementation other libcalls //-------------------------------------------------------------------- @@ -915,58 +926,61 @@ def _Unwind_SjLj_Resume : RuntimeLibcallImpl; // F128 libm Runtime Libcalls //===----------------------------------------------------------------------===// -def logf128 : RuntimeLibcallImpl; -def log2f128 : RuntimeLibcallImpl; -def log10f128 : RuntimeLibcallImpl; -def expf128 : RuntimeLibcallImpl; -def exp2f128 : RuntimeLibcallImpl; -def exp10f128 : RuntimeLibcallImpl; -def sinf128 : RuntimeLibcallImpl; -def cosf128 : RuntimeLibcallImpl; -def tanf128 : RuntimeLibcallImpl; -def tanhf128 : RuntimeLibcallImpl; -def sincosf128 : RuntimeLibcallImpl; -def powf128 : RuntimeLibcallImpl; -def fminf128 : RuntimeLibcallImpl; -def fmaxf128 : RuntimeLibcallImpl; -def fmodf128 : RuntimeLibcallImpl; -def sqrtf128 : RuntimeLibcallImpl; -def ceilf128 : RuntimeLibcallImpl; -def floorf128 : RuntimeLibcallImpl; -def truncf128 : RuntimeLibcallImpl; -def roundf128 : RuntimeLibcallImpl; -def lroundf128 : RuntimeLibcallImpl; -def llroundf128 : RuntimeLibcallImpl; -def rintf128 : RuntimeLibcallImpl; -def lrintf128 : RuntimeLibcallImpl; -def llrintf128 : RuntimeLibcallImpl; -def nearbyintf128 : RuntimeLibcallImpl; -def fmaf128 : RuntimeLibcallImpl; -def frexpf128 : RuntimeLibcallImpl; - -def cbrtf128 : RuntimeLibcallImpl; -def fminimumf128 : RuntimeLibcallImpl; -def fmaximumf128 : RuntimeLibcallImpl; -def fminimum_numf128 : RuntimeLibcallImpl; -def fmaximum_numf128 : RuntimeLibcallImpl; -def asinf128 : RuntimeLibcallImpl; -def acosf128 : RuntimeLibcallImpl; -def atanf128 : RuntimeLibcallImpl; -def atan2f128 : RuntimeLibcallImpl; -def ldexpf128 : RuntimeLibcallImpl; -def roundevenf128 : RuntimeLibcallImpl; -def modff128 : RuntimeLibcallImpl; -def sinhf128 : RuntimeLibcallImpl; -def coshf128 : RuntimeLibcallImpl; -def copysignf128 : RuntimeLibcallImpl; - -def __logf128_finite : RuntimeLibcallImpl; -def __log2f128_finite : RuntimeLibcallImpl; -def __log10f128_finite : RuntimeLibcallImpl; -def __expf128_finite : RuntimeLibcallImpl; -def __exp2f128_finite : RuntimeLibcallImpl; -def __exp10f128_finite : RuntimeLibcallImpl; -def __powf128_finite : RuntimeLibcallImpl; +defset list LibmF128Libcalls = { + def logf128 : RuntimeLibcallImpl; + def log2f128 : RuntimeLibcallImpl; + def log10f128 : RuntimeLibcallImpl; + def expf128 : RuntimeLibcallImpl; + def exp2f128 : RuntimeLibcallImpl; + def exp10f128 : RuntimeLibcallImpl; + def sinf128 : RuntimeLibcallImpl; + def cosf128 : RuntimeLibcallImpl; + def tanf128 : RuntimeLibcallImpl; + def tanhf128 : RuntimeLibcallImpl; + def sincosf128 : RuntimeLibcallImpl; + def powf128 : RuntimeLibcallImpl; + def fminf128 : RuntimeLibcallImpl; + def fmaxf128 : RuntimeLibcallImpl; + def fmodf128 : RuntimeLibcallImpl; + def sqrtf128 : RuntimeLibcallImpl; + def ceilf128 : RuntimeLibcallImpl; + def floorf128 : RuntimeLibcallImpl; + def truncf128 : RuntimeLibcallImpl; + def roundf128 : RuntimeLibcallImpl; + def lroundf128 : RuntimeLibcallImpl; + def llroundf128 : RuntimeLibcallImpl; + def rintf128 : RuntimeLibcallImpl; + def lrintf128 : RuntimeLibcallImpl; + def llrintf128 : RuntimeLibcallImpl; + def nearbyintf128 : RuntimeLibcallImpl; + def fmaf128 : RuntimeLibcallImpl; + def frexpf128 : RuntimeLibcallImpl; + def cbrtf128 : RuntimeLibcallImpl; + def fminimumf128 : RuntimeLibcallImpl; + def fmaximumf128 : RuntimeLibcallImpl; + def fminimum_numf128 : RuntimeLibcallImpl; + def fmaximum_numf128 : RuntimeLibcallImpl; + def asinf128 : RuntimeLibcallImpl; + def acosf128 : RuntimeLibcallImpl; + def atanf128 : RuntimeLibcallImpl; + def atan2f128 : RuntimeLibcallImpl; + def ldexpf128 : RuntimeLibcallImpl; + def roundevenf128 : RuntimeLibcallImpl; + def modff128 : RuntimeLibcallImpl; + def sinhf128 : RuntimeLibcallImpl; + def coshf128 : RuntimeLibcallImpl; + def copysignf128 : RuntimeLibcallImpl; +} + +defset list LibmF128FiniteLibcalls = { + def __logf128_finite : RuntimeLibcallImpl; + def __log2f128_finite : RuntimeLibcallImpl; + def __log10f128_finite : RuntimeLibcallImpl; + def __expf128_finite : RuntimeLibcallImpl; + def __exp2f128_finite : RuntimeLibcallImpl; + def __exp10f128_finite : RuntimeLibcallImpl; + def __powf128_finite : RuntimeLibcallImpl; +} //===----------------------------------------------------------------------===// // AArch64 Runtime Libcalls @@ -994,16 +1008,41 @@ defset list AArch64LibcallImpls = { def __arm_sc_memcpy : RuntimeLibcallImpl; def __arm_sc_memmove : RuntimeLibcallImpl; def __arm_sc_memset : RuntimeLibcallImpl; -} +} // End AArch64LibcallImpls -foreach libcall = AArch64LibcallImpls in { - def arm64ec_#libcall : DuplicateLibcallImplWithPrefix; -} +def isAArch64_ExceptArm64EC + : RuntimeLibcallPredicate<"(TT.isAArch64() && !TT.isWindowsArm64EC())">; +def isWindowsArm64EC : RuntimeLibcallPredicate<"TT.isWindowsArm64EC()">; + +def AArch64SystemLibrary : SystemRuntimeLibrary; -foreach libcall = DefaultRuntimeLibcallImpls in { - def arm64ec_#libcall : DuplicateLibcallImplWithPrefix; +// Prepend a # to every name +defset list WinArm64ECDefaultRuntimeLibcallImpls = { + foreach libcall = DefaultRuntimeLibcallImpls in { + def arm64ec_#libcall : DuplicateLibcallImplWithPrefix; + } + + foreach libcall = AArch64LibcallImpls in { + def arm64ec_#libcall : DuplicateLibcallImplWithPrefix; + } } +def WindowsARM64ECSystemLibrary + : SystemRuntimeLibrary; + +//===----------------------------------------------------------------------===// +// AMDGPU Runtime Libcalls +//===----------------------------------------------------------------------===// + +def isAMDGPU : RuntimeLibcallPredicate<"TT.isAMDGPU()">; + +// No calls, except for dummy atomic calls to avoid crashes. +def AMDGPUSystemLibrary + : SystemRuntimeLibrary; + //===----------------------------------------------------------------------===// // ARM Runtime Libcalls //===----------------------------------------------------------------------===// @@ -1227,6 +1266,30 @@ def __udivmodhi4 : RuntimeLibcallImpl; // CallingConv::AVR_BUILTIN def avr_sin : RuntimeLibcallImpl; def avr_cos : RuntimeLibcallImpl; +def isAVR : RuntimeLibcallPredicate<"TT.getArch() == Triple::avr">; + +def AVRSystemLibrary + : SystemRuntimeLibrary< + isAVR, + (add(sub DefaultRuntimeLibcallImpls, + + // Division rtlib functions (not supported), use divmod + // functions instead + __divqi3, __divhi3, __divsi3, __udivqi3, __udivhi3, __udivsi3, + + // Modulus rtlib functions (not supported), use divmod functions + // instead + __modqi3, __modhi3, __modsi3, __umodqi3, __umodhi3, __umodsi3, + + // Standard f64 names are replaced + sin, cos, sinf, cosf), + + __divmodqi4, __divmodhi4, __divmodsi4, __udivmodqi4, __udivmodhi4, + __udivmodsi4, + + // Trigonometric rtlib functions + avr_sin, avr_cos)>; + //===----------------------------------------------------------------------===// // Hexagon Runtime Libcalls //===----------------------------------------------------------------------===// @@ -1447,52 +1510,94 @@ def __mspabi_mpyll : RuntimeLibcallImpl; // setLibcallCallingConv(MUL_I64, CallingConv::MSP430_BUILTIN); //===----------------------------------------------------------------------===// -// PPC Runtime Libcalls +// NVPTX Runtime Libcalls //===----------------------------------------------------------------------===// -class PPCRuntimeLibcallImpl - : RuntimeLibcallImpl; +def isNVPTX : RuntimeLibcallPredicate<"TT.isNVPTX()">; + +// No calls, except for dummy atomic calls to avoid crashes. +def NVPTXSystemLibrary + : SystemRuntimeLibrary; + +//===----------------------------------------------------------------------===// +// PPC Runtime Libcalls +//===----------------------------------------------------------------------===// // For IEEE quad-precision libcall names, PPC uses "kf" instead of "tf". -def __addkf3 : PPCRuntimeLibcallImpl; -def __subkf3 : PPCRuntimeLibcallImpl; -def __mulkf3 : PPCRuntimeLibcallImpl; -def __divkf3 : PPCRuntimeLibcallImpl; -def __powikf2 : PPCRuntimeLibcallImpl; -def __extendsfkf2 : PPCRuntimeLibcallImpl; -def __extenddfkf2 : PPCRuntimeLibcallImpl; -def __trunckfhf2 : PPCRuntimeLibcallImpl; -def __trunckfsf2 : PPCRuntimeLibcallImpl; -def __trunckfdf2 : PPCRuntimeLibcallImpl; -def __fixkfsi : PPCRuntimeLibcallImpl; -def __fixkfdi : PPCRuntimeLibcallImpl; -def __fixkfti : PPCRuntimeLibcallImpl; -def __fixunskfsi : PPCRuntimeLibcallImpl; -def __fixunskfdi : PPCRuntimeLibcallImpl; -def __fixunskfti : PPCRuntimeLibcallImpl; -def __floatsikf : PPCRuntimeLibcallImpl; -def __floatdikf : PPCRuntimeLibcallImpl; -def __floattikf : PPCRuntimeLibcallImpl; -def __floatunsikf : PPCRuntimeLibcallImpl; -def __floatundikf : PPCRuntimeLibcallImpl; -def __floatuntikf : PPCRuntimeLibcallImpl; -def __eqkf2 : PPCRuntimeLibcallImpl; -def __nekf2 : PPCRuntimeLibcallImpl; -def __gekf2 : PPCRuntimeLibcallImpl; -def __ltkf2 : PPCRuntimeLibcallImpl; -def __lekf2 : PPCRuntimeLibcallImpl; -def __gtkf2 : PPCRuntimeLibcallImpl; -def __unordkf2 : PPCRuntimeLibcallImpl; - -// PPC64 && Subtarget.isAIXABI() -def ___memmove64 : RuntimeLibcallImpl; -def ___memset64 : RuntimeLibcallImpl; -def ___bzero64 : RuntimeLibcallImpl; - -// !PPC64 && Subtarget.isAIXABI() -def ___memmove : RuntimeLibcallImpl; -def ___memset : RuntimeLibcallImpl; -def ___bzero : RuntimeLibcallImpl; +defset list PPCRuntimeLibcalls = { + def __addkf3 : RuntimeLibcallImpl; + def __subkf3 : RuntimeLibcallImpl; + def __mulkf3 : RuntimeLibcallImpl; + def __divkf3 : RuntimeLibcallImpl; + def __powikf2 : RuntimeLibcallImpl; + def __extendsfkf2 : RuntimeLibcallImpl; + def __extenddfkf2 : RuntimeLibcallImpl; + def __trunckfhf2 : RuntimeLibcallImpl; + def __trunckfsf2 : RuntimeLibcallImpl; + def __trunckfdf2 : RuntimeLibcallImpl; + def __fixkfsi : RuntimeLibcallImpl; + def __fixkfdi : RuntimeLibcallImpl; + def __fixkfti : RuntimeLibcallImpl; + def __fixunskfsi : RuntimeLibcallImpl; + def __fixunskfdi : RuntimeLibcallImpl; + def __fixunskfti : RuntimeLibcallImpl; + def __floatsikf : RuntimeLibcallImpl; + def __floatdikf : RuntimeLibcallImpl; + def __floattikf : RuntimeLibcallImpl; + def __floatunsikf : RuntimeLibcallImpl; + def __floatundikf : RuntimeLibcallImpl; + def __floatuntikf : RuntimeLibcallImpl; + def __eqkf2 : RuntimeLibcallImpl; + def __nekf2 : RuntimeLibcallImpl; + def __gekf2 : RuntimeLibcallImpl; + def __ltkf2 : RuntimeLibcallImpl; + def __lekf2 : RuntimeLibcallImpl; + def __gtkf2 : RuntimeLibcallImpl; + def __unordkf2 : RuntimeLibcallImpl; +} + +defset list PPC64AIXCallList = { + def ___memmove64 : RuntimeLibcallImpl; + def ___memset64 : RuntimeLibcallImpl; + def ___bzero64 : RuntimeLibcallImpl; +} + +defset list PPC32AIXCallList = { + def ___memmove : RuntimeLibcallImpl; + def ___memset : RuntimeLibcallImpl; + def ___bzero : RuntimeLibcallImpl; +} + +defvar PPCOverrides = !foreach(entry, PPCRuntimeLibcalls, entry.Provides); + +defvar ToPrune = !listremove(DefaultLibCalls, PPCOverrides); +// DefaultLibcalls item.Provides +//); + +// defvar PPCOverride = !foldl([], DefaultRuntimeLibcallImpls, acc, item, +// !eq(item.Provides, +//); + +def isPPC : RuntimeLibcallPredicate<"TT.isPPC()">; +def isAIX : RuntimeLibcallPredicate<"TT.isOSAIX()">; +def isNotAIX : RuntimeLibcallPredicate<"!TT.isOSAIX()">; +def isPPC32_AIX : RuntimeLibcallPredicate<"(TT.isPPC32() && TT.isOSAIX())">; +def isPPC64_AIX : RuntimeLibcallPredicate<"(TT.isPPC64() && TT.isOSAIX())">; + +def AIX32Calls : LibcallImpls<(add PPC32AIXCallList), isPPC32_AIX>; +def AIX64Calls : LibcallImpls<(add PPC64AIXCallList), isPPC64_AIX>; + +// FIXME: Current emission behavior with multiple implementations is +// janky. We need to filter out the conflicting cases with different +// f128 names, and then add the overrides. We should switch to +// explicitly adding subsets of the default calls. +def PPCSystemLibrary + : SystemRuntimeLibrary)>; //===----------------------------------------------------------------------===// // SPARC Runtime Libcalls @@ -1562,94 +1667,105 @@ def _allmul : RuntimeLibcallImpl; // CallingConv::X86_StdCall def __memcpy_4 : RuntimeLibcallImpl; +def isXCore : RuntimeLibcallPredicate<"TT.getArch() == Triple::xcore">; +def XCoreSystemLibrary + : SystemRuntimeLibrary; + //===----------------------------------------------------------------------===// // ZOS Runtime Libcalls //===----------------------------------------------------------------------===// -class ZOSRuntimeLibcallImpl - : RuntimeLibcallImpl; - -def zos___TRNC_B : ZOSRuntimeLibcallImpl; -def zos___FTRC_B : ZOSRuntimeLibcallImpl; -def zos___LTRC_B : ZOSRuntimeLibcallImpl; -def zos___WSQT_B : ZOSRuntimeLibcallImpl; -def zos___FSQT_B : ZOSRuntimeLibcallImpl; -def zos___LSQT_B : ZOSRuntimeLibcallImpl; -def zos___SSIN_B : ZOSRuntimeLibcallImpl; -def zos___FSIN_B : ZOSRuntimeLibcallImpl; -def zos___LSIN_B : ZOSRuntimeLibcallImpl; -def zos___ROUN_B : ZOSRuntimeLibcallImpl; -def zos___ROUNFB : ZOSRuntimeLibcallImpl; -def zos___ROUNLB : ZOSRuntimeLibcallImpl; -def zos___SRNT_B : ZOSRuntimeLibcallImpl; -def zos___RINTFB : ZOSRuntimeLibcallImpl; -def zos___RINTLB : ZOSRuntimeLibcallImpl; -def zos___WFMD_B : ZOSRuntimeLibcallImpl; -def zos___FFMD_B : ZOSRuntimeLibcallImpl; -def zos___LFMD_B : ZOSRuntimeLibcallImpl; -def zos___WPOW_B : ZOSRuntimeLibcallImpl; -def zos___FPOW_B : ZOSRuntimeLibcallImpl; -def zos___LPOW_B : ZOSRuntimeLibcallImpl; -def zos___NBYI_B : ZOSRuntimeLibcallImpl; -def zos___NBYIFB : ZOSRuntimeLibcallImpl; -def zos___NBYILB : ZOSRuntimeLibcallImpl; -def zos___ROND_B : ZOSRuntimeLibcallImpl; -def zos___FRND_B : ZOSRuntimeLibcallImpl; -def zos___LRND_B : ZOSRuntimeLibcallImpl; -def zos___LRNT_B : ZOSRuntimeLibcallImpl; -def zos___LRNTFB : ZOSRuntimeLibcallImpl; -def zos___LRNTLB : ZOSRuntimeLibcallImpl; -def zos___WLOG_B : ZOSRuntimeLibcallImpl; -def zos___FLOG_B : ZOSRuntimeLibcallImpl; -def zos___LLOG_B : ZOSRuntimeLibcallImpl; -def zos___LOG2_B : ZOSRuntimeLibcallImpl; -def zos___FLG2_B : ZOSRuntimeLibcallImpl; -def zos___LLG2_B : ZOSRuntimeLibcallImpl; -def zos___WLG1_B : ZOSRuntimeLibcallImpl; -def zos___FLG1_B : ZOSRuntimeLibcallImpl; -def zos___LLG1_B : ZOSRuntimeLibcallImpl; -def zos___LLRD_B : ZOSRuntimeLibcallImpl; -def zos___LLRDFB : ZOSRuntimeLibcallImpl; -def zos___LLRDLB : ZOSRuntimeLibcallImpl; -def zos___LLRT_B : ZOSRuntimeLibcallImpl; -def zos___LLRTFB : ZOSRuntimeLibcallImpl; -def zos___LLRTLB : ZOSRuntimeLibcallImpl; -def zos___SLXP_B : ZOSRuntimeLibcallImpl; -def zos___FLXP_B : ZOSRuntimeLibcallImpl; -def zos___LLXP_B : ZOSRuntimeLibcallImpl; -def zos___SFXP_B : ZOSRuntimeLibcallImpl; -def zos___FFXP_B : ZOSRuntimeLibcallImpl; -def zos___LFXP_B : ZOSRuntimeLibcallImpl; -def zos___FMIN_B : ZOSRuntimeLibcallImpl; -def zos___FMINFB : ZOSRuntimeLibcallImpl; -def zos___FMINLB : ZOSRuntimeLibcallImpl; -def zos___FMA_B : ZOSRuntimeLibcallImpl; -def zos___FMAFB : ZOSRuntimeLibcallImpl; -def zos___FMALB : ZOSRuntimeLibcallImpl; -def zos___FMAX_B : ZOSRuntimeLibcallImpl; -def zos___FMAXFB : ZOSRuntimeLibcallImpl; -def zos___FMAXLB : ZOSRuntimeLibcallImpl; -def zos___SFLR_B : ZOSRuntimeLibcallImpl; -def zos___FFLR_B : ZOSRuntimeLibcallImpl; -def zos___LFLR_B : ZOSRuntimeLibcallImpl; -def zos___WEXP_B : ZOSRuntimeLibcallImpl; -def zos___FEXP_B : ZOSRuntimeLibcallImpl; -def zos___LEXP_B : ZOSRuntimeLibcallImpl; -def zos___EXP2_B : ZOSRuntimeLibcallImpl; -def zos___FXP2_B : ZOSRuntimeLibcallImpl; -def zos___LXP2_B : ZOSRuntimeLibcallImpl; -def zos___SCOS_B : ZOSRuntimeLibcallImpl; -def zos___FCOS_B : ZOSRuntimeLibcallImpl; -def zos___LCOS_B : ZOSRuntimeLibcallImpl; -def zos___DCPY_B : ZOSRuntimeLibcallImpl; -def zos___FCPY_B : ZOSRuntimeLibcallImpl; -def zos___LCPY_B : ZOSRuntimeLibcallImpl; -def zos___SCEL_B : ZOSRuntimeLibcallImpl; -def zos___FCEL_B : ZOSRuntimeLibcallImpl; -def zos___LCEL_B : ZOSRuntimeLibcallImpl; -def zos___SCRT_B : ZOSRuntimeLibcallImpl; -def zos___FCBT_B : ZOSRuntimeLibcallImpl; -def zos___LCBT_B : ZOSRuntimeLibcallImpl; +defset list ZOSRuntimeLibcalls = { + def zos___TRNC_B : RuntimeLibcallImpl; + def zos___FTRC_B : RuntimeLibcallImpl; + def zos___LTRC_B : RuntimeLibcallImpl; + def zos___WSQT_B : RuntimeLibcallImpl; + def zos___FSQT_B : RuntimeLibcallImpl; + def zos___LSQT_B : RuntimeLibcallImpl; + def zos___SSIN_B : RuntimeLibcallImpl; + def zos___FSIN_B : RuntimeLibcallImpl; + def zos___LSIN_B : RuntimeLibcallImpl; + def zos___ROUN_B : RuntimeLibcallImpl; + def zos___ROUNFB : RuntimeLibcallImpl; + def zos___ROUNLB : RuntimeLibcallImpl; + def zos___SRNT_B : RuntimeLibcallImpl; + def zos___RINTFB : RuntimeLibcallImpl; + def zos___RINTLB : RuntimeLibcallImpl; + def zos___WFMD_B : RuntimeLibcallImpl; + def zos___FFMD_B : RuntimeLibcallImpl; + def zos___LFMD_B : RuntimeLibcallImpl; + def zos___WPOW_B : RuntimeLibcallImpl; + def zos___FPOW_B : RuntimeLibcallImpl; + def zos___LPOW_B : RuntimeLibcallImpl; + def zos___NBYI_B : RuntimeLibcallImpl; + def zos___NBYIFB : RuntimeLibcallImpl; + def zos___NBYILB : RuntimeLibcallImpl; + def zos___ROND_B : RuntimeLibcallImpl; + def zos___FRND_B : RuntimeLibcallImpl; + def zos___LRND_B : RuntimeLibcallImpl; + def zos___LRNT_B : RuntimeLibcallImpl; + def zos___LRNTFB : RuntimeLibcallImpl; + def zos___LRNTLB : RuntimeLibcallImpl; + def zos___WLOG_B : RuntimeLibcallImpl; + def zos___FLOG_B : RuntimeLibcallImpl; + def zos___LLOG_B : RuntimeLibcallImpl; + def zos___LOG2_B : RuntimeLibcallImpl; + def zos___FLG2_B : RuntimeLibcallImpl; + def zos___LLG2_B : RuntimeLibcallImpl; + def zos___WLG1_B : RuntimeLibcallImpl; + def zos___FLG1_B : RuntimeLibcallImpl; + def zos___LLG1_B : RuntimeLibcallImpl; + def zos___LLRD_B : RuntimeLibcallImpl; + def zos___LLRDFB : RuntimeLibcallImpl; + def zos___LLRDLB : RuntimeLibcallImpl; + def zos___LLRT_B : RuntimeLibcallImpl; + def zos___LLRTFB : RuntimeLibcallImpl; + def zos___LLRTLB : RuntimeLibcallImpl; + def zos___SLXP_B : RuntimeLibcallImpl; + def zos___FLXP_B : RuntimeLibcallImpl; + def zos___LLXP_B : RuntimeLibcallImpl; + def zos___SFXP_B : RuntimeLibcallImpl; + def zos___FFXP_B : RuntimeLibcallImpl; + def zos___LFXP_B : RuntimeLibcallImpl; + def zos___FMIN_B : RuntimeLibcallImpl; + def zos___FMINFB : RuntimeLibcallImpl; + def zos___FMINLB : RuntimeLibcallImpl; + def zos___FMA_B : RuntimeLibcallImpl; + def zos___FMAFB : RuntimeLibcallImpl; + def zos___FMALB : RuntimeLibcallImpl; + def zos___FMAX_B : RuntimeLibcallImpl; + def zos___FMAXFB : RuntimeLibcallImpl; + def zos___FMAXLB : RuntimeLibcallImpl; + def zos___SFLR_B : RuntimeLibcallImpl; + def zos___FFLR_B : RuntimeLibcallImpl; + def zos___LFLR_B : RuntimeLibcallImpl; + def zos___WEXP_B : RuntimeLibcallImpl; + def zos___FEXP_B : RuntimeLibcallImpl; + def zos___LEXP_B : RuntimeLibcallImpl; + def zos___EXP2_B : RuntimeLibcallImpl; + def zos___FXP2_B : RuntimeLibcallImpl; + def zos___LXP2_B : RuntimeLibcallImpl; + def zos___SCOS_B : RuntimeLibcallImpl; + def zos___FCOS_B : RuntimeLibcallImpl; + def zos___LCOS_B : RuntimeLibcallImpl; + def zos___DCPY_B : RuntimeLibcallImpl; + def zos___FCPY_B : RuntimeLibcallImpl; + def zos___LCPY_B : RuntimeLibcallImpl; + def zos___SCEL_B : RuntimeLibcallImpl; + def zos___FCEL_B : RuntimeLibcallImpl; + def zos___LCEL_B : RuntimeLibcallImpl; + def zos___SCRT_B : RuntimeLibcallImpl; + def zos___FCBT_B : RuntimeLibcallImpl; + def zos___LCBT_B : RuntimeLibcallImpl; +} + +def isSystemZZOS : RuntimeLibcallPredicate<"(TT.isSystemZ() && TT.isOSzOS())">; +def isZOS : RuntimeLibcallPredicate<"TT.isOSzOS()">; +def SystemZZOSSystemLibrary + : SystemRuntimeLibrary< + isSystemZZOS, (add DefaultRuntimeLibcallImpls, + LibcallImpls<(add ZOSRuntimeLibcalls), isZOS>)>; //===----------------------------------------------------------------------===// // WebAssembly Runtime Libcalls @@ -1659,3 +1775,12 @@ def zos___LCBT_B : ZOSRuntimeLibcallImpl; // TODO: when implementing other Wasm backends, make this generic or only do // this on emscripten depending on what they end up doing. def emscripten_return_address : RuntimeLibcallImpl; + +def isWasm : RuntimeLibcallPredicate<"TT.isWasm()">; + +// Define the emscripten name for return address helper. +// TODO: when implementing other Wasm backends, make this generic or only do +// this on emscripten depending on what they end up doing. +def WasmSystemLibrary + : SystemRuntimeLibrary; diff --git a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td index 9444a0a838cdd..d64e0d0adfa75 100644 --- a/llvm/include/llvm/IR/RuntimeLibcallsImpl.td +++ b/llvm/include/llvm/IR/RuntimeLibcallsImpl.td @@ -6,6 +6,23 @@ // //===----------------------------------------------------------------------===// +include "llvm/TableGen/SetTheory.td" + +// Predicate for whether a libcall exists for the target ABI. This is +// a module level property that should only be computed based on the +// triple. +class RuntimeLibcallPredicate { + // Expression of an llvm::Triple named TT for whether a libcall + // should exist. + code Cond = cond; +} + +// Predicate for whether a libcall should be used for the current +// function/subtarget. +class LibcallLoweringPredicate { code Cond = cond; } + +def AlwaysAvailable : RuntimeLibcallPredicate<[{}]>; + /// 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 @@ -28,5 +45,24 @@ class RuntimeLibcall { class RuntimeLibcallImpl { RuntimeLibcall Provides = P; string LibCallFuncName = Name; + list LoweringPredicates; bit IsDefault = false; } + +class LibcallImpls { + // Function of the triple where this applies + RuntimeLibcallPredicate AvailabilityPredicate = Pred; + dag MemberList = funcList; +} + +/// Convenience wrapper around LibcallImplSet to make a single libcall +/// implementation conditionally conditionally available. +class AvailableIf + : LibcallImpls<(add Impl), Pred>; + +/// Define a complete top level set of runtime libcalls for a target. +class SystemRuntimeLibrary { + RuntimeLibcallPredicate TriplePred = Pred; + LibcallImpls MemberList = LibcallImpls; +} diff --git a/llvm/include/llvm/TableGen/SetTheory.td b/llvm/include/llvm/TableGen/SetTheory.td new file mode 100644 index 0000000000000..38b89671ee541 --- /dev/null +++ b/llvm/include/llvm/TableGen/SetTheory.td @@ -0,0 +1,27 @@ +//===- SetTheory.td - DAG set operator declarations --------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// FIXME: This is not used everywhere, and different files declare +// different subsets of used operators. +// +// It just happens TargetSelectionDAG.td defines records with the same +// names as the tablegen DAG operators for SelectionDAG operators. + +// Target.td separately declares the special set operators. + +def add; // Forward declare +def sub; +def and; +def shl; +// def trunc; // FIXME: Name collision +def rotl; +def rotr; + +def sequence; +def decimate; +def interleave; diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp index 67f872b4574b1..eaa2cf5100c77 100644 --- a/llvm/lib/IR/RuntimeLibcalls.cpp +++ b/llvm/lib/IR/RuntimeLibcalls.cpp @@ -12,51 +12,16 @@ using namespace llvm; using namespace RTLIB; -#define GET_INIT_RUNTIME_LIBCALL_UTILS #define GET_INIT_RUNTIME_LIBCALL_NAMES +#define GET_SET_TARGET_RUNTIME_LIBCALL_SETS #include "llvm/IR/RuntimeLibcalls.inc" -#undef GET_INIT_RUNTIME_LIBCALL_UTILS #undef GET_INIT_RUNTIME_LIBCALL_NAMES +#undef GET_SET_TARGET_RUNTIME_LIBCALL_SETS static cl::opt HexagonEnableFastMathRuntimeCalls("hexagon-fast-math", cl::Hidden, cl::desc("Enable Fast Math processing")); -static void setAArch64LibcallNames(RuntimeLibcallsInfo &Info, - const Triple &TT) { -#define LCALLNAMES(A, B, N) \ - Info.setLibcallImpl(A##N##_RELAX, B##N##_relax); \ - Info.setLibcallImpl(A##N##_ACQ, B##N##_acq); \ - Info.setLibcallImpl(A##N##_REL, B##N##_rel); \ - Info.setLibcallImpl(A##N##_ACQ_REL, B##N##_acq_rel); -#define LCALLNAME4(A, B) \ - LCALLNAMES(A, B, 1) \ - LCALLNAMES(A, B, 2) LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8) -#define LCALLNAME5(A, B) \ - LCALLNAMES(A, B, 1) \ - LCALLNAMES(A, B, 2) \ - LCALLNAMES(A, B, 4) LCALLNAMES(A, B, 8) LCALLNAMES(A, B, 16) - - if (TT.isWindowsArm64EC()) { - LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::arm64ec___aarch64_cas) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::arm64ec___aarch64_swp) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::arm64ec___aarch64_ldadd) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::arm64ec___aarch64_ldset) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::arm64ec___aarch64_ldclr) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::arm64ec___aarch64_ldeor) - } else { - LCALLNAME5(RTLIB::OUTLINE_ATOMIC_CAS, RTLIB::__aarch64_cas) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_SWP, RTLIB::__aarch64_swp) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDADD, RTLIB::__aarch64_ldadd) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDSET, RTLIB::__aarch64_ldset) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDCLR, RTLIB::__aarch64_ldclr) - LCALLNAME4(RTLIB::OUTLINE_ATOMIC_LDEOR, RTLIB::__aarch64_ldeor) - } -#undef LCALLNAMES -#undef LCALLNAME4 -#undef LCALLNAME5 -} - static void setARMLibcallNames(RuntimeLibcallsInfo &Info, const Triple &TT, FloatABI::ABIType FloatABIType, EABI EABIVersion) { @@ -358,6 +323,8 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, ExceptionHandling ExceptionModel, FloatABI::ABIType FloatABI, EABI EABIVersion) { + setTargetRuntimeLibcallSets(TT); + // Use the f128 variants of math functions on x86 if (TT.isX86() && TT.isGNUEnvironment()) setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/true); @@ -367,28 +334,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, setLibcallImpl(RTLIB::UNWIND_RESUME, RTLIB::_Unwind_SjLj_Resume); } - if (TT.isPPC()) { - setPPCLibCallNameOverrides(); - - // TODO: Do the finite only functions exist? - setLongDoubleIsF128Libm(*this, /*FiniteOnlyFuncs=*/false); - - // TODO: Tablegen predicate support - if (TT.isOSAIX()) { - if (TT.isPPC64()) { - setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported); - setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove64); - setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset64); - setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero64); - } else { - setLibcallImpl(RTLIB::MEMCPY, RTLIB::Unsupported); - setLibcallImpl(RTLIB::MEMMOVE, RTLIB::___memmove); - setLibcallImpl(RTLIB::MEMSET, RTLIB::___memset); - setLibcallImpl(RTLIB::BZERO, RTLIB::___bzero); - } - } - } - // A few names are different on particular architectures or environments. if (TT.isOSDarwin()) { // For f16/f32 conversions, Darwin uses the standard naming scheme, @@ -485,14 +430,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, setLibcallImpl(RTLIB::FREXP_PPCF128, RTLIB::Unsupported); } - // Disable most libcalls on AMDGPU and NVPTX. - if (TT.isAMDGPU() || TT.isNVPTX()) { - for (RTLIB::Libcall LC : RTLIB::libcalls()) { - if (!isAtomicLibCall(LC)) - setLibcallImpl(LC, RTLIB::Unsupported); - } - } - if (TT.isOSMSVCRT()) { // MSVCRT doesn't have powi; fall back to pow setLibcallImpl(RTLIB::POWI_F32, RTLIB::Unsupported); @@ -520,55 +457,14 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, } } - if (TT.isAArch64()) { - if (TT.isWindowsArm64EC()) { - setWindowsArm64LibCallNameOverrides(); - setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::arm64ec___arm_sc_memcpy); - setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::arm64ec___arm_sc_memmove); - setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::arm64ec___arm_sc_memset); - } else { - setLibcallImpl(RTLIB::SC_MEMCPY, RTLIB::__arm_sc_memcpy); - setLibcallImpl(RTLIB::SC_MEMMOVE, RTLIB::__arm_sc_memmove); - setLibcallImpl(RTLIB::SC_MEMSET, RTLIB::__arm_sc_memset); - } - - setAArch64LibcallNames(*this, TT); - } else if (TT.isARM() || TT.isThumb()) { + if (TT.isARM() || TT.isThumb()) setARMLibcallNames(*this, TT, FloatABI, EABIVersion); - } else if (TT.getArch() == Triple::ArchType::avr) { - // Division rtlib functions (not supported), use divmod functions instead - setLibcallImpl(RTLIB::SDIV_I8, RTLIB::Unsupported); - setLibcallImpl(RTLIB::SDIV_I16, RTLIB::Unsupported); - setLibcallImpl(RTLIB::SDIV_I32, RTLIB::Unsupported); - setLibcallImpl(RTLIB::UDIV_I8, RTLIB::Unsupported); - setLibcallImpl(RTLIB::UDIV_I16, RTLIB::Unsupported); - setLibcallImpl(RTLIB::UDIV_I32, RTLIB::Unsupported); - - // Modulus rtlib functions (not supported), use divmod functions instead - setLibcallImpl(RTLIB::SREM_I8, RTLIB::Unsupported); - setLibcallImpl(RTLIB::SREM_I16, RTLIB::Unsupported); - setLibcallImpl(RTLIB::SREM_I32, RTLIB::Unsupported); - setLibcallImpl(RTLIB::UREM_I8, RTLIB::Unsupported); - setLibcallImpl(RTLIB::UREM_I16, RTLIB::Unsupported); - setLibcallImpl(RTLIB::UREM_I32, RTLIB::Unsupported); - - // Division and modulus rtlib functions - setLibcallImpl(RTLIB::SDIVREM_I8, RTLIB::__divmodqi4); - setLibcallImpl(RTLIB::SDIVREM_I16, RTLIB::__divmodhi4); - setLibcallImpl(RTLIB::SDIVREM_I32, RTLIB::__divmodsi4); - setLibcallImpl(RTLIB::UDIVREM_I8, RTLIB::__udivmodqi4); - setLibcallImpl(RTLIB::UDIVREM_I16, RTLIB::__udivmodhi4); - setLibcallImpl(RTLIB::UDIVREM_I32, RTLIB::__udivmodsi4); - + else if (TT.getArch() == Triple::ArchType::avr) { // 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 - setLibcallImpl(RTLIB::SIN_F32, RTLIB::avr_sin); - setLibcallImpl(RTLIB::COS_F32, RTLIB::avr_cos); } if (!TT.isWasm()) { @@ -582,11 +478,6 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, } setLibcallImpl(RTLIB::MULO_I128, RTLIB::Unsupported); - } else { - // Define the emscripten name for return address helper. - // TODO: when implementing other Wasm backends, make this generic or only do - // this on emscripten depending on what they end up doing. - setLibcallImpl(RTLIB::RETURN_ADDRESS, RTLIB::emscripten_return_address); } if (TT.getArch() == Triple::ArchType::hexagon) { @@ -633,10 +524,4 @@ void RuntimeLibcallsInfo::initLibcalls(const Triple &TT, if (TT.getArch() == Triple::ArchType::msp430) setMSP430Libcalls(*this, TT); - - if (TT.isSystemZ() && TT.isOSzOS()) - setZOSLibCallNameOverrides(); - - if (TT.getArch() == Triple::ArchType::xcore) - setLibcallImpl(RTLIB::MEMCPY_ALIGN_4, RTLIB::__memcpy_4); } diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td b/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td new file mode 100644 index 0000000000000..086edc79e3b36 --- /dev/null +++ b/llvm/test/TableGen/RuntimeLibcallEmitter-conflict-warning.td @@ -0,0 +1,60 @@ +// RUN: llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2> %t.err | FileCheck %s +// RUN: FileCheck -check-prefix=ERR %s < %t.err + +// Check behavior of libcall emission when multiple RuntimeLibcallImpl +// implementations provide the same RuntimeLibcall + +include "llvm/IR/RuntimeLibCallsImpl.td" + +def SOME_FUNC : RuntimeLibcall; +def OTHER_FUNC : RuntimeLibcall; +def ANOTHER_DUP : RuntimeLibcall; + +def isTargetArchA : RuntimeLibcallPredicate<[{isTargetArchA()}]>; +def isTargetArchB : RuntimeLibcallPredicate<[{isTargetArchB()}]>; +def isTargetArchC : RuntimeLibcallPredicate<[{isTargetArchC()}]>; + +def func_a : RuntimeLibcallImpl; +def func_b : RuntimeLibcallImpl; +def func_c : RuntimeLibcallImpl; +def other_func : RuntimeLibcallImpl; + +def dup0 : RuntimeLibcallImpl; +def dup1 : RuntimeLibcallImpl; + +// func_a and func_b both provide SOME_FUNC. + +// CHECK: if (isTargetArchA()) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_b}, // func_b +// CHECK-NEXT: }; + +// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_b, func_a +def TheSystemLibraryA : SystemRuntimeLibrary; + +// CHECK: if (isTargetArchB()) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func +// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a +// CHECK-NEXT: }; + +// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b +def TheSystemLibraryB : SystemRuntimeLibrary; + +// CHECK: if (isTargetArchC()) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::ANOTHER_DUP, RTLIB::dup1}, // dup1 +// CHECK-NEXT: {RTLIB::OTHER_FUNC, RTLIB::other_func}, // other_func +// CHECK-NEXT: {RTLIB::SOME_FUNC, RTLIB::func_a}, // func_a +// CHECK-NEXT: }; + +// ERR: :[[@LINE+3]]:5: warning: conflicting implementations for libcall ANOTHER_DUP: dup1, dup0 +// ERR: :[[@LINE+2]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_b +// ERR: :[[@LINE+1]]:5: warning: conflicting implementations for libcall SOME_FUNC: func_a, func_c +def TheSystemLibraryC : SystemRuntimeLibrary; diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td b/llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td new file mode 100644 index 0000000000000..a8b33e48613c3 --- /dev/null +++ b/llvm/test/TableGen/RuntimeLibcallEmitter-nested-predicates-error.td @@ -0,0 +1,18 @@ +// RUN: not llvm-tblgen -gen-runtime-libcalls -I %p/../../include %s 2>&1 | FileCheck -check-prefix=ERR %s + +include "llvm/IR/RuntimeLibCallsImpl.td" + +def FUNC0 : RuntimeLibcall; +def FUNC1 : RuntimeLibcall; + +def isFoo : RuntimeLibcallPredicate<[{isFoo()}]>; +def isBar : RuntimeLibcallPredicate<[{isBar()}]>; +def isTargetArch : RuntimeLibcallPredicate<[{isTargetArch()}]>; + +def func0 : RuntimeLibcallImpl; +def func1 : RuntimeLibcallImpl; + +// ERR: :[[@LINE+2]]:8: error: combining nested libcall set predicates currently unhandled +def TheSystemLibrary : SystemRuntimeLibrary), isFoo>) +>; diff --git a/llvm/test/TableGen/RuntimeLibcallEmitter.td b/llvm/test/TableGen/RuntimeLibcallEmitter.td index d4030dd0a7e95..d810ce3787703 100644 --- a/llvm/test/TableGen/RuntimeLibcallEmitter.td +++ b/llvm/test/TableGen/RuntimeLibcallEmitter.td @@ -9,6 +9,9 @@ def SRL_I64 : RuntimeLibcall; def SQRT_F128 : RuntimeLibcall; def SQRT_F80 : RuntimeLibcall; def BZERO : RuntimeLibcall; +def MEMCPY : RuntimeLibcall; +def MEMSET : RuntimeLibcall; +def CALLOC : RuntimeLibcall; // Test default names. let IsDefault = true in { @@ -22,27 +25,84 @@ let IsDefault = true in { // Ignore non-default in initDefaultLibCallNames. def bzero : RuntimeLibcallImpl; +def ___memset : RuntimeLibcallImpl; +def ___memcpy : RuntimeLibcallImpl; + +def calloc : RuntimeLibcallImpl; + +def CompilerRTLibcalls : LibcallImpls<(add __ashlsi3, __lshrdi3)>; +def LibmLibcalls : LibcallImpls<(add sqrtl_f80)>; + +//def AllCalls : LibcallImpls<(add CompilerRTLibcalls, LibmLibcalls, __ashlsi3)>; + +//def MostCalls : LibcallImpls<(sub AllCalls, __ashlsi3, sqrtl_f128)>; + +def isSimpleArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::simple}]>; +def isFooArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::foo}]>; + + +def isZOS : RuntimeLibcallPredicate<[{TT.getOS() == Triple::zos}]>; +def isPPC : RuntimeLibcallPredicate<[{TT.getArch().isPPC()}]>; +def isPPC64 : RuntimeLibcallPredicate<[{TT.getArch().isPPC64()}]>; + + +def isFoo : RuntimeLibcallPredicate<[{isFOO()}]>; +def isBarOS : RuntimeLibcallPredicate<[{TT.getOS() == Triple::bar}]>; +def isBuzzArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::buzz}]>; +def isBlahArch : RuntimeLibcallPredicate<[{TT.getArch() == Triple::blah}]>; + +def hasCompilerRT : RuntimeLibcallPredicate<[{TT.hasCompilerRT()}]>; + + + +def SimpleLibrary : SystemRuntimeLibrary; + + +def LibraryWithConditionalFunc : LibcallImpls<(add sqrtl_f128, bzero, AvailableIf<___memset, isBarOS>)>; + +def FooLibrary : SystemRuntimeLibrary; + +def BuzzLibrary : SystemRuntimeLibrary; + + + +def LibraryWithConditionalSet : LibcallImpls<(add sqrtl_f128, bzero, + LibcallImpls<(add CompilerRTLibcalls), hasCompilerRT>)>; + + + +def BlahLibrary : SystemRuntimeLibrary)>; + + + // All entries should be emitted in Libcall enum. // CHECK: #ifdef GET_RUNTIME_LIBCALL_ENUM // CHECK-NEXT: namespace llvm { // CHECK-NEXT: namespace RTLIB { // CHECK-NEXT: enum Libcall : unsigned short { // CHECK-NEXT: BZERO = 0, -// CHECK-NEXT: SHL_I32 = 1, -// CHECK-NEXT: SQRT_F80 = 2, -// CHECK-NEXT: SQRT_F128 = 3, -// CHECK-NEXT: SRL_I64 = 4, -// CHECK-NEXT: UNKNOWN_LIBCALL = 5 +// CHECK-NEXT: CALLOC = 1, +// CHECK-NEXT: MEMCPY = 2, +// CHECK-NEXT: MEMSET = 3, +// CHECK-NEXT: SHL_I32 = 4, +// CHECK-NEXT: SQRT_F80 = 5, +// CHECK-NEXT: SQRT_F128 = 6, +// CHECK-NEXT: SRL_I64 = 7, +// CHECK-NEXT: UNKNOWN_LIBCALL = 8 // CHECK-NEXT: }; // CHECK-EMPTY: // CHECK-NEXT:enum LibcallImpl : unsigned short { // CHECK-NEXT: Unsupported = 0, -// CHECK-NEXT: __ashlsi3 = 1, // __ashlsi3 -// CHECK-NEXT: __lshrdi3 = 2, // __lshrdi3 -// CHECK-NEXT: bzero = 3, // bzero -// CHECK-NEXT: sqrtl_f80 = 4, // sqrtl -// CHECK-NEXT: sqrtl_f128 = 5, // sqrtl -// CHECK-NEXT: NumLibcallImpls = 6 +// CHECK-NEXT: ___memcpy = 1, // ___memcpy +// CHECK-NEXT: ___memset = 2, // ___memset +// CHECK-NEXT: __ashlsi3 = 3, // __ashlsi3 +// CHECK-NEXT: __lshrdi3 = 4, // __lshrdi3 +// CHECK-NEXT: bzero = 5, // bzero +// CHECK-NEXT: calloc = 6, // calloc +// CHECK-NEXT: sqrtl_f80 = 7, // sqrtl +// CHECK-NEXT: sqrtl_f128 = 8, // sqrtl +// CHECK-NEXT: NumLibcallImpls = 9 // CHECK-NEXT: }; // CHECK-NEXT: } // End namespace RTLIB // CHECK-NEXT: } // End namespace llvm @@ -51,6 +111,9 @@ def bzero : RuntimeLibcallImpl; // CHECK: #ifdef GET_INIT_RUNTIME_LIBCALL_NAMES // CHECK-NEXT: const RTLIB::LibcallImpl llvm::RTLIB::RuntimeLibcallsInfo::DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1] = { // CHECK-NEXT: RTLIB::Unsupported, // RTLIB::BZERO +// CHECK-NEXT: RTLIB::Unsupported, // RTLIB::CALLOC +// CHECK-NEXT: RTLIB::Unsupported, // RTLIB::MEMCPY +// CHECK-NEXT: RTLIB::Unsupported, // RTLIB::MEMSET // CHECK-NEXT: RTLIB::__ashlsi3, // RTLIB::SHL_I32 // CHECK-NEXT: RTLIB::sqrtl_f80, // RTLIB::SQRT_F80 // CHECK-NEXT: RTLIB::sqrtl_f128, // RTLIB::SQRT_F128 @@ -60,18 +123,118 @@ def bzero : RuntimeLibcallImpl; // CHECK-EMPTY: // CHECK-NEXT: const char *const llvm::RTLIB::RuntimeLibcallsInfo::LibCallImplNames[RTLIB::NumLibcallImpls] = { // CHECK-NEXT: nullptr, // RTLIB::Unsupported +// CHECK-NEXT: "___memcpy", // RTLIB::___memcpy +// CHECK-NEXT: "___memset", // RTLIB::___memset // CHECK-NEXT: "__ashlsi3", // RTLIB::__ashlsi3 // CHECK-NEXT: "__lshrdi3", // RTLIB::__lshrdi3 // CHECK-NEXT: "bzero", // RTLIB::bzero +// CHECK-NEXT: "calloc", // RTLIB::calloc // CHECK-NEXT: "sqrtl", // RTLIB::sqrtl_f80 // CHECK-NEXT: "sqrtl", // RTLIB::sqrtl_f128 // CHECK-NEXT: }; // CHECK: const RTLIB::Libcall llvm::RTLIB::RuntimeLibcallsInfo::ImplToLibcall[RTLIB::NumLibcallImpls] = { // CHECK-NEXT: RTLIB::UNKNOWN_LIBCALL, // RTLIB::Unsupported +// CHECK-NEXT: RTLIB::MEMCPY, // RTLIB::___memcpy +// CHECK-NEXT: RTLIB::MEMSET, // RTLIB::___memset // CHECK-NEXT: RTLIB::SHL_I32, // RTLIB::__ashlsi3 // CHECK-NEXT: RTLIB::SRL_I64, // RTLIB::__lshrdi3 // CHECK-NEXT: RTLIB::BZERO, // RTLIB::bzero +// CHECK-NEXT: RTLIB::CALLOC, // RTLIB::calloc // CHECK-NEXT: RTLIB::SQRT_F80, // RTLIB::sqrtl_f80 // CHECK-NEXT: RTLIB::SQRT_F128, // RTLIB::sqrtl_f128 // CHECK-NEXT: }; + + +// CHECK: void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(const llvm::Triple &TT) { +// CHECK-NEXT: struct LibcallImplPair { +// CHECK-NEXT: RTLIB::Libcall Func; +// CHECK-NEXT: RTLIB::LibcallImpl Impl; +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: if (TT.getArch() == Triple::blah) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero +// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc +// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: if (TT.hasCompilerRT()) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// 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: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: if (TT.getOS() == Triple::bar) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::MEMSET, RTLIB::___memset}, // ___memset +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: if (TT.getArch() == Triple::buzz) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3 +// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl +// CHECK-NEXT: {RTLIB::SRL_I64, RTLIB::__lshrdi3}, // __lshrdi3 +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: if (TT.getArch() == Triple::foo) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::BZERO, RTLIB::bzero}, // bzero +// CHECK-NEXT: {RTLIB::SQRT_F128, RTLIB::sqrtl_f128}, // sqrtl +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: if (TT.getOS() == Triple::bar) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::MEMSET, RTLIB::___memset}, // ___memset +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK-NEXT: if (TT.getArch() == Triple::simple) { +// CHECK-NEXT: static const LibcallImplPair LibraryCalls[] = { +// CHECK-NEXT: {RTLIB::CALLOC, RTLIB::calloc}, // calloc +// CHECK-NEXT: {RTLIB::SHL_I32, RTLIB::__ashlsi3}, // __ashlsi3 +// CHECK-NEXT: {RTLIB::SQRT_F80, RTLIB::sqrtl_f80}, // sqrtl +// CHECK-NEXT: {RTLIB::SRL_I64, RTLIB::__lshrdi3}, // __lshrdi3 +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: for (const auto [Func, Impl] : LibraryCalls) { +// CHECK-NEXT: setLibcallImpl(Func, Impl); +// CHECK-NEXT: } +// CHECK-NEXT: return; +// CHECK-NEXT: } +// CHECK-NEXT: initDefaultLibCallImpls(); +// CHECK-NEXT: } +// CHECK-EMPTY: +// CHECK: #endif diff --git a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp index 9d77631862ee5..30fcca47a4706 100644 --- a/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp +++ b/llvm/utils/TableGen/Basic/RuntimeLibcallsEmitter.cpp @@ -11,17 +11,61 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" +#include "llvm/TableGen/SetTheory.h" #include "llvm/TableGen/TableGenBackend.h" + using namespace llvm; namespace { +class AvailabilityPredicate { + const Record *TheDef; + StringRef PredicateString; + +public: + AvailabilityPredicate(const Record *Def) : TheDef(Def) { + if (TheDef) + PredicateString = TheDef->getValueAsString("Cond"); + } + + const Record *getDef() const { return TheDef; } + + bool isAlwaysAvailable() const { return PredicateString.empty(); } + + void emitIf(raw_ostream &OS) const { + OS << "if (" << PredicateString << ") {\n"; + } + + void emitEndIf(raw_ostream &OS) const { OS << "}\n"; } +}; + +class RuntimeLibcallEmitter; +class RuntimeLibcallImpl; + +/// Used to apply predicates to nested sets of libcalls. +struct LibcallPredicateExpander : SetTheory::Expander { + const RuntimeLibcallEmitter &LibcallEmitter; + DenseMap> &Func2Preds; + + LibcallPredicateExpander( + const RuntimeLibcallEmitter &LibcallEmitter, + DenseMap> &Func2Preds) + : LibcallEmitter(LibcallEmitter), Func2Preds(Func2Preds) {} + + void expand(SetTheory &ST, const Record *Def, + SetTheory::RecSet &Elts) override; +}; + class RuntimeLibcall { const Record *TheDef = nullptr; + const size_t EnumVal; public: RuntimeLibcall() = delete; - RuntimeLibcall(const Record *Def) : TheDef(Def) { assert(Def); } + RuntimeLibcall(const Record *Def, size_t EnumVal) + : TheDef(Def), EnumVal(EnumVal) { + assert(Def); + } ~RuntimeLibcall() { assert(TheDef); } @@ -29,6 +73,8 @@ class RuntimeLibcall { StringRef getName() const { return TheDef->getName(); } + size_t getEnumVal() const { return EnumVal; } + void emitEnumEntry(raw_ostream &OS) const { OS << "RTLIB::" << TheDef->getValueAsString("Name"); } @@ -37,12 +83,14 @@ class RuntimeLibcall { class RuntimeLibcallImpl { const Record *TheDef; const RuntimeLibcall *Provides = nullptr; + const size_t EnumVal; public: RuntimeLibcallImpl( const Record *Def, - const DenseMap &ProvideMap) - : TheDef(Def) { + const DenseMap &ProvideMap, + size_t EnumVal) + : TheDef(Def), EnumVal(EnumVal) { if (const Record *ProvidesDef = Def->getValueAsDef("Provides")) Provides = ProvideMap.lookup(ProvidesDef); } @@ -53,6 +101,8 @@ class RuntimeLibcallImpl { StringRef getName() const { return TheDef->getName(); } + size_t getEnumVal() const { return EnumVal; } + const RuntimeLibcall *getProvides() const { return Provides; } StringRef getLibcallFuncName() const { @@ -68,17 +118,29 @@ class RuntimeLibcallImpl { void emitEnumEntry(raw_ostream &OS) const { OS << "RTLIB::" << TheDef->getName(); } + + void emitSetImplCall(raw_ostream &OS) const { + OS << "setLibcallImpl("; + Provides->emitEnumEntry(OS); + OS << ", "; + emitEnumEntry(OS); + OS << "); // " << getLibcallFuncName() << '\n'; + } + + void emitTableEntry(raw_ostream &OS) const { + OS << '{'; + Provides->emitEnumEntry(OS); + OS << ", "; + emitEnumEntry(OS); + OS << "}, // " << getLibcallFuncName() << '\n'; + } }; class RuntimeLibcallEmitter { private: const RecordKeeper &Records; - DenseMap Def2RuntimeLibcall; - - const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const { - return Def2RuntimeLibcall.lookup(Def); - } + DenseMap Def2RuntimeLibcallImpl; std::vector RuntimeLibcallDefList; std::vector RuntimeLibcallImplDefList; @@ -86,16 +148,19 @@ class RuntimeLibcallEmitter { DenseMap LibCallToDefaultImpl; +private: void emitTargetOverrideFunc(raw_ostream &OS, StringRef FuncName, ArrayRef LibCallImplList) const; - void emitGetRuntimeLibcallEnum(raw_ostream &OS) const; + void emitTargetOverrideFunc(raw_ostream &OS, StringRef FuncName, + ArrayRef LibCallImplList) const; - void emitWindowsArm64LibCallNameOverrides(raw_ostream &OS) const; + void emitGetRuntimeLibcallEnum(raw_ostream &OS) const; void emitGetInitRuntimeLibcallNames(raw_ostream &OS) const; - void emitGetInitRuntimeLibcallUtils(raw_ostream &OS) const; + + void emitSystemRuntimeLibrarySetCalls(raw_ostream &OS) const; public: RuntimeLibcallEmitter(const RecordKeeper &R) : Records(R) { @@ -105,8 +170,9 @@ class RuntimeLibcallEmitter { RuntimeLibcallDefList.reserve(AllRuntimeLibcalls.size()); + size_t CallTypeEnumVal = 0; for (const Record *RuntimeLibcallDef : AllRuntimeLibcalls) { - RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef); + RuntimeLibcallDefList.emplace_back(RuntimeLibcallDef, CallTypeEnumVal++); Def2RuntimeLibcall[RuntimeLibcallDef] = &RuntimeLibcallDefList.back(); } @@ -117,12 +183,15 @@ class RuntimeLibcallEmitter { Records.getAllDerivedDefinitions("RuntimeLibcallImpl"); RuntimeLibcallImplDefList.reserve(AllRuntimeLibcallImpls.size()); + size_t LibCallImplEnumVal = 1; for (const Record *LibCallImplDef : AllRuntimeLibcallImpls) { - RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, - Def2RuntimeLibcall); + RuntimeLibcallImplDefList.emplace_back(LibCallImplDef, Def2RuntimeLibcall, + LibCallImplEnumVal++); RuntimeLibcallImpl &LibCallImpl = RuntimeLibcallImplDefList.back(); + Def2RuntimeLibcallImpl[LibCallImplDef] = &LibCallImpl; + // const RuntimeLibcallImpl &LibCallImpl = // RuntimeLibcallImplDefList.back(); if (LibCallImpl.isDefault()) { @@ -135,16 +204,12 @@ class RuntimeLibcallEmitter { } } - std::vector - getRuntimeLibcallImplSet(StringRef Name) const { - std::vector Result; - ArrayRef ImplSet = - Records.getAllDerivedDefinitionsIfDefined(Name); - Result.reserve(ImplSet.size()); + const RuntimeLibcall *getRuntimeLibcall(const Record *Def) const { + return Def2RuntimeLibcall.lookup(Def); + } - for (const Record *LibCallImplDef : ImplSet) - Result.emplace_back(LibCallImplDef, Def2RuntimeLibcall); - return Result; + const RuntimeLibcallImpl *getRuntimeLibcallImpl(const Record *Def) const { + return Def2RuntimeLibcallImpl.lookup(Def); } void run(raw_ostream &OS); @@ -182,72 +247,36 @@ void RuntimeLibcallEmitter::emitGetRuntimeLibcallEnum(raw_ostream &OS) const { "namespace RTLIB {\n" "enum Libcall : unsigned short {\n"; - size_t CallTypeEnumVal = 0; for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) { StringRef Name = LibCall.getName(); - OS << " " << Name << " = " << CallTypeEnumVal++ << ",\n"; + OS << " " << Name << " = " << LibCall.getEnumVal() << ",\n"; } // TODO: Emit libcall names as string offset table. - OS << " UNKNOWN_LIBCALL = " << CallTypeEnumVal + OS << " UNKNOWN_LIBCALL = " << RuntimeLibcallDefList.size() << "\n};\n\n" "enum LibcallImpl : unsigned short {\n" " Unsupported = 0,\n"; // FIXME: Emit this in a different namespace. And maybe use enum class. - size_t LibCallImplEnumVal = 1; for (const RuntimeLibcallImpl &LibCall : RuntimeLibcallImplDefList) { - OS << " " << LibCall.getName() << " = " << LibCallImplEnumVal++ << ", // " + OS << " " << LibCall.getName() << " = " << LibCall.getEnumVal() << ", // " << LibCall.getLibcallFuncName() << '\n'; } - OS << " NumLibcallImpls = " << LibCallImplEnumVal + OS << " NumLibcallImpls = " << RuntimeLibcallImplDefList.size() + 1 << "\n};\n" "} // End namespace RTLIB\n" "} // End namespace llvm\n" "#endif\n\n"; } -void RuntimeLibcallEmitter::emitWindowsArm64LibCallNameOverrides( - raw_ostream &OS) const { - // FIXME: Stop treating this as a special case - OS << "void " - "llvm::RTLIB::RuntimeLibcallsInfo::setWindowsArm64LibCallNameOverrides(" - ") {\n" - " static const RTLIB::LibcallImpl " - "WindowsArm64RoutineImpls[RTLIB::UNKNOWN_LIBCALL + 1] = {\n"; - for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) { - auto I = LibCallToDefaultImpl.find(&LibCall); - if (I == LibCallToDefaultImpl.end()) - OS << " RTLIB::Unsupported,"; - else { - const RuntimeLibcallImpl *LibCallImpl = I->second; - assert(LibCallImpl); - OS << " RTLIB::arm64ec_" << LibCallImpl->getName() << ','; - } - - OS << " // "; - LibCall.emitEnumEntry(OS); - OS << '\n'; - } - - OS << " RTLIB::Unsupported // RTLIB::UNKNOWN_LIBCALL\n" - " };\n\n" - " std::memcpy(LibcallImpls, WindowsArm64RoutineImpls,\n" - " sizeof(LibcallImpls));\n" - " static_assert(sizeof(LibcallImpls) == " - "sizeof(WindowsArm64RoutineImpls),\n" - " \"libcall array size should match\");\n" - "}\n#endif\n\n"; -} - void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames( raw_ostream &OS) const { // TODO: Emit libcall names as string offset table. - OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n" - "const RTLIB::LibcallImpl " + OS << "const RTLIB::LibcallImpl " "llvm::RTLIB::RuntimeLibcallsInfo::" "DefaultLibcallImpls[RTLIB::UNKNOWN_LIBCALL + 1] = {\n"; @@ -259,7 +288,7 @@ void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames( const RuntimeLibcallImpl *LibCallImpl = I->second; OS << " "; LibCallImpl->emitEnumEntry(OS); - OS << ","; + OS << ','; } OS << " // "; @@ -297,48 +326,182 @@ void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallNames( OS << '\n'; } OS << "};\n\n"; +} - std::vector ZOSRuntimeLibcallImplList = - getRuntimeLibcallImplSet("ZOSRuntimeLibcallImpl"); - emitTargetOverrideFunc(OS, "setZOSLibCallNameOverrides", - ZOSRuntimeLibcallImplList); +void RuntimeLibcallEmitter::emitSystemRuntimeLibrarySetCalls( + raw_ostream &OS) const { + OS << "void llvm::RTLIB::RuntimeLibcallsInfo::setTargetRuntimeLibcallSets(" + "const llvm::Triple &TT) {\n" + " struct LibcallImplPair {\n" + " RTLIB::Libcall Func;\n" + " RTLIB::LibcallImpl Impl;\n" + " };\n"; + ArrayRef AllLibs = + Records.getAllDerivedDefinitions("SystemRuntimeLibrary"); + + for (const Record *R : AllLibs) { + OS << '\n'; - std::vector PPCRuntimeLibcallImplList = - getRuntimeLibcallImplSet("PPCRuntimeLibcallImpl"); - emitTargetOverrideFunc(OS, "setPPCLibCallNameOverrides", - PPCRuntimeLibcallImplList); + AvailabilityPredicate TopLevelPredicate(R->getValueAsDef("TriplePred")); - emitWindowsArm64LibCallNameOverrides(OS); -} + OS << indent(2); + TopLevelPredicate.emitIf(OS); + SetTheory Sets; -void RuntimeLibcallEmitter::emitGetInitRuntimeLibcallUtils( - raw_ostream &OS) const { - // FIXME: Hack we shouldn't really need - OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_UTILS\n" - "static inline bool isAtomicLibCall(llvm::RTLIB::Libcall LC) {\n" - " switch (LC) {\n"; - for (const RuntimeLibcall &LibCall : RuntimeLibcallDefList) { - StringRef Name = LibCall.getName(); - if (Name.contains("ATOMIC")) { - OS << " case "; - LibCall.emitEnumEntry(OS); - OS << ":\n"; + DenseMap> Func2Preds; + Sets.addExpander( + "LibcallImpls", + std::make_unique(*this, Func2Preds)); + + const SetTheory::RecVec *Elements = + Sets.expand(R->getValueAsDef("MemberList")); + + // Sort to get deterministic output + SetVector PredicateSorter; + PredicateSorter.insert(nullptr); // No predicate first. + + DenseMap> + Pred2Funcs; + for (const Record *Elt : *Elements) { + const RuntimeLibcallImpl *LibCallImpl = getRuntimeLibcallImpl(Elt); + auto It = Func2Preds.find(Elt); + if (It == Func2Preds.end()) { + Pred2Funcs[nullptr].push_back(LibCallImpl); + continue; + } + + for (const Record *Pred : It->second) { + Pred2Funcs[Pred].push_back(LibCallImpl); + PredicateSorter.insert(Pred); + } } + + SmallVector SortedPredicates = + PredicateSorter.takeVector(); + + sort(SortedPredicates, [](const Record *A, const Record *B) { + if (!A) + return true; + if (!B) + return false; + return A->getName() < B->getName(); + }); + + for (const Record *Pred : SortedPredicates) { + AvailabilityPredicate SubsetPredicate(Pred); + unsigned IndentDepth = 2; + + auto It = Pred2Funcs.find(Pred); + if (It == Pred2Funcs.end()) + continue; + + if (!SubsetPredicate.isAlwaysAvailable()) { + IndentDepth = 4; + + OS << indent(IndentDepth); + SubsetPredicate.emitIf(OS); + } + + std::vector &Funcs = It->second; + + // Ensure we only emit a unique implementation per libcall in the + // selection table. + // + // FIXME: We need to generate separate functions for + // is-libcall-available and should-libcall-be-used to avoid this. + // + // This also makes it annoying to make use of the default set, since the + // entries from the default set may win over the replacements unless + // they are explicitly removed. + sort(Funcs, [](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) { + return A->getProvides()->getEnumVal() < B->getProvides()->getEnumVal(); + }); + + auto UniqueI = llvm::unique( + Funcs, [&](const RuntimeLibcallImpl *A, const RuntimeLibcallImpl *B) { + if (A->getProvides() == B->getProvides()) { + PrintWarning(R->getLoc(), + Twine("conflicting implementations for libcall " + + A->getProvides()->getName() + ": " + + A->getLibcallFuncName() + ", " + + B->getLibcallFuncName())); + return true; + } + + return false; + }); + + Funcs.erase(UniqueI, Funcs.end()); + + OS << indent(IndentDepth + 2) + << "static const LibcallImplPair LibraryCalls[] = {\n"; + for (const RuntimeLibcallImpl *LibCallImpl : Funcs) { + OS << indent(IndentDepth + 6); + LibCallImpl->emitTableEntry(OS); + } + + 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"; + + if (!SubsetPredicate.isAlwaysAvailable()) { + OS << indent(IndentDepth); + SubsetPredicate.emitEndIf(OS); + OS << '\n'; + } + } + + OS << indent(4) << "return;\n" << indent(2); + TopLevelPredicate.emitEndIf(OS); } - OS << " return true;\n" - " default:\n" - " return false;\n" - " }\n\n" - " llvm_unreachable(\"covered switch over libcalls\");\n" - "}\n#endif\n\n"; + // Fallback to the old default set for manual table entries. + // + // TODO: Remove this when targets have switched to using generated tables by + // default. + OS << " initDefaultLibCallImpls();\n"; + + OS << "}\n\n"; } void RuntimeLibcallEmitter::run(raw_ostream &OS) { emitSourceFileHeader("Runtime LibCalls Source Fragment", OS, Records); emitGetRuntimeLibcallEnum(OS); + + OS << "#ifdef GET_INIT_RUNTIME_LIBCALL_NAMES\n"; emitGetInitRuntimeLibcallNames(OS); - emitGetInitRuntimeLibcallUtils(OS); + OS << "#endif\n\n"; + + OS << "#ifdef GET_SET_TARGET_RUNTIME_LIBCALL_SETS\n"; + emitSystemRuntimeLibrarySetCalls(OS); + OS << "#endif\n\n"; +} + +void LibcallPredicateExpander::expand(SetTheory &ST, const Record *Def, + SetTheory::RecSet &Elts) { + assert(Def->isSubClassOf("LibcallImpls")); + + SetTheory::RecSet TmpElts; + + ST.evaluate(Def->getValueInit("MemberList"), TmpElts, Def->getLoc()); + + Elts.insert(TmpElts.begin(), TmpElts.end()); + + AvailabilityPredicate AP(Def->getValueAsDef("AvailabilityPredicate")); + + for (const Record *LibcallImpl : TmpElts) { + if (!AP.isAlwaysAvailable()) { + auto [It, Inserted] = Func2Preds.insert({LibcallImpl, {}}); + if (!Inserted) { + PrintError( + Def, "combining nested libcall set predicates currently unhandled"); + } + + It->second.push_back(AP.getDef()); + } + } } static TableGen::Emitter::OptClass