Hi,

On Wed, Jun 24, 2026 at 02:53:06PM +0200, Michael Matz wrote:
> Hello,
> 
> On Wed, 24 Jun 2026, Stefan Schulze Frielinghaus via Gcc 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.

> 
> > 1: r5=...
> > 2: r101=exp(r100)
> > ...
> > 9: // some user of r5
> 
> ... this situation should be unachievable with well-formed source code 
> (and absent specific bugs in gcc).  I could only imagine r5 to be 
> associated with a global register variable, in which case that would make 
> r5 a fixed reg, inherently conflicting with a single-register constraint 
> forcing r5 on insn 2.  Any other situation (that I can imagine) would have 
> to do with insns 1 and 9 coming from inline asm, with either local 
> register variables or single-reg constraints in their respective output 
> (insn 1) and input (insn 9) constraints.  In such cases the value from 
> output to input should already flow through a pseudo register, because we 
> explicitely _do not guarantee_ that a hardreg set in one inline asm still 
> contains the value at a different later inline asm.  Pseudo code:
> 
>   int x;
>   asm("" : "=r5" (x));  // insn 1 'r5 = ...something'
>   code;
>   asm("use r5");        // insn 9, but not using correct constraints
> 
> Not supported.  Or:
> 
>   register int x asm("r5");
>   x = exp;              // insn 1
>   code;
>   foo(x);               // insn 9, use of r5
> 
> Not supported (in the sense that the user couldn't expect that r5 is 
> actually used in insn 1 or 9, local regvars are only guaranteed to sit in 
> their specified register when used as inline-asm operands).  Or random 
> other combinations of that idea that hinge on the expectation that from 
> insn 1 to insn 9 the register 5 magically retains its value.
> 
> 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.
> 
> 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;
}

Due to register asm, hard register r18 is live across the division.  The
insn implementing the division makes use of a single-register
constraint referring to r18 which means we finally ICE during RA which
is pretty annoying.  I'm not willing to declare this a user error
especially in light of the clear documentation of local register asm and
where they should have an effect.  Again, I would like to stress that
this is not restricted to register asm only but we may also run into
similar scenarios if targets emit hard register assignments directly.

Cheers,
Stefan

[1] https://gcc.gnu.org/pipermail/gcc-patches/2026-May/717805.html

Reply via email to