Re: [RFC] LRA: Carrying hard registers around
Georg-Johann Lay via Gcc <[email protected]> Thu, 25 Jun 2026 12:06:11 +0200
| Newsgroups | gmane.comp.gcc.devel |
|---|---|
| Message-ID | <[email protected]> |
Am 24.06.26 um 14:53 schrieb Michael Matz via Gcc:
> 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 ...
>
>> 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
What should work though is:
register int x __asm("r5");
asm("" : "=r" (x));
code;
asm("" :: "r" (x));
Currently, RTL lowering emits explicit hard regs for local reg vars,
which collide with RA when code has insns with hard reg constraints.
Moreover, code like the following has always been problematic:
register int x __asm("r5") = expr1;
register int y __asm("r6") = expr2;
asm("" :: "r" (x), "r"(y));
When expr2 uses r5, e.g. by means of a libcall or an insn with
hard-reg constraints, then bad things happen.
The reason is that local reg vars are not emit as pseudos.
Local reg vars should be pseudos until RA.
What makes things even more contrived is that some RTL passes
are propagating hard regs into operand that allow pseudos,
even in cases where it's clear that it violates constraints.
Outcome is that RA cannot deal with that and ICE, gives
wrong code or is sub-optimal bloat with spills at best.
Currently the nonstrict-RTL passes are constraint agnostic,
and that's likely the only feasible way. But such situations
expose that RA has still some lessons to learn.
Johann
> 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?
>
> Ciao,
> Michael.