Commit ff2ad0f7 by Diego Novillo Committed by Diego Novillo

common.opt (ftree-fre): New flag.


	* common.opt (ftree-fre): New flag.
	* flags.h (flag_tree_fre): Declare.
	* opts.c (decode_options): Set.
	* timevar.def (TV_TREE_FRE): Define.
	* tree-flow-inline.h (may_propagate_copy): Re-arrange for
	readability.  Handle destinations that are not SSA_NAMEs.
	* tree-flow.h (struct ptr_info_def): Move from tree.h
	(cprop_into_stmt, cprop_into_successor_phis): Remove.
	(vn_compute, vn_lookup_or_add, vn_add, vn_lookup): Add
	vuse_optype parameter.
	* tree-pass.h (pass_fre): Declare.
	* tree-ssa-copy.c (cprop_operand): Move to tree-ssa-dom.c
	(cprop_into_stmt): Likewise.
	(cprop_into_successor_phis): Likewise.
	* tree-ssa-dom.c (eliminate_redundant_computations): Fix
	argument ordering in call to may_propagate_copy.
	* tree-ssa-pre.c (is_undefined_value): Assume hard registers
	to be always defined.
	(add_to_sets): New local function.
	(create_value_expr_from): New local function.
	(compute_avail): Call them.
	(eliminate): Don't ignore statements with virtual operands.
	(init_pre): New local function.
	(fini_pre): New local function.
	(execute_pre): Call them.
	Add argument DO_FRE.  Don't do insertion if DO_FRE is true.
	(do_pre): New function.
	(do_fre): New function.
	(gate_fre): New function.
	(pass_fre): Declare.
	* tree-ssa.c (init_tree_ssa): Don't call vn_init.
	(delete_tree_ssa): Don't call vn_delete.
	* tree-vn.c (val_expr_pair_d): Add documentation.
	(vn_compute): Add VUSES argument to incorporate in computing
	hash values.  Update all callers.
	(expressions_equal_p): Call operand_equal_p with
	OEP_PURE_SAME.
	(vn_add): Add VUSES argument.  Update all callers.
	(vn_lookup): Likewise.
	(vn_lookup_or_add): Likewise.
	* doc/invoke.texi: Document -ftree-fre and -fdump-tree-fre.

From-SVN: r83837
parent 7b63e340
2004-06-28 Diego Novillo <dnovillo@redhat.com>
* common.opt (ftree-fre): New flag.
* flags.h (flag_tree_fre): Declare.
* opts.c (decode_options): Set.
* timevar.def (TV_TREE_FRE): Define.
* tree-flow-inline.h (may_propagate_copy): Re-arrange for
readability. Handle destinations that are not SSA_NAMEs.
* tree-flow.h (struct ptr_info_def): Move from tree.h
(cprop_into_stmt, cprop_into_successor_phis): Remove.
(vn_compute, vn_lookup_or_add, vn_add, vn_lookup): Add
vuse_optype parameter.
* tree-pass.h (pass_fre): Declare.
* tree-ssa-copy.c (cprop_operand): Move to tree-ssa-dom.c
(cprop_into_stmt): Likewise.
(cprop_into_successor_phis): Likewise.
* tree-ssa-dom.c (eliminate_redundant_computations): Fix
argument ordering in call to may_propagate_copy.
* tree-ssa-pre.c (is_undefined_value): Assume hard registers
to be always defined.
(add_to_sets): New local function.
(create_value_expr_from): New local function.
(compute_avail): Call them.
(eliminate): Don't ignore statements with virtual operands.
(init_pre): New local function.
(fini_pre): New local function.
(execute_pre): Call them.
Add argument DO_FRE. Don't do insertion if DO_FRE is true.
(do_pre): New function.
(do_fre): New function.
(gate_fre): New function.
(pass_fre): Declare.
* tree-ssa.c (init_tree_ssa): Don't call vn_init.
(delete_tree_ssa): Don't call vn_delete.
* tree-vn.c (val_expr_pair_d): Add documentation.
(vn_compute): Add VUSES argument to incorporate in computing
hash values. Update all callers.
(expressions_equal_p): Call operand_equal_p with
OEP_PURE_SAME.
(vn_add): Add VUSES argument. Update all callers.
(vn_lookup): Likewise.
(vn_lookup_or_add): Likewise.
* doc/invoke.texi: Document -ftree-fre and -fdump-tree-fre.
2004-06-28 Steven Bosscher <stevenb@suse.de> 2004-06-28 Steven Bosscher <stevenb@suse.de>
* config/m32r/m32r.c (m32r_sched_odd_word_p, m32r_adjust_cost, * config/m32r/m32r.c (m32r_sched_odd_word_p, m32r_adjust_cost,
......
...@@ -773,6 +773,10 @@ ftree-dse ...@@ -773,6 +773,10 @@ ftree-dse
Common Report Var(flag_tree_dse) Common Report Var(flag_tree_dse)
Enable dead store elimination Enable dead store elimination
ftree-fre
Common Report Var(flag_tree_fre)
Enable Full Redundancy Elimination (FRE) on trees
ftree-points-to= ftree-points-to=
Common Joined RejectNegative Common Joined RejectNegative
......
...@@ -262,6 +262,7 @@ in the following sections. ...@@ -262,6 +262,7 @@ in the following sections.
-fdump-tree-copyrename@r{[}-@var{n}@r{]} @gol -fdump-tree-copyrename@r{[}-@var{n}@r{]} @gol
-fdump-tree-nrv @gol -fdump-tree-nrv @gol
-fdump-tree-sra@r{[}-@var{n}@r{]} @gol -fdump-tree-sra@r{[}-@var{n}@r{]} @gol
-fdump-tree-fre@r{[}-@var{n}@r{]} @gol
-feliminate-dwarf2-dups -feliminate-unused-debug-types @gol -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol
-feliminate-unused-debug-symbols -fmem-report -fprofile-arcs -ftree-based-profiling @gol -feliminate-unused-debug-symbols -fmem-report -fprofile-arcs -ftree-based-profiling @gol
-frandom-seed=@var{string} -fsched-verbose=@var{n} @gol -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol
...@@ -313,7 +314,7 @@ in the following sections. ...@@ -313,7 +314,7 @@ in the following sections.
-funswitch-loops -fold-unroll-loops -fold-unroll-all-loops @gol -funswitch-loops -fold-unroll-loops -fold-unroll-all-loops @gol
-ftree-pre -ftree-ccp -ftree-dce @gol -ftree-pre -ftree-ccp -ftree-dce @gol
-ftree-dominator-opts -ftree-dse -ftree-copyrename @gol -ftree-dominator-opts -ftree-dse -ftree-copyrename @gol
-ftree-ch -ftree-sra -ftree-ter -ftree-lrs @gol -ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre @gol
--param @var{name}=@var{value} --param @var{name}=@var{value}
-O -O0 -O1 -O2 -O3 -Os} -O -O0 -O1 -O2 -O3 -Os}
...@@ -3553,6 +3554,11 @@ Dump each function after CCP. The file name is made by appending ...@@ -3553,6 +3554,11 @@ Dump each function after CCP. The file name is made by appending
Dump trees after partial redundancy elimination. The file name is made Dump trees after partial redundancy elimination. The file name is made
by appending @file{.pre} to the source file name. by appending @file{.pre} to the source file name.
@item fre
@opindex fdump-tree-fre
Dump trees after full redundancy elimination. The file name is made
by appending @file{.fre} to the source file name.
@item dce @item dce
@opindex fdump-tree-dce @opindex fdump-tree-dce
Dump each function after dead code elimination. The file name is made by Dump each function after dead code elimination. The file name is made by
...@@ -4369,6 +4375,13 @@ Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}. ...@@ -4369,6 +4375,13 @@ Enabled at levels @option{-O2}, @option{-O3}, @option{-Os}.
Perform Partial Redundancy Elimination (PRE) on trees. This flag is Perform Partial Redundancy Elimination (PRE) on trees. This flag is
enabled by default at -O and higher. enabled by default at -O and higher.
@item -ftree-fre
Perform Full Redundancy Elimination (FRE) on trees. The difference
between FRE and PRE is that FRE only considers expressions
that are computed on all paths leading to the redundant computation.
This analysis faster than PRE, though it exposes fewer redundancies.
This flag is enabled by default at -O and higher.
@item -ftree-ccp @item -ftree-ccp
Perform sparse conditional constant propagation (CCP) on trees. This flag Perform sparse conditional constant propagation (CCP) on trees. This flag
is enabled by default at -O and higher. is enabled by default at -O and higher.
......
...@@ -700,6 +700,9 @@ enum pta_type ...@@ -700,6 +700,9 @@ enum pta_type
}; };
extern enum pta_type flag_tree_points_to; extern enum pta_type flag_tree_points_to;
/* Enable FRE (Full Redundancy Elimination) on trees. */
extern int flag_tree_fre;
/* Nonzero means put zero initialized data in the bss section. */ /* Nonzero means put zero initialized data in the bss section. */
extern int flag_zero_initialized_in_bss; extern int flag_zero_initialized_in_bss;
......
...@@ -495,6 +495,7 @@ decode_options (unsigned int argc, const char **argv) ...@@ -495,6 +495,7 @@ decode_options (unsigned int argc, const char **argv)
flag_tree_live_range_split = 1; flag_tree_live_range_split = 1;
flag_tree_sra = 1; flag_tree_sra = 1;
flag_tree_copyrename = 1; flag_tree_copyrename = 1;
flag_tree_fre = 1;
if (!optimize_size) if (!optimize_size)
{ {
......
...@@ -75,6 +75,7 @@ DEFTIMEVAR (TV_TREE_SRA , "tree SRA") ...@@ -75,6 +75,7 @@ DEFTIMEVAR (TV_TREE_SRA , "tree SRA")
DEFTIMEVAR (TV_TREE_CCP , "tree CCP") DEFTIMEVAR (TV_TREE_CCP , "tree CCP")
DEFTIMEVAR (TV_TREE_SPLIT_EDGES , "tree split crit edges") DEFTIMEVAR (TV_TREE_SPLIT_EDGES , "tree split crit edges")
DEFTIMEVAR (TV_TREE_PRE , "tree PRE") DEFTIMEVAR (TV_TREE_PRE , "tree PRE")
DEFTIMEVAR (TV_TREE_FRE , "tree FRE")
DEFTIMEVAR (TV_TREE_PHIOPT , "tree linearize phis") DEFTIMEVAR (TV_TREE_PHIOPT , "tree linearize phis")
DEFTIMEVAR (TV_TREE_FORWPROP , "tree forward propagate") DEFTIMEVAR (TV_TREE_FORWPROP , "tree forward propagate")
DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE") DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE")
......
...@@ -541,10 +541,20 @@ may_propagate_copy (tree dest, tree orig) ...@@ -541,10 +541,20 @@ may_propagate_copy (tree dest, tree orig)
return false; return false;
} }
return (!SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest) /* If ORIG flows in from an abnormal edge, it cannot be propagated. */
&& (TREE_CODE (orig) != SSA_NAME if (TREE_CODE (orig) == SSA_NAME
|| !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig)) && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig))
&& !DECL_HARD_REGISTER (SSA_NAME_VAR (dest))); return false;
/* If DEST is an SSA_NAME that flows from an abnormal edge or if it
represents a hard register, then it cannot be replaced. */
if (TREE_CODE (dest) == SSA_NAME
&& (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest)
|| DECL_HARD_REGISTER (SSA_NAME_VAR (dest))))
return false;
/* Anything else is OK. */
return true;
} }
/* Set the default definition for VAR to DEF. */ /* Set the default definition for VAR to DEF. */
......
...@@ -38,6 +38,39 @@ typedef struct basic_block_def *basic_block; ...@@ -38,6 +38,39 @@ typedef struct basic_block_def *basic_block;
#endif #endif
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Attributes for SSA_NAMEs.
NOTE: These structures are stored in struct tree_ssa_name
but are only used by the tree optimizers, so it makes better sense
to declare them here to avoid recompiling unrelated files when
making changes.
---------------------------------------------------------------------------*/
/* Aliasing information for SSA_NAMEs representing pointer variables. */
struct ptr_info_def GTY(())
{
/* Nonzero if points-to analysis couldn't determine where this pointer
is pointing to. */
unsigned int pt_anything : 1;
/* Nonzero if this pointer is the result of a call to malloc. */
unsigned int pt_malloc : 1;
/* Nonzero if the value of this pointer escapes the current function. */
unsigned int value_escapes_p : 1;
/* Set of variables that this pointer may point to. */
bitmap pt_vars;
/* If this pointer has been dereferenced, and points-to information is
more precise than type-based aliasing, indirect references to this
pointer will be represented by this memory tag, instead of the type
tag computed by TBAA. */
tree name_mem_tag;
};
/*---------------------------------------------------------------------------
Tree annotations stored in tree_common.ann Tree annotations stored in tree_common.ann
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
enum tree_ann_type { TREE_ANN_COMMON, VAR_ANN, STMT_ANN }; enum tree_ann_type { TREE_ANN_COMMON, VAR_ANN, STMT_ANN };
...@@ -554,8 +587,6 @@ extern void debug_dominator_optimization_stats (void); ...@@ -554,8 +587,6 @@ extern void debug_dominator_optimization_stats (void);
extern void propagate_value (use_operand_p, tree); extern void propagate_value (use_operand_p, tree);
extern void propagate_tree_value (tree *, tree); extern void propagate_tree_value (tree *, tree);
extern void replace_exp (use_operand_p, tree); extern void replace_exp (use_operand_p, tree);
extern bool cprop_into_stmt (tree, varray_type);
extern void cprop_into_successor_phis (basic_block, varray_type, bitmap);
/* In tree-flow-inline.h */ /* In tree-flow-inline.h */
static inline int phi_arg_from_edge (tree, edge); static inline int phi_arg_from_edge (tree, edge);
...@@ -578,12 +609,12 @@ void print_value_expressions (FILE *, tree); ...@@ -578,12 +609,12 @@ void print_value_expressions (FILE *, tree);
/* In tree-vn.c */ /* In tree-vn.c */
bool expressions_equal_p (tree e1, tree e2); bool expressions_equal_p (tree, tree);
tree get_value_handle (tree); tree get_value_handle (tree);
hashval_t vn_compute (tree, hashval_t); hashval_t vn_compute (tree, hashval_t, vuse_optype);
tree vn_lookup_or_add (tree); tree vn_lookup_or_add (tree, vuse_optype);
void vn_add (tree, tree); void vn_add (tree, tree, vuse_optype);
tree vn_lookup (tree); tree vn_lookup (tree, vuse_optype);
void vn_init (void); void vn_init (void);
void vn_delete (void); void vn_delete (void);
......
...@@ -131,6 +131,7 @@ extern struct tree_opt_pass pass_remove_useless_vars; ...@@ -131,6 +131,7 @@ extern struct tree_opt_pass pass_remove_useless_vars;
extern struct tree_opt_pass pass_rename_ssa_copies; extern struct tree_opt_pass pass_rename_ssa_copies;
extern struct tree_opt_pass pass_expand; extern struct tree_opt_pass pass_expand;
extern struct tree_opt_pass pass_rest_of_compilation; extern struct tree_opt_pass pass_rest_of_compilation;
extern struct tree_opt_pass pass_fre;
#endif /* GCC_TREE_PASS_H */ #endif /* GCC_TREE_PASS_H */
...@@ -111,6 +111,7 @@ replace_exp_1 (use_operand_p op_p, tree val, bool for_propagation) ...@@ -111,6 +111,7 @@ replace_exp_1 (use_operand_p op_p, tree val, bool for_propagation)
SET_USE (op_p, lhd_unsave_expr_now (val)); SET_USE (op_p, lhd_unsave_expr_now (val));
} }
/* Propagate the value VAL (assumed to be a constant or another SSA_NAME) /* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
into the operand pointed by OP_P. into the operand pointed by OP_P.
...@@ -123,6 +124,7 @@ propagate_value (use_operand_p op_p, tree val) ...@@ -123,6 +124,7 @@ propagate_value (use_operand_p op_p, tree val)
replace_exp_1 (op_p, val, true); replace_exp_1 (op_p, val, true);
} }
/* Propagate the value VAL (assumed to be a constant or another SSA_NAME) /* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
into the tree pointed by OP_P. into the tree pointed by OP_P.
...@@ -144,6 +146,7 @@ propagate_tree_value (tree *op_p, tree val) ...@@ -144,6 +146,7 @@ propagate_tree_value (tree *op_p, tree val)
*op_p = lhd_unsave_expr_now (val); *op_p = lhd_unsave_expr_now (val);
} }
/* Replace *OP_P with value VAL (assumed to be a constant or another SSA_NAME). /* Replace *OP_P with value VAL (assumed to be a constant or another SSA_NAME).
Use this version when not const/copy propagating values. For example, Use this version when not const/copy propagating values. For example,
...@@ -155,236 +158,3 @@ replace_exp (use_operand_p op_p, tree val) ...@@ -155,236 +158,3 @@ replace_exp (use_operand_p op_p, tree val)
{ {
replace_exp_1 (op_p, val, false); replace_exp_1 (op_p, val, false);
} }
/* Replace *OP_P in STMT with any known equivalent value for *OP_P from
CONST_AND_COPIES. */
static bool
cprop_operand (stmt_ann_t ann, use_operand_p op_p, varray_type const_and_copies)
{
bool may_have_exposed_new_symbols = false;
tree val;
tree op = USE_FROM_PTR (op_p);
/* If the operand has a known constant value or it is known to be a
copy of some other variable, use the value or copy stored in
CONST_AND_COPIES. */
val = VARRAY_TREE (const_and_copies, SSA_NAME_VERSION (op));
if (val)
{
tree op_type, val_type;
/* Do not change the base variable in the virtual operand
tables. That would make it impossible to reconstruct
the renamed virtual operand if we later modify this
statement. Also only allow the new value to be an SSA_NAME
for propagation into virtual operands. */
if (!is_gimple_reg (op)
&& (get_virtual_var (val) != get_virtual_var (op)
|| TREE_CODE (val) != SSA_NAME))
return false;
/* Get the toplevel type of each operand. */
op_type = TREE_TYPE (op);
val_type = TREE_TYPE (val);
/* While both types are pointers, get the type of the object
pointed to. */
while (POINTER_TYPE_P (op_type) && POINTER_TYPE_P (val_type))
{
op_type = TREE_TYPE (op_type);
val_type = TREE_TYPE (val_type);
}
/* Make sure underlying types match before propagating a
constant by converting the constant to the proper type. Note
that convert may return a non-gimple expression, in which case
we ignore this propagation opportunity. */
if (!lang_hooks.types_compatible_p (op_type, val_type)
&& TREE_CODE (val) != SSA_NAME)
{
val = fold_convert (TREE_TYPE (op), val);
if (!is_gimple_min_invariant (val)
&& TREE_CODE (val) != SSA_NAME)
return false;
}
/* Certain operands are not allowed to be copy propagated due
to their interaction with exception handling and some GCC
extensions. */
if (TREE_CODE (val) == SSA_NAME
&& !may_propagate_copy (op, val))
return false;
/* Dump details. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " Replaced '");
print_generic_expr (dump_file, op, dump_flags);
fprintf (dump_file, "' with %s '",
(TREE_CODE (val) != SSA_NAME ? "constant" : "variable"));
print_generic_expr (dump_file, val, dump_flags);
fprintf (dump_file, "'\n");
}
/* If VAL is an ADDR_EXPR or a constant of pointer type, note
that we may have exposed a new symbol for SSA renaming. */
if (TREE_CODE (val) == ADDR_EXPR
|| (POINTER_TYPE_P (TREE_TYPE (op))
&& is_gimple_min_invariant (val)))
may_have_exposed_new_symbols = true;
propagate_value (op_p, val);
/* And note that we modified this statement. This is now
safe, even if we changed virtual operands since we will
rescan the statement and rewrite its operands again. */
ann->modified = 1;
}
return may_have_exposed_new_symbols;
}
/* CONST_AND_COPIES is a table which maps an SSA_NAME to the current
known value for that SSA_NAME (or NULL if no value is known).
Propagate values from CONST_AND_COPIES into the uses, vuses and
v_may_def_ops of STMT. */
bool
cprop_into_stmt (tree stmt, varray_type const_and_copies)
{
bool may_have_exposed_new_symbols = false;
stmt_ann_t ann = stmt_ann (stmt);
size_t i, num_uses, num_vuses, num_v_may_defs;
vuse_optype vuses;
v_may_def_optype v_may_defs;
use_optype uses;
uses = USE_OPS (ann);
num_uses = NUM_USES (uses);
for (i = 0; i < num_uses; i++)
{
use_operand_p op_p = USE_OP_PTR (uses, i);
if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
may_have_exposed_new_symbols
|= cprop_operand (ann, op_p, const_and_copies);
}
vuses = VUSE_OPS (ann);
num_vuses = NUM_VUSES (vuses);
for (i = 0; i < num_vuses; i++)
{
use_operand_p op_p = VUSE_OP_PTR (vuses, i);
if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
may_have_exposed_new_symbols
|= cprop_operand (ann, op_p, const_and_copies);
}
v_may_defs = V_MAY_DEF_OPS (ann);
num_v_may_defs = NUM_V_MAY_DEFS (v_may_defs);
for (i = 0; i < num_v_may_defs; i++)
{
use_operand_p op_p = V_MAY_DEF_OP_PTR (v_may_defs, i);
if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
may_have_exposed_new_symbols
|= cprop_operand (ann, op_p, const_and_copies);
}
return may_have_exposed_new_symbols;
}
/* CONST_AND_COPIES is a table which maps an SSA_NAME to the current
known value for that SSA_NAME (or NULL if no value is known).
NONZERO_VARS is the set SSA_NAMES known to have a nonzero value,
even if we don't know their precise value.
Propagate values from CONST_AND_COPIES and NONZERO_VARS into the PHI
nodes of the successors of BB. */
void
cprop_into_successor_phis (basic_block bb,
varray_type const_and_copies,
bitmap nonzero_vars)
{
edge e;
/* This can get rather expensive if the implementation is naive in
how it finds the phi alternative associated with a particular edge. */
for (e = bb->succ; e; e = e->succ_next)
{
tree phi;
int phi_num_args;
int hint;
/* If this is an abnormal edge, then we do not want to copy propagate
into the PHI alternative associated with this edge. */
if (e->flags & EDGE_ABNORMAL)
continue;
phi = phi_nodes (e->dest);
if (! phi)
continue;
/* There is no guarantee that for any two PHI nodes in a block that
the phi alternative associated with a particular edge will be
at the same index in the phi alternative array.
However, it is very likely they will be the same. So we keep
track of the index of the alternative where we found the edge in
the previous phi node and check that index first in the next
phi node. If that hint fails, then we actually search all
the entries. */
phi_num_args = PHI_NUM_ARGS (phi);
hint = phi_num_args;
for ( ; phi; phi = PHI_CHAIN (phi))
{
int i;
tree new;
use_operand_p orig_p;
tree orig;
/* If the hint is valid (!= phi_num_args), see if it points
us to the desired phi alternative. */
if (hint != phi_num_args && PHI_ARG_EDGE (phi, hint) == e)
;
else
{
/* The hint was either invalid or did not point to the
correct phi alternative. Search all the alternatives
for the correct one. Update the hint. */
for (i = 0; i < phi_num_args; i++)
if (PHI_ARG_EDGE (phi, i) == e)
break;
hint = i;
}
#ifdef ENABLE_CHECKING
/* If we did not find the proper alternative, then something is
horribly wrong. */
if (hint == phi_num_args)
abort ();
#endif
/* The alternative may be associated with a constant, so verify
it is an SSA_NAME before doing anything with it. */
orig_p = PHI_ARG_DEF_PTR (phi, hint);
orig = USE_FROM_PTR (orig_p);
if (TREE_CODE (orig) != SSA_NAME)
continue;
/* If the alternative is known to have a nonzero value, record
that fact in the PHI node itself for future use. */
if (bitmap_bit_p (nonzero_vars, SSA_NAME_VERSION (orig)))
PHI_ARG_NONZERO (phi, hint) = true;
/* If we have *ORIG_P in our constant/copy table, then replace
ORIG_P with its value in our constant/copy table. */
new = VARRAY_TREE (const_and_copies, SSA_NAME_VERSION (orig));
if (new
&& (TREE_CODE (new) == SSA_NAME
|| is_gimple_min_invariant (new))
&& may_propagate_copy (orig, new))
propagate_value (orig_p, new);
}
}
}
...@@ -529,14 +529,9 @@ redirect_edges_and_update_ssa_graph (varray_type redirection_edges) ...@@ -529,14 +529,9 @@ redirect_edges_and_update_ssa_graph (varray_type redirection_edges)
/* Jump threading, redundancy elimination and const/copy propagation. /* Jump threading, redundancy elimination and const/copy propagation.
Optimize function FNDECL based on a walk through the dominator tree.
This pass may expose new symbols that need to be renamed into SSA. For This pass may expose new symbols that need to be renamed into SSA. For
every new symbol exposed, its corresponding bit will be set in every new symbol exposed, its corresponding bit will be set in
VARS_TO_RENAME. VARS_TO_RENAME. */
PHASE indicates which dump file from the DUMP_FILES array to use when
dumping debugging information. */
static void static void
tree_ssa_dominator_optimize (void) tree_ssa_dominator_optimize (void)
...@@ -2453,6 +2448,107 @@ simplify_switch_and_lookup_avail_expr (tree stmt, ...@@ -2453,6 +2448,107 @@ simplify_switch_and_lookup_avail_expr (tree stmt,
return 0; return 0;
} }
/* CONST_AND_COPIES is a table which maps an SSA_NAME to the current
known value for that SSA_NAME (or NULL if no value is known).
NONZERO_VARS is the set SSA_NAMES known to have a nonzero value,
even if we don't know their precise value.
Propagate values from CONST_AND_COPIES and NONZERO_VARS into the PHI
nodes of the successors of BB. */
static void
cprop_into_successor_phis (basic_block bb,
varray_type const_and_copies,
bitmap nonzero_vars)
{
edge e;
/* This can get rather expensive if the implementation is naive in
how it finds the phi alternative associated with a particular edge. */
for (e = bb->succ; e; e = e->succ_next)
{
tree phi;
int phi_num_args;
int hint;
/* If this is an abnormal edge, then we do not want to copy propagate
into the PHI alternative associated with this edge. */
if (e->flags & EDGE_ABNORMAL)
continue;
phi = phi_nodes (e->dest);
if (! phi)
continue;
/* There is no guarantee that for any two PHI nodes in a block that
the phi alternative associated with a particular edge will be
at the same index in the phi alternative array.
However, it is very likely they will be the same. So we keep
track of the index of the alternative where we found the edge in
the previous phi node and check that index first in the next
phi node. If that hint fails, then we actually search all
the entries. */
phi_num_args = PHI_NUM_ARGS (phi);
hint = phi_num_args;
for ( ; phi; phi = PHI_CHAIN (phi))
{
int i;
tree new;
use_operand_p orig_p;
tree orig;
/* If the hint is valid (!= phi_num_args), see if it points
us to the desired phi alternative. */
if (hint != phi_num_args && PHI_ARG_EDGE (phi, hint) == e)
;
else
{
/* The hint was either invalid or did not point to the
correct phi alternative. Search all the alternatives
for the correct one. Update the hint. */
for (i = 0; i < phi_num_args; i++)
if (PHI_ARG_EDGE (phi, i) == e)
break;
hint = i;
}
#ifdef ENABLE_CHECKING
/* If we did not find the proper alternative, then something is
horribly wrong. */
if (hint == phi_num_args)
abort ();
#endif
/* The alternative may be associated with a constant, so verify
it is an SSA_NAME before doing anything with it. */
orig_p = PHI_ARG_DEF_PTR (phi, hint);
orig = USE_FROM_PTR (orig_p);
if (TREE_CODE (orig) != SSA_NAME)
continue;
/* If the alternative is known to have a nonzero value, record
that fact in the PHI node itself for future use. */
if (bitmap_bit_p (nonzero_vars, SSA_NAME_VERSION (orig)))
PHI_ARG_NONZERO (phi, hint) = true;
/* If we have *ORIG_P in our constant/copy table, then replace
ORIG_P with its value in our constant/copy table. */
new = VARRAY_TREE (const_and_copies, SSA_NAME_VERSION (orig));
if (new
&& (TREE_CODE (new) == SSA_NAME
|| is_gimple_min_invariant (new))
&& may_propagate_copy (orig, new))
{
propagate_value (orig_p, new);
}
}
}
}
/* Propagate known constants/copies into PHI nodes of BB's successor /* Propagate known constants/copies into PHI nodes of BB's successor
blocks. */ blocks. */
...@@ -2538,7 +2634,7 @@ eliminate_redundant_computations (struct dom_walk_data *walk_data, ...@@ -2538,7 +2634,7 @@ eliminate_redundant_computations (struct dom_walk_data *walk_data,
CACHED_LHS into *EXPR_P. */ CACHED_LHS into *EXPR_P. */
if (cached_lhs if (cached_lhs
&& (TREE_CODE (cached_lhs) != SSA_NAME && (TREE_CODE (cached_lhs) != SSA_NAME
|| may_propagate_copy (cached_lhs, *expr_p))) || may_propagate_copy (*expr_p, cached_lhs)))
{ {
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
...@@ -2736,6 +2832,143 @@ record_equivalences_from_stmt (tree stmt, ...@@ -2736,6 +2832,143 @@ record_equivalences_from_stmt (tree stmt,
} }
} }
/* Replace *OP_P in STMT with any known equivalent value for *OP_P from
CONST_AND_COPIES. */
static bool
cprop_operand (stmt_ann_t ann, use_operand_p op_p, varray_type const_and_copies)
{
bool may_have_exposed_new_symbols = false;
tree val;
tree op = USE_FROM_PTR (op_p);
/* If the operand has a known constant value or it is known to be a
copy of some other variable, use the value or copy stored in
CONST_AND_COPIES. */
val = VARRAY_TREE (const_and_copies, SSA_NAME_VERSION (op));
if (val)
{
tree op_type, val_type;
/* Do not change the base variable in the virtual operand
tables. That would make it impossible to reconstruct
the renamed virtual operand if we later modify this
statement. Also only allow the new value to be an SSA_NAME
for propagation into virtual operands. */
if (!is_gimple_reg (op)
&& (get_virtual_var (val) != get_virtual_var (op)
|| TREE_CODE (val) != SSA_NAME))
return false;
/* Get the toplevel type of each operand. */
op_type = TREE_TYPE (op);
val_type = TREE_TYPE (val);
/* While both types are pointers, get the type of the object
pointed to. */
while (POINTER_TYPE_P (op_type) && POINTER_TYPE_P (val_type))
{
op_type = TREE_TYPE (op_type);
val_type = TREE_TYPE (val_type);
}
/* Make sure underlying types match before propagating a
constant by converting the constant to the proper type. Note
that convert may return a non-gimple expression, in which case
we ignore this propagation opportunity. */
if (!lang_hooks.types_compatible_p (op_type, val_type)
&& TREE_CODE (val) != SSA_NAME)
{
val = fold_convert (TREE_TYPE (op), val);
if (!is_gimple_min_invariant (val)
&& TREE_CODE (val) != SSA_NAME)
return false;
}
/* Certain operands are not allowed to be copy propagated due
to their interaction with exception handling and some GCC
extensions. */
if (TREE_CODE (val) == SSA_NAME
&& !may_propagate_copy (op, val))
return false;
/* Dump details. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " Replaced '");
print_generic_expr (dump_file, op, dump_flags);
fprintf (dump_file, "' with %s '",
(TREE_CODE (val) != SSA_NAME ? "constant" : "variable"));
print_generic_expr (dump_file, val, dump_flags);
fprintf (dump_file, "'\n");
}
/* If VAL is an ADDR_EXPR or a constant of pointer type, note
that we may have exposed a new symbol for SSA renaming. */
if (TREE_CODE (val) == ADDR_EXPR
|| (POINTER_TYPE_P (TREE_TYPE (op))
&& is_gimple_min_invariant (val)))
may_have_exposed_new_symbols = true;
propagate_value (op_p, val);
/* And note that we modified this statement. This is now
safe, even if we changed virtual operands since we will
rescan the statement and rewrite its operands again. */
ann->modified = 1;
}
return may_have_exposed_new_symbols;
}
/* CONST_AND_COPIES is a table which maps an SSA_NAME to the current
known value for that SSA_NAME (or NULL if no value is known).
Propagate values from CONST_AND_COPIES into the uses, vuses and
v_may_def_ops of STMT. */
static bool
cprop_into_stmt (tree stmt, varray_type const_and_copies)
{
bool may_have_exposed_new_symbols = false;
stmt_ann_t ann = stmt_ann (stmt);
size_t i, num_uses, num_vuses, num_v_may_defs;
vuse_optype vuses;
v_may_def_optype v_may_defs;
use_optype uses;
uses = USE_OPS (ann);
num_uses = NUM_USES (uses);
for (i = 0; i < num_uses; i++)
{
use_operand_p op_p = USE_OP_PTR (uses, i);
if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
may_have_exposed_new_symbols
|= cprop_operand (ann, op_p, const_and_copies);
}
vuses = VUSE_OPS (ann);
num_vuses = NUM_VUSES (vuses);
for (i = 0; i < num_vuses; i++)
{
use_operand_p op_p = VUSE_OP_PTR (vuses, i);
if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
may_have_exposed_new_symbols
|= cprop_operand (ann, op_p, const_and_copies);
}
v_may_defs = V_MAY_DEF_OPS (ann);
num_v_may_defs = NUM_V_MAY_DEFS (v_may_defs);
for (i = 0; i < num_v_may_defs; i++)
{
use_operand_p op_p = V_MAY_DEF_OP_PTR (v_may_defs, i);
if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
may_have_exposed_new_symbols
|= cprop_operand (ann, op_p, const_and_copies);
}
return may_have_exposed_new_symbols;
}
/* Optimize the statement pointed by iterator SI. /* Optimize the statement pointed by iterator SI.
We try to perform some simplistic global redundancy elimination and We try to perform some simplistic global redundancy elimination and
......
...@@ -497,7 +497,6 @@ init_tree_ssa (void) ...@@ -497,7 +497,6 @@ init_tree_ssa (void)
init_ssa_operands (); init_ssa_operands ();
init_ssanames (); init_ssanames ();
init_phinodes (); init_phinodes ();
vn_init ();
global_var = NULL_TREE; global_var = NULL_TREE;
aliases_computed_p = false; aliases_computed_p = false;
} }
...@@ -528,7 +527,6 @@ delete_tree_ssa (void) ...@@ -528,7 +527,6 @@ delete_tree_ssa (void)
fini_ssanames (); fini_ssanames ();
fini_phinodes (); fini_phinodes ();
fini_ssa_operands (); fini_ssa_operands ();
vn_delete ();
global_var = NULL_TREE; global_var = NULL_TREE;
BITMAP_XFREE (call_clobbered_vars); BITMAP_XFREE (call_clobbered_vars);
......
...@@ -42,7 +42,16 @@ static htab_t value_table; ...@@ -42,7 +42,16 @@ static htab_t value_table;
pairs, and the expression is the key. */ pairs, and the expression is the key. */
typedef struct val_expr_pair_d typedef struct val_expr_pair_d
{ {
tree v, e; /* Value handle. */
tree v;
/* Associated expression. */
tree e;
/* Virtual uses in E. */
vuse_optype vuses;
/* E's hash value. */
hashval_t hashcode; hashval_t hashcode;
} *val_expr_pair_t; } *val_expr_pair_t;
...@@ -63,13 +72,37 @@ make_value_handle (tree type) ...@@ -63,13 +72,37 @@ make_value_handle (tree type)
} }
/* Given an expression or statement P, compute a hash value number using the /* Given an expression EXPR, compute a hash value number using the
code of the expression and its real operands. */ code of the expression, its real operands and virtual operands (if
any).
VAL can be used to iterate by passing previous value numbers (it is
used by iterative_hash_expr).
VUSES is the set of virtual use operands associated with EXPR. It
may be NULL if EXPR has no virtual operands. */
hashval_t hashval_t
vn_compute (tree expr, hashval_t val) vn_compute (tree expr, hashval_t val, vuse_optype vuses)
{ {
size_t i;
#if defined ENABLE_CHECKING
/* EXPR must not be a statement. We are only interested in value
numbering expressions on the RHS of assignments. */
if (expr == NULL_TREE
|| (expr->common.ann
&& expr->common.ann->common.type == STMT_ANN))
abort ();
#endif
val = iterative_hash_expr (expr, val); val = iterative_hash_expr (expr, val);
/* If the expression has virtual uses, incorporate them into the
hash value computed for EXPR. */
for (i = 0; i < NUM_VUSES (vuses); i++)
val = iterative_hash_expr (VUSE_OP (vuses, i), val);
return val; return val;
} }
...@@ -90,7 +123,7 @@ expressions_equal_p (tree e1, tree e2) ...@@ -90,7 +123,7 @@ expressions_equal_p (tree e1, tree e2)
if (TREE_CODE (e1) == TREE_CODE (e2) if (TREE_CODE (e1) == TREE_CODE (e2)
&& (te1 == te2 || lang_hooks.types_compatible_p (te1, te2)) && (te1 == te2 || lang_hooks.types_compatible_p (te1, te2))
&& operand_equal_p (e1, e2, 0)) && operand_equal_p (e1, e2, OEP_PURE_SAME))
return true; return true;
return false; return false;
...@@ -143,41 +176,49 @@ set_value_handle (tree e, tree v) ...@@ -143,41 +176,49 @@ set_value_handle (tree e, tree v)
} }
/* Insert E into VALUE_TABLE with value V, and add expression E to the /* Insert EXPR into VALUE_TABLE with value VAL, and add expression
value set for value V. */ EXPR to the value set for value VAL. VUSES represent the virtual
use operands associated with EXPR (if any). They are used when
computing the hash value for EXPR. */
void void
vn_add (tree e, tree v) vn_add (tree expr, tree val, vuse_optype vuses)
{ {
void **slot; void **slot;
val_expr_pair_t new_pair = xmalloc (sizeof (struct val_expr_pair_d)); val_expr_pair_t new_pair;
new_pair->e = e;
new_pair->v = v; new_pair = xmalloc (sizeof (struct val_expr_pair_d));
new_pair->hashcode = vn_compute (e, 0); new_pair->e = expr;
new_pair->v = val;
new_pair->vuses = vuses;
new_pair->hashcode = vn_compute (expr, 0, vuses);
slot = htab_find_slot_with_hash (value_table, new_pair, new_pair->hashcode, slot = htab_find_slot_with_hash (value_table, new_pair, new_pair->hashcode,
INSERT); INSERT);
if (*slot) if (*slot)
free (*slot); free (*slot);
*slot = (void *) new_pair; *slot = (void *) new_pair;
set_value_handle (e, v);
add_to_value (v, e); set_value_handle (expr, val);
add_to_value (val, expr);
} }
/* Search in VALUE_TABLE for an existing instance of expression E, and /* Search in VALUE_TABLE for an existing instance of expression EXPR,
return its value, or NULL if none has been set. */ and return its value, or NULL if none has been set. VUSES
represent the virtual use operands associated with EXPR (if any).
They are used when computing the hash value for EXPR. */
tree tree
vn_lookup (tree e) vn_lookup (tree expr, vuse_optype vuses)
{ {
void **slot; void **slot;
struct val_expr_pair_d vep = {NULL, NULL, 0}; struct val_expr_pair_d vep = {NULL, NULL, NULL, 0};
if (TREE_CODE_CLASS (TREE_CODE (e)) == 'c') if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
return e; return expr;
vep.e = e; vep.e = expr;
vep.hashcode = vn_compute (e, 0); vep.vuses = vuses;
vep.hashcode = vn_compute (expr, 0, vuses);
slot = htab_find_slot_with_hash (value_table, &vep, vep.hashcode, NO_INSERT); slot = htab_find_slot_with_hash (value_table, &vep, vep.hashcode, NO_INSERT);
if (!slot) if (!slot)
return NULL_TREE; return NULL_TREE;
...@@ -186,33 +227,35 @@ vn_lookup (tree e) ...@@ -186,33 +227,35 @@ vn_lookup (tree e)
} }
/* Like vn_lookup, but creates a new value for expression E if E doesn't /* Like vn_lookup, but creates a new value for expression EXPR, if
already have a value. Return the existing/created value for E. */ EXPR doesn't already have a value. Return the existing/created
value for EXPR. VUSES represent the virtual use operands
associated with EXPR (if any). They are used when computing the
hash value for EXPR. */
tree tree
vn_lookup_or_add (tree e) vn_lookup_or_add (tree expr, vuse_optype vuses)
{ {
tree x = vn_lookup (e); tree v = vn_lookup (expr, vuses);
if (x == NULL_TREE) if (v == NULL_TREE)
{ {
tree v = make_value_handle (TREE_TYPE (e)); v = make_value_handle (TREE_TYPE (expr));
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "Created value "); fprintf (dump_file, "Created value ");
print_generic_expr (dump_file, v, dump_flags); print_generic_expr (dump_file, v, dump_flags);
fprintf (dump_file, " for "); fprintf (dump_file, " for ");
print_generic_expr (dump_file, e, dump_flags); print_generic_expr (dump_file, expr, dump_flags);
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
} }
vn_add (e, v); vn_add (expr, v, vuses);
x = v;
} }
set_value_handle (e, x); set_value_handle (expr, v);
return x; return v;
} }
......
...@@ -1215,33 +1215,10 @@ struct tree_exp GTY(()) ...@@ -1215,33 +1215,10 @@ struct tree_exp GTY(())
#define SSA_NAME_VALUE(N) \ #define SSA_NAME_VALUE(N) \
SSA_NAME_CHECK (N)->ssa_name.value_handle SSA_NAME_CHECK (N)->ssa_name.value_handle
#ifndef GCC_BITMAP_H #ifndef _TREE_FLOW_H
struct bitmap_head_def; struct ptr_info_def;
#endif #endif
/* Aliasing information for SSA_NAMEs representing pointer variables. */
struct ptr_info_def GTY(())
{
/* Nonzero if points-to analysis couldn't determine where this pointer
is pointing to. */
unsigned int pt_anything : 1;
/* Nonzero if this pointer is the result of a call to malloc. */
unsigned int pt_malloc : 1;
/* Nonzero if the value of this pointer escapes the current function. */
unsigned int value_escapes_p : 1;
/* Set of variables that this pointer may point to. */
struct bitmap_head_def *pt_vars;
/* If this pointer has been dereferenced, and points-to information is
more precise than type-based aliasing, indirect references to this
pointer will be represented by this memory tag, instead of the type
tag computed by TBAA. */
tree name_mem_tag;
};
struct tree_ssa_name GTY(()) struct tree_ssa_name GTY(())
{ {
struct tree_common common; struct tree_common common;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment