re PR tree-optimization/26854 (Inordinate compile times on large routines)

2009-06-07  Paolo Bonzini  <bonzini@gnu.org>

	PR rtl-optimization/26854
        * timevar.def: Remove TV_DF_RU, add TV_DF_MD.
        * df-problems.c (df_rd_add_problem): Fix comment.
        (df_md_set_bb_info, df_md_free_bb_info, df_md_alloc,
        df_md_simulate_artificial_defs_at_top,
        df_md_simulate_one_insn, df_md_bb_local_compute_process_def,
        df_md_bb_local_compute, df_md_local_compute, df_md_reset,
        df_md_transfer_function, df_md_init, df_md_confluence_0,
        df_md_confluence_n, df_md_free, df_md_top_dump, df_md_bottom_dump,
        problem_MD, df_md_add_problem): New.
        * df.h (DF_MD, DF_MD_BB_INFO, struct df_md_bb_info, df_md,
        df_md_get_bb_info): New.
        DF_LAST_PROBLEM_PLUS1): Adjust.

        * Makefile.in (fwprop.o): Include domwalk.h.
        * fwprop.c: Include domwalk.h.
        (reg_defs, reg_defs_stack): New.
        (bitmap_only_bit_between): Remove.
        (process_defs): New.
        (process_uses): Use reg_defs and local_md instead of
        bitmap_only_bit_between and local_rd.
        (single_def_use_enter_block): New, from build_single_def_use_links.
        (single_def_use_leave_block): New.
        (build_single_def_use_links): Remove code moved to
        single_def_use_enter_block, invoke domwalk.
        (use_killed_between): Adjust comment.

From-SVN: r149010
This commit is contained in:
Paolo Bonzini 2009-06-27 14:48:34 +00:00 committed by Paolo Bonzini
parent 7ff23740a3
commit c6741572cf
6 changed files with 658 additions and 69 deletions

View File

@ -1,3 +1,32 @@
2009-06-07 Paolo Bonzini <bonzini@gnu.org>
PR rtl-optimization/26854
* timevar.def: Remove TV_DF_RU, add TV_DF_MD.
* df-problems.c (df_rd_add_problem): Fix comment.
(df_md_set_bb_info, df_md_free_bb_info, df_md_alloc,
df_md_simulate_artificial_defs_at_top,
df_md_simulate_one_insn, df_md_bb_local_compute_process_def,
df_md_bb_local_compute, df_md_local_compute, df_md_reset,
df_md_transfer_function, df_md_init, df_md_confluence_0,
df_md_confluence_n, df_md_free, df_md_top_dump, df_md_bottom_dump,
problem_MD, df_md_add_problem): New.
* df.h (DF_MD, DF_MD_BB_INFO, struct df_md_bb_info, df_md,
df_md_get_bb_info): New.
DF_LAST_PROBLEM_PLUS1): Adjust.
* Makefile.in (fwprop.o): Include domwalk.h.
* fwprop.c: Include domwalk.h.
(reg_defs, reg_defs_stack): New.
(bitmap_only_bit_between): Remove.
(process_defs): New.
(process_uses): Use reg_defs and local_md instead of
bitmap_only_bit_between and local_rd.
(single_def_use_enter_block): New, from build_single_def_use_links.
(single_def_use_leave_block): New.
(build_single_def_use_links): Remove code moved to
single_def_use_enter_block, invoke domwalk.
(use_killed_between): Adjust comment.
2009-06-27 Paolo Bonzini <bonzini@gnu.org>
* bitmap.h (bitmap_ior_and_into): New.

View File

@ -2761,7 +2761,7 @@ dse.o : dse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
fwprop.o : fwprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TOPLEV_H) insn-config.h $(RECOG_H) $(FLAGS_H) $(OBSTACK_H) $(BASIC_BLOCK_H) \
output.h $(DF_H) alloc-pool.h $(TIMEVAR_H) $(TREE_PASS_H) $(TARGET_H) \
$(TM_P_H) $(CFGLOOP_H) $(EMIT_RTL_H)
$(TM_P_H) $(CFGLOOP_H) $(EMIT_RTL_H) domwalk.h
web.o : web.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
hard-reg-set.h $(FLAGS_H) $(BASIC_BLOCK_H) $(FUNCTION_H) output.h $(TOPLEV_H) \
$(DF_H) $(OBSTACK_H) $(TIMEVAR_H) $(TREE_PASS_H)

View File

@ -726,9 +726,8 @@ static struct df_problem problem_RD =
/* Create a new DATAFLOW instance and add it to an existing instance
of DF. The returned structure is what is used to get at the
solution. */
/* Create a new RD instance and add it to the existing instance
of DF. */
void
df_rd_add_problem (void)
@ -3952,3 +3951,448 @@ df_simulate_finalize_forwards (basic_block bb, bitmap live)
bitmap_clear_bit (live, DF_REF_REGNO (def));
}
}
/*----------------------------------------------------------------------------
MULTIPLE DEFINITIONS
Find the locations in the function reached by multiple definition sites
for a pseudo. In and out bitvectors are built for each basic
block.
The gen and kill sets for the problem are obvious. Together they
include all defined registers in a basic block; the gen set includes
registers where a partial or conditional or may-clobber definition is
last in the BB, while the kill set includes registers with a complete
definition coming last. However, the computation of the dataflow
itself is interesting.
The idea behind it comes from SSA form's iterated dominance frontier
criterion for inserting PHI functions. Just like in that case, we can use
the dominance frontier to find places where multiple definitions meet;
a register X defined in a basic block BB1 has multiple definitions in
basic blocks in BB1's dominance frontier.
So, the in-set of a basic block BB2 is not just the union of the
out-sets of BB2's predecessors, but includes some more bits that come
from the basic blocks of whose dominance frontier BB2 is part (BB1 in
the previous paragraph). I called this set the init-set of BB2.
(Note: I actually use the kill-set only to build the init-set.
gen bits are anyway propagated from BB1 to BB2 by dataflow).
For example, if you have
BB1 : r10 = 0
r11 = 0
if <...> goto BB2 else goto BB3;
BB2 : r10 = 1
r12 = 1
goto BB3;
BB3 :
you have BB3 in BB2's dominance frontier but not in BB1's, so that the
init-set of BB3 includes r10 and r12, but not r11. Note that we do
not need to iterate the dominance frontier, because we do not insert
anything like PHI functions there! Instead, dataflow will take care of
propagating the information to BB3's successors.
---------------------------------------------------------------------------*/
/* Set basic block info. */
static void
df_md_set_bb_info (unsigned int index,
struct df_md_bb_info *bb_info)
{
gcc_assert (df_md);
gcc_assert (index < df_md->block_info_size);
df_md->block_info[index] = bb_info;
}
static void
df_md_free_bb_info (basic_block bb ATTRIBUTE_UNUSED,
void *vbb_info)
{
struct df_md_bb_info *bb_info = (struct df_md_bb_info *) vbb_info;
if (bb_info)
{
BITMAP_FREE (bb_info->kill);
BITMAP_FREE (bb_info->gen);
BITMAP_FREE (bb_info->init);
BITMAP_FREE (bb_info->in);
BITMAP_FREE (bb_info->out);
pool_free (df_md->block_pool, bb_info);
}
}
/* Allocate or reset bitmaps for DF_MD. The solution bits are
not touched unless the block is new. */
static void
df_md_alloc (bitmap all_blocks)
{
unsigned int bb_index;
bitmap_iterator bi;
if (!df_md->block_pool)
df_md->block_pool = create_alloc_pool ("df_md_block pool",
sizeof (struct df_md_bb_info), 50);
df_grow_bb_info (df_md);
EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index);
if (bb_info)
{
bitmap_clear (bb_info->init);
bitmap_clear (bb_info->gen);
bitmap_clear (bb_info->kill);
bitmap_clear (bb_info->in);
bitmap_clear (bb_info->out);
}
else
{
bb_info = (struct df_md_bb_info *) pool_alloc (df_md->block_pool);
df_md_set_bb_info (bb_index, bb_info);
bb_info->init = BITMAP_ALLOC (NULL);
bb_info->gen = BITMAP_ALLOC (NULL);
bb_info->kill = BITMAP_ALLOC (NULL);
bb_info->in = BITMAP_ALLOC (NULL);
bb_info->out = BITMAP_ALLOC (NULL);
}
}
df_md->optional_p = true;
}
/* Add the effect of the top artificial defs of BB to the multiple definitions
bitmap LOCAL_MD. */
void
df_md_simulate_artificial_defs_at_top (basic_block bb, bitmap local_md)
{
int bb_index = bb->index;
df_ref *def_rec;
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)
{
unsigned int dregno = DF_REF_REGNO (def);
if (DF_REF_FLAGS (def)
& (DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER))
bitmap_set_bit (local_md, dregno);
else
bitmap_clear_bit (local_md, dregno);
}
}
}
/* Add the effect of the defs of INSN to the reaching definitions bitmap
LOCAL_MD. */
void
df_md_simulate_one_insn (basic_block bb ATTRIBUTE_UNUSED, rtx insn,
bitmap local_md)
{
unsigned uid = INSN_UID (insn);
df_ref *def_rec;
for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
{
df_ref def = *def_rec;
unsigned int dregno = DF_REF_REGNO (def);
if ((!(df->changeable_flags & DF_NO_HARD_REGS))
|| (dregno >= FIRST_PSEUDO_REGISTER))
{
if (DF_REF_FLAGS (def)
& (DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER))
bitmap_set_bit (local_md, DF_REF_ID (def));
else
bitmap_clear_bit (local_md, DF_REF_ID (def));
}
}
}
static void
df_md_bb_local_compute_process_def (struct df_md_bb_info *bb_info,
df_ref *def_rec,
int top_flag)
{
df_ref def;
bitmap_clear (seen_in_insn);
while ((def = *def_rec++) != NULL)
{
unsigned int dregno = DF_REF_REGNO (def);
if (((!(df->changeable_flags & DF_NO_HARD_REGS))
|| (dregno >= FIRST_PSEUDO_REGISTER))
&& top_flag == (DF_REF_FLAGS (def) & DF_REF_AT_TOP))
{
if (!bitmap_bit_p (seen_in_insn, dregno))
{
if (DF_REF_FLAGS (def)
& (DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER))
{
bitmap_set_bit (bb_info->gen, dregno);
bitmap_clear_bit (bb_info->kill, dregno);
}
else
{
/* When we find a clobber and a regular def,
make sure the regular def wins. */
bitmap_set_bit (seen_in_insn, dregno);
bitmap_set_bit (bb_info->kill, dregno);
bitmap_clear_bit (bb_info->gen, dregno);
}
}
}
}
}
/* Compute local multiple def info for basic block BB. */
static void
df_md_bb_local_compute (unsigned int bb_index)
{
basic_block bb = BASIC_BLOCK (bb_index);
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index);
rtx insn;
/* Artificials are only hard regs. */
if (!(df->changeable_flags & DF_NO_HARD_REGS))
df_md_bb_local_compute_process_def (bb_info,
df_get_artificial_defs (bb_index),
DF_REF_AT_TOP);
FOR_BB_INSNS (bb, insn)
{
unsigned int uid = INSN_UID (insn);
if (!INSN_P (insn))
continue;
df_md_bb_local_compute_process_def (bb_info, DF_INSN_UID_DEFS (uid), 0);
}
if (!(df->changeable_flags & DF_NO_HARD_REGS))
df_md_bb_local_compute_process_def (bb_info,
df_get_artificial_defs (bb_index),
0);
}
/* Compute local reaching def info for each basic block within BLOCKS. */
static void
df_md_local_compute (bitmap all_blocks)
{
unsigned int bb_index, df_bb_index;
bitmap_iterator bi1, bi2;
basic_block bb;
bitmap *frontiers;
df_set_seen ();
EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi1)
{
df_md_bb_local_compute (bb_index);
}
df_unset_seen ();
frontiers = XNEWVEC (bitmap, last_basic_block);
FOR_ALL_BB (bb)
frontiers[bb->index] = BITMAP_ALLOC (NULL);
compute_dominance_frontiers (frontiers);
/* Add each basic block's kills to the nodes in the frontier of the BB. */
EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi1)
{
bitmap kill = df_md_get_bb_info (bb_index)->kill;
EXECUTE_IF_SET_IN_BITMAP (frontiers[bb_index], 0, df_bb_index, bi2)
{
if (bitmap_bit_p (all_blocks, df_bb_index))
bitmap_ior_into (df_md_get_bb_info (df_bb_index)->init, kill);
}
}
FOR_ALL_BB (bb)
BITMAP_FREE (frontiers[bb->index]);
free (frontiers);
}
/* Reset the global solution for recalculation. */
static void
df_md_reset (bitmap all_blocks)
{
unsigned int bb_index;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index);
gcc_assert (bb_info);
bitmap_clear (bb_info->in);
bitmap_clear (bb_info->out);
}
}
static bool
df_md_transfer_function (int bb_index)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index);
bitmap in = bb_info->in;
bitmap out = bb_info->out;
bitmap gen = bb_info->gen;
bitmap kill = bb_info->kill;
return bitmap_ior_and_compl (out, gen, in, kill);
}
/* Initialize the solution bit vectors for problem. */
static void
df_md_init (bitmap all_blocks)
{
unsigned int bb_index;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index);
bitmap_copy (bb_info->in, bb_info->init);
df_md_transfer_function (bb_index);
}
}
static void
df_md_confluence_0 (basic_block bb)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb->index);
bitmap_copy (bb_info->in, bb_info->init);
}
/* In of target gets or of out of source. */
static void
df_md_confluence_n (edge e)
{
bitmap op1 = df_md_get_bb_info (e->dest->index)->in;
bitmap op2 = df_md_get_bb_info (e->src->index)->out;
if (e->flags & EDGE_FAKE)
return;
if (e->flags & EDGE_EH)
bitmap_ior_and_compl_into (op1, op2, regs_invalidated_by_call_regset);
else
bitmap_ior_into (op1, op2);
}
/* Free all storage associated with the problem. */
static void
df_md_free (void)
{
unsigned int i;
for (i = 0; i < df_md->block_info_size; i++)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (i);
if (bb_info)
{
BITMAP_FREE (bb_info->kill);
BITMAP_FREE (bb_info->gen);
BITMAP_FREE (bb_info->init);
BITMAP_FREE (bb_info->in);
BITMAP_FREE (bb_info->out);
}
}
free_alloc_pool (df_md->block_pool);
df_md->block_info_size = 0;
free (df_md->block_info);
free (df_md);
}
/* Debugging info at top of bb. */
static void
df_md_top_dump (basic_block bb, FILE *file)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb->index);
if (!bb_info || !bb_info->in)
return;
fprintf (file, ";; md in \t");
df_print_regset (file, bb_info->in);
fprintf (file, ";; md init \t");
df_print_regset (file, bb_info->init);
fprintf (file, ";; md gen \t");
df_print_regset (file, bb_info->gen);
fprintf (file, ";; md kill \t");
df_print_regset (file, bb_info->kill);
}
/* Debugging info at bottom of bb. */
static void
df_md_bottom_dump (basic_block bb, FILE *file)
{
struct df_md_bb_info *bb_info = df_md_get_bb_info (bb->index);
if (!bb_info || !bb_info->out)
return;
fprintf (file, ";; md out \t");
df_print_regset (file, bb_info->out);
}
static struct df_problem problem_MD =
{
DF_MD, /* Problem id. */
DF_FORWARD, /* Direction. */
df_md_alloc, /* Allocate the problem specific data. */
df_md_reset, /* Reset global information. */
df_md_free_bb_info, /* Free basic block info. */
df_md_local_compute, /* Local compute function. */
df_md_init, /* Init the solution specific data. */
df_worklist_dataflow, /* Worklist solver. */
df_md_confluence_0, /* Confluence operator 0. */
df_md_confluence_n, /* Confluence operator n. */
df_md_transfer_function, /* Transfer function. */
NULL, /* Finalize function. */
df_md_free, /* Free all of the problem information. */
df_md_free, /* Remove this problem from the stack of dataflow problems. */
NULL, /* Debugging. */
df_md_top_dump, /* Debugging start block. */
df_md_bottom_dump, /* Debugging end block. */
NULL, /* Incremental solution verify start. */
NULL, /* Incremental solution verify end. */
NULL, /* Dependent problem. */
TV_DF_MD, /* Timing variable. */
false /* Reset blocks on dropping out of blocks_to_analyze. */
};
/* Create a new MD instance and add it to the existing instance
of DF. */
void
df_md_add_problem (void)
{
df_add_problem (&problem_MD);
}

View File

@ -52,8 +52,9 @@ union df_ref_d;
#define DF_CHAIN 4 /* Def-Use and/or Use-Def Chains. */
#define DF_BYTE_LR 5 /* Subreg tracking lr. */
#define DF_NOTE 6 /* REG_DEF and REG_UNUSED notes. */
#define DF_MD 7 /* Multiple Definitions. */
#define DF_LAST_PROBLEM_PLUS1 (DF_NOTE + 1)
#define DF_LAST_PROBLEM_PLUS1 (DF_MD + 1)
/* Dataflow direction. */
enum df_flow_dir
@ -619,6 +620,7 @@ struct df
#define DF_LR_BB_INFO(BB) (df_lr_get_bb_info((BB)->index))
#define DF_LIVE_BB_INFO(BB) (df_live_get_bb_info((BB)->index))
#define DF_BYTE_LR_BB_INFO(BB) (df_byte_lr_get_bb_info((BB)->index))
#define DF_MD_BB_INFO(BB) (df_md_get_bb_info((BB)->index))
/* Most transformations that wish to use live register analysis will
use these macros. This info is the and of the lr and live sets. */
@ -802,6 +804,22 @@ struct df_rd_bb_info
};
/* Multiple reaching definitions. All bitmaps are referenced by the
register number. */
struct df_md_bb_info
{
/* Local sets to describe the basic blocks. */
bitmap gen; /* Partial/conditional definitions live at BB out. */
bitmap kill; /* Other definitions that are live at BB out. */
bitmap init; /* Definitions coming from dominance frontier edges. */
/* The results of the dataflow problem. */
bitmap in; /* Just before the block itself. */
bitmap out; /* At the bottom of the block. */
};
/* Live registers, a backwards dataflow problem. All bitmaps are
referenced by the register number. */
@ -862,6 +880,7 @@ extern struct df *df;
#define df_chain (df->problems_by_index[DF_CHAIN])
#define df_byte_lr (df->problems_by_index[DF_BYTE_LR])
#define df_note (df->problems_by_index[DF_NOTE])
#define df_md (df->problems_by_index[DF_MD])
/* This symbol turns on checking that each modification of the cfg has
been identified to the appropriate df routines. It is not part of
@ -955,6 +974,9 @@ extern void df_byte_lr_simulate_uses (rtx, bitmap);
extern void df_byte_lr_simulate_artificial_refs_at_top (basic_block, bitmap);
extern void df_byte_lr_simulate_artificial_refs_at_end (basic_block, bitmap);
extern void df_note_add_problem (void);
extern void df_md_add_problem (void);
extern void df_md_simulate_artificial_defs_at_top (basic_block, bitmap);
extern void df_md_simulate_one_insn (basic_block, rtx, bitmap);
extern void df_simulate_find_defs (rtx, bitmap);
extern void df_simulate_defs (rtx, bitmap);
extern void df_simulate_uses (rtx, bitmap);
@ -1034,6 +1056,15 @@ df_lr_get_bb_info (unsigned int index)
return NULL;
}
static inline struct df_md_bb_info *
df_md_get_bb_info (unsigned int index)
{
if (index < df_md->block_info_size)
return (struct df_md_bb_info *) df_md->block_info[index];
else
return NULL;
}
static inline struct df_live_bb_info *
df_live_get_bb_info (unsigned int index)
{

View File

@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "cfgloop.h"
#include "tree-pass.h"
#include "domwalk.h"
/* This pass does simple forward propagation and simplification when an
@ -100,7 +101,17 @@ along with GCC; see the file COPYING3. If not see
(set (reg:QI 121) (subreg:QI (reg:SI 119) 0))
(set (reg:SI 122) (plus:SI (reg:SI 118) (reg:SI 119)))
where the first two insns are now dead. */
where the first two insns are now dead.
We used to use reaching definitions to find which uses have a
single reaching definition (sounds obvious...), but this is too
complex a problem in nasty testcases like PR33928. Now we use the
multiple definitions problem in df-problems.c. The similarity
between that problem and SSA form creation is taken further, in
that fwprop does a dominator walk to create its chains; however,
instead of creating a PHI function where multiple definitions meet
I just punt and record only singleton use-def chains, which is
all that is needed by fwprop. */
static int num_changes;
@ -108,6 +119,8 @@ static int num_changes;
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;
/* Return the only def in USE's use-def chain, or NULL if there is
@ -120,96 +133,168 @@ get_def_for_use (df_ref use)
}
/* Return the only bit between FIRST and LAST that is set in B,
or -1 if there are zero or more than one such bits. */
/* Update the reg_defs vector with non-partial definitions in DEF_REC.
TOP_FLAG says which artificials uses should be used, when DEF_REC
is an artificial def vector. LOCAL_MD is modified as after a
df_md_simulate_* function; we do more or less the same processing
done there, so we do not use those functions. */
static inline int
bitmap_only_bit_between (const_bitmap b, unsigned first, unsigned last)
#define DF_MD_GEN_FLAGS \
(DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER)
static void
process_defs (bitmap local_md, df_ref *def_rec, int top_flag)
{
bitmap_iterator bi;
unsigned bit, bit2;
if (last < first)
return -1;
bmp_iter_set_init (&bi, b, first, &bit);
if (bmp_iter_set (&bi, &bit) && bit <= last)
df_ref def;
while ((def = *def_rec++) != NULL)
{
bit2 = bit;
bmp_iter_next (&bi, &bit2);
if (!bmp_iter_set (&bi, &bit2) || bit2 > last)
return bit;
df_ref curr_def = VEC_index (df_ref, reg_defs, DF_REF_REGNO (def));
unsigned int dregno;
if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) != top_flag)
continue;
dregno = DF_REF_REGNO (def);
if (curr_def)
VEC_safe_push (df_ref, heap, reg_defs_stack, curr_def);
else
{
/* Do not store anything if "transitioning" from NULL to NULL. But
otherwise, push a special entry on the stack to tell the
leave_block callback that the entry in reg_defs was NULL. */
if (DF_REF_FLAGS (def) & DF_MD_GEN_FLAGS)
;
else
VEC_safe_push (df_ref, heap, reg_defs_stack, def);
}
if (DF_REF_FLAGS (def) & DF_MD_GEN_FLAGS)
{
bitmap_set_bit (local_md, dregno);
VEC_replace (df_ref, reg_defs, dregno, NULL);
}
else
{
bitmap_clear_bit (local_md, dregno);
VEC_replace (df_ref, reg_defs, dregno, def);
}
}
return -1;
}
/* Fill the use_def_ref vector with values for the uses in USE_REC,
taking reaching definitions info from LOCAL_RD. TOP_FLAG says
which artificials uses should be used, when USE_REC is an
artificial use vector. */
taking reaching definitions info from LOCAL_MD and REG_DEFS.
TOP_FLAG says which artificials uses should be used, when USE_REC
is an artificial use vector. */
static void
process_uses (bitmap local_rd, df_ref *use_rec, int top_flag)
process_uses (bitmap local_md, df_ref *use_rec, int top_flag)
{
df_ref use;
while ((use = *use_rec++) != NULL)
if (top_flag == (DF_REF_FLAGS (use) & DF_REF_AT_TOP))
if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == top_flag)
{
unsigned int uregno = DF_REF_REGNO (use);
unsigned int first = DF_DEFS_BEGIN (uregno);
unsigned int last = first + DF_DEFS_COUNT (uregno) - 1;
int defno = bitmap_only_bit_between (local_rd, first, last);
df_ref def = (defno == -1) ? NULL : DF_DEFS_GET (defno);
VEC_replace (df_ref, use_def_ref, DF_REF_ID (use), def);
unsigned int uregno = DF_REF_REGNO (use);
if (VEC_index (df_ref, reg_defs, uregno)
&& !bitmap_bit_p (local_md, uregno))
VEC_replace (df_ref, use_def_ref, DF_REF_ID (use),
VEC_index (df_ref, reg_defs, uregno));
}
}
/* Do dataflow analysis and use reaching definitions to build
a vector holding the reaching definitions of uses that have a
single RD. */
static void
single_def_use_enter_block (struct dom_walk_data *walk_data, 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);
rtx insn;
bitmap_copy (local_md, 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);
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 (local_md, df_get_artificial_uses (bb_index), 0);
process_defs (local_md, df_get_artificial_defs (bb_index), 0);
}
/* Pop the definitions created in this basic block when leaving its
dominated parts. */
static void
single_def_use_leave_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
basic_block bb ATTRIBUTE_UNUSED)
{
df_ref saved_def;
while ((saved_def = VEC_pop (df_ref, reg_defs_stack)) != NULL)
{
unsigned int dregno = DF_REF_REGNO (saved_def);
/* See also process_defs. */
if (saved_def == VEC_index (df_ref, reg_defs, dregno))
VEC_replace (df_ref, reg_defs, dregno, NULL);
else
VEC_replace (df_ref, reg_defs, dregno, saved_def);
}
}
/* Build a vector holding the reaching definitions of uses reached by a
single dominating definition. */
static void
build_single_def_use_links (void)
{
basic_block bb;
bitmap local_rd = BITMAP_ALLOC (NULL);
struct dom_walk_data walk_data;
bitmap local_md;
/* We use reaching definitions to compute our restricted use-def chains. */
/* We use the multiple definitions problem to compute our restricted
use-def chains. */
df_set_flags (DF_EQ_NOTES);
df_rd_add_problem ();
df_md_add_problem ();
df_analyze ();
df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
use_def_ref = VEC_alloc (df_ref, heap, DF_USES_TABLE_SIZE ());
VEC_safe_grow (df_ref, heap, use_def_ref, DF_USES_TABLE_SIZE ());
VEC_safe_grow_cleared (df_ref, heap, use_def_ref, DF_USES_TABLE_SIZE ());
FOR_EACH_BB (bb)
{
int bb_index = bb->index;
struct df_rd_bb_info *bb_info = df_rd_get_bb_info (bb_index);
rtx insn;
reg_defs = VEC_alloc (df_ref, heap, max_reg_num ());
VEC_safe_grow_cleared (df_ref, heap, reg_defs, max_reg_num ());
bitmap_copy (local_rd, bb_info->in);
process_uses (local_rd, df_get_artificial_uses (bb_index), DF_REF_AT_TOP);
reg_defs_stack = VEC_alloc (df_ref, heap, n_basic_blocks * 10);
local_md = BITMAP_ALLOC (NULL);
df_rd_simulate_artificial_defs_at_top (bb, local_rd);
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
{
unsigned int uid = INSN_UID (insn);
process_uses (local_rd, DF_INSN_UID_USES (uid), 0);
process_uses (local_rd, DF_INSN_UID_EQ_USES (uid), 0);
df_rd_simulate_one_insn (bb, insn, local_rd);
}
/* Walk the dominator tree looking for single reaching definitions
dominating the uses. This is similar to how SSA form is built. */
walk_data.dom_direction = CDI_DOMINATORS;
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;
process_uses (local_rd, df_get_artificial_uses (bb_index), 0);
}
init_walk_dominator_tree (&walk_data);
walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
fini_walk_dominator_tree (&walk_data);
BITMAP_FREE (local_rd);
BITMAP_FREE (local_md);
VEC_free (df_ref, heap, reg_defs);
VEC_free (df_ref, heap, reg_defs_stack);
}
/* Do not try to replace constant addresses or addresses of local and
argument slots. These MEM expressions are made only once and inserted
@ -629,12 +714,12 @@ use_killed_between (df_ref use, rtx def_insn, rtx target_insn)
int regno;
df_ref def;
/* In some obscure situations we can have a def reaching a use
that is _before_ the def. In other words the def does not
dominate the use even though the use and def are in the same
basic block. This can happen when a register may be used
uninitialized in a loop. In such cases, we must assume that
DEF is not available. */
/* We used to have a def reaching a use that is _before_ the def,
with the def not dominating the use even though the use and def
are in the same basic block, when a register may be used
uninitialized in a loop. This should not happen anymore since
we do not use reaching definitions, but still we test for such
cases and assume that DEF is not available. */
if (def_bb == target_bb
? DF_INSN_LUID (def_insn) >= DF_INSN_LUID (target_insn)
: !dominated_by_p (CDI_DOMINATORS, target_bb, def_bb))

View File

@ -58,7 +58,7 @@ DEFTIMEVAR (TV_LIFE_UPDATE , "life info update")
/* Time spent in dataflow problems. */
DEFTIMEVAR (TV_DF_SCAN , "df scan insns")
DEFTIMEVAR (TV_DF_RU , "df reaching uses")
DEFTIMEVAR (TV_DF_MD , "df multiple defs")
DEFTIMEVAR (TV_DF_RD , "df reaching defs")
DEFTIMEVAR (TV_DF_LR , "df live regs")
DEFTIMEVAR (TV_DF_LIVE , "df live&initialized regs")