tree-ssa-loop-im.c: New file.

* tree-ssa-loop-im.c: New file.
	* Makefile.in (tree-ssa-loop-im.o): Add.
	* cfgloop.c (superloop_at_depth): New function.
	* cfgloop.h (superloop_at_depth): Declare.
	* common.opt (ftree-lim): New flag.
	* expr.c (array_ref_up_bound): New function.
	* params.def (PARAM_LIM_EXPENSIVE): New parameter.
	* timevar.def (TV_LIM): New timevar.
	* tree-dfa.c (compute_immediate_uses): Respect TDFA_USE flags when
	computing immediate uses of a phi node.
	* tree-flow.h (struct tree_ann_common_d): Add aux field.
	(loop_commit_inserts, for_each_index, tree_ssa_lim): Declare.
	* tree-optimize.c (init_tree_optimization_passes): Add pass_lim.
	* tree-pass.h (pass_lim): Declare.
	* tree-ssa-loop.c (tree_ssa_loop_im, gate_tree_ssa_loop_im): New
	functions.
	(pass_lim): New pass structure.
	* tree-eh.c (tree_could_trap_p): Handle ARRAY_REFs correctly.
	* tree.c (in_array_bounds_p): New function.
	* tree.h (TREE_THIS_NOTRAP): Define also for ARRAY_REFs.
	(in_array_bounds_p, array_ref_up_bound): Declare.
	* doc/invoke.texi (-ftree-lim, --param lim-expensive): Document.
	* doc/passes.texi (tree-ssa-loop-im.c): Document.

From-SVN: r84441
This commit is contained in:
Zdenek Dvorak 2004-07-10 06:57:58 +02:00 committed by Zdenek Dvorak
parent ad6e2a18c2
commit a7e5372d6a
19 changed files with 1521 additions and 12 deletions

View File

@ -1,3 +1,29 @@
2004-07-09 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* tree-ssa-loop-im.c: New file.
* Makefile.in (tree-ssa-loop-im.o): Add.
* cfgloop.c (superloop_at_depth): New function.
* cfgloop.h (superloop_at_depth): Declare.
* common.opt (ftree-lim): New flag.
* expr.c (array_ref_up_bound): New function.
* params.def (PARAM_LIM_EXPENSIVE): New parameter.
* timevar.def (TV_LIM): New timevar.
* tree-dfa.c (compute_immediate_uses): Respect TDFA_USE flags when
computing immediate uses of a phi node.
* tree-flow.h (struct tree_ann_common_d): Add aux field.
(loop_commit_inserts, for_each_index, tree_ssa_lim): Declare.
* tree-optimize.c (init_tree_optimization_passes): Add pass_lim.
* tree-pass.h (pass_lim): Declare.
* tree-ssa-loop.c (tree_ssa_loop_im, gate_tree_ssa_loop_im): New
functions.
(pass_lim): New pass structure.
* tree-eh.c (tree_could_trap_p): Handle ARRAY_REFs correctly.
* tree.c (in_array_bounds_p): New function.
* tree.h (TREE_THIS_NOTRAP): Define also for ARRAY_REFs.
(in_array_bounds_p, array_ref_up_bound): Declare.
* doc/invoke.texi (-ftree-lim, --param lim-expensive): Document.
* doc/passes.texi (tree-ssa-loop-im.c): Document.
2004-07-09 Richard Henderson <rth@redhat.com>
* builtins.c (expand_builtin_stpcpy): Don't modify len.

View File

@ -901,7 +901,7 @@ OBJS-common = \
cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \
cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \
cfgrtl.o combine.o conflict.o convert.o coverage.o cse.o cselib.o \
dbxout.o ddg.o tree-ssa-loop-ch.o loop-invariant.o \
dbxout.o ddg.o tree-ssa-loop-ch.o loop-invariant.o tree-ssa-loop-im.o \
debug.o df.o diagnostic.o dojump.o dominance.o loop-doloop.o \
dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o loop-iv.o \
expmed.o expr.o final.o flow.o fold-const.o function.o gcse.o \
@ -1686,6 +1686,10 @@ tree-ssa-loop-ch.o : tree-ssa-loop-ch.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) tree-inline.h \
output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
tree-pass.h flags.h
tree-ssa-loop-im.o : tree-ssa-loop-im.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) domwalk.h $(PARAMS_H)\
output.h diagnostic.h $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \
tree-pass.h flags.h
tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) tree-inline.h $(FLAGS_H) \
function.h $(TIMEVAR_H) tree-alias-common.h convert.h $(TM_H) coretypes.h \

View File

@ -101,6 +101,20 @@ flow_loop_nested_p (const struct loop *outer, const struct loop *loop)
&& loop->pred[outer->depth] == outer;
}
/* Returns superloop of LOOP at given DEPTH. */
struct loop *
superloop_at_depth (struct loop *loop, unsigned depth)
{
if (depth > (unsigned) loop->depth)
abort ();
if (depth == (unsigned) loop->depth)
return loop;
return loop->pred[depth];
}
/* Dump the loop information specified by LOOP to the stream FILE
using auxiliary dump callback function LOOP_DUMP_AUX if non null. */

View File

@ -256,6 +256,7 @@ extern bool flow_loop_outside_edge_p (const struct loop *, edge);
extern bool flow_loop_nested_p (const struct loop *, const struct loop *);
extern bool flow_bb_inside_loop_p (const struct loop *, const basic_block);
extern struct loop * find_common_loop (struct loop *, struct loop *);
struct loop *superloop_at_depth (struct loop *, unsigned);
extern int num_loop_insns (struct loop *);
extern int average_num_loop_insns (struct loop *);
extern unsigned get_loop_level (const struct loop *);

View File

@ -844,6 +844,10 @@ ftree-fre
Common Report Var(flag_tree_fre)
Enable Full Redundancy Elimination (FRE) on trees
ftree-lim
Common Report Var(flag_tree_lim) Init(1)
Enable loop invariant motion on trees
ftree-loop-optimize
Common Report Var(flag_tree_loop_optimize) Init(1)
Enable loop optimizations on tree level

View File

@ -313,6 +313,7 @@ in the following sections.
-funroll-all-loops -funroll-loops -fpeel-loops @gol
-funswitch-loops -fold-unroll-loops -fold-unroll-all-loops @gol
-ftree-pre -ftree-ccp -ftree-dce -ftree-loop-optimize @gol
-ftree-lim @gol
-ftree-dominator-opts -ftree-dse -ftree-copyrename @gol
-ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre @gol
--param @var{name}=@var{value}
@ -4401,6 +4402,14 @@ usually increases code size.
Perform loop optimizations on trees. This flag is enabled by default at -O
and higher.
@item -ftree-lim
Perform loop invariant motion on trees. This pass moves only invartiants that
would be hard to handle on rtl level (function calls, operations that expand to
nontrivial sequences of insns). With @option{-funswitch-loops} it also moves
operands of conditions that are invariant out of the loop, so that we can use
just trivial invariantness analysis in loop unswitching. The pass also includes
store motion.
@item -ftree-sra
Perform scalar replacement of aggregates. This pass replaces structure
references with scalars to prevent committing structures to memory too
@ -5174,6 +5183,9 @@ The maximum number of insns of an unswitched loop.
@item max-unswitch-level
The maximum number of branches unswitched in a single loop.
@item lim-expensive
The minimum cost of an expensive expression in the loop invariant motion.
@item max-iterations-to-track
The maximum number of iterations of a loop the brute force algorithm

View File

@ -363,9 +363,20 @@ and is described by @code{pass_pre}.
@item Loop optimization
TODO: Presumably we're going to do something with loops here. At
present we don't, and this is a placeholder. The pass is located
in @file{tree-ssa-loop.c} and is described by @code{pass_loop}.
The main driver of the pass is placed in @file{tree-ssa-loop.c}
and described by @code{pass_loop}.
The optimizations performed by this pass are:
Loop invariant motion. This pass moves only invariants that
would be hard to handle on rtl level (function calls, operations that expand to
nontrivial sequences of insns). With @option{-funswitch-loops} it also moves
operands of conditions that are invariant out of the loop, so that we can use
just trivial invariantness analysis in loop unswitching. The pass also includes
store motion. The pass is implemented in @file{tree-ssa-loop-im.c}.
The optimizations also use various utility functions contained in
@file{cfgloop.c}, @file{cfgloopanal.c} and @file{cfgloopmanip.c}.
@item Conditional constant propagation

View File

@ -5706,6 +5706,23 @@ array_ref_low_bound (tree exp)
return fold_convert (TREE_TYPE (TREE_OPERAND (exp, 1)), integer_zero_node);
}
/* Return a tree representing the upper bound of the array mentioned in
EXP, an ARRAY_REF. */
tree
array_ref_up_bound (tree exp)
{
tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
/* If there is a domain type and it has an upper bound, use it, substituting
for a PLACEHOLDER_EXPR as needed. */
if (domain_type && TYPE_MAX_VALUE (domain_type))
return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MAX_VALUE (domain_type), exp);
/* Otherwise fail. */
return NULL_TREE;
}
/* Return a tree representing the offset, in bytes, of the field referenced
by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */

View File

@ -312,6 +312,13 @@ DEFPARAM(PARAM_MAX_CSE_PATH_LENGTH,
"The maximum length of path considered in cse",
10)
/* The cost of expression in loop invariant motion that is considered
expensive. */
DEFPARAM(PARAM_LIM_EXPENSIVE,
"lim-expensive",
"The minimum cost of an expensive expression in the loop invariant motion",
20)
/* The product of the next two is used to decide whether or not to
use .GLOBAL_VAR. See tree-dfa.c. */
DEFPARAM(PARAM_GLOBAL_VAR_THRESHOLD,

View File

@ -82,6 +82,7 @@ DEFTIMEVAR (TV_TREE_DCE , "tree conservative DCE")
DEFTIMEVAR (TV_TREE_CD_DCE , "tree aggressive DCE")
DEFTIMEVAR (TV_TREE_DSE , "tree DSE")
DEFTIMEVAR (TV_TREE_LOOP , "tree loop optimization")
DEFTIMEVAR (TV_LIM , "loop invariant motion")
DEFTIMEVAR (TV_TREE_CH , "tree copy headers")
DEFTIMEVAR (TV_TREE_SSA_TO_NORMAL , "tree SSA to normal")
DEFTIMEVAR (TV_TREE_NRV , "tree NRV optimization")

View File

@ -178,7 +178,20 @@ compute_immediate_uses (int flags, bool (*calc_for)(tree))
tree phi;
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
compute_immediate_uses_for_phi (phi, calc_for);
{
if (is_gimple_reg (PHI_RESULT (phi)))
{
if (!(flags & TDFA_USE_OPS))
continue;
}
else
{
if (!(flags & TDFA_USE_VOPS))
continue;
}
compute_immediate_uses_for_phi (phi, calc_for);
}
for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
{

View File

@ -1705,7 +1705,7 @@ tree_could_trap_p (tree expr)
bool honor_nans = false;
bool honor_snans = false;
bool fp_operation = false;
tree t;
tree t, base, idx;
if (TREE_CODE_CLASS (code) == '<'
|| TREE_CODE_CLASS (code) == '1'
@ -1722,14 +1722,32 @@ tree_could_trap_p (tree expr)
switch (code)
{
case ARRAY_REF:
case ARRAY_RANGE_REF:
case COMPONENT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
case BIT_FIELD_REF:
t = get_base_address (expr);
return !t || tree_could_trap_p (t);
t = TREE_OPERAND (expr, 0);
return tree_could_trap_p (t);
case ARRAY_RANGE_REF:
/* Let us be conservative here for now. We might be checking bounds of
the access similarly to the case below. */
if (!TREE_THIS_NOTRAP (expr))
return true;
base = TREE_OPERAND (expr, 0);
return tree_could_trap_p (base);
case ARRAY_REF:
base = TREE_OPERAND (expr, 0);
idx = TREE_OPERAND (expr, 1);
if (tree_could_trap_p (base))
return true;
if (TREE_THIS_NOTRAP (expr))
return false;
return !in_array_bounds_p (expr);
case INDIRECT_REF:
return !TREE_THIS_NOTRAP (expr);

View File

@ -83,6 +83,10 @@ struct tree_ann_common_d GTY(())
/* Annotation type. */
enum tree_ann_type type;
/* Auxiliary info specific to a pass. At all times, this
should either point to valid data or be NULL. */
PTR GTY ((skip (""))) aux;
/* The value handle for this expression. Used by GVN-PRE. */
tree GTY((skip)) value_handle;
};
@ -636,6 +640,8 @@ struct tree_niter_desc
/* In tree-ssa-loop*.c */
void tree_ssa_lim (struct loops *);
void number_of_iterations_cond (tree, tree, tree, enum tree_code, tree, tree,
struct tree_niter_desc *);
bool number_of_iterations_exit (struct loop *, edge,
@ -645,6 +651,8 @@ tree find_loop_niter_by_eval (struct loop *, edge *);
void estimate_numbers_of_iterations (struct loops *);
tree can_count_iv_in_wider_type (struct loop *, tree, tree, tree, tree);
void free_numbers_of_iterations_estimates (struct loops *);
void loop_commit_inserts (void);
bool for_each_index (tree *, bool (*) (tree, tree *, void *), void *);
/* In tree-flow-inline.h */
static inline int phi_arg_from_edge (tree, edge);

View File

@ -328,6 +328,7 @@ init_tree_optimization_passes (void)
p = &pass_loop.sub;
NEXT_PASS (pass_loop_init);
NEXT_PASS (pass_lim);
NEXT_PASS (pass_loop_done);
*p = NULL;

View File

@ -107,6 +107,7 @@ extern struct tree_opt_pass pass_tail_recursion;
extern struct tree_opt_pass pass_tail_calls;
extern struct tree_opt_pass pass_loop;
extern struct tree_opt_pass pass_loop_init;
extern struct tree_opt_pass pass_lim;
extern struct tree_opt_pass pass_loop_done;
extern struct tree_opt_pass pass_ch;
extern struct tree_opt_pass pass_ccp;

1299
gcc/tree-ssa-loop-im.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -111,6 +111,39 @@ struct tree_opt_pass pass_loop_init =
0 /* todo_flags_finish */
};
/* Loop invariant motion pass. */
static void
tree_ssa_loop_im (void)
{
if (!current_loops)
return;
tree_ssa_lim (current_loops);
}
static bool
gate_tree_ssa_loop_im (void)
{
return flag_tree_lim != 0;
}
struct tree_opt_pass pass_lim =
{
"lim", /* name */
gate_tree_ssa_loop_im, /* gate */
tree_ssa_loop_im, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
TV_LIM, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func /* todo_flags_finish */
};
/* Loop optimizer finalization. */
static void

View File

@ -5650,6 +5650,34 @@ build_empty_stmt (void)
}
/* Returns true if it is possible to prove that the index of
an array access REF (an ARRAY_REF expression) falls into the
array bounds. */
bool
in_array_bounds_p (tree ref)
{
tree idx = TREE_OPERAND (ref, 1);
tree min, max;
if (TREE_CODE (idx) != INTEGER_CST)
return false;
min = array_ref_low_bound (ref);
max = array_ref_up_bound (ref);
if (!min
|| !max
|| TREE_CODE (min) != INTEGER_CST
|| TREE_CODE (max) != INTEGER_CST)
return false;
if (tree_int_cst_lt (idx, min)
|| tree_int_cst_lt (max, idx))
return false;
return true;
}
/* Return true if T (assumed to be a DECL) must be assigned a memory
location. */

View File

@ -303,7 +303,7 @@ struct tree_common GTY(())
..._TYPE
TREE_THIS_NOTRAP in
INDIRECT_REF
INDIRECT_REF, ARRAY_REF, ARRAY_RANGE_REF
deprecated_flag:
@ -798,7 +798,12 @@ extern void tree_operand_check_failed (int, enum tree_code,
/* Nonzero means this node will not trap. In an INDIRECT_REF, means
accessing the memory pointed to won't generate a trap. However,
this only applies to an object when used appropriately: it doesn't
mean that writing a READONLY mem won't trap. */
mean that writing a READONLY mem won't trap.
In ARRAY_REF and ARRAY_RANGE_REF means that we know that the index
(or slice of the array) always belongs to the range of the array.
I.e. that the access will not trap, provided that the access to
the base to the array will not trap. */
#define TREE_THIS_NOTRAP(NODE) ((NODE)->common.nothrow_flag)
/* In a VAR_DECL, PARM_DECL or FIELD_DECL, or any kind of ..._REF node,
@ -2722,6 +2727,7 @@ extern tree build_method_type (tree, tree);
extern tree build_offset_type (tree, tree);
extern tree build_complex_type (tree);
extern tree array_type_nelts (tree);
extern bool in_array_bounds_p (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (tree, tree);
@ -3256,6 +3262,11 @@ extern tree array_ref_element_size (tree);
extern tree array_ref_low_bound (tree);
/* Return a tree representing the upper bound of the array mentioned in
EXP, an ARRAY_REF. */
extern tree array_ref_up_bound (tree);
/* Return a tree representing the offset, in bytes, of the field referenced
by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */