On Mon, Jul 21, 2025 at 03:30:08PM +0200, Georg-Johann Lay wrote:
> The recently pushed hreg-constraints (HRCs) feature has this in
> the docs:
> 
> <docs>
> register asm may not only be clobbered by function calls but also by inline
> asm in conjunction with hard register constraints. For example, in the
> following
> 
> register int x asm ("r5") = 42;
> int y;
> asm ("" : "={r5}" (y));
> asm ("" : "+r" (x));
> 
> variable x materializes before the very first inline asm which writes to
> register r5 and therefore clobbers x which in turn is read by the subsequent
> inline asm.
> </docs>
> 
> As far as I understand this is quite different from local reg vars,
> which are only applied when they are an operand to an inline asm.  I.e.
> 
> register int x __asm ("r5") = 42;
> 
> does NOT mean that x lives in r5 throughout the function, but only that
> x lives in r5 in places where x is an operand to an inline asm.
> On places other that inline asm that refers x, x is treated just like
> a local variable (e.g. across function calls or across asm that doesn't
> reference x).

No, this was actually a motivation for coming up with hard register
constraints.  register asm materializes already during expand.  A
side effect of this is that any register which is not call saved may be
clobbered if there is a call between the register asm assignment and the
inline asm.  For example

long bar (void);

long
foo (void)
{
  register long x asm ("rax") = 42;
  bar ();
  asm volatile ("" :: "r" (x));
  return x;
}

On x86_64, the assignment $rax=42 materializes before the function call.
Since the functions return value is stored in rax, too, the register is
clobbered before it is used in the Extended asm.

This behaviour is also documented in
https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html

Cheers,
Stefan

> 
> Take this example on AVR:
> 
> char func (char x) // incoming r24
> {
>     register char z __asm("24") = x + 1;
>     __asm ("; clobber r24" ::: "24");
>     __asm ("inc %0" : "+r" (z));
>     return x; // returning in r24
> }
> 
> The 1st asm is clobbering r24, and therefore x must not be kept in
> r24 at that point.  This is demonstrated by the generated code:
> 
> $ avr-gcc asm.c -S -Os -dp
> 
> func:
>       mov r25,r24      ;  20  [c=4 l=1]  movqi_insn/0
> /* #APP */
>       ; clobber r24
> /* #NOAPP */
>       mov r24,r25      ;  21  [c=4 l=1]  movqi_insn/0
> /* #APP */
>       inc r24 
> /* #NOAPP */
>       ret              ;  24  [c=0 l=1]  return
> 
> As you can see, insn 20 moves r24 to r25 so it doesn't collide with
> the inline asm that clobbers r24.
> 
> Replacing the clobber with
> 
> __asm volatile ("; clobber %0" : "={r24}" (tmp));
> 
> Gives the same code, so I wonder why HRCs are so much weaker than local
> reg vars?
> 
> I think I saw some discussion on the HRC threads and problems in gimple,
> thougjh I wonder why gimple deals with hard regs to begin with?
> 
> Then I think this feature (or the absence of it) is a can of worms,
> because you cannot just port local reg vars to HRCs.
> 
> Johann

Reply via email to