/* RTL-based forward propagation pass for GNU compiler.
- Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by Paolo Bonzini and Steven Bosscher.
This file is part of GCC.
#include "timevar.h"
#include "rtl.h"
#include "tm_p.h"
-#include "emit-rtl.h"
#include "insn-config.h"
#include "recog.h"
#include "flags.h"
#include "cfgloop.h"
#include "tree-pass.h"
#include "domwalk.h"
+#include "emit-rtl.h"
/* This pass does simple forward propagation and simplification when an
DEF_VEC_P(df_ref);
DEF_VEC_ALLOC_P(df_ref,heap);
-VEC(df_ref,heap) *use_def_ref;
-VEC(df_ref,heap) *reg_defs;
-VEC(df_ref,heap) *reg_defs_stack;
+static VEC(df_ref,heap) *use_def_ref;
+static VEC(df_ref,heap) *reg_defs;
+static VEC(df_ref,heap) *reg_defs_stack;
+/* The MD bitmaps are trimmed to include only live registers to cut
+ memory usage on testcases like insn-recog.c. Track live registers
+ in the basic block and do not perform forward propagation if the
+ destination is a dead pseudo occurring in a note. */
+static bitmap local_md;
+static bitmap local_lr;
/* Return the only def in USE's use-def chain, or NULL if there is
more than one def in the chain. */
(DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER)
static void
-process_defs (bitmap local_md, df_ref *def_rec, int top_flag)
+process_defs (df_ref *def_rec, int top_flag)
{
df_ref def;
while ((def = *def_rec++) != NULL)
is an artificial use vector. */
static void
-process_uses (bitmap local_md, df_ref *use_rec, int top_flag)
+process_uses (df_ref *use_rec, int top_flag)
{
df_ref use;
while ((use = *use_rec++) != NULL)
{
unsigned int uregno = DF_REF_REGNO (use);
if (VEC_index (df_ref, reg_defs, uregno)
- && !bitmap_bit_p (local_md, uregno))
+ && !bitmap_bit_p (local_md, uregno)
+ && bitmap_bit_p (local_lr, uregno))
VEC_replace (df_ref, use_def_ref, DF_REF_ID (use),
VEC_index (df_ref, reg_defs, uregno));
}
static void
-single_def_use_enter_block (struct dom_walk_data *walk_data, basic_block bb)
+single_def_use_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+ basic_block bb)
{
- bitmap local_md = (bitmap) walk_data->global_data;
int bb_index = bb->index;
- struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index);
+ struct df_md_bb_info *md_bb_info = df_md_get_bb_info (bb_index);
+ struct df_lr_bb_info *lr_bb_info = df_lr_get_bb_info (bb_index);
rtx insn;
- bitmap_copy (local_md, bb_info->in);
+ bitmap_copy (local_md, &md_bb_info->in);
+ bitmap_copy (local_lr, &lr_bb_info->in);
/* Push a marker for the leave_block callback. */
VEC_safe_push (df_ref, heap, reg_defs_stack, NULL);
- process_uses (local_md, df_get_artificial_uses (bb_index), DF_REF_AT_TOP);
- process_defs (local_md, df_get_artificial_defs (bb_index), DF_REF_AT_TOP);
+ process_uses (df_get_artificial_uses (bb_index), DF_REF_AT_TOP);
+ process_defs (df_get_artificial_defs (bb_index), DF_REF_AT_TOP);
+
+ /* We don't call df_simulate_initialize_forwards, as it may overestimate
+ the live registers if there are unused artificial defs. We prefer
+ liveness to be underestimated. */
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
{
unsigned int uid = INSN_UID (insn);
- process_uses (local_md, DF_INSN_UID_USES (uid), 0);
- process_uses (local_md, DF_INSN_UID_EQ_USES (uid), 0);
- process_defs (local_md, DF_INSN_UID_DEFS (uid), 0);
+ process_uses (DF_INSN_UID_USES (uid), 0);
+ process_uses (DF_INSN_UID_EQ_USES (uid), 0);
+ process_defs (DF_INSN_UID_DEFS (uid), 0);
+ df_simulate_one_insn_forwards (bb, insn, local_lr);
}
- process_uses (local_md, df_get_artificial_uses (bb_index), 0);
- process_defs (local_md, df_get_artificial_defs (bb_index), 0);
+ process_uses (df_get_artificial_uses (bb_index), 0);
+ process_defs (df_get_artificial_defs (bb_index), 0);
}
/* Pop the definitions created in this basic block when leaving its
build_single_def_use_links (void)
{
struct dom_walk_data walk_data;
- bitmap local_md;
/* We use the multiple definitions problem to compute our restricted
use-def chains. */
df_set_flags (DF_EQ_NOTES);
df_md_add_problem ();
+ df_note_add_problem ();
df_analyze ();
df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
reg_defs_stack = VEC_alloc (df_ref, heap, n_basic_blocks * 10);
local_md = BITMAP_ALLOC (NULL);
+ local_lr = BITMAP_ALLOC (NULL);
/* Walk the dominator tree looking for single reaching definitions
dominating the uses. This is similar to how SSA form is built. */
walk_data.initialize_block_local_data = NULL;
walk_data.before_dom_children = single_def_use_enter_block;
walk_data.after_dom_children = single_def_use_leave_block;
- walk_data.global_data = local_md;
init_walk_dominator_tree (&walk_data);
walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
fini_walk_dominator_tree (&walk_data);
+ BITMAP_FREE (local_lr);
BITMAP_FREE (local_md);
VEC_free (df_ref, heap, reg_defs);
VEC_free (df_ref, heap, reg_defs_stack);
static bool
should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode,
- bool speed)
+ addr_space_t as, bool speed)
{
int gain;
- if (rtx_equal_p (old_rtx, new_rtx) || !memory_address_p (mode, new_rtx))
+ if (rtx_equal_p (old_rtx, new_rtx)
+ || !memory_address_addr_space_p (mode, new_rtx, as))
return false;
/* Copy propagation is always ok. */
return true;
/* Prefer the new address if it is less expensive. */
- gain = address_cost (old_rtx, mode, speed) - address_cost (new_rtx, mode, speed);
+ gain = (address_cost (old_rtx, mode, as, speed)
+ - address_cost (new_rtx, mode, as, speed));
/* If the addresses have equivalent cost, prefer the new address
if it has the highest `rtx_cost'. That has the potential of
/* Copy propagations are always ok. Otherwise check the costs. */
if (!(REG_P (old_rtx) && REG_P (new_rtx))
&& !should_replace_address (op0, new_op0, GET_MODE (x),
+ MEM_ADDR_SPACE (x),
flags & PR_OPTIMIZE_FOR_SPEED))
return true;
}
else
{
+ rtx def_reg = REG_P (SET_DEST (def_set)) ? SET_DEST (def_set) : NULL_RTX;
+
/* Look at all the uses of DEF_INSN, and see if they are not
killed between DEF_INSN and TARGET_INSN. */
for (use_rec = DF_INSN_INFO_USES (insn_info); *use_rec; use_rec++)
{
df_ref use = *use_rec;
+ if (def_reg && rtx_equal_p (DF_REF_REG (use), def_reg))
+ return false;
if (use_killed_between (use, def_insn, target_insn))
return false;
}
for (use_rec = DF_INSN_INFO_EQ_USES (insn_info); *use_rec; use_rec++)
{
df_ref use = *use_rec;
+ if (def_reg && rtx_equal_p (DF_REF_REG (use), def_reg))
+ return false;
if (use_killed_between (use, def_insn, target_insn))
return false;
}
use was within a MEM. */
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,
+ type, DF_REF_FLAGS (orig_use) | new_flags,
width, offset, mode);
/* Set up the use-def chain. */
{
rtx reg;
df_ref *use_vec;
- df_ref use, def;
+ df_ref use = 0, def;
reg = XEXP (src, 0);
#ifdef LOAD_EXTEND_OP
if (INSN_CODE (use_insn) < 0)
asm_use = asm_noperands (PATTERN (use_insn));
- if (!use_set && asm_use < 0)
+ if (!use_set && asm_use < 0 && !DEBUG_INSN_P (use_insn))
return false;
/* Do not propagate into PC, CC0, etc. */
loc = &SET_DEST (use_set);
set_reg_equal = false;
}
+ else if (!use_set)
+ {
+ loc = &INSN_VAR_LOCATION_LOC (use_insn);
+ set_reg_equal = false;
+ }
else
{
rtx note = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
fprintf (dump_file,
"\nNumber of successful forward propagations: %d\n\n",
num_changes);
- df_remove_problem (df_chain);
}
-
/* Main entry point. */
static bool