Re: [RFC] LRA: Carrying hard registers around

Vladimir Makarov via Gcc <[email protected]> Fri, 26 Jun 2026 13:09:55 -0400
Newsgroups gmane.comp.gcc.devel
Message-ID <[email protected]>
On 6/24/26 3:04 AM, Stefan Schulze Frielinghaus wrote:
> Hi all,
>
> 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 are not split so far which may result
> in unsatisfiable allocations.


As I understand, there was a consensus that we should avoid to use hard 
regs wherever it is possible.  It is better to create new moves 
involving hard regs and pseudos and use pseudos instead of the hard reg 
wherever it is possible.  RA will usually assign the pseudo to the hard 
reg when it is possible effectively removing such moves.

It simplifies work of RA and makes it more stable.  It also simplifies 
and improves optimizations before RA.

Hard reg life should be minimal (e.g. from assigning to arg reg to the 
call) or only in places of usage of local register variable or in 
asm. And optimizations should not make life longer.  For example, Segher 
Boessenkool worked on preventing hard reg propagation in combiner.  Life 
of arg regs was also implemented to be shorter in the function prologues.

That said, unfortunately there is still code where hard reg usage is not 
minimized, especially code originating from machine-dependent parts. And 
it was a problem especially for targets (e.g. x86) with insns requiring 
specific regs.  It was a problem for the reload pass and early LRA.  
Compilation failed with message about impossibility to find hard reg for 
a reload pseudo.

But hard reg life split was implemented in LRA long ago (see 
lra-constraints.cc:split_if_necessary).  First splitting for pseudos was 
implemented and on its base splitting of hard reg was implemented too.  
Maybe the implementation does not fully and optimally solve the problem 
but I did not see PRs about this for a long time.

Sorry, I don't think the proposed work is necessary.  Even if we could 
implement splitting more optimally, as I wrote, we should focus on 
minimizing hard reg life instead.



>    For example, assume that
> FIRST_PSEUDO_REGISTER == 100
>
> 1: r5=...
> 2: r101=exp(r100)
> ...
> 9: // some user of r5
>
> Furthermore, assume that in insn 2 the input operand is constrained to
> hard register r5 (e.g. via a hard register constraint, a single register
> constraint as e.g. {a,b,c,d,S,D} from x86_64, or even via a new
> dependent register filter assuming there was another input operand
> resulting in r100 being constrained to r5).
>
> In those cases we need to temporarily free hard register r5 for insn 2.
> I have been playing with an implementation where we end up with:
>
> 1: r5=...
> 3: r102=r5             // free r5
> 4: r103=r100           // assign r5 to input reload r103
> 2: r104=exp(r103)
> 6: r101=r104
> 5: r5=r102             // restore r5
> ...
> 9: // some user of r5
>
> The implementation is naive in the sense that it is not checked for an
> optimal restore point for r5, i.e., insns 3 and 5 are always emitted;
> independent of subsequent insns and whether they run into the same
> problem w.r.t. r5 which could in the worst case lead to many unnecessary
> "in-between" reloads.
>
> However, before diving into those missed optimizations, I would rather
> like to fix the place where such reloads should be introduced.  At the
> moment I decided to check during curr_insn_transform() whether the
> currently selected alternative makes use of a hard register constraint
> and whether this particular hard register is live.  If so, then create a
> new reload and emit moves before/after.  The obvious problem with this
> is, there is no liveness information at this point in time.  We could
> compute liveness just prior constraint handling (that's what I'm doing
> in my hack), however, from the liveness information we cannot
> distinguish why a hard register is live, i.e., whether it is live
> because we assigned it to a pseudo or whether it is live due to a hard
> register assignment as e.g. given in insn 1 above.  In the former case I
> think it would be better to rely on the current split mechanism for
> pseudos.
>
> Of course, we might unnecessarily introduce save/restores, if
> implemented via curr_insn_transfrom(), in case a single alternative
> contains not only a hard register constraint but also another constraint
> which is chosen in the end which in turn may result in r5 not being used
> rendering the save/restore unnecessary.  This would be another missed
> optimization.  Again, for the moment, I'm focusing on getting rid of
> ICEs.  Speaking of ICEs my current implementation hack also does not
> differentiate between spilling to registers vs. memory which may lead to
> other ICEs in the end in case of high register pressure.  I haven't
> looked into that so far.
>
> Before making any substantial changes: any thoughts about this?  Maybe
> there is a better place or mechanism to handle this at all?  I'm not
> expecting that we often hit those cases for most targets.  Especially,
> since on x86_64 with single register constraints I'm not aware of a real
> world example which fails due to this problem (even though some of them
> may have been obscured over the years by subsequent fixes in numerous
> passes).  That being said, for a first implementation, I would rather
> aim for a computational inexpensive solution instead of trying to emit
> optimal code in each and every scenario which is why I started by simply
> carrying hard registers around a single instructions.  Maybe some sort
> of light-liveness which considers only hard register assignments, which
> isn't influenced by pseudo allocation and is therefore to some degree
> static, would be enough.
>
As I know there was a consensus that we should avoid to use hard regs 
where it is possible.  Hard reg life should be minimal (e.g. from 
assigning to arg reg to the call).  And optimizations should not make 
life longer.  For example, Segher Boessenkool worked on preventing hard 
reg propagation in combiner.