#include "tree-ssa-loop.h"
#include "tree-scalar-evolution.h"
#include "vr-values.h"
-#include "gimple-ssa-evrp-analyze.h"
+#include "gimple-range.h"
#include "tree-ssa.h"
/* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
public:
strlen_pass (cdi_direction direction)
: dom_walker (direction),
- evrp (false),
- ptr_qry (&evrp, &var_cache),
+ ptr_qry (&m_ranger, &var_cache),
var_cache (),
m_cleanup_cfg (false)
{
unsigned HOST_WIDE_INT len[2],
unsigned HOST_WIDE_INT *psize);
bool count_nonzero_bytes (tree expr_or_type,
+ gimple *stmt,
unsigned lenrange[3], bool *nulterm,
bool *allnul, bool *allnonnul);
bool count_nonzero_bytes (tree exp,
+ gimple *stmt,
unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT nbytes,
unsigned lenrange[3], bool *nulterm,
bool *allnul, bool *allnonnul,
ssa_name_limit_t &snlim);
bool count_nonzero_bytes_addr (tree exp,
+ gimple *stmt,
unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT nbytes,
unsigned lenrange[3], bool *nulterm,
unsigned HOST_WIDE_INT lenrng[2],
unsigned HOST_WIDE_INT *size, bool *nulterm);
- /* EVRP analyzer used for printf argument range processing, and to
- track strlen results across integer variable assignments. */
- evrp_range_analyzer evrp;
+ gimple_ranger m_ranger;
/* A pointer_query object and its cache to store information about
pointers and their targets in. */
Uses RVALS to determine length range. */
static int
-compare_nonzero_chars (strinfo *si, unsigned HOST_WIDE_INT off,
+compare_nonzero_chars (strinfo *si, gimple *stmt,
+ unsigned HOST_WIDE_INT off,
range_query *rvals)
{
if (!si->nonzero_chars)
return -1;
value_range vr;
- if (!rvals->range_of_expr (vr, si->nonzero_chars, si->stmt))
+ if (!rvals->range_of_expr (vr, si->nonzero_chars, stmt))
return -1;
value_range_kind rng = vr.kind ();
if (rng != VR_RANGE)
information. */
static int
-get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out,
+get_addr_stridx (tree exp, gimple *stmt,
+ tree ptr, unsigned HOST_WIDE_INT *offset_out,
range_query *rvals = NULL)
{
HOST_WIDE_INT off;
unsigned HOST_WIDE_INT rel_off
= (unsigned HOST_WIDE_INT) off - last->offset;
strinfo *si = get_strinfo (last->idx);
- if (si && compare_nonzero_chars (si, rel_off, rvals) >= 0)
+ if (si && compare_nonzero_chars (si, stmt, rel_off, rvals) >= 0)
{
if (offset_out)
{
When nonnull, uses RVALS to determine range information. */
static int
-get_stridx (tree exp, wide_int offrng[2] = NULL, range_query *rvals = NULL)
+get_stridx (tree exp, gimple *stmt,
+ wide_int offrng[2] = NULL, range_query *rvals = NULL)
{
if (offrng)
offrng[0] = offrng[1] = wi::zero (TYPE_PRECISION (ptrdiff_type_node));
if (TREE_CODE (exp) == ADDR_EXPR)
{
- int idx = get_addr_stridx (TREE_OPERAND (exp, 0), exp, NULL);
+ int idx = get_addr_stridx (TREE_OPERAND (exp, 0), stmt, exp, NULL);
if (idx != 0)
return idx;
}
c_strlen_data *pdata, bitmap *visited,
range_query *rvals, unsigned *pssa_def_max)
{
- int idx = get_stridx (src);
+ int idx = get_stridx (src, stmt);
if (!idx)
{
if (TREE_CODE (src) == SSA_NAME)
tree src = gimple_call_arg (stmt, 0);
tree bound = (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRNLEN
? gimple_call_arg (stmt, 1) : NULL_TREE);
- int idx = get_stridx (src);
+ int idx = get_stridx (src, stmt);
if (idx || (bound && integer_zerop (bound)))
{
strinfo *si = NULL;
if (!check_nul_terminated_array (NULL_TREE, src))
return;
- int idx = get_stridx (src);
+ int idx = get_stridx (src, stmt);
if (idx)
{
strinfo *si = NULL;
src = gimple_call_arg (stmt, 1);
dst = gimple_call_arg (stmt, 0);
lhs = gimple_call_lhs (stmt);
- idx = get_stridx (src);
+ idx = get_stridx (src, stmt);
si = NULL;
if (idx > 0)
si = get_strinfo (idx);
- didx = get_stridx (dst);
+ didx = get_stridx (dst, stmt);
olddsi = NULL;
oldlen = NULL_TREE;
if (didx > 0)
when ssa_ver_to_stridx is empty. That implies the caller isn't
running under the control of this pass and ssa_ver_to_stridx hasn't
been created yet. */
- int sidx = ssa_ver_to_stridx.length () ? get_stridx (src) : 0;
+ int sidx = ssa_ver_to_stridx.length () ? get_stridx (src, stmt) : 0;
if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx))
return false;
a lower bound). */
tree dstlenp1 = NULL_TREE, srclenp1 = NULL_TREE;;
- int didx = get_stridx (dst);
+ int didx = get_stridx (dst, stmt);
if (strinfo *sidst = didx > 0 ? get_strinfo (didx) : NULL)
{
/* Compute the size of the destination string including the nul
dst = sidst->ptr;
}
- int sidx = get_stridx (src);
+ int sidx = get_stridx (src, stmt);
strinfo *sisrc = sidx > 0 ? get_strinfo (sidx) : NULL;
if (sisrc)
{
tree src = gimple_call_arg (stmt, 1);
tree dst = gimple_call_arg (stmt, 0);
- int didx = get_stridx (dst);
+ int didx = get_stridx (dst, stmt);
strinfo *olddsi = NULL;
if (didx > 0)
olddsi = get_strinfo (didx);
adjust_last_stmt (olddsi, stmt, false);
}
- int idx = get_stridx (src);
+ int idx = get_stridx (src, stmt);
if (idx == 0)
return;
tree lhs = gimple_call_lhs (stmt);
- didx = get_stridx (dst);
+ didx = get_stridx (dst, stmt);
if (didx < 0)
return;
srclen = NULL_TREE;
si = NULL;
- idx = get_stridx (src);
+ idx = get_stridx (src, stmt);
if (idx < 0)
srclen = build_int_cst (size_type_node, ~idx);
else if (idx > 0)
if (lhs == NULL_TREE)
return;
- gcc_assert (get_stridx (lhs) == 0);
+ gcc_assert (get_stridx (lhs, stmt) == 0);
int idx = new_stridx (lhs);
tree length = NULL_TREE;
if (bcode == BUILT_IN_CALLOC)
tree ptr = gimple_call_arg (memset_stmt, 0);
/* Set to the non-constant offset added to PTR. */
wide_int offrng[2];
- int idx1 = get_stridx (ptr, offrng, ptr_qry.rvals);
+ int idx1 = get_stridx (ptr, memset_stmt, offrng, ptr_qry.rvals);
if (idx1 <= 0)
return false;
strinfo *si1 = get_strinfo (idx1);
tree arg1 = gimple_call_arg (stmt, 0);
tree arg2 = gimple_call_arg (stmt, 1);
- int idx1 = get_stridx (arg1);
- int idx2 = get_stridx (arg2);
+ int idx1 = get_stridx (arg1, stmt);
+ int idx2 = get_stridx (arg2, stmt);
/* For strncmp set to the value of the third argument if known. */
HOST_WIDE_INT bound = -1;
{
gimple *stmt = gsi_stmt (m_gsi);
tree lhs = gimple_assign_lhs (stmt), off;
- int idx = get_stridx (gimple_assign_rhs1 (stmt));
+ int idx = get_stridx (gimple_assign_rhs1 (stmt), stmt);
strinfo *si, *zsi;
if (idx == 0)
Returns true on success and false otherwise. */
bool
-strlen_pass::count_nonzero_bytes (tree exp,
+strlen_pass::count_nonzero_bytes (tree exp, gimple *stmt,
unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT nbytes,
unsigned lenrange[3], bool *nulterm,
exact value is not known) recurse once to set the range
for an arbitrary constant. */
exp = build_int_cst (type, 1);
- return count_nonzero_bytes (exp, offset, 1, lenrange,
+ return count_nonzero_bytes (exp, stmt,
+ offset, 1, lenrange,
nulterm, allnul, allnonnul, snlim);
}
for (unsigned i = 0; i != n; i++)
{
tree def = gimple_phi_arg_def (stmt, i);
- if (!count_nonzero_bytes (def, offset, nbytes, lenrange, nulterm,
+ if (!count_nonzero_bytes (def, stmt,
+ offset, nbytes, lenrange, nulterm,
allnul, allnonnul, snlim))
return false;
}
return false;
/* Handle MEM_REF = SSA_NAME types of assignments. */
- return count_nonzero_bytes_addr (arg, offset, nbytes, lenrange, nulterm,
+ return count_nonzero_bytes_addr (arg, stmt,
+ offset, nbytes, lenrange, nulterm,
allnul, allnonnul, snlim);
}
bytes that are pointed to by EXP, which should be a pointer. */
bool
-strlen_pass::count_nonzero_bytes_addr (tree exp,
+strlen_pass::count_nonzero_bytes_addr (tree exp, gimple *stmt,
unsigned HOST_WIDE_INT offset,
unsigned HOST_WIDE_INT nbytes,
unsigned lenrange[3], bool *nulterm,
bool *allnul, bool *allnonnul,
ssa_name_limit_t &snlim)
{
- int idx = get_stridx (exp);
+ int idx = get_stridx (exp, stmt);
if (idx > 0)
{
strinfo *si = get_strinfo (idx);
&& TREE_CODE (si->nonzero_chars) == SSA_NAME)
{
value_range vr;
- ptr_qry.rvals->range_of_expr (vr, si->nonzero_chars, si->stmt);
+ ptr_qry.rvals->range_of_expr (vr, si->nonzero_chars, stmt);
if (vr.kind () != VR_RANGE)
return false;
}
if (TREE_CODE (exp) == ADDR_EXPR)
- return count_nonzero_bytes (TREE_OPERAND (exp, 0), offset, nbytes,
+ return count_nonzero_bytes (TREE_OPERAND (exp, 0), stmt,
+ offset, nbytes,
lenrange, nulterm, allnul, allnonnul, snlim);
if (TREE_CODE (exp) == SSA_NAME)
for (unsigned i = 0; i != n; i++)
{
tree def = gimple_phi_arg_def (stmt, i);
- if (!count_nonzero_bytes_addr (def, offset, nbytes, lenrange,
+ if (!count_nonzero_bytes_addr (def, stmt,
+ offset, nbytes, lenrange,
nulterm, allnul, allnonnul,
snlim))
return false;
(the results of strlen). */
bool
-strlen_pass::count_nonzero_bytes (tree expr_or_type,
+strlen_pass::count_nonzero_bytes (tree expr_or_type, gimple *stmt,
unsigned lenrange[3], bool *nulterm,
bool *allnul, bool *allnonnul)
{
ssa_name_limit_t snlim;
tree expr = expr_or_type;
- return count_nonzero_bytes (expr, 0, 0, lenrange, nulterm, allnul, allnonnul,
+ return count_nonzero_bytes (expr, stmt,
+ 0, 0, lenrange, nulterm, allnul, allnonnul,
snlim);
}
least OFFSET nonzero characters. This is trivially true if
OFFSET is zero. */
offset = tree_to_uhwi (mem_offset);
- idx = get_stridx (TREE_OPERAND (lhs, 0));
+ idx = get_stridx (TREE_OPERAND (lhs, 0), stmt);
if (idx > 0)
si = get_strinfo (idx);
if (offset == 0)
ssaname = TREE_OPERAND (lhs, 0);
- else if (si == NULL || compare_nonzero_chars (si, offset, rvals) < 0)
+ else if (si == NULL
+ || compare_nonzero_chars (si, stmt, offset, rvals) < 0)
{
*zero_write = rhs ? initializer_zerop (rhs) : false;
bool dummy;
unsigned lenrange[] = { UINT_MAX, 0, 0 };
- if (count_nonzero_bytes (rhs ? rhs : storetype, lenrange,
+ if (count_nonzero_bytes (rhs ? rhs : storetype, stmt, lenrange,
&dummy, &dummy, &dummy))
maybe_warn_overflow (stmt, true, lenrange[2]);
}
else
{
- idx = get_addr_stridx (lhs, NULL_TREE, &offset, rvals);
+ idx = get_addr_stridx (lhs, stmt, NULL_TREE, &offset, rvals);
if (idx > 0)
si = get_strinfo (idx);
}
bool full_string_p;
const bool ranges_valid
- = count_nonzero_bytes (rhs ? rhs : storetype, lenrange, &full_string_p,
+ = count_nonzero_bytes (rhs ? rhs : storetype, stmt,
+ lenrange, &full_string_p,
&storing_all_zeros_p, &storing_all_nonzero_p);
if (ranges_valid)
{
/* The offset of the last stored byte. */
unsigned HOST_WIDE_INT endoff = offset + lenrange[2] - 1;
- store_before_nul[0] = compare_nonzero_chars (si, offset, rvals);
+ store_before_nul[0]
+ = compare_nonzero_chars (si, stmt, offset, rvals);
if (endoff == offset)
store_before_nul[1] = store_before_nul[0];
else
- store_before_nul[1] = compare_nonzero_chars (si, endoff, rvals);
+ store_before_nul[1]
+ = compare_nonzero_chars (si, stmt, endoff, rvals);
}
else
{
- store_before_nul[0] = compare_nonzero_chars (si, offset, rvals);
+ store_before_nul[0]
+ = compare_nonzero_chars (si, stmt, offset, rvals);
store_before_nul[1] = store_before_nul[0];
gcc_assert (offset == 0 || store_before_nul[0] >= 0);
}
{
tree arg1 = gimple_call_arg (call_stmt, 1);
tree arg1_len = NULL_TREE;
- int idx = get_stridx (arg1);
+ int idx = get_stridx (arg1, call_stmt);
if (idx)
{
tree rhs1 = gimple_assign_rhs1 (stmt);
if (code == MEM_REF)
{
- idx = get_stridx (TREE_OPERAND (rhs1, 0));
+ idx = get_stridx (TREE_OPERAND (rhs1, 0), stmt);
if (idx > 0)
{
strinfo *si = get_strinfo (idx);
}
}
if (idx <= 0)
- idx = get_addr_stridx (rhs1, NULL_TREE, &coff);
+ idx = get_addr_stridx (rhs1, stmt, NULL_TREE, &coff);
if (idx > 0)
{
strinfo *si = get_strinfo (idx);
unsigned lenrange[] = { UINT_MAX, 0, 0 };
tree rhs = gimple_assign_rhs1 (stmt);
const bool ranges_valid
- = count_nonzero_bytes (rhs, lenrange, &full_string_p,
+ = count_nonzero_bytes (rhs, stmt,
+ lenrange, &full_string_p,
&storing_all_zeros_p,
&storing_all_nonzero_p);
if (ranges_valid)
|| (gimple_assign_cast_p (stmt)
&& POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))))
{
- int idx = get_stridx (gimple_assign_rhs1 (stmt));
+ int idx = get_stridx (gimple_assign_rhs1 (stmt), stmt);
ssa_ver_to_stridx[SSA_NAME_VERSION (lhs)] = idx;
}
else if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
edge
strlen_pass::before_dom_children (basic_block bb)
{
- evrp.enter (bb);
-
basic_block dombb = get_immediate_dominator (CDI_DOMINATORS, bb);
if (dombb == NULL)
tree result = gimple_phi_result (phi);
if (!virtual_operand_p (result) && POINTER_TYPE_P (TREE_TYPE (result)))
{
- int idx = get_stridx (gimple_phi_arg_def (phi, 0));
+ int idx = get_stridx (gimple_phi_arg_def (phi, 0), phi);
if (idx != 0)
{
unsigned int i, n = gimple_phi_num_args (phi);
for (i = 1; i < n; i++)
- if (idx != get_stridx (gimple_phi_arg_def (phi, i)))
+ if (idx != get_stridx (gimple_phi_arg_def (phi, i), phi))
break;
if (i == n)
ssa_ver_to_stridx[SSA_NAME_VERSION (result)] = idx;
/* Attempt to optimize individual statements. */
for (m_gsi = gsi_start_bb (bb); !gsi_end_p (m_gsi); )
{
- gimple *stmt = gsi_stmt (m_gsi);
-
- /* First record ranges generated by this statement so they
- can be used by printf argument processing. */
- evrp.record_ranges_from_stmt (stmt, false);
-
/* Reset search depth preformance counter. */
ptr_qry.depth = 0;
void
strlen_pass::after_dom_children (basic_block bb)
{
- evrp.leave (bb);
-
if (bb->aux)
{
stridx_to_strinfo = ((vec<strinfo *, va_heap, vl_embed> *) bb->aux);