Register Allocation Bug?

2009-03-25 Thread Kasper Bonne
Hi List

(Sorry for the cross-post in gcc-bugs, I didn't look properly at the
list before I posted).

I have a question (or possible compiler bug) regarding inline assembly
that I hope you can help me with.

I wanted a routine that would give me the value and address of a
memory location relative to the stack pointer. What I initially tried
was the following:

#define ESP(rel,value,addr) \
asm volatile ("mov (%%esp, %2, 4), %0\n\t"  \
  "lea (%%esp, %2, 4), %1\n\t"  \
  : "=r" (value), "=r" (addr)   \
  : "r" (rel)); \

It didn't work as expected so I looked at the assembler code generated
for the above:

 1:   b8 00 00 00 00  mov$0x0,%eax
 2:   8b 04 84mov(%esp,%eax,4),%eax
 3:   8d 14 84lea(%esp,%eax,4),%edx
 4:   89 45 f8mov%eax,0xfff8(%ebp)
 5:   89 55 fcmov%edx,0xfffc(%ebp)


As it turns out, %eax is being used for both input and output in line
2, clobbering %eax, so of course line 3 does not give the expected
result... Is this a compiler error?  I thought the only way the same
register would be used for both input and output was if you use the
"0" constraint? I'm compiling with 'GCC 4.2.1 20070719'.

The best solution I found was to split the two assembler statements in
the following way:

#define ESP(rel,value,addr) \
asm volatile ("movl (%%esp, %1, 4), %0\n\t" :   \
  "=r" (value) : "r" (rel));\
asm volatile ("lea  (%%esp, %1, 4), %0\n\t" :   \
  "=r" (addr) : "r" (rel));

The above compiles into six instructions instead of five (duplicating
mov $0x0,%eax) but is has the benefit of only using one register:

 1:   b8 00 00 00 00  mov$0x0,%eax
 2:   8b 04 84mov(%esp,%eax,4),%eax
 3:   89 45 fcmov%eax,0xfffc(%ebp)
 4:   b8 00 00 00 00  mov$0x0,%eax
 5:   8d 04 84lea(%esp,%eax,4),%eax
 6:   89 45 f0mov%eax,0xfff0(%ebp)

So, again, my question is this: Is the compiler doing what it's
supposed to when it's assigning the same register to both input and
output when the specified constraint is "r" and not "0"?

As far as I can tell this problem have been floating around for a
number of years. The following post from 2000 describes exactly the
same issue:

http://gcc.gnu.org/ml/gcc-bugs/2000-07/msg00456.html

Since it hasn't been fixed maybe it's a bu..*ahem*..feature?

Best
/Kasper


Re: Register Allocation Bug?

2009-03-25 Thread Kasper Bonne
Hi Andrew

On Wed, Mar 25, 2009 at 12:41, Andrew Haley  wrote:
>> Since it hasn't been fixed maybe it's a bu..*ahem*..feature?
>
> It's a feature.  Look up "earlyclobber" in the Fine Manual.

I tried that already and it does work but I actually thought the
'earlyclobber' modifier was for situations when the compiler couldn't
otherwise know that a register would be, well, clobbered early. E.g.,
when using 'rdtsc' or other instructions that modify a specific set of
registers.

In my example the compiler should be able to figure out that the
register is not available for output (because it is used as input in
the following line), so if this behavior is not a bug, it should
be. IMO.

The wording in the description of digit constraints (like "0") lead me
to believe that without such a constraint, the same register would not
be used for both input and output... but OK, it doesn't say that
explicitly.

Anyway, thanks for you answer...

On a side note, the assembler for your proposal is the following:

 1:   b8 00 00 00 00  mov$0x0,%eax
 2:   8b 0c 84mov(%esp,%eax,4),%ecx
 3:   8d 14 84lea(%esp,%eax,4),%edx
 4:   89 c8   mov%ecx,%eax
 5:   89 45 fcmov%eax,0xfffc(%ebp)
 6:   89 55 f0mov%edx,0xfff0(%ebp)

What is the point of line 4? Why not just:

 1:   b8 00 00 00 00  mov$0x0,%eax
 2:   8b 0c 84mov(%esp,%eax,4),%ecx
 3:   8d 14 84lea(%esp,%eax,4),%edx
 4:   89 45 fcmov%ecx,0xfffc(%ebp)
 5:   89 55 f0mov%edx,0xfff0(%ebp)

So at least there is still room for optimizations.

Best
/Kasper