www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 2746] New: Make float.init signalling NaN by default

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2746

           Summary: Make float.init signalling NaN by default
           Product: D
           Version: 2.025
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Keywords: patch
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: clugdbug yahoo.com.au


The patch below changes the init values for 
float, double, real, ifloat, idouble, ireal, cfloat, cdouble, and creal
from a quiet NaN into a signalling NaN.
Thus, use of uninitialized variables can be detected simply by enabling the
"invalid" floating-point exception.

------
It involves adding one short function (isSignallingNaN), and modifying 3
others.

(Note: compared to the version I posted on the newgroup, this uses a payload
which is different to the machine NaN, so that uninitialised variables can be
detected even if exceptions are disabled).

=================================
mtype.c line 2150
=================================

Expression *TypeBasic::defaultInit(Loc loc)
{   integer_t value = 0;
#if __DMC__
        // Note: could be up to 16 bytes long.
        unsigned short snan[8] = { 0, 0, 0, 0xA000, 0x7FFF, 0 };
        d_float80 fvalue = *(long double*)snan;
#endif

#if LOGDEFAULTINIT
    printf("TypeBasic::defaultInit() '%s'\n", toChars());
#endif
    switch (ty)
    {
        case Tchar:
            value = 0xFF;
            break;

        case Twchar:
        case Tdchar:
            value = 0xFFFF;
            break;

        case Timaginary32:
        case Timaginary64:
        case Timaginary80:
        case Tfloat32:
        case Tfloat64:
        case Tfloat80:
#if __DMC__
                return new RealExp(loc, fvalue, this);
#else 
            return getProperty(loc, Id::nan);
#endif

        case Tcomplex32:
        case Tcomplex64:
        case Tcomplex80:
#if __DMC__
                {   // Can't use fvalue + I*fvalue (the im part becomes a quiet
NaN).
                        complex_t cvalue;
                        ((real_t *)&cvalue)[0] = fvalue;
                        ((real_t *)&cvalue)[1] = fvalue;
                        return new ComplexExp(loc, cvalue, this);
                }
#else
            return getProperty(loc, Id::nan);
#endif

        case Tvoid:
            error(loc, "void does not have a default initializer");
    }
    return new IntegerExp(loc, value, this);
}

=================================
e2ir.c line 1182.
=================================

bool isSignallingNaN(real_t x)
{
#if __DMC__
        if (x>=0 || x<0) return false;
        return !((((unsigned short*)&x)[3])&0x4000);
#else
        return false;
#endif
}


elem *RealExp::toElem(IRState *irs)
{   union eve c;
    tym_t ty;

    //printf("RealExp::toElem(%p)\n", this);
    memset(&c, 0, sizeof(c));
    ty = type->toBasetype()->totym();
    switch (tybasic(ty))
    {
        case TYfloat:
        case TYifloat:
            c.Vfloat = value;
                if (isSignallingNaN(value) ) {
                        ((unsigned int*)&c.Vfloat)[0] &= 0xFFBFFFFFL;
                }
            break;

        case TYdouble:
        case TYidouble:
                c.Vdouble = value; // this unfortunately converts SNAN to QNAN.
                if ( isSignallingNaN(value) ) {
                        ((unsigned int*)&c.Vdouble)[1] &= 0xFFF7FFFFL;
                }
            break;

        case TYldouble:
        case TYildouble:
            c.Vldouble = value;
            break;

        default:
            print();
            type->print();
            type->toBasetype()->print();
            printf("ty = %d, tym = %x\n", type->ty, ty);
            assert(0);
    }
    return el_const(ty, &c);
}

elem *ComplexExp::toElem(IRState *irs)
{   union eve c;
    tym_t ty;
    real_t re;
    real_t im;

    re = creall(value);
    im = cimagl(value);

    memset(&c, 0, sizeof(c));
    ty = type->totym();
    switch (tybasic(ty))
    {
        case TYcfloat:
            c.Vcfloat.re = (float) re;
            c.Vcfloat.im = (float) im;
                if ( isSignallingNaN(re) && isSignallingNaN(im)) {
                        ((unsigned int*)&c.Vcfloat.re)[0] &= 0xFFBFFFFFL;
                        ((unsigned int*)&c.Vcfloat.im)[0] &= 0xFFBFFFFFL;
                }
            break;

        case TYcdouble:
            c.Vcdouble.re = (double) re;
            c.Vcdouble.im = (double) im;
                if ( isSignallingNaN(re) && isSignallingNaN(im)) {
                        ((unsigned int*)&c.Vcdouble.re)[1] &= 0xFFF7FFFFL;
                        ((unsigned int*)&c.Vcdouble.im)[1] &= 0xFFF7FFFFL;
                }
            break;

        case TYcldouble:
            c.Vcldouble.re = re;
            c.Vcldouble.im = im;
            break;

        default:
            assert(0);
    }
    return el_const(ty, &c);
}


-- 
Mar 19 2009
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2746





------- Comment #1 from bugzilla digitalmars.com  2009-03-20 01:29 -------
I'll put it in, but there's a problem if the compiler does any constant folding
on the values - they'll get converted to quiet NaNs.


-- 
Mar 19 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2746





------- Comment #2 from clugdbug yahoo.com.au  2009-03-20 09:14 -------
(In reply to comment #1)
 I'll put it in, but there's a problem if the compiler does any constant folding
 on the values - they'll get converted to quiet NaNs.

I know. I don't think it's too unreasonable: once you've done a calculation on it, it's no longer uninitialized. The only way it could get constant-folded is if you've explicitly entered 'real.init'. So you'd have to be doing something peculiar. (Negation still preserves signallingness, through the ancient code in DMD; and there, you're just setting the sign bit). Since it only SNANs automatically get converted to QNANs when no traps are enabled, and since no-one expects traps to be enabled at compile time, it's quite defensible, I think. --
Mar 20 2009
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2746


bugzilla digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |FIXED




------- Comment #3 from bugzilla digitalmars.com  2009-04-01 13:56 -------
Fixed DMD 2.027


-- 
Apr 01 2009