This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: 64-bit on ia-32


On 13-Aug-2003, Johan Rydberg <jrydberg@night.trouble.net> wrote:
>
> register unsigned long long v0 asm ("%esi");
>
> union u
>   {
>     unsigned int ww[2];
>     unsigned long long ll;
>   };
>
> extern int p1, p2;
> #define P1 ((int) &p1)
> #define P2 ((int) &p2)
...
> static void
> move2 (void)
> {
>   union u u1;
>   u1.ww[0] = P1;
>   u1.ww[1] = P2;
>   v0 = u1.ll;
> }
>
> This generates the following code with GCC 3.2.1 : (Flags is -O2
> -fomit-frame-pointer)
...
> move2:
>         movl    $p1, %eax
>         movl    $p2, %edx
>         movl    %eax, %esi
>         movl    %edx, %edi
>         ret
>
> What bothers me is the move2 function.  Why don't move the value
> to %esi:%edi directly?

My *guess* as to what is happening is this:
you've declared a local variable (`ui'), so GCC's register
allocator tries to allocate a register pair for it.
%esi:%edi is fixed, because it's used for a global register variable,
so GCC has to allocate a different pair; it chooses %eax:%edx.
Then GCC generates the obvious code, and unfortunately isn't able
to optimize it.

> Is there a away that I can make GCC emit code that moves the
> address of p1 and p2 to %esi and %edi, directly?

Declaring the global register variable as a union and assigning
to it directly seems to work:

        union u
          {
            unsigned int ww[2];
            unsigned long long ll;
          };
        register union u v0 asm ("%esi");

        extern int p1, p2;
        #define P1 ((int) &p1)
        #define P2 ((int) &p2)

        static void
        move4 (void)
        {
          v0.ww[0] = P1;
          v0.ww[1] = P2;
        }

With gcc 2.95.4 this generates

        move4:
                movl $p1,%esi
                movl $p2,%edi
                ret

> I've also tried this:
>
>   static void
>   move3 (void)
>   {
>     ((union u) v0).ww[0] = P1;
>     ((union u) v0).ww[1] = P2;
>   }
>
> But GCC elminates the code (only a ret insn is emitted).

That code is not standard C; it is making use of GNU C's "cast to union"
extension.  The documentation for that extension says

 | 	A cast to union is actually a constructor though, not a cast,
 | 	and hence does not yield an lvalue like normal casts.

So I think what is happening is that `(union u) v0' returns a _copy_
of v0, and you're assigning to (a field of) the copy, not to v0.  GCC then
optimizes away the assignment to the copy since the copy is not used again.

-- 
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
The University of Melbourne         |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]