aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-03-03 16:56:45 -0700
committerMartin Sebor <msebor@redhat.com>2021-03-03 17:04:48 -0700
commit8d57bdadd2d9c2e5c95515ca7a583d7b407b55c4 (patch)
treec7dbd3442b2ad0a283689ae61e707540dd8bc34b /gcc/builtins.c
parent9a5a1e278f91fd7e67fdfbdb8d2f2f72dd566c99 (diff)
downloadgcc-8d57bdadd2d9c2e5c95515ca7a583d7b407b55c4.zip
gcc-8d57bdadd2d9c2e5c95515ca7a583d7b407b55c4.tar.gz
gcc-8d57bdadd2d9c2e5c95515ca7a583d7b407b55c4.tar.bz2
Correct a workaround for vectorized stores.
Resolves: PR middle-end/96963 - -Wstringop-overflow false positive with -ftree-vectorize when assigning consecutive char struct members PR middle-end/94655 - -Wstringop-overflow on implicit string assignment with vectorized char store gcc/ChangeLog: PR middle-end/96963 PR middle-end/94655 * builtins.c (handle_array_ref): New helper. (handle_mem_ref): New helper. (compute_objsize_r): Factor out ARRAY_REF and MEM_REF handling into new helper functions. Correct a workaround for vectorized assignments. gcc/testsuite/ChangeLog: PR middle-end/96963 PR middle-end/94655 * gcc.dg/Wstringop-overflow-47.c: Xfail tests. * gcc.dg/Wstringop-overflow-65.c: New test. * gcc.dg/Warray-bounds-69.c: Same.
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c214
1 files changed, 128 insertions, 86 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index da6dac8..41e336c 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5209,7 +5209,7 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2],
return NULL_TREE;
}
-/* A helper of compute_objsize() to determine the size from an assignment
+/* A helper of compute_objsize_r() to determine the size from an assignment
statement STMT with the RHS of either MIN_EXPR or MAX_EXPR. */
static bool
@@ -5287,6 +5287,129 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref,
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. */
+
+static bool
+handle_array_ref (tree aref, bool addr, int ostype, access_ref *pref,
+ ssa_name_limit_t &snlim, pointer_query *qry)
+{
+ 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)
+ /* Avoid arrays of pointers. FIXME: Hande pointers to arrays
+ of known bound. */
+ return false;
+
+ if (!compute_objsize_r (arefop, ostype, pref, snlim, qry))
+ return false;
+
+ offset_int orng[2];
+ tree off = pref->eval (TREE_OPERAND (aref, 1));
+ range_query *const rvals = qry ? qry->rvals : NULL;
+ if (!get_offset_range (off, NULL, orng, rvals))
+ {
+ /* Set ORNG to the maximum offset representable in ptrdiff_t. */
+ orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
+ orng[0] = -orng[1] - 1;
+ }
+
+ /* Convert the array index range determined above to a byte
+ offset. */
+ tree lowbnd = array_ref_low_bound (aref);
+ if (!integer_zerop (lowbnd) && tree_fits_uhwi_p (lowbnd))
+ {
+ /* Adjust the index by the low bound of the array domain
+ (normally zero but 1 in Fortran). */
+ unsigned HOST_WIDE_INT lb = tree_to_uhwi (lowbnd);
+ orng[0] -= lb;
+ orng[1] -= lb;
+ }
+
+ tree eltype = TREE_TYPE (aref);
+ tree tpsize = TYPE_SIZE_UNIT (eltype);
+ if (!tpsize || TREE_CODE (tpsize) != INTEGER_CST)
+ {
+ pref->add_max_offset ();
+ return true;
+ }
+
+ offset_int sz = wi::to_offset (tpsize);
+ orng[0] *= sz;
+ orng[1] *= sz;
+
+ if (ostype && TREE_CODE (eltype) == ARRAY_TYPE)
+ {
+ /* Except for the permissive raw memory functions which use
+ the size of the whole object determined above, use the size
+ of the referenced array. Because the overall offset is from
+ the beginning of the complete array object add this overall
+ offset to the size of array. */
+ offset_int sizrng[2] =
+ {
+ pref->offrng[0] + orng[0] + sz,
+ pref->offrng[1] + orng[1] + sz
+ };
+ if (sizrng[1] < sizrng[0])
+ std::swap (sizrng[0], sizrng[1]);
+ if (sizrng[0] >= 0 && sizrng[0] <= pref->sizrng[0])
+ pref->sizrng[0] = sizrng[0];
+ if (sizrng[1] >= 0 && sizrng[1] <= pref->sizrng[1])
+ pref->sizrng[1] = sizrng[1];
+ }
+
+ pref->add_offset (orng[0], orng[1]);
+ return true;
+}
+
+/* A helper of compute_objsize_r() to determine the size from MEM_REF
+ MREF. Return true on success and false on failure. */
+
+static bool
+handle_mem_ref (tree mref, int ostype, access_ref *pref,
+ ssa_name_limit_t &snlim, pointer_query *qry)
+{
+ gcc_assert (TREE_CODE (mref) == MEM_REF);
+
+ ++pref->deref;
+
+ if (VECTOR_TYPE_P (TREE_TYPE (mref)))
+ {
+ /* Hack: Give up for MEM_REFs of vector types; those may be
+ synthesized from multiple assignments to consecutive data
+ members (see PR 93200 and 96963).
+ FIXME: Vectorized assignments should only be present after
+ vectorization so this hack is only necessary after it has
+ run and could be avoided in calls from prior passes (e.g.,
+ tree-ssa-strlen.c).
+ FIXME: Deal with this more generally, e.g., by marking up
+ such MEM_REFs at the time they're created. */
+ return false;
+ }
+
+ tree mrefop = TREE_OPERAND (mref, 0);
+ if (!compute_objsize_r (mrefop, ostype, pref, snlim, qry))
+ return false;
+
+ offset_int orng[2];
+ tree off = pref->eval (TREE_OPERAND (mref, 1));
+ range_query *const rvals = qry ? qry->rvals : NULL;
+ if (!get_offset_range (off, NULL, orng, rvals))
+ {
+ /* Set ORNG to the maximum offset representable in ptrdiff_t. */
+ orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
+ orng[0] = -orng[1] - 1;
+ }
+
+ pref->add_offset (orng[0], orng[1]);
+ 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).
@@ -5419,92 +5542,11 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref,
return true;
}
- if (code == ARRAY_REF || code == MEM_REF)
- {
- ++pref->deref;
-
- tree ref = TREE_OPERAND (ptr, 0);
- tree reftype = TREE_TYPE (ref);
- if (!addr && code == ARRAY_REF
- && TREE_CODE (TREE_TYPE (reftype)) == POINTER_TYPE)
- /* Avoid arrays of pointers. FIXME: Hande pointers to arrays
- of known bound. */
- return false;
-
- if (code == MEM_REF && TREE_CODE (reftype) == POINTER_TYPE)
- {
- /* Give up for MEM_REFs of vector types; those may be synthesized
- from multiple assignments to consecutive data members. See PR
- 93200.
- FIXME: Deal with this more generally, e.g., by marking up such
- MEM_REFs at the time they're created. */
- reftype = TREE_TYPE (reftype);
- if (TREE_CODE (reftype) == VECTOR_TYPE)
- return false;
- }
-
- if (!compute_objsize_r (ref, ostype, pref, snlim, qry))
- return false;
-
- offset_int orng[2];
- tree off = pref->eval (TREE_OPERAND (ptr, 1));
- if (!get_offset_range (off, NULL, orng, rvals))
- {
- /* Set ORNG to the maximum offset representable in ptrdiff_t. */
- orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
- orng[0] = -orng[1] - 1;
- }
-
- if (TREE_CODE (ptr) == ARRAY_REF)
- {
- /* Convert the array index range determined above to a byte
- offset. */
- tree lowbnd = array_ref_low_bound (ptr);
- if (!integer_zerop (lowbnd) && tree_fits_uhwi_p (lowbnd))
- {
- /* Adjust the index by the low bound of the array domain
- (normally zero but 1 in Fortran). */
- unsigned HOST_WIDE_INT lb = tree_to_uhwi (lowbnd);
- orng[0] -= lb;
- orng[1] -= lb;
- }
-
- tree eltype = TREE_TYPE (ptr);
- tree tpsize = TYPE_SIZE_UNIT (eltype);
- if (!tpsize || TREE_CODE (tpsize) != INTEGER_CST)
- {
- pref->add_max_offset ();
- return true;
- }
-
- offset_int sz = wi::to_offset (tpsize);
- orng[0] *= sz;
- orng[1] *= sz;
-
- if (ostype && TREE_CODE (eltype) == ARRAY_TYPE)
- {
- /* Except for the permissive raw memory functions which use
- the size of the whole object determined above, use the size
- of the referenced array. Because the overall offset is from
- the beginning of the complete array object add this overall
- offset to the size of array. */
- offset_int sizrng[2] =
- {
- pref->offrng[0] + orng[0] + sz,
- pref->offrng[1] + orng[1] + sz
- };
- if (sizrng[1] < sizrng[0])
- std::swap (sizrng[0], sizrng[1]);
- if (sizrng[0] >= 0 && sizrng[0] <= pref->sizrng[0])
- pref->sizrng[0] = sizrng[0];
- if (sizrng[1] >= 0 && sizrng[1] <= pref->sizrng[1])
- pref->sizrng[1] = sizrng[1];
- }
- }
+ if (code == ARRAY_REF)
+ return handle_array_ref (ptr, addr, ostype, pref, snlim, qry);
- pref->add_offset (orng[0], orng[1]);
- return true;
- }
+ if (code == MEM_REF)
+ return handle_mem_ref (ptr, ostype, pref, snlim, qry);
if (code == TARGET_MEM_REF)
{