OSDN Git Service

2009-01-03 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / global.c
index b8a0ec7..824fcf0 100644 (file)
@@ -131,31 +131,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 +165,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 +188,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 +197,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 +205,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 +217,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 +256,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 +366,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);
@@ -993,7 +981,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);
@@ -1010,7 +998,7 @@ 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)
@@ -1180,8 +1168,8 @@ 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 (optimize_size ? allocno[num].n_refs : allocno[num].freq,
-                                    optimize_size ? 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;
@@ -1366,7 +1354,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);
@@ -1396,11 +1385,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 && optimize && 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;
@@ -1423,7 +1423,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;
@@ -1441,7 +1440,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);
        }
 
@@ -1450,8 +1449,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;
@@ -1465,7 +1464,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
@@ -1478,11 +1477,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 && optimize))
                        && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
                      {
                        rtx reg = DF_REF_REG (def);
@@ -1490,7 +1491,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 
@@ -1501,6 +1502,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];
@@ -1544,7 +1556,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);
                    
@@ -1555,7 +1567,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;
                    
@@ -1567,14 +1579,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 
@@ -1747,6 +1761,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
@@ -1771,7 +1792,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);
@@ -1805,10 +1826,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 */
@@ -1819,7 +1842,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 */
+ }
 };