Refactor range handling of builtins in vr_values and ranger.

This sets things up so we can share range handling of builtins between
vr_values and ranger.  It is meant to refactor the code so that we can
verify that both implementations yield the same results.

First, we abstract out gimple_ranger::range_of_builtin_call into an externally
visible counterpart that can be called from vr_values.  It will take a
range_query since both ranger and vr_values inherit from this base class.

Then we abstract out all the builtin handling in vr_values into a separate
method that is easier to compare against.

Finally, we call the ranger version from vr_values and compare it with the
vr_values version.  Since this proves both versions return the same,
we can remove vr_values::extract_range_builtin in a follow-up patch.

The vr_values::range_of_expr change brings the vr_values version up to par
with the ranger version.  It should've handled non-SSA's.  This was
a small oversight that went unnoticed because the vr_value version isn't
stressed nearly as much as the ranger version.  The change is needed because
the ranger code handling builtins calls, may call it for integer arguments
in range_of_builtin_ubsan_call.

There should be no change in functionality.

gcc/ChangeLog:

	* gimple-range.cc (gimple_ranger::range_of_builtin_ubsan_call):
	Make externally visble...
	(range_of_builtin_ubsan_call): ...here.  Add range_query argument.
	(gimple_ranger::range_of_builtin_call): Make externally visible...
	(range_of_builtin_call): ...here.  Add range_query argument.
	* gimple-range.h (range_of_builtin_call): Move out from class and
	make externally visible.
	* vr-values.c (vr_values::extract_range_basic): Abstract out
	builtin handling to...
	(vr_values::range_of_expr): Handle non SSAs.
	(vr_values::extract_range_builtin): ...here.
	* vr-values.h (class vr_values): Add extract_range_builtin.
	(range_of_expr): Rename NAME to EXPR.
This commit is contained in:
Aldy Hernandez 2020-10-09 11:26:33 +02:00
parent 5d53ec2701
commit 16e4f1ad44
4 changed files with 306 additions and 271 deletions

View File

@ -552,9 +552,12 @@ gimple_ranger::range_of_call (irange &r, gcall *call)
return true;
}
// Return the range of a __builtin_ubsan* in CALL and set it in R.
// CODE is the type of ubsan call (PLUS_EXPR, MINUS_EXPR or
// MULT_EXPR).
void
gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
static void
range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
tree_code code)
{
gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
@ -565,8 +568,8 @@ gimple_ranger::range_of_builtin_ubsan_call (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 (range_of_expr (ir0, arg0, call));
gcc_assert (range_of_expr (ir1, arg1, call));
gcc_assert (query.range_of_expr (ir0, arg0, call));
gcc_assert (query.range_of_expr (ir1, arg1, call));
bool saved_flag_wrapv = flag_wrapv;
// Pretend the arithmetic is wrapping. If there is any overflow,
@ -582,9 +585,11 @@ gimple_ranger::range_of_builtin_ubsan_call (irange &r, gcall *call,
r.set_varying (type);
}
// For a builtin in CALL, return a range in R if known and return
// TRUE. Otherwise return FALSE.
bool
gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
range_of_builtin_call (range_query &query, irange &r, gcall *call)
{
combined_fn func = gimple_call_combined_fn (call);
if (func == CFN_LAST)
@ -605,7 +610,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
return true;
}
arg = gimple_call_arg (call, 0);
if (range_of_expr (r, arg, call) && r.singleton_p ())
if (query.range_of_expr (r, arg, call) && r.singleton_p ())
{
r.set (build_one_cst (type), build_one_cst (type));
return true;
@ -619,7 +624,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
prec = TYPE_PRECISION (TREE_TYPE (arg));
mini = 0;
maxi = prec;
gcc_assert (range_of_expr (r, arg, call));
gcc_assert (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;
@ -663,7 +668,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
}
}
gcc_assert (range_of_expr (r, arg, call));
gcc_assert (query.range_of_expr (r, arg, call));
// From clz of minimum we can compute result maximum.
if (r.constant_p ())
{
@ -728,7 +733,7 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
mini = -2;
}
}
gcc_assert (range_of_expr (r, arg, call));
gcc_assert (query.range_of_expr (r, arg, call));
if (!r.undefined_p ())
{
if (r.lower_bound () != 0)
@ -766,13 +771,13 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
r.set (build_int_cst (type, 0), build_int_cst (type, prec - 1));
return true;
case CFN_UBSAN_CHECK_ADD:
range_of_builtin_ubsan_call (r, call, PLUS_EXPR);
range_of_builtin_ubsan_call (query, r, call, PLUS_EXPR);
return true;
case CFN_UBSAN_CHECK_SUB:
range_of_builtin_ubsan_call (r, call, MINUS_EXPR);
range_of_builtin_ubsan_call (query, r, call, MINUS_EXPR);
return true;
case CFN_UBSAN_CHECK_MUL:
range_of_builtin_ubsan_call (r, call, MULT_EXPR);
range_of_builtin_ubsan_call (query, r, call, MULT_EXPR);
return true;
case CFN_GOACC_DIM_SIZE:
@ -822,6 +827,11 @@ gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
}
bool
gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
{
return ::range_of_builtin_call (*this, r, call);
}
// Calculate a range for COND_EXPR statement S and return it in R.
// If a range cannot be calculated, return false.

View File

@ -64,7 +64,6 @@ private:
bool range_of_phi (irange &r, gphi *phi);
bool range_of_non_trivial_assignment (irange &r, gimple *s);
bool range_of_builtin_call (irange &r, gcall *call);
void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code);
bool range_with_loop_info (irange &r, tree name);
void range_of_ssa_name_with_loop_info (irange &, tree, class loop *,
gphi *);
@ -179,4 +178,7 @@ private:
// Flag to enable debugging the various internal Caches.
#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG))
// Temporary external interface to share with vr_values.
bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
#endif // GCC_GIMPLE_RANGE_STMT_H

View File

@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#include "vr-values.h"
#include "cfghooks.h"
#include "range-op.h"
#include "gimple-range.h"
/* Set value range VR to a non-negative range of type TYPE. */
@ -174,9 +175,12 @@ vr_values::get_value_range (const_tree var,
}
bool
vr_values::range_of_expr (irange &r, tree name, gimple *stmt)
vr_values::range_of_expr (irange &r, tree expr, gimple *stmt)
{
if (const value_range *vr = get_value_range (name, stmt))
if (!gimple_range_ssa_p (expr))
return get_tree_range (r, expr);
if (const value_range *vr = get_value_range (expr, stmt))
{
if (vr->undefined_p () || vr->varying_p () || vr->constant_p ())
r = *vr;
@ -1151,18 +1155,14 @@ check_for_binary_op_overflow (range_query *query,
return true;
}
/* Try to derive a nonnegative or nonzero range out of STMT relying
primarily on generic routines in fold in conjunction with range data.
Store the result in *VR */
/* Derive a range from a builtin. Set range in VR and return TRUE if
successful. */
void
vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
bool
vr_values::extract_range_builtin (value_range_equiv *vr, gimple *stmt)
{
bool sop;
gcc_assert (is_gimple_call (stmt));
tree type = gimple_expr_type (stmt);
if (is_gimple_call (stmt))
{
tree arg;
int mini, maxi, zerov = 0, prec;
enum tree_code subcode = ERROR_MARK;
@ -1177,7 +1177,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
{
vr->set_zero (type);
vr->equiv_clear ();
return;
return true;
}
break;
/* Both __builtin_ffs* and __builtin_popcount return
@ -1340,7 +1340,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
goto bitop_builtin;
bitop_builtin:
vr->set (build_int_cst (type, mini), build_int_cst (type, maxi));
return;
return true;
case CFN_UBSAN_CHECK_ADD:
subcode = PLUS_EXPR;
break;
@ -1370,7 +1370,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
size
? build_int_cst (type, size - is_pos) : vrp_val_max (type));
}
return;
return true;
case CFN_BUILT_IN_STRLEN:
if (tree lhs = gimple_call_lhs (stmt))
if (ptrdiff_type_node
@ -1388,7 +1388,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
FIXME: Use max_object_size() - 1 here. */
tree range_max = wide_int_to_tree (type, wmax - 2);
vr->set (range_min, range_max);
return;
return true;
}
break;
default:
@ -1414,8 +1414,30 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
&& (vr->min () == vr->max ()
|| operand_equal_p (vr->min (), vr->max (), 0)))
vr->set_varying (vr->type ());
return;
return !vr->varying_p ();
}
return false;
}
/* Try to derive a nonnegative or nonzero range out of STMT relying
primarily on generic routines in fold in conjunction with range data.
Store the result in *VR */
void
vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
{
bool sop;
tree type = gimple_expr_type (stmt);
if (is_gimple_call (stmt) && extract_range_builtin (vr, stmt))
{
value_range_equiv tmp;
/* Assert that any ranges vr_values::extract_range_builtin gets
are also handled by the ranger counterpart. */
gcc_assert (range_of_builtin_call (*this, tmp, as_a<gcall *> (stmt)));
gcc_assert (tmp.equal_p (*vr, /*ignore_equivs=*/false));
return;
}
/* Handle extraction of the two results (result of arithmetics and
a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW

View File

@ -101,7 +101,7 @@ class vr_values : public range_query
vr_values (void);
~vr_values (void);
virtual bool range_of_expr (irange &r, tree name, gimple *stmt) OVERRIDE;
virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) OVERRIDE;
virtual tree value_of_expr (tree, gimple * = NULL) OVERRIDE;
virtual tree value_on_edge (edge, tree) OVERRIDE;
virtual tree value_of_stmt (gimple *, tree = NULL_TREE) OVERRIDE;
@ -148,6 +148,7 @@ class vr_values : public range_query
void extract_range_from_comparison (value_range_equiv *, gimple *);
void vrp_visit_assignment_or_call (gimple*, tree *, value_range_equiv *);
void vrp_visit_switch_stmt (gswitch *, edge *);
bool extract_range_builtin (value_range_equiv *, gimple *);
/* This probably belongs in the lattice rather than in here. */
bool values_propagated;