www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 2697] New: Cast of float function return to ulong or uint gives bogus value

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

           Summary: Cast of float function return to ulong or uint gives
                    bogus value
           Product: D
           Version: 1.040
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Keywords: wrong-code
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: smjg iname.com


import std.stdio;

float func() { return 5; }

void main() {
    writefln("float:  %f", func());
    writefln("ulong:  %d", cast(ulong)  func());
    writefln("long:   %d", cast(long)   func());
    writefln("uint:   %d", cast(uint)   func());
    writefln("int:    %d", cast(int)    func());
    writefln("ushort: %d", cast(ushort) func());
    writefln("short:  %d", cast(short)  func());
    writefln("ubyte:  %d", cast(ubyte)  func());
    writefln("byte:   %d", cast(byte)   func());

    float result = func();
    writefln("float:  %f", result);
    writefln("ulong:  %d", cast(ulong)  result);
    writefln("long:   %d", cast(long)   result);
    writefln("uint:   %d", cast(uint)   result);
    writefln("int:    %d", cast(int)    result);
    writefln("ushort: %d", cast(ushort) result);
    writefln("short:  %d", cast(short)  result);
    writefln("ubyte:  %d", cast(ubyte)  result);
    writefln("byte:   %d", cast(byte)   result);
}
----------
float:  5.000000
ulong:  2048
long:   5
uint:   0
int:    5
ushort: 5
short:  5
ubyte:  5
byte:   5
float:  5.000000
ulong:  5
long:   5
uint:   5
int:    5
ushort: 5
short:  5
ubyte:  5
byte:   5
----------

If the ulong and long cases are removed, the cast to uint gives 2048.
Seems to be only float that has the problem - it disappears if I change it to
double or real.


-- 
Feb 28 2009
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697





------- Comment #1 from maxmo pochta.ru  2009-03-06 04:39 -------
In D2:

float:  5.000000
ulong:  0
long:   5
uint:   0
int:    5
ushort: 5
short:  5
ubyte:  5
byte:   5
float:  5.000000
ulong:  5
long:   5
uint:   5
int:    5
ushort: 5
short:  5
ubyte:  5
byte:   5


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


moritzwarning web.de changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |moritzwarning web.de




------- Comment #2 from moritzwarning web.de  2009-05-03 13:30 -------
I only see this error on windows, linux (x64) works for me. (dmd 1.043)
This is the test case I have made after I ran into this problem:

float getFloat() {
    return 11468.78f;
}

void main() {
        uint i = cast(uint) 11468.78f;
        assert(i == 11468);

        uint j = cast(uint) getFloat();
        assert(j == 11468); //fails on windows: j is 0.
}


-- 
May 03 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697


Don <clugdbug yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |clugdbug yahoo.com.au
            Summary|Cast of float function      |[DMC too] Cast of float
                   |return to ulong or uint     |function return to ulong or
                   |gives bogus value           |uint gives bogus value
           Severity|major                       |critical




--- Comment #3 from Don <clugdbug yahoo.com.au>  2009-08-01 03:04:42 PDT ---
This code below fails on DMC, proving that this is a severe back-end bug.
Interesting on DMC, the uint case does NOT fail: it inlines in that case.
Raising severity, as I believe this is one of the worse extant compiler bugs.

What's happening is that a function _DBLULNG  is being used to convert from
double to ulong. It expects a double, but it's being given a float. So garbage
results.

#include <assert.h>
float getFloat() {
    return 5.0f;
}

int main()
{
   unsigned long j = (unsigned long)getFloat();
   assert(j==5);
   return 0;
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 01 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697





--- Comment #4 from Don <clugdbug yahoo.com.au>  2009-08-04 00:27:08 PDT ---
The evil is done in cdcnvt() in cod4.c, just after this bit...

        case OPf_d:
        case OPd_f:

        /* if won't do us much good to transfer back and    */
        /* forth between 8088 registers and 8087 registers    */

So it elides the conversion.
This comment, and the transformation it performs, is false in the case where
the OPf_d is followed a conversion from double to uint or ulong (OPd_u32 or
OPd_u64). This is because the C functions which perform the conversion expect
the double to be in EDX:EAX: ie, it genuinely needs to be converted to double.

Conversions from float to uint work on Linux because a different function is
called, which expects the double to be passed in ST0. They work on DMC Windows
because the conversion gets inlined.

Before presenting a patch, I'd like to make sure that there aren't any other
failing cases.

Could someone please check whether conversions from float to ulong work on
Linux?
(I'm surprised by the comment that it works on Linux, I would expect it to
fail).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 04 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697


Lars T. Kyllingstad <bugzilla kyllingen.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bugzilla kyllingen.net




--- Comment #5 from Lars T. Kyllingstad <bugzilla kyllingen.net>  2009-08-04
01:14:48 PDT ---
This is the output I get from running Stewart's program with DMD 2.031 on Linux
(64-bit, although since DMD is 32-bit it probably doesn't matter):

float:  5.000000
ulong:  9223372036854775808
long:   5
uint:   5
int:    5
ushort: 5
short:  5
ubyte:  5
byte:   5
float:  5.000000
ulong:  5
long:   5
uint:   5
int:    5
ushort: 5
short:  5
ubyte:  5
byte:   5

As you suspected, float->uint works, while float->ulong fails.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Aug 04 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697





--- Comment #6 from Don <clugdbug yahoo.com.au>  2009-08-04 01:48:40 PDT ---
(In reply to comment #5)
 This is the output I get from running Stewart's program with DMD 2.031 on Linux

 As you suspected, float->uint works, while float->ulong fails.

Awesome! There's several ways to fix this, I'm not sure which is the best. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Aug 04 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697


Don <clugdbug yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |patch
            Summary|[DMC too] Cast of float     |Cast of float function
                   |function return to ulong or |return to ulong or uint
                   |uint gives bogus value      |gives bogus value


--- Comment #7 from Don <clugdbug yahoo.com.au> 2009-09-08 08:44:56 PDT ---
Here's a patch against DMD2.032. It also requires a change to llmath.d in
druntime (or in Phobos1). The simplest way is to copy the contents of 
__LDBLULLNG() and put it into __DBLULLNG(). Because there's no need for a
difference between those functions (although there can be a performance
benefit, so they are both worth retaining, I think).

=================

Index: C:/dmd2best/src/dmd/backend/cod4.c
===================================================================
--- C:/dmd2best/src/dmd/backend/cod4.c    (revision 49)
+++ C:/dmd2best/src/dmd/backend/cod4.c    (revision 51)
   -2313,7 +2313,7   
         case OPd_s64:
         return cnvt87(e,pretregs);
         case OPd_u32:        // use subroutine, not 8087
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if 1//TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
         retregs = mST0;
 #else
         retregs = DOUBLEREGS;
   -2321,7 +2321,8   
         goto L1;

         case OPd_u64:
-        retregs = DOUBLEREGS;
+        retregs = mST0;
+        //retregs = DOUBLEREGS;
         goto L1;
         case OPu64_d:
         if (*pretregs & mST0)
Index: C:/dmd2best/src/dmd/backend/cod1.c
===================================================================
--- C:/dmd2best/src/dmd/backend/cod1.c    (revision 49)
+++ C:/dmd2best/src/dmd/backend/cod1.c    (revision 51)
   -1936,14 +1936,15   
     Y(DOUBLEREGS_16,"_INTDBL "),
     Y(DOUBLEREGS_16,"_DBLUNS "),
     Y(DOUBLEREGS_16,"_UNSDBL "),
-    Y(DOUBLEREGS_16,"_DBLULNG "),
+//    Y(DOUBLEREGS_16,"_DBLULNG "),
+    Y(DOUBLEREGS_16,"__DBLULNG"),
     Y(DOUBLEREGS_16,"_ULNGDBL "),
     Y(DOUBLEREGS_16,"_DBLFLT "),
     Y(ALLREGS,"_FLTDBL "),

     Y(DOUBLEREGS_16,"_DBLLLNG "),
     Y(DOUBLEREGS_16,"_LLNGDBL "),
-#if 0
+#if 1
     Y(DOUBLEREGS_16,"__DBLULLNG"),
 #else
     Y(DOUBLEREGS_16,"_DBLULLNG "),
   -2022,7 +2023,7   
     {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1},    // _INTDBL     intdbl
     {mAX,mAX,0,INFfloat,1,1},                // _DBLUNS     dbluns
     {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1},    // _UNSDBL     unsdbl
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if 1//TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
     {mDX|mAX,mAX,0,INF32|INFfloat,0,1},            // _DBLULNG     dblulng
 #else
     {mDX|mAX,mAX,0,INFfloat,1,1},            // _DBLULNG     dblulng
   -2035,7 +2036,7   

     {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1},        // _DBLLLNG 
     {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1},    // _LLNGDBL 
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if 1//TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
     {DOUBLEREGS_16,mDX|mAX,0,INFfloat,2,2},        // _DBLULLNG 
 #else
     {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1},        // _DBLULLNG 
   -2143,7 +2144,6   
         0x66,0xf7,0xe1,        // mul    ECX
         0x66,0x0f,0xa4,0xc2,0x10,    // shld    EDX,EAX,16    ;DX,AX = EAX
     };
-
     c = genasm(c,lmul,sizeof(lmul));
   }
   else

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 08 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697



--- Comment #8 from Don <clugdbug yahoo.com.au> 2009-09-24 08:43:25 PDT ---
There was a problem with the patch (failed the DMD test suite).
Here's a revised patch which passes.  As before, it also requires a change to
llmath.d in druntime (or in Phobos1). The simplest way is to copy the contents
of __LDBLULLNG() and put it into __DBLULLNG(). Note that __DLBULLNG() has never
been used by any previous DMD version, so it can be changed without breaking
anything.


Index: C:/dmd2/src/dmd/backend/cod4.c
===================================================================
--- C:/dmd2/src/dmd/backend/cod4.c    (revision 49)
+++ C:/dmd2/src/dmd/backend/cod4.c    (revision 62)
   -2313,7 +2313,7   
         case OPd_s64:
         return cnvt87(e,pretregs);
         case OPd_u32:        // use subroutine, not 8087
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if 1//TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
         retregs = mST0;
 #else
         retregs = DOUBLEREGS;
   -2321,7 +2321,8   
         goto L1;

         case OPd_u64:
-        retregs = DOUBLEREGS;
+        retregs = mST0;
+        //retregs = DOUBLEREGS;
         goto L1;
         case OPu64_d:
         if (*pretregs & mST0)
Index: C:/dmd2/src/dmd/backend/cod1.c
===================================================================
--- C:/dmd2/src/dmd/backend/cod1.c    (revision 49)
+++ C:/dmd2/src/dmd/backend/cod1.c    (revision 62)
   -1936,15 +1936,16   
     Y(DOUBLEREGS_16,"_INTDBL "),
     Y(DOUBLEREGS_16,"_DBLUNS "),
     Y(DOUBLEREGS_16,"_UNSDBL "),
-    Y(DOUBLEREGS_16,"_DBLULNG "),
+//    Y(DOUBLEREGS_16,"_DBLULNG "),
+    Y(DOUBLEREGS_16,"__DBLULNG"),
     Y(DOUBLEREGS_16,"_ULNGDBL "),
     Y(DOUBLEREGS_16,"_DBLFLT "),
     Y(ALLREGS,"_FLTDBL "),

     Y(DOUBLEREGS_16,"_DBLLLNG "),
     Y(DOUBLEREGS_16,"_LLNGDBL "),
-#if 0
-    Y(DOUBLEREGS_16,"__DBLULLNG"),
+#if 1
+    Y(mST0|mAX|mDX,"__DBLULLNG"),
 #else
     Y(DOUBLEREGS_16,"_DBLULLNG "),
 #endif
   -2022,7 +2023,7   
     {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1},    // _INTDBL     intdbl
     {mAX,mAX,0,INFfloat,1,1},                // _DBLUNS     dbluns
     {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1},    // _UNSDBL     unsdbl
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+#if 1//TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
     {mDX|mAX,mAX,0,INF32|INFfloat,0,1},            // _DBLULNG     dblulng
 #else
     {mDX|mAX,mAX,0,INFfloat,1,1},            // _DBLULNG     dblulng
   -2035,8 +2036,8   

     {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1},        // _DBLLLNG 
     {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1},    // _LLNGDBL 
-#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
-    {DOUBLEREGS_16,mDX|mAX,0,INFfloat,2,2},        // _DBLULLNG 
+#if 1//TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS
+    {0,mDX|mAX,0,INF32|INFfloat,1,2},    // __LDBLULLNG
 #else
     {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1},        // _DBLULLNG 
 #endif
   -2143,7 +2144,6   
         0x66,0xf7,0xe1,        // mul    ECX
         0x66,0x0f,0xa4,0xc2,0x10,    // shld    EDX,EAX,16    ;DX,AX = EAX
     };
-
     c = genasm(c,lmul,sizeof(lmul));
   }
   else

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 24 2009
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2697


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |bugzilla digitalmars.com
         Resolution|                            |FIXED


--- Comment #9 from Walter Bright <bugzilla digitalmars.com> 2009-10-06
02:14:47 PDT ---
Fixed dmd 1.048 and 2.033

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 06 2009