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) 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/driver/main.cpp b/driver/main.cpp index 5119a864fd5..a23dd2a1462 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -681,8 +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"); + 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/gen/abi/ppc64le.cpp b/gen/abi/ppc64le.cpp index 6a6f7923320..0fe70e591c1 100644 --- a/gen/abi/ppc64le.cpp +++ b/gen/abi/ppc64le.cpp @@ -10,24 +10,84 @@ // The ABI implementation used for 64 bit little-endian PowerPC targets. // // The PowerOpen 64bit ELF v2 ABI can be found here: -// https://members.openpowerfoundation.org/document/dl/576 +// https://files.openpower.foundation/s/cfA2oFPXbbZwEBK/download/64biteflv2abi-v1.5.pdf //===----------------------------------------------------------------------===// +#include + #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" +#include "target.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(target.RealProperties.mant_dig == 113) {} bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); @@ -51,9 +111,11 @@ 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)) { + longDoubleRewrite.applyTo(arg); } } }; diff --git a/gen/modules.cpp b/gen/modules.cpp index dce1b59f6f3..f0bd4f19f90 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 (target.RealProperties.mant_dig == 113) { + 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 diff --git a/gen/target.cpp b/gen/target.cpp index 85bcf9f3740..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) @@ -64,9 +82,20 @@ llvm::Type *getRealType(const llvm::Triple &triple) { case Triple::wasm64: return LLType::getFP128Ty(ctx); + case Triple::ppc64: + case Triple::ppc64le: + 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() && realTypeEncoding == RealTypeEncoding::IEEEQuad + ? 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); } } @@ -99,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(); @@ -156,6 +199,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; @@ -197,6 +241,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 " @@ -240,6 +296,19 @@ 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 (target.RealProperties.mant_dig == 113 && + triple.getEnvironment() == llvm::Triple::GNU) { + return "u9__ieee128"; + } + if (target.RealProperties.mant_dig == 106) { + // IBM long double + return "g"; + } + // fall back to 64-bit double type + return "e"; + } return isAndroidX64 ? "g" : "e"; } return nullptr; 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); } 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 = [ 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; 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. 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; 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"}