commit 7d1d8cc18678ccaec5f274919e0c9910ccfea86e
Author: Martin Sebor <msebor@redhat.com>
Date: Mon Dec 6 09:33:32 2021 -0700
Refactor compute_objsize_r into helpers.
gcc/ChangeLog:
* pointer-query.cc (compute_objsize_r): Add an argument.
(gimple_call_return_array): Pass a new argument to compute_objsize_r.
(access_ref::merge_ref): Same.
(access_ref::inform_access): Add an argument and use it.
(access_data::access_data): Initialize new member.
(handle_min_max_size): Pass a new argument to compute_objsize_r.
(handle_decl): New function.
(handle_array_ref): Pass a new argument to compute_objsize_r.
Avoid incrementing deref.
(set_component_ref_size): New function.
(handle_component_ref): New function.
(handle_mem_ref): Pass a new argument to compute_objsize_r.
Only increment deref after successfully computing object size.
(handle_ssa_name): New function.
(compute_objsize_r): Move code into helpers and call them.
(compute_objsize): Pass a new argument to compute_objsize_r.
* pointer-query.h (access_ref::inform_access): Add an argument.
(access_data::ostype): New member.
@@ -43,7 +43,7 @@
#include "tree-ssanames.h"
#include "target.h"
-static bool compute_objsize_r (tree, gimple *, int, access_ref *,
+static bool compute_objsize_r (tree, gimple *, bool, int, access_ref *,
ssa_name_limit_t &, pointer_query *);
/* Wrapper around the wide_int overload of get_range that accepts
@@ -199,7 +199,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
of the source object. */
access_ref aref;
tree src = gimple_call_arg (stmt, 1);
- if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry)
+ if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry)
&& aref.sizrng[1] < offrng[1])
offrng[1] = aref.sizrng[1];
}
@@ -233,7 +233,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
{
access_ref aref;
tree src = gimple_call_arg (stmt, 1);
- if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry))
+ if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry))
offrng[1] = aref.sizrng[1] - 1;
else
offrng[1] = HOST_WIDE_INT_M1U;
@@ -258,7 +258,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end,
of the source object. */
access_ref aref;
tree src = gimple_call_arg (stmt, 1);
- if (compute_objsize_r (src, stmt, 1, &aref, snlim, qry)
+ if (compute_objsize_r (src, stmt, false, 1, &aref, snlim, qry)
&& aref.sizrng[1] < offrng[1])
offrng[1] = aref.sizrng[1];
}
@@ -635,7 +635,7 @@ access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
ssa_name_limit_t &snlim, pointer_query &qry)
{
access_ref aref;
- if (!compute_objsize_r (arg, stmt, ostype, &aref, snlim, &qry)
+ if (!compute_objsize_r (arg, stmt, false, ostype, &aref, snlim, &qry)
|| aref.sizrng[0] < 0)
/* This may be a PHI with all null pointer arguments. */
return false;
@@ -997,42 +997,45 @@ void access_ref::add_offset (const offset_int &min, const offset_int &max)
WRITE is set for a write access and clear for a read access. */
void
-access_ref::inform_access (access_mode mode) const
+access_ref::inform_access (access_mode mode, int ostype /* = 1 */) const
{
const access_ref &aref = *this;
if (!aref.ref)
return;
- if (aref.phi ())
+ if (phi ())
{
/* Set MAXREF to refer to the largest object and fill ALL_REFS
with data for all objects referenced by the PHI arguments. */
access_ref maxref;
auto_vec<access_ref> all_refs;
- if (!get_ref (&all_refs, &maxref))
+ if (!get_ref (&all_refs, &maxref, ostype))
return;
- /* Except for MAXREF, the rest of the arguments' offsets need not
- reflect one added to the PHI itself. Determine the latter from
- MAXREF on which the result is based. */
- const offset_int orng[] =
+ if (all_refs.length ())
{
- offrng[0] - maxref.offrng[0],
- wi::smax (offrng[1] - maxref.offrng[1], offrng[0]),
- };
+ /* Except for MAXREF, the rest of the arguments' offsets need not
+ reflect one added to the PHI itself. Determine the latter from
+ MAXREF on which the result is based. */
+ const offset_int orng[] =
+ {
+ offrng[0] - maxref.offrng[0],
+ wi::smax (offrng[1] - maxref.offrng[1], offrng[0]),
+ };
- /* Add the final PHI's offset to that of each of the arguments
- and recurse to issue an inform message for it. */
- for (unsigned i = 0; i != all_refs.length (); ++i)
- {
- /* Skip any PHIs; those could lead to infinite recursion. */
- if (all_refs[i].phi ())
- continue;
+ /* Add the final PHI's offset to that of each of the arguments
+ and recurse to issue an inform message for it. */
+ for (unsigned i = 0; i != all_refs.length (); ++i)
+ {
+ /* Skip any PHIs; those could lead to infinite recursion. */
+ if (all_refs[i].phi ())
+ continue;
- all_refs[i].add_offset (orng[0], orng[1]);
- all_refs[i].inform_access (mode);
+ all_refs[i].add_offset (orng[0], orng[1]);
+ all_refs[i].inform_access (mode, ostype);
+ }
+ return;
}
- return;
}
/* Convert offset range and avoid including a zero range since it
@@ -1244,7 +1247,7 @@ access_data::access_data (range_query *query, gimple *stmt, access_mode mode,
bool minwrite /* = false */,
tree maxread /* = NULL_TREE */,
bool minread /* = false */)
- : stmt (stmt), call (), dst (), src (), mode (mode)
+ : stmt (stmt), call (), dst (), src (), mode (mode), ostype ()
{
set_bound (dst_bndrng, maxwrite, minwrite, query, stmt);
set_bound (src_bndrng, maxread, minread, query, stmt);
@@ -1257,7 +1260,7 @@ access_data::access_data (range_query *query, tree expr, access_mode mode,
bool minwrite /* = false */,
tree maxread /* = NULL_TREE */,
bool minread /* = false */)
- : stmt (), call (expr), dst (), src (), mode (mode)
+ : stmt (), call (expr), dst (), src (), mode (mode), ostype ()
{
set_bound (dst_bndrng, maxwrite, minwrite, query, stmt);
set_bound (src_bndrng, maxread, minread, query, stmt);
@@ -1406,7 +1409,8 @@ pointer_query::get_ref (tree ptr, int ostype /* = 1 */) const
there or compute it and insert it into the cache if it's nonnonull. */
bool
-pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref, int ostype /* = 1 */)
+pointer_query::get_ref (tree ptr, gimple *stmt, access_ref *pref,
+ int ostype /* = 1 */)
{
const unsigned version
= TREE_CODE (ptr) == SSA_NAME ? SSA_NAME_VERSION (ptr) : 0;
@@ -1606,7 +1610,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
for the expression. */
access_ref aref[2] = { *pref, *pref };
tree arg1 = gimple_assign_rhs1 (stmt);
- if (!compute_objsize_r (arg1, stmt, ostype, &aref[0], snlim, qry))
+ if (!compute_objsize_r (arg1, stmt, false, ostype, &aref[0], snlim, qry))
{
aref[0].base0 = false;
aref[0].offrng[0] = aref[0].offrng[1] = 0;
@@ -1615,7 +1619,7 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
}
tree arg2 = gimple_assign_rhs2 (stmt);
- if (!compute_objsize_r (arg2, stmt, ostype, &aref[1], snlim, qry))
+ if (!compute_objsize_r (arg2, stmt, false, ostype, &aref[1], snlim, qry))
{
aref[1].base0 = false;
aref[1].offrng[0] = aref[1].offrng[1] = 0;
@@ -1678,6 +1682,46 @@ handle_min_max_size (tree ptr, int ostype, access_ref *pref,
return true;
}
+/* A helper of compute_objsize_r() to determine the size of a DECL.
+ Return true on success and (possibly in the future) false on failure. */
+
+static bool
+handle_decl (tree decl, bool addr, access_ref *pref)
+{
+ tree decl_type = TREE_TYPE (decl);
+
+ pref->ref = decl;
+
+ /* Reset the offset in case it was set by a prior call and not
+ cleared by the caller. The offset is only adjusted after
+ the identity of the object has been determined. */
+ pref->offrng[0] = pref->offrng[1] = 0;
+
+ if (!addr && POINTER_TYPE_P (decl_type))
+ {
+ /* Set the maximum size if the reference is to the pointer
+ itself (as opposed to what it points to), and clear
+ BASE0 since the offset isn't necessarily zero-based. */
+ pref->set_max_size_range ();
+ pref->base0 = false;
+ return true;
+ }
+
+ /* Valid offsets into the object are nonnegative. */
+ pref->base0 = true;
+
+ if (tree size = decl_init_size (decl, false))
+ if (TREE_CODE (size) == INTEGER_CST)
+ {
+ pref->sizrng[0] = wi::to_offset (size);
+ pref->sizrng[1] = pref->sizrng[0];
+ return true;
+ }
+
+ pref->set_max_size_range ();
+ return true;
+}
+
/* A helper of compute_objsize_r() to determine the size from ARRAY_REF
AREF. ADDR is true if PTR is the operand of ADDR_EXPR. Return true
on success and false on failure. */
@@ -1689,8 +1733,6 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
{
gcc_assert (TREE_CODE (aref) == ARRAY_REF);
- ++pref->deref;
-
tree arefop = TREE_OPERAND (aref, 0);
tree reftype = TREE_TYPE (arefop);
if (!addr && TREE_CODE (TREE_TYPE (reftype)) == POINTER_TYPE)
@@ -1698,7 +1740,7 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
of known bound. */
return false;
- if (!compute_objsize_r (arefop, stmt, ostype, pref, snlim, qry))
+ if (!compute_objsize_r (arefop, stmt, addr, ostype, pref, snlim, qry))
return false;
offset_int orng[2];
@@ -1759,6 +1801,96 @@ handle_array_ref (tree aref, gimple *stmt, bool addr, int ostype,
return true;
}
+/* Given a COMPONENT_REF CREF, set *PREF size to the size of the referenced
+ member. */
+
+static void
+set_component_ref_size (tree cref, access_ref *pref)
+{
+ const tree base = TREE_OPERAND (cref, 0);
+ const tree base_type = TREE_TYPE (base);
+
+ /* SAM is set for array members that might need special treatment. */
+ special_array_member sam;
+ tree size = component_ref_size (cref, &sam);
+ if (sam == special_array_member::int_0)
+ pref->sizrng[0] = pref->sizrng[1] = 0;
+ else if (!pref->trail1special && sam == special_array_member::trail_1)
+ pref->sizrng[0] = pref->sizrng[1] = 1;
+ else if (size && TREE_CODE (size) == INTEGER_CST)
+ pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+ else
+ {
+ /* When the size of the member is unknown it's either a flexible
+ array member or a trailing special array member (either zero
+ length or one-element). Set the size to the maximum minus
+ the constant size of the base object's type. */
+ pref->sizrng[0] = 0;
+ pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
+ if (tree base_size = TYPE_SIZE_UNIT (base_type))
+ if (TREE_CODE (base_size) == INTEGER_CST)
+ pref->sizrng[1] -= wi::to_offset (base_size);
+ }
+}
+
+/* A helper of compute_objsize_r() to determine the size from COMPONENT_REF
+ CREF. Return true on success and false on failure. */
+
+static bool
+handle_component_ref (tree cref, gimple *stmt, bool addr, int ostype,
+ access_ref *pref, ssa_name_limit_t &snlim,
+ pointer_query *qry)
+{
+ gcc_assert (TREE_CODE (cref) == COMPONENT_REF);
+
+ const tree base = TREE_OPERAND (cref, 0);
+ const tree base_type = TREE_TYPE (base);
+ if (TREE_CODE (base_type) == UNION_TYPE)
+ /* In accesses through union types consider the entire unions
+ rather than just their members. */
+ ostype = 0;
+
+ tree field = TREE_OPERAND (cref, 1);
+
+ if (ostype == 0)
+ {
+ /* In OSTYPE zero (for raw memory functions like memcpy), use
+ the maximum size instead if the identity of the enclosing
+ object cannot be determined. */
+ if (!compute_objsize_r (base, stmt, addr, ostype, pref, snlim, qry))
+ return false;
+
+ /* Otherwise, use the size of the enclosing object and add
+ the offset of the member to the offset computed so far. */
+ tree offset = byte_position (field);
+ if (TREE_CODE (offset) == INTEGER_CST)
+ pref->add_offset (wi::to_offset (offset));
+ else
+ pref->add_max_offset ();
+
+ if (!pref->ref)
+ /* PREF->REF may have been already set to an SSA_NAME earlier
+ to provide better context for diagnostics. In that case,
+ leave it unchanged. */
+ pref->ref = base;
+
+ return true;
+ }
+
+ pref->ref = field;
+
+ if (!addr && POINTER_TYPE_P (TREE_TYPE (field)))
+ {
+ /* Set maximum size if the reference is to the pointer member
+ itself (as opposed to what it points to). */
+ pref->set_max_size_range ();
+ return true;
+ }
+
+ set_component_ref_size (cref, pref);
+ return true;
+}
+
/* A helper of compute_objsize_r() to determine the size from MEM_REF
MREF. Return true on success and false on failure. */
@@ -1768,10 +1900,9 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
{
gcc_assert (TREE_CODE (mref) == MEM_REF);
- ++pref->deref;
-
- if (VECTOR_TYPE_P (TREE_TYPE (mref)))
- {
+ tree mreftype = TYPE_MAIN_VARIANT (TREE_TYPE (mref));
+ if (VECTOR_TYPE_P (mreftype))
+ {
/* Hack: Handle MEM_REFs of vector types as those to complete
objects; those may be synthesized from multiple assignments
to consecutive data members (see PR 93200 and 96963).
@@ -1785,9 +1916,11 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
}
tree mrefop = TREE_OPERAND (mref, 0);
- if (!compute_objsize_r (mrefop, stmt, ostype, pref, snlim, qry))
+ if (!compute_objsize_r (mrefop, stmt, false, ostype, pref, snlim, qry))
return false;
+ ++pref->deref;
+
offset_int orng[2];
tree off = pref->eval (TREE_OPERAND (mref, 1));
range_query *const rvals = qry ? qry->rvals : NULL;
@@ -1802,168 +1935,283 @@ handle_mem_ref (tree mref, gimple *stmt, int ostype, access_ref *pref,
return true;
}
-/* Helper to compute the size of the object referenced by the PTR
- expression which must have pointer type, using Object Size type
- OSTYPE (only the least significant 2 bits are used).
- On success, sets PREF->REF to the DECL of the referenced object
- if it's unique, otherwise to null, PREF->OFFRNG to the range of
- offsets into it, and PREF->SIZRNG to the range of sizes of
- the object(s).
- SNLIM is used to avoid visiting the same PHI operand multiple
- times, and, when nonnull, RVALS to determine range information.
- Returns true on success, false when a meaningful size (or range)
- cannot be determined.
-
- The function is intended for diagnostics and should not be used
- to influence code generation or optimization. */
+/* A helper of compute_objsize_r() to determine the size from SSA_NAME
+ PTR. Return true on success and false on failure. */
static bool
-compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
- ssa_name_limit_t &snlim, pointer_query *qry)
+handle_ssa_name (tree ptr, bool addr, int ostype,
+ access_ref *pref, ssa_name_limit_t &snlim,
+ pointer_query *qry)
{
- STRIP_NOPS (ptr);
+ if (!snlim.next ())
+ return false;
- const bool addr = TREE_CODE (ptr) == ADDR_EXPR;
- if (addr)
+ /* Only process an SSA_NAME if the recursion limit has not yet
+ been reached. */
+ if (qry)
{
- --pref->deref;
- ptr = TREE_OPERAND (ptr, 0);
+ if (++qry->depth > qry->max_depth)
+ qry->max_depth = qry->depth;
+ if (const access_ref *cache_ref = qry->get_ref (ptr, ostype))
+ {
+ /* Add the number of DEREFerences accummulated so far. */
+ const int deref = pref->deref;
+ *pref = *cache_ref;
+ pref->deref += deref;
+ return true;
+ }
}
- if (DECL_P (ptr))
- {
- pref->ref = ptr;
-
- /* Reset the offset in case it was set by a prior call and not
- cleared by the caller. The offset is only adjusted after
- the identity of the object has been determined. */
- pref->offrng[0] = pref->offrng[1] = 0;
+ gimple *stmt = SSA_NAME_DEF_STMT (ptr);
+ if (is_gimple_call (stmt))
+ {
+ /* If STMT is a call to an allocation function get the size
+ from its argument(s). If successful, also set *PREF->REF
+ to PTR for the caller to include in diagnostics. */
+ wide_int wr[2];
+ range_query *const rvals = qry ? qry->rvals : NULL;
+ if (gimple_call_alloc_size (stmt, wr, rvals))
+ {
+ pref->ref = ptr;
+ pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
+ pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
+ /* Constrain both bounds to a valid size. */
+ offset_int maxsize = wi::to_offset (max_object_size ());
+ if (pref->sizrng[0] > maxsize)
+ pref->sizrng[0] = maxsize;
+ if (pref->sizrng[1] > maxsize)
+ pref->sizrng[1] = maxsize;
+ }
+ else
+ {
+ /* For functions known to return one of their pointer arguments
+ try to determine what the returned pointer points to, and on
+ success add OFFRNG which was set to the offset added by
+ the function (e.g., memchr) to the overall offset. */
+ bool past_end;
+ offset_int offrng[2];
+ if (tree ret = gimple_call_return_array (stmt, offrng, &past_end,
+ snlim, qry))
+ {
+ if (!compute_objsize_r (ret, stmt, addr, ostype, pref, snlim, qry))
+ return false;
+
+ /* Cap OFFRNG[1] to at most the remaining size of
+ the object. */
+ offset_int remrng[2];
+ remrng[1] = pref->size_remaining (remrng);
+ if (remrng[1] != 0 && !past_end)
+ /* Decrement the size for functions that never return
+ a past-the-end pointer. */
+ remrng[1] -= 1;
+
+ if (remrng[1] < offrng[1])
+ offrng[1] = remrng[1];
+ pref->add_offset (offrng[0], offrng[1]);
+ }
+ else
+ {
+ /* For other calls that might return arbitrary pointers
+ including into the middle of objects set the size
+ range to maximum, clear PREF->BASE0, and also set
+ PREF->REF to include in diagnostics. */
+ pref->set_max_size_range ();
+ pref->base0 = false;
+ pref->ref = ptr;
+ }
+ }
+ qry->put_ref (ptr, *pref, ostype);
+ return true;
+ }
- if (!addr && POINTER_TYPE_P (TREE_TYPE (ptr)))
+ if (gimple_nop_p (stmt))
+ {
+ /* For a function argument try to determine the byte size
+ of the array from the current function declaratation
+ (e.g., attribute access or related). */
+ wide_int wr[2];
+ bool static_array = false;
+ if (tree ref = gimple_parm_array_size (ptr, wr, &static_array))
{
- /* Set the maximum size if the reference is to the pointer
- itself (as opposed to what it points to), and clear
- BASE0 since the offset isn't necessarily zero-based. */
- pref->set_max_size_range ();
- pref->base0 = false;
+ pref->parmarray = !static_array;
+ pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
+ pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
+ pref->ref = ref;
+ qry->put_ref (ptr, *pref, ostype);
return true;
}
- /* Valid offsets into the object are nonnegative. */
- pref->base0 = true;
-
- if (tree size = decl_init_size (ptr, false))
- if (TREE_CODE (size) == INTEGER_CST)
- {
- pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
- return true;
- }
-
pref->set_max_size_range ();
+ pref->base0 = false;
+ pref->ref = ptr;
+ qry->put_ref (ptr, *pref, ostype);
return true;
}
- const tree_code code = TREE_CODE (ptr);
- range_query *const rvals = qry ? qry->rvals : NULL;
-
- if (code == BIT_FIELD_REF)
+ if (gimple_code (stmt) == GIMPLE_PHI)
{
- tree ref = TREE_OPERAND (ptr, 0);
- if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
+ /* Pass PTR to get_ref() via PREF. If all PHI arguments refer
+ to the same object the function will replace it with it. */
+ pref->ref = ptr;
+ access_ref phi_ref = *pref;
+ if (!pref->get_ref (NULL, &phi_ref, ostype, &snlim, qry))
return false;
+ *pref = phi_ref;
+ qry->put_ref (ptr, *pref, ostype);
+ return true;
+ }
- offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2)));
- pref->add_offset (off / BITS_PER_UNIT);
+ if (!is_gimple_assign (stmt))
+ {
+ /* Clear BASE0 since the assigned pointer might point into
+ the middle of the object, set the maximum size range and,
+ if the SSA_NAME refers to a function argumnent, set
+ PREF->REF to it. */
+ pref->base0 = false;
+ pref->set_max_size_range ();
+ pref->ref = ptr;
return true;
}
- if (code == COMPONENT_REF)
+ tree_code code = gimple_assign_rhs_code (stmt);
+
+ if (code == MAX_EXPR || code == MIN_EXPR)
{
- tree ref = TREE_OPERAND (ptr, 0);
- if (TREE_CODE (TREE_TYPE (ref)) == UNION_TYPE)
- /* In accesses through union types consider the entire unions
- rather than just their members. */
- ostype = 0;
- tree field = TREE_OPERAND (ptr, 1);
+ if (!handle_min_max_size (ptr, ostype, pref, snlim, qry))
+ return false;
- if (ostype == 0)
- {
- /* In OSTYPE zero (for raw memory functions like memcpy), use
- the maximum size instead if the identity of the enclosing
- object cannot be determined. */
- if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
- return false;
-
- /* Otherwise, use the size of the enclosing object and add
- the offset of the member to the offset computed so far. */
- tree offset = byte_position (field);
- if (TREE_CODE (offset) == INTEGER_CST)
- pref->add_offset (wi::to_offset (offset));
- else
- pref->add_max_offset ();
+ qry->put_ref (ptr, *pref, ostype);
+ return true;
+ }
- if (!pref->ref)
- /* REF may have been already set to an SSA_NAME earlier
- to provide better context for diagnostics. In that case,
- leave it unchanged. */
- pref->ref = ref;
- return true;
- }
+ tree rhs = gimple_assign_rhs1 (stmt);
- pref->ref = field;
+ if (code == ASSERT_EXPR)
+ {
+ rhs = TREE_OPERAND (rhs, 0);
+ return compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry);
+ }
- if (!addr && POINTER_TYPE_P (TREE_TYPE (field)))
- {
- /* Set maximum size if the reference is to the pointer member
- itself (as opposed to what it points to). */
- pref->set_max_size_range ();
- return true;
- }
+ if (code == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE)
+ {
+ /* Compute the size of the object first. */
+ if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry))
+ return false;
- /* SAM is set for array members that might need special treatment. */
- special_array_member sam;
- tree size = component_ref_size (ptr, &sam);
- if (sam == special_array_member::int_0)
- pref->sizrng[0] = pref->sizrng[1] = 0;
- else if (!pref->trail1special && sam == special_array_member::trail_1)
- pref->sizrng[0] = pref->sizrng[1] = 1;
- else if (size && TREE_CODE (size) == INTEGER_CST)
- pref->sizrng[0] = pref->sizrng[1] = wi::to_offset (size);
+ offset_int orng[2];
+ tree off = gimple_assign_rhs2 (stmt);
+ range_query *const rvals = qry ? qry->rvals : NULL;
+ if (get_offset_range (off, stmt, orng, rvals))
+ pref->add_offset (orng[0], orng[1]);
else
- {
- /* When the size of the member is unknown it's either a flexible
- array member or a trailing special array member (either zero
- length or one-element). Set the size to the maximum minus
- the constant size of the type. */
- pref->sizrng[0] = 0;
- pref->sizrng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
- if (tree recsize = TYPE_SIZE_UNIT (TREE_TYPE (ref)))
- if (TREE_CODE (recsize) == INTEGER_CST)
- pref->sizrng[1] -= wi::to_offset (recsize);
- }
+ pref->add_max_offset ();
+
+ qry->put_ref (ptr, *pref, ostype);
return true;
}
- if (code == ARRAY_REF)
- return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
-
- if (code == MEM_REF)
- return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry);
+ if (code == ADDR_EXPR || code == SSA_NAME)
+ {
+ if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry))
+ return false;
+ qry->put_ref (ptr, *pref, ostype);
+ return true;
+ }
- if (code == TARGET_MEM_REF)
+ if (ostype > 1 && POINTER_TYPE_P (TREE_TYPE (rhs)))
{
- tree ref = TREE_OPERAND (ptr, 0);
- if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
+ /* When determining the qualifiers follow the pointer but
+ avoid caching the result. As the pointer is added to
+ and/or dereferenced the computed size and offset need
+ not be meaningful for other queries involving the same
+ pointer. */
+ if (!compute_objsize_r (rhs, stmt, addr, ostype, pref, snlim, qry))
return false;
- /* TODO: Handle remaining operands. Until then, add maximum offset. */
- pref->ref = ptr;
- pref->add_max_offset ();
- return true;
+ rhs = pref->ref;
}
- if (code == INTEGER_CST)
+ /* (This could also be an assignment from a nonlocal pointer.) Save
+ PTR to mention in diagnostics but otherwise treat it as a pointer
+ to an unknown object. */
+ pref->ref = rhs;
+ pref->base0 = false;
+ pref->set_max_size_range ();
+ return true;
+}
+
+/* Helper to compute the size of the object referenced by the PTR
+ expression which must have pointer type, using Object Size type
+ OSTYPE (only the least significant 2 bits are used).
+ On success, sets PREF->REF to the DECL of the referenced object
+ if it's unique, otherwise to null, PREF->OFFRNG to the range of
+ offsets into it, and PREF->SIZRNG to the range of sizes of
+ the object(s).
+ ADDR is true for an enclosing ADDR_EXPR.
+ SNLIM is used to avoid visiting the same PHI operand multiple
+ times, and, when nonnull, RVALS to determine range information.
+ Returns true on success, false when a meaningful size (or range)
+ cannot be determined.
+
+ The function is intended for diagnostics and should not be used
+ to influence code generation or optimization. */
+
+static bool
+compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype,
+ access_ref *pref, ssa_name_limit_t &snlim,
+ pointer_query *qry)
+{
+ STRIP_NOPS (ptr);
+
+ if (DECL_P (ptr))
+ return handle_decl (ptr, addr, pref);
+
+ switch (TREE_CODE (ptr))
{
+ case ADDR_EXPR:
+ {
+ tree ref = TREE_OPERAND (ptr, 0);
+ if (!compute_objsize_r (ref, stmt, true, ostype, pref, snlim, qry))
+ return false;
+
+ --pref->deref;
+ return true;
+ }
+
+ case BIT_FIELD_REF:
+ {
+ tree ref = TREE_OPERAND (ptr, 0);
+ if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
+ return false;
+
+ offset_int off = wi::to_offset (pref->eval (TREE_OPERAND (ptr, 2)));
+ pref->add_offset (off / BITS_PER_UNIT);
+ return true;
+ }
+
+ case ARRAY_REF:
+ return handle_array_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
+
+ case COMPONENT_REF:
+ return handle_component_ref (ptr, stmt, addr, ostype, pref, snlim, qry);
+
+ case MEM_REF:
+ return handle_mem_ref (ptr, stmt, ostype, pref, snlim, qry);
+
+ case TARGET_MEM_REF:
+ {
+ tree ref = TREE_OPERAND (ptr, 0);
+ if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
+ return false;
+
+ /* TODO: Handle remaining operands. Until then, add maximum offset. */
+ pref->ref = ptr;
+ pref->add_max_offset ();
+ return true;
+ }
+
+ case INTEGER_CST:
/* Pointer constants other than null are most likely the result
of erroneous null pointer addition/subtraction. Unless zero
is a valid address set size to zero. For null pointers, set
@@ -1984,21 +2232,17 @@ compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
pref->sizrng[0] = pref->sizrng[1] = 0;
pref->ref = ptr;
-
return true;
- }
- if (code == STRING_CST)
- {
+ case STRING_CST:
pref->sizrng[0] = pref->sizrng[1] = TREE_STRING_LENGTH (ptr);
pref->ref = ptr;
return true;
- }
- if (code == POINTER_PLUS_EXPR)
+ case POINTER_PLUS_EXPR:
{
tree ref = TREE_OPERAND (ptr, 0);
- if (!compute_objsize_r (ref, stmt, ostype, pref, snlim, qry))
+ if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry))
return false;
/* Clear DEREF since the offset is being applied to the target
@@ -2007,200 +2251,22 @@ compute_objsize_r (tree ptr, gimple *stmt, int ostype, access_ref *pref,
offset_int orng[2];
tree off = pref->eval (TREE_OPERAND (ptr, 1));
- if (get_offset_range (off, stmt, orng, rvals))
+ if (get_offset_range (off, stmt, orng, qry->rvals))
pref->add_offset (orng[0], orng[1]);
else
pref->add_max_offset ();
return true;
}
- if (code == VIEW_CONVERT_EXPR)
- {
+ case VIEW_CONVERT_EXPR:
ptr = TREE_OPERAND (ptr, 0);
- return compute_objsize_r (ptr, stmt, ostype, pref, snlim, qry);
- }
+ return compute_objsize_r (ptr, stmt, addr, ostype, pref, snlim, qry);
- if (code == SSA_NAME)
- {
- if (!snlim.next ())
- return false;
+ case SSA_NAME:
+ return handle_ssa_name (ptr, addr, ostype, pref, snlim, qry);
- /* Only process an SSA_NAME if the recursion limit has not yet
- been reached. */
- if (qry)
- {
- if (++qry->depth)
- qry->max_depth = qry->depth;
- if (const access_ref *cache_ref = qry->get_ref (ptr))
- {
- /* If the pointer is in the cache set *PREF to what it refers
- to and return success. */
- *pref = *cache_ref;
- return true;
- }
- }
-
- stmt = SSA_NAME_DEF_STMT (ptr);
- if (is_gimple_call (stmt))
- {
- /* If STMT is a call to an allocation function get the size
- from its argument(s). If successful, also set *PREF->REF
- to PTR for the caller to include in diagnostics. */
- wide_int wr[2];
- if (gimple_call_alloc_size (stmt, wr, rvals))
- {
- pref->ref = ptr;
- pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
- pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
- /* Constrain both bounds to a valid size. */
- offset_int maxsize = wi::to_offset (max_object_size ());
- if (pref->sizrng[0] > maxsize)
- pref->sizrng[0] = maxsize;
- if (pref->sizrng[1] > maxsize)
- pref->sizrng[1] = maxsize;
- }
- else
- {
- /* For functions known to return one of their pointer arguments
- try to determine what the returned pointer points to, and on
- success add OFFRNG which was set to the offset added by
- the function (e.g., memchr) to the overall offset. */
- bool past_end;
- offset_int offrng[2];
- if (tree ret = gimple_call_return_array (stmt, offrng,
- &past_end, snlim, qry))
- {
- if (!compute_objsize_r (ret, stmt, ostype, pref, snlim, qry))
- return false;
-
- /* Cap OFFRNG[1] to at most the remaining size of
- the object. */
- offset_int remrng[2];
- remrng[1] = pref->size_remaining (remrng);
- if (remrng[1] != 0 && !past_end)
- /* Decrement the size for functions that never return
- a past-the-end pointer. */
- remrng[1] -= 1;
-
- if (remrng[1] < offrng[1])
- offrng[1] = remrng[1];
- pref->add_offset (offrng[0], offrng[1]);
- }
- else
- {
- /* For other calls that might return arbitrary pointers
- including into the middle of objects set the size
- range to maximum, clear PREF->BASE0, and also set
- PREF->REF to include in diagnostics. */
- pref->set_max_size_range ();
- pref->base0 = false;
- pref->ref = ptr;
- }
- }
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- if (gimple_nop_p (stmt))
- {
- /* For a function argument try to determine the byte size
- of the array from the current function declaratation
- (e.g., attribute access or related). */
- wide_int wr[2];
- bool static_array = false;
- if (tree ref = gimple_parm_array_size (ptr, wr, &static_array))
- {
- pref->parmarray = !static_array;
- pref->sizrng[0] = offset_int::from (wr[0], UNSIGNED);
- pref->sizrng[1] = offset_int::from (wr[1], UNSIGNED);
- pref->ref = ref;
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- pref->set_max_size_range ();
- pref->base0 = false;
- pref->ref = ptr;
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- if (gimple_code (stmt) == GIMPLE_PHI)
- {
- pref->ref = ptr;
- access_ref phi_ref = *pref;
- if (!pref->get_ref (NULL, &phi_ref, ostype, &snlim, qry))
- return false;
- *pref = phi_ref;
- pref->ref = ptr;
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- if (!is_gimple_assign (stmt))
- {
- /* Clear BASE0 since the assigned pointer might point into
- the middle of the object, set the maximum size range and,
- if the SSA_NAME refers to a function argumnent, set
- PREF->REF to it. */
- pref->base0 = false;
- pref->set_max_size_range ();
- pref->ref = ptr;
- return true;
- }
-
- tree_code code = gimple_assign_rhs_code (stmt);
-
- if (code == MAX_EXPR || code == MIN_EXPR)
- {
- if (!handle_min_max_size (ptr, ostype, pref, snlim, qry))
- return false;
-
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- tree rhs = gimple_assign_rhs1 (stmt);
-
- if (code == ASSERT_EXPR)
- {
- rhs = TREE_OPERAND (rhs, 0);
- return compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry);
- }
-
- if (code == POINTER_PLUS_EXPR
- && TREE_CODE (TREE_TYPE (rhs)) == POINTER_TYPE)
- {
- /* Compute the size of the object first. */
- if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry))
- return false;
-
- offset_int orng[2];
- tree off = gimple_assign_rhs2 (stmt);
- if (get_offset_range (off, stmt, orng, rvals))
- pref->add_offset (orng[0], orng[1]);
- else
- pref->add_max_offset ();
-
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- if (code == ADDR_EXPR || code == SSA_NAME)
- {
- if (!compute_objsize_r (rhs, stmt, ostype, pref, snlim, qry))
- return false;
- qry->put_ref (ptr, *pref);
- return true;
- }
-
- /* (This could also be an assignment from a nonlocal pointer.) Save
- PTR to mention in diagnostics but otherwise treat it as a pointer
- to an unknown object. */
- pref->ref = rhs;
- pref->base0 = false;
- pref->set_max_size_range ();
- return true;
+ default:
+ break;
}
/* Assume all other expressions point into an unknown object
@@ -2231,7 +2297,7 @@ compute_objsize (tree ptr, gimple *stmt, int ostype, access_ref *pref,
pref->sizrng[0] = pref->sizrng[1] = -1;
ssa_name_limit_t snlim;
- if (!compute_objsize_r (ptr, stmt, ostype, pref, snlim, ptr_qry))
+ if (!compute_objsize_r (ptr, stmt, false, ostype, pref, snlim, ptr_qry))
return NULL_TREE;
offset_int maxsize = pref->size_remaining ();
@@ -122,7 +122,7 @@ struct access_ref
/* Issue an informational message describing the target of an access
with the given mode. */
- void inform_access (access_mode) const;
+ void inform_access (access_mode, int = 1) const;
/* Reference to the accessed object(s). */
tree ref;
@@ -234,6 +234,8 @@ struct access_data
/* Read-only for functions like memcmp or strlen, write-only
for memset, read-write for memcpy or strcat. */
access_mode mode;
+ /* The object size type. */
+ int ostype;
};
enum size_range_flags