re PR rtl-optimization/58545 (error: unable to find a register to spill in class...
authorJoern Rennecke <joern.rennecke@embecosm.com>
Wed, 30 Oct 2013 23:55:46 +0000 (23:55 +0000)
committerJoern Rennecke <amylaar@gcc.gnu.org>
Wed, 30 Oct 2013 23:55:46 +0000 (23:55 +0000)
gcc:
        PR other/58545
        * reload1.c (update_eliminables_and_spill): New function, broken
        out of reload.
        (reload): Use it.  Check for frame size change after frame
        size alignment, and call update_eliminables_and_spill first
        if continue-ing.
gcc/testsuite:
        PR other/58545
        * gcc.target/avr/pr58545.c: New test.

From-SVN: r204234

gcc/ChangeLog
gcc/reload1.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/avr/pr58545.c [new file with mode: 0644]

index 0bf4cbc56d5b478628c2e1cb3d9ce9a3e2f153a8..60c58b620963b723086202b5d441d175843921f2 100644 (file)
@@ -1,3 +1,12 @@
+2013-10-30  Joern Rennecke  <joern.rennecke@embecosm.com>
+
+       PR other/58545
+       * reload1.c (update_eliminables_and_spill): New function, broken
+       out of reload.
+       (reload): Use it.  Check for frame size change after frame
+       size alignment, and call update_eliminables_and_spill first
+       if continue-ing.
+
 2013-10-30  Cong Hou  <congh@google.com>
 
        PR target/58762
index b62b047b070e1d9c73697824876512e4e39208e3..204685da31620ec8563128cfb7611269a5fc65cd 100644 (file)
@@ -373,6 +373,7 @@ static void init_eliminable_invariants (rtx, bool);
 static void init_elim_table (void);
 static void free_reg_equiv (void);
 static void update_eliminables (HARD_REG_SET *);
+static bool update_eliminables_and_spill (void);
 static void elimination_costs_in_insn (rtx);
 static void spill_hard_reg (unsigned int, int);
 static int finish_spills (int);
@@ -913,9 +914,6 @@ reload (rtx first, int global)
       if (caller_save_needed)
        setup_save_areas ();
 
-      /* If we allocated another stack slot, redo elimination bookkeeping.  */
-      if (something_was_spilled || starting_frame_size != get_frame_size ())
-       continue;
       if (starting_frame_size && crtl->stack_alignment_needed)
        {
          /* If we have a stack frame, we must align it now.  The
@@ -927,8 +925,12 @@ reload (rtx first, int global)
             STARTING_FRAME_OFFSET not be already aligned to
             STACK_BOUNDARY.  */
          assign_stack_local (BLKmode, 0, crtl->stack_alignment_needed);
-         if (starting_frame_size != get_frame_size ())
-           continue;
+       }
+      /* If we allocated another stack slot, redo elimination bookkeeping.  */
+      if (something_was_spilled || starting_frame_size != get_frame_size ())
+       {
+         update_eliminables_and_spill ();
+         continue;
        }
 
       if (caller_save_needed)
@@ -962,30 +964,11 @@ reload (rtx first, int global)
       else if (!verify_initial_elim_offsets ())
        something_changed = 1;
 
-      {
-       HARD_REG_SET to_spill;
-       CLEAR_HARD_REG_SET (to_spill);
-       update_eliminables (&to_spill);
-       AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill);
-
-       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-         if (TEST_HARD_REG_BIT (to_spill, i))
-           {
-             spill_hard_reg (i, 1);
-             did_spill = 1;
-
-             /* Regardless of the state of spills, if we previously had
-                a register that we thought we could eliminate, but now can
-                not eliminate, we must run another pass.
-
-                Consider pseudos which have an entry in reg_equiv_* which
-                reference an eliminable register.  We must make another pass
-                to update reg_equiv_* so that we do not substitute in the
-                old value from when we thought the elimination could be
-                performed.  */
-             something_changed = 1;
-           }
-      }
+      if (update_eliminables_and_spill ())
+       {
+         did_spill = 1;
+         something_changed = 1;
+       }
 
       select_reload_regs ();
       if (failure)
@@ -4031,6 +4014,38 @@ update_eliminables (HARD_REG_SET *pset)
     SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM);
 }
 
+/* Call update_eliminables an spill any registers we can't eliminate anymore.
+   Return true iff a register was spilled.  */
+
+static bool
+update_eliminables_and_spill (void)
+{
+  int i;
+  bool did_spill = false;
+  HARD_REG_SET to_spill;
+  CLEAR_HARD_REG_SET (to_spill);
+  update_eliminables (&to_spill);
+  AND_COMPL_HARD_REG_SET (used_spill_regs, to_spill);
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (TEST_HARD_REG_BIT (to_spill, i))
+      {
+       spill_hard_reg (i, 1);
+       did_spill = true;
+
+       /* Regardless of the state of spills, if we previously had
+          a register that we thought we could eliminate, but now can
+          not eliminate, we must run another pass.
+
+          Consider pseudos which have an entry in reg_equiv_* which
+          reference an eliminable register.  We must make another pass
+          to update reg_equiv_* so that we do not substitute in the
+          old value from when we thought the elimination could be
+          performed.  */
+      }
+  return did_spill;
+}
+
 /* Return true if X is used as the target register of an elimination.  */
 
 bool
index 04e7d63ceebe980228d163574b26bdc278043da0..23b2a7eed74ebb1dae1399f72b626698c40ec31e 100644 (file)
@@ -1,3 +1,8 @@
+2013-10-30  Joern Rennecke  <joern.rennecke@embecosm.com>
+
+       PR other/58545
+       * gcc.target/avr/pr58545.c: New test.
+
 2013-10-30  Tobias Burnus  <burnus@net-b.de>
 
        Revert:
diff --git a/gcc/testsuite/gcc.target/avr/pr58545.c b/gcc/testsuite/gcc.target/avr/pr58545.c
new file mode 100644 (file)
index 0000000..d1b8461
--- /dev/null
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mmcu=atmega8" } */
+
+typedef unsigned char uint8_t;
+typedef unsigned int uint16_t;
+
+extern uint8_t f1 (const uint8_t*);
+extern void f2 (uint8_t*, uint8_t);
+
+void func (uint16_t parameter, uint8_t *addr, uint8_t data)
+{
+   uint8_t status;
+
+   status = f1 (addr + 8);
+
+   addr++;
+
+   if (*addr == parameter + 8)
+      *addr = parameter;
+
+   f2 (addr, data);
+   f2 (addr + 8, status + 1);
+}