* reload1.c (inherit_piecemeal_p): New function.
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 4 May 2004 17:57:39 +0000 (17:57 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 4 May 2004 17:57:39 +0000 (17:57 +0000)
(emit_reload_insns): When reloading a group of hard registers, use
inherit_piecemeal_p to decide whether the values of individual hard
registers can be inherited.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@81480 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/reload1.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/mips-hilo-2.c [new file with mode: 0644]

index 9585261..95a70e6 100644 (file)
@@ -1,3 +1,10 @@
+2004-05-04  Richard Sandiford  <rsandifo@redhat.com>
+
+       * reload1.c (inherit_piecemeal_p): New function.
+       (emit_reload_insns): When reloading a group of hard registers, use
+       inherit_piecemeal_p to decide whether the values of individual hard
+       registers can be inherited.
+
 2004-05-04  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/ia64/t-ia64 (LIB2ADDEH): Remove gthr-gnat.c.
index 56f02c9..8c17a61 100644 (file)
@@ -417,6 +417,7 @@ static void emit_output_reload_insns (struct insn_chain *, struct reload *,
                                      int);
 static void do_input_reload (struct insn_chain *, struct reload *, int);
 static void do_output_reload (struct insn_chain *, struct reload *, int);
+static bool inherit_piecemeal_p (int, int);
 static void emit_reload_insns (struct insn_chain *);
 static void delete_output_reload (rtx, int, int);
 static void delete_address_reloads (rtx, rtx);
@@ -6956,6 +6957,27 @@ do_output_reload (struct insn_chain *chain, struct reload *rl, int j)
   emit_output_reload_insns (chain, rld + j, j);
 }
 
+/* Reload number R reloads from or to a group of hard registers starting at
+   register REGNO.  Return true if it can be treated for inheritance purposes
+   like a group of reloads, each one reloading a single hard register.
+   The caller has already checked that the spill register and REGNO use
+   the same number of registers to store the reload value.  */
+
+static bool
+inherit_piecemeal_p (int r, int regno)
+{
+#ifdef CANNOT_CHANGE_MODE_CLASS
+  return (!REG_CANNOT_CHANGE_MODE_P (reload_spill_index[r],
+                                    GET_MODE (rld[r].reg_rtx),
+                                    reg_raw_mode[reload_spill_index[r]])
+         && !REG_CANNOT_CHANGE_MODE_P (regno,
+                                       GET_MODE (rld[r].reg_rtx),
+                                       reg_raw_mode[regno]));
+#else
+  return true;
+#endif
+}
+
 /* Output insns to reload values in and out of the chosen reload regs.  */
 
 static void
@@ -7137,11 +7159,16 @@ emit_reload_insns (struct insn_chain *chain)
                  int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
                             : hard_regno_nregs[nregno]
                                               [GET_MODE (rld[r].reg_rtx)]);
+                 bool piecemeal;
 
                  spill_reg_store[i] = new_spill_reg_store[i];
                  spill_reg_stored_to[i] = out;
                  reg_last_reload_reg[nregno] = rld[r].reg_rtx;
 
+                 piecemeal = (nregno < FIRST_PSEUDO_REGISTER
+                              && nr == nnr
+                              && inherit_piecemeal_p (r, nregno));
+
                  /* If NREGNO is a hard register, it may occupy more than
                     one register.  If it does, say what is in the
                     rest of the registers assuming that both registers
@@ -7151,7 +7178,7 @@ emit_reload_insns (struct insn_chain *chain)
                  if (nregno < FIRST_PSEUDO_REGISTER)
                    for (k = 1; k < nnr; k++)
                      reg_last_reload_reg[nregno + k]
-                       = (nr == nnr
+                       = (piecemeal
                           ? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
                           : 0);
 
@@ -7160,7 +7187,7 @@ emit_reload_insns (struct insn_chain *chain)
                    {
                      CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
                      reg_reloaded_contents[i + k]
-                       = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+                       = (nregno >= FIRST_PSEUDO_REGISTER || !piecemeal
                           ? nregno
                           : nregno + k);
                      reg_reloaded_insn[i + k] = insn;
@@ -7185,6 +7212,7 @@ emit_reload_insns (struct insn_chain *chain)
                  int nregno;
                  int nnr;
                  rtx in;
+                 bool piecemeal;
 
                  if (GET_CODE (rld[r].in) == REG
                      && REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER)
@@ -7201,10 +7229,14 @@ emit_reload_insns (struct insn_chain *chain)
 
                  reg_last_reload_reg[nregno] = rld[r].reg_rtx;
 
+                 piecemeal = (nregno < FIRST_PSEUDO_REGISTER
+                              && nr == nnr
+                              && inherit_piecemeal_p (r, nregno));
+
                  if (nregno < FIRST_PSEUDO_REGISTER)
                    for (k = 1; k < nnr; k++)
                      reg_last_reload_reg[nregno + k]
-                       = (nr == nnr
+                       = (piecemeal
                           ? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
                           : 0);
 
@@ -7220,7 +7252,7 @@ emit_reload_insns (struct insn_chain *chain)
                    {
                      CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
                      reg_reloaded_contents[i + k]
-                       = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+                       = (nregno >= FIRST_PSEUDO_REGISTER || !piecemeal
                           ? nregno
                           : nregno + k);
                      reg_reloaded_insn[i + k] = insn;
index df01d26..f2d454b 100644 (file)
@@ -1,3 +1,7 @@
+2004-05-04  Richard Sandiford  <rsandifo@redhat.com>
+
+       * gcc.dg/torture/mips-hilo-2.c: New test.
+
 2004-05-03  Giovanni Bajo  <giovannibajo@gcc.gnu.org>
 
        PR c++/14389
diff --git a/gcc/testsuite/gcc.dg/torture/mips-hilo-2.c b/gcc/testsuite/gcc.dg/torture/mips-hilo-2.c
new file mode 100644 (file)
index 0000000..a8db617
--- /dev/null
@@ -0,0 +1,24 @@
+/* Due to a reload inheritance bug, the asm statement in f() would be passed
+   the low part of u.ll on little-endian 32-bit targets.  */
+/* { dg-do run { target mips*-*-* } } */
+
+unsigned int g;
+
+unsigned long long f (unsigned int x)
+{
+  union { unsigned long long ll; unsigned int parts[2]; } u;
+
+  u.ll = ((unsigned long long) x * x);
+  asm ("mflo\t%0" : "=r" (g) : "l" (u.parts[1]));
+  return u.ll;
+}
+
+int main ()
+{
+  union { unsigned long long ll; unsigned int parts[2]; } u;
+
+  u.ll = f (0x12345678);
+  if (g != u.parts[1])
+    abort ();
+  exit (0);
+}