Bug 2746 – Make float.init signalling NaN by default

Status
RESOLVED
Resolution
FIXED
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
x86
OS
Windows
Creation time
2009-03-19T07:01:00Z
Last change time
2015-06-09T01:21:08Z
Keywords
patch
Assigned to
bugzilla
Creator
clugdbug

Comments

Comment #0 by clugdbug — 2009-03-19T07:01:03Z
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); }
Comment #1 by bugzilla — 2009-03-20T01:29:25Z
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.
Comment #2 by clugdbug — 2009-03-20T09:14:17Z
(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.
Comment #3 by bugzilla — 2009-04-01T13:56:37Z
Fixed DMD 2.027