Re: Inline assembler + register values

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 01/25/2012 03:25 PM, Georg-Johann Lay wrote:
> Andrew Haley wrote:

>>> The "asm" in the local definition of buffer should have no effect except at the
>>> time it is used as operand to an inline assembler statement.
>>
>> Why do you say that?  People writing interpreters have for many
>> years used inline asm declarations to force variables to live in
>> certain hard registers.
> 
> Because the code breaks if, for example, the compiler introduces an implicit
> libgcc call.

Sure, but the programmer knows that.  For such use it doesn't make
sense to use a call-clobbered register.

> That code is not mentioned in the source and could otherwise
> clobber some if the values. Just as with other values, the values in the local
> asm registers have to be saved/restored around such calls.
> 
> If a variable is to be tied always to a specific hard register, then it can be
> accomplished by global register variable.

Not easily.  You need the variable to be in that register for the
interpreter loop, not the whole program.

> With hard-binding local register variables to hard registers you really run
> into problems with code like the following. Suppose the ABI says that the first
> parameter will be passed in r1 and the second in r2:
> 
> void foo (int r1, int r2)
> {
>     register int q1 asm ("r1") = r2;
>     register int q2 asm ("r2") = r1;
>     ...
> }
> 
> 
>>> A local asm variable does *not* say "this variable will be held in the register
>>> throughout the whole function or lifetime of the variable". Is just ensures
>>> that the variable is reloaded to respective asm operand.
>>
>> It always used to.  If not, this is a regression.
> 
> The docs say:
> 
>> Defining such a register variable does not reserve the register;
>> it remains available for other uses in places where flow control
>> determines the variable's value is not live.

That's reasonable enough.

>> This option does not guarantee that GCC will generate code that
>> has this variable in the register you specify at all times.
>> You may not code an explicit reference to this register in the assembler
>> instruction template part of an asm statement and assume it will always
>> refer to this variable. However, using the variable as an asm operand
>> guarantees that the specified register is used for the operand.
> 
> Maybe different users/code use local registers to accomplish different things
> and make different assumptions on what local registers must do or must not do.
> 
> There are many use cases for local regs and many existing code, for example
> writing an interface to a non-ABI function like the following. Again, the first
> parameter is passed and returned in r1:
> 
> void foo (int r1)
> {
>     register int r3 asm ("r3") = r1*5;
> 
>     // bar gets and returns values in r3
>     asm ("call bar" : "+r" (r3));
> 
>     return r3;
> }
> 
> In some of my applications I like to tie a local variable to a specific
> register or register class. Binding it globally is not option because that
> renders the register to a fixed one. The reason to bind the variable to a
> register serves to generate better code; it's rather a hack around optimization
> flaws in the compiler.

Indeed.

> But the code still works if the variable is not in the
> specified register class because the code using the register variable is all
> vanilla C code and no inline assembler.

Sure, but there's a while world of a difference between "works" and
"works well".  Interpreters tend to be very large functions, and gcc
-- like all compilers -- does an awful job of register allocation.
Writers of interpreters have loved gcc because it has precisely the
extensions you need to do a good job: register asm variables and
labels as values.

> I guess you have similar requirements in the interpreter, i.e. the
> local variable shall serve to yield small and/or fast code, but is
> it not essential to the code that the variable is kept in the
> register at each point in time?

Typically, register asm is used for the virtual PC and SP.  An add
would be

add:
  sp[1] = sp[0] + [sp1]; sp++;
  goto *(++pc);

You can easily imagine the rest.  With PC and SP in registers, this
generates super code.  Without register asm, gcc has always generated
tragic code for this sort of thing, especially on register-starved
machines.  More than a decade ago, interpreter writers discovered that
they could put PC and SP in registers and gcc would leave them there.
This allowed gcc to generate better code for such interpreters, and
become the compiler of choice.

Andrew.


[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux