X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fweb.c;h=1f7169fe069e9275e1c5c0c437441e00b8f07dd6;hb=cb5526cd76771c78bf232a61fcf3472e0faaf5fc;hp=a8f9f04dd4c872e45f9a4c91a45135d1d7cee544;hpb=8b5b1013b9a1d3a959fa5d9dcaefadfb2d095361;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/web.c b/gcc/web.c index a8f9f04dd4c..1f7169fe069 100644 --- a/gcc/web.c +++ b/gcc/web.c @@ -1,12 +1,13 @@ /* Web construction code for GNU compiler. Contributed by Jan Hubicka. - Copyright (C) 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2004, 2006, 2007 + Free Software Foundation, Inc. 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 2, or (at your option) any later +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 @@ -15,12 +16,11 @@ 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 COPYING. If not, write to the Free -Software Foundation, 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* Simple optimization pass that splits independent uses of each pseudo, - increasing effectivity of other optimizations. The optimization can + increasing effectiveness of other optimizations. The optimization can serve as an example of use for the dataflow module. We don't split registers with REG_USERVAR set unless -fmessy-debugging @@ -51,37 +51,22 @@ 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 PARAMS ((struct web_entry *)); -static void unionfind_union PARAMS ((struct web_entry *, - struct web_entry *)); -static void union_defs PARAMS ((struct df *, struct ref *, - struct web_entry *, - struct web_entry *)); -static rtx entry_register PARAMS ((struct web_entry *, - struct ref *, char *, char *)); -static void replace_ref PARAMS ((struct ref *, rtx)); -static int mark_addressof PARAMS ((rtx *, void *)); +static rtx entry_register (struct web_entry *, df_ref, char *); +static void replace_ref (df_ref, rtx); /* Find the root of unionfind tree (the representative of set). */ -static struct web_entry * -unionfind_root (element) - struct web_entry *element; +struct web_entry * +unionfind_root (struct web_entry *element) { struct web_entry *element1 = element, *element2; @@ -96,94 +81,127 @@ unionfind_root (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 -unionfind_union (first, second) - struct web_entry *first, *second; +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 (df, use, def_entry, use_entry) - struct df *df; - struct ref *use; - struct web_entry *def_entry; - struct web_entry *use_entry; +void +union_defs (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_insn_info *insn_info = DF_REF_INSN_INFO (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); + df_ref *use_link; + df_ref *eq_use_link; + df_ref *def_link; + rtx set; + + if (insn_info) + { + rtx insn = insn_info->insn; + use_link = DF_INSN_INFO_USES (insn_info); + eq_use_link = DF_INSN_INFO_EQ_USES (insn_info); + def_link = DF_INSN_INFO_DEFS (insn_info); + set = single_set (insn); + } + else + { + /* An artificial use. It links up with nothing. */ + use_link = NULL; + eq_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 invalid instructions, so union all uses of the same operand for each insn. */ - 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_link) + while (*use_link) + { + 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++; + } + + if (eq_use_link) + while (*eq_use_link) + { + if (use != *eq_use_link + && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (*eq_use_link)) + (*fun) (use_entry + DF_REF_ID (use), + use_entry + DF_REF_ID (*eq_use_link)); + eq_use_link++; } - /* Recognize trivial noop moves and attempt to keep them as noop. - While most of noop moves should be removed, we still keep some - of them at libcall boundaries and such. */ + /* Recognize trivial noop moves and attempt to keep them as noop. */ if (set && SET_SRC (set) == DF_REF_REG (use) && SET_SRC (set) == SET_DEST (set)) { - 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 (def_link) + while (*def_link) + { + 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++; + } } 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; } /* A READ_WRITE use requires the corresponding def to be in the same register. Find it and union. */ - if (use->flags & DF_REF_READ_WRITE) + if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE) { - struct df_link *link = DF_INSN_DEFS (df, DF_REF_INSN (use)); - - while (DF_REF_REAL_REG (link->ref) != DF_REF_REAL_REG (use)) - link = link->next; - - unionfind_union (use_entry + DF_REF_ID (use), - def_entry + DF_REF_ID (link->ref)); + df_ref *link; + + if (insn_info) + link = DF_INSN_INFO_DEFS (insn_info); + else + link = NULL; + + if (link) + 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++; + } } } /* Find the corresponding register for the given entry. */ static rtx -entry_register (entry, ref, used, use_addressof) - struct web_entry *entry; - struct ref *ref; - char *used; - char *use_addressof; +entry_register (struct web_entry *entry, df_ref ref, char *used) { struct web_entry *root; rtx reg, newreg; @@ -202,29 +220,19 @@ entry_register (entry, ref, used, use_addressof) 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)); } @@ -235,87 +243,151 @@ entry_register (entry, ref, used, use_addressof) /* Replace the reference by REG. */ static void -replace_ref (ref, reg) - struct ref *ref; - rtx reg; +replace_ref (df_ref ref, rtx reg) { rtx oldreg = DF_REF_REAL_REG (ref); rtx *loc = DF_REF_REAL_LOC (ref); + unsigned int uid = DF_REF_INSN_UID (ref); if (oldreg == reg) return; - if (rtl_dump_file) - fprintf (rtl_dump_file, "Updating insn %i (%i->%i)\n", - INSN_UID (DF_REF_INSN (ref)), REGNO (oldreg), REGNO (reg)); + if (dump_file) + fprintf (dump_file, "Updating insn %i (%i->%i)\n", + uid, REGNO (oldreg), REGNO (reg)); *loc = reg; + df_insn_rescan (DF_REF_INSN (ref)); } -/* Mark each pseudo whose address is taken. */ - -static int -mark_addressof (rtl, data) - rtx *rtl; - void *data; + +static bool +gate_handle_web (void) { - if (!*rtl) - return 0; - if (GET_CODE (*rtl) == ADDRESSOF - && REG_P (XEXP (*rtl, 0))) - ((char *)data)[REGNO (XEXP (*rtl, 0))] = 1; - return 0; + return (optimize > 0 && flag_web); } /* Main entry point. */ -void -web_main () +static unsigned int +web_main (void) { - struct df *df; struct web_entry *def_entry; struct web_entry *use_entry; - unsigned int i; - int max = max_reg_num (); + unsigned int max = max_reg_num (); char *used; - char *use_addressof; + basic_block bb; + unsigned int uses_num = 0; rtx insn; - df = df_init (); - df_analyse (df, 0, DF_UD_CHAIN | DF_EQUIV_NOTES); + df_set_flags (DF_NO_HARD_REGS + DF_EQ_NOTES); + df_chain_add_problem (DF_UD_CHAIN); + df_analyze (); + df_set_flags (DF_DEFER_INSN_RESCAN); - 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)); + /* Assign ids to the uses. */ + FOR_ALL_BB (bb) + FOR_BB_INSNS (bb, insn) + { + unsigned int uid = INSN_UID (insn); + if (INSN_P (insn)) + { + df_ref *use_rec; + for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++) + { + df_ref use = *use_rec; + if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) + DF_REF_ID (use) = uses_num++; + } + for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++) + { + df_ref use = *use_rec; + if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) + DF_REF_ID (use) = uses_num++; + } + } + } - if (rtl_dump_file) - df_dump (df, DF_UD_CHAIN | DF_DU_CHAIN, rtl_dump_file); + /* Record the number of uses and defs at the beginning of the optimization. */ + def_entry = XCNEWVEC (struct web_entry, DF_DEFS_TABLE_SIZE()); + used = XCNEWVEC (char, max); + use_entry = XCNEWVEC (struct web_entry, uses_num); /* 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_ALL_BB (bb) + FOR_BB_INSNS (bb, insn) + { + unsigned int uid = INSN_UID (insn); + if (INSN_P (insn)) + { + df_ref *use_rec; + for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++) + { + df_ref use = *use_rec; + if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) + union_defs (use, def_entry, use_entry, unionfind_union); + } + for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++) + { + df_ref use = *use_rec; + if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) + union_defs (use, 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)); - - /* Dataflow information is corrupt here, but it can be easily updated - by creating new entries for new registers and updates or calling - df_insns_modify. */ + FOR_ALL_BB (bb) + FOR_BB_INSNS (bb, insn) + { + unsigned int uid = INSN_UID (insn); + if (INSN_P (insn)) + { + df_ref *use_rec; + df_ref *def_rec; + for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++) + { + df_ref use = *use_rec; + if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) + replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used)); + } + for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++) + { + df_ref use = *use_rec; + if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) + replace_ref (use, entry_register (use_entry + DF_REF_ID (use), use, used)); + } + for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++) + { + df_ref def = *def_rec; + if (DF_REF_REGNO (def) >= FIRST_PSEUDO_REGISTER) + replace_ref (def, entry_register (def_entry + DF_REF_ID (def), def, used)); + } + } + } + free (def_entry); free (use_entry); free (used); - free (use_addressof); - df_finish (df); + return 0; } + +struct rtl_opt_pass pass_web = +{ + { + RTL_PASS, + "web", /* name */ + gate_handle_web, /* gate */ + web_main, /* 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_df_finish | TODO_verify_rtl_sharing | + TODO_dump_func /* todo_flags_finish */ + } +}; +