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:
parent
ad6e2a18c2
commit
a7e5372d6a
@ -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.
|
||||
|
@ -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 \
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
17
gcc/expr.c
17
gcc/expr.c
@ -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. */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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")
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
1299
gcc/tree-ssa-loop-im.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
28
gcc/tree.c
28
gcc/tree.c
@ -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. */
|
||||
|
||||
|
15
gcc/tree.h
15
gcc/tree.h
@ -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. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user