tree-flow.h: Move some protoypes.

* tree-flow.h: Move some protoypes.  Include new tree-ssa-loop.h.
	(struct affine_iv, struct tree_niter_desc): Move to tree-ssa-loop.h.
	(enum move_pos): Move to tree-ssa-loop-im.h
	* cfgloop.h: Move some prototypes.
	(gcov_type_to_double_int): relocate from tree-ssa-loop.niter.c.
	* tree-flow-inline.h (loop_containing_stmt): Move to tree-ssa-loop.h.
	* tree-ssa-loop.h: New File.  Include other tree-ssa-loop-*.h files.
	(struct affine_iv, struct tree_niter_desc): Relocate from tree-flow.h.
	(loop_containing_stmt): Relocate from tree-flow-inline.h.
	* tree-ssa-loop-ch.c: (do_while_loop_p): Make static.
	* tree-ssa-loop-im.c (for_each_index): Move to tree-ssa-loop.c.
	(enum move_pos): Relocate here.
	(lsm_tmp_name_add, gen_lsm_tmp_name, get_lsm_tmp_name): Move to
	tree-ssa-loop.c.
	(execute_sm_if_changed_flag_set): Change get_lsm_tmp_name call.
	(tree_ssa_loop_im, gate_tree_ssa_loop_im, pass_data_lim, make_pass_lim):
	Relocate here from tree-ssa-loop.c.
	* tree-ssa-loop-ivcanon.c (tree_num_loop_insns): Move to 
	tree-ssa-loop.c.
	(loop_edge_to_cancel, unloop_loops): Make static.
	(tree_ssa_loop_ivcanon, gate_tree_ssa_loop_ivcanon, pass_data_iv_canon,
	make_pass_iv_canon): Relocate from tree-ssa-loop.c.
	(tree_complete_unroll, gate_tree_complete_unroll,
	pass_data_complete_unroll, make_pass_complete_unroll): Relocate here.
	(tree_complete_unroll_inner, gate_tree_complete_unroll_inner,
	pass_data_complete_unrolli, make_pass_complete_unrolli): Relocate here.
	* tree-ssa-loop-ivopts.c: Remove local prototypes.
	(stmt_invariant_in_loop_p): Remove unused function.
	* tree-ssa-loop-ivopts.h: New file.  Add prototypes.
	* tree-ssa-loop-manip.h: New file.  Add prototypes.
	* tree-ssa-loop-niter.c (record_niter_bound): Move to cfgloop.c.
	(gcov_type_to_double_int): Move to cfgloop.h.
	(double_int_cmp, bound_index,
	estimate_numbers_of_iterations_loop): Make static.
	(estimated_loop_iterations): Factor out get_estimated_loop_iterations.
	(max_loop_iterations): Factor out get_max_loop_iterations.
	(estimated_loop_iterations_int, max_stmt_executions_int): Move to
	cfgloop.c.
	* tree-ssa-loop-niter.h: New file.  Add prototypes.
	* tree-ssa-loop-prefetch.c (tree_ssa_loop_prefetch,
	gate_tree_ssa_loop_prefetch, pass_data_loop_prefetch,
	make_pass_loop_prefetch): Relocate from tree-ssa-loop.c.
	* tree-ssa-loop-unswitch.c (tree_ssa_loop_unswitch,
	gate_tree_ssa_loop_unswitch, pass_data_tree_unswitch,
	make_pass_tree_unswitch): Relocate from tree-ssa-loop.c.
	* tree-ssa-loop.c (tree_ssa_loop_im, gate_tree_ssa_loop_im,
	pass_data_lim, make_pass_lim): Move to tree-ssa-loop-im.c.
	(tree_ssa_loop_unswitch, gate_tree_ssa_loop_unswitch,
	pass_data_tree_unswitch, make_pass_tree_unswitch): Move.
	(tree_ssa_loop_ivcanon, gate_tree_ssa_loop_ivcanon, pass_data_iv_canon,
	make_pass_iv_canon, tree_complete_unroll, gate_tree_complete_unroll,
	pass_data_complete_unroll, make_pass_complete_unroll,
	tree_complete_unroll_inner, gate_tree_complete_unroll_inner,
	pass_data_complete_unrolli, make_pass_complete_unrolli): Move to
	tree-ssa-loop-ivcanon.c.
	(tree_ssa_loop_prefetch, gate_tree_ssa_loop_prefetch,
	pass_data_loop_prefetch, make_pass_loop_prefetch): Move to
	tree-ssa-loop-prefetch.c.
	(for_each_index, lsm_tmp_name_add, gen_lsm_tmp_name): Relocate from
	tree-ssa-loop-im.c.
	(get_lsm_tmp_name): Relocate and add suffix parameter.
	(tree_num_loop_insns): Relocate from tree-ssa-ivcanon.c.
	* tree-scalar-evolution.h (simple_iv): Don't use affive_iv typedef.
	* cfgloop.c (record_niter_bound, estimated_loop_iterations_int,
	max_stmt_executions_int): Move from tree-ssa-loop-niter.c.
	(get_estimated_loop_iterations): Factor out accessor from 
	estimated_loop_iterations in tree-ssa-loop-niter.c.
	(get_max_loop_iterations): Factor out accessor from _max_loop_iterations
	in tree-ssa-niter.c.
	* loop-unroll.c (decide_unroll_constant_iterations,
	decide_unroll_runtime_iterations, decide_peel_simple,
	decide_unroll_stupid): Use new get_* accessors.

From-SVN: r203317
This commit is contained in:
Andrew MacLeod 2013-10-09 13:09:23 +00:00 committed by Andrew Macleod
parent 826cacfe24
commit 713438778b
19 changed files with 1034 additions and 856 deletions

View File

@ -1,3 +1,78 @@
2013-10-09 Andrew MacLeod <amacleod@redhat.com>
* tree-flow.h: Move some protoypes. Include new tree-ssa-loop.h.
(struct affine_iv, struct tree_niter_desc): Move to tree-ssa-loop.h.
(enum move_pos): Move to tree-ssa-loop-im.h
* cfgloop.h: Move some prototypes.
(gcov_type_to_double_int): relocate from tree-ssa-loop.niter.c.
* tree-flow-inline.h (loop_containing_stmt): Move to tree-ssa-loop.h.
* tree-ssa-loop.h: New File. Include other tree-ssa-loop-*.h files.
(struct affine_iv, struct tree_niter_desc): Relocate from tree-flow.h.
(loop_containing_stmt): Relocate from tree-flow-inline.h.
* tree-ssa-loop-ch.c: (do_while_loop_p): Make static.
* tree-ssa-loop-im.c (for_each_index): Move to tree-ssa-loop.c.
(enum move_pos): Relocate here.
(lsm_tmp_name_add, gen_lsm_tmp_name, get_lsm_tmp_name): Move to
tree-ssa-loop.c.
(execute_sm_if_changed_flag_set): Change get_lsm_tmp_name call.
(tree_ssa_loop_im, gate_tree_ssa_loop_im, pass_data_lim, make_pass_lim):
Relocate here from tree-ssa-loop.c.
* tree-ssa-loop-ivcanon.c (tree_num_loop_insns): Move to
tree-ssa-loop.c.
(loop_edge_to_cancel, unloop_loops): Make static.
(tree_ssa_loop_ivcanon, gate_tree_ssa_loop_ivcanon, pass_data_iv_canon,
make_pass_iv_canon): Relocate from tree-ssa-loop.c.
(tree_complete_unroll, gate_tree_complete_unroll,
pass_data_complete_unroll, make_pass_complete_unroll): Relocate here.
(tree_complete_unroll_inner, gate_tree_complete_unroll_inner,
pass_data_complete_unrolli, make_pass_complete_unrolli): Relocate here.
* tree-ssa-loop-ivopts.c: Remove local prototypes.
(stmt_invariant_in_loop_p): Remove unused function.
* tree-ssa-loop-ivopts.h: New file. Add prototypes.
* tree-ssa-loop-manip.h: New file. Add prototypes.
* tree-ssa-loop-niter.c (record_niter_bound): Move to cfgloop.c.
(gcov_type_to_double_int): Move to cfgloop.h.
(double_int_cmp, bound_index,
estimate_numbers_of_iterations_loop): Make static.
(estimated_loop_iterations): Factor out get_estimated_loop_iterations.
(max_loop_iterations): Factor out get_max_loop_iterations.
(estimated_loop_iterations_int, max_stmt_executions_int): Move to
cfgloop.c.
* tree-ssa-loop-niter.h: New file. Add prototypes.
* tree-ssa-loop-prefetch.c (tree_ssa_loop_prefetch,
gate_tree_ssa_loop_prefetch, pass_data_loop_prefetch,
make_pass_loop_prefetch): Relocate from tree-ssa-loop.c.
* tree-ssa-loop-unswitch.c (tree_ssa_loop_unswitch,
gate_tree_ssa_loop_unswitch, pass_data_tree_unswitch,
make_pass_tree_unswitch): Relocate from tree-ssa-loop.c.
* tree-ssa-loop.c (tree_ssa_loop_im, gate_tree_ssa_loop_im,
pass_data_lim, make_pass_lim): Move to tree-ssa-loop-im.c.
(tree_ssa_loop_unswitch, gate_tree_ssa_loop_unswitch,
pass_data_tree_unswitch, make_pass_tree_unswitch): Move.
(tree_ssa_loop_ivcanon, gate_tree_ssa_loop_ivcanon, pass_data_iv_canon,
make_pass_iv_canon, tree_complete_unroll, gate_tree_complete_unroll,
pass_data_complete_unroll, make_pass_complete_unroll,
tree_complete_unroll_inner, gate_tree_complete_unroll_inner,
pass_data_complete_unrolli, make_pass_complete_unrolli): Move to
tree-ssa-loop-ivcanon.c.
(tree_ssa_loop_prefetch, gate_tree_ssa_loop_prefetch,
pass_data_loop_prefetch, make_pass_loop_prefetch): Move to
tree-ssa-loop-prefetch.c.
(for_each_index, lsm_tmp_name_add, gen_lsm_tmp_name): Relocate from
tree-ssa-loop-im.c.
(get_lsm_tmp_name): Relocate and add suffix parameter.
(tree_num_loop_insns): Relocate from tree-ssa-ivcanon.c.
* tree-scalar-evolution.h (simple_iv): Don't use affive_iv typedef.
* cfgloop.c (record_niter_bound, estimated_loop_iterations_int,
max_stmt_executions_int): Move from tree-ssa-loop-niter.c.
(get_estimated_loop_iterations): Factor out accessor from
estimated_loop_iterations in tree-ssa-loop-niter.c.
(get_max_loop_iterations): Factor out accessor from _max_loop_iterations
in tree-ssa-niter.c.
* loop-unroll.c (decide_unroll_constant_iterations,
decide_unroll_runtime_iterations, decide_peel_simple,
decide_unroll_stupid): Use new get_* accessors.
2013-10-09 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/20318

View File

@ -1781,3 +1781,113 @@ get_loop_location (struct loop *loop)
return DECL_SOURCE_LOCATION (current_function_decl);
}
/* Records that every statement in LOOP is executed I_BOUND times.
REALISTIC is true if I_BOUND is expected to be close to the real number
of iterations. UPPER is true if we are sure the loop iterates at most
I_BOUND times. */
void
record_niter_bound (struct loop *loop, double_int i_bound, bool realistic,
bool upper)
{
/* Update the bounds only when there is no previous estimation, or when the
current estimation is smaller. */
if (upper
&& (!loop->any_upper_bound
|| i_bound.ult (loop->nb_iterations_upper_bound)))
{
loop->any_upper_bound = true;
loop->nb_iterations_upper_bound = i_bound;
}
if (realistic
&& (!loop->any_estimate
|| i_bound.ult (loop->nb_iterations_estimate)))
{
loop->any_estimate = true;
loop->nb_iterations_estimate = i_bound;
}
/* If an upper bound is smaller than the realistic estimate of the
number of iterations, use the upper bound instead. */
if (loop->any_upper_bound
&& loop->any_estimate
&& loop->nb_iterations_upper_bound.ult (loop->nb_iterations_estimate))
loop->nb_iterations_estimate = loop->nb_iterations_upper_bound;
}
/* Similar to estimated_loop_iterations, but returns the estimate only
if it fits to HOST_WIDE_INT. If this is not the case, or the estimate
on the number of iterations of LOOP could not be derived, returns -1. */
HOST_WIDE_INT
estimated_loop_iterations_int (struct loop *loop)
{
double_int nit;
HOST_WIDE_INT hwi_nit;
if (!get_estimated_loop_iterations (loop, &nit))
return -1;
if (!nit.fits_shwi ())
return -1;
hwi_nit = nit.to_shwi ();
return hwi_nit < 0 ? -1 : hwi_nit;
}
/* Returns an upper bound on the number of executions of statements
in the LOOP. For statements before the loop exit, this exceeds
the number of execution of the latch by one. */
HOST_WIDE_INT
max_stmt_executions_int (struct loop *loop)
{
HOST_WIDE_INT nit = max_loop_iterations_int (loop);
HOST_WIDE_INT snit;
if (nit == -1)
return -1;
snit = (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) nit + 1);
/* If the computation overflows, return -1. */
return snit < 0 ? -1 : snit;
}
/* Sets NIT to the estimated number of executions of the latch of the
LOOP. If we have no reliable estimate, the function returns false, otherwise
returns true. */
bool
get_estimated_loop_iterations (struct loop *loop, double_int *nit)
{
/* Even if the bound is not recorded, possibly we can derrive one from
profile. */
if (!loop->any_estimate)
{
if (loop->header->count)
{
*nit = gcov_type_to_double_int
(expected_loop_iterations_unbounded (loop) + 1);
return true;
}
return false;
}
*nit = loop->nb_iterations_estimate;
return true;
}
/* Sets NIT to an upper bound for the maximum number of executions of the
latch of the LOOP. If we have no reliable estimate, the function returns
false, otherwise returns true. */
bool
get_max_loop_iterations (struct loop *loop, double_int *nit)
{
if (!loop->any_upper_bound)
return false;
*nit = loop->nb_iterations_upper_bound;
return true;
}

View File

@ -255,7 +255,6 @@ 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);
struct eni_weights_d;
extern unsigned tree_num_loop_insns (struct loop *, struct eni_weights_d *);
extern int num_loop_insns (const struct loop *);
extern int average_num_loop_insns (const struct loop *);
extern unsigned get_loop_level (const struct loop *);
@ -306,16 +305,6 @@ gcov_type expected_loop_iterations_unbounded (const struct loop *);
extern unsigned expected_loop_iterations (const struct loop *);
extern rtx doloop_condition_get (rtx);
void estimate_numbers_of_iterations_loop (struct loop *);
void record_niter_bound (struct loop *, double_int, bool, bool);
bool estimated_loop_iterations (struct loop *, double_int *);
bool max_loop_iterations (struct loop *, double_int *);
HOST_WIDE_INT estimated_loop_iterations_int (struct loop *);
HOST_WIDE_INT max_loop_iterations_int (struct loop *);
bool max_stmt_executions (struct loop *, double_int *);
bool estimated_stmt_executions (struct loop *, double_int *);
HOST_WIDE_INT max_stmt_executions_int (struct loop *);
HOST_WIDE_INT estimated_stmt_executions_int (struct loop *);
/* Loop manipulation. */
extern bool can_duplicate_loop_p (const struct loop *loop);
@ -735,7 +724,6 @@ enum
extern void unroll_and_peel_loops (int);
extern void doloop_optimize_loops (void);
extern void move_loop_invariants (void);
extern bool finite_loop_p (struct loop *);
extern void scale_loop_profile (struct loop *loop, int scale, gcov_type iteration_bound);
extern vec<basic_block> get_loop_hot_path (const struct loop *loop);
@ -751,5 +739,26 @@ loop_outermost (struct loop *loop)
return (*loop->superloops)[1];
}
extern void record_niter_bound (struct loop *, double_int, bool, bool);
extern HOST_WIDE_INT estimated_loop_iterations_int (struct loop *);
extern HOST_WIDE_INT max_loop_iterations_int (struct loop *);
extern bool get_estimated_loop_iterations (struct loop *loop, double_int *nit);
extern bool get_max_loop_iterations (struct loop *loop, double_int *nit);
/* Converts VAL to double_int. */
static inline double_int
gcov_type_to_double_int (gcov_type val)
{
double_int ret;
ret.low = (unsigned HOST_WIDE_INT) val;
/* If HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_WIDEST_INT, avoid shifting by
the size of type. */
val >>= HOST_BITS_PER_WIDE_INT - 1;
val >>= 1;
ret.high = (unsigned HOST_WIDE_INT) val;
return ret;
}
#endif /* GCC_CFGLOOP_H */

View File

@ -694,8 +694,8 @@ decide_unroll_constant_iterations (struct loop *loop, int flags)
than one exit it may well loop less than determined maximal number
of iterations. */
if (desc->niter < 2 * nunroll
|| ((estimated_loop_iterations (loop, &iterations)
|| max_loop_iterations (loop, &iterations))
|| ((get_estimated_loop_iterations (loop, &iterations)
|| get_max_loop_iterations (loop, &iterations))
&& iterations.ult (double_int::from_shwi (2 * nunroll))))
{
if (dump_file)
@ -999,8 +999,8 @@ decide_unroll_runtime_iterations (struct loop *loop, int flags)
}
/* Check whether the loop rolls. */
if ((estimated_loop_iterations (loop, &iterations)
|| max_loop_iterations (loop, &iterations))
if ((get_estimated_loop_iterations (loop, &iterations)
|| get_max_loop_iterations (loop, &iterations))
&& iterations.ult (double_int::from_shwi (2 * nunroll)))
{
if (dump_file)
@ -1388,7 +1388,7 @@ decide_peel_simple (struct loop *loop, int flags)
}
/* If we have realistic estimate on number of iterations, use it. */
if (estimated_loop_iterations (loop, &iterations))
if (get_estimated_loop_iterations (loop, &iterations))
{
if (double_int::from_shwi (npeel).ule (iterations))
{
@ -1406,7 +1406,7 @@ decide_peel_simple (struct loop *loop, int flags)
}
/* If we have small enough bound on iterations, we can still peel (completely
unroll). */
else if (max_loop_iterations (loop, &iterations)
else if (get_max_loop_iterations (loop, &iterations)
&& iterations.ult (double_int::from_shwi (npeel)))
npeel = iterations.to_shwi () + 1;
else
@ -1556,8 +1556,8 @@ decide_unroll_stupid (struct loop *loop, int flags)
}
/* Check whether the loop rolls. */
if ((estimated_loop_iterations (loop, &iterations)
|| max_loop_iterations (loop, &iterations))
if ((get_estimated_loop_iterations (loop, &iterations)
|| get_max_loop_iterations (loop, &iterations))
&& iterations.ult (double_int::from_shwi (2 * nunroll)))
{
if (dump_file)

View File

@ -107,21 +107,6 @@ may_be_aliased (const_tree var)
|| TREE_ADDRESSABLE (var)));
}
/* Returns the loop of the statement STMT. */
static inline struct loop *
loop_containing_stmt (gimple stmt)
{
basic_block bb = gimple_bb (stmt);
if (!bb)
return NULL;
return bb->loop_father;
}
/* Return true if VAR cannot be modified by the program. */
static inline bool

View File

@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "gimple-low.h"
#include "tree-into-ssa.h"
#include "tree-ssa-loop.h"
/* This structure is used to map a gimple statement to a label,
or list of labels to represent transaction restart. */
@ -244,109 +245,19 @@ extern basic_block move_sese_region_to_fn (struct function *, basic_block,
void remove_edge_and_dominated_blocks (edge);
bool tree_node_can_be_shared (tree);
/* In tree-ssa-loop-ch.c */
bool do_while_loop_p (struct loop *);
/* Affine iv. */
typedef struct
{
/* Iv = BASE + STEP * i. */
tree base, step;
/* True if this iv does not overflow. */
bool no_overflow;
} affine_iv;
/* Description of number of iterations of a loop. All the expressions inside
the structure can be evaluated at the end of the loop's preheader
(and due to ssa form, also anywhere inside the body of the loop). */
struct tree_niter_desc
{
tree assumptions; /* The boolean expression. If this expression evaluates
to false, then the other fields in this structure
should not be used; there is no guarantee that they
will be correct. */
tree may_be_zero; /* The boolean expression. If it evaluates to true,
the loop will exit in the first iteration (i.e.
its latch will not be executed), even if the niter
field says otherwise. */
tree niter; /* The expression giving the number of iterations of
a loop (provided that assumptions == true and
may_be_zero == false), more precisely the number
of executions of the latch of the loop. */
double_int max; /* The upper bound on the number of iterations of
the loop. */
/* The simplified shape of the exit condition. The loop exits if
CONTROL CMP BOUND is false, where CMP is one of NE_EXPR,
LT_EXPR, or GT_EXPR, and step of CONTROL is positive if CMP is
LE_EXPR and negative if CMP is GE_EXPR. This information is used
by loop unrolling. */
affine_iv control;
tree bound;
enum tree_code cmp;
};
/* In tree-ssa-loop*.c */
unsigned int tree_ssa_lim (void);
unsigned int tree_ssa_unswitch_loops (void);
unsigned int canonicalize_induction_variables (void);
unsigned int tree_unroll_loops_completely (bool, bool);
unsigned int tree_ssa_prefetch_arrays (void);
void tree_ssa_iv_optimize (void);
unsigned tree_predictive_commoning (void);
tree canonicalize_loop_ivs (struct loop *, tree *, bool);
bool parallelize_loops (void);
bool loop_only_exit_p (const struct loop *, const_edge);
bool number_of_iterations_exit (struct loop *, edge,
struct tree_niter_desc *niter, bool,
bool every_iteration = true);
tree find_loop_niter (struct loop *, edge *);
tree loop_niter_by_eval (struct loop *, edge);
tree find_loop_niter_by_eval (struct loop *, edge *);
void estimate_numbers_of_iterations (void);
bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool);
bool convert_affine_scev (struct loop *, tree, tree *, tree *, gimple, bool);
bool nowrap_type_p (tree);
enum ev_direction {EV_DIR_GROWS, EV_DIR_DECREASES, EV_DIR_UNKNOWN};
enum ev_direction scev_direction (const_tree);
void free_numbers_of_iterations_estimates (void);
void free_numbers_of_iterations_estimates_loop (struct loop *);
void rewrite_into_loop_closed_ssa (bitmap, unsigned);
void verify_loop_closed_ssa (bool);
bool for_each_index (tree *, bool (*) (tree, tree *, void *), void *);
void create_iv (tree, tree, tree, struct loop *, gimple_stmt_iterator *, bool,
tree *, tree *);
basic_block split_loop_exit_edge (edge);
void standard_iv_increment_position (struct loop *, gimple_stmt_iterator *,
bool *);
basic_block ip_end_pos (struct loop *);
basic_block ip_normal_pos (struct loop *);
bool gimple_duplicate_loop_to_header_edge (struct loop *, edge,
unsigned int, sbitmap,
edge, vec<edge> *,
int);
struct loop *slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *, edge);
tree expand_simple_operations (tree);
void substitute_in_loop_info (struct loop *, tree, tree);
edge single_dom_exit (struct loop *);
bool can_unroll_loop_p (struct loop *loop, unsigned factor,
struct tree_niter_desc *niter);
void tree_unroll_loop (struct loop *, unsigned,
edge, struct tree_niter_desc *);
typedef void (*transform_callback)(struct loop *, void *);
void tree_transform_and_unroll_loop (struct loop *, unsigned,
edge, struct tree_niter_desc *,
transform_callback, void *);
bool contains_abnormal_ssa_name_p (tree);
bool stmt_dominates_stmt_p (gimple, gimple);
/* In tree-ssa-threadedge.c */
extern void threadedge_initialize_values (void);
@ -362,19 +273,6 @@ extern void thread_across_edge (gimple, edge, bool,
vec<tree> *, tree (*) (gimple, gimple));
extern void propagate_threaded_block_debug_into (basic_block, basic_block);
/* In tree-ssa-loop-im.c */
/* The possibilities of statement movement. */
enum move_pos
{
MOVE_IMPOSSIBLE, /* No movement -- side effect expression. */
MOVE_PRESERVE_EXECUTION, /* Must not cause the non-executed statement
become executed -- memory accesses, ... */
MOVE_POSSIBLE /* Unlimited movement. */
};
extern enum move_pos movement_possibility (gimple);
char *get_lsm_tmp_name (tree, unsigned);
/* In tree-loop-linear.c */
extern void linear_transform_loops (void);
extern unsigned perfect_loop_nest_depth (struct loop *);
@ -385,14 +283,6 @@ extern void graphite_transform_loops (void);
/* In tree-data-ref.c */
extern void tree_check_data_deps (void);
/* In tree-ssa-loop-ivopts.c */
bool expr_invariant_in_loop_p (struct loop *, tree);
bool stmt_invariant_in_loop_p (struct loop *, gimple);
struct loop *outermost_invariant_loop_for_expr (struct loop *, tree);
bool multiplier_allowed_in_address_p (HOST_WIDE_INT, enum machine_mode,
addr_space_t);
bool may_be_nonaddressable_p (tree expr);
/* In gimplify.c */
tree force_gimple_operand_1 (tree, gimple_seq *, gimple_predicate, tree);
tree force_gimple_operand (tree, gimple_seq *, bool, tree);

View File

@ -36,7 +36,8 @@ extern tree resolve_mixers (struct loop *, tree);
extern void gather_stats_on_scev_database (void);
extern unsigned int scev_const_prop (void);
extern bool expression_expensive_p (tree);
extern bool simple_iv (struct loop *, struct loop *, tree, affine_iv *, bool);
extern bool simple_iv (struct loop *, struct loop *, tree, struct affine_iv_d *,
bool);
extern tree compute_overall_effect_of_inner_loop (struct loop *, tree);
/* Returns the basic block preceding LOOP or ENTRY_BLOCK_PTR when the

View File

@ -29,7 +29,6 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "tree-inline.h"
#include "flags.h"
#include "tree-inline.h"
/* Duplicates headers of loops if they are small enough, so that the statements
in the loop body are always executed when the loop is entered. This
@ -100,7 +99,7 @@ should_duplicate_loop_header_p (basic_block header, struct loop *loop,
/* Checks whether LOOP is a do-while style loop. */
bool
static bool
do_while_loop_p (struct loop *loop)
{
gimple stmt = last_stmt (loop->latch);

View File

@ -242,98 +242,16 @@ clear_lim_data (gimple stmt)
*p = NULL;
}
/* Calls CBCK for each index in memory reference ADDR_P. There are two
kinds situations handled; in each of these cases, the memory reference
and DATA are passed to the callback:
Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also
pass the pointer to the index to the callback.
/* The possibilities of statement movement. */
enum move_pos
{
MOVE_IMPOSSIBLE, /* No movement -- side effect expression. */
MOVE_PRESERVE_EXECUTION, /* Must not cause the non-executed statement
become executed -- memory accesses, ... */
MOVE_POSSIBLE /* Unlimited movement. */
};
Pointer dereference: INDIRECT_REF (addr). In this case we also pass the
pointer to addr to the callback.
If the callback returns false, the whole search stops and false is returned.
Otherwise the function returns true after traversing through the whole
reference *ADDR_P. */
bool
for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
{
tree *nxt, *idx;
for (; ; addr_p = nxt)
{
switch (TREE_CODE (*addr_p))
{
case SSA_NAME:
return cbck (*addr_p, addr_p, data);
case MEM_REF:
nxt = &TREE_OPERAND (*addr_p, 0);
return cbck (*addr_p, nxt, data);
case BIT_FIELD_REF:
case VIEW_CONVERT_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
nxt = &TREE_OPERAND (*addr_p, 0);
break;
case COMPONENT_REF:
/* If the component has varying offset, it behaves like index
as well. */
idx = &TREE_OPERAND (*addr_p, 2);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
nxt = &TREE_OPERAND (*addr_p, 0);
break;
case ARRAY_REF:
case ARRAY_RANGE_REF:
nxt = &TREE_OPERAND (*addr_p, 0);
if (!cbck (*addr_p, &TREE_OPERAND (*addr_p, 1), data))
return false;
break;
case VAR_DECL:
case PARM_DECL:
case CONST_DECL:
case STRING_CST:
case RESULT_DECL:
case VECTOR_CST:
case COMPLEX_CST:
case INTEGER_CST:
case REAL_CST:
case FIXED_CST:
case CONSTRUCTOR:
return true;
case ADDR_EXPR:
gcc_assert (is_gimple_min_invariant (*addr_p));
return true;
case TARGET_MEM_REF:
idx = &TMR_BASE (*addr_p);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
idx = &TMR_INDEX (*addr_p);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
idx = &TMR_INDEX2 (*addr_p);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
return true;
default:
gcc_unreachable ();
}
}
}
/* If it is possible to hoist the statement STMT unconditionally,
returns MOVE_POSSIBLE.
@ -1741,122 +1659,6 @@ first_mem_ref_loc (struct loop *loop, mem_ref_p ref)
return locp;
}
/* The name and the length of the currently generated variable
for lsm. */
#define MAX_LSM_NAME_LENGTH 40
static char lsm_tmp_name[MAX_LSM_NAME_LENGTH + 1];
static int lsm_tmp_name_length;
/* Adds S to lsm_tmp_name. */
static void
lsm_tmp_name_add (const char *s)
{
int l = strlen (s) + lsm_tmp_name_length;
if (l > MAX_LSM_NAME_LENGTH)
return;
strcpy (lsm_tmp_name + lsm_tmp_name_length, s);
lsm_tmp_name_length = l;
}
/* Stores the name for temporary variable that replaces REF to
lsm_tmp_name. */
static void
gen_lsm_tmp_name (tree ref)
{
const char *name;
switch (TREE_CODE (ref))
{
case MEM_REF:
case TARGET_MEM_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_");
break;
case ADDR_EXPR:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
break;
case BIT_FIELD_REF:
case VIEW_CONVERT_EXPR:
case ARRAY_RANGE_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
break;
case REALPART_EXPR:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_RE");
break;
case IMAGPART_EXPR:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_IM");
break;
case COMPONENT_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_");
name = get_name (TREE_OPERAND (ref, 1));
if (!name)
name = "F";
lsm_tmp_name_add (name);
break;
case ARRAY_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_I");
break;
case SSA_NAME:
case VAR_DECL:
case PARM_DECL:
name = get_name (ref);
if (!name)
name = "D";
lsm_tmp_name_add (name);
break;
case STRING_CST:
lsm_tmp_name_add ("S");
break;
case RESULT_DECL:
lsm_tmp_name_add ("R");
break;
case INTEGER_CST:
/* Nothing. */
break;
default:
gcc_unreachable ();
}
}
/* Determines name for temporary variable that replaces REF.
The name is accumulated into the lsm_tmp_name variable.
N is added to the name of the temporary. */
char *
get_lsm_tmp_name (tree ref, unsigned n)
{
char ns[2];
lsm_tmp_name_length = 0;
gen_lsm_tmp_name (ref);
lsm_tmp_name_add ("_lsm");
if (n < 10)
{
ns[0] = '0' + n;
ns[1] = 0;
lsm_tmp_name_add (ns);
}
return lsm_tmp_name;
}
struct prev_flag_edges {
/* Edge to insert new flag comparison code. */
edge append_cond_position;
@ -2026,8 +1828,7 @@ static tree
execute_sm_if_changed_flag_set (struct loop *loop, mem_ref_p ref)
{
tree flag;
char *str = get_lsm_tmp_name (ref->mem.ref, ~0);
lsm_tmp_name_add ("_flag");
char *str = get_lsm_tmp_name (ref->mem.ref, ~0, "_flag");
flag = create_tmp_reg (boolean_type_node, str);
for_all_locs_in_loop (loop, ref, sm_set_flag_if_changed (flag));
return flag;
@ -2639,3 +2440,61 @@ tree_ssa_lim (void)
return todo;
}
/* Loop invariant motion pass. */
static unsigned int
tree_ssa_loop_im (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_ssa_lim ();
}
static bool
gate_tree_ssa_loop_im (void)
{
return flag_tree_loop_im != 0;
}
namespace {
const pass_data pass_data_lim =
{
GIMPLE_PASS, /* type */
"lim", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_LIM, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_lim : public gimple_opt_pass
{
public:
pass_lim (gcc::context *ctxt)
: gimple_opt_pass (pass_data_lim, ctxt)
{}
/* opt_pass methods: */
opt_pass * clone () { return new pass_lim (m_ctxt); }
bool gate () { return gate_tree_ssa_loop_im (); }
unsigned int execute () { return tree_ssa_loop_im (); }
}; // class pass_lim
} // anon namespace
gimple_opt_pass *
make_pass_lim (gcc::context *ctxt)
{
return new pass_lim (ctxt);
}

View File

@ -107,23 +107,6 @@ create_canonical_iv (struct loop *loop, edge exit, tree niter)
update_stmt (cond);
}
/* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */
unsigned
tree_num_loop_insns (struct loop *loop, eni_weights *weights)
{
basic_block *body = get_loop_body (loop);
gimple_stmt_iterator gsi;
unsigned size = 0, i;
for (i = 0; i < loop->num_nodes; i++)
for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
size += estimate_num_insns (gsi_stmt (gsi), weights);
free (body);
return size;
}
/* Describe size of loop as detected by tree_estimate_loop_size. */
struct loop_size
{
@ -422,7 +405,7 @@ estimated_unrolled_size (struct loop_size *size,
loop-niter identified as having undefined effect in the last iteration.
The other cases are hopefully rare and will be cleaned up later. */
edge
static edge
loop_edge_to_cancel (struct loop *loop)
{
vec<edge> exits;
@ -598,7 +581,7 @@ static vec<int> loops_to_unloop_nunroll;
LOOP_CLOSED_SSA_INVALIDATED is used to bookkepp the case
when we need to go into loop closed SSA form. */
void
static void
unloop_loops (bitmap loop_closed_ssa_invalidated,
bool *irred_invalidated)
{
@ -1253,3 +1236,182 @@ tree_unroll_loops_completely (bool may_increase_size, bool unroll_outer)
return 0;
}
/* Canonical induction variable creation pass. */
static unsigned int
tree_ssa_loop_ivcanon (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return canonicalize_induction_variables ();
}
static bool
gate_tree_ssa_loop_ivcanon (void)
{
return flag_tree_loop_ivcanon != 0;
}
namespace {
const pass_data pass_data_iv_canon =
{
GIMPLE_PASS, /* type */
"ivcanon", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_TREE_LOOP_IVCANON, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_iv_canon : public gimple_opt_pass
{
public:
pass_iv_canon (gcc::context *ctxt)
: gimple_opt_pass (pass_data_iv_canon, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_ssa_loop_ivcanon (); }
unsigned int execute () { return tree_ssa_loop_ivcanon (); }
}; // class pass_iv_canon
} // anon namespace
gimple_opt_pass *
make_pass_iv_canon (gcc::context *ctxt)
{
return new pass_iv_canon (ctxt);
}
/* Complete unrolling of loops. */
static unsigned int
tree_complete_unroll (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_unroll_loops_completely (flag_unroll_loops
|| flag_peel_loops
|| optimize >= 3, true);
}
static bool
gate_tree_complete_unroll (void)
{
return true;
}
namespace {
const pass_data pass_data_complete_unroll =
{
GIMPLE_PASS, /* type */
"cunroll", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_COMPLETE_UNROLL, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_complete_unroll : public gimple_opt_pass
{
public:
pass_complete_unroll (gcc::context *ctxt)
: gimple_opt_pass (pass_data_complete_unroll, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_complete_unroll (); }
unsigned int execute () { return tree_complete_unroll (); }
}; // class pass_complete_unroll
} // anon namespace
gimple_opt_pass *
make_pass_complete_unroll (gcc::context *ctxt)
{
return new pass_complete_unroll (ctxt);
}
/* Complete unrolling of inner loops. */
static unsigned int
tree_complete_unroll_inner (void)
{
unsigned ret = 0;
loop_optimizer_init (LOOPS_NORMAL
| LOOPS_HAVE_RECORDED_EXITS);
if (number_of_loops (cfun) > 1)
{
scev_initialize ();
ret = tree_unroll_loops_completely (optimize >= 3, false);
free_numbers_of_iterations_estimates ();
scev_finalize ();
}
loop_optimizer_finalize ();
return ret;
}
static bool
gate_tree_complete_unroll_inner (void)
{
return optimize >= 2;
}
namespace {
const pass_data pass_data_complete_unrolli =
{
GIMPLE_PASS, /* type */
"cunrolli", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_COMPLETE_UNROLL, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_verify_flow, /* todo_flags_finish */
};
class pass_complete_unrolli : public gimple_opt_pass
{
public:
pass_complete_unrolli (gcc::context *ctxt)
: gimple_opt_pass (pass_data_complete_unrolli, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_complete_unroll_inner (); }
unsigned int execute () { return tree_complete_unroll_inner (); }
}; // class pass_complete_unrolli
} // anon namespace
gimple_opt_pass *
make_pass_complete_unrolli (gcc::context *ctxt)
{
return new pass_complete_unrolli (ctxt);
}

View File

@ -452,7 +452,6 @@ single_dom_exit (struct loop *loop)
/* Dumps information about the induction variable IV to FILE. */
extern void dump_iv (FILE *, struct iv *);
void
dump_iv (FILE *file, struct iv *iv)
{
@ -497,7 +496,6 @@ dump_iv (FILE *file, struct iv *iv)
/* Dumps information about the USE to FILE. */
extern void dump_use (FILE *, struct iv_use *);
void
dump_use (FILE *file, struct iv_use *use)
{
@ -541,7 +539,6 @@ dump_use (FILE *file, struct iv_use *use)
/* Dumps information about the uses to FILE. */
extern void dump_uses (FILE *, struct ivopts_data *);
void
dump_uses (FILE *file, struct ivopts_data *data)
{
@ -559,7 +556,6 @@ dump_uses (FILE *file, struct ivopts_data *data)
/* Dumps information about induction variable candidate CAND to FILE. */
extern void dump_cand (FILE *, struct iv_cand *);
void
dump_cand (FILE *file, struct iv_cand *cand)
{
@ -1454,29 +1450,6 @@ expr_invariant_in_loop_p (struct loop *loop, tree expr)
return true;
}
/* Returns true if statement STMT is obviously invariant in LOOP,
i.e. if all its operands on the RHS are defined outside of the LOOP.
LOOP should not be the function body. */
bool
stmt_invariant_in_loop_p (struct loop *loop, gimple stmt)
{
unsigned i;
tree lhs;
gcc_assert (loop_depth (loop) > 0);
lhs = gimple_get_lhs (stmt);
for (i = 0; i < gimple_num_ops (stmt); i++)
{
tree op = gimple_op (stmt, i);
if (op != lhs && !expr_invariant_in_loop_p (loop, op))
return false;
}
return true;
}
/* Cumulates the steps of indices into DATA and replaces their values with the
initial ones. Returns false when the value of the index cannot be determined.
Callback for for_each_index. */

View File

@ -0,0 +1,36 @@
/* Header file for Induction variable optimizations.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_SSA_LOOP_IVOPTS_H
#define GCC_TREE_SSA_LOOP_IVOPTS_H
extern edge single_dom_exit (struct loop *);
extern void dump_iv (FILE *, struct iv *);
extern void dump_use (FILE *, struct iv_use *);
extern void dump_uses (FILE *, struct ivopts_data *);
extern void dump_cand (FILE *, struct iv_cand *);
extern bool contains_abnormal_ssa_name_p (tree);
extern struct loop *outermost_invariant_loop_for_expr (struct loop *, tree);
extern bool expr_invariant_in_loop_p (struct loop *, tree);
bool may_be_nonaddressable_p (tree expr);
bool multiplier_allowed_in_address_p (HOST_WIDE_INT, enum machine_mode,
addr_space_t);
void tree_ssa_iv_optimize (void);
#endif /* GCC_TREE_SSA_LOOP_IVOPTS_H */

49
gcc/tree-ssa-loop-manip.h Normal file
View File

@ -0,0 +1,49 @@
/* Header file for High-level loop manipulation functions.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_SSA_LOOP_MANIP_H
#define GCC_TREE_SSA_LOOP_MANIP_H
typedef void (*transform_callback)(struct loop *, void *);
extern void create_iv (tree, tree, tree, struct loop *, gimple_stmt_iterator *,
bool, tree *, tree *);
extern void rewrite_into_loop_closed_ssa (bitmap, unsigned);
extern void verify_loop_closed_ssa (bool);
extern basic_block split_loop_exit_edge (edge);
extern basic_block ip_end_pos (struct loop *);
extern basic_block ip_normal_pos (struct loop *);
extern void standard_iv_increment_position (struct loop *,
gimple_stmt_iterator *, bool *);
extern bool gimple_duplicate_loop_to_header_edge (struct loop *, edge,
unsigned int, sbitmap,
edge, vec<edge> *,
int);
extern bool can_unroll_loop_p (struct loop *loop, unsigned factor,
struct tree_niter_desc *niter);
extern void tree_transform_and_unroll_loop (struct loop *, unsigned,
edge, struct tree_niter_desc *,
transform_callback, void *);
extern void tree_unroll_loop (struct loop *, unsigned,
edge, struct tree_niter_desc *);
extern tree canonicalize_loop_ivs (struct loop *, tree *, bool);
#endif /* GCC_TREE_SSA_LOOP_MANIP_H */

View File

@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-inline.h"
#include "tree-pass.h"
#define SWAP(X, Y) do { affine_iv *tmp = (X); (X) = (Y); (Y) = tmp; } while (0)
/* The maximum number of dominator BBs we search for conditions
@ -2507,40 +2508,6 @@ derive_constant_upper_bound_ops (tree type, tree op0,
}
}
/* Records that every statement in LOOP is executed I_BOUND times.
REALISTIC is true if I_BOUND is expected to be close to the real number
of iterations. UPPER is true if we are sure the loop iterates at most
I_BOUND times. */
void
record_niter_bound (struct loop *loop, double_int i_bound, bool realistic,
bool upper)
{
/* Update the bounds only when there is no previous estimation, or when the
current estimation is smaller. */
if (upper
&& (!loop->any_upper_bound
|| i_bound.ult (loop->nb_iterations_upper_bound)))
{
loop->any_upper_bound = true;
loop->nb_iterations_upper_bound = i_bound;
}
if (realistic
&& (!loop->any_estimate
|| i_bound.ult (loop->nb_iterations_estimate)))
{
loop->any_estimate = true;
loop->nb_iterations_estimate = i_bound;
}
/* If an upper bound is smaller than the realistic estimate of the
number of iterations, use the upper bound instead. */
if (loop->any_upper_bound
&& loop->any_estimate
&& loop->nb_iterations_upper_bound.ult (loop->nb_iterations_estimate))
loop->nb_iterations_estimate = loop->nb_iterations_upper_bound;
}
/* Emit a -Waggressive-loop-optimizations warning if needed. */
static void
@ -3008,26 +2975,11 @@ infer_loop_bounds_from_undefined (struct loop *loop)
free (bbs);
}
/* Converts VAL to double_int. */
static double_int
gcov_type_to_double_int (gcov_type val)
{
double_int ret;
ret.low = (unsigned HOST_WIDE_INT) val;
/* If HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_WIDEST_INT, avoid shifting by
the size of type. */
val >>= HOST_BITS_PER_WIDE_INT - 1;
val >>= 1;
ret.high = (unsigned HOST_WIDE_INT) val;
return ret;
}
/* Compare double ints, callback for qsort. */
int
static int
double_int_cmp (const void *p1, const void *p2)
{
const double_int *d1 = (const double_int *)p1;
@ -3042,7 +2994,7 @@ double_int_cmp (const void *p1, const void *p2)
/* Return index of BOUND in BOUNDS array sorted in increasing order.
Lookup by binary search. */
int
static int
bound_index (vec<double_int> bounds, double_int bound)
{
unsigned int end = bounds.length ();
@ -3349,7 +3301,7 @@ maybe_lower_iteration_bound (struct loop *loop)
/* Records estimates on numbers of iterations of LOOP. If USE_UNDEFINED_P
is true also use estimates derived from undefined behavior. */
void
static void
estimate_numbers_of_iterations_loop (struct loop *loop)
{
vec<edge> exits;
@ -3433,21 +3385,7 @@ estimated_loop_iterations (struct loop *loop, double_int *nit)
if (scev_initialized_p ())
estimate_numbers_of_iterations_loop (loop);
/* Even if the bound is not recorded, possibly we can derrive one from
profile. */
if (!loop->any_estimate)
{
if (loop->header->count)
{
*nit = gcov_type_to_double_int
(expected_loop_iterations_unbounded (loop) + 1);
return true;
}
return false;
}
*nit = loop->nb_iterations_estimate;
return true;
return (get_estimated_loop_iterations (loop, nit));
}
/* Sets NIT to an upper bound for the maximum number of executions of the
@ -3461,31 +3399,8 @@ max_loop_iterations (struct loop *loop, double_int *nit)
estimate. Otherwise just return whatever we recorded earlier. */
if (scev_initialized_p ())
estimate_numbers_of_iterations_loop (loop);
if (!loop->any_upper_bound)
return false;
*nit = loop->nb_iterations_upper_bound;
return true;
}
/* Similar to estimated_loop_iterations, but returns the estimate only
if it fits to HOST_WIDE_INT. If this is not the case, or the estimate
on the number of iterations of LOOP could not be derived, returns -1. */
HOST_WIDE_INT
estimated_loop_iterations_int (struct loop *loop)
{
double_int nit;
HOST_WIDE_INT hwi_nit;
if (!estimated_loop_iterations (loop, &nit))
return -1;
if (!nit.fits_shwi ())
return -1;
hwi_nit = nit.to_shwi ();
return hwi_nit < 0 ? -1 : hwi_nit;
return get_max_loop_iterations (loop, nit);
}
/* Similar to max_loop_iterations, but returns the estimate only
@ -3508,25 +3423,6 @@ max_loop_iterations_int (struct loop *loop)
return hwi_nit < 0 ? -1 : hwi_nit;
}
/* Returns an upper bound on the number of executions of statements
in the LOOP. For statements before the loop exit, this exceeds
the number of execution of the latch by one. */
HOST_WIDE_INT
max_stmt_executions_int (struct loop *loop)
{
HOST_WIDE_INT nit = max_loop_iterations_int (loop);
HOST_WIDE_INT snit;
if (nit == -1)
return -1;
snit = (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) nit + 1);
/* If the computation overflows, return -1. */
return snit < 0 ? -1 : snit;
}
/* Returns an estimate for the number of executions of statements
in the LOOP. For statements before the loop exit, this exceeds
the number of execution of the latch by one. */

46
gcc/tree-ssa-loop-niter.h Normal file
View File

@ -0,0 +1,46 @@
/* Header file for loop interation estimates.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_SSA_LOOP_NITER_H
#define GCC_TREE_SSA_LOOP_NITER_H
extern tree expand_simple_operations (tree);
extern bool loop_only_exit_p (const struct loop *, const_edge);
extern bool number_of_iterations_exit (struct loop *, edge,
struct tree_niter_desc *niter, bool,
bool every_iteration = true);
extern tree find_loop_niter (struct loop *, edge *);
extern bool finite_loop_p (struct loop *);
extern tree loop_niter_by_eval (struct loop *, edge);
extern tree find_loop_niter_by_eval (struct loop *, edge *);
extern bool estimated_loop_iterations (struct loop *, double_int *);
extern bool max_loop_iterations (struct loop *, double_int *);
extern HOST_WIDE_INT max_stmt_executions_int (struct loop *);
extern HOST_WIDE_INT estimated_stmt_executions_int (struct loop *);
extern bool max_stmt_executions (struct loop *, double_int *);
extern bool estimated_stmt_executions (struct loop *, double_int *);
extern void estimate_numbers_of_iterations (void);
extern bool stmt_dominates_stmt_p (gimple, gimple);
extern bool nowrap_type_p (tree);
extern bool scev_probably_wraps_p (tree, tree, gimple, struct loop *, bool);
extern void free_numbers_of_iterations_estimates_loop (struct loop *);
extern void free_numbers_of_iterations_estimates (void);
extern void substitute_in_loop_info (struct loop *, tree, tree);
#endif /* GCC_TREE_SSA_LOOP_NITER_H */

View File

@ -1988,3 +1988,60 @@ tree_ssa_prefetch_arrays (void)
free_original_copy_tables ();
return todo_flags;
}
/* Prefetching. */
static unsigned int
tree_ssa_loop_prefetch (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_ssa_prefetch_arrays ();
}
static bool
gate_tree_ssa_loop_prefetch (void)
{
return flag_prefetch_loop_arrays > 0;
}
namespace {
const pass_data pass_data_loop_prefetch =
{
GIMPLE_PASS, /* type */
"aprefetch", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_TREE_PREFETCH, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_loop_prefetch : public gimple_opt_pass
{
public:
pass_loop_prefetch (gcc::context *ctxt)
: gimple_opt_pass (pass_data_loop_prefetch, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_ssa_loop_prefetch (); }
unsigned int execute () { return tree_ssa_loop_prefetch (); }
}; // class pass_loop_prefetch
} // anon namespace
gimple_opt_pass *
make_pass_loop_prefetch (gcc::context *ctxt)
{
return new pass_loop_prefetch (ctxt);
}

View File

@ -388,3 +388,60 @@ tree_unswitch_loop (struct loop *loop,
NULL, prob_true, prob_true,
REG_BR_PROB_BASE - prob_true, false);
}
/* Loop unswitching pass. */
static unsigned int
tree_ssa_loop_unswitch (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_ssa_unswitch_loops ();
}
static bool
gate_tree_ssa_loop_unswitch (void)
{
return flag_unswitch_loops != 0;
}
namespace {
const pass_data pass_data_tree_unswitch =
{
GIMPLE_PASS, /* type */
"unswitch", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_TREE_LOOP_UNSWITCH, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_tree_unswitch : public gimple_opt_pass
{
public:
pass_tree_unswitch (gcc::context *ctxt)
: gimple_opt_pass (pass_data_tree_unswitch, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_ssa_loop_unswitch (); }
unsigned int execute () { return tree_ssa_loop_unswitch (); }
}; // class pass_tree_unswitch
} // anon namespace
gimple_opt_pass *
make_pass_tree_unswitch (gcc::context *ctxt)
{
return new pass_tree_unswitch (ctxt);
}

View File

@ -134,117 +134,6 @@ make_pass_tree_loop_init (gcc::context *ctxt)
return new pass_tree_loop_init (ctxt);
}
/* Loop invariant motion pass. */
static unsigned int
tree_ssa_loop_im (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_ssa_lim ();
}
static bool
gate_tree_ssa_loop_im (void)
{
return flag_tree_loop_im != 0;
}
namespace {
const pass_data pass_data_lim =
{
GIMPLE_PASS, /* type */
"lim", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_LIM, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_lim : public gimple_opt_pass
{
public:
pass_lim (gcc::context *ctxt)
: gimple_opt_pass (pass_data_lim, ctxt)
{}
/* opt_pass methods: */
opt_pass * clone () { return new pass_lim (m_ctxt); }
bool gate () { return gate_tree_ssa_loop_im (); }
unsigned int execute () { return tree_ssa_loop_im (); }
}; // class pass_lim
} // anon namespace
gimple_opt_pass *
make_pass_lim (gcc::context *ctxt)
{
return new pass_lim (ctxt);
}
/* Loop unswitching pass. */
static unsigned int
tree_ssa_loop_unswitch (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_ssa_unswitch_loops ();
}
static bool
gate_tree_ssa_loop_unswitch (void)
{
return flag_unswitch_loops != 0;
}
namespace {
const pass_data pass_data_tree_unswitch =
{
GIMPLE_PASS, /* type */
"unswitch", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_TREE_LOOP_UNSWITCH, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_tree_unswitch : public gimple_opt_pass
{
public:
pass_tree_unswitch (gcc::context *ctxt)
: gimple_opt_pass (pass_data_tree_unswitch, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_ssa_loop_unswitch (); }
unsigned int execute () { return tree_ssa_loop_unswitch (); }
}; // class pass_tree_unswitch
} // anon namespace
gimple_opt_pass *
make_pass_tree_unswitch (gcc::context *ctxt)
{
return new pass_tree_unswitch (ctxt);
}
/* Predictive commoning. */
static unsigned
@ -515,61 +404,6 @@ make_pass_check_data_deps (gcc::context *ctxt)
return new pass_check_data_deps (ctxt);
}
/* Canonical induction variable creation pass. */
static unsigned int
tree_ssa_loop_ivcanon (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return canonicalize_induction_variables ();
}
static bool
gate_tree_ssa_loop_ivcanon (void)
{
return flag_tree_loop_ivcanon != 0;
}
namespace {
const pass_data pass_data_iv_canon =
{
GIMPLE_PASS, /* type */
"ivcanon", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_TREE_LOOP_IVCANON, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_iv_canon : public gimple_opt_pass
{
public:
pass_iv_canon (gcc::context *ctxt)
: gimple_opt_pass (pass_data_iv_canon, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_ssa_loop_ivcanon (); }
unsigned int execute () { return tree_ssa_loop_ivcanon (); }
}; // class pass_iv_canon
} // anon namespace
gimple_opt_pass *
make_pass_iv_canon (gcc::context *ctxt)
{
return new pass_iv_canon (ctxt);
}
/* Propagation of constants using scev. */
static bool
@ -667,128 +501,6 @@ make_pass_record_bounds (gcc::context *ctxt)
return new pass_record_bounds (ctxt);
}
/* Complete unrolling of loops. */
static unsigned int
tree_complete_unroll (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_unroll_loops_completely (flag_unroll_loops
|| flag_peel_loops
|| optimize >= 3, true);
}
static bool
gate_tree_complete_unroll (void)
{
return true;
}
namespace {
const pass_data pass_data_complete_unroll =
{
GIMPLE_PASS, /* type */
"cunroll", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_COMPLETE_UNROLL, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_complete_unroll : public gimple_opt_pass
{
public:
pass_complete_unroll (gcc::context *ctxt)
: gimple_opt_pass (pass_data_complete_unroll, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_complete_unroll (); }
unsigned int execute () { return tree_complete_unroll (); }
}; // class pass_complete_unroll
} // anon namespace
gimple_opt_pass *
make_pass_complete_unroll (gcc::context *ctxt)
{
return new pass_complete_unroll (ctxt);
}
/* Complete unrolling of inner loops. */
static unsigned int
tree_complete_unroll_inner (void)
{
unsigned ret = 0;
loop_optimizer_init (LOOPS_NORMAL
| LOOPS_HAVE_RECORDED_EXITS);
if (number_of_loops (cfun) > 1)
{
scev_initialize ();
ret = tree_unroll_loops_completely (optimize >= 3, false);
free_numbers_of_iterations_estimates ();
scev_finalize ();
}
loop_optimizer_finalize ();
return ret;
}
static bool
gate_tree_complete_unroll_inner (void)
{
return optimize >= 2;
}
namespace {
const pass_data pass_data_complete_unrolli =
{
GIMPLE_PASS, /* type */
"cunrolli", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_COMPLETE_UNROLL, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_verify_flow, /* todo_flags_finish */
};
class pass_complete_unrolli : public gimple_opt_pass
{
public:
pass_complete_unrolli (gcc::context *ctxt)
: gimple_opt_pass (pass_data_complete_unrolli, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_complete_unroll_inner (); }
unsigned int execute () { return tree_complete_unroll_inner (); }
}; // class pass_complete_unrolli
} // anon namespace
gimple_opt_pass *
make_pass_complete_unrolli (gcc::context *ctxt)
{
return new pass_complete_unrolli (ctxt);
}
/* Parallelization. */
static bool
@ -846,61 +558,6 @@ make_pass_parallelize_loops (gcc::context *ctxt)
return new pass_parallelize_loops (ctxt);
}
/* Prefetching. */
static unsigned int
tree_ssa_loop_prefetch (void)
{
if (number_of_loops (cfun) <= 1)
return 0;
return tree_ssa_prefetch_arrays ();
}
static bool
gate_tree_ssa_loop_prefetch (void)
{
return flag_prefetch_loop_arrays > 0;
}
namespace {
const pass_data pass_data_loop_prefetch =
{
GIMPLE_PASS, /* type */
"aprefetch", /* name */
OPTGROUP_LOOP, /* optinfo_flags */
true, /* has_gate */
true, /* has_execute */
TV_TREE_PREFETCH, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_loop_prefetch : public gimple_opt_pass
{
public:
pass_loop_prefetch (gcc::context *ctxt)
: gimple_opt_pass (pass_data_loop_prefetch, ctxt)
{}
/* opt_pass methods: */
bool gate () { return gate_tree_ssa_loop_prefetch (); }
unsigned int execute () { return tree_ssa_loop_prefetch (); }
}; // class pass_loop_prefetch
} // anon namespace
gimple_opt_pass *
make_pass_loop_prefetch (gcc::context *ctxt)
{
return new pass_loop_prefetch (ctxt);
}
/* Induction variable optimizations. */
static unsigned int
@ -1004,3 +661,235 @@ make_pass_tree_loop_done (gcc::context *ctxt)
{
return new pass_tree_loop_done (ctxt);
}
/* Calls CBCK for each index in memory reference ADDR_P. There are two
kinds situations handled; in each of these cases, the memory reference
and DATA are passed to the callback:
Access to an array: ARRAY_{RANGE_}REF (base, index). In this case we also
pass the pointer to the index to the callback.
Pointer dereference: INDIRECT_REF (addr). In this case we also pass the
pointer to addr to the callback.
If the callback returns false, the whole search stops and false is returned.
Otherwise the function returns true after traversing through the whole
reference *ADDR_P. */
bool
for_each_index (tree *addr_p, bool (*cbck) (tree, tree *, void *), void *data)
{
tree *nxt, *idx;
for (; ; addr_p = nxt)
{
switch (TREE_CODE (*addr_p))
{
case SSA_NAME:
return cbck (*addr_p, addr_p, data);
case MEM_REF:
nxt = &TREE_OPERAND (*addr_p, 0);
return cbck (*addr_p, nxt, data);
case BIT_FIELD_REF:
case VIEW_CONVERT_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
nxt = &TREE_OPERAND (*addr_p, 0);
break;
case COMPONENT_REF:
/* If the component has varying offset, it behaves like index
as well. */
idx = &TREE_OPERAND (*addr_p, 2);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
nxt = &TREE_OPERAND (*addr_p, 0);
break;
case ARRAY_REF:
case ARRAY_RANGE_REF:
nxt = &TREE_OPERAND (*addr_p, 0);
if (!cbck (*addr_p, &TREE_OPERAND (*addr_p, 1), data))
return false;
break;
case VAR_DECL:
case PARM_DECL:
case CONST_DECL:
case STRING_CST:
case RESULT_DECL:
case VECTOR_CST:
case COMPLEX_CST:
case INTEGER_CST:
case REAL_CST:
case FIXED_CST:
case CONSTRUCTOR:
return true;
case ADDR_EXPR:
gcc_assert (is_gimple_min_invariant (*addr_p));
return true;
case TARGET_MEM_REF:
idx = &TMR_BASE (*addr_p);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
idx = &TMR_INDEX (*addr_p);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
idx = &TMR_INDEX2 (*addr_p);
if (*idx
&& !cbck (*addr_p, idx, data))
return false;
return true;
default:
gcc_unreachable ();
}
}
}
/* The name and the length of the currently generated variable
for lsm. */
#define MAX_LSM_NAME_LENGTH 40
static char lsm_tmp_name[MAX_LSM_NAME_LENGTH + 1];
static int lsm_tmp_name_length;
/* Adds S to lsm_tmp_name. */
static void
lsm_tmp_name_add (const char *s)
{
int l = strlen (s) + lsm_tmp_name_length;
if (l > MAX_LSM_NAME_LENGTH)
return;
strcpy (lsm_tmp_name + lsm_tmp_name_length, s);
lsm_tmp_name_length = l;
}
/* Stores the name for temporary variable that replaces REF to
lsm_tmp_name. */
static void
gen_lsm_tmp_name (tree ref)
{
const char *name;
switch (TREE_CODE (ref))
{
case MEM_REF:
case TARGET_MEM_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_");
break;
case ADDR_EXPR:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
break;
case BIT_FIELD_REF:
case VIEW_CONVERT_EXPR:
case ARRAY_RANGE_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
break;
case REALPART_EXPR:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_RE");
break;
case IMAGPART_EXPR:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_IM");
break;
case COMPONENT_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_");
name = get_name (TREE_OPERAND (ref, 1));
if (!name)
name = "F";
lsm_tmp_name_add (name);
break;
case ARRAY_REF:
gen_lsm_tmp_name (TREE_OPERAND (ref, 0));
lsm_tmp_name_add ("_I");
break;
case SSA_NAME:
case VAR_DECL:
case PARM_DECL:
name = get_name (ref);
if (!name)
name = "D";
lsm_tmp_name_add (name);
break;
case STRING_CST:
lsm_tmp_name_add ("S");
break;
case RESULT_DECL:
lsm_tmp_name_add ("R");
break;
case INTEGER_CST:
/* Nothing. */
break;
default:
gcc_unreachable ();
}
}
/* Determines name for temporary variable that replaces REF.
The name is accumulated into the lsm_tmp_name variable.
N is added to the name of the temporary. */
char *
get_lsm_tmp_name (tree ref, unsigned n, const char *suffix)
{
char ns[2];
lsm_tmp_name_length = 0;
gen_lsm_tmp_name (ref);
lsm_tmp_name_add ("_lsm");
if (n < 10)
{
ns[0] = '0' + n;
ns[1] = 0;
lsm_tmp_name_add (ns);
}
return lsm_tmp_name;
if (suffix != NULL)
lsm_tmp_name_add (suffix);
}
/* Computes an estimated number of insns in LOOP, weighted by WEIGHTS. */
unsigned
tree_num_loop_insns (struct loop *loop, eni_weights *weights)
{
basic_block *body = get_loop_body (loop);
gimple_stmt_iterator gsi;
unsigned size = 0, i;
for (i = 0; i < loop->num_nodes; i++)
for (gsi = gsi_start_bb (body[i]); !gsi_end_p (gsi); gsi_next (&gsi))
size += estimate_num_insns (gsi_stmt (gsi), weights);
free (body);
return size;
}

85
gcc/tree-ssa-loop.h Normal file
View File

@ -0,0 +1,85 @@
/* Header file for SSA loop optimizations.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_SSA_LOOP_H
#define GCC_TREE_SSA_LOOP_H
#include "tree-ssa-loop-ivopts.h"
#include "tree-ssa-loop-manip.h"
#include "tree-ssa-loop-niter.h"
/* Affine iv. */
typedef struct affine_iv_d
{
/* Iv = BASE + STEP * i. */
tree base, step;
/* True if this iv does not overflow. */
bool no_overflow;
} affine_iv;
/* Description of number of iterations of a loop. All the expressions inside
the structure can be evaluated at the end of the loop's preheader
(and due to ssa form, also anywhere inside the body of the loop). */
struct tree_niter_desc
{
tree assumptions; /* The boolean expression. If this expression evaluates
to false, then the other fields in this structure
should not be used; there is no guarantee that they
will be correct. */
tree may_be_zero; /* The boolean expression. If it evaluates to true,
the loop will exit in the first iteration (i.e.
its latch will not be executed), even if the niter
field says otherwise. */
tree niter; /* The expression giving the number of iterations of
a loop (provided that assumptions == true and
may_be_zero == false), more precisely the number
of executions of the latch of the loop. */
double_int max; /* The upper bound on the number of iterations of
the loop. */
/* The simplified shape of the exit condition. The loop exits if
CONTROL CMP BOUND is false, where CMP is one of NE_EXPR,
LT_EXPR, or GT_EXPR, and step of CONTROL is positive if CMP is
LE_EXPR and negative if CMP is GE_EXPR. This information is used
by loop unrolling. */
affine_iv control;
tree bound;
enum tree_code cmp;
};
extern bool for_each_index (tree *, bool (*) (tree, tree *, void *), void *);
extern char *get_lsm_tmp_name (tree ref, unsigned n, const char *suffix = NULL);
extern unsigned tree_num_loop_insns (struct loop *, struct eni_weights_d *);
/* Returns the loop of the statement STMT. */
static inline struct loop *
loop_containing_stmt (gimple stmt)
{
basic_block bb = gimple_bb (stmt);
if (!bb)
return NULL;
return bb->loop_father;
}
#endif /* GCC_TREE_SSA_LOOP_H */