X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fweb.c;h=7f5ae67d9af069038cad299a25a885502b0f6f08;hp=e846ee1d2fc7836a9141a938e16893d2310d9ac4;hb=eebb423d73c49ec76fe9c1813616aa8bea4a1cb2;hpb=40e55fbbd58fe04a45af0335bc0b945cec36c9c9 diff --git a/gcc/web.c b/gcc/web.c index e846ee1d2fc..7f5ae67d9af 100644 --- a/gcc/web.c +++ b/gcc/web.c @@ -1,6 +1,7 @@ /* Web construction code for GNU compiler. Contributed by Jan Hubicka. - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2004, 2006 + Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +17,8 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ /* Simple optimization pass that splits independent uses of each pseudo, increasing effectiveness of other optimizations. The optimization can @@ -51,32 +52,21 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "rtl.h" #include "hard-reg-set.h" #include "flags.h" +#include "obstack.h" #include "basic-block.h" #include "output.h" #include "df.h" #include "function.h" +#include "timevar.h" +#include "tree-pass.h" -/* This entry is allocated for each reference in the insn stream. */ -struct web_entry -{ - /* Pointer to the parent in the union/find tree. */ - struct web_entry *pred; - /* Newly assigned register to the entry. Set only for roots. */ - rtx reg; -}; - -static struct web_entry *unionfind_root (struct web_entry *); -static void unionfind_union (struct web_entry *, struct web_entry *); -static void union_defs (struct df *, struct ref *, struct web_entry *, - struct web_entry *); -static rtx entry_register (struct web_entry *, struct ref *, char *, char *); -static void replace_ref (struct ref *, rtx); -static int mark_addressof (rtx *, void *); +static rtx entry_register (struct web_entry *, struct df_ref *, char *); +static void replace_ref (struct df_ref *, rtx); /* Find the root of unionfind tree (the representative of set). */ -static struct web_entry * +struct web_entry * unionfind_root (struct web_entry *element) { struct web_entry *element1 = element, *element2; @@ -92,30 +82,48 @@ unionfind_root (struct web_entry *element) return element; } -/* Union sets. */ +/* Union sets. + Return true if FIRST and SECOND points to the same web entry structure and + nothing is done. Otherwise, return false. */ -static void +bool unionfind_union (struct web_entry *first, struct web_entry *second) { first = unionfind_root (first); second = unionfind_root (second); if (first == second) - return; + return true; second->pred = first; + return false; } /* For each use, all possible defs reaching it must come in the same - register, union them. */ + register, union them. + FUN is the function that does the union. */ -static void -union_defs (struct df *df, struct ref *use, struct web_entry *def_entry, - struct web_entry *use_entry) +void +union_defs (struct df *df, struct df_ref *use, struct web_entry *def_entry, + struct web_entry *use_entry, + bool (*fun) (struct web_entry *, struct web_entry *)) { rtx insn = DF_REF_INSN (use); struct df_link *link = DF_REF_CHAIN (use); - struct df_link *use_link = DF_INSN_USES (df, insn); - struct df_link *def_link = DF_INSN_DEFS (df, insn); - rtx set = single_set (insn); + struct df_ref *use_link; + struct df_ref *def_link; + rtx set; + + if (insn) + { + use_link = DF_INSN_USES (df, insn); + def_link = DF_INSN_DEFS (df, insn); + set = single_set (insn); + } + else + { + use_link = NULL; + def_link = NULL; + set = NULL; + } /* Some instructions may use match_dup for their operands. In case the operands are dead, we will assign them different pseudos, creating @@ -124,11 +132,11 @@ union_defs (struct df *df, struct ref *use, struct web_entry *def_entry, while (use_link) { - if (use != use_link->ref - && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (use_link->ref)) - unionfind_union (use_entry + DF_REF_ID (use), - use_entry + DF_REF_ID (use_link->ref)); - use_link = use_link->next; + if (use != use_link + && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (use_link)) + (*fun) (use_entry + DF_REF_ID (use), + use_entry + DF_REF_ID (use_link)); + use_link = use_link->next_ref; } /* Recognize trivial noop moves and attempt to keep them as noop. @@ -141,16 +149,16 @@ union_defs (struct df *df, struct ref *use, struct web_entry *def_entry, { while (def_link) { - if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def_link->ref)) - unionfind_union (use_entry + DF_REF_ID (use), - def_entry + DF_REF_ID (def_link->ref)); - def_link = def_link->next; + if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def_link)) + (*fun) (use_entry + DF_REF_ID (use), + def_entry + DF_REF_ID (def_link)); + def_link = def_link->next_ref; } } while (link) { - unionfind_union (use_entry + DF_REF_ID (use), - def_entry + DF_REF_ID (link->ref)); + (*fun) (use_entry + DF_REF_ID (use), + def_entry + DF_REF_ID (link->ref)); link = link->next; } @@ -158,21 +166,27 @@ union_defs (struct df *df, struct ref *use, struct web_entry *def_entry, register. Find it and union. */ if (use->flags & DF_REF_READ_WRITE) { - struct df_link *link = DF_INSN_DEFS (df, DF_REF_INSN (use)); + struct df_ref *link; - while (DF_REF_REAL_REG (link->ref) != DF_REF_REAL_REG (use)) - link = link->next; + if (DF_REF_INSN (use)) + link = DF_INSN_DEFS (df, DF_REF_INSN (use)); + else + link = NULL; - unionfind_union (use_entry + DF_REF_ID (use), - def_entry + DF_REF_ID (link->ref)); + while (link) + { + if (DF_REF_REAL_REG (link) == DF_REF_REAL_REG (use)) + (*fun) (use_entry + DF_REF_ID (use), + def_entry + DF_REF_ID (link)); + link = link->next_ref; + } } } /* Find the corresponding register for the given entry. */ static rtx -entry_register (struct web_entry *entry, struct ref *ref, char *used, - char *use_addressof) +entry_register (struct web_entry *entry, struct df_ref *ref, char *used) { struct web_entry *root; rtx reg, newreg; @@ -191,29 +205,19 @@ entry_register (struct web_entry *entry, struct ref *ref, char *used, else if (REG_USERVAR_P (reg) && 0/*&& !flag_messy_debugging*/) { newreg = reg; - if (rtl_dump_file) - fprintf (rtl_dump_file, + if (dump_file) + fprintf (dump_file, "New web forced to keep reg=%i (user variable)\n", REGNO (reg)); } - else if (use_addressof [REGNO (reg)]) - { - newreg = reg; - if (rtl_dump_file) - fprintf (rtl_dump_file, - "New web forced to keep reg=%i (address taken)\n", - REGNO (reg)); - } else { newreg = gen_reg_rtx (GET_MODE (reg)); REG_USERVAR_P (newreg) = REG_USERVAR_P (reg); REG_POINTER (newreg) = REG_POINTER (reg); - REG_LOOP_TEST_P (newreg) = REG_LOOP_TEST_P (reg); - RTX_UNCHANGING_P (newreg) = RTX_UNCHANGING_P (reg); REG_ATTRS (newreg) = REG_ATTRS (reg); - if (rtl_dump_file) - fprintf (rtl_dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg), + if (dump_file) + fprintf (dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg), REGNO (newreg)); } @@ -224,35 +228,22 @@ entry_register (struct web_entry *entry, struct ref *ref, char *used, /* Replace the reference by REG. */ static void -replace_ref (struct ref *ref, rtx reg) +replace_ref (struct df_ref *ref, rtx reg) { rtx oldreg = DF_REF_REAL_REG (ref); rtx *loc = DF_REF_REAL_LOC (ref); if (oldreg == reg) return; - if (rtl_dump_file) - fprintf (rtl_dump_file, "Updating insn %i (%i->%i)\n", + if (dump_file) + fprintf (dump_file, "Updating insn %i (%i->%i)\n", INSN_UID (DF_REF_INSN (ref)), REGNO (oldreg), REGNO (reg)); *loc = reg; } -/* Mark each pseudo whose address is taken. */ - -static int -mark_addressof (rtx *rtl, void *data) -{ - if (!*rtl) - return 0; - if (GET_CODE (*rtl) == ADDRESSOF - && REG_P (XEXP (*rtl, 0))) - ((char *)data)[REGNO (XEXP (*rtl, 0))] = 1; - return 0; -} - /* Main entry point. */ -void +static void web_main (void) { struct df *df; @@ -261,39 +252,32 @@ web_main (void) unsigned int i; int max = max_reg_num (); char *used; - char *use_addressof; - rtx insn; - df = df_init (); - df_analyse (df, 0, DF_UD_CHAIN | DF_EQUIV_NOTES); + df = df_init (DF_EQUIV_NOTES); + df_chain_add_problem (df, DF_UD_CHAIN); + df_analyze (df); + df_reorganize_refs (&df->def_info); + df_reorganize_refs (&df->use_info); - def_entry = - (struct web_entry *) xcalloc (df->n_defs, sizeof (struct web_entry)); - use_entry = - (struct web_entry *) xcalloc (df->n_uses, sizeof (struct web_entry)); - used = (char *) xcalloc (max, sizeof (char)); - use_addressof = (char *) xcalloc (max, sizeof (char)); + def_entry = XCNEWVEC (struct web_entry, DF_DEFS_SIZE (df)); + use_entry = XCNEWVEC (struct web_entry, DF_USES_SIZE (df)); + used = XCNEWVEC (char, max); - if (rtl_dump_file) - df_dump (df, DF_UD_CHAIN | DF_DU_CHAIN, rtl_dump_file); + if (dump_file) + df_dump (df, dump_file); /* Produce the web. */ - for (i = 0; i < df->n_uses; i++) - union_defs (df, df->uses[i], def_entry, use_entry); - - /* We can not safely rename registers whose address is taken. */ - for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - for_each_rtx (&PATTERN (insn), mark_addressof, use_addressof); + for (i = 0; i < DF_USES_SIZE (df); i++) + union_defs (df, DF_USES_GET (df, i), def_entry, use_entry, unionfind_union); /* Update the instruction stream, allocating new registers for split pseudos in progress. */ - for (i = 0; i < df->n_uses; i++) - replace_ref (df->uses[i], entry_register (use_entry + i, df->uses[i], - used, use_addressof)); - for (i = 0; i < df->n_defs; i++) - replace_ref (df->defs[i], entry_register (def_entry + i, df->defs[i], - used, use_addressof)); + for (i = 0; i < DF_USES_SIZE (df); i++) + replace_ref (DF_USES_GET (df, i), + entry_register (use_entry + i, DF_USES_GET (df, i), used)); + for (i = 0; i < DF_DEFS_SIZE (df); i++) + replace_ref (DF_DEFS_GET (df, i), + entry_register (def_entry + i, DF_DEFS_GET (df, i), used)); /* Dataflow information is corrupt here, but it can be easily updated by creating new entries for new registers and updates or calling @@ -301,6 +285,40 @@ web_main (void) free (def_entry); free (use_entry); free (used); - free (use_addressof); df_finish (df); + df = NULL; +} + +static bool +gate_handle_web (void) +{ + return (optimize > 0 && flag_web); +} + +static unsigned int +rest_of_handle_web (void) +{ + web_main (); + delete_trivially_dead_insns (get_insns (), max_reg_num ()); + cleanup_cfg (CLEANUP_EXPENSIVE); + reg_scan (get_insns (), max_reg_num ()); + return 0; } + +struct tree_opt_pass pass_web = +{ + "web", /* name */ + gate_handle_web, /* gate */ + rest_of_handle_web, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_WEB, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 'Z' /* letter */ +}; +