Bug 23793 - Unhealthy optimization. Accessing double with reinterpret_cast.
Summary: Unhealthy optimization. Accessing double with reinterpret_cast.
Status: RESOLVED DUPLICATE of bug 21920
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.3.5
: P2 normal
Target Milestone: 3.4.4
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-09-09 07:50 UTC by Thorbjørn Martsum
Modified: 2005-09-10 04:58 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work: 3.4.4 4.0.0 4.1.0
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Thorbjørn Martsum 2005-09-09 07:50:52 UTC
This is an error-report. However I will provide some background 
for my little piece of code. (The code itself is very simple)

I will try to post on comp.std.c++ in order to make this a part of C++ 
(maybe c) otherwise I might come back too beck you to implement it just in your
compiler.

There are many reasons. (One and the best is to switch a double based on
intervals) Therefore I would like a VERY FAST FUNCTION to return the sign of a
double (and float and long double) ...

(And compare on a double d<=-0.0 (without branch) wont do the trick. And I can't
blame you because you will have to respect Nan. 

Since c/c++ does not have this fast function (skipping Nan)
(which I hope will come) I have no other no other options that to 
write it myself (and cheat!)

That means that my trick will only work on doubles in IEEE 754 - with a size of 2. 

The sizepart of double (in my case 8 bytes) and int (in my case 4 bytes) could
probably be fixed with the right macros. 

However my code will only work on x86 and other machines accepting the IEEE 754
standard. I think Motorola does not follow this - but nevermind.

The code with the bug is : (Read signbit a push it to be one or zero)
int is_not_positive(double v)
{
  return ((reinterpret_cast<unsigned int*>(&v)[1]) >> 31);
}

This works with option O1 (and below)
but fails with O2 (and above)

The O1 correct (but not fast fast code) looks like this:

    .file    "bug.cpp"
    .text
    .align 2
.globl _Z15is_not_positived
    .type    _Z15is_not_positived, @function
_Z15is_not_positived:
.LFB3:
    pushl    %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $8, %esp
.LCFI2:
    fldl    8(%ebp)
    fstpl    -8(%ebp)
    movl    -4(%ebp), %eax
    shrl    $31, %eax
    movl    %ebp, %esp
    popl    %ebp
    ret
.LFE3:
    .size    _Z15is_not_positived, .-_Z15is_not_positived
    .section    .note.GNU-stack,"",@progbits
    .ident    "GCC: (GNU) 3.3.5-20050130 (Gentoo 3.3.5.20050130-r1,
ssp-3.3.5.20050130-1, pie-8.7.7.1)"

The wrong optimization simply removes:
fldl    8(%ebp)
fstpl    -8(%ebp)
// I guess that it removes the store. 

---------------------------------------
The "wished optimized code" is (notice this is partly manually written so
I might be wrong. I am not an assembler expert)

.LFB4:
    pushl    %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    movl    12(%ebp), %eax
    popl    %ebp
    shrl    $31, %eax
    ret
.LFE4:

I am sorry that I have not testet it with a newer version. 
(However I am not to bright and last time I did emerge gcc (with accept newest
version I got problems with compiling my kernel))
I hope the answer is "just upgrade you stupid man..."

Regards 
Thorbjørn Martsum

PS: 
BTW...
I have found a workaround using unsigned long long. 
This works with O3 and has only one extra instruction compared to "my best"

    movl    12(%ebp), %eax
    popl    %ebp

expands to

    movl    12(%ebp), %ecx
    popl    %ebp
    movl    %ecx, %eax

(a missing peephole-pattern (?) ) 
But sill WAY WAY Better than what the MS VS6 gives =)
Comment 1 Richard Biener 2005-09-09 08:39:47 UTC
All still maintained compilers produce the code you want.  I checked 3.4.4,
4.0.0 and current mainline.

So FIXED.
Comment 2 Falk Hueffner 2005-09-09 10:07:34 UTC
(In reply to comment #0)

> There are many reasons. (One and the best is to switch a double based on
> intervals) Therefore I would like a VERY FAST FUNCTION to return the sign of a
> double (and float and long double) ...
> 
> (And compare on a double d<=-0.0 (without branch) wont do the trick. And I can't
> blame you because you will have to respect Nan. 
> 
> Since c/c++ does not have this fast function (skipping Nan)
> (which I hope will come) I have no other no other options that to 
> write it myself (and cheat!)

C99 has this function; it's called signbit. So you should use that.
Newer gcc's also have a __builtin_signbit function.


> The code with the bug is : (Read signbit a push it to be one or zero)
> int is_not_positive(double v)
> {
>   return ((reinterpret_cast<unsigned int*>(&v)[1]) >> 31);
> }

This code has undefined behavior, since it violates aliasing rules. 
You should use a union, if you absolutely have to do it this way.

Comment 3 Andrew Pinski 2005-09-09 12:26:48 UTC
Reopening to ...
Comment 4 Andrew Pinski 2005-09-09 12:29:01 UTC
Mark as a dup of bug 21920 as this is an aliasing violation.

Use Falk's suggestion of signbit.  It is defined as returning non-zero for negative bit being set.

*** This bug has been marked as a duplicate of 21920 ***
Comment 5 Thorbjørn Martsum 2005-09-10 04:58:59 UTC
First of all - Thank you. 
And I promise never to report an error against such an old version.

Second I however think I am happy to haven reported it since nobody on
comp.lang.c++ knew ..... I found nothing on the internet or 
man math.h | grep -i sign // this might have changed since my old version

Third I know that the reinterpret_cast is more than bad behavior and it 
strictly needs not to work. However I am not casting an int into a char-array
where I should be able to hit eg an odd adresses (or?) and I guess that no
padding could be in my way(?)
So I could see no *reason* for it not to work. I know the union would do it 
(more) secure. I was just so stupid to think that it would not be as efficient.

Summa: I am happy that I have been told about signbit - 
and I am really sorry to have wasted your time... 

Regards 
Thorbjørn