Mercurial > hg > CbC > CbC_gcc
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; +} +