Wolfgang Thallergcc16 merge934c3885 months agoHistory
1429 lines · 41.4 KB · D
RawDownload
// 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.inexact

Lines 1–500 of 1429.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t