From: Robin Dapp <[email protected]>
This patch adds a path for scev to continue when encountering wrapping
behavior instead of giving up. If scev_probably_wraps_p is passed a
nonzero nowrap_bound tree it will use the type bound of the current step
as upper bound for wrapping and store it.
In order for the nowrap_bound parameter to reach scev_probably_wraps_p,
the patch adds parameters to many of the internal scev functions. Most
of them just forward the parameter.
Initially, I attempted a global variable that was supposed to store the
bound. None of my tries resulted in comprehensible code or correct
results, however, and I found myself running into corner case
after corner case. Thus, I arrived at the mostly mechanical "brute-force"
solution.
The patch also introduces a new helper scev_add_nowrap_bound that
combines two bounds by building a MIN of each so that we'd get a
condition like IV <= MIN (dr1.bound, dr2.bound, ...).
Cache invalidation is handled by an additional bit (assumption or no
assumption) for the respective entry.
affine_iv gets a new field nowrap_bound. This allows passing the nowrap
bounds to dataref analysis.
gcc/ChangeLog:
* tree-chrec.cc (convert_affine_scev): Add nowrap_bound param.
(chrec_convert_rhs): Ditto.
(chrec_convert_1): Ditto.
(chrec_convert): Ditto.
* tree-chrec.h (chrec_convert): Ditto.
(chrec_convert_rhs): Ditto.
(convert_affine_scev): Ditto.
* tree-scalar-evolution.cc (analyze_scalar_evolution_1): Ditto.
(analyze_scalar_evolution_for_address_of): Ditto.
(struct scev_info_str): Add nowrap_assumed.
(new_scev_info_str): Ditto.
(scev_info_hasher::hash): Ditto.
(scev_info_hasher::equal): Ditto.
(find_var_scev_info): Ditto.
(scev_add_nowrap_bound): New function to accumulate bounds.
(set_scalar_evolution): Add nowrap_bound param.
(get_scalar_evolution): Ditto.
(simplify_peeled_chrec): Ditto.
(analyze_evolution_in_loop): Ditto.
(interpret_loop_phi): Ditto.
(interpret_condition_phi): Ditto.
(interpret_rhs_expr): Ditto.
(interpret_expr): Ditto.
(interpret_gimple_assign): Ditto.
(analyze_scalar_evolution): Ditto.
(analyze_scalar_evolution_in_loop): Ditto.
(simple_iv_with_niters): Add allow_wrapping.
(simple_iv): Ditto.
* tree-scalar-evolution.h (analyze_scalar_evolution): Add new
param.
(simple_iv_with_niters): Ditto.
(scev_add_nowrap_bound): Declare.
* tree-ssa-loop-niter.cc (scev_probably_wraps_p): Build no-wrap
bound.
* tree-ssa-loop-niter.h (scev_probably_wraps_p): Add param.
* tree-ssa-loop.h (struct affine_iv): Add nowrap_bound.
---
gcc/tree-chrec.cc | 51 ++++--
gcc/tree-chrec.h | 7 +-
gcc/tree-scalar-evolution.cc | 314 +++++++++++++++++++++++------------
gcc/tree-scalar-evolution.h | 9 +-
gcc/tree-ssa-loop-niter.cc | 16 +-
gcc/tree-ssa-loop-niter.h | 2 +-
gcc/tree-ssa-loop.h | 4 +
7 files changed, 270 insertions(+), 133 deletions(-)
diff --git a/gcc/tree-chrec.cc b/gcc/tree-chrec.cc
index 9869389a7b9..2b1659eab76 100644
--- a/gcc/tree-chrec.cc
+++ b/gcc/tree-chrec.cc
@@ -1421,13 +1421,18 @@ nb_vars_in_chrec (tree chrec)
that the rules for overflow of the given language apply (e.g., that signed
arithmetics in C does not overflow) -- i.e., to use them to avoid
unnecessary tests, but also to enforce that the result follows them.
- FROM is the source variable converted if it's not NULL. Returns true if
- the conversion succeeded, false otherwise. */
+ FROM is the source variable converted if it's not NULL.
+ If NOWRAP_BOUND is nonzero, pass it on to scev_probably_wraps_p etc.
+ to have them determine the bound below which no wrapping occurs.
+ Most other functions just forward NOWRAP_BOUND, therefore it is not
+ documented everywhere.
+ The function returns true if the conversion succeeded, false otherwise. */
bool
convert_affine_scev (class loop *loop, tree type,
tree *base, tree *step, gimple *at_stmt,
- bool use_overflow_semantics, tree from)
+ bool use_overflow_semantics, tree from,
+ tree *nowrap_bound)
{
tree ct = TREE_TYPE (*step);
bool enforce_overflow_semantics;
@@ -1452,6 +1457,11 @@ convert_affine_scev (class loop *loop, tree type,
happen. */
must_check_src_overflow = TYPE_PRECISION (ct) < TYPE_PRECISION (type);
+ /* MUST_CHECK_SRC_OVERFLOW implies chrec_convert_aggressive later
+ which can prove "no wrap" without assumptions. */
+ if (!must_check_src_overflow)
+ nowrap_bound = NULL;
+
enforce_overflow_semantics = (use_overflow_semantics
&& nowrap_type_p (type));
if (enforce_overflow_semantics)
@@ -1487,10 +1497,11 @@ convert_affine_scev (class loop *loop, tree type,
if (must_check_src_overflow
&& scev_probably_wraps_p (from, *base, *step, at_stmt, loop,
- use_overflow_semantics))
+ use_overflow_semantics, nowrap_bound))
return false;
- new_base = chrec_convert (type, *base, at_stmt, use_overflow_semantics);
+ new_base = chrec_convert (type, *base, at_stmt, nowrap_bound,
+ use_overflow_semantics);
/* The step must be sign extended, regardless of the signedness
of CT and TYPE. This only needs to be handled specially when
CT is unsigned -- to avoid e.g. unsigned char [100, +, 255]
@@ -1501,10 +1512,10 @@ convert_affine_scev (class loop *loop, tree type,
if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct))
{
tree signed_ct = signed_type_for (ct);
- new_step = chrec_convert (signed_ct, new_step, at_stmt,
+ new_step = chrec_convert (signed_ct, new_step, at_stmt, nowrap_bound,
use_overflow_semantics);
}
- new_step = chrec_convert (step_type, new_step, at_stmt,
+ new_step = chrec_convert (step_type, new_step, at_stmt, nowrap_bound,
use_overflow_semantics);
if (automatically_generated_chrec_p (new_base)
@@ -1515,7 +1526,7 @@ convert_affine_scev (class loop *loop, tree type,
/* Note that in this case we cannot use the fact that signed variables
do not overflow, as this is what we are verifying for the new iv. */
&& scev_probably_wraps_p (NULL_TREE, new_base, new_step,
- at_stmt, loop, false))
+ at_stmt, loop, false, nowrap_bound))
return false;
*base = new_base;
@@ -1528,12 +1539,12 @@ convert_affine_scev (class loop *loop, tree type,
The increment for a pointer type is always sizetype. */
tree
-chrec_convert_rhs (tree type, tree chrec, gimple *at_stmt)
+chrec_convert_rhs (tree type, tree chrec, gimple *at_stmt, tree *nowrap_bound)
{
if (POINTER_TYPE_P (type))
type = sizetype;
- return chrec_convert (type, chrec, at_stmt);
+ return chrec_convert (type, chrec, at_stmt, nowrap_bound);
}
/* Convert CHREC to TYPE. When the analyzer knows the context in
@@ -1552,7 +1563,7 @@ chrec_convert_rhs (tree type, tree chrec, gimple *at_stmt)
static tree
chrec_convert_1 (tree type, tree chrec, gimple *at_stmt,
- bool use_overflow_semantics, tree from)
+ tree *nowrap_bound, bool use_overflow_semantics, tree from)
{
tree ct, res;
tree base, step;
@@ -1573,7 +1584,7 @@ chrec_convert_1 (tree type, tree chrec, gimple *at_stmt,
step = CHREC_RIGHT (chrec);
if (convert_affine_scev (loop, type, &base, &step, at_stmt,
- use_overflow_semantics, from))
+ use_overflow_semantics, from, nowrap_bound))
return build_polynomial_chrec (loop->num, base, step);
/* If we cannot propagate the cast inside the chrec, just keep the cast. */
@@ -1606,7 +1617,8 @@ keep_cast:
CHREC_LEFT (chrec)),
fold_convert (utype,
CHREC_RIGHT (chrec)));
- res = chrec_convert_1 (type, res, at_stmt, use_overflow_semantics, from);
+ res = chrec_convert_1 (type, res, at_stmt, nowrap_bound,
+ use_overflow_semantics, from);
}
/* Similar perform the trick that (unsigned T)(base + step) can be
folded to ((unsigned T)x + (unsigned T)step). */
@@ -1631,7 +1643,8 @@ keep_cast:
CHREC_LEFT (chrec)),
fold_convert (type,
CHREC_RIGHT (chrec)));
- res = chrec_convert_1 (type, res, at_stmt, use_overflow_semantics, from);
+ res = chrec_convert_1 (type, res, at_stmt, nowrap_bound,
+ use_overflow_semantics, from);
}
else
res = fold_convert (type, chrec);
@@ -1677,6 +1690,11 @@ keep_cast:
{(uint) 0, +, (uint) 260}
+ If NOWRAP_BOUND is nonzero it is used to store the bound below which
+ no wrapping occurs. Here as well as in many other similar functions,
+ it is just passed through to other functions and thus not documented
+ everywhere.
+
USE_OVERFLOW_SEMANTICS is true if this function should assume that
the rules for overflow of the given language apply (e.g., that signed
arithmetics in C does not overflow) -- i.e., to use them to avoid
@@ -1686,9 +1704,10 @@ keep_cast:
tree
chrec_convert (tree type, tree chrec, gimple *at_stmt,
- bool use_overflow_semantics, tree from)
+ tree *nowrap_bound, bool use_overflow_semantics, tree from)
{
- return chrec_convert_1 (type, chrec, at_stmt, use_overflow_semantics, from);
+ return chrec_convert_1 (type, chrec, at_stmt, nowrap_bound,
+ use_overflow_semantics, from);
}
/* Convert CHREC to TYPE, without regard to signed overflows. Returns the new
diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h
index 7777ff50942..9fdfaac0e15 100644
--- a/gcc/tree-chrec.h
+++ b/gcc/tree-chrec.h
@@ -62,8 +62,9 @@ enum ev_direction scev_direction (const_tree);
extern tree chrec_fold_plus (tree, tree, tree);
extern tree chrec_fold_minus (tree, tree, tree);
extern tree chrec_fold_multiply (tree, tree, tree);
-extern tree chrec_convert (tree, tree, gimple *, bool = true, tree = NULL);
-extern tree chrec_convert_rhs (tree, tree, gimple * = NULL);
+extern tree chrec_convert (tree, tree, gimple *, tree * = nullptr,
+ bool = true, tree = NULL);
+extern tree chrec_convert_rhs (tree, tree, gimple * = NULL, tree * = nullptr);
extern tree chrec_convert_aggressive (tree, tree, bool *);
/* Operations. */
@@ -78,7 +79,7 @@ extern tree reset_evolution_in_loop (unsigned, tree, tree);
extern tree chrec_merge (tree, tree);
extern void for_each_scev_op (tree *, bool (*) (tree *, void *), void *);
extern bool convert_affine_scev (class loop *, tree, tree *, tree *, gimple *,
- bool, tree = NULL);
+ bool, tree = NULL, tree * = nullptr);
/* Observers. */
extern bool eq_evolutions_p (const_tree, const_tree);
diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc
index b9acdbe9135..0d1500fec65 100644
--- a/gcc/tree-scalar-evolution.cc
+++ b/gcc/tree-scalar-evolution.cc
@@ -286,18 +286,24 @@ along with GCC; see the file COPYING3. If not see
#include "case-cfn-macros.h"
#include "tree-eh.h"
-static tree analyze_scalar_evolution_1 (class loop *, tree);
+static tree analyze_scalar_evolution_1 (class loop *, tree, tree * = nullptr);
static tree analyze_scalar_evolution_for_address_of (class loop *loop,
- tree var);
+ tree var,
+ tree * = nullptr);
/* The cached information about an SSA name with version NAME_VERSION,
claiming that below basic block with index INSTANTIATED_BELOW, the
- value of the SSA name can be expressed as CHREC. */
+ value of the SSA name can be expressed as CHREC.
+ NOWRAP_ASSUMPTION_P indicates whether or not the SSA name requires
+ an assumption to guarantee that it doesn't wrap. The assumption
+ itself is stored in NOWRAP_BOUND if necessary. */
struct GTY((for_user)) scev_info_str {
unsigned int name_version;
int instantiated_below;
+ bool nowrap_assumption_p;
tree chrec;
+ tree nowrap_bound;
};
/* Counters for the scev database. */
@@ -316,14 +322,17 @@ static GTY (()) hash_table<scev_info_hasher>
*scalar_evolution_info;
/* Constructs a new SCEV_INFO_STR structure for VAR and INSTANTIATED_BELOW. */
static inline struct scev_info_str *
-new_scev_info_str (basic_block instantiated_below, tree var)
+new_scev_info_str (basic_block instantiated_below, tree var,
+ bool nowrap_assumption_p)
{
struct scev_info_str *res;
res = ggc_alloc<scev_info_str> ();
res->name_version = SSA_NAME_VERSION (var);
- res->chrec = chrec_not_analyzed_yet;
res->instantiated_below = instantiated_below->index;
+ res->nowrap_assumption_p = nowrap_assumption_p;
+ res->chrec = chrec_not_analyzed_yet;
+ res->nowrap_bound = NULL_TREE;
return res;
}
@@ -333,7 +342,8 @@ new_scev_info_str (basic_block instantiated_below, tree var)
hashval_t
scev_info_hasher::hash (scev_info_str *elt)
{
- return elt->name_version ^ elt->instantiated_below;
+ return (elt->name_version ^ elt->instantiated_below)
+ + elt->nowrap_assumption_p;
}
/* Compares database elements E1 and E2. */
@@ -342,27 +352,29 @@ bool
scev_info_hasher::equal (const scev_info_str *elt1, const scev_info_str *elt2)
{
return (elt1->name_version == elt2->name_version
- && elt1->instantiated_below == elt2->instantiated_below);
+ && elt1->instantiated_below == elt2->instantiated_below
+ && elt1->nowrap_assumption_p == elt2->nowrap_assumption_p);
}
/* Get the scalar evolution of VAR for INSTANTIATED_BELOW basic block.
A first query on VAR returns chrec_not_analyzed_yet. */
-static tree *
-find_var_scev_info (basic_block instantiated_below, tree var)
+static scev_info_str *
+find_var_scev_info (basic_block instantiated_below, tree var,
+ bool nowrap_assumption_p)
{
- struct scev_info_str *res;
struct scev_info_str tmp;
tmp.name_version = SSA_NAME_VERSION (var);
tmp.instantiated_below = instantiated_below->index;
+ tmp.nowrap_assumption_p = nowrap_assumption_p;
scev_info_str **slot = scalar_evolution_info->find_slot (&tmp, INSERT);
if (!*slot)
- *slot = new_scev_info_str (instantiated_below, var);
- res = *slot;
+ *slot = new_scev_info_str (instantiated_below, var,
+ tmp.nowrap_assumption_p);
- return &res->chrec;
+ return *slot;
}
@@ -396,6 +408,27 @@ instantiate_cache_type::~instantiate_cache_type ()
or resolve_mixers call. */
static instantiate_cache_type *global_cache;
+/* Build a combined bound from BASE and BOUND by taking the minimum
+ of both. The result is stored in BASE. */
+
+void
+scev_add_nowrap_bound (tree *base, tree bound)
+{
+ if (!base || !bound)
+ return;
+ if (!*base)
+ {
+ *base = bound;
+ return;
+ }
+
+ tree t1 = TREE_TYPE (*base);
+ tree t2 = TREE_TYPE (bound);
+ tree wide_type = TYPE_PRECISION (t1) >= TYPE_PRECISION (t2) ? t1 : t2;
+ *base = fold_build2 (MIN_EXPR, wide_type,
+ fold_convert (wide_type, *base),
+ fold_convert (wide_type, bound));
+}
/* Return true when PHI is a loop-phi-node. */
@@ -493,14 +526,16 @@ compute_overall_effect_of_inner_loop (class loop *loop,
tree evolution_fn)
/* Associate CHREC to SCALAR. */
static void
-set_scalar_evolution (basic_block instantiated_below, tree scalar, tree chrec)
+set_scalar_evolution (basic_block instantiated_below, tree scalar, tree chrec,
+ tree *nowrap_bound)
{
- tree *scalar_info;
+ scev_info_str *scalar_info;
if (TREE_CODE (scalar) != SSA_NAME)
return;
- scalar_info = find_var_scev_info (instantiated_below, scalar);
+ scalar_info = find_var_scev_info (instantiated_below, scalar,
+ nowrap_bound != nullptr);
if (dump_file)
{
@@ -519,14 +554,17 @@ set_scalar_evolution (basic_block instantiated_below,
tree scalar, tree chrec)
nb_set_scev++;
}
- *scalar_info = chrec;
+ scalar_info->chrec = chrec;
+ if (scalar_info->nowrap_assumption_p && nowrap_bound)
+ scalar_info->nowrap_bound = *nowrap_bound;
}
/* Retrieve the chrec associated to SCALAR instantiated below
INSTANTIATED_BELOW block. */
static tree
-get_scalar_evolution (basic_block instantiated_below, tree scalar)
+get_scalar_evolution (basic_block instantiated_below, tree scalar,
+ tree *nowrap_bound)
{
tree res;
@@ -551,10 +589,19 @@ get_scalar_evolution (basic_block instantiated_below,
tree scalar)
switch (TREE_CODE (scalar))
{
case SSA_NAME:
- if (SSA_NAME_IS_DEFAULT_DEF (scalar))
+ if (SSA_NAME_IS_DEFAULT_DEF (scalar))
res = scalar;
else
- res = *find_var_scev_info (instantiated_below, scalar);
+ {
+ scev_info_str *info
+ = find_var_scev_info (instantiated_below, scalar,
+ nowrap_bound != nullptr);
+ res = info->chrec;
+ if (info->nowrap_assumption_p
+ && res != chrec_not_analyzed_yet
+ && info->nowrap_bound)
+ scev_add_nowrap_bound (nowrap_bound, info->nowrap_bound);
+ }
break;
case REAL_CST:
@@ -1361,12 +1408,18 @@ get_loop_exit_condition (const_edge exit_edge)
See PR41488. */
static tree
-simplify_peeled_chrec (class loop *loop, tree arg, tree init_cond)
+simplify_peeled_chrec (class loop *loop, tree arg, tree init_cond,
+ tree *nowrap_bound = nullptr)
{
aff_tree aff1, aff2;
tree ev, left, right, type, step_val;
hash_map<tree, name_expansion *> *peeled_chrec_map = NULL;
+ tree local_nowrap_bound = NULL_TREE;
+ tree *bound = nullptr;
+ if (nowrap_bound)
+ bound = &local_nowrap_bound;
+
ev = instantiate_parameters (loop, analyze_scalar_evolution (loop, arg));
if (ev == NULL_TREE)
return chrec_dont_know;
@@ -1390,7 +1443,7 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree
init_cond)
if (TREE_CODE (left_before) == INTEGER_CST
&& wi::to_widest (init_cond) == wi::to_widest (left_before)
&& !scev_probably_wraps_p (NULL_TREE, left_before, right, NULL,
- loop, false))
+ loop, false, bound))
{
tree tp = TREE_TYPE (right);
@@ -1399,10 +1452,11 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree
init_cond)
if (TYPE_UNSIGNED (tp))
right = fold_convert (signed_type_for (tp), right);
- return build_polynomial_chrec (loop->num, init_cond,
- chrec_convert (TREE_TYPE (ev),
- right, NULL,
- false, NULL_TREE));
+ scev_add_nowrap_bound (nowrap_bound, local_nowrap_bound);
+ return build_polynomial_chrec
+ (loop->num, init_cond, chrec_convert (TREE_TYPE (ev), right, NULL,
+ nullptr, false,
+ NULL_TREE));
}
return chrec_dont_know;
}
@@ -1422,6 +1476,7 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree
init_cond)
if (dump_file && (dump_flags & TDF_SCEV))
fprintf (dump_file, "Simplify PEELED_CHREC into POLYNOMIAL_CHREC.\n");
+ scev_add_nowrap_bound (nowrap_bound, local_nowrap_bound);
return build_polynomial_chrec (loop->num, init_cond, right);
}
@@ -1444,6 +1499,7 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree
init_cond)
if (dump_file && (dump_flags & TDF_SCEV))
fprintf (dump_file, "Simplify PEELED_CHREC into POLYNOMIAL_CHREC.\n");
+ scev_add_nowrap_bound (nowrap_bound, local_nowrap_bound);
return build_polynomial_chrec (loop->num, init_cond, right);
}
return chrec_dont_know;
@@ -1454,7 +1510,8 @@ simplify_peeled_chrec (class loop *loop, tree arg, tree
init_cond)
static tree
analyze_evolution_in_loop (gphi *loop_phi_node,
- tree init_cond)
+ tree init_cond,
+ tree *nowrap_bound = nullptr)
{
int i, n = gimple_phi_num_args (loop_phi_node);
tree evolution_function = chrec_not_analyzed_yet;
@@ -1517,7 +1574,8 @@ analyze_evolution_in_loop (gphi *loop_phi_node,
if (simplify_peeled_chrec_p && TREE_CODE (arg) == SSA_NAME)
{
simplify_peeled_chrec_p = false;
- ev_fn = simplify_peeled_chrec (loop, arg, init_cond);
+ ev_fn = simplify_peeled_chrec
+ (loop, arg, init_cond, nowrap_bound);
simplify_peeled_chrec_p = true;
}
}
@@ -1640,7 +1698,8 @@ analyze_initial_condition (gphi *loop_phi_node)
/* Analyze the scalar evolution for LOOP_PHI_NODE. */
static tree
-interpret_loop_phi (class loop *loop, gphi *loop_phi_node)
+interpret_loop_phi (class loop *loop, gphi *loop_phi_node,
+ tree *nowrap_bound = nullptr)
{
class loop *phi_loop = loop_containing_stmt (loop_phi_node);
tree init_cond;
@@ -1649,7 +1708,7 @@ interpret_loop_phi (class loop *loop, gphi *loop_phi_node)
/* Otherwise really interpret the loop phi. */
init_cond = analyze_initial_condition (loop_phi_node);
- return analyze_evolution_in_loop (loop_phi_node, init_cond);
+ return analyze_evolution_in_loop (loop_phi_node, init_cond, nowrap_bound);
}
/* This function merges the branches of a condition-phi-node,
@@ -1657,7 +1716,8 @@ interpret_loop_phi (class loop *loop, gphi *loop_phi_node)
analyzed. */
static tree
-interpret_condition_phi (class loop *loop, gphi *condition_phi)
+interpret_condition_phi (class loop *loop, gphi *condition_phi,
+ tree *nowrap_bound)
{
int i, n = gimple_phi_num_args (condition_phi);
tree res = chrec_not_analyzed_yet;
@@ -1673,7 +1733,7 @@ interpret_condition_phi (class loop *loop, gphi
*condition_phi)
}
branch_chrec = analyze_scalar_evolution
- (loop, PHI_ARG_DEF (condition_phi, i));
+ (loop, PHI_ARG_DEF (condition_phi, i), nowrap_bound);
res = chrec_merge (res, branch_chrec);
if (res == chrec_dont_know)
@@ -1692,7 +1752,8 @@ interpret_condition_phi (class loop *loop, gphi
*condition_phi)
static tree
interpret_rhs_expr (class loop *loop, gimple *at_stmt,
- tree type, tree rhs1, enum tree_code code, tree rhs2)
+ tree type, tree rhs1, enum tree_code code, tree rhs2,
+ tree *nowrap_bound = nullptr)
{
tree res, chrec1, chrec2, ctype;
gimple *def;
@@ -1703,8 +1764,10 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
return chrec_convert (type, rhs1, at_stmt);
if (code == SSA_NAME)
- return chrec_convert (type, analyze_scalar_evolution (loop, rhs1),
- at_stmt);
+ return chrec_convert (type,
+ analyze_scalar_evolution (loop, rhs1,
+ nowrap_bound),
+ at_stmt, nowrap_bound);
}
switch (code)
@@ -1730,25 +1793,28 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
rhs2 = TREE_OPERAND (base, 1);
rhs1 = TREE_OPERAND (base, 0);
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
- chrec1 = chrec_convert (type, chrec1, at_stmt);
- chrec2 = chrec_convert (TREE_TYPE (rhs2), chrec2, at_stmt);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
+ chrec1 = chrec_convert (type, chrec1, at_stmt, nowrap_bound);
+ chrec2 = chrec_convert (TREE_TYPE (rhs2), chrec2, at_stmt,
+ nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_plus (type, chrec1, chrec2);
}
else
{
- chrec1 = analyze_scalar_evolution_for_address_of (loop, base);
- chrec1 = chrec_convert (type, chrec1, at_stmt);
+ chrec1 = analyze_scalar_evolution_for_address_of (loop, base,
+ nowrap_bound);
+ chrec1 = chrec_convert (type, chrec1, at_stmt, nowrap_bound);
res = chrec1;
}
if (offset != NULL_TREE)
{
- chrec2 = analyze_scalar_evolution (loop, offset);
- chrec2 = chrec_convert (TREE_TYPE (offset), chrec2, at_stmt);
+ chrec2 = analyze_scalar_evolution (loop, offset, nowrap_bound);
+ chrec2 = chrec_convert (TREE_TYPE (offset), chrec2, at_stmt,
+ nowrap_bound);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_plus (type, res, chrec2);
}
@@ -1756,8 +1822,9 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
if (maybe_ne (bitpos, 0))
{
unitpos = size_int (exact_div (bitpos, BITS_PER_UNIT));
- chrec3 = analyze_scalar_evolution (loop, unitpos);
- chrec3 = chrec_convert (TREE_TYPE (unitpos), chrec3, at_stmt);
+ chrec3 = analyze_scalar_evolution (loop, unitpos, nowrap_bound);
+ chrec3 = chrec_convert (TREE_TYPE (unitpos), chrec3, at_stmt,
+ nowrap_bound);
chrec3 = instantiate_parameters (loop, chrec3);
res = chrec_fold_plus (type, res, chrec3);
}
@@ -1767,10 +1834,11 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
break;
case POINTER_PLUS_EXPR:
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
- chrec1 = chrec_convert (type, chrec1, at_stmt);
- chrec2 = chrec_convert (TREE_TYPE (rhs2), chrec2, at_stmt);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
+ chrec1 = chrec_convert (type, chrec1, at_stmt, nowrap_bound);
+ chrec2 = chrec_convert (TREE_TYPE (rhs2), chrec2, at_stmt,
+ nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_plus (type, chrec1, chrec2);
@@ -1779,20 +1847,20 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
case POINTER_DIFF_EXPR:
{
tree utype = unsigned_type_for (type);
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
- chrec1 = chrec_convert (utype, chrec1, at_stmt);
- chrec2 = chrec_convert (utype, chrec2, at_stmt);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
+ chrec1 = chrec_convert (utype, chrec1, at_stmt, nowrap_bound);
+ chrec2 = chrec_convert (utype, chrec2, at_stmt, nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_minus (utype, chrec1, chrec2);
- res = chrec_convert (type, res, at_stmt);
+ res = chrec_convert (type, res, at_stmt, nowrap_bound);
break;
}
case PLUS_EXPR:
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
ctype = type;
/* When the stmt is conditionally executed re-write the CHREC
into a form that has well-defined behavior on overflow. */
@@ -1802,18 +1870,18 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
&& ! dominated_by_p (CDI_DOMINATORS, loop->latch,
gimple_bb (at_stmt)))
ctype = unsigned_type_for (type);
- chrec1 = chrec_convert (ctype, chrec1, at_stmt);
- chrec2 = chrec_convert (ctype, chrec2, at_stmt);
+ chrec1 = chrec_convert (ctype, chrec1, at_stmt, nowrap_bound);
+ chrec2 = chrec_convert (ctype, chrec2, at_stmt, nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_plus (ctype, chrec1, chrec2);
if (type != ctype)
- res = chrec_convert (type, res, at_stmt);
+ res = chrec_convert (type, res, at_stmt, nowrap_bound);
break;
case MINUS_EXPR:
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
ctype = type;
/* When the stmt is conditionally executed re-write the CHREC
into a form that has well-defined behavior on overflow. */
@@ -1823,17 +1891,17 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
&& ! dominated_by_p (CDI_DOMINATORS,
loop->latch, gimple_bb (at_stmt)))
ctype = unsigned_type_for (type);
- chrec1 = chrec_convert (ctype, chrec1, at_stmt);
- chrec2 = chrec_convert (ctype, chrec2, at_stmt);
+ chrec1 = chrec_convert (ctype, chrec1, at_stmt, nowrap_bound);
+ chrec2 = chrec_convert (ctype, chrec2, at_stmt, nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_minus (ctype, chrec1, chrec2);
if (type != ctype)
- res = chrec_convert (type, res, at_stmt);
+ res = chrec_convert (type, res, at_stmt, nowrap_bound);
break;
case NEGATE_EXPR:
- chrec1 = analyze_scalar_evolution (loop, rhs1);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
ctype = type;
/* When the stmt is conditionally executed re-write the CHREC
into a form that has well-defined behavior on overflow. */
@@ -1843,19 +1911,19 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
&& ! dominated_by_p (CDI_DOMINATORS,
loop->latch, gimple_bb (at_stmt)))
ctype = unsigned_type_for (type);
- chrec1 = chrec_convert (ctype, chrec1, at_stmt);
+ chrec1 = chrec_convert (ctype, chrec1, at_stmt, nowrap_bound);
/* TYPE may be integer, real or complex, so use fold_convert. */
chrec1 = instantiate_parameters (loop, chrec1);
res = chrec_fold_multiply (ctype, chrec1,
fold_convert (ctype, integer_minus_one_node));
if (type != ctype)
- res = chrec_convert (type, res, at_stmt);
+ res = chrec_convert (type, res, at_stmt, nowrap_bound);
break;
case BIT_NOT_EXPR:
/* Handle ~X as -1 - X. */
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec1 = chrec_convert (type, chrec1, at_stmt);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec1 = chrec_convert (type, chrec1, at_stmt, nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
res = chrec_fold_minus (type,
fold_convert (type, integer_minus_one_node),
@@ -1863,8 +1931,8 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
break;
case MULT_EXPR:
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
ctype = type;
/* When the stmt is conditionally executed re-write the CHREC
into a form that has well-defined behavior on overflow. */
@@ -1874,29 +1942,29 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
&& ! dominated_by_p (CDI_DOMINATORS,
loop->latch, gimple_bb (at_stmt)))
ctype = unsigned_type_for (type);
- chrec1 = chrec_convert (ctype, chrec1, at_stmt);
- chrec2 = chrec_convert (ctype, chrec2, at_stmt);
+ chrec1 = chrec_convert (ctype, chrec1, at_stmt, nowrap_bound);
+ chrec2 = chrec_convert (ctype, chrec2, at_stmt, nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
res = chrec_fold_multiply (ctype, chrec1, chrec2);
if (type != ctype)
- res = chrec_convert (type, res, at_stmt);
+ res = chrec_convert (type, res, at_stmt, nowrap_bound);
break;
case LSHIFT_EXPR:
{
/* Handle A<<B as A * (1<<B). */
tree uns = unsigned_type_for (type);
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec2 = analyze_scalar_evolution (loop, rhs2);
- chrec1 = chrec_convert (uns, chrec1, at_stmt);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec2 = analyze_scalar_evolution (loop, rhs2, nowrap_bound);
+ chrec1 = chrec_convert (uns, chrec1, at_stmt, nowrap_bound);
chrec1 = instantiate_parameters (loop, chrec1);
chrec2 = instantiate_parameters (loop, chrec2);
tree one = build_int_cst (uns, 1);
chrec2 = fold_build2 (LSHIFT_EXPR, uns, one, chrec2);
res = chrec_fold_multiply (uns, chrec1, chrec2);
- res = chrec_convert (type, res, at_stmt);
+ res = chrec_convert (type, res, at_stmt, nowrap_bound);
}
break;
@@ -1920,11 +1988,12 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
chrec1 = interpret_rhs_expr (loop, at_stmt, utype,
gimple_assign_rhs1 (def),
gimple_assign_rhs_code (def),
- gimple_assign_rhs2 (def));
+ gimple_assign_rhs2 (def),
+ nowrap_bound);
}
else
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- res = chrec_convert (type, chrec1, at_stmt, true, rhs1);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ res = chrec_convert (type, chrec1, at_stmt, nowrap_bound, true, rhs1);
break;
case BIT_AND_EXPR:
@@ -1949,9 +2018,11 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
if (TYPE_PRECISION (utype) < TYPE_PRECISION (TREE_TYPE (rhs1)))
{
- chrec1 = analyze_scalar_evolution (loop, rhs1);
- chrec1 = chrec_convert (utype, chrec1, at_stmt);
- res = chrec_convert (TREE_TYPE (rhs1), chrec1, at_stmt);
+ chrec1 = analyze_scalar_evolution (loop, rhs1, nowrap_bound);
+ chrec1 = chrec_convert (utype, chrec1, at_stmt,
+ nowrap_bound);
+ res = chrec_convert (TREE_TYPE (rhs1), chrec1, at_stmt,
+ nowrap_bound);
}
}
}
@@ -1968,7 +2039,8 @@ interpret_rhs_expr (class loop *loop, gimple *at_stmt,
/* Interpret the expression EXPR. */
static tree
-interpret_expr (class loop *loop, gimple *at_stmt, tree expr)
+interpret_expr (class loop *loop, gimple *at_stmt, tree expr,
+ tree *nowrap_bound)
{
enum tree_code code;
tree type = TREE_TYPE (expr), op0, op1;
@@ -1984,20 +2056,20 @@ interpret_expr (class loop *loop, gimple *at_stmt, tree
expr)
extract_ops_from_tree (expr, &code, &op0, &op1);
return interpret_rhs_expr (loop, at_stmt, type,
- op0, code, op1);
+ op0, code, op1, nowrap_bound);
}
/* Interpret the rhs of the assignment STMT. */
static tree
-interpret_gimple_assign (class loop *loop, gimple *stmt)
+interpret_gimple_assign (class loop *loop, gimple *stmt, tree *nowrap_bound)
{
tree type = TREE_TYPE (gimple_assign_lhs (stmt));
enum tree_code code = gimple_assign_rhs_code (stmt);
return interpret_rhs_expr (loop, stmt, type,
gimple_assign_rhs1 (stmt), code,
- gimple_assign_rhs2 (stmt));
+ gimple_assign_rhs2 (stmt), nowrap_bound);
}
@@ -2011,7 +2083,7 @@ interpret_gimple_assign (class loop *loop, gimple *stmt)
/* Helper recursive function. */
static tree
-analyze_scalar_evolution_1 (class loop *loop, tree var)
+analyze_scalar_evolution_1 (class loop *loop, tree var, tree *nowrap_bound)
{
gimple *def;
basic_block bb;
@@ -2019,7 +2091,12 @@ analyze_scalar_evolution_1 (class loop *loop, tree var)
tree res;
if (TREE_CODE (var) != SSA_NAME)
- return interpret_expr (loop, NULL, var);
+ return interpret_expr (loop, NULL, var, nowrap_bound);
+
+ tree local_nowrap_bound = NULL_TREE;
+ tree *bound = nullptr;
+ if (nowrap_bound)
+ bound = &local_nowrap_bound;
def = SSA_NAME_DEF_STMT (var);
bb = gimple_bb (def);
@@ -2034,26 +2111,26 @@ analyze_scalar_evolution_1 (class loop *loop, tree var)
if (loop != def_loop)
{
- res = analyze_scalar_evolution_1 (def_loop, var);
+ res = analyze_scalar_evolution_1 (def_loop, var, bound);
class loop *loop_to_skip = superloop_at_depth (def_loop,
loop_depth (loop) + 1);
res = compute_overall_effect_of_inner_loop (loop_to_skip, res);
if (chrec_contains_symbols_defined_in_loop (res, loop->num))
- res = analyze_scalar_evolution_1 (loop, res);
+ res = analyze_scalar_evolution_1 (loop, res, bound);
goto set_and_end;
}
switch (gimple_code (def))
{
case GIMPLE_ASSIGN:
- res = interpret_gimple_assign (loop, def);
+ res = interpret_gimple_assign (loop, def, bound);
break;
case GIMPLE_PHI:
if (loop_phi_node_p (def))
- res = interpret_loop_phi (loop, as_a <gphi *> (def));
+ res = interpret_loop_phi (loop, as_a <gphi *> (def), bound);
else
- res = interpret_condition_phi (loop, as_a <gphi *> (def));
+ res = interpret_condition_phi (loop, as_a <gphi *> (def), bound);
break;
default:
@@ -2068,7 +2145,9 @@ analyze_scalar_evolution_1 (class loop *loop, tree var)
res = var;
if (loop == def_loop)
- set_scalar_evolution (block_before_loop (loop), var, res);
+ set_scalar_evolution (block_before_loop (loop), var, res, bound);
+
+ scev_add_nowrap_bound (nowrap_bound, local_nowrap_bound);
return res;
}
@@ -2087,7 +2166,7 @@ analyze_scalar_evolution_1 (class loop *loop, tree var)
*/
tree
-analyze_scalar_evolution (class loop *loop, tree var)
+analyze_scalar_evolution (class loop *loop, tree var, tree *nowrap_bound)
{
tree res;
@@ -2104,7 +2183,7 @@ analyze_scalar_evolution (class loop *loop, tree var)
fprintf (dump_file, ")\n");
}
- res = get_scalar_evolution (block_before_loop (loop), var);
+ res = get_scalar_evolution (block_before_loop (loop), var, nowrap_bound);
if (res == chrec_not_analyzed_yet)
{
/* We'll recurse into instantiate_scev, avoid tearing down the
@@ -2115,7 +2194,7 @@ analyze_scalar_evolution (class loop *loop, tree var)
global_cache = new instantiate_cache_type;
destr = true;
}
- res = analyze_scalar_evolution_1 (loop, var);
+ res = analyze_scalar_evolution_1 (loop, var, nowrap_bound);
if (destr)
{
delete global_cache;
@@ -2156,9 +2235,11 @@ bool nonwrapping_chrec_p (tree chrec)
/* Analyzes and returns the scalar evolution of VAR address in LOOP. */
static tree
-analyze_scalar_evolution_for_address_of (class loop *loop, tree var)
+analyze_scalar_evolution_for_address_of (class loop *loop, tree var,
+ tree *nowrap_bound)
{
- return analyze_scalar_evolution (loop, build_fold_addr_expr (var));
+ return analyze_scalar_evolution (loop, build_fold_addr_expr (var),
+ nowrap_bound);
}
/* Analyze scalar evolution of use of VERSION in USE_LOOP with respect to
@@ -2213,7 +2294,8 @@ analyze_scalar_evolution_for_address_of (class loop
*loop, tree var)
static tree
analyze_scalar_evolution_in_loop (class loop *wrto_loop, class loop *use_loop,
- tree version, bool *folded_casts)
+ tree version, bool *folded_casts,
+ tree *nowrap_bound = nullptr)
{
bool val = false;
tree ev = version, tmp;
@@ -2241,7 +2323,7 @@ analyze_scalar_evolution_in_loop (class loop *wrto_loop,
class loop *use_loop,
*folded_casts = false;
while (1)
{
- tmp = analyze_scalar_evolution (use_loop, ev);
+ tmp = analyze_scalar_evolution (use_loop, ev, nowrap_bound);
ev = resolve_mixers (use_loop, tmp, folded_casts);
if (use_loop == wrto_loop)
@@ -3280,12 +3362,17 @@ derive_simple_iv_with_niters (tree ev, tree *niters)
The derived condition normally is the maximum number the inner iv can
iterate, and will be stored in IV_NITERS. This is useful in loop niter
analysis, to derive break conditions when a loop must terminate, when is
- infinite. */
+ infinite.
+
+ If ALLOW_WRAPPING is true, let scev analysis continue rather than stop if
+ an IV might wrap. Store the bound under which no wrapping occurs in IV's
+ nowrap_bound. */
bool
simple_iv_with_niters (class loop *wrto_loop, class loop *use_loop,
tree op, affine_iv *iv, tree *iv_niters,
- bool allow_nonconstant_step)
+ bool allow_nonconstant_step,
+ bool allow_wrapping)
{
enum tree_code code;
tree type, ev, base, e;
@@ -3295,14 +3382,23 @@ simple_iv_with_niters (class loop *wrto_loop, class
loop *use_loop,
iv->base = NULL_TREE;
iv->step = NULL_TREE;
iv->no_overflow = false;
+ iv->nowrap_bound = NULL_TREE;
type = TREE_TYPE (op);
if (!POINTER_TYPE_P (type)
&& !INTEGRAL_TYPE_P (type))
return false;
+ tree nowrap_bound = NULL_TREE;
ev = analyze_scalar_evolution_in_loop (wrto_loop, use_loop, op,
- &folded_casts);
+ &folded_casts,
+ allow_wrapping ? &nowrap_bound
+ : nullptr);
+
+ /* If there was a nontrivial nowrap bound, add it to the IV. */
+ if (allow_wrapping && nowrap_bound)
+ iv->nowrap_bound = nowrap_bound;
+
if (chrec_contains_undetermined (ev)
|| chrec_contains_symbols_defined_in_loop (ev, wrto_loop->num))
return false;
@@ -3429,10 +3525,12 @@ simple_iv_with_niters (class loop *wrto_loop, class
loop *use_loop,
bool
simple_iv (class loop *wrto_loop, class loop *use_loop, tree op,
- affine_iv *iv, bool allow_nonconstant_step)
+ affine_iv *iv, bool allow_nonconstant_step,
+ bool allow_wrapping)
{
return simple_iv_with_niters (wrto_loop, use_loop, op, iv,
- NULL, allow_nonconstant_step);
+ NULL, allow_nonconstant_step,
+ allow_wrapping);
}
/* Finalize the scalar evolution analysis. */
diff --git a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h
index 0c15956de3f..4f94cf7baa0 100644
--- a/gcc/tree-scalar-evolution.h
+++ b/gcc/tree-scalar-evolution.h
@@ -30,7 +30,7 @@ extern bool scev_initialized_p (void);
extern void scev_reset (void);
extern void scev_reset_htab (void);
extern void scev_finalize (void);
-extern tree analyze_scalar_evolution (class loop *, tree);
+extern tree analyze_scalar_evolution (class loop *, tree, tree * = nullptr);
extern tree instantiate_scev (edge, class loop *, tree);
extern tree resolve_mixers (class loop *, tree, bool *);
extern void gather_stats_on_scev_database (void);
@@ -38,14 +38,17 @@ extern bool final_value_replacement_loop (class loop *);
extern unsigned int scev_const_prop (void);
extern bool expression_expensive_p (tree, bool *);
extern bool simple_iv_with_niters (class loop *, class loop *, tree,
- struct affine_iv *, tree *, bool);
+ struct affine_iv *, tree *, bool,
+ bool = false);
extern bool simple_iv (class loop *, class loop *, tree, struct affine_iv *,
- bool);
+ bool, bool = false);
extern bool iv_can_overflow_p (class loop *, tree, tree, tree);
extern tree compute_overall_effect_of_inner_loop (class loop *, tree);
extern void record_nonwrapping_chrec (tree);
extern bool nonwrapping_chrec_p (tree);
+extern void scev_add_nowrap_bound (tree *, tree);
+
/* Returns the basic block preceding LOOP, or the CFG entry block when
the loop is function's body. */
diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index fe179b69b05..a4630c8a0a1 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -5604,12 +5604,16 @@ scev_var_range_cant_overflow (tree var, tree step,
class loop *loop)
arithmetics in C does not overflow).
If VAR is a ssa variable, this function also returns false if VAR can
- be proven not overflow with value range info. */
+ be proven not overflow with value range info.
+
+ If NOWRAP_BOUND is nonzero and we can't prove it differently, get
+ STEP's type bound, build a bound MIN (NOWRAP_BOUND, STEP_TYPE_BOUND)
+ and store it in NOWRAP_BOUND. */
bool
scev_probably_wraps_p (tree var, tree base, tree step,
gimple *at_stmt, class loop *loop,
- bool use_overflow_semantics)
+ bool use_overflow_semantics, tree *nowrap_bound)
{
/* FIXME: We really need something like
http://gcc.gnu.org/ml/gcc-patches/2005-06/msg02025.html.
@@ -5657,6 +5661,14 @@ scev_probably_wraps_p (tree var, tree base, tree step,
if (var && nonwrapping_chrec_p (analyze_scalar_evolution (loop, var)))
return false;
+ /* If we can use a bound to guarantee no wrapping, save it. */
+ if (nowrap_bound)
+ {
+ tree b = get_niter_type_bound (TREE_TYPE (step), base, step);
+ scev_add_nowrap_bound (nowrap_bound, b);
+ return false;
+ }
+
/* At this point we still don't have a proof that the iv does not
overflow: give up. */
return true;
diff --git a/gcc/tree-ssa-loop-niter.h b/gcc/tree-ssa-loop-niter.h
index 24e458f08db..c789ec524f9 100644
--- a/gcc/tree-ssa-loop-niter.h
+++ b/gcc/tree-ssa-loop-niter.h
@@ -54,7 +54,7 @@ extern bool stmt_dominates_stmt_p (gimple *, gimple *);
extern bool nowrap_type_p (tree);
extern tree get_niter_type_bound (tree, tree, tree);
extern bool scev_probably_wraps_p (tree, tree, tree, gimple *,
- class loop *, bool);
+ class loop *, bool, tree * = nullptr);
extern void free_numbers_of_iterations_estimates (class loop *);
extern void free_numbers_of_iterations_estimates (function *);
extern tree simplify_replace_tree (tree, tree,
diff --git a/gcc/tree-ssa-loop.h b/gcc/tree-ssa-loop.h
index 73796a2732b..de8f9c69dac 100644
--- a/gcc/tree-ssa-loop.h
+++ b/gcc/tree-ssa-loop.h
@@ -30,6 +30,10 @@ struct affine_iv
/* True if this iv does not overflow. */
bool no_overflow;
+
+ /* Upper bound for the number of loop iterations for which this IV
+ does not wrap. */
+ tree nowrap_bound;
};
/* Description of number of iterations of a loop. All the expressions inside
--
2.54.0