OSDN Git Service

PR c++/15463
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 12451db..c848ce6 100644 (file)
@@ -402,6 +402,7 @@ static int reload_reg_free_for_value_p (int, int, int, enum reload_type,
                                        rtx, rtx, int, int);
 static int free_for_value_p (int, enum machine_mode, int, enum reload_type,
                             rtx, rtx, int, int);
+static int function_invariant_p (rtx);
 static int reload_reg_reaches_end_p (unsigned int, int, enum reload_type);
 static int allocate_reload_reg (struct insn_chain *, int, int);
 static int conflicts_with_override (rtx);
@@ -416,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);
@@ -4976,6 +4978,27 @@ free_for_value_p (int regno, enum machine_mode mode, int opnum,
   return 1;
 }
 
+/* Return nonzero if the rtx X is invariant over the current function.  */
+/* ??? Actually, the places where we use this expect exactly what
+ * is tested here, and not everything that is function invariant.  In
+ * particular, the frame pointer and arg pointer are special cased;
+ * pic_offset_table_rtx is not, and this will cause aborts when we
+ *             go to spill these things to memory.  */
+
+static int
+function_invariant_p (rtx x)
+{
+  if (CONSTANT_P (x))
+    return 1;
+  if (x == frame_pointer_rtx || x == arg_pointer_rtx)
+    return 1;
+  if (GET_CODE (x) == PLUS
+      && (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx)
+      && CONSTANT_P (XEXP (x, 1)))
+    return 1;
+  return 0;
+}
+
 /* Determine whether the reload reg X overlaps any rtx'es used for
    overriding inheritance.  Return nonzero if so.  */
 
@@ -6934,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 ATTRIBUTE_UNUSED, int regno ATTRIBUTE_UNUSED)
+{
+#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
@@ -7115,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
@@ -7129,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);
 
@@ -7138,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;
@@ -7163,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)
@@ -7179,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);
 
@@ -7198,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;
@@ -7302,6 +7356,10 @@ emit_reload_insns (struct insn_chain *chain)
                        CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno);
                    }
                  reg_last_reload_reg[nregno] = src_reg;
+                 /* We have to set reg_has_output_reload here, or else 
+                    forget_old_reloads_1 will clear reg_last_reload_reg
+                    right away.  */
+                 reg_has_output_reload[nregno] = 1;
                }
            }
          else
@@ -7512,7 +7570,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
 #endif
 
   /* If IN is a simple operand, use gen_move_insn.  */
-  else if (GET_RTX_CLASS (GET_CODE (in)) == 'o' || GET_CODE (in) == SUBREG)
+  else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
     emit_insn (gen_move_insn (out, in));
 
 #ifdef HAVE_reload_load_address
@@ -7779,7 +7837,7 @@ delete_address_reloads_1 (rtx dead_insn, rtx x, rtx current_insn)
       code = GET_CODE (prev);
       if (code == CODE_LABEL || code == JUMP_INSN)
        return;
-      if (GET_RTX_CLASS (code) != 'i')
+      if (!INSN_P (prev))
        continue;
       if (reg_set_p (x, PATTERN (prev)))
        break;