Subject: Re: powerpc Linux scv support and scv system call ABI proposal

From: Segher Boessenkool <[email-masked]>
Date: Thu, 30 Jan 2020 05:25:12 -0600

On Thu, Jan 30, 2020 at 11:42:51AM +0100, Florian Weimer wrote:
> * Segher Boessenkool:
> > No, that *is* supported: as input to or output from an asm, a local
> > register asm variable *is* guaranteed to live in the specified register.
> > This is the *only* supported use.  Other uses may sometimes still work,
> > but they never worked reliably, and it cannot be made reliable; it has
> > been documented as not supported since ages, and it will not work at all
> > anymore some day.
> 
> I must say I find this situation *very* confusing.

Local register variables live in that register when they are operands to
an (extended) inline asm.  There are no other guarantees.  That is all.

> You said that r0 & 1 is undefined.

I said that in

  int reg asm("r0");
  ...
  ...  reg & 1  ...

in that last expression, reg can be in any register, not necessarily r0.
The code is still perfectly well-defined of course, it just might not do
what you expected.

>  I *assumed* that I would still get
> the value of r0 (the register) from the associated extended asm in this
> expression, even if it may now be a different register.  Your comment
> made me think that this is undefined.

Please show full(er) examples, I think we are talking about something
else?

> But then the syscall wrappers use
> this construct:
> 
>     __asm__ __volatile__						\
>       ("sc\n\t"								\
>        "mfcr  %0\n\t"							\
>        "0:"								\
>        : "=&r" (r0),							\
>          "=&r" (r3), "=&r" (r4), "=&r" (r5),				\
>          "=&r" (r6), "=&r" (r7), "=&r" (r8)				\
>        : ASM_INPUT_##nr							\
>        : "r9", "r10", "r11", "r12",					\
>          "cr0", "ctr", "memory");					\
> 	  err = r0;  \
>     r3;  \
> 
> That lone r3 at the end would be equally undefined because it is not
> used in an input or output operand of an extended asm statement.

Nothing is undefined.  That r3 variable at the end might not live in
register r3 there; but the output from the asm does (the compiler can
have swapped registers around already, or even put this in memory
(which is what will probably happen here at -O0!), etc.

> The GCC documentation has this warning:
> 
> |  _Warning:_ In the above example, be aware that a register (for
> | example 'r0') can be call-clobbered by subsequent code, including
> | function calls and library calls for arithmetic operators on other
> | variables (for example the initialization of 'p2').

Yes.  This does not matter for the only supported use.  This is why that
*is* the only supported use.  The documentation could use a touch-up, I
think.  Unless we still have problems here?

> On POWER, the LOADARGS macros attempt to deal with this by using
> non-register temporaries.  However, I don't know how effective this is
> if the compiler really doesn't deal with call-clobbered registers
> properly.

It worked on old compilers.  This isn't necessary on newer compilers.

> For the extended asm use case (to express register assignments that
> cannot be listed in constraints), I would expect that these variables
> retain their values according to the C specification (so they are never
> clobbered by calls), but that they only reside in their designated
> registers when used as input or output operands in extended asm
> statements.

That is what is done now.

In the old days (more than ten years ago), local register variables had
more guarantees, guarantees that were broken once by one (or all all of
the time, depends on your viewpoint ;-) )  Such variables *did* live in
the specified register everywhere, well, not *everywhere*, and there
the problems started.

Nowadays:

Local register variables live in that register when they are operands to
an (extended) inline asm.  There are no other guarantees.  That is all.

Segher