Makefile.in (tree-ssa-sink.o): New.
2005-03-01 Daniel Berlin <dberlin@dberlin.org> * Makefile.in (tree-ssa-sink.o): New. (OBJS-common): Add tree-ssa-sink.o. * common.opt: Add -ftree-sink * opts.c (decode_options): flag_tree_sink is set at O1 or higher. * timevar.def (TV_TREE_SINK): new timevar. * tree-flow.h (is_hidden_global_store): Prototype. * tree-optimize.c (init_tree_optimization_passes): Add pass_sink_code. * tree-pass.h (pass_sink_code): New. * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Move checking for non-obvious global store store to is_hidden_global_store, and call that new function. * tree-ssa-sink.c: New file. * doc/invoke.texi: Document -fdump-tree-sink and -ftree-sink. * doc/passes.texi: Document forward store motion. * testsuite/gcc.dg/tree-ssa/ssa-sink-1.c: New test * testsuite/gcc.dg/tree-ssa/ssa-sink-2.c: New test * testsuite/gcc.dg/tree-ssa/ssa-sink-3.c: New test * testsuite/gcc.dg/tree-ssa/ssa-sink-4.c: New test From-SVN: r95750
This commit is contained in:
parent
7cea62b4f5
commit
fa55525216
|
@ -1,3 +1,25 @@
|
|||
2005-03-01 Daniel Berlin <dberlin@dberlin.org>
|
||||
|
||||
* Makefile.in (tree-ssa-sink.o): New.
|
||||
(OBJS-common): Add tree-ssa-sink.o.
|
||||
* common.opt: Add -ftree-sink
|
||||
* opts.c (decode_options): flag_tree_sink is set at O1 or higher.
|
||||
* timevar.def (TV_TREE_SINK): new timevar.
|
||||
* tree-flow.h (is_hidden_global_store): Prototype.
|
||||
* tree-optimize.c (init_tree_optimization_passes): Add
|
||||
pass_sink_code.
|
||||
* tree-pass.h (pass_sink_code): New.
|
||||
* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Move checking
|
||||
for non-obvious global store store to is_hidden_global_store, and
|
||||
call that new function.
|
||||
* tree-ssa-sink.c: New file.
|
||||
* doc/invoke.texi: Document -fdump-tree-sink and -ftree-sink.
|
||||
* doc/passes.texi: Document forward store motion.
|
||||
* testsuite/gcc.dg/tree-ssa/ssa-sink-1.c: New test
|
||||
* testsuite/gcc.dg/tree-ssa/ssa-sink-2.c: New test
|
||||
* testsuite/gcc.dg/tree-ssa/ssa-sink-3.c: New test
|
||||
* testsuite/gcc.dg/tree-ssa/ssa-sink-4.c: New test
|
||||
|
||||
2005-03-01 Per Bothner <per@bothner.com>
|
||||
|
||||
* diagnostic.c (diagnostic_build_prefix): If USE_MAPPED_LOCATION
|
||||
|
|
|
@ -935,7 +935,7 @@ OBJS-common = \
|
|||
varasm.o varray.o vec.o version.o vmsdbgout.o xcoffout.o alloc-pool.o \
|
||||
et-forest.o cfghooks.o bt-load.o pretty-print.o $(GGC) web.o passes.o \
|
||||
rtl-profile.o tree-profile.o rtlhooks.o cfgexpand.o lambda-mat.o \
|
||||
lambda-trans.o lambda-code.o tree-loop-linear.o
|
||||
lambda-trans.o lambda-code.o tree-loop-linear.o tree-ssa-sink.o
|
||||
|
||||
OBJS-md = $(out_object_file)
|
||||
OBJS-archive = $(EXTRA_OBJS) $(host_hook_obj) tree-inline.o \
|
||||
|
@ -1673,6 +1673,10 @@ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
|
|||
tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
|
||||
$(RTL_H) $(TREE_H) $(TM_P_H) function.h $(TM_H) coretypes.h \
|
||||
$(TREE_DUMP_H) diagnostic.h except.h tree-pass.h $(FLAGS_H) langhooks.h
|
||||
tree-ssa-sink.o : tree-ssa-sink.c $(TREE_FLOW_H) $(CONFIG_H) \
|
||||
$(SYSTEM_H) $(TREE_H) $(TM_P_H) $(EXPR_H) \
|
||||
$(GGC_H) output.h diagnostic.h errors.h toplev.h $(TIMEVAR_H) \
|
||||
$(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H)
|
||||
tree-nested.o: tree-nested.c $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) \
|
||||
$(RTL_H) $(TM_P_H) function.h tree-dump.h tree-inline.h tree-iterator.h \
|
||||
tree-gimple.h $(CGRAPH_H) $(EXPR_H) langhooks.h $(GGC_H) gt-tree-nested.h
|
||||
|
|
|
@ -872,6 +872,10 @@ ftree-pre
|
|||
Common Report Var(flag_tree_pre)
|
||||
Enable SSA-PRE optimization on trees
|
||||
|
||||
ftree-sink
|
||||
Common Report Var(flag_tree_sink)
|
||||
Enable SSA code sinking on trees
|
||||
|
||||
ftree-sra
|
||||
Common Report Var(flag_tree_sra)
|
||||
Perform scalar replacement of aggregates
|
||||
|
|
|
@ -264,6 +264,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-fdump-tree-forwprop@r{[}-@var{n}@r{]} @gol
|
||||
-fdump-tree-copyrename@r{[}-@var{n}@r{]} @gol
|
||||
-fdump-tree-nrv -fdump-tree-vect @gol
|
||||
-fdump-tree-sink @gol
|
||||
-fdump-tree-sra@r{[}-@var{n}@r{]} @gol
|
||||
-fdump-tree-fre@r{[}-@var{n}@r{]} @gol
|
||||
-ftree-vectorizer-verbose=@var{n} @gol
|
||||
|
@ -319,7 +320,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||
-fvariable-expansion-in-unroller @gol
|
||||
-ftree-pre -ftree-ccp -ftree-dce -ftree-loop-optimize @gol
|
||||
-ftree-loop-linear -ftree-loop-im -ftree-loop-ivcanon -fivopts @gol
|
||||
-ftree-dominator-opts -ftree-dse -ftree-copyrename @gol
|
||||
-ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-sink @gol
|
||||
-ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre -ftree-vectorize @gol
|
||||
--param @var{name}=@var{value}
|
||||
-O -O0 -O1 -O2 -O3 -Os}
|
||||
|
@ -3843,6 +3844,11 @@ made by appending @file{.mudflap} to the source file name.
|
|||
Dump each function after performing scalar replacement of aggregates. The
|
||||
file name is made by appending @file{.sra} to the source file name.
|
||||
|
||||
@item sink
|
||||
@opindex fdump-tree-sink
|
||||
Dump each function after performing code sinking. The file name is made
|
||||
by appending @file{.sink} to the source file name.
|
||||
|
||||
@item dom
|
||||
@opindex fdump-tree-dom
|
||||
Dump each function after applying dominator tree optimizations. The file
|
||||
|
@ -4679,6 +4685,10 @@ 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 @option{-O} and higher.
|
||||
|
||||
@item -ftree-sink
|
||||
Perform forward store motion on trees. This flag is
|
||||
enabled by default at @option{-O} and higher.
|
||||
|
||||
@item -ftree-ccp
|
||||
Perform sparse conditional constant propagation (CCP) on trees. This flag
|
||||
is enabled by default at @option{-O} and higher.
|
||||
|
|
|
@ -350,6 +350,12 @@ in @file{tree-ssa-dse.c} and is described by @code{pass_dse}.
|
|||
This pass transforms tail recursion into a loop. It is located in
|
||||
@file{tree-tailcall.c} and is described by @code{pass_tail_recursion}.
|
||||
|
||||
@item Forward store motion
|
||||
|
||||
This pass sinks stores and assignments down the flowgraph closer to it's
|
||||
use point. The pass is located in @file{tree-ssa-sink.c} and is
|
||||
described by @code{pass_sink_code}
|
||||
|
||||
@item Partial redundancy elimination
|
||||
|
||||
This pass eliminates partially redundant computations, as well as
|
||||
|
|
|
@ -501,6 +501,7 @@ decode_options (unsigned int argc, const char **argv)
|
|||
flag_tree_sra = 1;
|
||||
flag_tree_copyrename = 1;
|
||||
flag_tree_fre = 1;
|
||||
flag_tree_sink = 1;
|
||||
|
||||
if (!optimize_size)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-sink-stats" } */
|
||||
int
|
||||
foo (int a, int b, int c)
|
||||
{
|
||||
int x = a * b;
|
||||
return c ? x : a;
|
||||
}
|
||||
/* We should sink the x = a * b calculation into the branch that returns x. */
|
||||
/* { dg-final { scan-tree-dump-times "Sunk statements:1" 1 "sink"} } */
|
|
@ -0,0 +1,12 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-sink-stats" } */
|
||||
int
|
||||
bar (int a, int b, int c)
|
||||
{
|
||||
int y = a * b;
|
||||
if (c)
|
||||
y = 12;
|
||||
return y;
|
||||
}
|
||||
/* We should sink the x = a * b calculation into the else branch */
|
||||
/* { dg-final { scan-tree-dump-times "Sunk statements:1" 1 "sink"} } */
|
|
@ -0,0 +1,15 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-sink-stats" } */
|
||||
extern void foo(int a);
|
||||
int
|
||||
main (int argc)
|
||||
{
|
||||
int a;
|
||||
a = argc + 1;
|
||||
if (argc + 3)
|
||||
{
|
||||
foo (a);
|
||||
}
|
||||
}
|
||||
/* We should sink the a = argc + 1 calculation into the if branch */
|
||||
/* { dg-final { scan-tree-dump-times "Sunk statements:1" 1 "sink"} } */
|
|
@ -0,0 +1,20 @@
|
|||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-sink-stats" } */
|
||||
extern int foo (int *, int *);
|
||||
extern int foo2 (int);
|
||||
int
|
||||
main (int argc)
|
||||
{
|
||||
int a, b, c;
|
||||
b = argc + 1;
|
||||
c = argc + 2;
|
||||
a = b + c;
|
||||
if (argc)
|
||||
{
|
||||
foo (&b, &c);
|
||||
a = b + c;
|
||||
}
|
||||
foo2 (a);
|
||||
}
|
||||
/* We should sink the first a = b + c calculation into the else branch */
|
||||
/* { dg-final { scan-tree-dump-times "Sunk statements:1" 1 "sink"} } */
|
|
@ -79,6 +79,7 @@ DEFTIMEVAR (TV_TREE_SPLIT_EDGES , "tree split crit edges")
|
|||
DEFTIMEVAR (TV_TREE_PRE , "tree PRE")
|
||||
DEFTIMEVAR (TV_TREE_REDPHI , "tree remove redundant PHIs")
|
||||
DEFTIMEVAR (TV_TREE_FRE , "tree FRE")
|
||||
DEFTIMEVAR (TV_TREE_SINK , "tree code sinking")
|
||||
DEFTIMEVAR (TV_TREE_PHIOPT , "tree linearize phis")
|
||||
DEFTIMEVAR (TV_TREE_FORWPROP , "tree forward propagate")
|
||||
DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE")
|
||||
|
|
|
@ -736,6 +736,8 @@ tree vn_lookup (tree, vuse_optype);
|
|||
void vn_init (void);
|
||||
void vn_delete (void);
|
||||
|
||||
/* In tree-ssa-sink.c */
|
||||
bool is_hidden_global_store (tree);
|
||||
|
||||
/* In tree-sra.c */
|
||||
void insert_edge_copies (tree, basic_block);
|
||||
|
|
|
@ -384,6 +384,7 @@ init_tree_optimization_passes (void)
|
|||
NEXT_PASS (pass_may_alias);
|
||||
NEXT_PASS (pass_split_crit_edges);
|
||||
NEXT_PASS (pass_pre);
|
||||
NEXT_PASS (pass_sink_code);
|
||||
NEXT_PASS (pass_loop);
|
||||
NEXT_PASS (pass_dominator);
|
||||
NEXT_PASS (pass_redundant_phi);
|
||||
|
|
|
@ -164,6 +164,7 @@ extern struct tree_opt_pass pass_mark_used_blocks;
|
|||
extern struct tree_opt_pass pass_rename_ssa_copies;
|
||||
extern struct tree_opt_pass pass_expand;
|
||||
extern struct tree_opt_pass pass_rest_of_compilation;
|
||||
extern struct tree_opt_pass pass_sink_code;
|
||||
extern struct tree_opt_pass pass_fre;
|
||||
extern struct tree_opt_pass pass_linear_transform;
|
||||
|
||||
|
|
|
@ -277,8 +277,6 @@ mark_operand_necessary (tree op, bool phionly)
|
|||
static void
|
||||
mark_stmt_if_obviously_necessary (tree stmt, bool aggressive)
|
||||
{
|
||||
v_may_def_optype v_may_defs;
|
||||
v_must_def_optype v_must_defs;
|
||||
stmt_ann_t ann;
|
||||
tree op, def;
|
||||
ssa_op_iter iter;
|
||||
|
@ -368,78 +366,10 @@ mark_stmt_if_obviously_necessary (tree stmt, bool aggressive)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check virtual definitions. If we get here, the only virtual
|
||||
definitions we should see are those generated by assignment
|
||||
statements. */
|
||||
v_may_defs = V_MAY_DEF_OPS (ann);
|
||||
v_must_defs = V_MUST_DEF_OPS (ann);
|
||||
if (NUM_V_MAY_DEFS (v_may_defs) > 0 || NUM_V_MUST_DEFS (v_must_defs) > 0)
|
||||
if (is_hidden_global_store (stmt))
|
||||
{
|
||||
tree lhs;
|
||||
|
||||
gcc_assert (TREE_CODE (stmt) == MODIFY_EXPR);
|
||||
|
||||
/* Note that we must not check the individual virtual operands
|
||||
here. In particular, if this is an aliased store, we could
|
||||
end up with something like the following (SSA notation
|
||||
redacted for brevity):
|
||||
|
||||
foo (int *p, int i)
|
||||
{
|
||||
int x;
|
||||
p_1 = (i_2 > 3) ? &x : p_1;
|
||||
|
||||
# x_4 = V_MAY_DEF <x_3>
|
||||
*p_1 = 5;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
Notice that the store to '*p_1' should be preserved, if we
|
||||
were to check the virtual definitions in that store, we would
|
||||
not mark it needed. This is because 'x' is not a global
|
||||
variable.
|
||||
|
||||
Therefore, we check the base address of the LHS. If the
|
||||
address is a pointer, we check if its name tag or type tag is
|
||||
a global variable. Otherwise, we check if the base variable
|
||||
is a global. */
|
||||
lhs = TREE_OPERAND (stmt, 0);
|
||||
if (REFERENCE_CLASS_P (lhs))
|
||||
lhs = get_base_address (lhs);
|
||||
|
||||
if (lhs == NULL_TREE)
|
||||
{
|
||||
/* If LHS is NULL, it means that we couldn't get the base
|
||||
address of the reference. In which case, we should not
|
||||
remove this store. */
|
||||
mark_stmt_necessary (stmt, true);
|
||||
}
|
||||
else if (DECL_P (lhs))
|
||||
{
|
||||
/* If the store is to a global symbol, we need to keep it. */
|
||||
if (is_global_var (lhs))
|
||||
mark_stmt_necessary (stmt, true);
|
||||
}
|
||||
else if (INDIRECT_REF_P (lhs))
|
||||
{
|
||||
tree ptr = TREE_OPERAND (lhs, 0);
|
||||
struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
|
||||
tree nmt = (pi) ? pi->name_mem_tag : NULL_TREE;
|
||||
tree tmt = var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
|
||||
|
||||
/* If either the name tag or the type tag for PTR is a
|
||||
global variable, then the store is necessary. */
|
||||
if ((nmt && is_global_var (nmt))
|
||||
|| (tmt && is_global_var (tmt)))
|
||||
{
|
||||
mark_stmt_necessary (stmt, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
mark_stmt_necessary (stmt, true);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue