static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
static void maybe_emit_free_warning (tree);
static tree fold_builtin_object_size (tree, tree);
-static bool get_range (tree, signop, offset_int[2], const vr_values * = NULL);
+static bool get_range (tree, gimple *, signop, offset_int[2],
+ range_query * = NULL);
static bool check_read_access (tree, tree, tree = NULL_TREE, int = 1);
unsigned HOST_WIDE_INT target_newline;
tree
gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
- const vr_values *rvals /* = NULL */)
+ range_query *rvals /* = NULL */)
{
if (!stmt)
return NULL_TREE;
const int prec = ADDR_MAX_PRECISION;
const tree size_max = TYPE_MAX_VALUE (sizetype);
- if (!get_range (size, rng1, rvals))
+ if (!get_range (size, stmt, rng1, rvals))
{
/* Use the full non-negative range on failure. */
rng1[0] = wi::zero (prec);
of the upper bounds as a constant. Ignore anti-ranges. */
tree n = argidx2 < nargs ? gimple_call_arg (stmt, argidx2) : integer_one_node;
wide_int rng2[2];
- if (!get_range (n, rng2, rvals))
+ if (!get_range (n, stmt, rng2, rvals))
{
/* As above, use the full non-negative range on failure. */
rng2[0] = wi::zero (prec);
Return the function parameter on success and null otherwise. */
tree
-gimple_parm_array_size (tree ptr, wide_int rng[2],
- const vr_values * /* = NULL */)
+gimple_parm_array_size (tree ptr, wide_int rng[2], range_query * /* = NULL */)
{
/* For a function argument try to determine the byte size of the array
from the current function declaratation (e.g., attribute access or
result but accepts offset_int instead. */
static bool
-get_range (tree x, signop sgn, offset_int r[2],
- const vr_values *rvals /* = NULL */)
+get_range (tree x, gimple *stmt, signop sgn, offset_int r[2],
+ range_query *rvals /* = NULL */)
{
wide_int wr[2];
- if (!get_range (x, wr, rvals))
+ if (!get_range (x, stmt, wr, rvals))
return false;
r[0] = offset_int::from (wr[0], sgn);
static bool
compute_objsize (tree ptr, int ostype, access_ref *pref,
- bitmap *visited, const vr_values *rvals /* = NULL */)
+ bitmap *visited, range_query *rvals /* = NULL */)
{
const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
if (addr)
offset_int orng[2];
tree off = TREE_OPERAND (ptr, 1);
- if (!get_range (off, SIGNED, orng, rvals))
+ if (!get_range (off, NULL, SIGNED, orng, rvals))
/* Fail unless the size of the object is zero. */
return pref->sizrng[0] == 0 && pref->sizrng[0] == pref->sizrng[1];
offset to the maximum. */
offset_int orng[2];
tree off = gimple_assign_rhs2 (stmt);
- if (!get_range (off, SIGNED, orng, rvals))
+ if (!get_range (off, stmt, SIGNED, orng, rvals))
{
orng[0] = wi::to_offset (TYPE_MIN_VALUE (ptrdiff_type_node));
orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
&& !array_at_struct_end_p (ptr))
{
if (tree size = TYPE_SIZE_UNIT (type))
- return get_range (size, UNSIGNED, pref->sizrng, rvals);
+ return get_range (size, NULL, UNSIGNED, pref->sizrng, rvals);
}
return false;
tree
compute_objsize (tree ptr, int ostype, access_ref *pref,
- const vr_values *rvals /* = NULL */)
+ range_query *rvals /* = NULL */)
{
bitmap visited = NULL;
tree
compute_objsize (tree ptr, int ostype, tree *pdecl /* = NULL */,
- tree *poff /* = NULL */, const vr_values *rvals /* = NULL */)
+ tree *poff /* = NULL */, class range_query *rvals /* = NULL */)
{
/* Set the initial offsets to zero and size to negative to indicate
none has been computed yet. */
access_mode mode;
};
-class vr_values;
+class range_query;
extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
- const vr_values * = NULL);
-extern tree gimple_parm_array_size (tree, wide_int[2], const vr_values * = NULL);
+ range_query * = NULL);
+extern tree gimple_parm_array_size (tree, wide_int[2], range_query * = NULL);
extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL,
- const vr_values * = NULL);
-extern tree compute_objsize (tree, int, access_ref *, const vr_values * = NULL);
+ range_query * = NULL);
+extern tree compute_objsize (tree, int, access_ref *, range_query * = NULL);
extern bool check_access (tree, tree, tree, tree, tree, access_mode,
const access_data * = NULL);
}
static bool
-get_int_range (tree, HOST_WIDE_INT *, HOST_WIDE_INT *, bool, HOST_WIDE_INT,
- const vr_values *);
+get_int_range (tree, gimple *, HOST_WIDE_INT *, HOST_WIDE_INT *,
+ bool, HOST_WIDE_INT, range_query *);
struct call_info;
/* Format conversion function that given a directive and an argument
returns the formatting result. */
- fmtresult (*fmtfunc) (const directive &, tree, const vr_values *);
+ fmtresult (*fmtfunc) (const directive &, tree, range_query *);
/* Return True when the format flag CHR has been used. */
bool get_flag (char chr) const
or 0, whichever is greater. For a non-constant ARG in some range
set width to its range adjusting each bound to -1 if it's less.
For an indeterminate ARG set width to [0, INT_MAX]. */
- void set_width (tree arg, const vr_values *vr)
- {
- get_int_range (arg, width, width + 1, true, 0, vr);
- }
+ void set_width (tree arg, range_query *);
/* Set both bounds of the precision range to VAL. */
void set_precision (HOST_WIDE_INT val)
or -1 whichever is greater. For a non-constant ARG in some range
set precision to its range adjusting each bound to -1 if it's less.
For an indeterminate ARG set precision to [-1, INT_MAX]. */
- void set_precision (tree arg, const vr_values *vr)
- {
- get_int_range (arg, prec, prec + 1, false, -1, vr);
- }
+ void set_precision (tree arg, range_query *query);
/* Return true if both width and precision are known to be
either constant or in some range, false otherwise. */
}
};
+void
+directive::set_width (tree arg, range_query *query)
+{
+ get_int_range (arg, info->callstmt, width, width + 1, true, 0, query);
+}
+
+void
+directive::set_precision (tree arg, range_query *query)
+{
+ get_int_range (arg, info->callstmt, prec, prec + 1, false, -1, query);
+}
+
/* Return the result of formatting a no-op directive (such as '%n'). */
static fmtresult
-format_none (const directive &, tree, const vr_values *)
+format_none (const directive &, tree, range_query *)
{
fmtresult res (0);
return res;
/* Return the result of formatting the '%%' directive. */
static fmtresult
-format_percent (const directive &, tree, const vr_values *)
+format_percent (const directive &, tree, range_query *)
{
fmtresult res (1);
return res;
the determined range are replaced with NEGBOUND. */
static bool
-get_int_range (tree arg, HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
+get_int_range (tree arg, gimple *stmt,
+ HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax,
bool absolute, HOST_WIDE_INT negbound,
- const class vr_values *vr_values)
+ range_query *query)
{
/* The type of the result. */
const_tree type = integer_type_node;
&& TYPE_PRECISION (argtype) <= TYPE_PRECISION (type))
{
/* Try to determine the range of values of the integer argument. */
- const value_range_equiv *vr
- = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg);
+ value_range vr;
+ query->range_of_expr (vr, arg, stmt);
- if (!vr->undefined_p () && !vr->varying_p () && !vr->symbolic_p ())
+ if (!vr.undefined_p () && !vr.varying_p ())
{
HOST_WIDE_INT type_min
= (TYPE_UNSIGNED (argtype)
HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype));
tree type = TREE_TYPE (arg);
- tree tmin = wide_int_to_tree (type, vr->lower_bound ());
- tree tmax = wide_int_to_tree (type, vr->upper_bound ());
+ tree tmin = wide_int_to_tree (type, vr.lower_bound ());
+ tree tmax = wide_int_to_tree (type, vr.upper_bound ());
*pmin = TREE_INT_CST_LOW (tmin);
*pmax = TREE_INT_CST_LOW (tmax);
/* Handle an argument with an unknown range as if none had been
provided. */
if (unknown)
- return get_int_range (NULL_TREE, pmin, pmax, absolute,
- negbound, vr_values);
+ return get_int_range (NULL_TREE, NULL, pmin, pmax, absolute,
+ negbound, query);
}
/* Adjust each bound as specified by ABSOLUTE and NEGBOUND. */
used when the directive argument or its value isn't known. */
static fmtresult
-format_integer (const directive &dir, tree arg, const vr_values *vr_values)
+format_integer (const directive &dir, tree arg, range_query *query)
{
tree intmax_type_node;
tree uintmax_type_node;
{
/* Try to determine the range of values of the integer argument
(range information is not available for pointers). */
- const value_range_equiv *vr
- = CONST_CAST (class vr_values *, vr_values)->get_value_range (arg);
+ value_range vr;
+ query->range_of_expr (vr, arg, dir.info->callstmt);
- if (!vr->varying_p () && !vr->undefined_p () && !vr->symbolic_p ())
+ if (!vr.varying_p () && !vr.undefined_p ())
{
- argmin = wide_int_to_tree (TREE_TYPE (arg), vr->lower_bound ());
- argmax = wide_int_to_tree (TREE_TYPE (arg), vr->upper_bound ());
+ argmin = wide_int_to_tree (TREE_TYPE (arg), vr.lower_bound ());
+ argmax = wide_int_to_tree (TREE_TYPE (arg), vr.upper_bound ());
/* Set KNOWNRANGE if the argument is in a known subrange
of the directive's type and neither width nor precision
if (code == INTEGER_CST)
{
arg = gimple_assign_rhs1 (def);
- return format_integer (dir, arg, vr_values);
+ return format_integer (dir, arg, query);
}
if (code == NOP_EXPR)
/* For unsigned conversions/directives or signed when
the minimum is positive, use the minimum and maximum to compute
the shortest and longest output, respectively. */
- res.range.min = format_integer (dir, argmin, vr_values).range.min;
- res.range.max = format_integer (dir, argmax, vr_values).range.max;
+ res.range.min = format_integer (dir, argmin, query).range.min;
+ res.range.max = format_integer (dir, argmax, query).range.max;
}
else if (tree_int_cst_sgn (argmax) < 0)
{
/* For signed conversions/directives if maximum is negative,
use the minimum as the longest output and maximum as the
shortest output. */
- res.range.min = format_integer (dir, argmax, vr_values).range.min;
- res.range.max = format_integer (dir, argmin, vr_values).range.max;
+ res.range.min = format_integer (dir, argmax, query).range.min;
+ res.range.max = format_integer (dir, argmin, query).range.max;
}
else
{
length of the output of both minimum and maximum and pick the
longer. */
unsigned HOST_WIDE_INT max1
- = format_integer (dir, argmin, vr_values).range.max;
+ = format_integer (dir, argmin, query).range.max;
unsigned HOST_WIDE_INT max2
- = format_integer (dir, argmax, vr_values).range.max;
+ = format_integer (dir, argmax, query).range.max;
res.range.min
- = format_integer (dir, integer_zero_node, vr_values).range.min;
+ = format_integer (dir, integer_zero_node, query).range.min;
res.range.max = MAX (max1, max2);
}
ARG. */
static fmtresult
-format_floating (const directive &dir, tree arg, const vr_values *)
+format_floating (const directive &dir, tree arg, range_query *)
{
HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] };
tree type = (dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll
Used by the format_string function below. */
static fmtresult
-get_string_length (tree str, unsigned eltsize, const vr_values *vr)
+get_string_length (tree str, gimple *stmt, unsigned eltsize,
+ range_query *query)
{
if (!str)
return fmtresult ();
c_strlen_data lendata = { };
lendata.maxbound = str;
if (eltsize == 1)
- get_range_strlen_dynamic (str, &lendata, vr);
+ get_range_strlen_dynamic (str, stmt, &lendata, query);
else
{
/* Determine the length of the shortest and longest string referenced
vsprinf). */
static fmtresult
-format_character (const directive &dir, tree arg, const vr_values *vr_values)
+format_character (const directive &dir, tree arg, range_query *query)
{
fmtresult res;
res.range.min = 0;
HOST_WIDE_INT min, max;
- if (get_int_range (arg, &min, &max, false, 0, vr_values))
+ if (get_int_range (arg, dir.info->callstmt, &min, &max, false, 0, query))
{
if (min == 0 && max == 0)
{
vsprinf). */
static fmtresult
-format_string (const directive &dir, tree arg, const vr_values *vr_values)
+format_string (const directive &dir, tree arg, range_query *query)
{
fmtresult res;
gcc_checking_assert (count_by == 2 || count_by == 4);
}
- fmtresult slen = get_string_length (arg, count_by, vr_values);
+ fmtresult slen = get_string_length (arg, dir.info->callstmt, count_by, query);
if (slen.range.min == slen.range.max
&& slen.range.min < HOST_WIDE_INT_MAX)
{
/* Format plain string (part of the format string itself). */
static fmtresult
-format_plain (const directive &dir, tree, const vr_values *)
+format_plain (const directive &dir, tree, range_query *)
{
fmtresult res (dir.len);
return res;
static bool
format_directive (const call_info &info,
format_result *res, const directive &dir,
- const class vr_values *vr_values)
+ range_query *query)
{
/* Offset of the beginning of the directive from the beginning
of the format string. */
return false;
/* Compute the range of lengths of the formatted output. */
- fmtresult fmtres = dir.fmtfunc (dir, dir.arg, vr_values);
+ fmtresult fmtres = dir.fmtfunc (dir, dir.arg, query);
/* Record whether the output of all directives is known to be
bounded by some maximum, implying that their arguments are
parse_directive (call_info &info,
directive &dir, format_result *res,
const char *str, unsigned *argno,
- const vr_values *vr_values)
+ range_query *query)
{
const char *pcnt = strchr (str, target_percent);
dir.beg = str;
if (star_width)
{
if (INTEGRAL_TYPE_P (TREE_TYPE (star_width)))
- dir.set_width (star_width, vr_values);
+ dir.set_width (star_width, query);
else
{
/* Width specified by a va_list takes on the range [0, -INT_MIN]
if (star_precision)
{
if (INTEGRAL_TYPE_P (TREE_TYPE (star_precision)))
- dir.set_precision (star_precision, vr_values);
+ dir.set_precision (star_precision, query);
else
{
/* Precision specified by a va_list takes on the range [-1, INT_MAX]
that caused the processing to be terminated early). */
static bool
-compute_format_length (call_info &info, format_result *res, const vr_values *vr)
+compute_format_length (call_info &info, format_result *res, range_query *query)
{
if (dump_file)
{
{
directive dir (&info, dirno);
- size_t n = parse_directive (info, dir, res, pf, &argno, vr);
+ size_t n = parse_directive (info, dir, res, pf, &argno, query);
/* Return failure if the format function fails. */
- if (!format_directive (info, res, dir, vr))
+ if (!format_directive (info, res, dir, query))
return false;
/* Return success when the directive is zero bytes long and it's
gsi_next should not be performed in the caller. */
bool
-handle_printf_call (gimple_stmt_iterator *gsi, const vr_values *vr_values)
+handle_printf_call (gimple_stmt_iterator *gsi, range_query *query)
{
init_target_to_host_charmap ();
/* Try to determine the range of values of the argument
and use the greater of the two at level 1 and the smaller
of them at level 2. */
- const value_range_equiv *vr
- = CONST_CAST (class vr_values *, vr_values)->get_value_range (size);
+ value_range vr;
+ query->range_of_expr (vr, size, info.callstmt);
- if (!vr->undefined_p () && !vr->symbolic_p ())
+ if (!vr.undefined_p ())
{
tree type = TREE_TYPE (size);
- tree tmin = wide_int_to_tree (type, vr->lower_bound ());
- tree tmax = wide_int_to_tree (type, vr->upper_bound ());
+ tree tmin = wide_int_to_tree (type, vr.lower_bound ());
+ tree tmax = wide_int_to_tree (type, vr.upper_bound ());
unsigned HOST_WIDE_INT minsize = TREE_INT_CST_LOW (tmin);
unsigned HOST_WIDE_INT maxsize = TREE_INT_CST_LOW (tmax);
dstsize = warn_level < 2 ? maxsize : minsize;
never set to true again). */
res.posunder4k = posunder4k && dstptr;
- bool success = compute_format_length (info, &res, vr_values);
+ bool success = compute_format_length (info, &res, query);
if (res.warned)
gimple_set_no_warning (info.callstmt, true);
to determine the range, otherwise get_range_info. */
tree
-get_range (tree val, wide_int minmax[2], const vr_values *rvals /* = NULL */)
+get_range (tree val, gimple *stmt, wide_int minmax[2],
+ range_query *rvals /* = NULL */)
{
if (TREE_CODE (val) == INTEGER_CST)
{
if (TREE_CODE (val) != SSA_NAME)
return NULL_TREE;
- if (rvals)
- {
- /* The range below may be "inaccurate" if a constant has been
- substituted earlier for VAL by this pass that hasn't been
- propagated through the CFG. This shoud be fixed by the new
- on-demand VRP if/when it becomes available (hopefully in
- GCC 11). */
- const value_range *vr
- = (CONST_CAST (class vr_values *, rvals)->get_value_range (val));
- value_range_kind rng = vr->kind ();
- if (rng != VR_RANGE || !range_int_cst_p (vr))
+ if (rvals && stmt)
+ {
+ value_range vr;
+ if (!rvals->range_of_expr (vr, val, stmt))
+ return NULL_TREE;
+ value_range_kind rng = vr.kind ();
+ if (rng != VR_RANGE)
return NULL_TREE;
- minmax[0] = wi::to_wide (vr->min ());
- minmax[1] = wi::to_wide (vr->max ());
+ minmax[0] = wi::to_wide (vr.min ());
+ minmax[1] = wi::to_wide (vr.max ());
return val;
}
static int
compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off,
- const vr_values *rvals)
+ range_query *rvals)
{
if (!si->nonzero_chars)
return -1;
if (!rvals || TREE_CODE (si->nonzero_chars) != SSA_NAME)
return -1;
- const value_range_equiv *vr
- = (CONST_CAST (class vr_values *, rvals)
- ->get_value_range (si->nonzero_chars));
-
- value_range_kind rng = vr->kind ();
- if (rng != VR_RANGE || !range_int_cst_p (vr))
+ value_range vr;
+ if (!rvals->range_of_expr (vr, si->nonzero_chars, si->stmt))
+ return -1;
+ value_range_kind rng = vr.kind ();
+ if (rng != VR_RANGE)
return -1;
/* If the offset is less than the minimum length or if the bounds
of the length range are equal return the result of the comparison
same as in the constant case. Otherwise return a conservative
result. */
- int cmpmin = compare_tree_int (vr->min (), off);
- if (cmpmin > 0 || tree_int_cst_equal (vr->min (), vr->max ()))
+ int cmpmin = compare_tree_int (vr.min (), off);
+ if (cmpmin > 0 || tree_int_cst_equal (vr.min (), vr.max ()))
return cmpmin;
return -1;
static int
get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out,
- const vr_values *rvals = NULL)
+ range_query *rvals = NULL)
{
HOST_WIDE_INT off;
struct stridxlist *list, *last = NULL;
When nonnull, uses RVALS to determine range information. */
static int
-get_stridx (tree exp, wide_int offrng[2] = NULL, const vr_values *rvals = NULL)
+get_stridx (tree exp, wide_int offrng[2] = NULL, range_query *rvals = NULL)
{
if (offrng)
offrng[0] = offrng[1] = wi::zero (TYPE_PRECISION (ptrdiff_type_node));
return the index corresponding to the SSA_NAME.
Do this irrespective of the whether the offset
is known. */
- if (get_range (off, offrng, rvals))
+ if (get_range (off, def_stmt, offrng, rvals))
{
/* When the offset range is known, increment it
it by the constant offset computed in prior
}
/* Dump strlen data to FP for statement STMT. When non-null, RVALS
- points to EVRP info and is used to dump strlen range for non-constant
- results. */
+ points to the valuation engine used to calculate ranges, and is
+ used to dump strlen range for non-constant results. */
DEBUG_FUNCTION void
-dump_strlen_info (FILE *fp, gimple *stmt, const vr_values *rvals)
+dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
{
if (stmt)
{
wide_int min, max;
if (rvals)
{
- const value_range *vr
- = CONST_CAST (class vr_values *, rvals)
- ->get_value_range (si->nonzero_chars);
- rng = vr->kind ();
- if (range_int_cst_p (vr))
+ value_range vr;
+ rvals->range_of_expr (vr, si->nonzero_chars,
+ si->stmt);
+ rng = vr.kind ();
+ if (range_int_cst_p (&vr))
{
- min = wi::to_wide (vr->min ());
- max = wi::to_wide (vr->max ());
+ min = wi::to_wide (vr.min ());
+ max = wi::to_wide (vr.max ());
}
else
rng = VR_UNDEFINED;
/* Attempt to determine the length of the string SRC. On success, store
the length in *PDATA and return true. Otherwise, return false.
- VISITED is a bitmap of visited PHI nodes. RVALS points to EVRP info
- and PSSA_DEF_MAX to an SSA_NAME assignment limit used to prevent runaway
- recursion. */
+ VISITED is a bitmap of visited PHI nodes. RVALS points to the valuation
+ engine used to calculate ranges. PSSA_DEF_MAX to an SSA_NAME
+ assignment limit used to prevent runaway recursion. */
static bool
-get_range_strlen_dynamic (tree src, c_strlen_data *pdata, bitmap *visited,
- const vr_values *rvals, unsigned *pssa_def_max)
+get_range_strlen_dynamic (tree src, gimple *stmt,
+ c_strlen_data *pdata, bitmap *visited,
+ range_query *rvals, unsigned *pssa_def_max)
{
int idx = get_stridx (src);
if (!idx)
continue;
c_strlen_data argdata = { };
- if (get_range_strlen_dynamic (arg, &argdata, visited, rvals,
- pssa_def_max))
+ if (get_range_strlen_dynamic (arg, phi, &argdata, visited,
+ rvals, pssa_def_max))
{
/* Set the DECL of an unterminated array this argument
refers to if one hasn't been found yet. */
pdata->minlen = si->nonzero_chars;
else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
{
- const value_range_equiv *vr
- = CONST_CAST (class vr_values *, rvals)
- ->get_value_range (si->nonzero_chars);
- if (vr->kind () == VR_RANGE
- && range_int_cst_p (vr))
+ value_range vr;
+ rvals->range_of_expr (vr, si->nonzero_chars, si->stmt);
+ if (range_int_cst_p (&vr))
{
- pdata->minlen = vr->min ();
- pdata->maxlen = vr->max ();
+ pdata->minlen = vr.min ();
+ pdata->maxlen = vr.max ();
}
else
pdata->minlen = build_zero_cst (size_type_node);
}
else if (pdata->minlen && TREE_CODE (pdata->minlen) == SSA_NAME)
{
- const value_range_equiv *vr
- = CONST_CAST (class vr_values *, rvals)
- ->get_value_range (si->nonzero_chars);
- if (vr->kind () == VR_RANGE
- && range_int_cst_p (vr))
+ value_range vr;
+ rvals->range_of_expr (vr, si->nonzero_chars, stmt);
+ if (range_int_cst_p (&vr))
{
- pdata->minlen = vr->min ();
- pdata->maxlen = vr->max ();
+ pdata->minlen = vr.min ();
+ pdata->maxlen = vr.max ();
pdata->maxbound = pdata->maxlen;
}
else
Try to obtain the range of the lengths of the string(s) referenced
by SRC, or the size of the largest array SRC refers to if the range
of lengths cannot be determined, and store all in *PDATA. RVALS
- points to EVRP info. */
+ points to the valuation engine used to calculate ranges. */
void
-get_range_strlen_dynamic (tree src, c_strlen_data *pdata,
- const vr_values *rvals)
+get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata,
+ range_query *rvals)
{
bitmap visited = NULL;
tree maxbound = pdata->maxbound;
unsigned limit = param_ssa_name_def_chain_limit;
- if (!get_range_strlen_dynamic (src, pdata, &visited, rvals, &limit))
+ if (!get_range_strlen_dynamic (src, stmt, pdata, &visited, rvals, &limit))
{
/* On failure extend the length range to an impossible maximum
(a valid MAXLEN must be less than PTRDIFF_MAX - 1). Other
else if (TREE_CODE (bound) == SSA_NAME)
{
wide_int minbound, maxbound;
+ // FIXME: Use range_query instead of global ranges.
value_range_kind rng = get_range_info (bound, &minbound, &maxbound);
if (rng == VR_RANGE)
{
static void
maybe_warn_overflow (gimple *stmt, tree len,
- const vr_values *rvals = NULL,
+ range_query *rvals = NULL,
strinfo *si = NULL, bool plus_one = false,
bool rawmem = false)
{
tree off = TREE_OPERAND (ref, 1);
ref = TREE_OPERAND (ref, 0);
wide_int rng[2];
- if (get_range (off, rng, rvals))
+ if (get_range (off, stmt, rng, rvals))
{
/* Convert offsets to the maximum precision. */
offrng[0] = widest_int::from (rng[0], SIGNED);
tree mem_off = TREE_OPERAND (ref, 1);
ref = TREE_OPERAND (ref, 0);
wide_int rng[2];
- if (get_range (mem_off, rng, rvals))
+ if (get_range (mem_off, stmt, rng, rvals))
{
offrng[0] += widest_int::from (rng[0], SIGNED);
offrng[1] += widest_int::from (rng[1], SIGNED);
}
wide_int rng[2];
- if (get_range (destsize, rng, rvals))
+ if (get_range (destsize, stmt, rng, rvals))
{
sizrng[0] = widest_int::from (rng[0], UNSIGNED);
sizrng[1] = widest_int::from (rng[1], UNSIGNED);
return;
wide_int rng[2];
- if (!get_range (len, rng, rvals))
+ if (!get_range (len, stmt, rng, rvals))
return;
widest_int lenrng[2] =
if (destoff)
{
wide_int rng[2];
- if (get_range (destoff, rng))
+ if (get_range (destoff, stmt, rng))
{
offrng[0] = widest_int::from (rng[0], SIGNED);
offrng[1] = widest_int::from (rng[1], SIGNED);
static inline void
maybe_warn_overflow (gimple *stmt, unsigned HOST_WIDE_INT len,
- const vr_values *rvals = NULL, strinfo *si = NULL,
+ range_query *rvals = NULL, strinfo *si = NULL,
bool plus_one = false, bool rawmem = false)
{
maybe_warn_overflow (stmt, build_int_cst (size_type_node, len), rvals,
static void
handle_builtin_strcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi,
- const vr_values *rvals)
+ range_query *rvals)
{
int idx, didx;
tree src, dst, srclen, len, lhs, type, fn, oldlen;
cntrange[0] = cntrange[1] = wi::to_wide (cnt);
else if (TREE_CODE (cnt) == SSA_NAME)
{
+ // FIXME: Use range_query instead of global ranges.
enum value_range_kind rng = get_range_info (cnt, cntrange, cntrange + 1);
if (rng == VR_RANGE)
;
static void
handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi,
- const vr_values *rvals)
+ range_query *rvals)
{
tree lhs, oldlen, newlen;
gimple *stmt = gsi_stmt (*gsi);
static bool
handle_builtin_memset (gimple_stmt_iterator *gsi, bool *zero_write,
- const vr_values *rvals)
+ range_query *rvals)
{
gimple *memset_stmt = gsi_stmt (*gsi);
tree ptr = gimple_call_arg (memset_stmt, 0);
determine range information. Returns true on success. */
static bool
-get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
+get_len_or_size (gimple *stmt, tree arg, int idx,
+ unsigned HOST_WIDE_INT lenrng[2],
unsigned HOST_WIDE_INT *size, bool *nulterm,
- const vr_values *rvals)
+ range_query *rvals)
{
/* Invalidate. */
*size = HOST_WIDE_INT_M1U;
else if (TREE_CODE (si->nonzero_chars) == SSA_NAME)
{
wide_int min, max;
+ // FIXME: Use range_query instead of global ranges.
value_range_kind rng = get_range_info (si->nonzero_chars, &min, &max);
if (rng == VR_RANGE)
{
/* Set MAXBOUND to an arbitrary non-null non-integer node as a request
to have it set to the length of the longest string in a PHI. */
lendata.maxbound = arg;
- get_range_strlen_dynamic (arg, &lendata, rvals);
+ get_range_strlen_dynamic (arg, stmt, &lendata, rvals);
unsigned HOST_WIDE_INT maxbound = HOST_WIDE_INT_M1U;
if (tree_fits_uhwi_p (lendata.maxbound)
Otherwise return null. */
static tree
-strxcmp_eqz_result (tree arg1, int idx1, tree arg2, int idx2,
+strxcmp_eqz_result (gimple *stmt, tree arg1, int idx1, tree arg2, int idx2,
unsigned HOST_WIDE_INT bound, unsigned HOST_WIDE_INT len[2],
- unsigned HOST_WIDE_INT *psize, const vr_values *rvals)
+ unsigned HOST_WIDE_INT *psize, range_query *rvals)
{
/* Determine the range the length of each string is in and whether it's
known to be nul-terminated, or the size of the array it's stored in. */
bool nul1, nul2;
unsigned HOST_WIDE_INT siz1, siz2;
unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
- if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1, rvals)
- || !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2, rvals))
+ if (!get_len_or_size (stmt, arg1, idx1, len1rng, &siz1, &nul1, rvals)
+ || !get_len_or_size (stmt, arg2, idx2, len2rng, &siz2, &nul2, rvals))
return NULL_TREE;
/* BOUND is set to HWI_M1U for strcmp and less to strncmp, and LENiRNG
another and false otherwise. */
static bool
-handle_builtin_string_cmp (gimple_stmt_iterator *gsi, const vr_values *rvals)
+handle_builtin_string_cmp (gimple_stmt_iterator *gsi, range_query *rvals)
{
gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
tree lhs = gimple_call_lhs (stmt);
/* Try to determine if the two strings are either definitely equal
or definitely unequal and if so, either fold the result to zero
(when equal) or set the range of the result to ~[0, 0] otherwise. */
- if (tree eqz = strxcmp_eqz_result (arg1, idx1, arg2, idx2, bound,
+ if (tree eqz = strxcmp_eqz_result (stmt, arg1, idx1, arg2, idx2, bound,
len, &siz, rvals))
{
if (integer_zerop (eqz))
unsigned HOST_WIDE_INT arsz1, arsz2;
bool nulterm[2];
- if (!get_len_or_size (arg1, idx1, len1rng, &arsz1, nulterm, rvals)
- || !get_len_or_size (arg2, idx2, len2rng, &arsz2, nulterm + 1, rvals))
+ if (!get_len_or_size (stmt, arg1, idx1, len1rng, &arsz1, nulterm, rvals)
+ || !get_len_or_size (stmt, arg2, idx2, len2rng, &arsz2, nulterm + 1,
+ rvals))
return false;
if (len1rng[0] == len1rng[1] && len1rng[0] < HOST_WIDE_INT_MAX)
static bool
count_nonzero_bytes_addr (tree, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
unsigned [3], bool *, bool *, bool *,
- const vr_values *, ssa_name_limit_t &);
+ range_query *, ssa_name_limit_t &);
/* Determines the minimum and maximum number of leading non-zero bytes
in the representation of EXP and set LENRANGE[0] and LENRANGE[1]
count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT nbytes,
unsigned lenrange[3], bool *nulterm,
- bool *allnul, bool *allnonnul, const vr_values *rvals,
+ bool *allnul, bool *allnonnul, range_query *rvals,
ssa_name_limit_t &snlim)
{
if (TREE_CODE (exp) == SSA_NAME)
unsigned HOST_WIDE_INT nbytes,
unsigned lenrange[3], bool *nulterm,
bool *allnul, bool *allnonnul,
- const vr_values *rvals, ssa_name_limit_t &snlim)
+ range_query *rvals, ssa_name_limit_t &snlim)
{
int idx = get_stridx (exp);
if (idx > 0)
else if (si->nonzero_chars
&& TREE_CODE (si->nonzero_chars) == SSA_NAME)
{
- vr_values *v = CONST_CAST (vr_values *, rvals);
- const value_range_equiv *vr = v->get_value_range (si->nonzero_chars);
- if (vr->kind () != VR_RANGE || !range_int_cst_p (vr))
+ value_range vr;
+ rvals->range_of_expr (vr, si->nonzero_chars, si->stmt);
+ if (vr.kind () != VR_RANGE)
return false;
- minlen = tree_to_uhwi (vr->min ());
- maxlen = tree_to_uhwi (vr->max ());
+ minlen = tree_to_uhwi (vr.min ());
+ maxlen = tree_to_uhwi (vr.max ());
}
else
return false;
static bool
count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
- bool *allnul, bool *allnonnul, const vr_values *rvals)
+ bool *allnul, bool *allnonnul, range_query *rvals)
{
/* Set to optimistic values so the caller doesn't have to worry about
initializing these and to what. On success, the function will clear
static bool
handle_store (gimple_stmt_iterator *gsi, bool *zero_write,
- const vr_values *rvals)
+ range_query *rvals)
{
int idx = -1;
strinfo *si = NULL;
static bool
strlen_check_and_optimize_call (gimple_stmt_iterator *gsi, bool *zero_write,
- const vr_values *rvals)
+ range_query *rvals)
{
gimple *stmt = gsi_stmt (*gsi);
static void
handle_integral_assign (gimple_stmt_iterator *gsi, bool *cleanup_eh,
- const vr_values *rvals)
+ range_query *rvals)
{
gimple *stmt = gsi_stmt (*gsi);
tree lhs = gimple_assign_lhs (stmt);
wide_int min, max;
signop sign = TYPE_SIGN (lhs_type);
int prec = TYPE_PRECISION (lhs_type);
+ // FIXME: Use range_query instead of global ranges.
value_range_kind vr = get_range_info (lhs, &min, &max);
if (vr == VR_VARYING
|| (vr == VR_RANGE
static bool
check_and_optimize_stmt (gimple_stmt_iterator *gsi, bool *cleanup_eh,
- const vr_values *rvals)
+ range_query *rvals)
{
gimple *stmt = gsi_stmt (*gsi);
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
extern tree set_strlen_range (tree, wide_int, wide_int, tree = NULL_TREE);
-class vr_values;
-extern tree get_range (tree, wide_int[2], const vr_values * = NULL);
+extern tree get_range (tree, gimple *, wide_int[2],
+ class range_query * = NULL);
struct c_strlen_data;
-extern void get_range_strlen_dynamic (tree , c_strlen_data *, const vr_values *);
+extern void get_range_strlen_dynamic (tree, gimple *, c_strlen_data *,
+ class range_query *);
/* APIs internal to strlen pass. Defined in gimple-ssa-sprintf.c. */
-extern bool handle_printf_call (gimple_stmt_iterator *, const vr_values *);
+extern bool handle_printf_call (gimple_stmt_iterator *, class range_query *);
#endif // GCC_TREE_SSA_STRLEN_H