optimization/9174: pentium4 double raw through union

Kevin Ryde user42@zip.com.au
Sat Jan 4 21:26:00 GMT 2003

>Number:         9174
>Category:       optimization
>Synopsis:       pentium4 double raw through union
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          wrong-code
>Submitter-Id:   net
>Arrival-Date:   Sat Jan 04 13:26:00 PST 2003
>Release:        3.2.1
System: FreeBSD binxxxxx.swox.se 4.6-STABLE FreeBSD 4.6-STABLE #1: Sun Sep 15 20:28:51 CEST 2002 tege@king.swox.se:/media/u/FreeBSD/RELENG_4/src/sys/compile/CLIENT i386
	<machine, os, target, libraries (multiple lines)>
host: i386-unknown-freebsd4.6
build: i386-unknown-freebsd4.6
target: i386-unknown-freebsd4.6
configured with: /u/gcc/gcc-3.2.1/configure --enable-languages=c,c++

Using a union to access the raw bytes of a double returns an incorrect
part of the double when compiled with -O and -march=pentium4.

The file foo.c below, compiled and run

	gcc -O -march=pentium4 foo.c


	want  419D6F34
	got   54000000

Whereas I believe the "want" value is correct and the "got" ought to
be the same, which it is if compiled either without -O or without

The program attempts to do a raw read of the high 32-bits of a double
using an array of two "unsigned"s.  The code seems to come out as

        fstpl   -8(%ebp)
        movsd   -8(%ebp), %xmm1
        movd    %xmm1, %eax

I think movd here is incorrect.  It ignores the "[1]" index on the u.s
access, and instead returns the low half of the double.

For what it's worth, this seems to occur the same when using a
bitfield to access part of the double, which is how I struck it in
some code that's part of the GMP MPFR library.

Also for what it's worth, the test "d != 0" seems necessary to induce
gcc to load the double onto the x87 stack then send it to an integer

Incidentally, movsd+movd is not efficient, no doubt a plain movl could
load from memory straight to eax.  And the fstpl is unnecessary too,
since the value in question is still in the parameters on the stack,
and could be read direct from there into eax.  Though perhaps it's a
bit tricky to "see through" a union back to the original operand for a
raw access.

Content-Type: text/x-csrc
Content-Disposition: attachment; filename=foo.c

union dbl
  double    d;
  unsigned  s[2];

foo (double d)
  union dbl  u;
  if (d != 0)
      u.d = d;
      return u.s[1];
    return 0;

main (void)
  double  d = 123456789.0;
  union dbl  u;

  u.d = d;
  printf ("want  %X\n", u.s[1]);

  printf ("got   %X\n", foo (d));

  return 0;


More information about the Gcc-bugs mailing list