Skip to content

Commit 97edc88

Browse files
committed
[IR] Change fp128 lowering to use f128 functions by default
LLVM currently emits calls to `*l` (`long double`) libm symbols for `fp128` intrinsics. This works on platforms where `long double` and `_Float128` are the same type, but is incorrect on many platforms. Change RuntimeLibcalls such that `*f128` libcalls are used by default, which is always safe and correct but may not be available. On platforms where it is likely that `sqrtf128` and similar are not available, keep the current behavior of lowering to `*l` symbols if `long double` is `binary128`. The logic for whether f128 is `long double` is based on the platforms in Clang that set `LongDoubleFormat` to `llvm::APFloat::IEEEquad`. Fixes #44744
1 parent 7e94e41 commit 97edc88

File tree

15 files changed

+439
-350
lines changed

15 files changed

+439
-350
lines changed

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3564,7 +3564,8 @@ class LLVM_ABI TargetLoweringBase {
35643564
return Libcalls.getLibcallImpl(Call);
35653565
}
35663566

3567-
/// Get the libcall routine name for the specified libcall.
3567+
/// Get the libcall routine name for the specified libcall if implemented,
3568+
/// otherwise NULL.
35683569
const char *getLibcallName(RTLIB::Libcall Call) const {
35693570
return Libcalls.getLibcallName(Call);
35703571
}

llvm/include/llvm/IR/RuntimeLibcalls.td

Lines changed: 93 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def isOSWindows : RuntimeLibcallPredicate<"TT.isOSWindows()">;
2222
def darwinHasSinCosStret : RuntimeLibcallPredicate<"darwinHasSinCosStret(TT)">;
2323
def darwinHasExp10 : RuntimeLibcallPredicate<"darwinHasExp10(TT)">;
2424
def hasSinCos : RuntimeLibcallPredicate<"hasSinCos(TT)">;
25+
def f128LibmShouldUseLongDouble
26+
: RuntimeLibcallPredicate<"f128LibmShouldUseLongDouble(TT)">;
2527

2628
//--------------------------------------------------------------------
2729
// Declare all kinds of used libcalls
@@ -363,6 +365,9 @@ def MIPS16_RET_DF : RuntimeLibcall;
363365
def MIPS16_RET_SC : RuntimeLibcall;
364366
def MIPS16_RET_SF : RuntimeLibcall;
365367

368+
// Create libcall impls for `long double` and `_Float128`. See also `_ld128`
369+
// impls defined at `LibmF128AsLongDoubleLibcalls`.
370+
366371
// Produce libcall impls for all float types. If provided, `rtbasename` should
367372
// contain an `X` that will be replaced with the `f`/`l`/`fX` suffix (if not
368373
// provided, it is appended to the def name).
@@ -376,7 +381,7 @@ multiclass LibmLibcallImpls<string libcall_basename = !toupper(NAME),
376381
!subst("X", "", rtbasename)>;
377382
def NAME#"_f128"
378383
: RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_F128"),
379-
!subst("X", "l", rtbasename)>;
384+
!subst("X", "f128", rtbasename)>;
380385
def NAME#"_ppcf128"
381386
: RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_PPCF128"),
382387
!subst("X", "l", rtbasename)>;
@@ -385,6 +390,14 @@ multiclass LibmLibcallImpls<string libcall_basename = !toupper(NAME),
385390
!subst("X", "l", rtbasename)>;
386391
}
387392

393+
multiclass LibmF128AsLongDoubleImpls<string libcall_basename = !toupper(NAME),
394+
string rtbasename =
395+
!strconcat(NAME, "X")> {
396+
def NAME#"_ld128"
397+
: RuntimeLibcallImpl<!cast<RuntimeLibcall>(libcall_basename#"_F128"),
398+
!subst("X", "l", rtbasename)>;
399+
}
400+
388401
// AArch64 calls
389402
def SC_MEMCPY : RuntimeLibcall;
390403
def SC_MEMMOVE : RuntimeLibcall;
@@ -825,60 +838,65 @@ def __riscv_flush_icache : RuntimeLibcallImpl<RISCV_FLUSH_ICACHE>;
825838
// F128 libm Runtime Libcalls
826839
//===----------------------------------------------------------------------===//
827840

828-
defset list<RuntimeLibcallImpl> LibmF128Libcalls = {
829-
def logf128 : RuntimeLibcallImpl<LOG_F128>;
830-
def log2f128 : RuntimeLibcallImpl<LOG2_F128>;
831-
def log10f128 : RuntimeLibcallImpl<LOG10_F128>;
832-
def expf128 : RuntimeLibcallImpl<EXP_F128>;
833-
def exp2f128 : RuntimeLibcallImpl<EXP2_F128>;
834-
def exp10f128 : RuntimeLibcallImpl<EXP10_F128>;
835-
def sinf128 : RuntimeLibcallImpl<SIN_F128>;
836-
def cosf128 : RuntimeLibcallImpl<COS_F128>;
837-
def tanf128 : RuntimeLibcallImpl<TAN_F128>;
838-
def tanhf128 : RuntimeLibcallImpl<TANH_F128>;
839-
def sincosf128 : RuntimeLibcallImpl<SINCOS_F128>;
840-
def powf128 : RuntimeLibcallImpl<POW_F128>;
841-
def fminf128 : RuntimeLibcallImpl<FMIN_F128>;
842-
def fmaxf128 : RuntimeLibcallImpl<FMAX_F128>;
843-
def fmodf128 : RuntimeLibcallImpl<REM_F128>;
844-
def sqrtf128 : RuntimeLibcallImpl<SQRT_F128>;
845-
def ceilf128 : RuntimeLibcallImpl<CEIL_F128>;
846-
def floorf128 : RuntimeLibcallImpl<FLOOR_F128>;
847-
def truncf128 : RuntimeLibcallImpl<TRUNC_F128>;
848-
def roundf128 : RuntimeLibcallImpl<ROUND_F128>;
849-
def lroundf128 : RuntimeLibcallImpl<LROUND_F128>;
850-
def llroundf128 : RuntimeLibcallImpl<LLROUND_F128>;
851-
def rintf128 : RuntimeLibcallImpl<RINT_F128>;
852-
def lrintf128 : RuntimeLibcallImpl<LRINT_F128>;
853-
def llrintf128 : RuntimeLibcallImpl<LLRINT_F128>;
854-
def nearbyintf128 : RuntimeLibcallImpl<NEARBYINT_F128>;
855-
def fmaf128 : RuntimeLibcallImpl<FMA_F128>;
856-
def frexpf128 : RuntimeLibcallImpl<FREXP_F128>;
857-
def cbrtf128 : RuntimeLibcallImpl<CBRT_F128>;
858-
def fminimumf128 : RuntimeLibcallImpl<FMINIMUM_F128>;
859-
def fmaximumf128 : RuntimeLibcallImpl<FMAXIMUM_F128>;
860-
def fminimum_numf128 : RuntimeLibcallImpl<FMINIMUM_NUM_F128>;
861-
def fmaximum_numf128 : RuntimeLibcallImpl<FMAXIMUM_NUM_F128>;
862-
def asinf128 : RuntimeLibcallImpl<ASIN_F128>;
863-
def acosf128 : RuntimeLibcallImpl<ACOS_F128>;
864-
def atanf128 : RuntimeLibcallImpl<ATAN_F128>;
865-
def atan2f128 : RuntimeLibcallImpl<ATAN2_F128>;
866-
def ldexpf128 : RuntimeLibcallImpl<LDEXP_F128>;
867-
def roundevenf128 : RuntimeLibcallImpl<ROUNDEVEN_F128>;
868-
def modff128 : RuntimeLibcallImpl<MODF_F128>;
869-
def sinhf128 : RuntimeLibcallImpl<SINH_F128>;
870-
def coshf128 : RuntimeLibcallImpl<COSH_F128>;
871-
def copysignf128 : RuntimeLibcallImpl<COPYSIGN_F128>;
841+
// Impls for treating `fp128` as `long double`
842+
defset list<RuntimeLibcallImpl> LibmF128AsLongDoubleLibcalls = {
843+
defm log : LibmF128AsLongDoubleImpls;
844+
defm log2 : LibmF128AsLongDoubleImpls;
845+
defm log10 : LibmF128AsLongDoubleImpls;
846+
defm exp : LibmF128AsLongDoubleImpls;
847+
defm exp2 : LibmF128AsLongDoubleImpls;
848+
defm exp10 : LibmF128AsLongDoubleImpls;
849+
defm sin : LibmF128AsLongDoubleImpls;
850+
defm cos : LibmF128AsLongDoubleImpls;
851+
defm tan : LibmF128AsLongDoubleImpls;
852+
defm tanh : LibmF128AsLongDoubleImpls;
853+
defm sincos : LibmF128AsLongDoubleImpls;
854+
defm pow : LibmF128AsLongDoubleImpls;
855+
defm fmin : LibmF128AsLongDoubleImpls;
856+
defm fmax : LibmF128AsLongDoubleImpls;
857+
defm fmod : LibmF128AsLongDoubleImpls<"REM">;
858+
defm sqrt : LibmF128AsLongDoubleImpls;
859+
defm ceil : LibmF128AsLongDoubleImpls;
860+
defm floor : LibmF128AsLongDoubleImpls;
861+
defm trunc : LibmF128AsLongDoubleImpls;
862+
defm round : LibmF128AsLongDoubleImpls;
863+
defm lround : LibmF128AsLongDoubleImpls;
864+
defm llround : LibmF128AsLongDoubleImpls;
865+
defm rint : LibmF128AsLongDoubleImpls;
866+
defm lrint : LibmF128AsLongDoubleImpls;
867+
defm llrint : LibmF128AsLongDoubleImpls;
868+
defm nearbyint : LibmF128AsLongDoubleImpls;
869+
defm fma : LibmF128AsLongDoubleImpls;
870+
defm frexp : LibmF128AsLongDoubleImpls;
871+
defm cbrt : LibmF128AsLongDoubleImpls;
872+
defm fminimum : LibmF128AsLongDoubleImpls;
873+
defm fmaximum : LibmF128AsLongDoubleImpls;
874+
defm fminimum_num : LibmF128AsLongDoubleImpls;
875+
defm fmaximum_num : LibmF128AsLongDoubleImpls;
876+
defm asin : LibmF128AsLongDoubleImpls;
877+
defm acos : LibmF128AsLongDoubleImpls;
878+
defm atan : LibmF128AsLongDoubleImpls;
879+
defm atan2 : LibmF128AsLongDoubleImpls;
880+
defm ldexp : LibmF128AsLongDoubleImpls;
881+
defm roundeven : LibmF128AsLongDoubleImpls;
882+
defm modf : LibmF128AsLongDoubleImpls;
883+
defm sinh : LibmF128AsLongDoubleImpls;
884+
defm cosh : LibmF128AsLongDoubleImpls;
885+
defm copysign : LibmF128AsLongDoubleImpls;
872886
}
873887

874-
defset list<RuntimeLibcallImpl> LibmF128FiniteLibcalls = {
875-
def __logf128_finite : RuntimeLibcallImpl<LOG_FINITE_F128>;
876-
def __log2f128_finite : RuntimeLibcallImpl<LOG2_FINITE_F128>;
877-
def __log10f128_finite : RuntimeLibcallImpl<LOG10_FINITE_F128>;
878-
def __expf128_finite : RuntimeLibcallImpl<EXP_FINITE_F128>;
879-
def __exp2f128_finite : RuntimeLibcallImpl<EXP2_FINITE_F128>;
880-
def __exp10f128_finite : RuntimeLibcallImpl<EXP10_FINITE_F128>;
881-
def __powf128_finite : RuntimeLibcallImpl<POW_FINITE_F128>;
888+
defset list<RuntimeLibcallImpl> LibmF128AsLongDoubleFiniteLibcalls = {
889+
defm __log_finite : LibmF128AsLongDoubleImpls<"LOG_FINITE", "__logX_finite">;
890+
defm __log2_finite
891+
: LibmF128AsLongDoubleImpls<"LOG2_FINITE", "__log2X_finite">;
892+
defm __log10_finite
893+
: LibmF128AsLongDoubleImpls<"LOG10_FINITE", "__log10X_finite">;
894+
defm __exp_finite : LibmF128AsLongDoubleImpls<"EXP_FINITE", "__expX_finite">;
895+
defm __exp2_finite
896+
: LibmF128AsLongDoubleImpls<"EXP2_FINITE", "__exp2X_finite">;
897+
defm __exp10_finite
898+
: LibmF128AsLongDoubleImpls<"EXP10_FINITE", "__exp10X_finite">;
899+
defm __pow_finite : LibmF128AsLongDoubleImpls<"POW_FINITE", "__powX_finite">;
882900
}
883901

884902
//===----------------------------------------------------------------------===//
@@ -901,10 +919,6 @@ defvar DefaultRuntimeLibcallImpls_ppcf128 =
901919
!filter(entry, AllDefaultRuntimeLibcallImpls,
902920
!match(!cast<string>(entry.Provides), "PPCF128"));
903921

904-
defvar DefaultRuntimeLibcallImpls_f128 =
905-
!filter(entry, AllDefaultRuntimeLibcallImpls,
906-
!match(!cast<string>(entry.Provides), "_F128"));
907-
908922
defvar DefaultRuntimeLibcallImpls =
909923
!listremove(
910924
!listremove(
@@ -1692,7 +1706,7 @@ def NVPTXSystemLibrary : SystemRuntimeLibrary<isNVPTX, (add)>;
16921706
//===----------------------------------------------------------------------===//
16931707

16941708
// For IEEE quad-precision libcall names, PPC uses "kf" instead of "tf".
1695-
defset list<RuntimeLibcallImpl> PPCRuntimeLibcalls = {
1709+
defset list<RuntimeLibcallImpl> PPCOverriddenRuntimeLibcalls = {
16961710
def __addkf3 : RuntimeLibcallImpl<ADD_F128>;
16971711
def __subkf3 : RuntimeLibcallImpl<SUB_F128>;
16981712
def __mulkf3 : RuntimeLibcallImpl<MUL_F128>;
@@ -1736,7 +1750,17 @@ defset list<RuntimeLibcallImpl> PPC32AIXCallList = {
17361750
def ___bzero : RuntimeLibcallImpl<BZERO>;
17371751
}
17381752

1739-
defvar PPCOverrides = !foreach(entry, PPCRuntimeLibcalls, entry.Provides);
1753+
// List of overriden libcalls as strings, `["ADD_F128", "SUB_F128", ...]`
1754+
defvar PPCOverriddenNames = !foreach(entry, PPCOverriddenRuntimeLibcalls,
1755+
!cast<string>(entry.Provides));
1756+
1757+
// Default libcalls except for those that appear in `PPCOverrideNames`
1758+
defvar PPCNonOverriddenImpls = !filter(
1759+
default_entry, DefaultRuntimeLibcallImpls,
1760+
// `!contains` does not exist, `not->empty->filter` is a slightly hacky way
1761+
!not(!empty(
1762+
!filter(overridden, PPCOverriddenNames,
1763+
!eq(overridden, !cast<string>(default_entry.Provides))))));
17401764

17411765
def isPPC : RuntimeLibcallPredicate<"TT.isPPC()">;
17421766
def isPPC32 : RuntimeLibcallPredicate<"TT.isPPC32()">;
@@ -1749,20 +1773,22 @@ def isPPC64_AIX : RuntimeLibcallPredicate<"(TT.isPPC64() && TT.isOSAIX())">;
17491773
def AIX32Calls : LibcallImpls<(add PPC32AIXCallList), isPPC32_AIX>;
17501774
def AIX64Calls : LibcallImpls<(add PPC64AIXCallList), isPPC64_AIX>;
17511775

1776+
// Replace overridden values, adjust mem* symbols, add ppc_f128<->f128
1777+
// conversions.
1778+
defvar PPCDefaultRuntimeLibcallImpls = (add
1779+
(sub DefaultRuntimeLibcallImpls, PPCNonOverriddenImpls, memcpy),
1780+
PPCOverriddenRuntimeLibcalls, __extendkftf2, __trunctfkf2,
1781+
DefaultRuntimeLibcallImpls_ppcf128, AIX32Calls, AIX64Calls);
1782+
17521783
// FIXME: Current emission behavior with multiple implementations is
17531784
// janky. We need to filter out the conflicting cases with different
17541785
// f128 names, and then add the overrides. We should switch to
17551786
// explicitly adding subsets of the default calls.
17561787
def PPCSystemLibrary
17571788
: SystemRuntimeLibrary<isPPC,
1758-
(add PPCRuntimeLibcalls,
1759-
(sub DefaultRuntimeLibcallImpls, memcpy,
1760-
DefaultRuntimeLibcallImpls_f128),
1761-
__extendkftf2, __trunctfkf2,
1762-
DefaultRuntimeLibcallImpls_ppcf128,
1763-
LibmF128Libcalls, AIX32Calls, AIX64Calls,
1764-
AvailableIf<memcpy, isNotAIX>,
1765-
LibcallImpls<(add Int128RTLibcalls), isPPC64>)>;
1789+
(add PPCDefaultRuntimeLibcallImpls,
1790+
AvailableIf<memcpy, isNotAIX>,
1791+
LibcallImpls<(add Int128RTLibcalls), isPPC64>)>;
17661792

17671793
//===----------------------------------------------------------------------===//
17681794
// RISCV Runtime Libcalls

llvm/include/llvm/TargetParser/Triple.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,13 @@ class Triple {
266266
EABIHF,
267267
Android,
268268
Musl,
269-
MuslABIN32,
270-
MuslABI64,
271-
MuslEABI,
272-
MuslEABIHF,
273-
MuslF32,
274-
MuslSF,
275-
MuslX32,
269+
MuslABIN32, ///< MIPS N32 ABI
270+
MuslABI64, ///< MIPS N64 ABI
271+
MuslEABI, ///< Arm32 EABI
272+
MuslEABIHF, ///< Arm32 EABI + HF
273+
MuslF32, ///< LoongArch ILP32F/LP64F
274+
MuslSF, ///< LoongArch ILP32S/LP64S
275+
MuslX32, ///< Musl using 32-bit ABI on x86_64
276276
LLVM,
277277

278278
MSVC,
@@ -1274,6 +1274,10 @@ class Triple {
12741274
/// or an invalid version tuple if this triple doesn't have one.
12751275
LLVM_ABI VersionTuple getMinimumSupportedOSVersion() const;
12761276

1277+
/// Return true if `_Float128` libcalls should lower to e.g. `sqrtf` (`long
1278+
/// double`) rather than the default `sqrtf128`.
1279+
bool f128LibmShouldUseLongDouble() const;
1280+
12771281
/// @}
12781282
/// @name Static helpers for IDs.
12791283
/// @{

llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,10 @@ TargetLowering::makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT,
182182
}
183183

184184
const char *LibcallName = getLibcallName(LC);
185-
if (LC == RTLIB::UNKNOWN_LIBCALL || !LibcallName)
186-
reportFatalInternalError("unsupported library call operation");
185+
if (LC == RTLIB::UNKNOWN_LIBCALL || !LibcallName) {
186+
reportFatalInternalError("unsupported library call operation: libcall " +
187+
Twine(LC));
188+
}
187189

188190
SDValue Callee =
189191
DAG.getExternalSymbol(LibcallName, getPointerTy(DAG.getDataLayout()));

0 commit comments

Comments
 (0)