Thread overview
[Issue 3918] New: Parameter use before its use in an AndAnd expression with reals treats NaN as false
Mar 10, 2010
Aldo Nunez
Mar 16, 2010
Don
Mar 16, 2010
Aldo Nunez
Aug 02, 2010
Don
Oct 28, 2012
yebblies
March 10, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3918

           Summary: Parameter use before its use in an AndAnd expression
                    with reals treats NaN as false
           Product: D
           Version: 2.041
          Platform: x86
        OS/Version: Windows
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: crimson.magus@gmail.com


--- Comment #0 from Aldo Nunez <crimson.magus@gmail.com> 2010-03-09 16:41:26 PST ---
NaN is supposed to be treated as true when implicitly converted to bool, because it's not the same as zero. But, in the following case, the NaN is treated as false.

- optimized build
- a variable of type real with value NaN
- the variable is used in an AndAnd (&&) or OrOr (||) expression
- the variable is used before the AndAnd (&&) or OrOr (||) expression

I assume this happens anywhere a real is turned into a bool, but I haven't checked.

Here's a sample program:

import std.stdio;

void Do( float t, real u )
{
    writeln( u );
    writeln( t && u );
}

void Do2( real t, float u )
{
    writeln( t );
    writeln( t && u );
}

void main( string[] args )
{
    Do( float.nan, real.nan );
    Do2( real.nan, float.nan );
}

In the function calls to both Do and Do2, the result is "false". It should be
"true". Commenting out "writeln( u )" and "writeln( t )" also make the results
"true".

Looking at the assembly code, I noticed that the cause seems to be an instruction that's left out when the program is optimized.

Unoptimized (right):

00403C0D  fld         tbyte ptr [esp+8] 00403C11  fldz 00403C13  fucompp 00403C15  fnstsw      ax 00403C17  sahf 00403C18  jne         00403C20 00403C1A  jp          00403C20

Optimized (wrong):

00403C1E  fld         tbyte ptr [esp+8] 00403C22  fldz 00403C24  fucompp 00403C26  fnstsw      ax 00403C28  sahf 00403C29  jne         00403C2F

The JP instruction is missing. As a result, we'll fall thru to where EAX is cleared, and the result turns into false.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 16, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3918


Don <clugdbug@yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |clugdbug@yahoo.com.au


--- Comment #1 from Don <clugdbug@yahoo.com.au> 2010-03-15 21:07:26 PDT ---
>NaN is supposed to be treated as true when implicitly converted to bool,
because it's not the same as zero.

That's surprising behaviour, I'd have expected that it needs to a non-zero value.

I don't think implicit conversion float->bool should be legal at all, for exactly this reason. But obviously its behaviour should be unaffected by -O.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 16, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3918



--- Comment #2 from Aldo Nunez <aldonunez1@gmail.com> 2010-03-15 21:49:32 PDT ---
Actually, I'm fine with NaN going either way, as long as it's consistent... and documented.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
August 02, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=3918



--- Comment #3 from Don <clugdbug@yahoo.com.au> 2010-08-02 00:12:09 PDT ---
I investigated this bug because I thought it might be related to the more
difficult bug 4443. Unfortunately, they are unrelated.
This one happens because the variable 'u' is recognised as a common sub
expression (CSE).

Then in cod3.c, jmpopcode(), around line 805, we see this code. The two lines marked with * mean that it just does a JNE, instead of a JNE/JP combination. When there's no CSE, the next return is used, "return XP|JNE", which adds the JP in.

  op = e->Eoper;
*  if (e->Ecount != e->Ecomsub)          // comsubs just get Z bit set
*        return JNE;
  if (!OTrel(op))                       // not relational operator
  {
        tym_t tymx = tybasic(e->Ety);
        if (tyfloating(tymx) && config.inline8087 &&
            (tymx == TYldouble || tymx == TYildouble || tymx == TYcldouble ||
             tymx == TYcdouble || tymx == TYcfloat ||
             op == OPind))
        {
            return XP|JNE;
        }
        return (op >= OPbt && op <= OPbts) ? JC : JNE;
  }
------------
How to fix this?
(1) Duplicate the if(tyfloating) code in the first return, so that floating
point CSEs still include a JP. But that penalizes the general case.
(2) Don't detect if(x) as a CSE, when x is floating point. One way of doing
this would be to change it into  x!=0.
(3) Entirely disallow if (x) for floating point, generating an error in the
front end.

Personally I think (3) is the best. I think making  'if (nan)' true leads to
subtle bugs, and making it false also leads to subtle bugs.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
October 28, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=3918


yebblies <yebblies@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |yebblies@gmail.com


--- Comment #4 from yebblies <yebblies@gmail.com> 2012-10-29 07:30:53 EST ---
(In reply to comment #3)
> 
> Then in cod3.c, jmpopcode(), around line 805, we see this code. The two lines marked with * mean that it just does a JNE, instead of a JNE/JP combination. When there's no CSE, the next return is used, "return XP|JNE", which adds the JP in.
> 

I hit this same bit of code when investigating the xmm codegen bugs earlier this year and tried to fix it by moving the CSE if to under the fp block, and Walter told me that "floating point expressions are not common subexpressioned."  Nasty.

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