summaryrefslogtreecommitdiff
path: root/libphobos
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2020-04-07 16:14:30 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2020-04-08 06:28:51 +0200
commitf1a6150ecb7b17f068150e98bc107d730604f5b6 (patch)
tree7c93a55a8e9cc1eef8283b167a18405dd7f2fa35 /libphobos
parent7e5367f34d7b6fbc0dc4e499653cd3564465f45e (diff)
libphobos: Merge upstream phobos fb4f6a713
Improves the versioning of IeeeFlags and FloatingPointControl code and unit-tests, making it clearer which targets can and cannot support it. Reviewed-on: https://github.com/dlang/phobos/pull/7435
Diffstat (limited to 'libphobos')
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/math.d292
3 files changed, 152 insertions, 144 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 54ae72fa54e..18d479d54ff 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-6c45dd3a6523a21887cb9a883eeb3abd40375dc1
+c9c209e2c62ce43a2c08ddd61d647730716b2d0f
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index c7e4878945a..7570cd9b9fd 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-68cc18adbcdbf2a62cb85a5cb2a34236af2ab05a
+fb4f6a713f5b78742f93e072cff6a6c4ecf9323d
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/math.d b/libphobos/src/std/math.d
index dedfa2014ec..5cc3a858e9d 100644
--- a/libphobos/src/std/math.d
+++ b/libphobos/src/std/math.d
@@ -195,6 +195,38 @@ else version (X86)
private alias haveSSE = core.cpuid.sse;
}
+version (D_SoftFloat)
+{
+ // Some soft float implementations may support IEEE floating flags.
+ // The implementation here supports hardware flags only and is so currently
+ // only available for supported targets.
+}
+else version (X86_Any) version = IeeeFlagsSupport;
+else version (PPC_Any) version = IeeeFlagsSupport;
+else version (RISCV_Any) version = IeeeFlagsSupport;
+else version (MIPS_Any) version = IeeeFlagsSupport;
+else version (ARM_Any) version = IeeeFlagsSupport;
+
+// Struct FloatingPointControl is only available if hardware FP units are available.
+version (D_HardFloat)
+{
+ // FloatingPointControl.clearExceptions() depends on version IeeeFlagsSupport
+ version (IeeeFlagsSupport) version = FloatingPointControlSupport;
+}
+
+version (GNU)
+{
+ // The compiler can unexpectedly rearrange floating point operations and
+ // access to the floating point status flags when optimizing. This means
+ // ieeeFlags tests cannot be reliably checked in optimized code.
+ // See https://github.com/ldc-developers/ldc/issues/888
+}
+else
+{
+ version = IeeeFlagsUnittest;
+ version = FloatingPointControlUnittest;
+}
+
version (unittest)
{
import core.stdc.stdio; // : sprintf;
@@ -1817,19 +1849,9 @@ real exp(real x) @trusted pure nothrow @nogc
if (isNaN(x))
return x;
if (x > OF)
- {
- if (__ctfe)
- return real.infinity;
- else
- return real.max * copysign(real.max, real.infinity);
- }
+ return real.infinity;
if (x < UF)
- {
- if (__ctfe)
- return 0.0;
- else
- return real.min_normal * copysign(real.min_normal, 0.0);
- }
+ return 0.0;
// Express: e^^x = e^^g * 2^^n
// = e^^g * e^^(n * LOG2E)
@@ -2102,12 +2124,7 @@ L_largenegative:
// Special cases. Raises an overflow flag, except in the case
// for CTFE, where there are no hardware controls.
if (x > OF)
- {
- if (__ctfe)
- return real.infinity;
- else
- return real.max * copysign(real.max, real.infinity);
- }
+ return real.infinity;
if (x == 0.0)
return x;
if (x < UF)
@@ -2402,19 +2419,9 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
if (isNaN(x))
return x;
if (x > OF)
- {
- if (__ctfe)
- return real.infinity;
- else
- return real.max * copysign(real.max, real.infinity);
- }
+ return real.infinity;
if (x < UF)
- {
- if (__ctfe)
- return 0.0;
- else
- return real.min_normal * copysign(real.min_normal, 0.0);
- }
+ return 0.0;
// Separate into integer and fractional parts.
int n = cast(int) floor(x + 0.5);
@@ -2453,10 +2460,13 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
@system unittest
{
- FloatingPointControl ctrl;
- if (FloatingPointControl.hasExceptionTraps)
- ctrl.disableExceptions(FloatingPointControl.allExceptions);
- ctrl.rounding = FloatingPointControl.roundToNearest;
+ version (FloatingPointControlSupport)
+ {
+ FloatingPointControl ctrl;
+ if (FloatingPointControl.hasExceptionTraps)
+ ctrl.disableExceptions(FloatingPointControl.allExceptions);
+ ctrl.rounding = FloatingPointControl.roundToNearest;
+ }
static if (real.mant_dig == 113)
{
@@ -2519,49 +2529,42 @@ private real exp2Impl(real x) @nogc @trusted pure nothrow
const minEqualDecimalDigits = real.dig - 3;
real x;
- IeeeFlags f;
+ version (IeeeFlagsSupport) IeeeFlags f;
foreach (ref pair; exptestpoints)
{
- resetIeeeFlags();
+ version (IeeeFlagsSupport) resetIeeeFlags();
x = exp(pair[0]);
- f = ieeeFlags;
assert(equalsDigit(x, pair[1], minEqualDecimalDigits));
-
- version (IeeeFlagsSupport)
- {
- // Check the overflow bit
- if (x == real.infinity)
- {
- // don't care about the overflow bit if input was inf
- // (e.g., the LLVM intrinsic doesn't set it on Linux x86_64)
- assert(pair[0] == real.infinity || f.overflow);
- }
- else
- assert(!f.overflow);
- // Check the underflow bit
- assert(f.underflow == (fabs(x) < real.min_normal));
- // Invalid and div by zero shouldn't be affected.
- assert(!f.invalid);
- assert(!f.divByZero);
- }
}
+
// Ideally, exp(0) would not set the inexact flag.
// Unfortunately, fldl2e sets it!
// So it's not realistic to avoid setting it.
assert(exp(0.0L) == 1.0);
// NaN propagation. Doesn't set flags, bcos was already NaN.
- resetIeeeFlags();
- x = exp(real.nan);
- f = ieeeFlags;
- assert(isIdentical(abs(x), real.nan));
- assert(f.flags == 0);
+ version (IeeeFlagsSupport)
+ {
+ resetIeeeFlags();
+ x = exp(real.nan);
+ f = ieeeFlags;
+ assert(isIdentical(abs(x), real.nan));
+ assert(f.flags == 0);
- resetIeeeFlags();
- x = exp(-real.nan);
- f = ieeeFlags;
- assert(isIdentical(abs(x), real.nan));
- assert(f.flags == 0);
+ resetIeeeFlags();
+ x = exp(-real.nan);
+ f = ieeeFlags;
+ assert(isIdentical(abs(x), real.nan));
+ assert(f.flags == 0);
+ }
+ else
+ {
+ x = exp(real.nan);
+ assert(isIdentical(abs(x), real.nan));
+
+ x = exp(-real.nan);
+ assert(isIdentical(abs(x), real.nan));
+ }
x = exp(NaN(0x123));
assert(isIdentical(x, NaN(0x123)));
@@ -4678,6 +4681,10 @@ real remquo(real x, real y, out int n) @trusted nothrow @nogc /// ditto
assert(0, "remquo not implemented");
}
+
+version (IeeeFlagsSupport)
+{
+
/** IEEE exception status flags ('sticky bits')
These flags indicate that an exceptional floating-point condition has occurred.
@@ -4813,13 +4820,14 @@ private:
else
assert(0, "Not yet supported");
}
+
static void resetIeeeFlags() @nogc
{
version (GNU)
{
version (X86_Any)
{
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"fnclex";
}
@@ -4828,12 +4836,12 @@ private:
if (haveSSE)
{
uint mxcsr;
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"stmxcsr %0" : "=m" (mxcsr);
}
mxcsr &= ~EXCEPTIONS_MASK;
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"ldmxcsr %0" : : "m" (mxcsr);
}
@@ -4847,7 +4855,7 @@ private:
{
uint old = FloatingPointControl.getControlState();
old &= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"vmsr FPSCR, %0" : : "r" (old);
}
@@ -4860,7 +4868,7 @@ private:
else
{
uint newValues = 0x0;
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"fsflags %0" : : "r" (newValues);
}
@@ -4872,7 +4880,7 @@ private:
else
version (InlineAsm_X86_Any)
{
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
fnclex;
}
@@ -4935,27 +4943,25 @@ public:
}
///
-version (GNU)
-{
- // ieeeFlags test disabled, see LDC Issue #888.
-}
-else
+version (IeeeFlagsUnittest)
@system unittest
{
static void func() {
int a = 10 * 10;
}
-
- real a=3.5;
+ pragma(inline, false) static void blockopt(ref real x) {}
+ real a = 3.5;
// Set all the flags to zero
resetIeeeFlags();
assert(!ieeeFlags.divByZero);
+ blockopt(a); // avoid constant propagation by the optimizer
// Perform a division by zero.
- a/=0.0L;
+ a /= 0.0L;
assert(a == real.infinity);
assert(ieeeFlags.divByZero);
+ blockopt(a); // avoid constant propagation by the optimizer
// Create a NaN
- a*=0.0L;
+ a *= 0.0L;
assert(ieeeFlags.invalid);
assert(isNaN(a));
@@ -4966,11 +4972,7 @@ else
assert(ieeeFlags == f);
}
-version (GNU)
-{
- // ieeeFlags test disabled, see LDC Issue #888.
-}
-else
+version (IeeeFlagsUnittest)
@system unittest
{
import std.meta : AliasSeq;
@@ -5017,27 +5019,6 @@ else
}
}
-version (X86_Any)
-{
- version = IeeeFlagsSupport;
-}
-else version (PPC_Any)
-{
- version = IeeeFlagsSupport;
-}
-else version (RISCV_Any)
-{
- version = IeeeFlagsSupport;
-}
-else version (MIPS_Any)
-{
- version = IeeeFlagsSupport;
-}
-else version (ARM_Any)
-{
- version = IeeeFlagsSupport;
-}
-
/// Set all of the floating-point status flags to false.
void resetIeeeFlags() @nogc { IeeeFlags.resetIeeeFlags(); }
@@ -5047,6 +5028,12 @@ void resetIeeeFlags() @nogc { IeeeFlags.resetIeeeFlags(); }
return IeeeFlags(IeeeFlags.getIeeeFlags());
}
+} // IeeeFlagsSupport
+
+
+version (FloatingPointControlSupport)
+{
+
/** Control the Floating point hardware
Change the IEEE754 floating-point rounding mode and the floating-point
@@ -5418,7 +5405,10 @@ private:
// Clear all pending exceptions
static void clearExceptions() @nogc
{
- resetIeeeFlags();
+ version (IeeeFlagsSupport)
+ resetIeeeFlags();
+ else
+ static assert(false, "Not implemented for this architecture");
}
// Read from the control register
@@ -5479,7 +5469,7 @@ private:
version (D_InlineAsm_X86)
{
short cont;
- asm nothrow @nogc
+ asm pure nothrow @nogc
{
xor EAX, EAX;
fstcw cont;
@@ -5490,7 +5480,7 @@ private:
version (D_InlineAsm_X86_64)
{
short cont;
- asm nothrow @nogc
+ asm pure nothrow @nogc
{
xor RAX, RAX;
fstcw cont;
@@ -5508,7 +5498,7 @@ private:
{
version (X86_Any)
{
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"fclex; fldcw %0" : : "m" (newState);
}
@@ -5517,7 +5507,7 @@ private:
if (haveSSE)
{
uint mxcsr;
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"stmxcsr %0" : "=m" (mxcsr);
}
@@ -5532,7 +5522,7 @@ private:
mxcsr &= ~(allExceptions << 7); // delete old masks
mxcsr |= (newState & allExceptions) << 7; // write new exception masks
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"ldmxcsr %0" : : "m" (mxcsr);
}
@@ -5540,7 +5530,7 @@ private:
}
else version (AArch64)
{
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"msr FPCR, %0;" : : "r" (newState);
}
@@ -5551,7 +5541,7 @@ private:
return;
else
{
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"vmsr FPSCR, %0" : : "r" (newState);
}
@@ -5563,7 +5553,7 @@ private:
return;
else
{
- asm pure nothrow @nogc
+ asm nothrow @nogc
{
"fscsr %0" : : "r" (newState);
}
@@ -5605,7 +5595,7 @@ private:
}
}
-version (D_HardFloat) @system unittest
+@system unittest
{
void ensureDefaults()
{
@@ -5642,46 +5632,64 @@ version (D_HardFloat) @system unittest
ensureDefaults();
}
-version (D_HardFloat) @system unittest // rounding
+version (FloatingPointControlUnittest)
+@system unittest // rounding
{
import std.meta : AliasSeq;
foreach (T; AliasSeq!(float, double, real))
{
- FloatingPointControl fpctrl;
-
- fpctrl.rounding = FloatingPointControl.roundUp;
- T u = 1;
- u += 0.1;
-
- fpctrl.rounding = FloatingPointControl.roundDown;
- T d = 1;
- d += 0.1;
+ /* Be careful with changing the rounding mode, it interferes
+ * with common subexpressions. Changing rounding modes should
+ * be done with separate functions that are not inlined.
+ */
- fpctrl.rounding = FloatingPointControl.roundToZero;
- T z = 1;
- z += 0.1;
+ {
+ static T addRound(T)(uint rm)
+ {
+ pragma(inline, false) static void blockopt(ref T x) {}
+ pragma(inline, false);
+ FloatingPointControl fpctrl;
+ fpctrl.rounding = rm;
+ T x = 1;
+ blockopt(x); // avoid constant propagation by the optimizer
+ x += 0.1;
+ return x;
+ }
- assert(u > d);
- assert(z == d);
+ T u = addRound!(T)(FloatingPointControl.roundUp);
+ T d = addRound!(T)(FloatingPointControl.roundDown);
+ T z = addRound!(T)(FloatingPointControl.roundToZero);
- fpctrl.rounding = FloatingPointControl.roundUp;
- u = -1;
- u -= 0.1;
+ assert(u > d);
+ assert(z == d);
+ }
- fpctrl.rounding = FloatingPointControl.roundDown;
- d = -1;
- d -= 0.1;
+ {
+ static T subRound(T)(uint rm)
+ {
+ pragma(inline, false) static void blockopt(ref T x) {}
+ pragma(inline, false);
+ FloatingPointControl fpctrl;
+ fpctrl.rounding = rm;
+ T x = -1;
+ blockopt(x); // avoid constant propagation by the optimizer
+ x -= 0.1;
+ return x;
+ }
- fpctrl.rounding = FloatingPointControl.roundToZero;
- z = -1;
- z -= 0.1;
+ T u = subRound!(T)(FloatingPointControl.roundUp);
+ T d = subRound!(T)(FloatingPointControl.roundDown);
+ T z = subRound!(T)(FloatingPointControl.roundToZero);
- assert(u > d);
- assert(z == u);
+ assert(u > d);
+ assert(z == u);
+ }
}
}
+} // FloatingPointControlSupport
+
/*********************************
* Determines if $(D_PARAM x) is NaN.