OSDN Git Service

2011-01-25 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / caller-save.c
index 9ca8592..7f7e222 100644 (file)
@@ -1,6 +1,6 @@
 /* Save and restore call-clobbered registers which are live across a call.
    Copyright (C) 1989, 1992, 1994, 1995, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -35,7 +35,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "function.h"
 #include "expr.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "tm_p.h"
 #include "addresses.h"
 #include "output.h"
@@ -116,11 +115,15 @@ reg_save_code (int reg, enum machine_mode mode)
   if (cached_reg_save_code[reg][mode])
      return cached_reg_save_code[reg][mode];
   if (!HARD_REGNO_MODE_OK (reg, mode))
-     {
-       cached_reg_save_code[reg][mode] = -1;
-       cached_reg_restore_code[reg][mode] = -1;
-       return -1;
-     }
+    {
+      /* Depending on how HARD_REGNO_MODE_OK is defined, range propagation
+        might deduce here that reg >= FIRST_PSEUDO_REGISTER.  So the assert
+        below silences a warning.  */
+      gcc_assert (reg < FIRST_PSEUDO_REGISTER);
+      cached_reg_save_code[reg][mode] = -1;
+      cached_reg_restore_code[reg][mode] = -1;
+      return -1;
+    }
 
   /* Update the register number and modes of the register
      and memory operand.  */
@@ -413,101 +416,93 @@ saved_hard_reg_compare_func (const void *v1p, const void *v2p)
 void
 setup_save_areas (void)
 {
-  int i, j, k;
-  unsigned int r;
+  int i, j, k, freq;
   HARD_REG_SET hard_regs_used;
+  struct saved_hard_reg *saved_reg;
+  rtx insn;
+  struct insn_chain *chain, *next;
+  unsigned int regno;
+  HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets;
+  reg_set_iterator rsi;
 
-  /* Allocate space in the save area for the largest multi-register
-     pseudos first, then work backwards to single register
-     pseudos.  */
-
-  /* Find and record all call-used hard-registers in this function.  */
   CLEAR_HARD_REG_SET (hard_regs_used);
-  for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
-    if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0)
-      {
-       unsigned int regno = reg_renumber[i];
-       unsigned int endregno
-         = end_hard_regno (GET_MODE (regno_reg_rtx[i]), regno);
-       for (r = regno; r < endregno; r++)
-         if (call_used_regs[r])
-           SET_HARD_REG_BIT (hard_regs_used, r);
-      }
 
-  if (optimize && flag_ira_share_save_slots)
+  /* Find every CALL_INSN and record which hard regs are live across the
+     call into HARD_REG_MAP and HARD_REGS_USED.  */
+  initiate_saved_hard_regs ();
+  /* Create hard reg saved regs.  */
+  for (chain = reload_insn_chain; chain != 0; chain = next)
     {
-      rtx insn, slot;
-      struct insn_chain *chain, *next;
-      char *saved_reg_conflicts;
-      unsigned int regno;
-      int next_k, freq;
-      struct saved_hard_reg *saved_reg, *saved_reg2, *saved_reg3;
-      int call_saved_regs_num;
-      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
-      HARD_REG_SET hard_regs_to_save, used_regs, this_insn_sets;
-      reg_set_iterator rsi;
-      int best_slot_num;
-      int prev_save_slots_num;
-      rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
-
-      initiate_saved_hard_regs ();
-      /* Create hard reg saved regs.  */
-      for (chain = reload_insn_chain; chain != 0; chain = next)
+      insn = chain->insn;
+      next = chain->next;
+      if (!CALL_P (insn)
+         || find_reg_note (insn, REG_NORETURN, NULL))
+       continue;
+      freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
+      REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
+                              &chain->live_throughout);
+      COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+
+      /* Record all registers set in this call insn.  These don't
+        need to be saved.  N.B. the call insn might set a subreg
+        of a multi-hard-reg pseudo; then the pseudo is considered
+        live during the call, but the subreg that is set
+        isn't.  */
+      CLEAR_HARD_REG_SET (this_insn_sets);
+      note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
+      /* Sibcalls are considered to set the return value.  */
+      if (SIBLING_CALL_P (insn) && crtl->return_rtx)
+       mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+
+      AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
+      AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
+      AND_HARD_REG_SET (hard_regs_to_save, used_regs);
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+       if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+         {
+           if (hard_reg_map[regno] != NULL)
+             hard_reg_map[regno]->call_freq += freq;
+           else
+             saved_reg = new_saved_hard_reg (regno, freq);
+           SET_HARD_REG_BIT (hard_regs_used, regno);
+         }
+      /* Look through all live pseudos, mark their hard registers.  */
+      EXECUTE_IF_SET_IN_REG_SET
+       (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
        {
-         insn = chain->insn;
-         next = chain->next;
-         if (!CALL_P (insn)
-             || find_reg_note (insn, REG_NORETURN, NULL))
-           continue;
-         freq = REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn));
-         REG_SET_TO_HARD_REG_SET (hard_regs_to_save,
-                                  &chain->live_throughout);
-         COPY_HARD_REG_SET (used_regs, call_used_reg_set);
+         int r = reg_renumber[regno];
+         int bound;
 
-         /* Record all registers set in this call insn.  These don't
-            need to be saved.  N.B. the call insn might set a subreg
-            of a multi-hard-reg pseudo; then the pseudo is considered
-            live during the call, but the subreg that is set
-            isn't.  */
-         CLEAR_HARD_REG_SET (this_insn_sets);
-         note_stores (PATTERN (insn), mark_set_regs, &this_insn_sets);
-         /* Sibcalls are considered to set the return value.  */
-         if (SIBLING_CALL_P (insn) && crtl->return_rtx)
-           mark_set_regs (crtl->return_rtx, NULL_RTX, &this_insn_sets);
+         if (r < 0)
+           continue;
 
-         AND_COMPL_HARD_REG_SET (used_regs, call_fixed_reg_set);
-         AND_COMPL_HARD_REG_SET (used_regs, this_insn_sets);
-         AND_HARD_REG_SET (hard_regs_to_save, used_regs);
-         for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
-           if (TEST_HARD_REG_BIT (hard_regs_to_save, regno))
+         bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
+         for (; r < bound; r++)
+           if (TEST_HARD_REG_BIT (used_regs, r))
              {
-               if (hard_reg_map[regno] != NULL)
-                 hard_reg_map[regno]->call_freq += freq;
+               if (hard_reg_map[r] != NULL)
+                 hard_reg_map[r]->call_freq += freq;
                else
-                 saved_reg = new_saved_hard_reg (regno, freq);
+                 saved_reg = new_saved_hard_reg (r, freq);
+                SET_HARD_REG_BIT (hard_regs_to_save, r);
+                SET_HARD_REG_BIT (hard_regs_used, r);
              }
-         /* Look through all live pseudos, mark their hard registers.  */
-         EXECUTE_IF_SET_IN_REG_SET
-           (&chain->live_throughout, FIRST_PSEUDO_REGISTER, regno, rsi)
-           {
-             int r = reg_renumber[regno];
-             int bound;
+       }
+    }
 
-             if (r < 0)
-               continue;
+  /* If requested, figure out which hard regs can share save slots.  */
+  if (optimize && flag_ira_share_save_slots)
+    {
+      rtx slot;
+      char *saved_reg_conflicts;
+      int next_k;
+      struct saved_hard_reg *saved_reg2, *saved_reg3;
+      int call_saved_regs_num;
+      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
+      int best_slot_num;
+      int prev_save_slots_num;
+      rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
 
-             bound = r + hard_regno_nregs[r][PSEUDO_REGNO_MODE (regno)];
-             for (; r < bound; r++)
-               if (TEST_HARD_REG_BIT (used_regs, r))
-                 {
-                   if (hard_reg_map[r] != NULL)
-                     hard_reg_map[r]->call_freq += freq;
-                   else
-                     saved_reg = new_saved_hard_reg (r, freq);
-                   SET_HARD_REG_BIT (hard_regs_to_save, r);
-                 }
-           }
-       }
       /* Find saved hard register conflicts.  */
       saved_reg_conflicts = (char *) xmalloc (saved_regs_num * saved_regs_num);
       memset (saved_reg_conflicts, 0, saved_regs_num * saved_regs_num);
@@ -665,8 +660,10 @@ setup_save_areas (void)
     }
   else
     {
-      /* Now run through all the call-used hard-registers and allocate
-        space for them in the caller-save area.  Try to allocate space
+      /* We are not sharing slots. 
+
+        Run through all the call-used hard-registers and allocate
+        space for each in the caller-save area.  Try to allocate space
         in a manner which allows multi-register saves/restores to be done.  */
 
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)