OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index 90f6da8..abf070d 100644 (file)
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "vecprim.h"
 #include "dbgcnt.h"
 #include "ra.h"
+#include "ira.h"
 
 /* This pass of the compiler performs global register allocation.
    It assigns hard register numbers to all the pseudo registers
@@ -131,31 +132,6 @@ static int local_reg_live_length[FIRST_PSEUDO_REGISTER];
 
 #define SET_REGBIT(TABLE, I, J)  SET_HARD_REG_BIT (allocno[I].TABLE, J)
 
-/* This is turned off because it doesn't work right for DImode.
-   (And it is only used for DImode, so the other cases are worthless.)
-   The problem is that it isn't true that there is NO possibility of conflict;
-   only that there is no conflict if the two pseudos get the exact same regs.
-   If they were allocated with a partial overlap, there would be a conflict.
-   We can't safely turn off the conflict unless we have another way to
-   prevent the partial overlap.
-
-   Idea: change hard_reg_conflicts so that instead of recording which
-   hard regs the allocno may not overlap, it records where the allocno
-   may not start.  Change both where it is used and where it is updated.
-   Then there is a way to record that (reg:DI 108) may start at 10
-   but not at 9 or 11.  There is still the question of how to record
-   this semi-conflict between two pseudos.  */
-#if 0
-/* Reg pairs for which conflict after the current insn
-   is inhibited by a REG_NO_CONFLICT note.
-   If the table gets full, we ignore any other notes--that is conservative.  */
-#define NUM_NO_CONFLICT_PAIRS 4
-/* Number of pairs in use in this insn.  */
-int n_no_conflict_pairs;
-static struct { int allocno1, allocno2;}
-  no_conflict_pairs[NUM_NO_CONFLICT_PAIRS];
-#endif /* 0 */
-
 /* Return true if *LOC contains an asm.  */
 
 static int
@@ -190,11 +166,11 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
       rtx insn;
       FOR_BB_INSNS_REVERSE (bb, insn)
        {
-         struct df_ref **def_rec;
+         df_ref *def_rec;
          if (insn_contains_asm (insn))
            for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
              {
-               struct df_ref *def = *def_rec;
+               df_ref def = *def_rec;
                unsigned int dregno = DF_REF_REGNO (def);
                if (dregno < FIRST_PSEUDO_REGISTER)
                  {
@@ -213,7 +189,7 @@ compute_regs_asm_clobbered (char *regs_asm_clobbered)
 
 /* All registers that can be eliminated.  */
 
-static HARD_REG_SET eliminable_regset;
+HARD_REG_SET eliminable_regset;
 
 static int regno_compare (const void *, const void *);
 static int allocno_compare (const void *, const void *);
@@ -222,7 +198,6 @@ static void prune_preferences (void);
 static void set_preferences (void);
 static void find_reg (int, HARD_REG_SET, int, int, int);
 static void dump_conflicts (FILE *);
-static void build_insn_chain (void);
 \f
 
 /* Look through the list of eliminable registers.  Set ELIM_SET to the
@@ -231,7 +206,9 @@ static void build_insn_chain (void);
 
    This will normally be called with ELIM_SET as the file static
    variable eliminable_regset, and NO_GLOBAL_SET as the file static
-   variable NO_GLOBAL_ALLOC_REGS.  */
+   variable NO_GLOBAL_ALLOC_REGS.
+
+   It also initializes global flag frame_pointer_needed.  */
 
 static void
 compute_regsets (HARD_REG_SET *elim_set, 
@@ -241,17 +218,26 @@ compute_regsets (HARD_REG_SET *elim_set,
 /* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
    Unlike regs_ever_live, elements of this array corresponding to
    eliminable regs like the frame pointer are set if an asm sets them.  */
-  char *regs_asm_clobbered = alloca (FIRST_PSEUDO_REGISTER * sizeof (char));
+  char *regs_asm_clobbered = XALLOCAVEC (char, FIRST_PSEUDO_REGISTER);
 
 #ifdef ELIMINABLE_REGS
   static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
   size_t i;
 #endif
+
+  /* FIXME: If EXIT_IGNORE_STACK is set, we will not save and restore
+     sp for alloca.  So we can't eliminate the frame pointer in that
+     case.  At some point, we should improve this by emitting the
+     sp-adjusting insns for this case.  */
   int need_fp
     = (! flag_omit_frame_pointer
-       || (current_function_calls_alloca && EXIT_IGNORE_STACK)
+       || (cfun->calls_alloca && EXIT_IGNORE_STACK)
+       || crtl->accesses_prior_frames
+       || crtl->stack_realign_needed
        || FRAME_POINTER_REQUIRED);
 
+  frame_pointer_needed = need_fp;
+
   max_regno = max_reg_num ();
   compact_blocks ();
 
@@ -271,7 +257,10 @@ compute_regsets (HARD_REG_SET *elim_set,
     {
       bool cannot_elim
        = (! CAN_ELIMINATE (eliminables[i].from, eliminables[i].to)
-          || (eliminables[i].to == STACK_POINTER_REGNUM && need_fp));
+          || (eliminables[i].to == STACK_POINTER_REGNUM
+              && need_fp 
+              && (! SUPPORTS_STACK_ALIGNMENT
+                  || ! stack_realign_fp)));
 
       if (!regs_asm_clobbered[eliminables[i].from])
        {
@@ -378,7 +367,7 @@ global_alloc (void)
     if (REG_N_REFS (i) != 0 && REG_LIVE_LENGTH (i) != -1
        /* Don't allocate pseudos that cross calls,
           if this function receives a nonlocal goto.  */
-       && (! current_function_has_nonlocal_label
+       && (! cfun->has_nonlocal_label
            || REG_N_CALLS_CROSSED (i) == 0))
       {
        int blk = regno_basic_block (i);
@@ -404,6 +393,7 @@ global_alloc (void)
       allocno[i].reg = regno;
       allocno[i].size = PSEUDO_REGNO_SIZE (regno);
       allocno[i].calls_crossed += REG_N_CALLS_CROSSED (regno);
+      allocno[i].freq_calls_crossed += REG_FREQ_CALLS_CROSSED (regno);
       allocno[i].throwing_calls_crossed
        += REG_N_THROWING_CALLS_CROSSED (regno);
       allocno[i].n_refs += REG_N_REFS (regno);
@@ -992,7 +982,7 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
   int i, best_reg, pass;
   HARD_REG_SET used, used1, used2;
 
-  enum reg_class class = (alt_regs_p
+  enum reg_class rclass = (alt_regs_p
                          ? reg_alternate_class (allocno[num].reg)
                          : reg_preferred_class (allocno[num].reg));
   enum machine_mode mode = PSEUDO_REGNO_MODE (allocno[num].reg);
@@ -1009,7 +999,22 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
   if (losers)
     IOR_HARD_REG_SET (used1, losers);
 
-  IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) class]);
+  IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) rclass]);
+
+#ifdef EH_RETURN_DATA_REGNO
+  if (allocno[num].no_eh_reg)
+    {
+      unsigned int j;
+      for (j = 0; ; ++j)
+       {
+         unsigned int regno = EH_RETURN_DATA_REGNO (j);
+         if (regno == INVALID_REGNUM)
+           break;
+         SET_HARD_REG_BIT (used1, regno);
+       }
+    }
+#endif
+
   COPY_HARD_REG_SET (used2, used1);
 
   IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts);
@@ -1164,8 +1169,9 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
       if (! accept_call_clobbered
          && allocno[num].calls_crossed != 0
          && allocno[num].throwing_calls_crossed == 0
-         && CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
-                                    allocno[num].calls_crossed))
+         && CALLER_SAVE_PROFITABLE (optimize_function_for_size_p (cfun) ? allocno[num].n_refs : allocno[num].freq,
+                                    optimize_function_for_size_p (cfun) ? allocno[num].calls_crossed
+                                    : allocno[num].freq_calls_crossed))
        {
          HARD_REG_SET new_losers;
          if (! losers)
@@ -1349,7 +1355,8 @@ mark_elimination (int from, int to)
 
   FOR_EACH_BB (bb)
     {
-      regset r = DF_LIVE_IN (bb);
+      /* We don't use LIVE info in IRA.  */
+      regset r = (flag_ira ? DF_LR_IN (bb) : DF_LIVE_IN (bb));
       if (REGNO_REG_SET_P (r, from))
        {
          CLEAR_REGNO_REG_SET (r, from);
@@ -1379,11 +1386,22 @@ print_insn_chains (FILE *file)
     print_insn_chain (file, c);
 }
 
+/* Return true if pseudo REGNO should be added to set live_throughout
+   or dead_or_set of the insn chains for reload consideration.  */
+
+static bool
+pseudo_for_reload_consideration_p (int regno)
+{
+  /* Consider spilled pseudos too for IRA because they still have a
+     chance to get hard-registers in the reload when IRA is used.  */
+  return (reg_renumber[regno] >= 0
+         || (flag_ira && ira_conflicts_p && flag_ira_share_spill_slots));
+}
 
 /* Walk the insns of the current function and build reload_insn_chain,
    and record register life information.  */
 
-static void
+void
 build_insn_chain (void)
 {
   unsigned int i;
@@ -1406,7 +1424,6 @@ build_insn_chain (void)
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (TEST_HARD_REG_BIT (eliminable_regset, i))
       bitmap_set_bit (elim_regset, i);
-
   FOR_EACH_BB_REVERSE (bb)
     {
       bitmap_iterator bi;
@@ -1424,7 +1441,7 @@ build_insn_chain (void)
 
       EXECUTE_IF_SET_IN_BITMAP (df_get_live_out (bb), FIRST_PSEUDO_REGISTER, i, bi)
        {
-         if (reg_renumber[i] >= 0)
+         if (pseudo_for_reload_consideration_p (i))
            bitmap_set_bit (live_relevant_regs, i);
        }
 
@@ -1433,8 +1450,8 @@ build_insn_chain (void)
          if (!NOTE_P (insn) && !BARRIER_P (insn))
            {
              unsigned int uid = INSN_UID (insn);
-             struct df_ref **def_rec;
-             struct df_ref **use_rec;
+             df_ref *def_rec;
+             df_ref *use_rec;
 
              c = new_insn_chain ();
              c->next = next;
@@ -1448,7 +1465,7 @@ build_insn_chain (void)
              if (INSN_P (insn))
                for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
                  {
-                   struct df_ref *def = *def_rec;
+                   df_ref def = *def_rec;
                    unsigned int regno = DF_REF_REGNO (def);
                    
                    /* Ignore may clobbers because these are generated
@@ -1461,11 +1478,13 @@ build_insn_chain (void)
                            if (!fixed_regs[regno])
                              bitmap_set_bit (&c->dead_or_set, regno);
                          }
-                       else if (reg_renumber[regno] >= 0)
+                       else if (pseudo_for_reload_consideration_p (regno))
                          bitmap_set_bit (&c->dead_or_set, regno);
                      }
 
-                   if ((regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+                   if ((regno < FIRST_PSEUDO_REGISTER
+                        || reg_renumber[regno] >= 0
+                        || (flag_ira && ira_conflicts_p))
                        && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
                      {
                        rtx reg = DF_REF_REG (def);
@@ -1473,7 +1492,7 @@ build_insn_chain (void)
                        /* We can model subregs, but not if they are
                           wrapped in ZERO_EXTRACTS.  */
                        if (GET_CODE (reg) == SUBREG
-                           && !DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT))
+                           && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
                          {
                            unsigned int start = SUBREG_BYTE (reg);
                            unsigned int last = start 
@@ -1484,6 +1503,17 @@ build_insn_chain (void)
                                                  live_subregs, 
                                                  live_subregs_used,
                                                  regno, reg);
+
+                           if (!DF_REF_FLAGS_IS_SET
+                               (def, DF_REF_STRICT_LOW_PART))
+                             {
+                               /* Expand the range to cover entire words.
+                                  Bytes added here are "don't care".  */
+                               start = start / UNITS_PER_WORD * UNITS_PER_WORD;
+                               last = ((last + UNITS_PER_WORD - 1)
+                                       / UNITS_PER_WORD * UNITS_PER_WORD);
+                             }
+
                            /* Ignore the paradoxical bits.  */
                            if ((int)last > live_subregs_used[regno])
                              last = live_subregs_used[regno];
@@ -1527,7 +1557,7 @@ build_insn_chain (void)
              if (INSN_P (insn))
                for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
                  {
-                   struct df_ref *use = *use_rec;
+                   df_ref use = *use_rec;
                    unsigned int regno = DF_REF_REGNO (use);
                    rtx reg = DF_REF_REG (use);
                    
@@ -1538,7 +1568,7 @@ build_insn_chain (void)
                       precisely so we do not need to look at the
                       fabricated use. */
                    if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE) 
-                       && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT) 
+                       && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT) 
                        && DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
                      continue;
                    
@@ -1550,14 +1580,16 @@ build_insn_chain (void)
                            if (!fixed_regs[regno])
                              bitmap_set_bit (&c->dead_or_set, regno);
                          }
-                       else if (reg_renumber[regno] >= 0)
+                       else if (pseudo_for_reload_consideration_p (regno))
                          bitmap_set_bit (&c->dead_or_set, regno);
                      }
                    
-                   if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
+                   if (regno < FIRST_PSEUDO_REGISTER
+                       || pseudo_for_reload_consideration_p (regno))
                      {
                        if (GET_CODE (reg) == SUBREG
-                           && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT)) 
+                           && !DF_REF_FLAGS_IS_SET (use,
+                                                    DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT)) 
                          {
                            unsigned int start = SUBREG_BYTE (reg);
                            unsigned int last = start 
@@ -1730,6 +1762,13 @@ dump_global_regs (FILE *file)
   fprintf (file, "\n\n");
 }
 
+
+static bool
+gate_handle_global_alloc (void)
+{
+  return ! flag_ira;
+}
+
 /* Run old register allocator.  Return TRUE if we must exit
    rest_of_compilation upon return.  */
 static unsigned int
@@ -1754,7 +1793,7 @@ rest_of_handle_global_alloc (void)
       failure = reload (get_insns (), 0);
     }
 
-  if (dump_enabled_p (pass_global_alloc.static_pass_number))
+  if (dump_enabled_p (pass_global_alloc.pass.static_pass_number))
     {
       timevar_push (TV_DUMP);
       dump_global_regs (dump_file);
@@ -1771,7 +1810,7 @@ rest_of_handle_global_alloc (void)
   reload_completed = !failure;
 
   /* The world has changed so much that at this point we might as well
-     just rescan everything.  Not that df_rescan_all_insns is not
+     just rescan everything.  Note that df_rescan_all_insns is not
      going to help here because it does not touch the artificial uses
      and defs.  */
   df_finish_pass (true);
@@ -1788,10 +1827,12 @@ rest_of_handle_global_alloc (void)
   return 0;
 }
 
-struct tree_opt_pass pass_global_alloc =
+struct rtl_opt_pass pass_global_alloc =
 {
+ {
+  RTL_PASS,
   "greg",                               /* name */
-  NULL,                                 /* gate */
+  gate_handle_global_alloc,             /* gate */
   rest_of_handle_global_alloc,          /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
@@ -1802,7 +1843,7 @@ struct tree_opt_pass pass_global_alloc =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func | TODO_verify_rtl_sharing
-  | TODO_ggc_collect,                   /* todo_flags_finish */
-  'g'                                   /* letter */
+  | TODO_ggc_collect                    /* todo_flags_finish */
+ }
 };