aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range.cc
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2021-01-03 21:40:04 +0100
committerThomas Koenig <tkoenig@gcc.gnu.org>2021-01-03 21:40:04 +0100
commitafae4a55ccaa0de95ea11e5f634084db6ab2f444 (patch)
treed632cc867d10410ba9fb750523be790b86846ac4 /gcc/gimple-range.cc
parent9d9a82ec8478ff52c7a9d61f58cd2a7b6295b5f9 (diff)
parentd2eb616a0f7bea78164912aa438c29fe1ef5774a (diff)
downloadgcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.zip
gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.gz
gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.bz2
Merge branch 'master' into devel/coarray_native
Diffstat (limited to 'gcc/gimple-range.cc')
-rw-r--r--gcc/gimple-range.cc224
1 files changed, 135 insertions, 89 deletions
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 267ebad..4f5d502 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -144,7 +144,7 @@ gimple_range_adjustment (irange &res, const gimple *stmt)
}
// Return a range in R for the tree EXPR. Return true if a range is
-// representable.
+// representable, and UNDEFINED/false if not.
bool
get_tree_range (irange &r, tree expr)
@@ -157,11 +157,16 @@ get_tree_range (irange &r, tree expr)
// Return false if the type isn't suported.
if (!irange::supports_type_p (type))
- return false;
+ {
+ r.set_undefined ();
+ return false;
+ }
switch (TREE_CODE (expr))
{
case INTEGER_CST:
+ if (TREE_OVERFLOW_P (expr))
+ expr = drop_tree_overflow (expr);
r.set (expr, expr);
return true;
@@ -373,7 +378,8 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name)
res = range_of_call (r, as_a<gcall *> (s));
else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR)
res = range_of_cond_expr (r, as_a<gassign *> (s));
- else
+
+ if (!res)
{
// If no name is specified, try the expression kind.
if (!name)
@@ -384,25 +390,24 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name)
r.set_varying (t);
return true;
}
+ if (!gimple_range_ssa_p (name))
+ return false;
// We don't understand the stmt, so return the global range.
r = gimple_range_global (name);
return true;
}
- if (res)
+
+ if (r.undefined_p ())
+ return true;
+
+ // We sometimes get compatible types copied from operands, make sure
+ // the correct type is being returned.
+ if (name && TREE_TYPE (name) != r.type ())
{
- if (r.undefined_p ())
- return true;
- // We sometimes get compatible types copied from operands, make sure
- // the correct type is being returned.
- if (name && TREE_TYPE (name) != r.type ())
- {
- gcc_checking_assert (range_compatible_p (r.type (),
- TREE_TYPE (name)));
- range_cast (r, TREE_TYPE (name));
- }
- return true;
+ gcc_checking_assert (range_compatible_p (r.type (), TREE_TYPE (name)));
+ range_cast (r, TREE_TYPE (name));
}
- return false;
+ return true;
}
// Calculate a range for range_op statement S and return it in R. If any
@@ -412,14 +417,23 @@ bool
gimple_ranger::range_of_range_op (irange &r, gimple *s)
{
int_range_max range1, range2;
+ tree lhs = gimple_get_lhs (s);
tree type = gimple_expr_type (s);
gcc_checking_assert (irange::supports_type_p (type));
tree op1 = gimple_range_operand1 (s);
tree op2 = gimple_range_operand2 (s);
- if (range_of_non_trivial_assignment (r, s))
- return true;
+ if (lhs)
+ {
+ // Register potential dependencies for stale value tracking.
+ m_cache.register_dependency (lhs, op1);
+ m_cache.register_dependency (lhs, op2);
+ }
+
+ if (gimple_code (s) == GIMPLE_ASSIGN
+ && gimple_assign_rhs_code (s) == ADDR_EXPR)
+ return range_of_address (r, s);
if (range_of_expr (range1, op1, s))
{
@@ -433,48 +447,84 @@ gimple_ranger::range_of_range_op (irange &r, gimple *s)
return true;
}
-// Calculate the range of a non-trivial assignment. That is, is one
-// inolving arithmetic on an SSA name (for example, an ADDR_EXPR).
+// Calculate the range of an assignment containing an ADDR_EXPR.
// Return the range in R.
-//
-// If a range cannot be calculated, return false.
+// If a range cannot be calculated, set it to VARYING and return true.
bool
-gimple_ranger::range_of_non_trivial_assignment (irange &r, gimple *stmt)
+gimple_ranger::range_of_address (irange &r, gimple *stmt)
{
- if (gimple_code (stmt) != GIMPLE_ASSIGN)
- return false;
+ gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
+ gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR);
- tree base = gimple_range_base_of_assignment (stmt);
- if (base)
+ bool strict_overflow_p;
+ tree expr = gimple_assign_rhs1 (stmt);
+ poly_int64 bitsize, bitpos;
+ tree offset;
+ machine_mode mode;
+ int unsignedp, reversep, volatilep;
+ tree base = get_inner_reference (TREE_OPERAND (expr, 0), &bitsize,
+ &bitpos, &offset, &mode, &unsignedp,
+ &reversep, &volatilep);
+
+
+ if (base != NULL_TREE
+ && TREE_CODE (base) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
- if (TREE_CODE (base) == MEM_REF)
+ tree ssa = TREE_OPERAND (base, 0);
+ gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa)));
+ range_of_expr (r, ssa, stmt);
+ range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt)));
+
+ poly_offset_int off = 0;
+ bool off_cst = false;
+ if (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST)
{
- if (TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
- {
- int_range_max range1;
- tree ssa = TREE_OPERAND (base, 0);
- if (range_of_expr (range1, ssa, stmt))
- {
- tree type = TREE_TYPE (ssa);
- range_operator *op = range_op_handler (POINTER_PLUS_EXPR,
- type);
- int_range<2> offset (TREE_OPERAND (base, 1),
- TREE_OPERAND (base, 1));
- op->fold_range (r, type, range1, offset);
- return true;
- }
- }
- return false;
+ off = mem_ref_offset (base);
+ if (offset)
+ off += poly_offset_int::from (wi::to_poly_wide (offset),
+ SIGNED);
+ off <<= LOG2_BITS_PER_UNIT;
+ off += bitpos;
+ off_cst = true;
}
- if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
+ /* If &X->a is equal to X, the range of X is the result. */
+ if (off_cst && known_eq (off, 0))
+ return true;
+ else if (flag_delete_null_pointer_checks
+ && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr)))
+ {
+ /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't
+ allow going from non-NULL pointer to NULL. */
+ if(!range_includes_zero_p (&r))
+ return true;
+ }
+ /* If MEM_REF has a "positive" offset, consider it non-NULL
+ always, for -fdelete-null-pointer-checks also "negative"
+ ones. Punt for unknown offsets (e.g. variable ones). */
+ if (!TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))
+ && off_cst
+ && known_ne (off, 0)
+ && (flag_delete_null_pointer_checks || known_gt (off, 0)))
{
- // Handle "= &a" and return non-zero.
r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
return true;
}
+ r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+ return true;
}
- return false;
+
+ // Handle "= &a".
+ if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p))
+ {
+ r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+ return true;
+ }
+
+ // Otherwise return varying.
+ r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+ return true;
}
// Calculate a range for phi statement S and return it in R.
@@ -498,6 +548,9 @@ gimple_ranger::range_of_phi (irange &r, gphi *phi)
tree arg = gimple_phi_arg_def (phi, x);
edge e = gimple_phi_arg_edge (phi, x);
+ // Register potential dependencies for stale value tracking.
+ m_cache.register_dependency (phi_def, arg);
+
range_on_edge (arg_range, e, arg);
r.union_ (arg_range);
// Once the value reaches varying, stop looking.
@@ -582,8 +635,8 @@ range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
int_range_max ir0, ir1;
tree arg0 = gimple_call_arg (call, 0);
tree arg1 = gimple_call_arg (call, 1);
- gcc_assert (query.range_of_expr (ir0, arg0, call));
- gcc_assert (query.range_of_expr (ir1, arg1, call));
+ query.range_of_expr (ir0, arg0, call);
+ query.range_of_expr (ir1, arg1, call);
bool saved_flag_wrapv = flag_wrapv;
// Pretend the arithmetic is wrapping. If there is any overflow,
@@ -611,7 +664,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
tree type = gimple_call_return_type (call);
tree arg;
- int mini, maxi, zerov, prec;
+ int mini, maxi, zerov = 0, prec;
scalar_int_mode mode;
switch (func)
@@ -638,7 +691,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
prec = TYPE_PRECISION (TREE_TYPE (arg));
mini = 0;
maxi = prec;
- gcc_assert (query.range_of_expr (r, arg, call));
+ query.range_of_expr (r, arg, call);
// If arg is non-zero, then ffs or popcount are non-zero.
if (!range_includes_zero_p (&r))
mini = 1;
@@ -682,7 +735,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
}
}
- gcc_assert (query.range_of_expr (r, arg, call));
+ query.range_of_expr (r, arg, call);
// From clz of minimum we can compute result maximum.
if (r.constant_p ())
{
@@ -747,7 +800,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
mini = -2;
}
}
- gcc_assert (query.range_of_expr (r, arg, call));
+ query.range_of_expr (r, arg, call);
if (!r.undefined_p ())
{
if (r.lower_bound () != 0)
@@ -864,9 +917,9 @@ gimple_ranger::range_of_cond_expr (irange &r, gassign *s)
if (!irange::supports_type_p (TREE_TYPE (op1)))
return false;
- gcc_assert (range_of_expr (cond_range, cond, s));
- gcc_assert (range_of_expr (range1, op1, s));
- gcc_assert (range_of_expr (range2, op2, s));
+ range_of_expr (cond_range, cond, s);
+ range_of_expr (range1, op1, s);
+ range_of_expr (range2, op2, s);
// If the condition is known, choose the appropriate expression.
if (cond_range.singleton_p ())
@@ -894,7 +947,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
// If there is no statement, just get the global value.
if (!stmt)
{
- if (!m_cache.m_globals.get_global_range (r, expr))
+ if (!m_cache.get_global_range (r, expr))
r = gimple_range_global (expr);
return true;
}
@@ -904,7 +957,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
// If name is defined in this block, try to get an range from S.
if (def_stmt && gimple_bb (def_stmt) == bb)
- gcc_assert (range_of_stmt (r, def_stmt, expr));
+ range_of_stmt (r, def_stmt, expr);
else
// Otherwise OP comes from outside this block, use range on entry.
range_on_entry (r, bb, expr);
@@ -933,7 +986,7 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
gcc_checking_assert (gimple_range_ssa_p (name));
// Start with any known range
- gcc_assert (range_of_stmt (r, SSA_NAME_DEF_STMT (name), name));
+ range_of_stmt (r, SSA_NAME_DEF_STMT (name), name);
// Now see if there is any on_entry value which may refine it.
if (m_cache.block_range (entry_range, bb, name))
@@ -948,6 +1001,7 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
{
// on-exit from the exit block?
gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
+ gcc_checking_assert (gimple_range_ssa_p (name));
gimple *s = last_stmt (bb);
// If there is no statement in the block and this isn't the entry
@@ -956,7 +1010,7 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
if (!s && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
range_on_entry (r, bb, name);
else
- gcc_assert (range_of_expr (r, name, s));
+ range_of_expr (r, name, s);
gcc_checking_assert (r.undefined_p ()
|| range_compatible_p (r.type (), TREE_TYPE (name)));
}
@@ -971,10 +1025,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
// PHI arguments can be constants, catch these here.
if (!gimple_range_ssa_p (name))
- {
- gcc_assert (range_of_expr (r, name));
- return true;
- }
+ return range_of_expr (r, name);
range_on_exit (r, e->src, name);
gcc_checking_assert (r.undefined_p ()
@@ -991,33 +1042,36 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
// provided it represents the SSA_NAME on the LHS of the statement.
// It is only required if there is more than one lhs/output. Check
// the global cache for NAME first to see if the evaluation can be
-// avoided. If a range cannot be calculated, return false.
+// avoided. If a range cannot be calculated, return false and UNDEFINED.
bool
gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
{
- // If no name, simply call the base routine.
+ r.set_undefined ();
+
if (!name)
name = gimple_get_lhs (s);
+ // If no name, simply call the base routine.
if (!name)
return calc_stmt (r, s, NULL_TREE);
- gcc_checking_assert (TREE_CODE (name) == SSA_NAME &&
- irange::supports_type_p (TREE_TYPE (name)));
+ if (!gimple_range_ssa_p (name))
+ return false;
- // If this STMT has already been processed, return that value.
- if (m_cache.m_globals.get_global_range (r, name))
+ // Check if the stmt has already been processed, and is not stale.
+ if (m_cache.get_non_stale_global_range (r, name))
return true;
- // Avoid infinite recursion by initializing global cache
- int_range_max tmp = gimple_range_global (name);
- m_cache.m_globals.set_global_range (name, tmp);
- gcc_assert (calc_stmt (r, s, name));
+ // Otherwise calculate a new value.
+ int_range_max tmp;
+ calc_stmt (tmp, s, name);
- if (is_a<gphi *> (s))
- r.intersect (tmp);
- m_cache.m_globals.set_global_range (name, r);
+ // Combine the new value with the old value. This is required because
+ // the way value propagation works, when the IL changes on the fly we
+ // can sometimes get different results. See PR 97741.
+ r.intersect (tmp);
+ m_cache.set_global_range (name, r);
return true;
}
@@ -1040,7 +1094,7 @@ gimple_ranger::export_global_ranges ()
tree name = ssa_name (x);
if (name && !SSA_NAME_IN_FREE_LIST (name)
&& gimple_range_ssa_p (name)
- && m_cache.m_globals.get_global_range (r, name)
+ && m_cache.get_global_range (r, name)
&& !r.varying_p())
{
// Make sure the new range is a subset of the old range.
@@ -1084,7 +1138,7 @@ gimple_ranger::dump (FILE *f)
edge e;
int_range_max range;
fprintf (f, "\n=========== BB %d ============\n", bb->index);
- m_cache.m_on_entry.dump (f, bb);
+ m_cache.dump (f, bb);
dump_bb (f, bb, 4, TDF_NONE);
@@ -1094,7 +1148,7 @@ gimple_ranger::dump (FILE *f)
tree name = ssa_name (x);
if (gimple_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) &&
gimple_bb (SSA_NAME_DEF_STMT (name)) == bb &&
- m_cache.m_globals.get_global_range (range, name))
+ m_cache.get_global_range (range, name))
{
if (!range.varying_p ())
{
@@ -1146,15 +1200,7 @@ gimple_ranger::dump (FILE *f)
}
}
- m_cache.m_globals.dump (dump_file);
- fprintf (f, "\n");
-
- if (dump_flags & TDF_DETAILS)
- {
- fprintf (f, "\nDUMPING GORI MAP\n");
- m_cache.dump (f);
- fprintf (f, "\n");
- }
+ m_cache.dump (dump_file, (dump_flags & TDF_DETAILS) != 0);
}
// If SCEV has any information about phi node NAME, return it as a range in R.