Makefile.in (tree-data-ref.o): Add langhooks.h dependency.
* Makefile.in (tree-data-ref.o): Add langhooks.h dependency. * tree-ssa-loop-niter.c (derive_constant_upper_bound): Follow ud-chains. Handle AND_EXPR. (record_estimate): Record whether the estimate is realistic and whether it is derived from a loop exit. (record_nonwrapping_iv, idx_infer_loop_bounds, infer_loop_bounds_from_ref, infer_loop_bounds_from_array, infer_loop_bounds_from_signedness): New functions. (compute_estimated_nb_iterations): Take only realistic bounds into account. Set estimate_state. Use double_ints. (infer_loop_bounds_from_undefined): Call infer_loop_bounds_from_array and infer_loop_bounds_from_signedness. Do not consider basic blocks that do not have to be always executed. (estimate_numbers_of_iterations_loop): Set estimate_state, and use it to determine whether to call infer_loop_bounds_from_undefined and compute_estimated_nb_iterations. (n_of_executions_at_most): Use double_ints. (free_numbers_of_iterations_estimates_loop): Set estimate_state. (substitute_in_loop_info): Do not replace in estimated_nb_iterations. * double-int.c (double_int_to_tree): Improve comment. (double_int_fits_to_tree_p): New function. * double-int.h (double_int_fits_to_tree_p): Declare. * tree-data-ref.c: Include langhooks.h. (estimate_niter_from_size_of_data, estimate_iters_using_array): Removed. (analyze_array_indexes): Do not call estimate_niter_from_size_of_data. (analyze_array): Do not pass estimate_only argument to analyze_array_indexes. (get_number_of_iters_for_loop): Build tree from the stored double_int value. (get_references_in_stmt, find_data_references_in_stmt): New functions. (find_data_references_in_loop): Use find_data_references_in_stmt. * tree-data-ref.h (struct data_ref_loc_d): New. (get_references_in_stmt): Declare. (estimate_iters_using_array): Declaration removed. * cfgloop.h (struct nb_iter_bound): Change type of bound to double_int. Improve comments. Add is_exit and realistic fields. (struct loop): Changed type of estimated_nb_iterations to double_int. Added estimate_state field. (record_estimate): Declaration removed. From-SVN: r118729
This commit is contained in:
parent
47eb5b329b
commit
946e1bc757
@ -1,3 +1,46 @@
|
||||
2006-11-12 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
* Makefile.in (tree-data-ref.o): Add langhooks.h dependency.
|
||||
* tree-ssa-loop-niter.c (derive_constant_upper_bound): Follow
|
||||
ud-chains. Handle AND_EXPR.
|
||||
(record_estimate): Record whether the estimate is realistic
|
||||
and whether it is derived from a loop exit.
|
||||
(record_nonwrapping_iv, idx_infer_loop_bounds, infer_loop_bounds_from_ref,
|
||||
infer_loop_bounds_from_array, infer_loop_bounds_from_signedness): New
|
||||
functions.
|
||||
(compute_estimated_nb_iterations): Take only realistic bounds into
|
||||
account. Set estimate_state. Use double_ints.
|
||||
(infer_loop_bounds_from_undefined): Call infer_loop_bounds_from_array
|
||||
and infer_loop_bounds_from_signedness. Do not consider basic blocks
|
||||
that do not have to be always executed.
|
||||
(estimate_numbers_of_iterations_loop): Set estimate_state, and use it
|
||||
to determine whether to call infer_loop_bounds_from_undefined
|
||||
and compute_estimated_nb_iterations.
|
||||
(n_of_executions_at_most): Use double_ints.
|
||||
(free_numbers_of_iterations_estimates_loop): Set estimate_state.
|
||||
(substitute_in_loop_info): Do not replace in estimated_nb_iterations.
|
||||
* double-int.c (double_int_to_tree): Improve comment.
|
||||
(double_int_fits_to_tree_p): New function.
|
||||
* double-int.h (double_int_fits_to_tree_p): Declare.
|
||||
* tree-data-ref.c: Include langhooks.h.
|
||||
(estimate_niter_from_size_of_data, estimate_iters_using_array): Removed.
|
||||
(analyze_array_indexes): Do not call estimate_niter_from_size_of_data.
|
||||
(analyze_array): Do not pass estimate_only argument to
|
||||
analyze_array_indexes.
|
||||
(get_number_of_iters_for_loop): Build tree from the stored double_int
|
||||
value.
|
||||
(get_references_in_stmt, find_data_references_in_stmt): New functions.
|
||||
(find_data_references_in_loop): Use find_data_references_in_stmt.
|
||||
* tree-data-ref.h (struct data_ref_loc_d): New.
|
||||
(get_references_in_stmt): Declare.
|
||||
(estimate_iters_using_array): Declaration removed.
|
||||
* cfgloop.h (struct nb_iter_bound): Change type of bound to
|
||||
double_int. Improve comments. Add is_exit and realistic
|
||||
fields.
|
||||
(struct loop): Changed type of estimated_nb_iterations to double_int.
|
||||
Added estimate_state field.
|
||||
(record_estimate): Declaration removed.
|
||||
|
||||
2006-11-12 Zdenek Dvorak <dvorakz@suse.cz>
|
||||
|
||||
* params.c (set_param_value): Initialize the "set" field.
|
||||
|
@ -2080,7 +2080,7 @@ tree-scalar-evolution.o: tree-scalar-evolution.c $(CONFIG_H) $(SYSTEM_H) \
|
||||
tree-data-ref.o: tree-data-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
||||
$(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \
|
||||
$(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \
|
||||
$(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h
|
||||
$(TREE_DATA_REF_H) $(SCEV_H) tree-pass.h tree-chrec.h langhooks.h
|
||||
tree-vect-analyze.o: tree-vect-analyze.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
$(TM_H) $(GGC_H) $(OPTABS_H) $(TREE_H) $(BASIC_BLOCK_H) \
|
||||
$(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) $(CFGLOOP_H) \
|
||||
|
@ -47,12 +47,31 @@ struct lpt_decision
|
||||
|
||||
struct nb_iter_bound
|
||||
{
|
||||
tree bound; /* The constant expression whose value is an upper
|
||||
bound on the number of executions of ... */
|
||||
tree at_stmt; /* ... this statement during one execution of
|
||||
a loop. */
|
||||
/* The statement STMT is executed at most ... */
|
||||
tree stmt;
|
||||
|
||||
/* ... BOUND + 1 times (BOUND must be an unsigned constant).
|
||||
The + 1 is added for the following reasons:
|
||||
|
||||
a) 0 would otherwise be unused, while we would need to care more about
|
||||
overflows (as MAX + 1 is sometimes produced as the estimate on number
|
||||
of executions of STMT).
|
||||
b) it is consistent with the result of number_of_iterations_exit. */
|
||||
double_int bound;
|
||||
|
||||
/* True if the statement will cause the loop to be leaved the (at most)
|
||||
BOUND + 1-st time it is executed, that is, all the statements after it
|
||||
are executed at most BOUND times. */
|
||||
bool is_exit;
|
||||
|
||||
/* True if the bound is "realistic" -- i.e., most likely the loop really has
|
||||
number of iterations close to the bound. Exact bounds (if the number of
|
||||
iterations of a loop is a constant) and bounds derived from the size of
|
||||
data accessed in the loop are considered realistic. */
|
||||
bool realistic;
|
||||
|
||||
/* The next bound in the list. */
|
||||
struct nb_iter_bound *next;
|
||||
/* The next bound in a list. */
|
||||
};
|
||||
|
||||
/* Structure to hold information for each natural loop. */
|
||||
@ -111,9 +130,18 @@ struct loop
|
||||
information in this field. */
|
||||
tree nb_iterations;
|
||||
|
||||
/* An INTEGER_CST estimation of the number of iterations. NULL_TREE
|
||||
if there is no estimation. */
|
||||
tree estimated_nb_iterations;
|
||||
/* An integer estimation of the number of iterations. Estimate_state
|
||||
describes what is the state of the estimation. */
|
||||
enum
|
||||
{
|
||||
/* Estimate was not computed yet. */
|
||||
EST_NOT_COMPUTED,
|
||||
/* Estimate was computed, but we could derive no useful bound. */
|
||||
EST_NOT_AVAILABLE,
|
||||
/* Estimate is ready. */
|
||||
EST_AVAILABLE
|
||||
} estimate_state;
|
||||
double_int estimated_nb_iterations;
|
||||
|
||||
/* Upper bound on number of iterations of a loop. */
|
||||
struct nb_iter_bound *bounds;
|
||||
@ -398,6 +426,5 @@ enum
|
||||
extern void unroll_and_peel_loops (struct loops *, int);
|
||||
extern void doloop_optimize_loops (struct loops *);
|
||||
extern void move_loop_invariants (struct loops *);
|
||||
extern void record_estimate (struct loop *, tree, tree, tree);
|
||||
|
||||
#endif /* GCC_CFGLOOP_H */
|
||||
|
@ -290,7 +290,8 @@ double_int_umod (double_int a, double_int b, unsigned code)
|
||||
return double_int_mod (a, b, true, code);
|
||||
}
|
||||
|
||||
/* Constructs tree in type TYPE from with value given by CST. */
|
||||
/* Constructs tree in type TYPE from with value given by CST. Signedness of CST
|
||||
is assumed to be the same as the signedness of TYPE. */
|
||||
|
||||
tree
|
||||
double_int_to_tree (tree type, double_int cst)
|
||||
@ -300,6 +301,19 @@ double_int_to_tree (tree type, double_int cst)
|
||||
return build_int_cst_wide (type, cst.low, cst.high);
|
||||
}
|
||||
|
||||
/* Returns true if CST fits into range of TYPE. Signedness of CST is assumed
|
||||
to be the same as the signedness of TYPE. */
|
||||
|
||||
bool
|
||||
double_int_fits_to_tree_p (tree type, double_int cst)
|
||||
{
|
||||
double_int ext = double_int_ext (cst,
|
||||
TYPE_PRECISION (type),
|
||||
TYPE_UNSIGNED (type));
|
||||
|
||||
return double_int_equal_p (cst, ext);
|
||||
}
|
||||
|
||||
/* Returns true if CST is negative. Of course, CST is considered to
|
||||
be signed. */
|
||||
|
||||
|
@ -58,7 +58,8 @@ union tree_node;
|
||||
/* Constructors and conversions. */
|
||||
|
||||
union tree_node *double_int_to_tree (union tree_node *, double_int);
|
||||
double_int tree_to_double_int (union tree_node *tree);
|
||||
bool double_int_fits_to_tree_p (union tree_node *, double_int);
|
||||
double_int tree_to_double_int (union tree_node *);
|
||||
|
||||
/* Constructs double_int from integer CST. The bits over the precision of
|
||||
HOST_WIDE_INT are filled with the sign bit. */
|
||||
|
@ -93,6 +93,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
#include "tree-data-ref.h"
|
||||
#include "tree-scalar-evolution.h"
|
||||
#include "tree-pass.h"
|
||||
#include "langhooks.h"
|
||||
|
||||
static struct datadep_stats
|
||||
{
|
||||
@ -888,75 +889,16 @@ dump_ddrs (FILE *file, VEC (ddr_p, heap) *ddrs)
|
||||
|
||||
|
||||
|
||||
/* Estimate the number of iterations from the size of the data and the
|
||||
access functions. */
|
||||
|
||||
static void
|
||||
estimate_niter_from_size_of_data (struct loop *loop,
|
||||
tree opnd0,
|
||||
tree access_fn,
|
||||
tree stmt)
|
||||
{
|
||||
tree estimation = NULL_TREE;
|
||||
tree array_size, data_size, element_size;
|
||||
tree init, step;
|
||||
|
||||
init = initial_condition (access_fn);
|
||||
step = evolution_part_in_loop_num (access_fn, loop->num);
|
||||
|
||||
array_size = TYPE_SIZE (TREE_TYPE (opnd0));
|
||||
element_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (opnd0)));
|
||||
if (array_size == NULL_TREE
|
||||
|| TREE_CODE (array_size) != INTEGER_CST
|
||||
|| TREE_CODE (element_size) != INTEGER_CST)
|
||||
return;
|
||||
|
||||
data_size = fold_build2 (EXACT_DIV_EXPR, integer_type_node,
|
||||
array_size, element_size);
|
||||
|
||||
if (init != NULL_TREE
|
||||
&& step != NULL_TREE
|
||||
&& TREE_CODE (init) == INTEGER_CST
|
||||
&& TREE_CODE (step) == INTEGER_CST)
|
||||
{
|
||||
tree i_plus_s = fold_build2 (PLUS_EXPR, integer_type_node, init, step);
|
||||
tree sign = fold_binary (GT_EXPR, boolean_type_node, i_plus_s, init);
|
||||
|
||||
if (sign == boolean_true_node)
|
||||
estimation = fold_build2 (CEIL_DIV_EXPR, integer_type_node,
|
||||
fold_build2 (MINUS_EXPR, integer_type_node,
|
||||
data_size, init), step);
|
||||
|
||||
/* When the step is negative, as in PR23386: (init = 3, step =
|
||||
0ffffffff, data_size = 100), we have to compute the
|
||||
estimation as ceil_div (init, 0 - step) + 1. */
|
||||
else if (sign == boolean_false_node)
|
||||
estimation =
|
||||
fold_build2 (PLUS_EXPR, integer_type_node,
|
||||
fold_build2 (CEIL_DIV_EXPR, integer_type_node,
|
||||
init,
|
||||
fold_build2 (MINUS_EXPR, unsigned_type_node,
|
||||
integer_zero_node, step)),
|
||||
integer_one_node);
|
||||
|
||||
if (estimation)
|
||||
record_estimate (loop, estimation, boolean_true_node, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Given an ARRAY_REF node REF, records its access functions.
|
||||
Example: given A[i][3], record in ACCESS_FNS the opnd1 function,
|
||||
i.e. the constant "3", then recursively call the function on opnd0,
|
||||
i.e. the ARRAY_REF "A[i]".
|
||||
If ESTIMATE_ONLY is true, we just set the estimated number of loop
|
||||
iterations, we don't store the access function.
|
||||
The function returns the base name: "A". */
|
||||
|
||||
static tree
|
||||
analyze_array_indexes (struct loop *loop,
|
||||
VEC(tree,heap) **access_fns,
|
||||
tree ref, tree stmt,
|
||||
bool estimate_only)
|
||||
tree ref, tree stmt)
|
||||
{
|
||||
tree opnd0, opnd1;
|
||||
tree access_fn;
|
||||
@ -971,32 +913,17 @@ analyze_array_indexes (struct loop *loop,
|
||||
access_fn = instantiate_parameters
|
||||
(loop, analyze_scalar_evolution (loop, opnd1));
|
||||
|
||||
if (estimate_only
|
||||
&& chrec_contains_undetermined (loop->estimated_nb_iterations))
|
||||
estimate_niter_from_size_of_data (loop, opnd0, access_fn, stmt);
|
||||
|
||||
if (!estimate_only)
|
||||
VEC_safe_push (tree, heap, *access_fns, access_fn);
|
||||
VEC_safe_push (tree, heap, *access_fns, access_fn);
|
||||
|
||||
/* Recursively record other array access functions. */
|
||||
if (TREE_CODE (opnd0) == ARRAY_REF)
|
||||
return analyze_array_indexes (loop, access_fns, opnd0, stmt, estimate_only);
|
||||
return analyze_array_indexes (loop, access_fns, opnd0, stmt);
|
||||
|
||||
/* Return the base name of the data access. */
|
||||
else
|
||||
return opnd0;
|
||||
}
|
||||
|
||||
/* For an array reference REF contained in STMT, attempt to bound the
|
||||
number of iterations in the loop containing STMT */
|
||||
|
||||
void
|
||||
estimate_iters_using_array (tree stmt, tree ref)
|
||||
{
|
||||
analyze_array_indexes (loop_containing_stmt (stmt), NULL, ref, stmt,
|
||||
true);
|
||||
}
|
||||
|
||||
/* For a data reference REF contained in the statement STMT, initialize
|
||||
a DATA_REFERENCE structure, and return it. IS_READ flag has to be
|
||||
set to true when REF is in the right hand side of an
|
||||
@ -1022,7 +949,7 @@ analyze_array (tree stmt, tree ref, bool is_read)
|
||||
DR_REF (res) = ref;
|
||||
acc_fns = VEC_alloc (tree, heap, 3);
|
||||
DR_BASE_OBJECT (res) = analyze_array_indexes
|
||||
(loop_containing_stmt (stmt), &acc_fns, ref, stmt, false);
|
||||
(loop_containing_stmt (stmt), &acc_fns, ref, stmt);
|
||||
DR_TYPE (res) = ARRAY_REF_TYPE;
|
||||
DR_SET_ACCESS_FNS (res, acc_fns);
|
||||
DR_IS_READ (res) = is_read;
|
||||
@ -2377,13 +2304,20 @@ analyze_ziv_subscript (tree chrec_a,
|
||||
static tree
|
||||
get_number_of_iters_for_loop (int loopnum)
|
||||
{
|
||||
tree numiter = number_of_iterations_in_loop (current_loops->parray[loopnum]);
|
||||
struct loop *loop = current_loops->parray[loopnum];
|
||||
tree numiter = number_of_iterations_in_loop (loop);
|
||||
|
||||
if (TREE_CODE (numiter) != INTEGER_CST)
|
||||
numiter = current_loops->parray[loopnum]->estimated_nb_iterations;
|
||||
if (chrec_contains_undetermined (numiter))
|
||||
return NULL_TREE;
|
||||
return numiter;
|
||||
if (TREE_CODE (numiter) == INTEGER_CST)
|
||||
return numiter;
|
||||
|
||||
if (loop->estimate_state == EST_AVAILABLE)
|
||||
{
|
||||
tree type = lang_hooks.types.type_for_size (INT_TYPE_SIZE, true);
|
||||
if (double_int_fits_to_tree_p (type, loop->estimated_nb_iterations))
|
||||
return double_int_to_tree (type, loop->estimated_nb_iterations);
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Analyze a SIV (Single Index Variable) subscript where CHREC_A is a
|
||||
@ -4060,6 +3994,105 @@ compute_all_dependences (VEC (data_reference_p, heap) *datarefs,
|
||||
}
|
||||
}
|
||||
|
||||
/* Stores the locations of memory references in STMT to REFERENCES. Returns
|
||||
true if STMT clobbers memory, false otherwise. */
|
||||
|
||||
bool
|
||||
get_references_in_stmt (tree stmt, VEC (data_ref_loc, heap) **references)
|
||||
{
|
||||
bool clobbers_memory = false;
|
||||
data_ref_loc *ref;
|
||||
tree *op0, *op1, args, call;
|
||||
|
||||
*references = NULL;
|
||||
|
||||
/* ASM_EXPR and CALL_EXPR may embed arbitrary side effects.
|
||||
Calls have side-effects, except those to const or pure
|
||||
functions. */
|
||||
call = get_call_expr_in (stmt);
|
||||
if ((call
|
||||
&& !(call_expr_flags (call) & (ECF_CONST | ECF_PURE)))
|
||||
|| (TREE_CODE (stmt) == ASM_EXPR
|
||||
&& ASM_VOLATILE_P (stmt)))
|
||||
clobbers_memory = true;
|
||||
|
||||
if (ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
|
||||
return clobbers_memory;
|
||||
|
||||
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
{
|
||||
op0 = &TREE_OPERAND (stmt, 0);
|
||||
op1 = &TREE_OPERAND (stmt, 1);
|
||||
|
||||
if (DECL_P (*op1)
|
||||
|| REFERENCE_CLASS_P (*op1))
|
||||
{
|
||||
ref = VEC_safe_push (data_ref_loc, heap, *references, NULL);
|
||||
ref->pos = op1;
|
||||
ref->is_read = true;
|
||||
}
|
||||
|
||||
if (DECL_P (*op0)
|
||||
|| REFERENCE_CLASS_P (*op0))
|
||||
{
|
||||
ref = VEC_safe_push (data_ref_loc, heap, *references, NULL);
|
||||
ref->pos = op0;
|
||||
ref->is_read = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (call)
|
||||
{
|
||||
for (args = TREE_OPERAND (call, 1); args; args = TREE_CHAIN (args))
|
||||
{
|
||||
op0 = &TREE_VALUE (args);
|
||||
if (DECL_P (*op0)
|
||||
|| REFERENCE_CLASS_P (*op0))
|
||||
{
|
||||
ref = VEC_safe_push (data_ref_loc, heap, *references, NULL);
|
||||
ref->pos = op0;
|
||||
ref->is_read = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clobbers_memory;
|
||||
}
|
||||
|
||||
/* Stores the data references in STMT to DATAREFS. If there is an unanalyzable
|
||||
reference, returns false, otherwise returns true. */
|
||||
|
||||
static bool
|
||||
find_data_references_in_stmt (tree stmt,
|
||||
VEC (data_reference_p, heap) **datarefs)
|
||||
{
|
||||
unsigned i;
|
||||
VEC (data_ref_loc, heap) *references;
|
||||
data_ref_loc *ref;
|
||||
bool ret = true;
|
||||
data_reference_p dr;
|
||||
|
||||
if (get_references_in_stmt (stmt, &references))
|
||||
{
|
||||
VEC_free (data_ref_loc, heap, references);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; VEC_iterate (data_ref_loc, references, i, ref); i++)
|
||||
{
|
||||
dr = create_data_ref (*ref->pos, stmt, ref->is_read);
|
||||
if (dr)
|
||||
VEC_safe_push (data_reference_p, heap, *datarefs, dr);
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VEC_free (data_ref_loc, heap, references);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Search the data references in LOOP, and record the information into
|
||||
DATAREFS. Returns chrec_dont_know when failing to analyze a
|
||||
difficult case, returns NULL_TREE otherwise.
|
||||
@ -4074,118 +4107,41 @@ find_data_references_in_loop (struct loop *loop,
|
||||
basic_block bb, *bbs;
|
||||
unsigned int i;
|
||||
block_stmt_iterator bsi;
|
||||
struct data_reference *dr;
|
||||
|
||||
bbs = get_loop_body (loop);
|
||||
loop->parallel_p = true;
|
||||
|
||||
for (i = 0; i < loop->num_nodes; i++)
|
||||
{
|
||||
bb = bbs[i];
|
||||
|
||||
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
||||
{
|
||||
{
|
||||
tree stmt = bsi_stmt (bsi);
|
||||
|
||||
/* ASM_EXPR and CALL_EXPR may embed arbitrary side effects.
|
||||
Calls have side-effects, except those to const or pure
|
||||
functions. */
|
||||
if ((TREE_CODE (stmt) == CALL_EXPR
|
||||
&& !(call_expr_flags (stmt) & (ECF_CONST | ECF_PURE)))
|
||||
|| (TREE_CODE (stmt) == ASM_EXPR
|
||||
&& ASM_VOLATILE_P (stmt)))
|
||||
goto insert_dont_know_node;
|
||||
|
||||
if (ZERO_SSA_OPERANDS (stmt, SSA_OP_ALL_VIRTUALS))
|
||||
continue;
|
||||
|
||||
switch (TREE_CODE (stmt))
|
||||
if (!find_data_references_in_stmt (stmt, datarefs))
|
||||
{
|
||||
case MODIFY_EXPR:
|
||||
{
|
||||
bool one_inserted = false;
|
||||
tree opnd0 = TREE_OPERAND (stmt, 0);
|
||||
tree opnd1 = TREE_OPERAND (stmt, 1);
|
||||
|
||||
if (TREE_CODE (opnd0) == ARRAY_REF
|
||||
|| TREE_CODE (opnd0) == INDIRECT_REF
|
||||
|| TREE_CODE (opnd0) == COMPONENT_REF)
|
||||
{
|
||||
dr = create_data_ref (opnd0, stmt, false);
|
||||
if (dr)
|
||||
{
|
||||
VEC_safe_push (data_reference_p, heap, *datarefs, dr);
|
||||
one_inserted = true;
|
||||
}
|
||||
}
|
||||
struct data_reference *res;
|
||||
res = XNEW (struct data_reference);
|
||||
DR_STMT (res) = NULL_TREE;
|
||||
DR_REF (res) = NULL_TREE;
|
||||
DR_BASE_OBJECT (res) = NULL;
|
||||
DR_TYPE (res) = ARRAY_REF_TYPE;
|
||||
DR_SET_ACCESS_FNS (res, NULL);
|
||||
DR_BASE_OBJECT (res) = NULL;
|
||||
DR_IS_READ (res) = false;
|
||||
DR_BASE_ADDRESS (res) = NULL_TREE;
|
||||
DR_OFFSET (res) = NULL_TREE;
|
||||
DR_INIT (res) = NULL_TREE;
|
||||
DR_STEP (res) = NULL_TREE;
|
||||
DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
|
||||
DR_MEMTAG (res) = NULL_TREE;
|
||||
DR_PTR_INFO (res) = NULL;
|
||||
loop->parallel_p = false;
|
||||
VEC_safe_push (data_reference_p, heap, *datarefs, res);
|
||||
|
||||
if (TREE_CODE (opnd1) == ARRAY_REF
|
||||
|| TREE_CODE (opnd1) == INDIRECT_REF
|
||||
|| TREE_CODE (opnd1) == COMPONENT_REF)
|
||||
{
|
||||
dr = create_data_ref (opnd1, stmt, true);
|
||||
if (dr)
|
||||
{
|
||||
VEC_safe_push (data_reference_p, heap, *datarefs, dr);
|
||||
one_inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!one_inserted)
|
||||
goto insert_dont_know_node;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CALL_EXPR:
|
||||
{
|
||||
tree args;
|
||||
bool one_inserted = false;
|
||||
|
||||
for (args = TREE_OPERAND (stmt, 1); args;
|
||||
args = TREE_CHAIN (args))
|
||||
if (TREE_CODE (TREE_VALUE (args)) == ARRAY_REF
|
||||
|| TREE_CODE (TREE_VALUE (args)) == INDIRECT_REF
|
||||
|| TREE_CODE (TREE_VALUE (args)) == COMPONENT_REF)
|
||||
{
|
||||
dr = create_data_ref (TREE_VALUE (args), stmt, true);
|
||||
if (dr)
|
||||
{
|
||||
VEC_safe_push (data_reference_p, heap, *datarefs, dr);
|
||||
one_inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!one_inserted)
|
||||
goto insert_dont_know_node;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
struct data_reference *res;
|
||||
|
||||
insert_dont_know_node:;
|
||||
res = XNEW (struct data_reference);
|
||||
DR_STMT (res) = NULL_TREE;
|
||||
DR_REF (res) = NULL_TREE;
|
||||
DR_BASE_OBJECT (res) = NULL;
|
||||
DR_TYPE (res) = ARRAY_REF_TYPE;
|
||||
DR_SET_ACCESS_FNS (res, NULL);
|
||||
DR_BASE_OBJECT (res) = NULL;
|
||||
DR_IS_READ (res) = false;
|
||||
DR_BASE_ADDRESS (res) = NULL_TREE;
|
||||
DR_OFFSET (res) = NULL_TREE;
|
||||
DR_INIT (res) = NULL_TREE;
|
||||
DR_STEP (res) = NULL_TREE;
|
||||
DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
|
||||
DR_MEMTAG (res) = NULL_TREE;
|
||||
DR_PTR_INFO (res) = NULL;
|
||||
VEC_safe_push (data_reference_p, heap, *datarefs, res);
|
||||
|
||||
free (bbs);
|
||||
return chrec_dont_know;
|
||||
}
|
||||
free (bbs);
|
||||
return chrec_dont_know;
|
||||
}
|
||||
|
||||
/* When there are no defs in the loop, the loop is parallel. */
|
||||
@ -4193,7 +4149,6 @@ find_data_references_in_loop (struct loop *loop,
|
||||
loop->parallel_p = false;
|
||||
}
|
||||
}
|
||||
|
||||
free (bbs);
|
||||
|
||||
return NULL_TREE;
|
||||
|
@ -269,6 +269,21 @@ DEF_VEC_ALLOC_P(ddr_p,heap);
|
||||
|
||||
|
||||
|
||||
/* Describes a location of a memory reference. */
|
||||
|
||||
typedef struct data_ref_loc_d
|
||||
{
|
||||
/* Position of the memory reference. */
|
||||
tree *pos;
|
||||
|
||||
/* True if the memory reference is read. */
|
||||
bool is_read;
|
||||
} data_ref_loc;
|
||||
|
||||
DEF_VEC_O (data_ref_loc);
|
||||
DEF_VEC_ALLOC_O (data_ref_loc, heap);
|
||||
|
||||
bool get_references_in_stmt (tree, VEC (data_ref_loc, heap) **);
|
||||
extern tree find_data_references_in_loop (struct loop *,
|
||||
VEC (data_reference_p, heap) **);
|
||||
extern void compute_data_dependences_for_loop (struct loop *, bool,
|
||||
@ -292,7 +307,6 @@ extern void free_dependence_relation (struct data_dependence_relation *);
|
||||
extern void free_dependence_relations (VEC (ddr_p, heap) *);
|
||||
extern void free_data_refs (VEC (data_reference_p, heap) *);
|
||||
extern struct data_reference *analyze_array (tree, tree, bool);
|
||||
extern void estimate_iters_using_array (tree, tree);
|
||||
|
||||
|
||||
/* Return the index of the variable VAR in the LOOP_NEST array. */
|
||||
|
@ -1533,6 +1533,7 @@ derive_constant_upper_bound (tree val, tree additional)
|
||||
tree type = TREE_TYPE (val);
|
||||
tree op0, op1, subtype, maxt;
|
||||
double_int bnd, max, mmax, cst;
|
||||
tree stmt;
|
||||
|
||||
if (INTEGRAL_TYPE_P (type))
|
||||
maxt = TYPE_MAX_VALUE (type);
|
||||
@ -1647,39 +1648,113 @@ derive_constant_upper_bound (tree val, tree additional)
|
||||
bnd = derive_constant_upper_bound (op0, additional);
|
||||
return double_int_udiv (bnd, tree_to_double_int (op1), FLOOR_DIV_EXPR);
|
||||
|
||||
case BIT_AND_EXPR:
|
||||
op1 = TREE_OPERAND (val, 1);
|
||||
if (TREE_CODE (op1) != INTEGER_CST
|
||||
|| tree_int_cst_sign_bit (op1))
|
||||
return max;
|
||||
return tree_to_double_int (op1);
|
||||
|
||||
case SSA_NAME:
|
||||
stmt = SSA_NAME_DEF_STMT (val);
|
||||
if (TREE_CODE (stmt) != MODIFY_EXPR
|
||||
|| TREE_OPERAND (stmt, 0) != val)
|
||||
return max;
|
||||
return derive_constant_upper_bound (TREE_OPERAND (stmt, 1), additional);
|
||||
|
||||
default:
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
||||
/* Records that AT_STMT is executed at most BOUND times in LOOP. The
|
||||
additional condition ADDITIONAL is recorded with the bound. */
|
||||
/* Records that AT_STMT is executed at most BOUND + 1 times in LOOP. The
|
||||
additional condition ADDITIONAL is recorded with the bound. IS_EXIT
|
||||
is true if the loop is exited immediately after STMT, and this exit
|
||||
is taken at last when the STMT is executed BOUND + 1 times.
|
||||
REALISTIC is true if the estimate comes from a reliable source
|
||||
(number of iterations analysis, or size of data accessed in the loop). */
|
||||
|
||||
void
|
||||
record_estimate (struct loop *loop, tree bound, tree additional, tree at_stmt)
|
||||
static void
|
||||
record_estimate (struct loop *loop, tree bound, tree additional, tree at_stmt,
|
||||
bool is_exit, bool realistic)
|
||||
{
|
||||
struct nb_iter_bound *elt = xmalloc (sizeof (struct nb_iter_bound));
|
||||
double_int i_bound = derive_constant_upper_bound (bound, additional);
|
||||
tree c_bound = double_int_to_tree (unsigned_type_for (TREE_TYPE (bound)),
|
||||
i_bound);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Statements after ");
|
||||
fprintf (dump_file, "Statement %s", is_exit ? "(exit)" : "");
|
||||
print_generic_expr (dump_file, at_stmt, TDF_SLIM);
|
||||
fprintf (dump_file, " are executed at most ");
|
||||
fprintf (dump_file, " is executed at most ");
|
||||
print_generic_expr (dump_file, bound, TDF_SLIM);
|
||||
fprintf (dump_file, " (bounded by ");
|
||||
print_generic_expr (dump_file, c_bound, TDF_SLIM);
|
||||
fprintf (dump_file, ") times in loop %d.\n", loop->num);
|
||||
dump_double_int (dump_file, i_bound, true);
|
||||
fprintf (dump_file, ") + 1 times in loop %d.\n", loop->num);
|
||||
}
|
||||
|
||||
elt->bound = c_bound;
|
||||
elt->at_stmt = at_stmt;
|
||||
elt->bound = i_bound;
|
||||
elt->stmt = at_stmt;
|
||||
elt->is_exit = is_exit;
|
||||
elt->realistic = realistic && TREE_CODE (bound) == INTEGER_CST;
|
||||
elt->next = loop->bounds;
|
||||
loop->bounds = elt;
|
||||
}
|
||||
|
||||
/* Record the estimate on number of iterations of LOOP based on the fact that
|
||||
the induction variable BASE + STEP * i evaluated in STMT does not wrap and
|
||||
its values belong to the range <LOW, HIGH>. DATA_SIZE_BOUNDS_P is true if
|
||||
LOW and HIGH are derived from the size of data. */
|
||||
|
||||
static void
|
||||
record_nonwrapping_iv (struct loop *loop, tree base, tree step, tree stmt,
|
||||
tree low, tree high, bool data_size_bounds_p)
|
||||
{
|
||||
tree niter_bound, extreme, delta;
|
||||
tree type = TREE_TYPE (base), unsigned_type;
|
||||
|
||||
if (TREE_CODE (step) != INTEGER_CST || zero_p (step))
|
||||
return;
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Induction variable (");
|
||||
print_generic_expr (dump_file, TREE_TYPE (base), TDF_SLIM);
|
||||
fprintf (dump_file, ") ");
|
||||
print_generic_expr (dump_file, base, TDF_SLIM);
|
||||
fprintf (dump_file, " + ");
|
||||
print_generic_expr (dump_file, step, TDF_SLIM);
|
||||
fprintf (dump_file, " * iteration does not wrap in statement ");
|
||||
print_generic_expr (dump_file, stmt, TDF_SLIM);
|
||||
fprintf (dump_file, " in loop %d.\n", loop->num);
|
||||
}
|
||||
|
||||
unsigned_type = unsigned_type_for (type);
|
||||
base = fold_convert (unsigned_type, base);
|
||||
step = fold_convert (unsigned_type, step);
|
||||
|
||||
if (tree_int_cst_sign_bit (step))
|
||||
{
|
||||
extreme = fold_convert (unsigned_type, low);
|
||||
if (TREE_CODE (base) != INTEGER_CST)
|
||||
base = fold_convert (unsigned_type, high);
|
||||
delta = fold_build2 (MINUS_EXPR, unsigned_type, base, extreme);
|
||||
step = fold_build1 (NEGATE_EXPR, unsigned_type, step);
|
||||
}
|
||||
else
|
||||
{
|
||||
extreme = fold_convert (unsigned_type, high);
|
||||
if (TREE_CODE (base) != INTEGER_CST)
|
||||
base = fold_convert (unsigned_type, low);
|
||||
delta = fold_build2 (MINUS_EXPR, unsigned_type, extreme, base);
|
||||
}
|
||||
|
||||
/* STMT is executed at most NITER_BOUND + 1 times, since otherwise the value
|
||||
would get out of the range. */
|
||||
niter_bound = fold_build2 (FLOOR_DIV_EXPR, unsigned_type, delta, step);
|
||||
record_estimate (loop, niter_bound, boolean_true_node, stmt,
|
||||
false, data_size_bounds_p);
|
||||
}
|
||||
|
||||
/* Initialize LOOP->ESTIMATED_NB_ITERATIONS with the lowest safe
|
||||
approximation of the number of iterations for LOOP. */
|
||||
|
||||
@ -1687,20 +1762,184 @@ static void
|
||||
compute_estimated_nb_iterations (struct loop *loop)
|
||||
{
|
||||
struct nb_iter_bound *bound;
|
||||
|
||||
|
||||
gcc_assert (loop->estimate_state == EST_NOT_AVAILABLE);
|
||||
|
||||
for (bound = loop->bounds; bound; bound = bound->next)
|
||||
{
|
||||
if (TREE_CODE (bound->bound) != INTEGER_CST)
|
||||
if (!bound->realistic)
|
||||
continue;
|
||||
|
||||
/* Update only when there is no previous estimation, or when the current
|
||||
estimation is smaller. */
|
||||
if (chrec_contains_undetermined (loop->estimated_nb_iterations)
|
||||
|| tree_int_cst_lt (bound->bound, loop->estimated_nb_iterations))
|
||||
loop->estimated_nb_iterations = bound->bound;
|
||||
if (loop->estimate_state == EST_NOT_AVAILABLE
|
||||
|| double_int_ucmp (bound->bound, loop->estimated_nb_iterations) < 0)
|
||||
{
|
||||
loop->estimate_state = EST_AVAILABLE;
|
||||
loop->estimated_nb_iterations = bound->bound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine information about number of iterations a LOOP from the index
|
||||
IDX of a data reference accessed in STMT. Callback for for_each_index. */
|
||||
|
||||
struct ilb_data
|
||||
{
|
||||
struct loop *loop;
|
||||
tree stmt;
|
||||
};
|
||||
|
||||
static bool
|
||||
idx_infer_loop_bounds (tree base, tree *idx, void *dta)
|
||||
{
|
||||
struct ilb_data *data = dta;
|
||||
tree ev, init, step;
|
||||
tree low, high, type, next;
|
||||
bool sign;
|
||||
struct loop *loop = data->loop;
|
||||
|
||||
if (TREE_CODE (base) != ARRAY_REF)
|
||||
return true;
|
||||
|
||||
ev = instantiate_parameters (loop, analyze_scalar_evolution (loop, *idx));
|
||||
init = initial_condition (ev);
|
||||
step = evolution_part_in_loop_num (ev, loop->num);
|
||||
|
||||
if (!init
|
||||
|| !step
|
||||
|| TREE_CODE (step) != INTEGER_CST
|
||||
|| zero_p (step)
|
||||
|| tree_contains_chrecs (init, NULL)
|
||||
|| chrec_contains_symbols_defined_in_loop (init, loop->num))
|
||||
return true;
|
||||
|
||||
low = array_ref_low_bound (base);
|
||||
high = array_ref_up_bound (base);
|
||||
|
||||
/* The case of nonconstant bounds could be handled, but it would be
|
||||
complicated. */
|
||||
if (TREE_CODE (low) != INTEGER_CST
|
||||
|| !high
|
||||
|| TREE_CODE (high) != INTEGER_CST)
|
||||
return true;
|
||||
sign = tree_int_cst_sign_bit (step);
|
||||
type = TREE_TYPE (step);
|
||||
|
||||
/* In case the relevant bound of the array does not fit in type, or
|
||||
it does, but bound + step (in type) still belongs into the range of the
|
||||
array, the index may wrap and still stay within the range of the array
|
||||
(consider e.g. if the array is indexed by the full range of
|
||||
unsigned char).
|
||||
|
||||
To make things simpler, we require both bounds to fit into type, although
|
||||
there are cases where this would not be strightly necessary. */
|
||||
if (!int_fits_type_p (high, type)
|
||||
|| !int_fits_type_p (low, type))
|
||||
return true;
|
||||
low = fold_convert (type, low);
|
||||
high = fold_convert (type, high);
|
||||
|
||||
if (sign)
|
||||
next = fold_binary (PLUS_EXPR, type, low, step);
|
||||
else
|
||||
next = fold_binary (PLUS_EXPR, type, high, step);
|
||||
|
||||
if (tree_int_cst_compare (low, next) <= 0
|
||||
&& tree_int_cst_compare (next, high) <= 0)
|
||||
return true;
|
||||
|
||||
record_nonwrapping_iv (loop, init, step, data->stmt, low, high, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Determine information about number of iterations a LOOP from the bounds
|
||||
of arrays in the data reference REF accessed in STMT. */
|
||||
|
||||
static void
|
||||
infer_loop_bounds_from_ref (struct loop *loop, tree stmt, tree ref)
|
||||
{
|
||||
struct ilb_data data;
|
||||
|
||||
data.loop = loop;
|
||||
data.stmt = stmt;
|
||||
for_each_index (&ref, idx_infer_loop_bounds, &data);
|
||||
}
|
||||
|
||||
/* Determine information about number of iterations of a LOOP from the way
|
||||
arrays are used in STMT. */
|
||||
|
||||
static void
|
||||
infer_loop_bounds_from_array (struct loop *loop, tree stmt)
|
||||
{
|
||||
tree call;
|
||||
|
||||
if (TREE_CODE (stmt) == MODIFY_EXPR)
|
||||
{
|
||||
tree op0 = TREE_OPERAND (stmt, 0);
|
||||
tree op1 = TREE_OPERAND (stmt, 1);
|
||||
|
||||
/* For each memory access, analyze its access function
|
||||
and record a bound on the loop iteration domain. */
|
||||
if (REFERENCE_CLASS_P (op0))
|
||||
infer_loop_bounds_from_ref (loop, stmt, op0);
|
||||
|
||||
if (REFERENCE_CLASS_P (op1))
|
||||
infer_loop_bounds_from_ref (loop, stmt, op1);
|
||||
}
|
||||
|
||||
|
||||
call = get_call_expr_in (stmt);
|
||||
if (call)
|
||||
{
|
||||
tree args;
|
||||
|
||||
for (args = TREE_OPERAND (call, 1); args; args = TREE_CHAIN (args))
|
||||
if (REFERENCE_CLASS_P (TREE_VALUE (args)))
|
||||
infer_loop_bounds_from_ref (loop, stmt, TREE_VALUE (args));
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine information about number of iterations of a LOOP from the fact
|
||||
that signed arithmetics in STMT does not overflow. */
|
||||
|
||||
static void
|
||||
infer_loop_bounds_from_signedness (struct loop *loop, tree stmt)
|
||||
{
|
||||
tree def, base, step, scev, type, low, high;
|
||||
|
||||
if (flag_wrapv || TREE_CODE (stmt) != MODIFY_EXPR)
|
||||
return;
|
||||
|
||||
def = TREE_OPERAND (stmt, 0);
|
||||
|
||||
if (TREE_CODE (def) != SSA_NAME)
|
||||
return;
|
||||
|
||||
type = TREE_TYPE (def);
|
||||
if (!INTEGRAL_TYPE_P (type)
|
||||
|| TYPE_UNSIGNED (type))
|
||||
return;
|
||||
|
||||
scev = instantiate_parameters (loop, analyze_scalar_evolution (loop, def));
|
||||
if (chrec_contains_undetermined (scev))
|
||||
return;
|
||||
|
||||
base = initial_condition_in_loop_num (scev, loop->num);
|
||||
step = evolution_part_in_loop_num (scev, loop->num);
|
||||
|
||||
if (!base || !step
|
||||
|| TREE_CODE (step) != INTEGER_CST
|
||||
|| tree_contains_chrecs (base, NULL)
|
||||
|| chrec_contains_symbols_defined_in_loop (base, loop->num))
|
||||
return;
|
||||
|
||||
low = lower_bound_in_type (type, type);
|
||||
high = upper_bound_in_type (type, type);
|
||||
|
||||
record_nonwrapping_iv (loop, base, step, stmt, low, high, false);
|
||||
}
|
||||
|
||||
/* The following analyzers are extracting informations on the bounds
|
||||
of LOOP from the following undefined behaviors:
|
||||
|
||||
@ -1714,8 +1953,9 @@ static void
|
||||
infer_loop_bounds_from_undefined (struct loop *loop)
|
||||
{
|
||||
unsigned i;
|
||||
basic_block bb, *bbs;
|
||||
basic_block *bbs;
|
||||
block_stmt_iterator bsi;
|
||||
basic_block bb;
|
||||
|
||||
bbs = get_loop_body (loop);
|
||||
|
||||
@ -1723,95 +1963,21 @@ infer_loop_bounds_from_undefined (struct loop *loop)
|
||||
{
|
||||
bb = bbs[i];
|
||||
|
||||
/* If BB is not executed in each iteration of the loop, we cannot
|
||||
use it to infer any information about # of iterations of the loop. */
|
||||
if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb))
|
||||
continue;
|
||||
|
||||
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
|
||||
{
|
||||
{
|
||||
tree stmt = bsi_stmt (bsi);
|
||||
|
||||
switch (TREE_CODE (stmt))
|
||||
{
|
||||
case MODIFY_EXPR:
|
||||
{
|
||||
tree op0 = TREE_OPERAND (stmt, 0);
|
||||
tree op1 = TREE_OPERAND (stmt, 1);
|
||||
infer_loop_bounds_from_array (loop, stmt);
|
||||
infer_loop_bounds_from_signedness (loop, stmt);
|
||||
}
|
||||
|
||||
/* For each array access, analyze its access function
|
||||
and record a bound on the loop iteration domain. */
|
||||
if (TREE_CODE (op1) == ARRAY_REF
|
||||
&& !array_ref_contains_indirect_ref (op1))
|
||||
estimate_iters_using_array (stmt, op1);
|
||||
|
||||
if (TREE_CODE (op0) == ARRAY_REF
|
||||
&& !array_ref_contains_indirect_ref (op0))
|
||||
estimate_iters_using_array (stmt, op0);
|
||||
|
||||
/* For each signed type variable in LOOP, analyze its
|
||||
scalar evolution and record a bound of the loop
|
||||
based on the type's ranges. */
|
||||
else if (!flag_wrapv && TREE_CODE (op0) == SSA_NAME)
|
||||
{
|
||||
tree init, step, diff, estimation;
|
||||
tree scev = instantiate_parameters
|
||||
(loop, analyze_scalar_evolution (loop, op0));
|
||||
tree type = chrec_type (scev);
|
||||
|
||||
if (chrec_contains_undetermined (scev)
|
||||
|| TYPE_UNSIGNED (type))
|
||||
break;
|
||||
|
||||
init = initial_condition_in_loop_num (scev, loop->num);
|
||||
step = evolution_part_in_loop_num (scev, loop->num);
|
||||
|
||||
if (init == NULL_TREE
|
||||
|| step == NULL_TREE
|
||||
|| TREE_CODE (init) != INTEGER_CST
|
||||
|| TREE_CODE (step) != INTEGER_CST
|
||||
|| TYPE_MIN_VALUE (type) == NULL_TREE
|
||||
|| TYPE_MAX_VALUE (type) == NULL_TREE)
|
||||
break;
|
||||
|
||||
if (integer_nonzerop (step))
|
||||
{
|
||||
tree utype;
|
||||
|
||||
if (tree_int_cst_lt (step, integer_zero_node))
|
||||
diff = fold_build2 (MINUS_EXPR, type, init,
|
||||
TYPE_MIN_VALUE (type));
|
||||
else
|
||||
diff = fold_build2 (MINUS_EXPR, type,
|
||||
TYPE_MAX_VALUE (type), init);
|
||||
|
||||
utype = unsigned_type_for (type);
|
||||
estimation = fold_build2 (CEIL_DIV_EXPR, type, diff,
|
||||
step);
|
||||
record_estimate (loop,
|
||||
fold_convert (utype, estimation),
|
||||
boolean_true_node, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CALL_EXPR:
|
||||
{
|
||||
tree args;
|
||||
|
||||
for (args = TREE_OPERAND (stmt, 1); args;
|
||||
args = TREE_CHAIN (args))
|
||||
if (TREE_CODE (TREE_VALUE (args)) == ARRAY_REF
|
||||
&& !array_ref_contains_indirect_ref (TREE_VALUE (args)))
|
||||
estimate_iters_using_array (stmt, TREE_VALUE (args));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compute_estimated_nb_iterations (loop);
|
||||
free (bbs);
|
||||
}
|
||||
|
||||
@ -1826,13 +1992,9 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
|
||||
struct tree_niter_desc niter_desc;
|
||||
|
||||
/* Give up if we already have tried to compute an estimation. */
|
||||
if (loop->estimated_nb_iterations == chrec_dont_know
|
||||
/* Or when we already have an estimation. */
|
||||
|| (loop->estimated_nb_iterations != NULL_TREE
|
||||
&& TREE_CODE (loop->estimated_nb_iterations) == INTEGER_CST))
|
||||
if (loop->estimate_state != EST_NOT_COMPUTED)
|
||||
return;
|
||||
else
|
||||
loop->estimated_nb_iterations = chrec_dont_know;
|
||||
loop->estimate_state = EST_NOT_AVAILABLE;
|
||||
|
||||
exits = get_loop_exit_edges (loop, &n_exits);
|
||||
for (i = 0; i < n_exits; i++)
|
||||
@ -1842,19 +2004,19 @@ estimate_numbers_of_iterations_loop (struct loop *loop)
|
||||
|
||||
niter = niter_desc.niter;
|
||||
type = TREE_TYPE (niter);
|
||||
if (!zero_p (niter_desc.may_be_zero)
|
||||
&& !nonzero_p (niter_desc.may_be_zero))
|
||||
if (TREE_CODE (niter_desc.may_be_zero) != INTEGER_CST)
|
||||
niter = build3 (COND_EXPR, type, niter_desc.may_be_zero,
|
||||
build_int_cst (type, 0),
|
||||
niter);
|
||||
record_estimate (loop, niter,
|
||||
niter_desc.additional_info,
|
||||
last_stmt (exits[i]->src));
|
||||
last_stmt (exits[i]->src),
|
||||
true, true);
|
||||
}
|
||||
free (exits);
|
||||
|
||||
if (chrec_contains_undetermined (loop->estimated_nb_iterations))
|
||||
infer_loop_bounds_from_undefined (loop);
|
||||
infer_loop_bounds_from_undefined (loop);
|
||||
compute_estimated_nb_iterations (loop);
|
||||
}
|
||||
|
||||
/* Records estimates on numbers of iterations of LOOPS. */
|
||||
@ -1899,40 +2061,67 @@ stmt_dominates_stmt_p (tree s1, tree s2)
|
||||
}
|
||||
|
||||
/* Returns true when we can prove that the number of executions of
|
||||
STMT in the loop is at most NITER, according to the fact
|
||||
that the statement NITER_BOUND->at_stmt is executed at most
|
||||
NITER_BOUND->bound times. */
|
||||
STMT in the loop is at most NITER, according to the bound on
|
||||
the number of executions of the statement NITER_BOUND->stmt recorded in
|
||||
NITER_BOUND. If STMT is NULL, we must prove this bound for all
|
||||
statements in the loop. */
|
||||
|
||||
static bool
|
||||
n_of_executions_at_most (tree stmt,
|
||||
struct nb_iter_bound *niter_bound,
|
||||
tree niter)
|
||||
{
|
||||
tree cond;
|
||||
tree bound = niter_bound->bound;
|
||||
tree bound_type = TREE_TYPE (bound);
|
||||
double_int bound = niter_bound->bound;
|
||||
tree nit_type = TREE_TYPE (niter);
|
||||
enum tree_code cmp;
|
||||
|
||||
gcc_assert (TYPE_UNSIGNED (bound_type)
|
||||
&& TYPE_UNSIGNED (nit_type)
|
||||
&& is_gimple_min_invariant (bound));
|
||||
if (TYPE_PRECISION (nit_type) > TYPE_PRECISION (bound_type))
|
||||
bound = fold_convert (nit_type, bound);
|
||||
else
|
||||
niter = fold_convert (bound_type, niter);
|
||||
gcc_assert (TYPE_UNSIGNED (nit_type));
|
||||
|
||||
/* After the statement niter_bound->at_stmt we know that anything is
|
||||
executed at most BOUND times. */
|
||||
if (stmt && stmt_dominates_stmt_p (niter_bound->at_stmt, stmt))
|
||||
cmp = GE_EXPR;
|
||||
/* Before the statement niter_bound->at_stmt we know that anything
|
||||
is executed at most BOUND + 1 times. */
|
||||
else
|
||||
cmp = GT_EXPR;
|
||||
/* If the bound does not even fit into NIT_TYPE, it cannot tell us that
|
||||
the number of iterations is small. */
|
||||
if (!double_int_fits_to_tree_p (nit_type, bound))
|
||||
return false;
|
||||
|
||||
cond = fold_binary (cmp, boolean_type_node, niter, bound);
|
||||
return nonzero_p (cond);
|
||||
/* We know that NITER_BOUND->stmt is executed at most NITER_BOUND->bound + 1
|
||||
times. This means that:
|
||||
|
||||
-- if NITER_BOUND->is_exit is true, then everything before
|
||||
NITER_BOUND->stmt is executed at most NITER_BOUND->bound + 1
|
||||
times, and everyting after it at most NITER_BOUND->bound times.
|
||||
|
||||
-- If NITER_BOUND->is_exit is false, then if we can prove that when STMT
|
||||
is executed, then NITER_BOUND->stmt is executed as well in the same
|
||||
iteration (we conclude that if both statements belong to the same
|
||||
basic block, or if STMT is after NITER_BOUND->stmt), then STMT
|
||||
is executed at most NITER_BOUND->bound + 1 times. Otherwise STMT is
|
||||
executed at most NITER_BOUND->bound + 2 times. */
|
||||
|
||||
if (niter_bound->is_exit)
|
||||
{
|
||||
if (stmt
|
||||
&& stmt != niter_bound->stmt
|
||||
&& stmt_dominates_stmt_p (niter_bound->stmt, stmt))
|
||||
cmp = GE_EXPR;
|
||||
else
|
||||
cmp = GT_EXPR;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!stmt
|
||||
|| (bb_for_stmt (stmt) != bb_for_stmt (niter_bound->stmt)
|
||||
&& !stmt_dominates_stmt_p (niter_bound->stmt, stmt)))
|
||||
{
|
||||
bound = double_int_add (bound, double_int_one);
|
||||
if (double_int_zero_p (bound)
|
||||
|| !double_int_fits_to_tree_p (nit_type, bound))
|
||||
return false;
|
||||
}
|
||||
cmp = GT_EXPR;
|
||||
}
|
||||
|
||||
return nonzero_p (fold_binary (cmp, boolean_type_node,
|
||||
niter,
|
||||
double_int_to_tree (nit_type, bound)));
|
||||
}
|
||||
|
||||
/* Returns true if the arithmetics in TYPE can be assumed not to wrap. */
|
||||
@ -2042,7 +2231,7 @@ free_numbers_of_iterations_estimates_loop (struct loop *loop)
|
||||
struct nb_iter_bound *bound, *next;
|
||||
|
||||
loop->nb_iterations = NULL;
|
||||
loop->estimated_nb_iterations = NULL;
|
||||
loop->estimate_state = EST_NOT_COMPUTED;
|
||||
for (bound = loop->bounds; bound; bound = next)
|
||||
{
|
||||
next = bound->next;
|
||||
@ -2075,6 +2264,4 @@ void
|
||||
substitute_in_loop_info (struct loop *loop, tree name, tree val)
|
||||
{
|
||||
loop->nb_iterations = simplify_replace_tree (loop->nb_iterations, name, val);
|
||||
loop->estimated_nb_iterations
|
||||
= simplify_replace_tree (loop->estimated_nb_iterations, name, val);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user