From fa5dbf215f8430a1ab55d12d38408b003ffab0fe Mon Sep 17 00:00:00 2001 From: Martin Date: Sat, 18 Oct 2014 02:37:42 +0200 Subject: [PATCH 1/2] std.math: use most inline x86/x64 assembly only if real is defined as 80-bit x87 --- std/math.d | 55 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/std/math.d b/std/math.d index db657314ae4..0769be44d8b 100644 --- a/std/math.d +++ b/std/math.d @@ -83,8 +83,12 @@ version(LDC) { import ldc.intrinsics; import ldc.llvmasm; - version(X86) version = INLINE_YL2X; - version(X86_64) version = INLINE_YL2X; + + static if (real.sizeof > double.sizeof) + { + version(X86) version = INLINE_YL2X; + version(X86_64) version = INLINE_YL2X; + } } version(DigitalMars) @@ -109,6 +113,15 @@ else version(D_InlineAsm_X86_64) version = InlineAsm_X86_Any; } +// define InlineAsm*_X87 versions if real is defined as 80-bit x87 +static if (real.sizeof > double.sizeof) +{ + version (D_InlineAsm_X86) version = InlineAsm_X86_X87; + version (D_InlineAsm_X86_64) version = InlineAsm_X86_64_X87; + version (InlineAsm_X86_Any) version = InlineAsm_X86_Any_X87; + version (Win64_DMD_InlineAsm) version = Win64_DMD_InlineAsm_X87; +} + version(unittest) { @@ -633,7 +646,7 @@ real tan(real x) @trusted pure nothrow @nogc { return core.stdc.math.tanl(x); } - else version(D_InlineAsm_X86) + else version(InlineAsm_X86_X87) { asm { @@ -667,7 +680,7 @@ trigerr: Lret: {} } - else version(D_InlineAsm_X86_64) + else version(InlineAsm_X86_64_X87) { version (Win64) { @@ -907,7 +920,7 @@ unittest */ real atan(real x) @safe pure nothrow @nogc { - version(InlineAsm_X86_Any) + version(InlineAsm_X86_Any_X87) { return atan2(x, 1.0L); } @@ -1006,7 +1019,7 @@ unittest */ real atan2(real y, real x) @trusted pure nothrow @nogc { - version(InlineAsm_X86_Any) + version(InlineAsm_X86_Any_X87) { version (Win64) { @@ -1468,14 +1481,14 @@ creal sqrt(creal z) @nogc @safe pure nothrow */ real exp(real x) @trusted pure nothrow @nogc { - version(D_InlineAsm_X86) + version(InlineAsm_X86_X87) { // e^^x = 2^^(LOG2E*x) // (This is valid because the overflow & underflow limits for exp // and exp2 are so similar). return exp2(LOG2E*x); } - else version(D_InlineAsm_X86_64) + else version(InlineAsm_X86_64_X87) { // e^^x = 2^^(LOG2E*x) // (This is valid because the overflow & underflow limits for exp @@ -1562,7 +1575,7 @@ unittest */ real expm1(real x) @trusted pure nothrow @nogc { - version(D_InlineAsm_X86) + version(InlineAsm_X86_X87) { enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 asm @@ -1634,7 +1647,7 @@ L_largenegative: ret PARAMSIZE; } } - else version(D_InlineAsm_X86_64) + else version(InlineAsm_X86_64_X87) { asm { @@ -1793,7 +1806,7 @@ L_largenegative: */ real exp2(real x) @nogc @trusted pure nothrow { - version(D_InlineAsm_X86) + version(InlineAsm_X86_X87) { enum PARAMSIZE = (real.sizeof+3)&(0xFFFF_FFFC); // always a multiple of 4 @@ -1879,7 +1892,7 @@ L_was_nan: ret PARAMSIZE; } } - else version(D_InlineAsm_X86_64) + else version(InlineAsm_X86_64_X87) { asm { @@ -2117,7 +2130,7 @@ creal expi(real y) @trusted pure nothrow @nogc // LDC_FIXME: Temporarily disabled because of precision-related issues // in the unittest below. version (none) { - version(InlineAsm_X86_Any) + version(InlineAsm_X86_Any_X87) { version (Win64) { @@ -2390,7 +2403,7 @@ unittest */ int ilogb(real x) @trusted nothrow @nogc { - version (Win64_DMD_InlineAsm) + version (Win64_DMD_InlineAsm_X87) { asm { @@ -2954,7 +2967,7 @@ unittest */ real logb(real x) @trusted nothrow @nogc { - version (Win64_DMD_InlineAsm) + version (Win64_DMD_InlineAsm_X87) { asm { @@ -3030,7 +3043,7 @@ real modf(real x, ref real i) @trusted nothrow @nogc real scalbn(real x, int n) @trusted nothrow @nogc { // FIXME: LDC fild not really supported - /*version(InlineAsm_X86_Any) { + /*version(InlineAsm_X86_Any_X87) { // scalbnl is not supported on DMD-Windows, so use asm. version (Win64) { @@ -3103,7 +3116,7 @@ version(LDC) { real fabs(real x) @trusted pure nothrow @nogc { - version(D_InlineAsm_X86) + version(InlineAsm_X86_X87) { asm { fld x; @@ -3235,7 +3248,7 @@ unittest */ real ceil(real x) @trusted pure nothrow @nogc { - version (Win64_DMD_InlineAsm) + version (Win64_DMD_InlineAsm_X87) { asm { @@ -3344,7 +3357,7 @@ unittest */ real floor(real x) @trusted pure nothrow @nogc { - version (Win64_DMD_InlineAsm) + version (Win64_DMD_InlineAsm_X87) { asm { @@ -3509,7 +3522,7 @@ real rint(real x) @safe pure nothrow @nogc; /* intrinsic */ long lrint(real x) @trusted pure nothrow @nogc { // FIXME: LDC fistp not really supported - /*version(InlineAsm_X86_Any) + /*version(InlineAsm_X86_Any_X87) { version (Win64) { @@ -3705,7 +3718,7 @@ version(Posix) */ real trunc(real x) @trusted nothrow @nogc { - version (Win64_DMD_InlineAsm) + version (Win64_DMD_InlineAsm_X87) { asm { From 4953b02efa760bf054f42758e47a776b4259b580 Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 19 Oct 2014 01:52:12 +0200 Subject: [PATCH 2/2] std.math: use more LLVM intrinsics if available --- std/math.d | 204 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 157 insertions(+), 47 deletions(-) diff --git a/std/math.d b/std/math.d index 0769be44d8b..3b3199b03b0 100644 --- a/std/math.d +++ b/std/math.d @@ -89,6 +89,26 @@ version(LDC) version(X86) version = INLINE_YL2X; version(X86_64) version = INLINE_YL2X; } + + version(LDC_LLVM_303) + { + version = INTRINSICS_FROM_303; + } + version(LDC_LLVM_304) + { + version = INTRINSICS_FROM_303; + version = INTRINSICS_FROM_304; + } + version(LDC_LLVM_305) + { + version = INTRINSICS_FROM_303; + version = INTRINSICS_FROM_304; + } + version(LDC_LLVM_306) + { + version = INTRINSICS_FROM_303; + version = INTRINSICS_FROM_304; + } } version(DigitalMars) @@ -534,12 +554,7 @@ unittest version(LDC) { - -real cos(real x) @safe pure nothrow @nogc -{ - return llvm_cos(x); -} - + real cos(real x) @safe pure nothrow @nogc { return llvm_cos(x); } } else { @@ -562,12 +577,7 @@ real cos(real x) @safe pure nothrow @nogc; /* intrinsic */ */ version(LDC) { - -real sin(real x) @safe pure nothrow @nogc -{ - return llvm_sin(x); -} - + real sin(real x) @safe pure nothrow @nogc { return llvm_sin(x); } } else { @@ -1395,17 +1405,11 @@ extern (C) real rndtonl(real x); * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no)) * ) */ - version(LDC) { - -@safe pure nothrow @nogc -{ - float sqrt(float x) { return llvm_sqrt(x); } - double sqrt(double x) { return llvm_sqrt(x); } - real sqrt(real x) { return llvm_sqrt(x); } -} - + real sqrt(real x) @safe pure nothrow @nogc { return llvm_sqrt(x); } + double sqrt(double x) @safe pure nothrow @nogc { return llvm_sqrt(x); } + float sqrt(float x) @safe pure nothrow @nogc { return llvm_sqrt(x); } } else { @@ -1479,6 +1483,15 @@ creal sqrt(creal z) @nogc @safe pure nothrow * $(TR $(TD $(NAN)) $(TD $(NAN)) ) * ) */ +version(LDC) +{ + real exp(real x) @safe pure nothrow @nogc { return llvm_exp(x); } + double exp(double x) @safe pure nothrow @nogc { return llvm_exp(x); } + float exp(float x) @safe pure nothrow @nogc { return llvm_exp(x); } +} +else +{ + real exp(real x) @trusted pure nothrow @nogc { version(InlineAsm_X86_X87) @@ -1553,6 +1566,8 @@ double exp(double x) @safe pure nothrow @nogc { return exp(cast(real)x); } /// ditto float exp(float x) @safe pure nothrow @nogc { return exp(cast(real)x); } +} + unittest { assert(equalsDigit(exp(3.0L), E * E * E, useDigits)); @@ -1804,6 +1819,13 @@ L_largenegative: * $(TR $(TD $(NAN)) $(TD $(NAN)) ) * ) */ +version(INTRINSICS_FROM_303) +{ + real exp2(real x) @safe pure nothrow @nogc { return llvm_exp2(x); } +} +else +{ + real exp2(real x) @nogc @trusted pure nothrow { version(InlineAsm_X86_X87) @@ -2038,6 +2060,8 @@ L_was_nan: } } +} + unittest { assert(feqrel(exp2(0.5L), SQRT2) >= real.mant_dig -1); @@ -2541,6 +2565,12 @@ unittest * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ +version(LDC) +{ + real log(real x) @safe pure nothrow @nogc { return llvm_log(x); } +} +else +{ real log(real x) @safe pure nothrow @nogc { @@ -2653,6 +2683,8 @@ real log(real x) @safe pure nothrow @nogc } } +} + unittest { assert(log(E) == 1); @@ -2668,6 +2700,12 @@ unittest * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no)) * ) */ +version(INTRINSICS_FROM_303) +{ + real log10(real x) @safe pure nothrow @nogc { return llvm_log10(x); } +} +else +{ real log10(real x) @safe pure nothrow @nogc { @@ -2784,6 +2822,8 @@ real log10(real x) @safe pure nothrow @nogc } } +} + unittest { //printf("%Lg\n", log10(1000) - 3); @@ -2840,6 +2880,13 @@ real log1p(real x) @safe pure nothrow @nogc * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD no) $(TD no) ) * ) */ +version(INTRINSICS_FROM_303) +{ + real log2(real x) @safe pure nothrow @nogc { return llvm_log2(x); } +} +else +{ + real log2(real x) @safe pure nothrow @nogc { version (INLINE_YL2X) @@ -2946,6 +2993,8 @@ real log2(real x) @safe pure nothrow @nogc } } +} + unittest { assert(equalsDigit(log2(1024), 10, 19)); @@ -3111,23 +3160,9 @@ real cbrt(real x) @trusted nothrow @nogc * $(TR $(TD $(PLUSMN)$(INFIN)) $(TD +$(INFIN)) ) * ) */ - version(LDC) { - real fabs(real x) @trusted pure nothrow @nogc - { - version(InlineAsm_X86_X87) - { - asm { - fld x; - fabs; - } - } - else - { - return fabsl(x); - } - } + real fabs(real x) @safe pure nothrow @nogc { return llvm_fabs(x); } } else { @@ -3246,6 +3281,15 @@ unittest * Returns the value of x rounded upward to the next integer * (toward positive infinity). */ +version(INTRINSICS_FROM_303) +{ + real ceil(real x) @safe pure nothrow @nogc { return llvm_ceil(x); } + double ceil(double x) @safe pure nothrow @nogc { return llvm_ceil(x); } + float ceil(float x) @safe pure nothrow @nogc { return llvm_ceil(x); } +} +else +{ + real ceil(real x) @trusted pure nothrow @nogc { version (Win64_DMD_InlineAsm_X87) @@ -3351,10 +3395,21 @@ unittest assert(isNaN(ceil(float.init))); } +} + /************************************** * Returns the value of x rounded downward to the next integer * (toward negative infinity). */ +version(LDC) +{ + real floor(real x) @safe pure nothrow @nogc { return llvm_floor(x); } + double floor(double x) @safe pure nothrow @nogc { return llvm_floor(x); } + float floor(float x) @safe pure nothrow @nogc { return llvm_floor(x); } +} +else +{ + real floor(real x) @trusted pure nothrow @nogc { version (Win64_DMD_InlineAsm_X87) @@ -3448,6 +3503,8 @@ unittest assert(isNaN(floor(float.init))); } +} + /****************************************** * Rounds x to the nearest integer value, using the current rounding * mode. @@ -3455,6 +3512,13 @@ unittest * Unlike the rint functions, nearbyint does not raise the * FE_INEXACT exception. */ +version(INTRINSICS_FROM_303) +{ + real nearbyint(real x) @safe nothrow @nogc { return llvm_nearbyint(x); } +} +else +{ + real nearbyint(real x) @trusted nothrow @nogc { version (Win64) @@ -3465,6 +3529,8 @@ real nearbyint(real x) @trusted nothrow @nogc return core.stdc.math.nearbyintl(x); } +} + /********************************** * Rounds x to the nearest integer value, using the current rounding * mode. @@ -3475,20 +3541,13 @@ real nearbyint(real x) @trusted nothrow @nogc */ version(LDC) { - version(LDC_LLVM_303) version = HAS_INTRINSIC_RINT; - version(LDC_LLVM_304) version = HAS_INTRINSIC_RINT; - version(LDC_LLVM_305) version = HAS_INTRINSIC_RINT; - version(LDC_LLVM_306) version = HAS_INTRINSIC_RINT; - - version(HAS_INTRINSIC_RINT) + version(INTRINSICS_FROM_303) { - @safe pure nothrow @nogc real rint(real x) - { - return llvm_rint(x); - } + real rint(real x) @safe pure nothrow @nogc { return llvm_rint(x); } } else { + // BUG: assumes x86/x64 architecture pure nothrow @nogc real rint(real x) { asm @@ -3500,7 +3559,6 @@ version(LDC) return x; } } - } else { @@ -3673,6 +3731,13 @@ unittest * If the fractional part of x is exactly 0.5, the return value is rounded to * the even integer. */ +version(INTRINSICS_FROM_304) +{ + real round(real x) @safe nothrow @nogc { return llvm_round(x); } +} +else +{ + real round(real x) @trusted nothrow @nogc { version (Win64) @@ -3687,6 +3752,8 @@ real round(real x) @trusted nothrow @nogc return core.stdc.math.roundl(x); } +} + /********************************************** * Return the value of x rounded to the nearest integer. * @@ -3716,6 +3783,13 @@ version(Posix) * * This is also known as "chop" rounding. */ +version(INTRINSICS_FROM_303) +{ + real trunc(real x) @safe pure nothrow @nogc { return llvm_trunc(x); } +} +else +{ + real trunc(real x) @trusted nothrow @nogc { version (Win64_DMD_InlineAsm_X87) @@ -3741,6 +3815,8 @@ real trunc(real x) @trusted nothrow @nogc return core.stdc.math.truncl(x); } +} + /**************************************************** * Calculate the remainder x REM y, following IEC 60559. * @@ -4967,6 +5043,16 @@ int signbit(X)(X x) @nogc @trusted pure nothrow /********************************* * Return a value composed of to with from's sign bit. */ +version(INTRINSICS_FROM_304) +{ + R copysign(R, X)(R to, X from) @safe pure nothrow @nogc + if (isFloatingPoint!(R) && isFloatingPoint!(X)) + { + return llvm_copysign(to, cast(R) from); + } +} +else +{ R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc if (isFloatingPoint!(R) && isFloatingPoint!(X)) @@ -4981,6 +5067,8 @@ R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc return to; } +} + // ditto R copysign(R, X)(X to, R from) @trusted pure nothrow @nogc if (isIntegral!(X) && isFloatingPoint!(R)) @@ -5560,8 +5648,17 @@ real fmin(real x, real y) @safe pure nothrow @nogc { return x < y ? x : y; } * * BUGS: Not currently implemented - rounds twice. */ +version(LDC) +{ + real fma(real x, real y, real z) @safe pure nothrow @nogc { return llvm_fma(x, y, z); } +} +else +{ + real fma(real x, real y, real z) @safe pure nothrow @nogc { return (x * y) + z; } +} + /******************************************************************* * Compute the value of x $(SUP n), where n is an integer */ @@ -5775,6 +5872,17 @@ real pow(I, F)(I x, F y) @nogc @trusted pure nothrow * $(TD no) $(TD no) ) * ) */ +version(LDC) +{ + Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @safe pure nothrow @nogc + if (isFloatingPoint!(F) && isFloatingPoint!(G)) + { + alias Float = typeof(return); + return llvm_pow!(Float)(x, y); + } +} +else +{ Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow if (isFloatingPoint!(F) && isFloatingPoint!(G)) @@ -5959,6 +6067,8 @@ Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow return impl(x, y); } +} + unittest { // Test all the special values. These unittests can be run on Windows