On Mon, Jan 19, 2026 at 05:33:38PM +0100, Georg-Johann Lay wrote:
> Am 19.01.26 um 15:06 schrieb Stefan Schulze Frielinghaus:
> > On Mon, Jan 19, 2026 at 02:26:41PM +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.
> > > 
> > > Hi Stefan,
> > > 
> > > I reran the tests, and there are still some ICEs.
> > > 
> > > GCC is:
> > > 
> > > commit 1367db23a5626499468d79b3c12a9b1859e7b819 (HEAD -> master, 
> > > origin/master, origin/HEAD)
> > > Author: Tobias Burnus <[email protected]>
> > > Date:   Mon Jan 19 12:17:59 2026 +0100
> > > 
> > > Tests ran with x.diff. z.diff doesn't have an effect on the outcome.
> > 
> > Hmm neither x.diff nor z.diff contain the patch you are currently
> > replying to, i.e., the combine patch is missing.  Did you still apply
> > the combine patch?
> 
> You mean this one?
> 
> https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705494.html

No, that one is about ira.  I mean the one you are replying to, i.e.
the one about combine:

https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705804.html

> 
> I assumed it is upstream since it has been approved by Jeff.
> I tried to apply it but patch complains.

Because I pushed it last week as r16-6806-g6393102322a.

> 
> Loosing track of what patches I need in what order and which are
> outdated...

No worries, don't feel obligated to test it.  It was just a spontaneous
idea I had.

Cheers,
Stefan

> 
> I also tried the patch below (as y.diff like attached), but it gives
> me ICE for unrecognizable insn, called from y.diff's
> 
> extract_insn (insn); // around combine.cc::2246
> 
> AFAIK insn should be recognizable at this point, but may not be => ICE.
> 
> In file included from 
> /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.target/avr/torture/addr-space-1-fx.c:6:
> /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.target/avr/torture/addr-space-1.h:
>  In function 'main':
> /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.target/avr/torture/addr-space-1.h:96:1:
>  error: unrecognizable insn:
> (insn 77 76 78 10 (set (reg:HI 30 r30)
>         (subreg:HI (symbol_ref:PSI ("A") [flags 0xe02] <var_decl 
> 0x7fda2559e000 A>) 0)) 
> "/home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.target/avr/torture/add\
> r-space-1.h":65:6 -1
>      (expr_list:REG_EQUAL (subreg:HI (symbol_ref:PSI ("A") [flags 0xe02] 
> <var_decl 0x7fda2559e000 A>) 0)
>         (nil)))
> during RTL pass: combine
> /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.target/avr/torture/addr-space-1.h:96:1:
>  internal compiler error: in extract_insn, at recog.cc:2888
> 0x1e482fc internal_error(char const*, ...)
>         ../../../source/gcc-x/gcc/diagnostic-global-context.cc:787
> 0x8bdd15 fancy_abort(char const*, int, char const*)
>         ../../../source/gcc-x/gcc/diagnostics/context.cc:1805
> 0x7597ff _fatal_insn(char const*, rtx_def const*, char const*, int, char 
> const*)
>         ../../../source/gcc-x/gcc/rtl-error.cc:108
> 0x75981b _fatal_insn_not_found(rtx_def const*, char const*, int, char const*)
>         ../../../source/gcc-x/gcc/rtl-error.cc:116
> 0x75814b extract_insn(rtx_insn*)
>         ../../../source/gcc-x/gcc/recog.cc:2888
> 0x1b9f635 cant_combine_insn_p
>         ../../../source/gcc-x/gcc/combine.cc:2246
> 0x1bafe17 try_combine
>         ../../../source/gcc-x/gcc/combine.cc:2681
> 0x1bb704c combine_instructions
>         ../../../source/gcc-x/gcc/combine.cc:1416
> 0x1bb704c rest_of_handle_combine
>         ../../../source/gcc-x/gcc/combine.cc:15253
> 0x1bb704c execute
>         ../../../source/gcc-x/gcc/combine.cc:15297
> 
> There is no such insn. Presumably there are 2 insns,
>    pseudo:PSI = symbol_ref:PSI ("A")
>    reg:HI = subreg:HI (pseudo:PSI 0).
> Dunno why it slipped through, but checking that
> the insn is recognizable at that point should be doable.
> 
> > > Notice that x.diff is only a very small fraction of avr insns that
> > > would use HRCs.
> > > 
> > > Tests that now fail, but worked before (7 tests):
> > > 
> > > atmega128-sim: gcc: gcc.c-torture/execute/pr94412.c   -O1  (test for 
> > > excess errors)
> > > atmega128-sim: gcc: gcc.c-torture/execute/pr94412.c   -O2  (test for 
> > > excess errors)
> > > atmega128-sim: gcc: gcc.c-torture/execute/pr94412.c   -O2 -flto 
> > > -fno-use-linker-plugin -flto-partition=none  (test for excess errors)
> > > atmega128-sim: gcc: gcc.c-torture/execute/pr94412.c   -O3 -g  (test for 
> > > excess errors)
> > > atmega128-sim: gcc: gcc.c-torture/execute/pr94412.c   -Os  (test for 
> > > excess errors)
> > > atmega128-sim: gcc: gcc.dg/loop-invariant-2.c (test for excess errors)
> > > atmega128-sim: gcc: gcc.dg/tree-ssa/ssa-lim-23.c (test for excess errors)
> > > 
> > > The ICEs are like
> > > 
> > > 
> > > /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.c-torture/execute/pr94412.c: 
> > > In function 'bar':
> > > /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.c-torture/execute/pr94412.c:15:1:
> > >  error: unable to find a register to spill
> > > /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.c-torture/execute/pr94412.c:15:1:
> > >  error: this is the insn:
> > > (insn 12 28 26 2 (parallel [
> > >              (set (subreg:HI (reg:SI 73 [orig:52 _3 ] [52]) 0)
> > >                  (udiv:HI (reg:HI 74 [58])
> > >                      (reg:HI 75 [orig:53 _9 ] [53])))
> > >              (set (reg:HI 76 [57])
> > >                  (umod:HI (reg:HI 74 [58])
> > >                      (reg:HI 75 [orig:53 _9 ] [53])))
> > >              (clobber (reg:HI 77 [67]))
> > >              (clobber (reg:QI 78 [68]))
> > >          ]) 
> > > "/home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.c-torture/execute/pr94412.c":14:12
> > >  604 {udivmodhi4}
> > >       (expr_list:REG_UNUSED (reg:QI 78 [68])
> > >          (expr_list:REG_UNUSED (reg:HI 77 [67])
> > >              (expr_list:REG_UNUSED (reg:HI 76 [57])
> > >                  (expr_list:REG_DEAD (reg:HI 75 [orig:53 _9 ] [53])
> > >                      (expr_list:REG_DEAD (reg:HI 74 [58])
> > >                          (nil)))))))
> > > during RTL pass: reload
> > > /home/gjl/gnu/source/gcc-x/gcc/testsuite/gcc.c-torture/execute/pr94412.c:15:1:
> > >  internal compiler error: in lra_split_hard_reg_for, at 
> > > lra-assigns.cc:1882
> > > 0x1e4823c internal_error(char const*, ...)
> > >   ../../../source/gcc-x/gcc/diagnostic-global-context.cc:787
> > > 0x8bdd15 fancy_abort(char const*, int, char const*)
> > >   ../../../source/gcc-x/gcc/diagnostics/context.cc:1805
> > > 0x7597ff _fatal_insn(char const*, rtx_def const*, char const*, int, char 
> > > const*)
> > >   ../../../source/gcc-x/gcc/rtl-error.cc:108
> > > 0xe39dc6 lra_split_hard_reg_for(bool)
> > >   ../../../source/gcc-x/gcc/lra-assigns.cc:1882
> > > 0xe338b6 lra(_IO_FILE*, int)
> > >   ../../../source/gcc-x/gcc/lra.cc:2535
> > > 0xde954f do_reload
> > >   ../../../source/gcc-x/gcc/ira.cc:6076
> > > 0xde954f execute
> > >   ../../../source/gcc-x/gcc/ira.cc:6264
> > > 
> > > As far as I understand, HRC won't work with scratches,
> > > but almost all avr insns that would want to use HRCs have
> > > hard reg clobbers. Such insns represent libgcc calls with
> > > a reg footprint smaller than the ABI, and such functions
> > > usually clobber at least some regs.
> > > 
> > > What would happen to hard-reg clobbers under HRC? Wrong code?
> > 
> > I haven't looked into this and cannot tell right away.
> > 
> > > 
> > > Moreover, quite some insns rely on insn combine, e.g. the
> > > ones for mul with sign-, zero- or one-extended operands.
> > > AFAIU, HRCs are incompatible with insn combine, so that HRCs
> > > are no alternative to the current hard-reg operands?
> > > 
> > > There are almost no insns that don't need insn combine *and*
> > > don't have hard-reg clobbers, so that almost nothing of HRC
> > > is left to be usable in the avr backend :-(
> > > 
> > > It seems a bit strange that insn combine would interfere with
> > > RA.  Some problems are when insn combine (or other passes) are
> > > propagating hard regs into operands, but they don't match constraints
> > > and RA has to kick them out again, perhaps resulting in sub-optimal code.
> > > But in no case I saw RA ICEing.
> > 
> > That is because so far RA had a choice here when regular register
> > constraints were used with a register class with multiple registers.
> > With hard register constraints, however, you really pin a pseudo to a
> > particular hard register and if that is already live due to an
> > assignment to that hard register you error out because it cannot be
> > reloaded.
> 
> Huh, I thought RA would try to spill the non-fitting reg?
> I don't know anything about RA though...
> 
> Cheers,
> Johann
> 
> > You run into the very same problem when you create single> register classes 
> > and assign them to new constraints and use those
> > instead of hard register constraints.
> > 
> > Cheers,
> > Stefan
> > 
> > > 
> > > 
> > > Johann
> > > 
> > > 
> > > > -- 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);
> > > > +  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
> > 
> > > commit 4725614255a2a5a428048db76ab931434c829758
> > > Author: Georg-Johann Lay <[email protected]>
> > > Date:   Tue Aug 5 14:54:35 2025 +0200
> > > 
> > >      htc: [u]divmod hi
> > > 
> > > diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
> > > index 30a02a4b6c9..ebfc16104c3 100644
> > > --- a/gcc/config/avr/avr.md
> > > +++ b/gcc/config/avr/avr.md
> > > @@ -3846,32 +3846,14 @@ (define_insn "*udivmodqi4_call"
> > >     [(set_attr "type" "xcall")])
> > >   (define_insn_and_split "divmodhi4"
> > > -  [(set (match_operand:HI 0 "pseudo_register_operand")
> > > -        (div:HI (match_operand:HI 1 "pseudo_register_operand")
> > > -                (match_operand:HI 2 "pseudo_register_operand")))
> > > -   (set (match_operand:HI 3 "pseudo_register_operand")
> > > -        (mod:HI (match_dup 1) (match_dup 2)))
> > > -   (clobber (reg:QI 21))
> > > -   (clobber (reg:HI 22))
> > > -   (clobber (reg:HI 24))
> > > -   (clobber (reg:HI 26))]
> > > -  ""
> > > -  { gcc_unreachable(); }
> > > -  ""
> > > -  [(set (reg:HI 24) (match_dup 1))
> > > -   (set (reg:HI 22) (match_dup 2))
> > > -   (parallel [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22)))
> > > -              (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22)))
> > > -              (clobber (reg:HI 26))
> > > -              (clobber (reg:QI 21))])
> > > -   (set (match_dup 0) (reg:HI 22))
> > > -   (set (match_dup 3) (reg:HI 24))])
> > > -
> > > -(define_insn_and_split "*divmodhi4_call_split"
> > > -  [(set (reg:HI 22) (div:HI (reg:HI 24) (reg:HI 22)))
> > > -   (set (reg:HI 24) (mod:HI (reg:HI 24) (reg:HI 22)))
> > > -   (clobber (reg:HI 26))
> > > -   (clobber (reg:QI 21))]
> > > +  [(set (match_operand:HI 0 "register_operand"        "={r22}")
> > > +        (div:HI (match_operand:HI 1 "register_operand" "{r24}")
> > > +                (match_operand:HI 2 "register_operand" "{r22}")))
> > > +   (set (match_operand:HI 3 "register_operand"        "={r24}")
> > > +        (mod:HI (match_dup 1)
> > > +                (match_dup 2)))
> > > +   (clobber (match_scratch:HI 4                       "={r26}"))
> > > +   (clobber (match_scratch:QI 5                       "={r21}"))]
> > >     ""
> > >     "#"
> > >     "&& reload_completed"
> > > @@ -3889,32 +3871,14 @@ (define_insn "*divmodhi4_call"
> > >     [(set_attr "type" "xcall")])
> > >   (define_insn_and_split "udivmodhi4"
> > > -  [(set (match_operand:HI 0 "pseudo_register_operand")
> > > -        (udiv:HI (match_operand:HI 1 "pseudo_register_operand")
> > > -                 (match_operand:HI 2 "pseudo_register_operand")))
> > > -   (set (match_operand:HI 3 "pseudo_register_operand")
> > > -        (umod:HI (match_dup 1) (match_dup 2)))
> > > -   (clobber (reg:QI 21))
> > > -   (clobber (reg:HI 22))
> > > -   (clobber (reg:HI 24))
> > > -   (clobber (reg:HI 26))]
> > > -  ""
> > > -  { gcc_unreachable(); }
> > > -  ""
> > > -  [(set (reg:HI 24) (match_dup 1))
> > > -   (set (reg:HI 22) (match_dup 2))
> > > -   (parallel [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22)))
> > > -              (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
> > > -              (clobber (reg:HI 26))
> > > -              (clobber (reg:QI 21))])
> > > -   (set (match_dup 0) (reg:HI 22))
> > > -   (set (match_dup 3) (reg:HI 24))])
> > > -
> > > -(define_insn_and_split "*udivmodhi4_call_split"
> > > -  [(set (reg:HI 22) (udiv:HI (reg:HI 24) (reg:HI 22)))
> > > -   (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
> > > -   (clobber (reg:HI 26))
> > > -   (clobber (reg:QI 21))]
> > > +  [(set (match_operand:HI 0 "register_operand"         "={r22}")
> > > +        (udiv:HI (match_operand:HI 1 "register_operand" "{r24}")
> > > +                 (match_operand:HI 2 "register_operand" "{r22}")))
> > > +   (set (match_operand:HI 3 "register_operand"         "={r24}")
> > > +        (umod:HI (match_dup 1)
> > > +                 (match_dup 2)))
> > > +   (clobber (match_scratch:HI 4                        "={r26}"))
> > > +   (clobber (match_scratch:QI 5                        "={r21}"))]
> > >     ""
> > >     "#"
> > >     "&& reload_completed"
> > > @@ -3926,8 +3890,7 @@ (define_insn "*udivmodhi4_call"
> > >      (set (reg:HI 24) (umod:HI (reg:HI 24) (reg:HI 22)))
> > >      (clobber (reg:HI 26))
> > >      (clobber (reg:QI 21))
> > > -   (clobber (reg:CC REG_CC))
> > > -   ]
> > > +   (clobber (reg:CC REG_CC))]
> > >     "reload_completed"
> > >     "%~call __udivmodhi4"
> > >     [(set_attr "type" "xcall")])
> > 
> > > diff --git a/gcc/cse.cc b/gcc/cse.cc
> > > index a86fe307819..28175e2732b 100644
> > > --- a/gcc/cse.cc
> > > +++ b/gcc/cse.cc
> > > @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
> > >   #include "backend.h"
> > >   #include "target.h"
> > >   #include "rtl.h"
> > > +#include "stmt.h"
> > >   #include "tree.h"
> > >   #include "cfghooks.h"
> > >   #include "df.h"
> > > @@ -31,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
> > >   #include "insn-config.h"
> > >   #include "regs.h"
> > >   #include "emit-rtl.h"
> > > +#include "ira.h"
> > >   #include "recog.h"
> > >   #include "cfgrtl.h"
> > >   #include "cfganal.h"
> > > @@ -6217,6 +6219,46 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
> > >               invalidate (SET_DEST (y), VOIDmode);
> > >           }
> > >       }
> > > +
> > > +  /* Any single register constraint may introduce a conflict, if the 
> > > associated
> > > +     hard register is live.  For example:
> > > +
> > > +     r100=%1
> > > +     r101=42
> > > +     r102=exp(r101)
> > > +
> > > +     If the first operand r101 of exp is constrained to hard register 
> > > %1, then
> > > +     r100 cannot be trivially substituted by %1 in the following since 
> > > %1 got
> > > +     clobbered.  Such conflicts may stem from single register classes as 
> > > well
> > > +     as hard register constraints.  Since prior RA we do not know which
> > > +     alternative will be chosen, be conservative and consider any such 
> > > hard
> > > +     register from any alternative as a potential clobber.  */
> > > +  extract_insn (insn);
> > > +  for (int nop = recog_data.n_operands - 1; nop >= 0; --nop)
> > > +    {
> > > +      int c;
> > > +      const char *p = recog_data.constraints[nop];
> > > +      for (; (c = *p); p += CONSTRAINT_LEN (c, p))
> > > + if (c == ',')
> > > +   ;
> > > + else if (c == '{')
> > > +   {
> > > +     int regno = decode_hard_reg_constraint (p);
> > > +     machine_mode mode = recog_data.operand_mode[nop];
> > > +     invalidate_reg (gen_rtx_REG (mode, regno));
> > > +   }
> > > + else
> > > +   {
> > > +     enum reg_class cl
> > > +       = reg_class_for_constraint (lookup_constraint (p));
> > > +     if (cl == NO_REGS)
> > > +       continue;
> > > +     machine_mode mode = recog_data.operand_mode[nop];
> > > +     int regno = ira_class_singleton[cl][mode];
> > > +     if (regno >= 0)
> > > +       invalidate_reg (gen_rtx_REG (mode, regno));
> > > +   }
> > > +    }
> > >   }
> > >   
> > >   static rtx cse_process_note (rtx);
> > > diff --git a/gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c 
> > > b/gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c
> > > new file mode 100644
> > > index 00000000000..c0aad292acb
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.target/powerpc/asm-hard-reg-2.c
> > > @@ -0,0 +1,9 @@
> > > +/* { dg-do compile } */
> > > +
> > > +double a;
> > > +double b (long double c) {
> > > +  long double d = 0;
> > > +  double e;
> > > +  __asm__ ("" : "=f" (a), "={fr2}" (e) : "{fr1}" (d));
> > > +  return c + c;
> > > +}
> > 

> 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);
> +  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

Reply via email to