On Wed, Jun 24, 2026 at 06:37:28PM +0200, Michael Matz wrote:
> Hello,
> 
> On Wed, 24 Jun 2026, Stefan Schulze Frielinghaus wrote:
> 
> > > > Live range splitting for hard regs which are assigned to some pseudo is
> > > > already implemented.  However, live ranges of hard regs which are live
> > > > due to hard register assignments
> > > 
> > > Define "hard register assignments".  Because ...
> > 
> > Basically any set insn where the left-hand side is a hard register.
> > Such insns may stem from register asm (assuming that
> > -fstrict-extended-asm [1] isn't used) during expand but could also be
> > directly emitted by a target.
> > 
> > We already forbid certain forms of optimizations in e.g. cselib/combine 
> > which could lead to those scenarios.  So instead of fighting 
> > optimization passes I was rather hoping for a general solution.
> 
> The general solution is to not let values stay in hardregs before register 
> allocation.  As I was trying to alude to here:
> 
> > > This example is similar but supported:
> > > 
> > >   int x;
> > >   asm("" : "=r5" (x));         // insn 1 'r5 = ...something'
> > >   code;
> > >   asm("use %0" : : "r5" (x));  // insn 9 'use r5'
> > > 
> > > here the output/input are r5, as in your situation, but the actual value 
> > > from 1 to 9 will be carried through the local variable 'x': a pseudo or 
> > > memory:
> > > 
> > >   1:  r5=...
> > >   1': r102=r5                  // from inline-asm output setup
> > >   2:  r101=exp(r100)
> > >   ...
> > >   9': r5=r102                  // from inline-asm input setup
> > >   9:  // some user of r5
> > > 
> > > The value doesn't (or shouldn't) flow through r5, but through some 
> > > pseudo/memory.  It's the reg-allocators duty then to not assign it to r5 
> > > itself, on the grounds that it would conflict with r100, which is 
> > > constrained to r5 itself, or if it does, generated the appropriate 
> > > compensation code.
> 
> Making 'x' a register var shouldn't influence this: that's the whole 
> reason why we explicitely document valid uses of register vars: so that 
> they can live in pseudos (or eventually, after reg-alloc, in different 
> than specified hardregs) outside of the inline asm instructions referring 
> to them.
> 
> > > So, make an example to show us?
> > 
> > See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125780 where we are
> > given
> > 
> > uint32_t xdiv (uint32_t a, uint32_t b)
> > {
> >     register int r18 __asm("18") = 0x1122;
> >     __asm volatile ("seh ; %0" : "+r" (r18), "+r" (a));
> >     uint32_t c = a / b;    // r18 is live here
> >     __asm volatile ("clh ; %0" : "+r" (r18), "+r" (c));
> >     return c;
> > }
> 
> I see, thanks.
> 
> > Due to register asm, hard register r18 is live across the division.
> 
> And that's the bogosity.  The register variable r18 can live in a pseudo 
> during that division, and _should_ live in a pseudo outside of the 
> specific setup/teardown sequences of the two inline asms.

This is not how register asm is implemented in GCC.  During expand
assignments involving register asm reduce to simple hard register
assignments (that is the whole point why I came up with [1] which is
supposed to fix at least this).  There are no pseudos involved.

Cheers,
Stefan

Reply via email to