OSDN Git Service

Merge dataflow branch into mainline
[pf3gnuchains/gcc-fork.git] / gcc / config / sh / sh.c
index d8825d0..4ca2d5c 100644 (file)
@@ -1,6 +1,6 @@
 /* Output routines for GCC for Renesas / SuperH SH.
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Steve Chamberlain (sac@cygnus.com).
    Improved by Jim Wilson (wilson@cygnus.com).
 
@@ -47,6 +47,7 @@ Boston, MA 02110-1301, USA.  */
 #include "real.h"
 #include "langhooks.h"
 #include "basic-block.h"
+#include "df.h"
 #include "cfglayout.h"
 #include "intl.h"
 #include "sched-int.h"
@@ -88,6 +89,9 @@ static short *regmode_weight[2];
 /* Total SFmode and SImode weights of scheduled insns.  */
 static int curr_regmode_pressure[2];
 
+/* Number of r0 life regions.  */
+static int r0_life_regions;
+
 /* If true, skip cycles for Q -> R movement.  */
 static int skip_cycles = 0;
 
@@ -195,6 +199,7 @@ static int sh_dfa_new_cycle (FILE *, int, rtx, int, int, int *sort_p);
 static short find_set_regmode_weight (rtx, enum machine_mode);
 static short find_insn_regmode_weight (rtx, enum machine_mode);
 static void find_regmode_weight (basic_block, enum machine_mode);
+static int find_r0_life_regions (basic_block);
 static void  sh_md_init_global (FILE *, int, int);
 static void  sh_md_finish_global (FILE *, int);
 static int rank_for_reorder (const void *, const void *);
@@ -4757,51 +4762,25 @@ sh_reorg (void)
          if (GET_CODE (reg) != REG)
            continue;
 
-         /* This is a function call via REG.  If the only uses of REG
-            between the time that it is set and the time that it dies
-            are in function calls, then we can associate all the
-            function calls with the setting of REG.  */
-
-         for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
-           {
-             rtx linked_insn;
-
-             if (REG_NOTE_KIND (link) != 0)
-               continue;
-             linked_insn = XEXP (link, 0);
-             set = single_set (linked_insn);
-             if (set
-                 && rtx_equal_p (reg, SET_DEST (set))
-                 && ! INSN_DELETED_P (linked_insn))
-               {
-                 link = linked_insn;
-                 break;
-               }
-           }
-
-         if (! link)
+         /* Try scanning backward to find where the register is set.  */
+         link = NULL;
+         for (scan = PREV_INSN (insn);
+              scan && GET_CODE (scan) != CODE_LABEL;
+              scan = PREV_INSN (scan))
            {
-             /* ??? Sometimes global register allocation will have
-                 deleted the insn pointed to by LOG_LINKS.  Try
-                 scanning backward to find where the register is set.  */
-             for (scan = PREV_INSN (insn);
-                  scan && GET_CODE (scan) != CODE_LABEL;
-                  scan = PREV_INSN (scan))
-               {
-                 if (! INSN_P (scan))
-                   continue;
+             if (! INSN_P (scan))
+               continue;
 
-                 if (! reg_mentioned_p (reg, scan))
-                   continue;
+             if (! reg_mentioned_p (reg, scan))
+               continue;
 
-                 if (noncall_uses_reg (reg, scan, &set))
-                   break;
+             if (noncall_uses_reg (reg, scan, &set))
+               break;
 
-                 if (set)
-                   {
-                     link = scan;
-                     break;
-                   }
+             if (set)
+               {
+                 link = scan;
+                 break;
                }
            }
 
@@ -4833,7 +4812,7 @@ sh_reorg (void)
 
              /* Don't try to trace forward past a CODE_LABEL if we haven't
                 seen INSN yet.  Ordinarily, we will only find the setting insn
-                in LOG_LINKS if it is in the same basic block.  However,
+                if it is in the same basic block.  However,
                 cross-jumping can insert code labels in between the load and
                 the call, and can result in situations where a single call
                 insn may have two targets depending on where we came from.  */
@@ -4880,11 +4859,8 @@ sh_reorg (void)
                 later insn.  */
 
              /* ??? We shouldn't have to use FOUNDINSN here.
-                However, the LOG_LINKS fields are apparently not
-                entirely reliable around libcalls;
-                newlib/libm/math/e_pow.c is a test case.  Sometimes
-                an insn will appear in LOG_LINKS even though it is
-                not the most recent insn which sets the register.  */
+                This dates back to when we used LOG_LINKS to find 
+                the most recent insn which sets the register.  */
 
              if (foundinsn
                  && (scanset
@@ -5849,12 +5825,12 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
 
   CLEAR_HARD_REG_SET (*live_regs_mask);
   if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler
-      && regs_ever_live[FPSCR_REG])
+      && df_regs_ever_live_p (FPSCR_REG))
     target_flags &= ~MASK_FPU_SINGLE;
   /* If we can save a lot of saves by switching to double mode, do that.  */
   else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && TARGET_FPU_SINGLE)
     for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
-      if (regs_ever_live[reg] && regs_ever_live[reg+1]
+      if (df_regs_ever_live_p (reg) && df_regs_ever_live_p (reg+1)
          && (! call_really_used_regs[reg]
              || interrupt_handler)
          && ++count > 2)
@@ -5876,11 +5852,11 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
       pr_live = (pr_initial
                 ? (GET_CODE (pr_initial) != REG
                    || REGNO (pr_initial) != (PR_REG))
-                : regs_ever_live[PR_REG]);
+                : df_regs_ever_live_p (PR_REG));
       /* For Shcompact, if not optimizing, we end up with a memory reference
         using the return address pointer for __builtin_return_address even
         though there is no actual need to put the PR register on the stack.  */
-      pr_live |= regs_ever_live[RETURN_ADDRESS_POINTER_REGNUM];
+      pr_live |= df_regs_ever_live_p (RETURN_ADDRESS_POINTER_REGNUM);
     }
   /* Force PR to be live if the prologue has to call the SHmedia
      argument decoder or register saver.  */
@@ -5896,7 +5872,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
          ? pr_live
          : interrupt_handler
          ? (/* Need to save all the regs ever live.  */
-            (regs_ever_live[reg]
+            (df_regs_ever_live_p (reg)
              || (call_really_used_regs[reg]
                  && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
                      || reg == PIC_OFFSET_TABLE_REGNUM)
@@ -5914,7 +5890,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
              && flag_pic
              && current_function_args_info.call_cookie
              && reg == PIC_OFFSET_TABLE_REGNUM)
-            || (regs_ever_live[reg]
+            || (df_regs_ever_live_p (reg)
                 && (!call_really_used_regs[reg]
                     || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
             || (current_function_calls_eh_return
@@ -5923,7 +5899,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
                     || reg == EH_RETURN_DATA_REGNO (2)
                     || reg == EH_RETURN_DATA_REGNO (3)))
             || ((reg == MACL_REG || reg == MACH_REG)
-                && regs_ever_live[reg]
+                && df_regs_ever_live_p (reg)
                 && sh_cfun_attr_renesas_p ())
             ))
        {
@@ -5935,7 +5911,7 @@ calc_live_regs (HARD_REG_SET *live_regs_mask)
            {
              if (FP_REGISTER_P (reg))
                {
-                 if (! TARGET_FPU_SINGLE && ! regs_ever_live[reg ^ 1])
+                 if (! TARGET_FPU_SINGLE && ! df_regs_ever_live_p (reg ^ 1))
                    {
                      SET_HARD_REG_BIT (*live_regs_mask, (reg ^ 1));
                      count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg ^ 1));
@@ -6012,10 +5988,10 @@ sh_media_register_for_return (void)
   if (sh_cfun_interrupt_handler_p ())
     return -1;
 
-  tr0_used = flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
+  tr0_used = flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM);
 
   for (regno = FIRST_TARGET_REG + tr0_used; regno <= LAST_TARGET_REG; regno++)
-    if (call_really_used_regs[regno] && ! regs_ever_live[regno])
+    if (call_really_used_regs[regno] && ! df_regs_ever_live_p (regno))
       return regno;
 
   return -1;
@@ -6174,7 +6150,7 @@ sh_expand_prologue (void)
        incoming-argument decoder and/or of the return trampoline from
        the GOT, so make sure the PIC register is preserved and
        initialized.  */
-    regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
+    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
 
   if (TARGET_SHCOMPACT
       && (current_function_args_info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
@@ -6207,19 +6183,8 @@ sh_expand_prologue (void)
       int tr = sh_media_register_for_return ();
 
       if (tr >= 0)
-       {
-         rtx insn = emit_move_insn (gen_rtx_REG (DImode, tr),
-                                    gen_rtx_REG (DImode, PR_MEDIA_REG));
-
-         /* ??? We should suppress saving pr when we don't need it, but this
-            is tricky because of builtin_return_address.  */
-
-         /* If this function only exits with sibcalls, this copy
-            will be flagged as dead.  */
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                               const0_rtx,
-                                               REG_NOTES (insn));
-       }
+       emit_move_insn (gen_rtx_REG (DImode, tr),
+                       gen_rtx_REG (DImode, PR_MEDIA_REG));
     }
 
   /* Emit the code for SETUP_VARARGS.  */
@@ -6467,24 +6432,8 @@ sh_expand_prologue (void)
   else
     push_regs (&live_regs_mask, current_function_interrupt);
 
-  if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-    {
-      rtx insn = get_last_insn ();
-      rtx last = emit_insn (gen_GOTaddr2picreg ());
-
-      /* Mark these insns as possibly dead.  Sometimes, flow2 may
-        delete all uses of the PIC register.  In this case, let it
-        delete the initialization too.  */
-      do
-       {
-         insn = NEXT_INSN (insn);
-
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                               const0_rtx,
-                                               REG_NOTES (insn));
-       }
-      while (insn != last);
-    }
+  if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+    emit_insn (gen_GOTaddr2picreg ());
 
   if (SHMEDIA_REGS_STACK_ADJUST ())
     {
@@ -6499,16 +6448,7 @@ sh_expand_prologue (void)
     }
 
   if (target_flags != save_flags && ! current_function_interrupt)
-    {
-      rtx insn = emit_insn (gen_toggle_sz ());
-
-      /* If we're lucky, a mode switch in the function body will
-        overwrite fpscr, turning this insn dead.  Tell flow this
-        insn is ok to delete.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                           const0_rtx,
-                                           REG_NOTES (insn));
-    }
+    emit_insn (gen_toggle_sz ());
 
   target_flags = save_flags;
 
@@ -6729,11 +6669,6 @@ sh_expand_epilogue (bool sibcall_p)
            }
 
          insn = emit_move_insn (reg_rtx, mem_rtx);
-         if (reg == PR_MEDIA_REG && sh_media_register_for_return () >= 0)
-           /* This is dead, unless we return with a sibcall.  */
-           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                                 const0_rtx,
-                                                 REG_NOTES (insn));
        }
 
       gcc_assert (entry->offset + offset_base == d + d_rounding);
@@ -6742,7 +6677,11 @@ sh_expand_epilogue (bool sibcall_p)
     {
       save_size = 0;
       if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
-       pop (PR_REG);
+       {
+         if (!frame_pointer_needed)
+           emit_insn (gen_blockage ());
+         pop (PR_REG);
+       }
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        {
          int j = (FIRST_PSEUDO_REGISTER - 1) - i;
@@ -8799,7 +8738,7 @@ sh_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
      saved by the prologue, even if they would normally be
      call-clobbered.  */
 
-  if (sh_cfun_interrupt_handler_p () && !regs_ever_live[new_reg])
+  if (sh_cfun_interrupt_handler_p () && !df_regs_ever_live_p (new_reg))
     return 0;
 
   return 1;
@@ -9039,7 +8978,7 @@ flow_dependent_p_1 (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data)
 static int
 sh_pr_n_sets (void)
 {
-  return REG_N_SETS (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
+  return DF_REG_DEF_COUNT (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
 }
 
 /* Return where to allocate pseudo for a given hard register initial
@@ -9206,6 +9145,56 @@ ready_reorder (rtx *ready, int nready)
   SCHED_REORDER (ready, nready);
 }
 
+/* Count life regions of r0 for a block.  */
+static int
+find_r0_life_regions (basic_block b)
+{
+  rtx end, insn;
+  rtx pset;
+  rtx r0_reg;
+  int live;
+  int set;
+  int death = 0;
+
+  if (REGNO_REG_SET_P (DF_LIVE_IN (b), R0_REG))
+    {
+      set = 1;
+      live = 1;
+    }
+  else
+    {
+      set = 0;
+      live = 0;
+    }
+
+  insn = BB_HEAD (b);
+  end = BB_END (b);
+  r0_reg = gen_rtx_REG (SImode, R0_REG);
+  while (1)
+    {
+      if (INSN_P (insn))
+       {
+         if (find_regno_note (insn, REG_DEAD, R0_REG))
+           {
+             death++;
+             live = 0;
+           }
+         if (!live
+             && (pset = single_set (insn))
+             && reg_overlap_mentioned_p (r0_reg, SET_DEST (pset))
+             && !find_regno_note (insn, REG_UNUSED, R0_REG))
+           {
+             set++;
+             live = 1;
+           }
+       }
+      if (insn == end)
+       break;
+      insn = NEXT_INSN (insn);
+    }
+  return set - death;
+}
+
 /* Calculate regmode weights for all insns of all basic block.  */
 static void
 sh_md_init_global (FILE *dump ATTRIBUTE_UNUSED,
@@ -9216,11 +9205,14 @@ sh_md_init_global (FILE *dump ATTRIBUTE_UNUSED,
 
   regmode_weight[0] = (short *) xcalloc (old_max_uid, sizeof (short));
   regmode_weight[1] = (short *) xcalloc (old_max_uid, sizeof (short));
+  r0_life_regions = 0;
 
   FOR_EACH_BB_REVERSE (b)
   {
     find_regmode_weight (b, SImode);
     find_regmode_weight (b, SFmode);
+    if (!reload_completed)
+      r0_life_regions += find_r0_life_regions (b);
   }
 
   CURR_REGMODE_PRESSURE (SImode) = 0;
@@ -9281,7 +9273,6 @@ sh_md_init (FILE *dump ATTRIBUTE_UNUSED,
 /* Pressure on register r0 can lead to spill failures. so avoid sched1 for
    functions that already have high pressure on r0. */
 #define R0_MAX_LIFE_REGIONS 2
-#define R0_MAX_LIVE_LENGTH 12
 /* Register Pressure thresholds for SImode and SFmode registers.  */
 #define SIMODE_MAX_WEIGHT 5
 #define SFMODE_MAX_WEIGHT 10
@@ -9292,9 +9283,8 @@ high_pressure (enum machine_mode mode)
 {
   /* Pressure on register r0 can lead to spill failures. so avoid sched1 for
      functions that already have high pressure on r0. */
-  if ((REG_N_SETS (0) - REG_N_DEATHS (0)) >= R0_MAX_LIFE_REGIONS
-      && REG_LIVE_LENGTH (0) >= R0_MAX_LIVE_LENGTH)
-    return 1;
+   if (r0_life_regions >= R0_MAX_LIFE_REGIONS)
+     return 1;
 
   if (mode == SFmode)
     return (CURR_REGMODE_PRESSURE (SFmode) > SFMODE_MAX_WEIGHT);
@@ -10275,6 +10265,7 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   insn_locators_alloc ();
   insns = get_insns ();
 
+#if 0
   if (optimize > 0)
     {
       /* Initialize the bitmap obstacks.  */
@@ -10301,6 +10292,14 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
       else if (flag_pic)
        split_all_insns_noflow ();
     }
+#else
+  if (optimize > 0)
+    {
+      if (! cfun->cfg)
+       init_flow ();
+      split_all_insns_noflow ();
+    }
+#endif
 
   sh_reorg ();
 
@@ -10312,15 +10311,21 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   final (insns, file, 1);
   final_end_function ();
 
+#if 0
   if (optimize > 0)
     {
-      /* Release all memory allocated by flow.  */
-      free_basic_block_vars ();
+      /* Release all memory allocated by df.  */
+      if (rtl_df)
+       {
+         df_finish (rtl_df);
+         rtl_df = NULL;
+       }
 
       /* Release the bitmap obstacks.  */
       bitmap_obstack_release (&reg_obstack);
       bitmap_obstack_release (NULL);
     }
+#endif
 
   reload_completed = 0;
   epilogue_completed = 0;