summaryrefslogtreecommitdiff
path: root/gcc/fwprop.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fwprop.c')
-rw-r--r--gcc/fwprop.c141
1 files changed, 85 insertions, 56 deletions
diff --git a/gcc/fwprop.c b/gcc/fwprop.c
index 106424efc96..a3c8bc1edde 100644
--- a/gcc/fwprop.c
+++ b/gcc/fwprop.c
@@ -1,5 +1,5 @@
/* RTL-based forward propagation pass for GNU compiler.
- Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Paolo Bonzini and Steven Bosscher.
This file is part of GCC.
@@ -104,7 +104,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
where the first two insns are now dead. */
-static struct df *df;
static int num_changes;
@@ -432,23 +431,22 @@ propagate_rtx (rtx x, enum machine_mode mode, rtx old, rtx new)
/* Return true if the register from reference REF is killed
between FROM to (but not including) TO. */
-static bool
+static bool
local_ref_killed_between_p (struct df_ref * ref, rtx from, rtx to)
{
rtx insn;
- struct df_ref *def;
for (insn = from; insn != to; insn = NEXT_INSN (insn))
{
+ struct df_ref **def_rec;
if (!INSN_P (insn))
continue;
- def = DF_INSN_DEFS (df, insn);
- while (def)
+ for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
{
+ struct df_ref *def = *def_rec;
if (DF_REF_REGNO (ref) == DF_REF_REGNO (def))
return true;
- def = def->next_ref;
}
}
return false;
@@ -478,14 +476,14 @@ use_killed_between (struct df_ref *use, rtx def_insn, rtx target_insn)
uninitialized in a loop. In such cases, we must assume that
DEF is not available. */
if (def_bb == target_bb
- ? DF_INSN_LUID (df, def_insn) >= DF_INSN_LUID (df, target_insn)
+ ? DF_INSN_LUID (def_insn) >= DF_INSN_LUID (target_insn)
: !dominated_by_p (CDI_DOMINATORS, target_bb, def_bb))
return true;
/* Check if the reg in USE has only one definition. We already
know that this definition reaches use, or we wouldn't be here. */
regno = DF_REF_REGNO (use);
- def = DF_REG_DEF_GET (df, regno)->reg_chain;
+ def = DF_REG_DEF_CHAIN (regno);
if (def && (def->next_reg == NULL))
return false;
@@ -501,14 +499,14 @@ use_killed_between (struct df_ref *use, rtx def_insn, rtx target_insn)
/* See if USE is killed between DEF_INSN and the last insn in the
basic block containing DEF_INSN. */
- x = df_bb_regno_last_def_find (df, def_bb, regno);
- if (x && DF_INSN_LUID (df, x->insn) >= DF_INSN_LUID (df, def_insn))
+ x = df_bb_regno_last_def_find (def_bb, regno);
+ if (x && DF_INSN_LUID (x->insn) >= DF_INSN_LUID (def_insn))
return true;
/* See if USE is killed between TARGET_INSN and the first insn in the
basic block containing TARGET_INSN. */
- x = df_bb_regno_first_def_find (df, target_bb, regno);
- if (x && DF_INSN_LUID (df, x->insn) < DF_INSN_LUID (df, target_insn))
+ x = df_bb_regno_first_def_find (target_bb, regno);
+ if (x && DF_INSN_LUID (x->insn) < DF_INSN_LUID (target_insn))
return true;
return false;
@@ -528,14 +526,14 @@ varying_mem_p (rtx *body, void *data ATTRIBUTE_UNUSED)
rtx x = *body;
return MEM_P (x) && !MEM_READONLY_P (x);
}
-
+
/* Check if all uses in DEF_INSN can be used in TARGET_INSN. This
would require full computation of available expressions;
we check only restricted conditions, see use_killed_between. */
static bool
all_uses_available_at (rtx def_insn, rtx target_insn)
{
- struct df_ref * use;
+ struct df_ref **use_rec;
rtx def_set = single_set (def_insn);
gcc_assert (def_set);
@@ -549,17 +547,35 @@ all_uses_available_at (rtx def_insn, rtx target_insn)
/* If the insn uses the reg that it defines, the substitution is
invalid. */
- for (use = DF_INSN_USES (df, def_insn); use; use = use->next_ref)
- if (rtx_equal_p (use->reg, def_reg))
- return false;
+ for (use_rec = DF_INSN_USES (def_insn); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ if (rtx_equal_p (DF_REF_REG (use), def_reg))
+ return false;
+ }
+ for (use_rec = DF_INSN_EQ_USES (def_insn); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ if (rtx_equal_p (use->reg, def_reg))
+ return false;
+ }
}
else
{
/* Look at all the uses of DEF_INSN, and see if they are not
killed between DEF_INSN and TARGET_INSN. */
- for (use = DF_INSN_USES (df, def_insn); use; use = use->next_ref)
- if (use_killed_between (use, def_insn, target_insn))
- return false;
+ for (use_rec = DF_INSN_USES (def_insn); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ if (use_killed_between (use, def_insn, target_insn))
+ return false;
+ }
+ for (use_rec = DF_INSN_EQ_USES (def_insn); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ if (use_killed_between (use, def_insn, target_insn))
+ return false;
+ }
}
/* We don't do any analysis of memories or aliasing. Reject any
@@ -613,34 +629,38 @@ find_occurrence (rtx *px, rtx find)
/* Inside INSN, the expression rooted at *LOC has been changed, moving some
- uses from ORIG_USES. Find those that are present, and create new items
+ uses from USE_VEC. Find those that are present, and create new items
in the data flow object of the pass. Mark any new uses as having the
given TYPE. */
static void
-update_df (rtx insn, rtx *loc, struct df_ref *orig_uses, enum df_ref_type type,
+update_df (rtx insn, rtx *loc, struct df_ref **use_rec, enum df_ref_type type,
int new_flags)
{
- struct df_ref *use;
+ bool changed = false;
/* Add a use for the registers that were propagated. */
- for (use = orig_uses; use; use = use->next_ref)
+ while (*use_rec)
{
+ struct df_ref *use = *use_rec;
struct df_ref *orig_use = use, *new_use;
rtx *new_loc = find_occurrence (loc, DF_REF_REG (orig_use));
+ use_rec++;
if (!new_loc)
continue;
/* Add a new insn use. Use the original type, because it says if the
use was within a MEM. */
- new_use = df_ref_create (df, DF_REF_REG (orig_use), new_loc,
+ new_use = df_ref_create (DF_REF_REG (orig_use), new_loc,
insn, BLOCK_FOR_INSN (insn),
type, DF_REF_FLAGS (orig_use) | new_flags);
/* Set up the use-def chain. */
- df_chain_copy (df->problems_by_index[DF_CHAIN],
- new_use, DF_REF_CHAIN (orig_use));
+ df_chain_copy (new_use, DF_REF_CHAIN (orig_use));
+ changed = true;
}
+ if (changed)
+ df_insn_rescan (insn);
}
@@ -672,11 +692,12 @@ try_fwprop_subst (struct df_ref *use, rtx *loc, rtx new, rtx def_insn, bool set_
if (dump_file)
fprintf (dump_file, "Changed insn %d\n", INSN_UID (insn));
- /* Unlink the use that we changed. */
- df_ref_remove (df, use);
+ df_ref_remove (use);
if (!CONSTANT_P (new))
- update_df (insn, loc, DF_INSN_USES (df, def_insn), type, flags);
-
+ {
+ update_df (insn, loc, DF_INSN_USES (def_insn), type, flags);
+ update_df (insn, loc, DF_INSN_EQ_USES (def_insn), type, flags);
+ }
return true;
}
else
@@ -697,8 +718,12 @@ try_fwprop_subst (struct df_ref *use, rtx *loc, rtx new, rtx def_insn, bool set_
/* ??? Is this still necessary if we add the note through
set_unique_reg_note? */
if (!CONSTANT_P (new))
- update_df (insn, loc, DF_INSN_USES (df, def_insn),
- type, DF_REF_IN_NOTE);
+ {
+ update_df (insn, loc, DF_INSN_USES (def_insn),
+ type, DF_REF_IN_NOTE);
+ update_df (insn, loc, DF_INSN_EQ_USES (def_insn),
+ type, DF_REF_IN_NOTE);
+ }
}
return false;
@@ -793,7 +818,7 @@ forward_propagate_and_simplify (struct df_ref *use, rtx def_insn, rtx def_set)
rtx note = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
rtx old = note ? XEXP (note, 0) : SET_SRC (use_set);
rtx new = simplify_replace_rtx (old, src, x);
- if (old != new)
+ if (old != new)
set_unique_reg_note (use_insn, REG_EQUAL, copy_rtx (new));
}
return false;
@@ -813,7 +838,7 @@ forward_propagate_and_simplify (struct df_ref *use, rtx def_insn, rtx def_set)
loc = &XEXP (note, 0);
else
loc = &SET_SRC (use_set);
-
+
/* Do not replace an existing REG_EQUAL note if the insn is not
recognized. Either we're already replacing in the note, or
we'll separately try plugging the definition in the note and
@@ -827,7 +852,7 @@ forward_propagate_and_simplify (struct df_ref *use, rtx def_insn, rtx def_set)
mode = GET_MODE (*loc);
new = propagate_rtx (*loc, mode, reg, src);
-
+
if (!new)
return false;
@@ -844,11 +869,11 @@ forward_propagate_into (struct df_ref *use)
struct df_link *defs;
struct df_ref *def;
rtx def_insn, def_set, use_insn;
- rtx parent;
+ rtx parent;
if (DF_REF_FLAGS (use) & DF_REF_READ_WRITE)
return;
- if (DF_REF_FLAGS (use) & DF_REF_ARTIFICIAL)
+ if (DF_REF_IS_ARTIFICIAL (use))
return;
/* Only consider uses that have a single definition. */
@@ -859,7 +884,7 @@ forward_propagate_into (struct df_ref *use)
def = defs->ref;
if (DF_REF_FLAGS (def) & DF_REF_READ_WRITE)
return;
- if (DF_REF_FLAGS (def) & DF_REF_ARTIFICIAL)
+ if (DF_REF_IS_ARTIFICIAL (def))
return;
/* Do not propagate loop invariant definitions inside the loop. */
@@ -877,6 +902,8 @@ forward_propagate_into (struct df_ref *use)
return;
def_insn = DF_REF_INSN (def);
+ if (multiple_sets (def_insn))
+ return;
def_set = single_set (def_insn);
if (!def_set)
return;
@@ -902,17 +929,18 @@ fwprop_init (void)
/* Now set up the dataflow problem (we only want use-def chains) and
put the dataflow solver to work. */
- df = df_init (DF_HARD_REGS | DF_SUBREGS | DF_EQUIV_NOTES);
- df_chain_add_problem (df, DF_UD_CHAIN);
- df_analyze (df);
- df_dump (df, dump_file);
+ df_set_flags (DF_EQ_NOTES);
+ df_chain_add_problem (DF_UD_CHAIN);
+ df_analyze ();
+ df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
+ df_set_flags (DF_DEFER_INSN_RESCAN);
}
static void
fwprop_done (void)
{
- df_finish (df);
loop_optimizer_finalize ();
+
free_dominance_info (CDI_DOMINATORS);
cleanup_cfg (0);
delete_trivially_dead_insns (get_insns (), max_reg_num ());
@@ -946,10 +974,9 @@ fwprop (void)
Do not forward propagate addresses into loops until after unrolling.
CSE did so because it was able to fix its own mess, but we are not. */
- df_reorganize_refs (&df->use_info);
- for (i = 0; i < DF_USES_SIZE (df); i++)
+ for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
{
- struct df_ref *use = DF_USES_GET (df, i);
+ struct df_ref *use = DF_USES_GET (i);
if (use)
if (DF_REF_TYPE (use) == DF_REF_REG_USE
|| DF_REF_BB (use)->loop_father == NULL)
@@ -957,15 +984,14 @@ fwprop (void)
}
fwprop_done ();
-
return 0;
}
struct tree_opt_pass pass_rtl_fwprop =
{
"fwprop1", /* name */
- gate_fwprop, /* gate */
- fwprop, /* execute */
+ gate_fwprop, /* gate */
+ fwprop, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
@@ -974,6 +1000,7 @@ struct tree_opt_pass pass_rtl_fwprop =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
+ TODO_df_finish |
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
@@ -986,10 +1013,11 @@ fwprop_addr (void)
/* Go through all the uses. update_df will create new ones at the
end, and we'll go through them as well. */
- df_reorganize_refs (&df->use_info);
- for (i = 0; i < DF_USES_SIZE (df); i++)
+ df_set_flags (DF_DEFER_INSN_RESCAN);
+
+ for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
{
- struct df_ref *use = DF_USES_GET (df, i);
+ struct df_ref *use = DF_USES_GET (i);
if (use)
if (DF_REF_TYPE (use) != DF_REF_REG_USE
&& DF_REF_BB (use)->loop_father != NULL)
@@ -1004,8 +1032,8 @@ fwprop_addr (void)
struct tree_opt_pass pass_rtl_fwprop_addr =
{
"fwprop2", /* name */
- gate_fwprop, /* gate */
- fwprop_addr, /* execute */
+ gate_fwprop, /* gate */
+ fwprop_addr, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
@@ -1014,6 +1042,7 @@ struct tree_opt_pass pass_rtl_fwprop_addr =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
+ TODO_df_finish |
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};