From 05ccbb72a1192205c1f42bbade509a401b95958e Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 26 Jan 2025 11:23:12 -0700 Subject: [PATCH 01/15] gen: use IEEE128 on ppc64le internally ... ... and then add a long double rewrite to convert it to ppc_f128 when lowering --- driver/targetmachine.cpp | 2 ++ gen/abi/ppc64le.cpp | 66 ++++++++++++++++++++++++++++++++++++++-- gen/target.cpp | 3 ++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 1408d632377..488e96ca2fb 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -108,6 +108,8 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl + +#include "driver/cl_options.h" #include "gen/abi/abi.h" #include "gen/abi/generic.h" #include "gen/dvalue.h" +#include "gen/funcgenstate.h" #include "gen/irstate.h" #include "gen/llvmhelpers.h" #include "gen/tollvm.h" using namespace dmd; +struct LongDoubleRewrite : ABIRewrite { + inline bool shouldRewrite(Type *ty) { + const auto baseTy = ty->toBasetype()->ty; + return baseTy == TY::Tfloat80 || baseTy == TY::Tcomplex80 || + baseTy == TY::Timaginary80; + } + + LLValue *put(DValue *dv, bool, bool) override { + if (shouldRewrite(dv->type)) { + auto *dconst = llvm::dyn_cast(DtoRVal(dv)); + if (dconst) { + // try to CTFE the conversion + // (ppc_convert_f128_to_ppcf128 intrinsics do not perform the conversion + // during the compile time) + bool ignored; + auto apfloat = dconst->getValue(); + apfloat.convert(llvm::APFloat::PPCDoubleDouble(), + llvm::APFloat::rmNearestTiesToEven, &ignored); + return llvm::ConstantFP::get(gIR->context(), apfloat); + } + const auto convertFunc = llvm::Intrinsic::getDeclaration( + &gIR->module, llvm::Intrinsic::ppc_convert_f128_to_ppcf128); + const auto ret = gIR->funcGen().callOrInvoke( + convertFunc, convertFunc->getFunctionType(), {DtoRVal(dv)}); + return ret; + } + return DtoRVal(dv); + } + + LLValue *getLVal(Type *dty, LLValue *v) override { + // inverse operation of method "put" + auto dstType = DtoType(dty); + if (shouldRewrite(dty) && dstType->isFP128Ty()) { + const auto convertFunc = llvm::Intrinsic::getDeclaration( + &gIR->module, llvm::Intrinsic::ppc_convert_ppcf128_to_f128); + const auto retType = LLType::getFP128Ty(gIR->context()); + const auto buffer = DtoRawAlloca(retType, 16); + const auto ret = gIR->funcGen().callOrInvoke( + convertFunc, convertFunc->getFunctionType(), {v}); + DtoStore(ret, buffer); + return buffer; + } + // dual-ABI situation: if the destination type is already correct, we just store it + const auto buffer = DtoRawAlloca(dstType, 16); + DtoStore(v, buffer); + return buffer; + } + + LLType *type(Type *ty) override { + return LLType::getPPC_FP128Ty(gIR->context()); + } +}; + struct PPC64LETargetABI : TargetABI { HFVAToArray hfvaToArray; CompositeToArray64 compositeToArray64; IntegerRewrite integerRewrite; + LongDoubleRewrite longDoubleRewrite; + bool useIEEE128; - explicit PPC64LETargetABI() : hfvaToArray(8) {} + explicit PPC64LETargetABI() + : hfvaToArray(8), useIEEE128(opts::mABI == "ieeelongdouble") {} bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); @@ -54,6 +114,8 @@ struct PPC64LETargetABI : TargetABI { } else if (ty->isintegral()) { arg.attrs.addAttribute(ty->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt); + } else if (!useIEEE128 && longDoubleRewrite.shouldRewrite(arg.type)) { + longDoubleRewrite.applyTo(arg); } } }; diff --git a/gen/target.cpp b/gen/target.cpp index 85bcf9f3740..db2033dab9b 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -64,6 +64,9 @@ llvm::Type *getRealType(const llvm::Triple &triple) { case Triple::wasm64: return LLType::getFP128Ty(ctx); + case Triple::ppc64le: + return LLType::getFP128Ty(ctx); + default: // 64-bit double precision for all other targets // FIXME: PowerPC, SystemZ, ... From 7802f8d0a0e367df8947224d038da83248ab0ab2 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sun, 26 Jan 2025 12:51:20 -0700 Subject: [PATCH 02/15] gen: use ppc_f128 or fp128 on ppc64le depending on the ABI switch --- gen/target.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/gen/target.cpp b/gen/target.cpp index db2033dab9b..62ba1d9b64c 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -64,12 +64,20 @@ llvm::Type *getRealType(const llvm::Triple &triple) { case Triple::wasm64: return LLType::getFP128Ty(ctx); + case Triple::ppc64: case Triple::ppc64le: - return LLType::getFP128Ty(ctx); + if (triple.isMusl()) { // Musl uses double + return LLType::getDoubleTy(ctx); + } + // dual-ABI complications: PPC only has IEEE 128-bit quad precision on + // Linux, IBM double-double is available on both AIX and Linux. + return triple.isOSLinux() && opts::mABI == "ieeelongdouble" + ? LLType::getFP128Ty(ctx) + : LLType::getPPC_FP128Ty(ctx); default: // 64-bit double precision for all other targets - // FIXME: PowerPC, SystemZ, ... + // FIXME: SystemZ, ... return LLType::getDoubleTy(ctx); } } @@ -159,6 +167,7 @@ void Target::_init(const Param ¶ms) { const auto IEEEdouble = &APFloat::IEEEdouble(); const auto x87DoubleExtended = &APFloat::x87DoubleExtended(); const auto IEEEquad = &APFloat::IEEEquad(); + const auto PPCDoubleDouble = &APFloat::PPCDoubleDouble(); bool isOutOfRange = false; RealProperties.nan = CTFloat::nan; @@ -200,6 +209,18 @@ void Target::_init(const Param ¶ms) { RealProperties.min_exp = -16381; RealProperties.max_10_exp = 4932; RealProperties.min_10_exp = -4931; + } else if (targetRealSemantics == PPCDoubleDouble) { + RealProperties.max = + CTFloat::parse("0x1.fffffffffffff7ffffffffffff8p1023", isOutOfRange); + RealProperties.min_normal = CTFloat::parse("0x1p-969", isOutOfRange); + RealProperties.epsilon = + CTFloat::parse("0x0.000000000000000000000000008p-969", isOutOfRange); + RealProperties.dig = 31; + RealProperties.mant_dig = 106; + RealProperties.max_exp = 1024; + RealProperties.min_exp = -968; + RealProperties.max_10_exp = 308; + RealProperties.min_10_exp = -291; } else { // leave initialized with host real_t values warning(Loc(), "unknown properties for target `real` type, relying on D " From d892d689fe9ae23ac755b48b85c31eec63baec5e Mon Sep 17 00:00:00 2001 From: liushuyu Date: Mon, 27 Jan 2025 13:58:11 -0700 Subject: [PATCH 03/15] driver: add D_PPCUseIEEE128 pre-defined version ... ... if -mabi=ieeelongdouble is specified on ppc64 --- driver/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/driver/main.cpp b/driver/main.cpp index 5119a864fd5..e254815630b 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -683,6 +683,10 @@ void registerPredefinedTargetVersions() { if (triple.getOS() == llvm::Triple::Linux) { VersionCondition::addPredefinedGlobalIdent( triple.getArch() == llvm::Triple::ppc64 ? "ELFv1" : "ELFv2"); + if (opts::mABI == "ieeelongdouble" && triple.isOSGlibc()) { + // Only GLibc needs this for IEEELongDouble + VersionCondition::addPredefinedGlobalIdent("D_PPCUseIEEE128"); + } } break; case llvm::Triple::arm: From 84c6a2bf5678f282d5370b5399151bd0e3949280 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Mon, 27 Jan 2025 13:58:50 -0700 Subject: [PATCH 04/15] druntime: redirect dual-ABI functions on glibc to IEEE128 version ... ... if IEEE long double ABI is selected --- runtime/druntime/src/core/stdc/config.d | 5 + runtime/druntime/src/core/stdc/math.d | 499 ++++++++++++++++++------ runtime/druntime/src/core/stdc/stdio.d | 188 ++++++--- runtime/druntime/src/core/stdc/stdlib.d | 12 +- 4 files changed, 522 insertions(+), 182 deletions(-) diff --git a/runtime/druntime/src/core/stdc/config.d b/runtime/druntime/src/core/stdc/config.d index 3ab41f834da..ea74c85386e 100644 --- a/runtime/druntime/src/core/stdc/config.d +++ b/runtime/druntime/src/core/stdc/config.d @@ -651,3 +651,8 @@ package(core) template muslRedirTime64Mangle(string name, string redirectedName) else enum muslRedirTime64Mangle = name; } + +version (PPC64) + enum PPCUseIEEE128 = real.mant_dig == 113; +else + enum PPCUseIEEE128 = false; diff --git a/runtime/druntime/src/core/stdc/math.d b/runtime/druntime/src/core/stdc/math.d index e54d5813995..1f384f9cbd4 100644 --- a/runtime/druntime/src/core/stdc/math.d +++ b/runtime/druntime/src/core/stdc/math.d @@ -4284,404 +4284,651 @@ else double acos(double x); /// float acosf(float x); - /// - real acosl(real x); /// double asin(double x); /// float asinf(float x); - /// - real asinl(real x); /// pure double atan(double x); /// pure float atanf(float x); - /// - pure real atanl(real x); /// double atan2(double y, double x); /// float atan2f(float y, float x); - /// - real atan2l(real y, real x); /// pure double cos(double x); /// pure float cosf(float x); - /// - pure real cosl(real x); /// pure double sin(double x); /// pure float sinf(float x); - /// - pure real sinl(real x); /// pure double tan(double x); /// pure float tanf(float x); - /// - pure real tanl(real x); /// double acosh(double x); /// float acoshf(float x); - /// - real acoshl(real x); /// pure double asinh(double x); /// pure float asinhf(float x); - /// - pure real asinhl(real x); /// double atanh(double x); /// float atanhf(float x); - /// - real atanhl(real x); /// double cosh(double x); /// float coshf(float x); - /// - real coshl(real x); /// double sinh(double x); /// float sinhf(float x); - /// - real sinhl(real x); /// pure double tanh(double x); /// pure float tanhf(float x); - /// - pure real tanhl(real x); /// double exp(double x); /// float expf(float x); - /// - real expl(real x); /// double exp2(double x); /// float exp2f(float x); - /// - real exp2l(real x); /// double expm1(double x); /// float expm1f(float x); - /// - real expm1l(real x); /// pure double frexp(double value, int* exp); /// pure float frexpf(float value, int* exp); - /// - pure real frexpl(real value, int* exp); /// int ilogb(double x); /// int ilogbf(float x); - /// - int ilogbl(real x); /// double ldexp(double x, int exp); /// float ldexpf(float x, int exp); - /// - real ldexpl(real x, int exp); /// double log(double x); /// float logf(float x); - /// - real logl(real x); /// double log10(double x); /// float log10f(float x); - /// - real log10l(real x); /// double log1p(double x); /// float log1pf(float x); - /// - real log1pl(real x); /// double log2(double x); /// float log2f(float x); - /// - real log2l(real x); /// double logb(double x); /// float logbf(float x); - /// - real logbl(real x); /// pure double modf(double value, double* iptr); /// pure float modff(float value, float* iptr); - /// - pure real modfl(real value, real *iptr); /// double scalbn(double x, int n); /// float scalbnf(float x, int n); - /// - real scalbnl(real x, int n); /// double scalbln(double x, c_long n); /// float scalblnf(float x, c_long n); - /// - real scalblnl(real x, c_long n); /// pure double cbrt(double x); /// pure float cbrtf(float x); - /// - pure real cbrtl(real x); /// pure double fabs(double x); - version (CRuntime_Microsoft) - { - } - else - { - /// - pure float fabsf(float x); - /// - pure real fabsl(real x); - } /// double hypot(double x, double y); /// float hypotf(float x, float y); - /// - real hypotl(real x, real y); /// double pow(double x, double y); /// float powf(float x, float y); - /// - real powl(real x, real y); /// double sqrt(double x); /// float sqrtf(float x); - /// - real sqrtl(real x); /// pure double erf(double x); /// pure float erff(float x); - /// - pure real erfl(real x); /// double erfc(double x); /// float erfcf(float x); - /// - real erfcl(real x); /// double lgamma(double x); /// float lgammaf(float x); - /// - real lgammal(real x); /// double tgamma(double x); /// float tgammaf(float x); - /// - real tgammal(real x); /// pure double ceil(double x); /// pure float ceilf(float x); - /// - pure real ceill(real x); /// pure double floor(double x); /// pure float floorf(float x); - /// - pure real floorl(real x); /// pure double nearbyint(double x); /// pure float nearbyintf(float x); - /// - pure real nearbyintl(real x); /// pure double rint(double x); /// pure float rintf(float x); - /// - pure real rintl(real x); /// c_long lrint(double x); /// c_long lrintf(float x); - /// - c_long lrintl(real x); /// long llrint(double x); /// long llrintf(float x); - /// - long llrintl(real x); /// pure double round(double x); /// pure float roundf(float x); - /// - pure real roundl(real x); /// c_long lround(double x); /// c_long lroundf(float x); - /// - c_long lroundl(real x); /// long llround(double x); /// long llroundf(float x); - /// - long llroundl(real x); /// pure double trunc(double x); /// pure float truncf(float x); - /// - pure real truncl(real x); /// double fmod(double x, double y); /// float fmodf(float x, float y); - /// - real fmodl(real x, real y); /// double remainder(double x, double y); /// float remainderf(float x, float y); - /// - real remainderl(real x, real y); /// double remquo(double x, double y, int* quo); /// float remquof(float x, float y, int* quo); - /// - real remquol(real x, real y, int* quo); /// pure double copysign(double x, double y); /// pure float copysignf(float x, float y); - /// - pure real copysignl(real x, real y); /// pure double nan(char* tagp); /// pure float nanf(char* tagp); - /// - pure real nanl(char* tagp); /// double nextafter(double x, double y); /// float nextafterf(float x, float y); /// - real nextafterl(real x, real y); - - /// - double nexttoward(double x, real y); - /// - float nexttowardf(float x, real y); - /// - real nexttowardl(real x, real y); /// double fdim(double x, double y); /// float fdimf(float x, float y); - /// - real fdiml(real x, real y); /// pure double fmax(double x, double y); /// pure float fmaxf(float x, float y); - /// - pure real fmaxl(real x, real y); + /// pure double fmin(double x, double y); /// pure float fminf(float x, float y); - /// - pure real fminl(real x, real y); + /// pure double fma(double x, double y, double z); /// pure float fmaf(float x, float y, float z); - /// - pure real fmal(real x, real y, real z); + + + static if (PPCUseIEEE128) { + /// + real __acosieee128(real x); + /// + alias acosl = __acosieee128; + /// + real __asinieee128(real x); + /// + alias asinl = __asinieee128; + /// + pure real __atanieee128(real x); + /// + alias atanl = __atanieee128; + /// + real __atan2ieee128(real y, real x); + /// + alias atan2l = __atan2ieee128; + /// + pure real __cosieee128(real x); + /// + alias cosl = __cosieee128; + /// + pure real __sinieee128(real x); + /// + alias sinl = __sinieee128; + /// + pure real __tanieee128(real x); + /// + alias tanl = __tanieee128; + /// + real __acoshieee128(real x); + /// + alias acoshl = __acoshieee128; + /// + pure real __asinhieee128(real x); + /// + alias asinhl = __asinhieee128; + /// + real __atanhieee128(real x); + /// + alias atanhl = __atanhieee128; + /// + real __coshieee128(real x); + /// + alias coshl = __coshieee128; + /// + real __sinhieee128(real x); + /// + alias sinhl = __sinhieee128; + /// + pure real __tanhieee128(real x); + /// + alias tanhl = __tanhieee128; + /// + real __expieee128(real x); + /// + alias expl = __expieee128; + /// + real __exp2ieee128(real x); + /// + alias exp2l = __exp2ieee128; + /// + real __expm1ieee128(real x); + /// + alias expm1l = __expm1ieee128; + /// + pure real __frexpieee128(real value, int* exp); + /// + alias frexpl = __frexpieee128; + /// + int __ilogbieee128(real x); + /// + alias ilogbl = __ilogbieee128; + /// + real __ldexpieee128(real x, int exp); + /// + alias ldexpl = __ldexpieee128; + /// + real __logieee128(real x); + /// + alias logl = __logieee128; + /// + real __log10ieee128(real x); + /// + alias log10l = __log10ieee128; + /// + real __log1pieee128(real x); + /// + alias log1pl = __log1pieee128; + /// + real __log2ieee128(real x); + /// + alias log2l = __log2ieee128; + /// + real __logbieee128(real x); + /// + alias logbl = __logbieee128; + /// + pure real __modfieee128(real value, real *iptr); + /// + alias modfl = __modfieee128; + /// + real __scalbnieee128(real x, int n); + /// + alias scalbnl = __scalbnieee128; + /// + real __scalblnieee128(real x, c_long n); + /// + alias scalblnl = __scalblnieee128; + /// + pure real __cbrtieee128(real x); + /// + alias cbrtl = __cbrtieee128; + /// + pure float fabsf(float x); + /// + pure real __fabsieee128(real x); + /// + alias fabsl = __fabsieee128; + /// + real __hypotieee128(real x, real y); + /// + alias hypotl = __hypotieee128; + /// + real __powieee128(real x, real y); + /// + alias powl = __powieee128; + /// + real __sqrtieee128(real x); + /// + alias sqrtl = __sqrtieee128; + /// + pure real __erfieee128(real x); + /// + alias erfl = __erfieee128; + /// + real __erfcieee128(real x); + /// + alias erfcl = __erfcieee128; + /// + real __lgammaieee128(real x); + /// + alias lgammal = __lgammaieee128; + /// + real __tgammaieee128(real x); + /// + alias tgammal = __tgammaieee128; + /// + pure real __ceilieee128(real x); + /// + alias ceill = __ceilieee128; + /// + pure real __floorieee128(real x); + /// + alias floorl = __floorieee128; + /// + pure real __nearbyintieee128(real x); + /// + alias nearbyintl = __nearbyintieee128; + /// + pure real __rintieee128(real x); + /// + alias rintl = __rintieee128; + /// + c_long __lrintieee128(real x); + /// + alias lrintl = __lrintieee128; + /// + long __llrintieee128(real x); + /// + alias llrintl = __llrintieee128; + /// + pure real __roundieee128(real x); + /// + alias roundl = __roundieee128; + /// + c_long __lroundieee128(real x); + /// + alias lroundl = __lroundieee128; + /// + long __llroundieee128(real x); + /// + alias llroundl = __llroundieee128; + /// + pure real __truncieee128(real x); + /// + alias truncl = __truncieee128; + /// + real __fmodieee128(real x, real y); + /// + alias fmodl = __fmodieee128; + /// + real __remainderieee128(real x, real y); + /// + alias remainderl = __remainderieee128; + /// + real __remquoieee128(real x, real y, int* quo); + /// + alias remquol = __remquoieee128; + /// + pure real __copysignieee128(real x, real y); + /// + alias copysignl = __copysignieee128; + /// + pure real __nanieee128(char* tagp); + /// + alias nanl = __nanieee128; + /// + real __nextafterieee128(real x, real y); + /// + alias nextafterl = __nextafterieee128; + /// + double __nexttoward_to_ieee128(double x, real y); + /// + alias nexttoward = __nexttoward_to_ieee128; + /// + float __nexttowardf_to_ieee128(float x, real y); + /// + alias nexttowardf = __nexttowardf_to_ieee128; + /// + real __nexttowardieee128(real x, real y); + /// + alias nexttowardl = __nexttowardieee128; + /// + real __fdimieee128(real x, real y); + /// + alias fdiml = __fdimieee128; + /// + pure real __fmaxieee128(real x, real y); + /// + alias fmaxl = __fmaxieee128; + /// + pure real __fminieee128(real x, real y); + /// + alias fminl = __fminieee128; + /// + pure real __fmaieee128(real x, real y, real z); + /// + alias fmal = __fmaieee128; + } + else + { + /// + real acosl(real x); + /// + real asinl(real x); + /// + pure real atanl(real x); + /// + real atan2l(real y, real x); + /// + pure real cosl(real x); + /// + pure real sinl(real x); + /// + pure real tanl(real x); + /// + real acoshl(real x); + /// + pure real asinhl(real x); + /// + real atanhl(real x); + /// + real coshl(real x); + /// + real sinhl(real x); + /// + pure real tanhl(real x); + /// + real expl(real x); + /// + real exp2l(real x); + /// + real expm1l(real x); + /// + pure real frexpl(real value, int* exp); + /// + int ilogbl(real x); + /// + real ldexpl(real x, int exp); + /// + real logl(real x); + /// + real log10l(real x); + /// + real log1pl(real x); + /// + real log2l(real x); + /// + real logbl(real x); + /// + pure real modfl(real value, real *iptr); + /// + real scalbnl(real x, int n); + /// + real scalblnl(real x, c_long n); + /// + pure real cbrtl(real x); + version (CRuntime_Microsoft) + { + } + else + { + /// + pure float fabsf(float x); + /// + pure real fabsl(real x); + } + /// + real hypotl(real x, real y); + /// + real powl(real x, real y); + /// + real sqrtl(real x); + /// + pure real erfl(real x); + /// + real erfcl(real x); + /// + real lgammal(real x); + /// + real tgammal(real x); + /// + pure real ceill(real x); + /// + pure real floorl(real x); + /// + pure real nearbyintl(real x); + /// + pure real rintl(real x); + /// + c_long lrintl(real x); + /// + long llrintl(real x); + /// + pure real roundl(real x); + /// + c_long lroundl(real x); + /// + long llroundl(real x); + /// + pure real truncl(real x); + /// + real fmodl(real x, real y); + /// + real remainderl(real x, real y); + /// + real remquol(real x, real y, int* quo); + /// + pure real copysignl(real x, real y); + /// + pure real nanl(char* tagp); + /// + real nextafterl(real x, real y); + /// + double nexttoward(double x, real y); + /// + float nexttowardf(float x, real y); + /// + real nexttowardl(real x, real y); + /// + real fdiml(real x, real y); + /// + pure real fmaxl(real x, real y); + /// + pure real fminl(real x, real y); + /// + pure real fmal(real x, real y, real z); + } } diff --git a/runtime/druntime/src/core/stdc/stdio.d b/runtime/druntime/src/core/stdc/stdio.d index 8afb68f8585..ba7015e8d86 100644 --- a/runtime/druntime/src/core/stdc/stdio.d +++ b/runtime/druntime/src/core/stdc/stdio.d @@ -1303,54 +1303,118 @@ version (MinGW) } else version (CRuntime_Glibc) { - /// - pragma(printf) - int fprintf(FILE* stream, scope const char* format, scope const ...); - /// - pragma(scanf) - int __isoc99_fscanf(FILE* stream, scope const char* format, scope ...); - /// - alias fscanf = __isoc99_fscanf; - /// - pragma(printf) - int sprintf(scope char* s, scope const char* format, scope const ...); - /// - pragma(scanf) - int __isoc99_sscanf(scope const char* s, scope const char* format, scope ...); - /// - alias sscanf = __isoc99_sscanf; - /// - pragma(printf) - int vfprintf(FILE* stream, scope const char* format, va_list arg); - /// - pragma(scanf) - int __isoc99_vfscanf(FILE* stream, scope const char* format, va_list arg); - /// - alias vfscanf = __isoc99_vfscanf; - /// - pragma(printf) - int vsprintf(scope char* s, scope const char* format, va_list arg); - /// - pragma(scanf) - int __isoc99_vsscanf(scope const char* s, scope const char* format, va_list arg); - /// - alias vsscanf = __isoc99_vsscanf; - /// - pragma(printf) - int vprintf(scope const char* format, va_list arg); - /// - pragma(scanf) - int __isoc99_vscanf(scope const char* format, va_list arg); - /// - alias vscanf = __isoc99_vscanf; - /// - pragma(printf) - int printf(scope const char* format, scope const ...); - /// - pragma(scanf) - int __isoc99_scanf(scope const char* format, scope ...); - /// - alias scanf = __isoc99_scanf; + static if (PPCUseIEEE128) + { + /// + pragma(printf) + int __fprintfieee128(FILE* stream, scope const char* format, scope const ...); + /// + alias fprintf = __fprintfieee128; + /// + pragma(scanf) + int __isoc99_fscanfieee128(FILE* stream, scope const char* format, scope ...); + /// + alias fscanf = __isoc99_fscanfieee128; + /// + pragma(printf) + int __sprintfieee128(scope char* s, scope const char* format, scope const ...); + /// + alias sprintf = __sprintfieee128; + /// + pragma(scanf) + int __isoc99_sscanfieee128(scope const char* s, scope const char* format, scope ...); + /// + alias sscanf = __isoc99_sscanfieee128; + /// + pragma(printf) + int vfprintf(FILE* stream, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vfscanfieee128(FILE* stream, scope const char* format, va_list arg); + /// + alias vfscanf = __isoc99_vfscanfieee128; + /// + pragma(printf) + int __vsprintfieee128(scope char* s, scope const char* format, va_list arg); + /// + alias vsprintf = __vsprintfieee128; + /// + pragma(scanf) + int __isoc99_vsscanfieee128(scope const char* s, scope const char* format, va_list arg); + /// + alias vsscanf = __isoc99_vsscanfieee128; + /// + pragma(printf) + int __vprintfieee128(scope const char* format, va_list arg); + /// + alias vprintf = __vprintfieee128; + /// + pragma(scanf) + int __isoc99_vfscanfieee128(scope const char* format, va_list arg); + /// + alias vscanf = __isoc99_vfscanfieee128; + /// + pragma(printf) + int __printfieee128(scope const char* format, scope const ...); + /// + alias printf = __printfieee128; + /// + pragma(scanf) + int __isoc99_scanfieee128(scope const char* format, scope ...); + /// + alias scanf = __isoc99_scanfieee128; + } + else + { + /// + pragma(printf) + int fprintf(FILE* stream, scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_fscanf(FILE* stream, scope const char* format, scope ...); + /// + alias fscanf = __isoc99_fscanf; + /// + pragma(printf) + int sprintf(scope char* s, scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_sscanf(scope const char* s, scope const char* format, scope ...); + /// + alias sscanf = __isoc99_sscanf; + /// + pragma(printf) + int vfprintf(FILE* stream, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vfscanf(FILE* stream, scope const char* format, va_list arg); + /// + alias vfscanf = __isoc99_vfscanf; + /// + pragma(printf) + int vsprintf(scope char* s, scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vsscanf(scope const char* s, scope const char* format, va_list arg); + /// + alias vsscanf = __isoc99_vsscanf; + /// + pragma(printf) + int vprintf(scope const char* format, va_list arg); + /// + pragma(scanf) + int __isoc99_vscanf(scope const char* format, va_list arg); + /// + alias vscanf = __isoc99_vscanf; + /// + pragma(printf) + int printf(scope const char* format, scope const ...); + /// + pragma(scanf) + int __isoc99_scanf(scope const char* format, scope ...); + /// + alias scanf = __isoc99_scanf; + } } else { @@ -1544,12 +1608,28 @@ else version (CRuntime_Glibc) int fileno(FILE *); } - /// - pragma(printf) - int snprintf(scope char* s, size_t n, scope const char* format, scope const ...); - /// - pragma(printf) - int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg); + static if (PPCUseIEEE128) + { + /// + pragma(printf) + int __snprintfieee128(scope char* s, size_t n, scope const char* format, scope const ...); + /// + alias snprintf = __snprintfieee128; + /// + pragma(printf) + int __vsnprintfieee128(scope char* s, size_t n, scope const char* format, va_list arg); + /// + alias vsnprintf = __vsnprintfieee128; + } + else + { + /// + pragma(printf) + int snprintf(scope char* s, size_t n, scope const char* format, scope const ...); + /// + pragma(printf) + int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg); + } // // Gnu under-the-hood C I/O functions. Uses _iobuf* for the unshared diff --git a/runtime/druntime/src/core/stdc/stdlib.d b/runtime/druntime/src/core/stdc/stdlib.d index bd5fc2b15ea..52fa1d0f70c 100644 --- a/runtime/druntime/src/core/stdc/stdlib.d +++ b/runtime/druntime/src/core/stdc/stdlib.d @@ -147,8 +147,16 @@ version (CRuntime_Microsoft) } else { - /// Added to Bionic since Lollipop. - real strtold(scope inout(char)* nptr, scope inout(char)** endptr); + static if (PPCUseIEEE128) + { + real __strtoieee128(scope inout(char)* nptr, scope inout(char)** endptr); + alias strtold = __strtoieee128; + } + else + { + /// Added to Bionic since Lollipop. + real strtold(scope inout(char)* nptr, scope inout(char)** endptr); + } } // No unsafe pointer manipulation. From eb7c41c5fbd285d3a7a79321220235b26b66bee1 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Fri, 31 Jan 2025 20:57:59 -0700 Subject: [PATCH 05/15] gen/modules.cpp: add PowerPC float-abi metadata marking --- gen/modules.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gen/modules.cpp b/gen/modules.cpp index dce1b59f6f3..d0294462e37 100644 --- a/gen/modules.cpp +++ b/gen/modules.cpp @@ -22,6 +22,7 @@ #include "dmd/statement.h" #include "dmd/target.h" #include "dmd/template.h" +#include "driver/cl_options.h" #include "driver/cl_options_instrumentation.h" #include "driver/timetrace.h" #include "gen/abi/abi.h" @@ -404,6 +405,23 @@ void addModuleFlags(llvm::Module &m) { opts::fCFProtection == opts::CFProtectionType::Full) { m.setModuleFlag(ModuleMinFlag, "cf-protection-branch", ConstantOneMetadata); } + + // Target specific flags + const auto ModuleErrFlag = llvm::Module::Error; + switch (global.params.targetTriple->getArch()) { + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + if (opts::mABI == "ieeelongdouble") { + const auto ConstantIEEE128String = llvm::MDString::get(gIR->context(), "ieeequad"); + m.setModuleFlag(ModuleErrFlag, "float-abi", ConstantIEEE128String); + } else { + const auto ConstantIBM128String = llvm::MDString::get(gIR->context(), "doubledouble"); + m.setModuleFlag(ModuleErrFlag, "float-abi", ConstantIBM128String); + } + break; + default: + break; + } } } // anonymous namespace From b0ab201e739c5e067fe89d5c8e7f690f9672629c Mon Sep 17 00:00:00 2001 From: liushuyu Date: Fri, 31 Jan 2025 20:58:39 -0700 Subject: [PATCH 06/15] gen/toir.cpp: use xor operator to emulate unary not operation ... ... to avoid a LLVM bug on multiple platforms --- gen/toir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index eea09ac405b..c1dc6d5362c 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1858,8 +1858,8 @@ class ToElemVisitor : public Visitor { LLValue *b = DtoRVal(DtoCast(e->loc, u, Type::tbool)); - LLConstant *zero = DtoConstBool(false); - b = p->ir->CreateICmpEQ(b, zero); + LLConstant *one = DtoConstBool(true); + b = p->ir->CreateXor(b, one); result = zextBool(b, e->type); } From a698cafeadc662c6d6a187cc2490c8dd8bd5e10c Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sat, 1 Feb 2025 15:06:45 -0700 Subject: [PATCH 07/15] gen/target.cpp: special C++ mangling for ppc64 --- gen/target.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gen/target.cpp b/gen/target.cpp index 62ba1d9b64c..eb842c83c04 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -264,6 +264,13 @@ const char *TargetCPP::typeMangle(Type *t) { // `long double` on Android/x64 is __float128 and mangled as `g` bool isAndroidX64 = triple.getEnvironment() == llvm::Triple::Android && triple.getArch() == llvm::Triple::x86_64; + if (triple.getArch() == llvm::Triple::ppc64 || + triple.getArch() == llvm::Triple::ppc64le) { + if (opts::mABI == "ieeelongdouble") { + return "u9__ieee128"; + } + return "g"; + } return isAndroidX64 ? "g" : "e"; } return nullptr; From 4e7800d34212d18754b243f8d22c5508a7918fa4 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sat, 1 Feb 2025 16:21:05 -0700 Subject: [PATCH 08/15] gen/abi/ppc64le.cpp: fix zext/sext for vector types --- gen/abi/ppc64le.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gen/abi/ppc64le.cpp b/gen/abi/ppc64le.cpp index 7f750d40f2c..7374d3f36f2 100644 --- a/gen/abi/ppc64le.cpp +++ b/gen/abi/ppc64le.cpp @@ -111,7 +111,7 @@ struct PPC64LETargetABI : TargetABI { } else { compositeToArray64.applyTo(arg); } - } else if (ty->isintegral()) { + } else if (ty->isintegral() && !ty->isTypeVector()) { arg.attrs.addAttribute(ty->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt); } else if (!useIEEE128 && longDoubleRewrite.shouldRewrite(arg.type)) { From 26034e503d6206d142e838bdac30b92d042885dc Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sat, 1 Feb 2025 16:21:27 -0700 Subject: [PATCH 09/15] runtime/fiber: enable CheckFiberMigration for ppc64 --- runtime/druntime/src/core/thread/fiber.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/druntime/src/core/thread/fiber.d b/runtime/druntime/src/core/thread/fiber.d index 03c122f86d0..f5d81a3c2c4 100644 --- a/runtime/druntime/src/core/thread/fiber.d +++ b/runtime/druntime/src/core/thread/fiber.d @@ -573,6 +573,8 @@ version (LDC) version (AArch64) version = CheckFiberMigration; + version (PPC64) version = CheckFiberMigration; + // Fiber migration across threads is (probably) not possible with ASan fakestack enabled (different parts of the stack // will contain fakestack pointers that were created on different threads...) version (SupportSanitizers) version = CheckFiberMigration; From f6d20f429b41a49c9a0c44e1604fa788e410ee64 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sat, 1 Feb 2025 16:23:33 -0700 Subject: [PATCH 10/15] runtime/atomic: enable 128BitCAS for ppc64 when using IEEE 128 ABI --- runtime/druntime/src/core/atomic.d | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runtime/druntime/src/core/atomic.d b/runtime/druntime/src/core/atomic.d index a71ca475532..e317632da68 100644 --- a/runtime/druntime/src/core/atomic.d +++ b/runtime/druntime/src/core/atomic.d @@ -652,9 +652,13 @@ version (LDC) version (D_LP64) { version (PPC64) - enum has128BitCAS = false; + { + enum has128BitCAS = real.mant_dig == 113; + } else + { enum has128BitCAS = true; + } } else enum has128BitCAS = false; From 5180b4d4dfebdcc826e1f58f45b4a2fa4fb135ad Mon Sep 17 00:00:00 2001 From: liushuyu Date: Tue, 4 Feb 2025 16:41:24 -0700 Subject: [PATCH 11/15] driver/main + gen/target: fix environment detection for ppc64 real type --- driver/main.cpp | 10 +++++++--- gen/target.cpp | 10 ++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/driver/main.cpp b/driver/main.cpp index e254815630b..0b3873d8b7e 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -683,9 +683,13 @@ void registerPredefinedTargetVersions() { if (triple.getOS() == llvm::Triple::Linux) { VersionCondition::addPredefinedGlobalIdent( triple.getArch() == llvm::Triple::ppc64 ? "ELFv1" : "ELFv2"); - if (opts::mABI == "ieeelongdouble" && triple.isOSGlibc()) { - // Only GLibc needs this for IEEELongDouble - VersionCondition::addPredefinedGlobalIdent("D_PPCUseIEEE128"); + if (opts::mABI == "ieeelongdouble") { + if (triple.getEnvironment() == llvm::Triple::GNU) { + // Only GLibc needs this for IEEELongDouble + VersionCondition::addPredefinedGlobalIdent("D_PPCUseIEEE128"); + } else { + warning(Loc(), "float ABI 'ieeelongdouble' is not supported by the target system"); + } } } break; diff --git a/gen/target.cpp b/gen/target.cpp index eb842c83c04..92e0b2f228c 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -266,10 +266,16 @@ const char *TargetCPP::typeMangle(Type *t) { triple.getArch() == llvm::Triple::x86_64; if (triple.getArch() == llvm::Triple::ppc64 || triple.getArch() == llvm::Triple::ppc64le) { - if (opts::mABI == "ieeelongdouble") { + if (opts::mABI == "ieeelongdouble" && + triple.getEnvironment() == llvm::Triple::GNU) { return "u9__ieee128"; } - return "g"; + if (size(t) == 16) { + // IBM long double + return "g"; + } + // fall back to 64-bit double type + return "e"; } return isAndroidX64 ? "g" : "e"; } From 4151349d7e01d7b4e21dfda2c6fbbadcdf472bc6 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Tue, 4 Feb 2025 16:59:03 -0700 Subject: [PATCH 12/15] CHANGELOG.md: document ppc64 and ppc64le IEEE 128 support changes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 125aefb5763..abea5883e0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - ldc2.conf: `%%ldcversion%%` placeholder added, allowing to refer to version-specific directories. #### Platform support +- Supports LLVM 15 - 19. +- Initial compiler and runtime support for ppc64 and ppc64le systems that use IEEE 754R 128-bit floating-point as the default 128-bit floating-point format. (#4833) #### Bug fixes - Building multi-file D applications with control-flow protection will no longer cause LDC to throw an internal compiler error. (#4828) From ae4c0d8e387c20d29cf5de37fcee314deca01bf0 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Wed, 5 Feb 2025 14:26:49 -0700 Subject: [PATCH 13/15] gen+driver: use a different approach to parse and pass IEEE 128 options This will allow the user to specify -real-precision=quad + -mabi=elfv1 together without changing how LDC parses mabi options --- driver/main.cpp | 14 ++++---------- driver/targetmachine.cpp | 2 -- gen/abi/ppc64le.cpp | 4 ++-- gen/modules.cpp | 2 +- gen/target.cpp | 38 +++++++++++++++++++++++++++++++++++--- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/driver/main.cpp b/driver/main.cpp index 0b3873d8b7e..a23dd2a1462 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -681,16 +681,10 @@ void registerPredefinedTargetVersions() { VersionCondition::addPredefinedGlobalIdent("PPC64"); registerPredefinedFloatABI("PPC_SoftFloat", "PPC_HardFloat"); if (triple.getOS() == llvm::Triple::Linux) { - VersionCondition::addPredefinedGlobalIdent( - triple.getArch() == llvm::Triple::ppc64 ? "ELFv1" : "ELFv2"); - if (opts::mABI == "ieeelongdouble") { - if (triple.getEnvironment() == llvm::Triple::GNU) { - // Only GLibc needs this for IEEELongDouble - VersionCondition::addPredefinedGlobalIdent("D_PPCUseIEEE128"); - } else { - warning(Loc(), "float ABI 'ieeelongdouble' is not supported by the target system"); - } - } + const llvm::SmallVector features{}; + const std::string abi = getABI(triple, features); + VersionCondition::addPredefinedGlobalIdent(abi == "elfv1" ? "ELFv1" + : "ELFv2"); } break; case llvm::Triple::arm: diff --git a/driver/targetmachine.cpp b/driver/targetmachine.cpp index 488e96ca2fb..1408d632377 100644 --- a/driver/targetmachine.cpp +++ b/driver/targetmachine.cpp @@ -108,8 +108,6 @@ const char *getABI(const llvm::Triple &triple, const llvm::SmallVectorImpl -#include "driver/cl_options.h" #include "gen/abi/abi.h" #include "gen/abi/generic.h" #include "gen/dvalue.h" @@ -23,6 +22,7 @@ #include "gen/irstate.h" #include "gen/llvmhelpers.h" #include "gen/tollvm.h" +#include "target.h" using namespace dmd; @@ -87,7 +87,7 @@ struct PPC64LETargetABI : TargetABI { bool useIEEE128; explicit PPC64LETargetABI() - : hfvaToArray(8), useIEEE128(opts::mABI == "ieeelongdouble") {} + : hfvaToArray(8), useIEEE128(target.RealProperties.mant_dig == 113) {} bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); diff --git a/gen/modules.cpp b/gen/modules.cpp index d0294462e37..f0bd4f19f90 100644 --- a/gen/modules.cpp +++ b/gen/modules.cpp @@ -411,7 +411,7 @@ void addModuleFlags(llvm::Module &m) { switch (global.params.targetTriple->getArch()) { case llvm::Triple::ppc64: case llvm::Triple::ppc64le: - if (opts::mABI == "ieeelongdouble") { + if (target.RealProperties.mant_dig == 113) { const auto ConstantIEEE128String = llvm::MDString::get(gIR->context(), "ieeequad"); m.setModuleFlag(ModuleErrFlag, "float-abi", ConstantIEEE128String); } else { diff --git a/gen/target.cpp b/gen/target.cpp index 92e0b2f228c..982db3ade56 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -26,6 +26,19 @@ using namespace dmd; using llvm::APFloat; +enum class RealTypeEncoding : uint8_t { Double, IEEEQuad, Platform }; +static llvm::cl::opt realTypeEncoding{ + "real-precision", llvm::cl::ZeroOrMore, + llvm::cl::init(RealTypeEncoding::Platform), + llvm::cl::desc("Set the precision of the `real` type"), + llvm::cl::values( + clEnumValN(RealTypeEncoding::Double, "double", + "Use double precision (64-bit)"), + clEnumValN(RealTypeEncoding::IEEEQuad, "quad", + "Use IEEE quad precision (128-bit)"), + clEnumValN(RealTypeEncoding::Platform, "platform", + "Use platform-specific precision (target-specific)"))}; + namespace { // Returns the LL type to be used for D `real` (C `long double`). llvm::Type *getRealType(const llvm::Triple &triple) { @@ -33,6 +46,11 @@ llvm::Type *getRealType(const llvm::Triple &triple) { auto &ctx = getGlobalContext(); + // If user specified double precision, use it unconditionally. + if (realTypeEncoding == RealTypeEncoding::Double) { + return LLType::getDoubleTy(ctx); + } + // Android: x86 targets follow ARM, with emulated quad precision for x64 if (triple.getEnvironment() == llvm::Triple::Android) { return triple.isArch64Bit() ? LLType::getFP128Ty(ctx) @@ -71,7 +89,7 @@ llvm::Type *getRealType(const llvm::Triple &triple) { } // dual-ABI complications: PPC only has IEEE 128-bit quad precision on // Linux, IBM double-double is available on both AIX and Linux. - return triple.isOSLinux() && opts::mABI == "ieeelongdouble" + return triple.isOSLinux() && realTypeEncoding == RealTypeEncoding::IEEEQuad ? LLType::getFP128Ty(ctx) : LLType::getPPC_FP128Ty(ctx); @@ -110,6 +128,20 @@ void Target::_init(const Param ¶ms) { os = OS_Freestanding; } + if (triple.isPPC64() && realTypeEncoding == RealTypeEncoding::IEEEQuad) { + if (triple.isGNUEnvironment()) { + // Only GLibc needs this for IEEELongDouble + if (!triple.isLittleEndian()) { + warning(Loc(), "float ABI 'ieeelongdouble' is not well-supported " + "on big-endian POWER systems"); + } + } else { + warning( + Loc(), + "float ABI 'ieeelongdouble' is not supported by the target system"); + } + } + osMajor = triple.getOSMajorVersion(); ptrsize = gDataLayout->getPointerSize(); @@ -266,11 +298,11 @@ const char *TargetCPP::typeMangle(Type *t) { triple.getArch() == llvm::Triple::x86_64; if (triple.getArch() == llvm::Triple::ppc64 || triple.getArch() == llvm::Triple::ppc64le) { - if (opts::mABI == "ieeelongdouble" && + if (target.RealProperties.mant_dig == 113 && triple.getEnvironment() == llvm::Triple::GNU) { return "u9__ieee128"; } - if (size(t) == 16) { + if (target.RealProperties.mant_dig == 106) { // IBM long double return "g"; } From 5195def3ff02f98d854a92b9097c153a5e028675 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Wed, 6 Dec 2023 13:04:46 -0700 Subject: [PATCH 14/15] cmake: do not turn off long double on ppc64 if ... ... the system is using the new ABI that supports IEEE 754R long double instead of the legacy IBM double double format --- CMakeLists.txt | 23 ++++++++++++++++++++++- ldc2.conf.in | 7 +++++++ ldc2_install.conf.in | 7 +++++++ ldc2_phobos.conf.in | 7 +++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc4c83dd69e..51080b0f5de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,7 +277,28 @@ if( CMAKE_COMPILER_IS_GNUCXX endif() # Do not use doubledouble on ppc if( CMAKE_SYSTEM_PROCESSOR MATCHES "ppc|powerpc") - append("-mlong-double-64" LDC_CXXFLAGS) + # this extra test checks if the system uses IEEE 754R long double + # if that is supported, then there is no need to turn off 128-bit double type + CHECK_CXX_SOURCE_COMPILES( + "#include \nint main(){static_assert(LDBL_MANT_DIG == 113, \"not IEEE long double\");return 0;}\n" + HAS_IEEE_LONG_DOUBLE + ) + CHECK_CXX_SOURCE_COMPILES( + "#include \nint main(){static_assert(LDBL_MANT_DIG == 106, \"not IBM long double\");return 0;}\n" + HAS_IBM_LONG_DOUBLE + ) + if ( HAS_IEEE_LONG_DOUBLE ) + set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -mabi=ieeelongdouble") + message( + WARNING + "Your system defaults to IEEE 128-bit ABI." + "You will need to include -mabi=ieeelongdouble (GDMD) or --real-precision=quad (LDC) in DFLAGS." + "You need to also make sure your host D libraries are built using IEEE 128-bit ABI." + ) + elseif ( NOT HAS_IBM_LONG_DOUBLE ) + # usually the case for musl/uclibc + set(LLVM_CXXFLAGS "${LLVM_CXXFLAGS} -mlong-double-64") + endif() endif() if(UNIX) append("-DLDC_POSIX" LDC_CXXFLAGS) diff --git a/ldc2.conf.in b/ldc2.conf.in index 0ef4caa07a2..0370c63927f 100644 --- a/ldc2.conf.in +++ b/ldc2.conf.in @@ -34,6 +34,13 @@ default: rpath = "@SHARED_LIBS_RPATH@"; }; +"^powerpc64le-.*linux-gnu$": +{ + // default to IEEE quad precision + // if your platform does not support this, feel free to remove it. + switches = ["--real-precision=quad"] +}; + "^wasm(32|64)-": { switches = [ diff --git a/ldc2_install.conf.in b/ldc2_install.conf.in index f8afa42613c..d6120918538 100644 --- a/ldc2_install.conf.in +++ b/ldc2_install.conf.in @@ -32,6 +32,13 @@ default: rpath = "@SHARED_LIBS_INSTALL_RPATH@"; }; +"^powerpc64le-.*linux-gnu$": +{ + // default to IEEE quad precision + // if your platform does not support this, feel free to remove it. + switches = ["--real-precision=quad"] +}; + "^wasm(32|64)-": { switches = [ diff --git a/ldc2_phobos.conf.in b/ldc2_phobos.conf.in index f2c00634f16..a984fb974aa 100644 --- a/ldc2_phobos.conf.in +++ b/ldc2_phobos.conf.in @@ -35,6 +35,13 @@ default: rpath = "@SHARED_LIBS_RPATH@"; }; +"^powerpc64le-.*linux-gnu$": +{ + // default to IEEE quad precision + // if your platform does not support this, feel free to remove it. + switches = ["--real-precision=quad"] +}; + "^wasm(32|64)-": { switches = [ From 96c455c4445c84b735e37224d89357379e521edc Mon Sep 17 00:00:00 2001 From: liushuyu Date: Tue, 4 Feb 2025 16:40:46 -0700 Subject: [PATCH 15/15] tests/driver/ppc_float_abi.d: add a test to test ppc64 real type ABI switching --- tests/driver/ppc_float_abi.d | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/driver/ppc_float_abi.d diff --git a/tests/driver/ppc_float_abi.d b/tests/driver/ppc_float_abi.d new file mode 100644 index 00000000000..53c4cbf352b --- /dev/null +++ b/tests/driver/ppc_float_abi.d @@ -0,0 +1,19 @@ +// REQUIRES: target_PowerPC + +// RUN: %ldc -c -output-ll -of=%t.ll %s -mtriple=powerpc64le-linux-gnu -real-precision=quad && FileCheck %s --check-prefix=CHECK-GNU-IEEE < %t.ll +// RUN: %ldc -c -output-ll -of=%t.ll %s -mtriple=powerpc64le-linux-gnu -real-precision=platform && FileCheck %s --check-prefix=CHECK-IBM-LDBL < %t.ll +// the following is an invalid configuration: Musl does not support IEEE quad fp on powerpc +// RUN: %ldc -c -output-ll -of=%t.ll %s -mtriple=powerpc64le-linux-musl -real-precision=quad && FileCheck %s --check-prefix=CHECK-MUSL < %t.ll + +// CHECK-GNU-IEEE-LABEL: @_Z13test_functionu9__ieee128 +// CHECK-IBM-LDBL-LABEL: @_Z13test_functiong +// CHECK-MUSL-LABEL: @_Z13test_functione +extern (C++) bool test_function(real arg) { + // CHECK-GNU-IEEE: fcmp ogt fp128 {{.*}}, 0xL00000000000000000000000000000000 + // CHECK-IBM-LDBL: fcmp ogt ppc_fp128 {{.*}}, 0xM00000000000000000000000000000000 + // CHECK-MUSL: fcmp ogt double {{.*}}, 0.000000e+00 + return arg > 0.0; +} + +// CHECK-GNU-IEEE: !{i32 1, !"float-abi", !"ieeequad"} +// CHECK-IBM-LDBL: !{i32 1, !"float-abi", !"doubledouble"}