OSDN Git Service

2005-06-03 Richard Guenther <rguenth@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index 5e1ab1a..0caa411 100644 (file)
@@ -383,7 +383,7 @@ static int eliminate_regs_in_insn (rtx, int);
 static void update_eliminable_offsets (void);
 static void mark_not_eliminable (rtx, rtx, void *);
 static void set_initial_elim_offsets (void);
-static void verify_initial_elim_offsets (void);
+static bool verify_initial_elim_offsets (void);
 static void set_initial_label_offsets (void);
 static void set_offsets_for_label (rtx);
 static void init_elim_table (void);
@@ -405,7 +405,6 @@ 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);
@@ -740,8 +739,20 @@ reload (rtx first, int global)
                     that is not a legitimate memory operand.  As later
                     stages of reload assume that all addresses found
                     in the reg_equiv_* arrays were originally legitimate,
-                    we ignore such REG_EQUIV notes.  */
-                 if (memory_operand (x, VOIDmode))
+
+                    It can also happen that a REG_EQUIV note contains a
+                    readonly memory location.  If the destination pseudo
+                    is set from some other value (typically a different
+                    pseudo), and the destination pseudo does not get a
+                    hard reg, then reload will replace the destination
+                    pseudo with its equivalent memory location.  This
+                    is horribly bad as it creates a store to a readonly
+                    memory location and a runtime segfault.  To avoid
+                    this problem we reject readonly memory locations
+                    for equivalences.  This is overly conservative as
+                    we could find all sets of the destination pseudo
+                    and remove them as they should be redundant.  */
+                 if (memory_operand (x, VOIDmode) && ! MEM_READONLY_P (x))
                    {
                      /* Always unshare the equivalence, so we can
                         substitute into this insn without touching the
@@ -972,6 +983,13 @@ reload (rtx first, int global)
       if (starting_frame_size != get_frame_size ())
        something_changed = 1;
 
+      /* Even if the frame size remained the same, we might still have
+        changed elimination offsets, e.g. if find_reloads called 
+        force_const_mem requiring the back end to allocate a constant
+        pool base register that needs to be saved on the stack.  */
+      else if (!verify_initial_elim_offsets ())
+       something_changed = 1;
+
       {
        HARD_REG_SET to_spill;
        CLEAR_HARD_REG_SET (to_spill);
@@ -1063,8 +1081,7 @@ reload (rtx first, int global)
 
       gcc_assert (old_frame_size == get_frame_size ());
 
-      if (num_eliminable)
-       verify_initial_elim_offsets ();
+      gcc_assert (verify_initial_elim_offsets ());
     }
 
   /* If we were able to eliminate the frame pointer, show that it is no
@@ -1078,8 +1095,8 @@ reload (rtx first, int global)
       CLEAR_REGNO_REG_SET (bb->global_live_at_start,
                           HARD_FRAME_POINTER_REGNUM);
 
-  /* Come here (with failure set nonzero) if we can't get enough spill regs
-     and we decide not to abort about it.  */
+  /* Come here (with failure set nonzero) if we can't get enough spill
+     regs.  */
  failed:
 
   CLEAR_REG_SET (&spilled_pseudos);
@@ -1221,10 +1238,10 @@ reload (rtx first, int global)
 
       if (size > STACK_CHECK_MAX_FRAME_SIZE)
        {
-         warning ("frame size too large for reliable stack checking");
+         warning (0, "frame size too large for reliable stack checking");
          if (! verbose_warned)
            {
-             warning ("try reducing the number of local variables");
+             warning (0, "try reducing the number of local variables");
              verbose_warned = 1;
            }
        }
@@ -3288,23 +3305,32 @@ mark_not_eliminable (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
    where something illegal happened during reload_as_needed that could
    cause incorrect code to be generated if we did not check for it.  */
 
-static void
+static bool
 verify_initial_elim_offsets (void)
 {
   HOST_WIDE_INT t;
 
-#ifdef ELIMINABLE_REGS
-  struct elim_table *ep;
+  if (!num_eliminable)
+    return true;
 
-  for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
-    {
-      INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
-      gcc_assert (t == ep->initial_offset);
-    }
+#ifdef ELIMINABLE_REGS
+  {
+   struct elim_table *ep;
+
+   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+     {
+       INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t);
+       if (t != ep->initial_offset)
+        return false;
+     }
+  }
 #else
   INITIAL_FRAME_POINTER_OFFSET (t);
-  gcc_assert (t == reg_eliminate[0].initial_offset);
+  if (t != reg_eliminate[0].initial_offset)
+    return false;
 #endif
+
+  return true;
 }
 
 /* Reset all offsets on eliminable registers to their initial values.  */
@@ -4047,7 +4073,7 @@ forget_old_reloads_1 (rtx x, rtx ignored ATTRIBUTE_UNUSED,
   unsigned int nr;
 
   /* note_stores does give us subregs of hard regs,
-     subreg_regno_offset will abort if it is not a hard reg.  */
+     subreg_regno_offset requires a hard reg.  */
   while (GET_CODE (x) == SUBREG)
     {
       /* We ignore the subreg offset when calculating the regno,
@@ -4951,13 +4977,13 @@ free_for_value_p (int regno, enum machine_mode mode, int opnum,
 }
 
 /* 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.  */
+/* ??? 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 we must not spill these things to
  memory.  */
 
-static int
+int
 function_invariant_p (rtx x)
 {
   if (CONSTANT_P (x))
@@ -6075,10 +6101,10 @@ merge_assigned_reloads (rtx insn)
                        || rld[j].when_needed == RELOAD_FOR_INPADDR_ADDRESS)
                       ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
 
-                 /* Check to see if we accidentally converted two reloads
-                    that use the same reload register with different inputs
-                    to the same type.  If so, the resulting code won't work,
-                    so abort.  */
+                 /* Check to see if we accidentally converted two
+                    reloads that use the same reload register with
+                    different inputs to the same type.  If so, the
+                    resulting code won't work.  */
                  if (rld[j].reg_rtx)
                    for (k = 0; k < j; k++)
                      gcc_assert (rld[k].in == 0 || rld[k].reg_rtx == 0