Am 30.05.26 um 16:48 schrieb Segher Boessenkool:
Hi!
On Fri, May 29, 2026 at 11:28:21AM +0200, Georg-Johann Lay via Gcc wrote:
Is it allowed in non-strict RTL that a register_operand contains
a REG_P register that doesn't satisfy the constraint of the
operand? Given that the REG meets register_operand of course,
and that the machine mode matches.
After reload (or LRA, the same thing really) has finished, all pseudos
are assigned hard registers, and predicates no longer have meaning,
instead we now use constraints. This is what people sometimes call
"strict RTL", a terrible name (not in the least because it actually is
quite a bit more lenient! But it also doesn't describe at all anything
that is different, and it doesn't even say this is "late in the
pipeline" or something like that).
To all of my knowledge, the answer is "yes": Prior to register
allocation, what matters are the insn predicates, not the insn
constraints.
Prior to RA you have the predicates only. During RA and reload you
have to satisfy both the predicates and the constraints. After reload
only the constraints matter.
RA assigns hard registers to whatever it can. Not more though! That
is what reload (called "LRA" nowadays, although register allocation is
a tiny and relatively trivial part of its job) is for: it makes sure
the instruction stream will semantically do the same, don't look too
hard at performance though :-)
So after reload there are only real ("hardware") registers. "Strict
mode".
In particular, a pass that operates on non-strict RTL may propagate
a (hard) register into a register_operand provided the predicate is
true, even in cases where the constraint doesn't match.
Yes, constraints aren't looked at at all so early.
It's clear that such a transformation makes the register allocator's
life harder, but RA is supposed to handle that. Correct?
Register allocation __tries to__ assign hard registers to all pseudos.
It cannot always, for various reasons (capacity problems is the
unavoidable one of course, but various conflict situations are nasty to
handle as well).
The reload pass will make things work. Traditional reload did
everything in one fell swoop, having a big to-the-side representation
that nothing else kept up-to-date. LRA instead works on tiny things at
a time (it is called the "Local RA" because of that), allowing it to
work directly on the RTL stream, there is no state anywhere else.
Context is that I am getting ICEs from RA for some __RTL test cases
that start at "ira".
Interesting! PR #s? (Hint hint hint :-) )
Segher
Okay, so I opened https://gcc.gnu.org/PR125518 for that.
The similar https://gcc.gnu.org/PR121426 has been resolved by pulling
the sledge hammer as Stefan calls it: combine.cc rejects all insn
combinations that involve hard-reg constraints.
I understand that fixing RA stuff is hard and only a hand-full of
guys can do it, yet it would be great if insns with hard-reg
constraints could be insn-combined.
What's confusing is that IRA doesn't seem to care at all about the
upcoming conflict, and leaves the mess to LRA which must solve
it as an afterthought. And test cases like from PR125518 might
be much easier to track and resolve than bug reports with
real-world test cases with 1000 lines of code or more...
What my be related are similar "conflicts" with local register vars.
Suppose:
register int arg1 __asm("r24") = 0;
register int arg2 __asm("r22") = a / b;
where the division clobbers R24 or sets it as a side effect.
The docs say that this code is not supported, though it *could*
be supported if each register var was assigned its own pseudo,
and RA would handle it properly. The pseudos would be moved to
the respective hard reg right before the inline asm that uses them.
Would be nice if the users could write their code without knowing
whether an initialization / assignment triggers some libcall.
Johann