www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 16217] New: Wrong code with -O -inline on function with right

https://issues.dlang.org/show_bug.cgi?id=16217

          Issue ID: 16217
           Summary: Wrong code with -O -inline on function with right
                    shift
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: dbugz joakim.fea.st

There was a recent off-by-one bug in Phobos, where toChars was incorrectly
slicing its result:

https://issues.dlang.org/show_bug.cgi?id=16192

It ended up right-shifting by a negative number and I wondered why dmd didn't
warn about this.  I see now that static analysis or a runtime check is not done
with such functions, so the compiler doesn't know and the binary can't tell you
what went wrong at runtime.

However, when creating an equivalent test to see what's going on, I seem to
have stumbled on another inlining/optimization combo bug in dmd.

Here's the code I wrote to mimic the toChars issue linked above:

int check_shift(int x) { return 16 >>> ((2 - x) * 4);}
unittest
{
    assert(check_shift(3)  ==  16);
    //assert(( 16 >>> (2-3) * 4)  ==  16);
}

If the second assert isn't commented out, dmd always evaluates that expression
at compile-time and gives this error:

shift.d(5): Error: shift by -4 is outside the range 0..31

If it's left commented out and the file is compiled with this command,

./2.071.1/linux/bin64/dmd -O -unittest -main shift.d

the resulting binary asserts at runtime on line 4, ie the first assert.  If I
compile again with inlining,

./2.071.1/linux/bin64/dmd -O -inline -unittest -main shift.d

the test passes, because the entire unittest block is "optimized" out, ie it's
simply removed from the resulting assembly:

0000000000422b80 <_D5shift14__unittestL2_1FZv>:
422b80:       50                      push   %rax
422b81:       58                      pop    %rax
422b82:       c3                      retq
422b83:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

This doesn't happen with inlining alone, the binary asserts there.  The problem
is reproducible with dmd 2.063.2 on linux/x64 also, which is the oldest dmd I
had lying around.  Fwiw, ldc 1.0.0 for linux/x64 also passes the test if
optimization and inlining are enabled.

--
Jun 29 2016