mirror of git://gcc.gnu.org/git/gcc.git
cfgloop.h (struct loop): New field constraints.
* cfgloop.h (struct loop): New field constraints. (LOOP_C_INFINITE, LOOP_C_FINITE): New macros. (loop_constraint_set, loop_constraint_clr, loop_constraint_set_p): New functions. * cfgloop.c (alloc_loop): Initialize new field. * cfgloopmanip.c (copy_loop_info): Copy constraints. * tree-ssa-loop-niter.c (number_of_iterations_exit_assumptions): Adjust niter analysis wrto loop constraints. * doc/loop.texi (@node Number of iterations): Add description for loop constraints. From-SVN: r238876
This commit is contained in:
parent
f6c7a248d5
commit
18767ebc32
|
|
@ -1,3 +1,16 @@
|
||||||
|
2016-07-29 Bin Cheng <bin.cheng@arm.com>
|
||||||
|
|
||||||
|
* cfgloop.h (struct loop): New field constraints.
|
||||||
|
(LOOP_C_INFINITE, LOOP_C_FINITE): New macros.
|
||||||
|
(loop_constraint_set, loop_constraint_clr, loop_constraint_set_p): New
|
||||||
|
functions.
|
||||||
|
* cfgloop.c (alloc_loop): Initialize new field.
|
||||||
|
* cfgloopmanip.c (copy_loop_info): Copy constraints.
|
||||||
|
* tree-ssa-loop-niter.c (number_of_iterations_exit_assumptions):
|
||||||
|
Adjust niter analysis wrto loop constraints.
|
||||||
|
* doc/loop.texi (@node Number of iterations): Add description for loop
|
||||||
|
constraints.
|
||||||
|
|
||||||
2016-07-29 Marek Polacek <polacek@redhat.com>
|
2016-07-29 Marek Polacek <polacek@redhat.com>
|
||||||
|
|
||||||
PR c/7652
|
PR c/7652
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,7 @@ alloc_loop (void)
|
||||||
loop->exits = ggc_cleared_alloc<loop_exit> ();
|
loop->exits = ggc_cleared_alloc<loop_exit> ();
|
||||||
loop->exits->next = loop->exits->prev = loop->exits;
|
loop->exits->next = loop->exits->prev = loop->exits;
|
||||||
loop->can_be_parallel = false;
|
loop->can_be_parallel = false;
|
||||||
|
loop->constraints = 0;
|
||||||
loop->nb_iterations_upper_bound = 0;
|
loop->nb_iterations_upper_bound = 0;
|
||||||
loop->nb_iterations_likely_upper_bound = 0;
|
loop->nb_iterations_likely_upper_bound = 0;
|
||||||
loop->nb_iterations_estimate = 0;
|
loop->nb_iterations_estimate = 0;
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,29 @@ struct GTY ((chain_next ("%h.next"))) loop {
|
||||||
of the loop can be safely evaluated concurrently. */
|
of the loop can be safely evaluated concurrently. */
|
||||||
int safelen;
|
int safelen;
|
||||||
|
|
||||||
|
/* Constraints are generally set by consumers and affect certain
|
||||||
|
semantics of niter analyzer APIs. Currently the APIs affected are
|
||||||
|
number_of_iterations_exit* functions and their callers. One typical
|
||||||
|
use case of constraints is to vectorize possibly infinite loop:
|
||||||
|
|
||||||
|
1) Compute niter->assumptions by calling niter analyzer API and
|
||||||
|
record it as possible condition for loop versioning.
|
||||||
|
2) Clear buffered result of niter/scev analyzer.
|
||||||
|
3) Set constraint LOOP_C_FINITE assuming the loop is finite.
|
||||||
|
4) Analyze data references. Since data reference analysis depends
|
||||||
|
on niter/scev analyzer, the point is that niter/scev analysis
|
||||||
|
is done under circumstance of LOOP_C_FINITE constraint.
|
||||||
|
5) Version the loop with niter->assumptions computed in step 1).
|
||||||
|
6) Vectorize the versioned loop in which niter->assumptions is
|
||||||
|
checked to be true.
|
||||||
|
7) Update constraints in versioned loops so that niter analyzer
|
||||||
|
in following passes can use it.
|
||||||
|
|
||||||
|
Note consumers are usually the loop optimizers and it is consumers'
|
||||||
|
responsibility to set/clear constraints correctly. Failing to do
|
||||||
|
that might result in hard to track down bugs in niter/scev consumers. */
|
||||||
|
unsigned constraints;
|
||||||
|
|
||||||
/* True if this loop should never be vectorized. */
|
/* True if this loop should never be vectorized. */
|
||||||
bool dont_vectorize;
|
bool dont_vectorize;
|
||||||
|
|
||||||
|
|
@ -221,6 +244,32 @@ struct GTY ((chain_next ("%h.next"))) loop {
|
||||||
basic_block former_header;
|
basic_block former_header;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Set if the loop is known to be infinite. */
|
||||||
|
#define LOOP_C_INFINITE (1 << 0)
|
||||||
|
/* Set if the loop is known to be finite without any assumptions. */
|
||||||
|
#define LOOP_C_FINITE (1 << 1)
|
||||||
|
|
||||||
|
/* Set C to the LOOP constraint. */
|
||||||
|
static inline void
|
||||||
|
loop_constraint_set (struct loop *loop, unsigned c)
|
||||||
|
{
|
||||||
|
loop->constraints |= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear C from the LOOP constraint. */
|
||||||
|
static inline void
|
||||||
|
loop_constraint_clear (struct loop *loop, unsigned c)
|
||||||
|
{
|
||||||
|
loop->constraints &= ~c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if C is set in the LOOP constraint. */
|
||||||
|
static inline bool
|
||||||
|
loop_constraint_set_p (struct loop *loop, unsigned c)
|
||||||
|
{
|
||||||
|
return (loop->constraints & c) == c;
|
||||||
|
}
|
||||||
|
|
||||||
/* Flags for state of loop structure. */
|
/* Flags for state of loop structure. */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1015,6 +1015,7 @@ copy_loop_info (struct loop *loop, struct loop *target)
|
||||||
target->any_estimate = loop->any_estimate;
|
target->any_estimate = loop->any_estimate;
|
||||||
target->nb_iterations_estimate = loop->nb_iterations_estimate;
|
target->nb_iterations_estimate = loop->nb_iterations_estimate;
|
||||||
target->estimate_state = loop->estimate_state;
|
target->estimate_state = loop->estimate_state;
|
||||||
|
target->constraints = loop->constraints;
|
||||||
target->warned_aggressive_loop_optimizations
|
target->warned_aggressive_loop_optimizations
|
||||||
|= loop->warned_aggressive_loop_optimizations;
|
|= loop->warned_aggressive_loop_optimizations;
|
||||||
target->in_oacc_kernels_region = loop->in_oacc_kernels_region;
|
target->in_oacc_kernels_region = loop->in_oacc_kernels_region;
|
||||||
|
|
|
||||||
|
|
@ -476,6 +476,32 @@ The function @code{number_of_cond_exit_executions} can be used to
|
||||||
determine number of executions of the exit condition of a single-exit
|
determine number of executions of the exit condition of a single-exit
|
||||||
loop (i.e., the @code{number_of_latch_executions} increased by one).
|
loop (i.e., the @code{number_of_latch_executions} increased by one).
|
||||||
|
|
||||||
|
On GIMPLE, below constraint flags affect semantics of some APIs of number
|
||||||
|
of iterations analyzer:
|
||||||
|
|
||||||
|
@itemize
|
||||||
|
@item @code{LOOP_C_INFINITE}: If this constraint flag is set, the loop
|
||||||
|
is known to be infinite. APIs like @code{number_of_iterations_exit} can
|
||||||
|
return false directly without doing any analysis.
|
||||||
|
@item @code{LOOP_C_FINITE}: If this constraint flag is set, the loop is
|
||||||
|
known to be finite, in other words, loop's number of iterations can be
|
||||||
|
computed with @code{assumptions} be true.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
Generally, the constraint flags are set/cleared by consumers which are
|
||||||
|
loop optimizers. It's also the consumers' responsibility to set/clear
|
||||||
|
constraints correctly. Failing to do that might result in hard to track
|
||||||
|
down bugs in scev/niter consumers. One typical use case is vectorizer:
|
||||||
|
it drives number of iterations analyzer by setting @code{LOOP_C_FINITE}
|
||||||
|
and vectorizes possibly infinite loop by versioning loop with analysis
|
||||||
|
result. In return, constraints set by consumers can also help number of
|
||||||
|
iterations analyzer in following optimizers. For example, @code{niter}
|
||||||
|
of a loop versioned under @code{assumptions} is valid unconditionally.
|
||||||
|
|
||||||
|
Other constraints may be added in the future, for example, a constraint
|
||||||
|
indicating that loops' latch must roll thus @code{may_be_zero} would be
|
||||||
|
false unconditionally.
|
||||||
|
|
||||||
@node Dependency analysis
|
@node Dependency analysis
|
||||||
@section Data Dependency Analysis
|
@section Data Dependency Analysis
|
||||||
@cindex Data Dependency Analysis
|
@cindex Data Dependency Analysis
|
||||||
|
|
|
||||||
|
|
@ -2151,6 +2151,10 @@ number_of_iterations_exit_assumptions (struct loop *loop, edge exit,
|
||||||
affine_iv iv0, iv1;
|
affine_iv iv0, iv1;
|
||||||
bool safe;
|
bool safe;
|
||||||
|
|
||||||
|
/* Nothing to analyze if the loop is known to be infinite. */
|
||||||
|
if (loop_constraint_set_p (loop, LOOP_C_INFINITE))
|
||||||
|
return false;
|
||||||
|
|
||||||
safe = dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src);
|
safe = dominated_by_p (CDI_DOMINATORS, loop->latch, exit->src);
|
||||||
|
|
||||||
if (every_iteration && !safe)
|
if (every_iteration && !safe)
|
||||||
|
|
@ -2236,6 +2240,11 @@ number_of_iterations_exit_assumptions (struct loop *loop, edge exit,
|
||||||
niter->max = wi::to_widest (iv_niters);
|
niter->max = wi::to_widest (iv_niters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* There is no assumptions if the loop is known to be finite. */
|
||||||
|
if (!integer_zerop (niter->assumptions)
|
||||||
|
&& loop_constraint_set_p (loop, LOOP_C_FINITE))
|
||||||
|
niter->assumptions = boolean_true_node;
|
||||||
|
|
||||||
if (optimize >= 3)
|
if (optimize >= 3)
|
||||||
{
|
{
|
||||||
niter->assumptions = simplify_using_outer_evolutions (loop,
|
niter->assumptions = simplify_using_outer_evolutions (loop,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue