On Fri, Jun 26, 2026 at 01:09:55PM -0400, Vladimir Makarov wrote:
> 
> 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.

Fair enough.  This idea was rather a (last?) straw.  That being said it
is unclear to me how advisable it is to use hard register constraints in
a backend without having a fallback for the worst case (however I haven't
looked into split_if_necessary so far and if it could help for
PR125780).  So maybe the takeaway is to wait until [1] becomes the
default which would at least rule out ICEs due to register asm leaving
any other ICE due to hard register usages under our control (backend +
optimizations).

Thanks for considering!

Cheers,
Stefan

> 
> 
> 
> >    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.
> 

Reply via email to