diff options
author | Martin Sebor <msebor@redhat.com> | 2021-03-03 16:56:45 -0700 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-03-03 17:04:48 -0700 |
commit | 8d57bdadd2d9c2e5c95515ca7a583d7b407b55c4 (patch) | |
tree | c7dbd3442b2ad0a283689ae61e707540dd8bc34b /gcc/builtins.c | |
parent | 9a5a1e278f91fd7e67fdfbdb8d2f2f72dd566c99 (diff) | |
download | gcc-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.c | 214 |
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) { |