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: bugzi...@digitalmars.com ReportedBy: clugd...@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); } --