https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66591

            Bug ID: 66591
           Summary: [SH] ICE: in get_reload_reg, at lra-constraints.c:633
                    with -mlra
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Keywords: ice-on-valid-code
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kkojima at gcc dot gnu.org
                CC: olegendo at gcc dot gnu.org
  Target Milestone: ---
            Target: sh*-*-*

When I tried to build trunk with cross SH trunk compiler, I've got

tree-ssa-math-opts.c:1030:1: internal compiler error: in get_reload_reg, at
lra-constraints.c:633

Here is a reduced test case

static const unsigned char table[8] = { 0, 1, 1, 2, 2, 3, 3, 4, };

int
foo (long long n)
{
  if (n && n < 8)
    foo (table[n]);

  return 0;
}

The problem starts when LRA tries to reload the insn

(insn 23 22 24 5 (set (reg:QI 181)
        (mem/u/j:QI (plus:SI (reg/f:SI 179)
                (subreg:SI (reg/v:DI 168 [ n ]) 0)) [0 table S1 A8])) rel.cc:7
271 {*movqi}
     (expr_list:REG_DEAD (reg/f:SI 179)
        (expr_list:REG_DEAD (reg/v:DI 168 [ n ])
            (nil))))

.reload says

      Creating newreg=189 from oldreg=168, assigning class R0_REGS to address
r189
      Creating newreg=190 from oldreg=189, assigning class R0_REGS to address
r190
      Creating newreg=191 from oldreg=190, assigning class R0_REGS to address
r191
      ...
      Creating newreg=279 from oldreg=278, assigning class R0_REGS to address
r279

which shows that something loops.
It looks that LRA tries to find DImode R0_REGS hardware register for
reg 168 and fails to do so because R1 is allocated already in the above
test case unfortuantely.  So LRA gives another DImode newreg for it
and tries again.  Thus it drops into the loop.
This won't happen on other targets which have enough index registers
and looks to be very rare even on SH in the actual codes.  I think that
pre-allocating R0 is enough for that issue ATM.  It would be a yet another
issue that is appropriate for R0-preallocating pass.
Now I'm testing the patch below.

diff --git a/config/sh/sh.c b/config/sh/sh.c
index 8fc8197..af8727e 100644
--- a/config/sh/sh.c
+++ b/config/sh/sh.c
@@ -1780,7 +1780,6 @@ prepare_move_operands (rtx operands[], machine_mode mode)
         win on avarage for LRA.  */
       else if (sh_lra_p ()
               && TARGET_SH1 && ! TARGET_SH2A
-              && (mode == QImode || mode == HImode)
               && ((REG_P (operands[0]) && MEM_P (operands[1]))
                   || (REG_P (operands[1]) && MEM_P (operands[0]))))
        {
@@ -1788,7 +1787,8 @@ prepare_move_operands (rtx operands[], machine_mode mode)
          rtx reg = operands[load_p ? 0 : 1];
          rtx adr = XEXP (operands[load_p ? 1 : 0], 0);

-         if (REGNO (reg) >= FIRST_PSEUDO_REGISTER
+         if ((mode == QImode || mode == HImode)
+             && REGNO (reg) >= FIRST_PSEUDO_REGISTER
              && GET_CODE (adr) == PLUS
              && REG_P (XEXP (adr, 0))
              && (REGNO (XEXP (adr, 0)) >= FIRST_PSEUDO_REGISTER)
@@ -1800,6 +1800,17 @@ prepare_move_operands (rtx operands[], machine_mode
mode)
              emit_move_insn (r0_rtx, operands[1]);
              operands[1] = r0_rtx;
            }
+         if (REGNO (reg) >= FIRST_PSEUDO_REGISTER
+             && GET_CODE (adr) == PLUS
+             && REG_P (XEXP (adr, 0))
+             && (REGNO (XEXP (adr, 0)) >= FIRST_PSEUDO_REGISTER)
+             && SUBREG_P (XEXP (adr, 1))
+             && REG_P (SUBREG_REG (XEXP (adr, 1))))
+           {
+             rtx r0_rtx = gen_rtx_REG (GET_MODE (XEXP (adr, 1)), R0_REG);
+             emit_move_insn (r0_rtx, XEXP (adr, 1));
+             XEXP (adr, 1) = r0_rtx;
+           }
        }
     }

Reply via email to