// Written in the D programming language. /**This is a submodule of $(MREF std, math). It contains hardware support for floating point numbers. Copyright: Copyright The D Language Foundation 2000 - 2011.License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, Conversion of CEPHES math library to D by Iain Buclaw and David NadlingerSource: $(PHOBOSSRC std/math/hardware.d) */ /* NOTE: This file has been patched from the original DMD distribution to * work with the GDC compiler. */module std.math.hardware; static import core.stdc.fenv; version (X86) version = X86_Any;version (X86_64) version = X86_Any;version (PPC) version = PPC_Any;version (PPC64) version = PPC_Any;version (MIPS32) version = MIPS_Any;version (MIPS64) version = MIPS_Any;version (AArch64) version = ARM_Any;version (ARM) version = ARM_Any;version (S390) version = IBMZ_Any;version (SPARC) version = SPARC_Any;version (SPARC64) version = SPARC_Any;version (SystemZ) version = IBMZ_Any;version (RISCV32) version = RISCV_Any;version (RISCV64) version = RISCV_Any;version (LoongArch64) version = LoongArch_Any; version (D_InlineAsm_X86) version = InlineAsm_X86_Any;version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; version (X86_64) version = StaticallyHaveSSE;version (X86) version (OSX) version = StaticallyHaveSSE; version (StaticallyHaveSSE){ private enum bool haveSSE = true;}else version (X86){ static import core.cpuid; 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 (LoongArch_Any) version = IeeeFlagsSupport;else version (ARM_Any) version = IeeeFlagsSupport;else version (SPARC_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 (IeeeFlagsSupport){ /** IEEE exception status flags ('sticky bits') These flags indicate that an exceptional floating-point condition has occurred. They indicate that a NaN or an infinity has been generated, that a result is inexact, or that a signalling NaN has been encountered. If floating-point exceptions are enabled (unmasked), a hardware exception will be generated instead of setting these flags. */struct IeeeFlags{nothrow @nogc: private: // The x87 FPU status register is 16 bits. // The Pentium SSE2 status register is 32 bits. // The ARM and PowerPC FPSCR is a 32-bit register. // The SPARC FSR is a 32-bit register (64 bits for SPARC V9, but high bits are uninteresting). // The RISC-V (32 & 64 bit) fcsr is 32-bit register. // THe LoongArch fcsr (fcsr0) is a 32-bit register. uint flags; version (CRuntime_Microsoft) { // Microsoft uses hardware-incompatible custom constants in fenv.h (core.stdc.fenv). // Applies to both x87 status word (16 bits) and SSE2 status word(32 bits). enum : int { INEXACT_MASK = 0x20, UNDERFLOW_MASK = 0x10, OVERFLOW_MASK = 0x08, DIVBYZERO_MASK = 0x04, INVALID_MASK = 0x01, EXCEPTIONS_MASK = 0b11_1111 } // Don't bother about subnormals, they are not supported on most CPUs. // SUBNORMAL_MASK = 0x02; } else version (Solaris) { // Solaris <fenv.h> uses hardware-incompatible floating-point status flags. // Use the <sys/fsr.h> AEXC (Accrued EXCeption) bit field of fsr instead. version (SPARC_Any) { enum : int { INEXACT_MASK = 0x020, UNDERFLOW_MASK = 0x080, OVERFLOW_MASK = 0x100, DIVBYZERO_MASK = 0x040, INVALID_MASK = 0x200, EXCEPTIONS_MASK = 0x3E0, } } // Use the <sys/fp.h> masks for 80387 control word or SSE/SSE2 MXCSR instead. else version (X86_Any) { enum : int { INEXACT_MASK = 0x20, UNDERFLOW_MASK = 0x10, OVERFLOW_MASK = 0x08, DIVBYZERO_MASK = 0x04, INVALID_MASK = 0x01, EXCEPTIONS_MASK = 0x3D, } } } else { enum : int { INEXACT_MASK = core.stdc.fenv.FE_INEXACT, UNDERFLOW_MASK = core.stdc.fenv.FE_UNDERFLOW, OVERFLOW_MASK = core.stdc.fenv.FE_OVERFLOW, DIVBYZERO_MASK = core.stdc.fenv.FE_DIVBYZERO, INVALID_MASK = core.stdc.fenv.FE_INVALID, EXCEPTIONS_MASK = core.stdc.fenv.FE_ALL_EXCEPT, } } static uint getIeeeFlags() @trusted pure { version (GNU) { version (X86_Any) { ushort sw; asm pure nothrow @nogc { "fstsw %0" : "=a" (sw); } // OR the result with the SSE2 status register (MXCSR). if (haveSSE) { uint mxcsr; asm pure nothrow @nogc { "stmxcsr %0" : "=m" (mxcsr); } return (sw | mxcsr) & EXCEPTIONS_MASK; } else return sw & EXCEPTIONS_MASK; } else version (ARM) { version (ARM_SoftFloat) return 0; else { uint result = void; asm pure nothrow @nogc { "vmrs %0, FPSCR; and %0, %0, #0x1F;" : "=r" (result); } return result; } } else version (RISCV_Any) { version (D_SoftFloat) return 0; else { uint result = void; asm pure nothrow @nogc { "frflags %0" : "=r" (result); } return result; } } else version (SPARC_Any) { version (D_SoftFloat) return 0; else { uint result = void; asm pure nothrow @nogc { "st %%fsr, %0" : "=m" (result); } return result & EXCEPTIONS_MASK; } } else assert(0, "Not yet supported"); } else version (InlineAsm_X86_Any) { ushort sw; asm pure nothrow @nogc { fstsw sw; } // OR the result with the SSE2 status register (MXCSR). if (haveSSE) { uint mxcsr; asm pure nothrow @nogc { stmxcsr mxcsr; } return (sw | mxcsr) & EXCEPTIONS_MASK; } else return sw & EXCEPTIONS_MASK; } else version (SPARC) { /* int retval; asm pure nothrow @nogc { st %fsr, retval; } return retval; */ assert(0, "Not yet supported"); } else version (ARM) { assert(false, "Not yet supported."); } else version (RISCV_Any) { uint result = void; asm pure nothrow @nogc { "frflags %0" : "=r" (result); } return result; } else version (LoongArch_Any) { uint result = void; asm pure nothrow @nogc { "movfcsr2gr %0, $fcsr2" : "=r" (result); } return result & EXCEPTIONS_MASK; } else assert(0, "Not yet supported"); } static void resetIeeeFlags() @trusted { version (GNU) { version (X86_Any) { asm nothrow @nogc { "fnclex"; } // Also clear exception flags in MXCSR, SSE's control register. if (haveSSE) { uint mxcsr; asm nothrow @nogc { "stmxcsr %0" : "=m" (mxcsr); } mxcsr &= ~EXCEPTIONS_MASK; asm nothrow @nogc { "ldmxcsr %0" : : "m" (mxcsr); } } } else version (ARM) { version (ARM_SoftFloat) return; else { uint old = FloatingPointControl.getControlState(); old &= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html asm nothrow @nogc { "vmsr FPSCR, %0" : : "r" (old); } } } else version (RISCV_Any) { version (D_SoftFloat) return; else { uint newValues = 0x0; asm nothrow @nogc { "fsflags %0" : : "r" (newValues); } } } else version (SPARC_Any) { version (D_SoftFloat) return; else { uint fsr; asm pure nothrow @nogc { "st %%fsr, %0" : "=m" (fsr); } fsr &= ~EXCEPTIONS_MASK; asm pure nothrow @nogc { "ld %0, %%fsr" : : "m" (fsr); } } } else assert(0, "Not yet supported"); } else version (InlineAsm_X86_Any) { asm nothrow @nogc { fnclex; } // Also clear exception flags in MXCSR, SSE's control register. if (haveSSE) { uint mxcsr; asm nothrow @nogc { stmxcsr mxcsr; } mxcsr &= ~EXCEPTIONS_MASK; asm nothrow @nogc { ldmxcsr mxcsr; } } } else version (RISCV_Any) { uint newValues = 0x0; asm pure nothrow @nogc { "fsflags %0" : : "r" (newValues); } } else version (LoongArch_Any) { asm nothrow @nogc { "movgr2fcsr $fcsr2,$r0"; } } else { /* SPARC: int tmpval; asm pure nothrow @nogc { st %fsr, tmpval; } tmpval &=0xFFFF_FC00; asm pure nothrow @nogc { ld tmpval, %fsr; } */ assert(0, "Not yet supported"); } } public: /** * The result cannot be represented exactly, so rounding occurred. * Example: `x = sin(0.1);` */ @property bool inexact() @safe const { return (flags & INEXACT_MASK) != 0; } /** * A zero was generated by underflow * Example: `x = real.min*real.epsilon/2;` */ @property bool underflow() @safe const { return (flags & UNDERFLOW_MASK) != 0; } /** * An infinity was generated by overflow * Example: `x = real.max*2;` */ @property bool overflow() @safe const { return (flags & OVERFLOW_MASK) != 0; } /** * An infinity was generated by division by zero * Example: `x = 3/0.0;` */ @property bool divByZero() @safe const { return (flags & DIVBYZERO_MASK) != 0; } /** * A machine NaN was generated. * Example: `x = real.infinity * 0.0;` */ @property bool invalid() @safe const { return (flags & INVALID_MASK) != 0; }} ///version (StdDdoc)@safe unittest{ import std.math.traits : isNaN; static void func() { int a = 10 * 10; } real a = 3.5; // Set all the flags to zero resetIeeeFlags(); assert(!ieeeFlags.divByZero); // Perform a division by zero. a /= 0.0L; assert(a == real.infinity); assert(ieeeFlags.divByZero); // Create a NaN a *= 0.0L; assert(ieeeFlags.invalid); assert(isNaN(a)); // Check that calling func() has no effect on the // status flags. IeeeFlags f = ieeeFlags; func(); assert(ieeeFlags == f);} @safe unittest{ import std.math.traits : isNaN; static void func() { int a = 10 * 10; } real a = 3.5; // Set all the flags to zero resetIeeeFlags(); assert(!ieeeFlags.divByZero); // Perform a division by zero. a = forceDivOp(a, 0.0L); assert(a == real.infinity); assert(ieeeFlags.divByZero); // Create a NaN a = forceMulOp(a, 0.0L); assert(ieeeFlags.invalid); assert(isNaN(a)); // Check that calling func() has no effect on the // status flags. IeeeFlags f = ieeeFlags; func(); assert(ieeeFlags == f);} @safe unittest{ import std.meta : AliasSeq; static struct Test { void delegate() @trusted action; bool function() @trusted ieeeCheck; } static foreach (T; AliasSeq!(float, double, real)) {{ T x; // Needs to be here to avoid `call without side effects` warning. auto tests = [ Test( () { x = forceAddOp!T(1, 0.1L); }, () => ieeeFlags.inexactLines 1–500 of 1429. Load more
// Written in the D programming language. /** This is a submodule of $(MREF std, math). It contains hardware support for floating point numbers. Copyright: Copyright The D Language Foundation 2000 - 2011. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, Conversion of CEPHES math library to D by Iain Buclaw and David Nadlinger Source: $(PHOBOSSRC std/math/hardware.d) */ /* NOTE: This file has been patched from the original DMD distribution to * work with the GDC compiler. */ module std.math.hardware; static import core.stdc.fenv; version (X86) version = X86_Any; version (X86_64) version = X86_Any; version (PPC) version = PPC_Any; version (PPC64) version = PPC_Any; version (MIPS32) version = MIPS_Any; version (MIPS64) version = MIPS_Any; version (AArch64) version = ARM_Any; version (ARM) version = ARM_Any; version (S390) version = IBMZ_Any; version (SPARC) version = SPARC_Any; version (SPARC64) version = SPARC_Any; version (SystemZ) version = IBMZ_Any; version (RISCV32) version = RISCV_Any; version (RISCV64) version = RISCV_Any; version (LoongArch64) version = LoongArch_Any; version (D_InlineAsm_X86) version = InlineAsm_X86_Any; version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any; version (X86_64) version = StaticallyHaveSSE; version (X86) version (OSX) version = StaticallyHaveSSE; version (StaticallyHaveSSE) { private enum bool haveSSE = true; } else version (X86) { static import core.cpuid; 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 (LoongArch_Any) version = IeeeFlagsSupport; else version (ARM_Any) version = IeeeFlagsSupport; else version (SPARC_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 (IeeeFlagsSupport) { /** IEEE exception status flags ('sticky bits') These flags indicate that an exceptional floating-point condition has occurred. They indicate that a NaN or an infinity has been generated, that a result is inexact, or that a signalling NaN has been encountered. If floating-point exceptions are enabled (unmasked), a hardware exception will be generated instead of setting these flags. */ struct IeeeFlags { nothrow @nogc: private: // The x87 FPU status register is 16 bits. // The Pentium SSE2 status register is 32 bits. // The ARM and PowerPC FPSCR is a 32-bit register. // The SPARC FSR is a 32-bit register (64 bits for SPARC V9, but high bits are uninteresting). // The RISC-V (32 & 64 bit) fcsr is 32-bit register. // THe LoongArch fcsr (fcsr0) is a 32-bit register. uint flags; version (CRuntime_Microsoft) { // Microsoft uses hardware-incompatible custom constants in fenv.h (core.stdc.fenv). // Applies to both x87 status word (16 bits) and SSE2 status word(32 bits). enum : int { INEXACT_MASK = 0x20, UNDERFLOW_MASK = 0x10, OVERFLOW_MASK = 0x08, DIVBYZERO_MASK = 0x04, INVALID_MASK = 0x01, EXCEPTIONS_MASK = 0b11_1111 } // Don't bother about subnormals, they are not supported on most CPUs. // SUBNORMAL_MASK = 0x02; } else version (Solaris) { // Solaris <fenv.h> uses hardware-incompatible floating-point status flags. // Use the <sys/fsr.h> AEXC (Accrued EXCeption) bit field of fsr instead. version (SPARC_Any) { enum : int { INEXACT_MASK = 0x020, UNDERFLOW_MASK = 0x080, OVERFLOW_MASK = 0x100, DIVBYZERO_MASK = 0x040, INVALID_MASK = 0x200, EXCEPTIONS_MASK = 0x3E0, } } // Use the <sys/fp.h> masks for 80387 control word or SSE/SSE2 MXCSR instead. else version (X86_Any) { enum : int { INEXACT_MASK = 0x20, UNDERFLOW_MASK = 0x10, OVERFLOW_MASK = 0x08, DIVBYZERO_MASK = 0x04, INVALID_MASK = 0x01, EXCEPTIONS_MASK = 0x3D, } } } else { enum : int { INEXACT_MASK = core.stdc.fenv.FE_INEXACT, UNDERFLOW_MASK = core.stdc.fenv.FE_UNDERFLOW, OVERFLOW_MASK = core.stdc.fenv.FE_OVERFLOW, DIVBYZERO_MASK = core.stdc.fenv.FE_DIVBYZERO, INVALID_MASK = core.stdc.fenv.FE_INVALID, EXCEPTIONS_MASK = core.stdc.fenv.FE_ALL_EXCEPT, } } static uint getIeeeFlags() @trusted pure { version (GNU) { version (X86_Any) { ushort sw; asm pure nothrow @nogc { "fstsw %0" : "=a" (sw); } // OR the result with the SSE2 status register (MXCSR). if (haveSSE) { uint mxcsr; asm pure nothrow @nogc { "stmxcsr %0" : "=m" (mxcsr); } return (sw | mxcsr) & EXCEPTIONS_MASK; } else return sw & EXCEPTIONS_MASK; } else version (ARM) { version (ARM_SoftFloat) return 0; else { uint result = void; asm pure nothrow @nogc { "vmrs %0, FPSCR; and %0, %0, #0x1F;" : "=r" (result); } return result; } } else version (RISCV_Any) { version (D_SoftFloat) return 0; else { uint result = void; asm pure nothrow @nogc { "frflags %0" : "=r" (result); } return result; } } else version (SPARC_Any) { version (D_SoftFloat) return 0; else { uint result = void; asm pure nothrow @nogc { "st %%fsr, %0" : "=m" (result); } return result & EXCEPTIONS_MASK; } } else assert(0, "Not yet supported"); } else version (InlineAsm_X86_Any) { ushort sw; asm pure nothrow @nogc { fstsw sw; } // OR the result with the SSE2 status register (MXCSR). if (haveSSE) { uint mxcsr; asm pure nothrow @nogc { stmxcsr mxcsr; } return (sw | mxcsr) & EXCEPTIONS_MASK; } else return sw & EXCEPTIONS_MASK; } else version (SPARC) { /* int retval; asm pure nothrow @nogc { st %fsr, retval; } return retval; */ assert(0, "Not yet supported"); } else version (ARM) { assert(false, "Not yet supported."); } else version (RISCV_Any) { uint result = void; asm pure nothrow @nogc { "frflags %0" : "=r" (result); } return result; } else version (LoongArch_Any) { uint result = void; asm pure nothrow @nogc { "movfcsr2gr %0, $fcsr2" : "=r" (result); } return result & EXCEPTIONS_MASK; } else assert(0, "Not yet supported"); } static void resetIeeeFlags() @trusted { version (GNU) { version (X86_Any) { asm nothrow @nogc { "fnclex"; } // Also clear exception flags in MXCSR, SSE's control register. if (haveSSE) { uint mxcsr; asm nothrow @nogc { "stmxcsr %0" : "=m" (mxcsr); } mxcsr &= ~EXCEPTIONS_MASK; asm nothrow @nogc { "ldmxcsr %0" : : "m" (mxcsr); } } } else version (ARM) { version (ARM_SoftFloat) return; else { uint old = FloatingPointControl.getControlState(); old &= ~0b11111; // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0408i/Chdfifdc.html asm nothrow @nogc { "vmsr FPSCR, %0" : : "r" (old); } } } else version (RISCV_Any) { version (D_SoftFloat) return; else { uint newValues = 0x0; asm nothrow @nogc { "fsflags %0" : : "r" (newValues); } } } else version (SPARC_Any) { version (D_SoftFloat) return; else { uint fsr; asm pure nothrow @nogc { "st %%fsr, %0" : "=m" (fsr); } fsr &= ~EXCEPTIONS_MASK; asm pure nothrow @nogc { "ld %0, %%fsr" : : "m" (fsr); } } } else assert(0, "Not yet supported"); } else version (InlineAsm_X86_Any) { asm nothrow @nogc { fnclex; } // Also clear exception flags in MXCSR, SSE's control register. if (haveSSE) { uint mxcsr; asm nothrow @nogc { stmxcsr mxcsr; } mxcsr &= ~EXCEPTIONS_MASK; asm nothrow @nogc { ldmxcsr mxcsr; } } } else version (RISCV_Any) { uint newValues = 0x0; asm pure nothrow @nogc { "fsflags %0" : : "r" (newValues); } } else version (LoongArch_Any) { asm nothrow @nogc { "movgr2fcsr $fcsr2,$r0"; } } else { /* SPARC: int tmpval; asm pure nothrow @nogc { st %fsr, tmpval; } tmpval &=0xFFFF_FC00; asm pure nothrow @nogc { ld tmpval, %fsr; } */ assert(0, "Not yet supported"); } } public: /** * The result cannot be represented exactly, so rounding occurred. * Example: `x = sin(0.1);` */ @property bool inexact() @safe const { return (flags & INEXACT_MASK) != 0; } /** * A zero was generated by underflow * Example: `x = real.min*real.epsilon/2;` */ @property bool underflow() @safe const { return (flags & UNDERFLOW_MASK) != 0; } /** * An infinity was generated by overflow * Example: `x = real.max*2;` */ @property bool overflow() @safe const { return (flags & OVERFLOW_MASK) != 0; } /** * An infinity was generated by division by zero * Example: `x = 3/0.0;` */ @property bool divByZero() @safe const { return (flags & DIVBYZERO_MASK) != 0; } /** * A machine NaN was generated. * Example: `x = real.infinity * 0.0;` */ @property bool invalid() @safe const { return (flags & INVALID_MASK) != 0; } } /// version (StdDdoc) @safe unittest { import std.math.traits : isNaN; static void func() { int a = 10 * 10; } real a = 3.5; // Set all the flags to zero resetIeeeFlags(); assert(!ieeeFlags.divByZero); // Perform a division by zero. a /= 0.0L; assert(a == real.infinity); assert(ieeeFlags.divByZero); // Create a NaN a *= 0.0L; assert(ieeeFlags.invalid); assert(isNaN(a)); // Check that calling func() has no effect on the // status flags. IeeeFlags f = ieeeFlags; func(); assert(ieeeFlags == f); } @safe unittest { import std.math.traits : isNaN; static void func() { int a = 10 * 10; } real a = 3.5; // Set all the flags to zero resetIeeeFlags(); assert(!ieeeFlags.divByZero); // Perform a division by zero. a = forceDivOp(a, 0.0L); assert(a == real.infinity); assert(ieeeFlags.divByZero); // Create a NaN a = forceMulOp(a, 0.0L); assert(ieeeFlags.invalid); assert(isNaN(a)); // Check that calling func() has no effect on the // status flags. IeeeFlags f = ieeeFlags; func(); assert(ieeeFlags == f); } @safe unittest { import std.meta : AliasSeq; static struct Test { void delegate() @trusted action; bool function() @trusted ieeeCheck; } static foreach (T; AliasSeq!(float, double, real)) {{ T x; // Needs to be here to avoid `call without side effects` warning. auto tests = [ Test( () { x = forceAddOp!T(1, 0.1L); }, () => ieeeFlags.inexact