diff gcc/regstat.c @ 0:a06113de4d67

first commit
author kent <kent@cr.ie.u-ryukyu.ac.jp>
date Fri, 17 Jul 2009 14:47:48 +0900
parents
children 77e2b8dfacca
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/regstat.c	Fri Jul 17 14:47:48 2009 +0900
@@ -0,0 +1,513 @@
+/* Scanning of rtl for dataflow analysis.
+   Copyright (C) 2007, 2008
+   Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck (zadeck@naturalbridge.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "flags.h"
+#include "regs.h"
+#include "output.h"
+#include "except.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "timevar.h"
+#include "df.h"
+
+
+struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
+
+/*----------------------------------------------------------------------------
+   REG_N_SETS and REG_N_REFS.  
+   ----------------------------------------------------------------------------*/
+
+/* If a pass need to change these values in some magical way or or the
+   pass needs to have accurate values for these and is not using
+   incremental df scanning, then it should use REG_N_SETS and
+   REG_N_USES.  If the pass is doing incremental scanning then it
+   should be getting the info from DF_REG_DEF_COUNT and
+   DF_REG_USE_COUNT.  */
+
+void
+regstat_init_n_sets_and_refs (void)
+{
+  unsigned int i;
+  unsigned int max_regno = max_reg_num ();
+
+  timevar_push (TV_REG_STATS);
+  df_grow_reg_info ();
+  gcc_assert (!regstat_n_sets_and_refs);
+
+  regstat_n_sets_and_refs = XNEWVEC (struct regstat_n_sets_and_refs_t, max_regno);
+
+  for (i = 0; i < max_regno; i++)
+    {
+      SET_REG_N_SETS (i, DF_REG_DEF_COUNT (i));
+      SET_REG_N_REFS (i, DF_REG_USE_COUNT (i) + REG_N_SETS (i));
+    }
+  timevar_pop (TV_REG_STATS);
+
+}
+
+
+/* Free the array that holds the REG_N_SETS and REG_N_REFS.  */
+
+void
+regstat_free_n_sets_and_refs (void)
+{
+  gcc_assert (regstat_n_sets_and_refs);
+  free (regstat_n_sets_and_refs);
+  regstat_n_sets_and_refs = NULL;
+}
+
+
+/*----------------------------------------------------------------------------
+   REGISTER INFORMATION
+
+   Process REG_N_DEATHS, REG_LIVE_LENGTH, REG_N_CALLS_CROSSED,
+   REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK.
+
+   ----------------------------------------------------------------------------*/
+
+static bitmap setjmp_crosses;
+struct reg_info_t *reg_info_p;
+
+/* The number allocated elements of reg_info_p.  */
+size_t reg_info_p_size;
+
+/* Compute register info: lifetime, bb, and number of defs and uses
+   for basic block BB.  The three bitvectors are scratch regs used
+   here.  */
+
+static void
+regstat_bb_compute_ri (unsigned int bb_index, 
+		       bitmap live, bitmap do_not_gen, bitmap artificial_uses,
+		       bitmap local_live, bitmap local_processed)
+{
+  basic_block bb = BASIC_BLOCK (bb_index);
+  rtx insn;
+  df_ref *def_rec;
+  df_ref *use_rec;
+  int luid = 0;
+  bitmap_iterator bi;
+  unsigned int regno;
+
+  bitmap_copy (live, df_get_live_out (bb));
+  bitmap_clear (artificial_uses);
+
+  /* Process the regs live at the end of the block.  Mark them as
+     not local to any one basic block.  */
+  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+    REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
+
+  /* Process the artificial defs and uses at the bottom of the block
+     to begin processing.  */
+  for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+    {
+      df_ref def = *def_rec;
+      if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
+	bitmap_clear_bit (live, DF_REF_REGNO (def));
+    }
+
+  for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+    {
+      df_ref use = *use_rec;
+      if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
+	{
+	  regno = DF_REF_REGNO (use);
+	  bitmap_set_bit (live, regno);
+	  bitmap_set_bit (artificial_uses, regno);
+	}
+    }
+  
+  FOR_BB_INSNS_REVERSE (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      unsigned int regno;
+      bitmap_iterator bi;
+      struct df_mw_hardreg **mws_rec;
+      rtx link;
+ 
+      if (!INSN_P (insn))
+	continue;
+
+      /* Increment the live_length for all of the registers that
+	 are are referenced in this block and live at this
+	 particular point.  */
+      EXECUTE_IF_SET_IN_BITMAP (local_live, 0, regno, bi)
+	{
+	  REG_LIVE_LENGTH (regno)++;
+	}
+      luid++;
+  
+      bitmap_clear (do_not_gen);
+
+      link = REG_NOTES (insn);
+      while (link)
+	{
+	  if (REG_NOTE_KIND (link) == REG_DEAD)
+	    REG_N_DEATHS(REGNO (XEXP (link, 0)))++;
+	  link = XEXP (link, 1);
+	}
+
+      /* Process the defs.  */
+      if (CALL_P (insn))
+	{
+	  bool can_throw = can_throw_internal (insn); 
+	  bool set_jump = (find_reg_note (insn, REG_SETJMP, NULL) != NULL);
+	  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+	    {
+	      REG_N_CALLS_CROSSED (regno)++;
+	      REG_FREQ_CALLS_CROSSED (regno) += REG_FREQ_FROM_BB (bb);
+	      if (can_throw)
+		REG_N_THROWING_CALLS_CROSSED (regno)++;
+	      
+	      /* We have a problem with any pseudoreg that lives
+		 across the setjmp.  ANSI says that if a user variable
+		 does not change in value between the setjmp and the
+		 longjmp, then the longjmp preserves it.  This
+		 includes longjmp from a place where the pseudo
+		 appears dead.  (In principle, the value still exists
+		 if it is in scope.)  If the pseudo goes in a hard
+		 reg, some other value may occupy that hard reg where
+		 this pseudo is dead, thus clobbering the pseudo.
+		 Conclusion: such a pseudo must not go in a hard
+		 reg.  */
+	      if (set_jump)
+		bitmap_set_bit (setjmp_crosses, regno);
+	    }
+	}
+	  
+      /* We only care about real sets for calls.  Clobbers only
+	 may clobbers cannot be depended on.  */
+      for (mws_rec = DF_INSN_UID_MWS (uid); *mws_rec; mws_rec++)
+	{
+	  struct df_mw_hardreg *mws = *mws_rec; 
+	  if (DF_MWS_REG_DEF_P (mws)) 
+	    {
+	      bool all_dead = true;
+	      unsigned int r;
+	      
+	      for (r=mws->start_regno; r <= mws->end_regno; r++)
+		if ((bitmap_bit_p (live, r))
+		    || bitmap_bit_p (artificial_uses, r))
+		  {
+		    all_dead = false;
+		    break;
+		  }
+	      
+	      if (all_dead)
+		{
+		  unsigned int regno = mws->start_regno;
+		  bitmap_set_bit (do_not_gen, regno);
+		  /* Only do this if the value is totally dead.  */
+		  REG_LIVE_LENGTH (regno)++;
+		}
+	    }
+	}
+      
+      /* All of the defs except the return value are some sort of
+	 clobber.  This code is for the return.  */
+      for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+	{
+	  df_ref def = *def_rec;
+	  if ((!CALL_P (insn))
+	      || (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))))
+	    {
+	      unsigned int dregno = DF_REF_REGNO (def);
+	      
+	      if (bitmap_bit_p (live, dregno))
+		{
+		  /* If we have seen this regno, then it has already been
+		     processed correctly with the per insn increment.  If we
+		     have not seen it we need to add the length from here to
+		     the end of the block to the live length.  */
+		  if (bitmap_bit_p (local_processed, dregno))
+		    {
+		      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+			bitmap_clear_bit (local_live, dregno);
+		    }
+		  else
+		    {
+		      bitmap_set_bit (local_processed, dregno);
+		      REG_LIVE_LENGTH (dregno) += luid;
+		    }
+		}
+	      else if ((!(DF_REF_FLAGS (def) & DF_REF_MW_HARDREG))
+		       && (!bitmap_bit_p (artificial_uses, dregno)))
+		{
+		  REG_LIVE_LENGTH (dregno)++;
+		}
+	      
+	      if (dregno >= FIRST_PSEUDO_REGISTER)
+		{
+		  REG_FREQ (dregno) += REG_FREQ_FROM_BB (bb);
+		  if (REG_BASIC_BLOCK (dregno) == REG_BLOCK_UNKNOWN)
+		    REG_BASIC_BLOCK (dregno) = bb->index;
+		  else if (REG_BASIC_BLOCK (dregno) != bb->index)
+		    REG_BASIC_BLOCK (dregno) = REG_BLOCK_GLOBAL;
+		}
+	      
+	      if (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER + DF_REF_MAY_CLOBBER)))
+		bitmap_set_bit (do_not_gen, dregno);
+	      
+	      /* Kill this register if it is not a subreg store or conditional store.  */
+	      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+		bitmap_clear_bit (live, dregno);
+	    }
+	}
+      
+      for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+	{
+	  df_ref use = *use_rec;
+	  unsigned int uregno = DF_REF_REGNO (use);
+
+	  if (uregno >= FIRST_PSEUDO_REGISTER)
+	    {
+	      REG_FREQ (uregno) += REG_FREQ_FROM_BB (bb);
+	      if (REG_BASIC_BLOCK (uregno) == REG_BLOCK_UNKNOWN)
+		REG_BASIC_BLOCK (uregno) = bb->index;
+	      else if (REG_BASIC_BLOCK (uregno) != bb->index)
+		REG_BASIC_BLOCK (uregno) = REG_BLOCK_GLOBAL;
+	    }
+	  
+	  if (!bitmap_bit_p (live, uregno))
+	    {
+	      /* This register is now live.  */
+	      bitmap_set_bit (live, uregno);
+
+	      /* If we have seen this regno, then it has already been
+		 processed correctly with the per insn increment.  If
+		 we have not seen it we set the bit so that begins to
+		 get processed locally.  Note that we don't even get
+		 here if the variable was live at the end of the block
+		 since just a ref inside the block does not effect the
+		 calculations.  */
+	      REG_LIVE_LENGTH (uregno) ++;
+	      bitmap_set_bit (local_live, uregno);
+	      bitmap_set_bit (local_processed, uregno);
+	    }
+	}
+    }
+  
+  /* Add the length of the block to all of the registers that were not
+     referenced, but still live in this block.  */
+  bitmap_and_compl_into (live, local_processed);
+  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+    REG_LIVE_LENGTH (regno) += luid;
+
+  bitmap_clear (local_processed);
+  bitmap_clear (local_live);
+}
+
+
+/* Compute register info: lifetime, bb, and number of defs and uses.  */
+void
+regstat_compute_ri (void)
+{
+  basic_block bb;
+  bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap do_not_gen = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap artificial_uses = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap local_live = BITMAP_ALLOC (&df_bitmap_obstack);
+  bitmap local_processed = BITMAP_ALLOC (&df_bitmap_obstack);
+  unsigned int regno;
+  bitmap_iterator bi;
+
+  /* Initialize everything.  */
+
+  gcc_assert (!reg_info_p);
+
+  timevar_push (TV_REG_STATS);
+  setjmp_crosses = BITMAP_ALLOC (&df_bitmap_obstack);
+  max_regno = max_reg_num ();
+  reg_info_p_size = max_regno;
+  reg_info_p = XCNEWVEC (struct reg_info_t, max_regno);
+
+  FOR_EACH_BB (bb)
+    {
+      regstat_bb_compute_ri (bb->index, live, do_not_gen, artificial_uses,
+			     local_live, local_processed);
+    }
+
+  BITMAP_FREE (live);
+  BITMAP_FREE (do_not_gen);
+  BITMAP_FREE (artificial_uses);
+
+  /* See the setjmp comment in regstat_ri_bb_compute.  */
+  EXECUTE_IF_SET_IN_BITMAP (setjmp_crosses, FIRST_PSEUDO_REGISTER, regno, bi)
+    {
+      REG_BASIC_BLOCK (regno) = REG_BLOCK_UNKNOWN;
+      REG_LIVE_LENGTH (regno) = -1;
+    }	  
+  
+  BITMAP_FREE (local_live);
+  BITMAP_FREE (local_processed);
+  timevar_pop (TV_REG_STATS);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+void
+regstat_free_ri (void)
+{
+  gcc_assert (reg_info_p);
+  reg_info_p_size = 0;
+  free (reg_info_p); 
+  reg_info_p = NULL;
+
+  BITMAP_FREE (setjmp_crosses);
+}
+
+
+/* Return a bitmap containing the set of registers that cross a setjmp.  
+   The client should not change or delete this bitmap.  */
+
+bitmap
+regstat_get_setjmp_crosses (void)
+{
+  return setjmp_crosses;
+}
+
+/*----------------------------------------------------------------------------
+   Process REG_N_CALLS_CROSSED.  
+
+   This is used by sched_deps.  A good implementation of sched-deps
+   would really process the blocks directly rather than going through
+   lists of insns.  If it did this, it could use the exact regs that
+   cross an individual call rather than using this info that merges
+   the info for all calls.
+
+   ----------------------------------------------------------------------------*/
+
+
+
+/* Compute calls crossed for BB. Live is a scratch bitvector.  */
+
+static void
+regstat_bb_compute_calls_crossed (unsigned int bb_index, bitmap live)
+{
+  basic_block bb = BASIC_BLOCK (bb_index);
+  rtx insn;
+  df_ref *def_rec;
+  df_ref *use_rec;
+
+  bitmap_copy (live, df_get_live_out (bb));
+
+  /* Process the artificial defs and uses at the bottom of the block
+     to begin processing.  */
+  for (def_rec = df_get_artificial_defs (bb_index); *def_rec; def_rec++)
+    {
+      df_ref def = *def_rec;
+      if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) == 0)
+	bitmap_clear_bit (live, DF_REF_REGNO (def));
+    }
+
+  for (use_rec = df_get_artificial_uses (bb_index); *use_rec; use_rec++)
+    {
+      df_ref use = *use_rec;
+      if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == 0)
+	bitmap_set_bit (live, DF_REF_REGNO (use));
+    }
+  
+  FOR_BB_INSNS_REVERSE (bb, insn)
+    {
+      unsigned int uid = INSN_UID (insn);
+      unsigned int regno;
+ 
+      if (!INSN_P (insn))
+	continue;
+
+      /* Process the defs.  */
+      if (CALL_P (insn))
+	{
+	  bitmap_iterator bi;
+	  EXECUTE_IF_SET_IN_BITMAP (live, 0, regno, bi)
+	    {
+	      REG_N_CALLS_CROSSED (regno)++;
+	      REG_FREQ_CALLS_CROSSED (regno) += REG_FREQ_FROM_BB (bb);
+	    }
+	}
+	  
+      /* All of the defs except the return value are some sort of
+	 clobber.  This code is for the return.  */
+      for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+	{
+	  df_ref def = *def_rec;
+	  if ((!CALL_P (insn))
+	      || (!(DF_REF_FLAGS (def) & (DF_REF_MUST_CLOBBER | DF_REF_MAY_CLOBBER))))
+	    {
+	      /* Kill this register if it is not a subreg store or conditional store.  */
+	      if (!(DF_REF_FLAGS (def) & (DF_REF_PARTIAL | DF_REF_CONDITIONAL)))
+		bitmap_clear_bit (live, DF_REF_REGNO (def));
+	    }
+	}
+      
+      for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+	{
+	  df_ref use = *use_rec;
+	  bitmap_set_bit (live, DF_REF_REGNO (use));
+	}
+    }
+}
+
+
+/* Compute register info: lifetime, bb, and number of defs and uses.  */
+void
+regstat_compute_calls_crossed (void)
+{
+  basic_block bb;
+  bitmap live = BITMAP_ALLOC (&df_bitmap_obstack);
+
+  /* Initialize everything.  */
+  gcc_assert (!reg_info_p);
+
+  timevar_push (TV_REG_STATS);
+  max_regno = max_reg_num ();
+  reg_info_p_size = max_regno;
+  reg_info_p = XCNEWVEC (struct reg_info_t, max_regno);
+
+  FOR_EACH_BB (bb)
+    {
+      regstat_bb_compute_calls_crossed (bb->index, live);
+    }
+
+  BITMAP_FREE (live);
+  timevar_pop (TV_REG_STATS);
+}
+
+
+/* Free all storage associated with the problem.  */
+
+void
+regstat_free_calls_crossed (void)
+{
+  gcc_assert (reg_info_p);
+  reg_info_p_size = 0;
+  free (reg_info_p); 
+  reg_info_p = NULL;
+}
+