On Tue, Jan 20, 2026 at 11:23:25AM +0100, Georg-Johann Lay wrote:
> Am 14.01.26 um 14:55 schrieb Stefan Schulze Frielinghaus:
> > From: Stefan Schulze Frielinghaus <[email protected]>
> >
> > I have put the check into cant_combine_insn_p(). However, I still
> > haven't convinced myself that this is a full fledged solution. Even the
> > current behaviour for constraints associated a single register class
> > seems like only partially solved to me. For the current case it would
> > solve the problem because we are substituting into a reg-reg move.
> > However, my current understanding is that I could actually make use of
> > hard registers in arbitrary patterns which wouldn't be dealt with.
> >
> > With this patch I'm conservative when hard register constraints are
> > involved and skip any combination.
> >
> > In light of not having real world examples were it breaks also for
> > constraints associated a single register class and being in stage 4, I'm
> > limiting this to hard register constraints for now.
> >
> > @Jeff ok for mainline assuming that bootstrap and regtest are successful
> > for x86_64 and s390?
> >
> > @Johann if you have a larger test than what you provided in the PR,
> > could you give this patch a try? I can confirm that with the machine
> > description patch provided in the PR, the example from the PR compiles
> > fine if this patch is applied. If you still see failures in more
> > complex examples you might also want to apply
> > https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705494.html
> > https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705495.html
> > Note, I haven't tested hard register constraints in clobbers so far, and
> > would rather assume that they do not work as expected. Once I find some
> > time, I will look into this.
> >
> > -- 8< --
> >
> > This fixes
> >
> > t.c:6:1: error: unable to find a register to spill
> > 6 | }
> > | ^
> >
> > for target avr. In the PR we are given a patch which makes use of hard
> > register constraints in the machine description for divmodhi4. Prior
> > combine we have for the test from the PR
> >
> > (insn 7 6 8 2 (parallel [
> > (set (reg:HI 46 [ _1 ])
> > (div:HI (reg/v:HI 44 [ k ])
> > (reg:HI 48)))
> > (set (reg:HI 47)
> > (mod:HI (reg/v:HI 44 [ k ])
> > (reg:HI 48)))
> > (clobber (scratch:HI))
> > (clobber (scratch:QI))
> > ]) "t.c":5:5 602 {divmodhi4}
> > (expr_list:REG_DEAD (reg:HI 48)
> > (expr_list:REG_DEAD (reg/v:HI 44 [ k ])
> > (expr_list:REG_UNUSED (reg:HI 47)
> > (nil)))))
> > (insn 8 7 9 2 (set (reg:HI 22 r22)
> > (symbol_ref/f:HI ("*.LC0") [flags 0x2] <var_decl 0x3fff7950d10
> > *.LC0>)) "t.c":5:5 128 {*movhi_split}
> > (nil))
> > (insn 9 8 10 2 (set (reg:HI 24 r24)
> > (reg:HI 46 [ _1 ])) "t.c":5:5 128 {*movhi_split}
> > (expr_list:REG_DEAD (reg:HI 46 [ _1 ])
> > (nil)))
> >
> > The patched instruction divmodhi4 constraints operand 2 (here pseudo
> > 48) to hard register 22. Combine merges insn 7 into 9 by crossing a
> > hard register assignment of register 22.
> >
> > (note 7 6 8 2 NOTE_INSN_DELETED)
> > (insn 8 7 9 2 (set (reg:HI 22 r22)
> > (symbol_ref/f:HI ("*.LC0") [flags 0x2] <var_decl 0x3fff7950d10
> > *.LC0>)) "t.c":5:5 128 {*movhi_split}
> > (nil))
> > (insn 9 8 10 2 (parallel [
> > (set (reg:HI 24 r24)
> > (div:HI (reg:HI 49 [ k ])
> > (reg:HI 48)))
> > (set (reg:HI 47)
> > (mod:HI (reg:HI 49 [ k ])
> > (reg:HI 48)))
> > (clobber (scratch:HI))
> > (clobber (scratch:QI))
> > ]) "t.c":5:5 602 {divmodhi4}
> > (expr_list:REG_DEAD (reg:HI 48)
> > (expr_list:REG_DEAD (reg:HI 49 [ k ])
> > (nil))))
> >
> > This leaves us with a conflict for pseudo 48 in the updated insn 9 since
> > register 22 is live here.
> >
> > Fixed by pulling the sledge hammer and skipping any potential
> > combination if a hard register constraint is involved. Ideally we would
> > skip based on the fact whether there is any usage of a hard register
> > referred by any hard register constraint between potentially combined
> > insns.
> >
> > gcc/ChangeLog:
> >
> > * combine.cc (cant_combine_insn_p): Do not try to combine insns
> > if hard register constraints are involved.
> > ---
> > gcc/combine.cc | 21 +++++++++++++++++++++
> > 1 file changed, 21 insertions(+)
> >
> > diff --git a/gcc/combine.cc b/gcc/combine.cc
> > index 816324f4735..a4e7aff971d 100644
> > --- a/gcc/combine.cc
> > +++ b/gcc/combine.cc
> > @@ -2229,6 +2229,27 @@ cant_combine_insn_p (rtx_insn *insn)
> > if (!NONDEBUG_INSN_P (insn))
> > return true;
> > + /* Do not try to combine insns which make use of hard register
> > constraints.
> > + For example, assume that in the first insn operand r100 of exp_a is
> > + constrained to hard register %5.
> > +
> > + r101=exp_a(r100)
> > + %5=...
> > + r102=exp_b(r101)
> > +
> > + Then combining the first insn into the last one creates a conflict for
> > + pseudo r100 since hard register %5 is live for the last insn.
> > Therefore,
> > + skip for now. This is a sledge hammer approach. Ideally we would
> > skip
> > + based on the fact whether there is any definition of a hard register
> > used
> > + in a single register constraint between potentially combined insns.
> > */
> > +
> > + extract_insn (insn);
>
> Hi Stefan,
>
> as already noted, that extract_insn may run into "unrecognizable insn"
> ICE. So before using extract_insn, it must be sure that the insn is
> recognizable. I see this in a few tests in the avr testsuite.
extract_insn() is called for the argument of cant_combine_insn_p() and
if that would fail because of an unrecognizable insn this would mean we
call combine for unrecognizable insns. Your reported test failures as
e.g.
gcc.c-torture/execute/pr94412.c -O2 (test for excess errors)
compile fine for me if patch v2 or v3 is applied and fail with the
error message you posted if none of the patches is installed. This all
sounds to me as if you are still testing without v2 or v3 applied.
If you have something reproducible for me, I'm willing to have a look.
Cheers,
Stefan
>
> Johann
>
> > + for (int nop = recog_data.n_operands - 1; nop >= 0; --nop)
> > + {
> > + if (strchr (recog_data.constraints[nop], '{'))
> > + return true;
> > + }
> > +
> > /* Never combine loads and stores involving hard regs that are likely
> > to be spilled. The register allocator can usually handle such
> > reg-reg moves by tying. If we allow the combiner to make
>