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>
|
||||
|
||||
PR c/7652
|
||||
|
|
|
|||
|
|
@ -339,6 +339,7 @@ alloc_loop (void)
|
|||
loop->exits = ggc_cleared_alloc<loop_exit> ();
|
||||
loop->exits->next = loop->exits->prev = loop->exits;
|
||||
loop->can_be_parallel = false;
|
||||
loop->constraints = 0;
|
||||
loop->nb_iterations_upper_bound = 0;
|
||||
loop->nb_iterations_likely_upper_bound = 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. */
|
||||
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. */
|
||||
bool dont_vectorize;
|
||||
|
||||
|
|
@ -221,6 +244,32 @@ struct GTY ((chain_next ("%h.next"))) loop {
|
|||
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. */
|
||||
enum
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1015,6 +1015,7 @@ copy_loop_info (struct loop *loop, struct loop *target)
|
|||
target->any_estimate = loop->any_estimate;
|
||||
target->nb_iterations_estimate = loop->nb_iterations_estimate;
|
||||
target->estimate_state = loop->estimate_state;
|
||||
target->constraints = loop->constraints;
|
||||
target->warned_aggressive_loop_optimizations
|
||||
|= loop->warned_aggressive_loop_optimizations;
|
||||
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
|
||||
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
|
||||
@section 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;
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
niter->assumptions = simplify_using_outer_evolutions (loop,
|
||||
|
|
|
|||
Loading…
Reference in New Issue