aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-sccvn.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-02-27 10:12:52 +0100
committerJakub Jelinek <jakub@redhat.com>2020-02-27 10:12:52 +0100
commit5f9cd512c4278621435cce486dd00248ea2e821c (patch)
treedffe17c1326c8d4b3bea8892207a7e4e8eafa587 /gcc/tree-ssa-sccvn.c
parent4fd9efc8877814e8cda506563d0282a267c562c8 (diff)
downloadgcc-5f9cd512c4278621435cce486dd00248ea2e821c.zip
gcc-5f9cd512c4278621435cce486dd00248ea2e821c.tar.gz
gcc-5f9cd512c4278621435cce486dd00248ea2e821c.tar.bz2
sccvn: Handle non-byte aligned offset or size for memset (, 123, ) [PR93945]
The following is the last spot in vn_reference_lookup_3 that didn't allow non-byte aligned offsets or sizes. To be precise, it did allow size that wasn't multiple of byte size and that caused a wrong-code issue on big-endian, as the pr93945.c testcase shows, so for GCC 9 we should add && multiple_p (ref->size, BITS_PER_UNIT) check instead. For the memset with SSA_NAME middle-argument, it still requires byte-aligned offset, as we'd otherwise need to rotate the value at runtime. 2020-02-27 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/93582 PR tree-optimization/93945 * tree-ssa-sccvn.c (vn_reference_lookup_3): Handle memset with non-zero INTEGER_CST second argument and ref->offset or ref->size not a multiple of BITS_PER_UNIT. * gcc.dg/tree-ssa/pr93582-9.c: New test. * gcc.c-torture/execute/pr93945.c: New test.
Diffstat (limited to 'gcc/tree-ssa-sccvn.c')
-rw-r--r--gcc/tree-ssa-sccvn.c42
1 files changed, 36 insertions, 6 deletions
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index a3fba28..0487f59 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -2386,7 +2386,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
vn_reference_t vr = data->vr;
gimple *def_stmt = SSA_NAME_DEF_STMT (vuse);
tree base = ao_ref_base (ref);
- HOST_WIDE_INT offseti, maxsizei;
+ HOST_WIDE_INT offseti = 0, maxsizei, sizei = 0;
static vec<vn_reference_op_s> lhs_ops;
ao_ref lhs_ref;
bool lhs_ref_ok = false;
@@ -2541,9 +2541,13 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
&& (integer_zerop (gimple_call_arg (def_stmt, 1))
|| ((TREE_CODE (gimple_call_arg (def_stmt, 1)) == INTEGER_CST
|| (INTEGRAL_TYPE_P (vr->type) && known_eq (ref->size, 8)))
- && CHAR_BIT == 8 && BITS_PER_UNIT == 8
+ && CHAR_BIT == 8
+ && BITS_PER_UNIT == 8
+ && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
&& offset.is_constant (&offseti)
- && offseti % BITS_PER_UNIT == 0))
+ && ref->size.is_constant (&sizei)
+ && (offseti % BITS_PER_UNIT == 0
+ || TREE_CODE (gimple_call_arg (def_stmt, 1)) == INTEGER_CST)))
&& poly_int_tree_p (gimple_call_arg (def_stmt, 2))
&& (TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR
|| TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME))
@@ -2604,7 +2608,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
else
return (void *)-1;
tree len = gimple_call_arg (def_stmt, 2);
- HOST_WIDE_INT leni, offset2i, offseti;
+ HOST_WIDE_INT leni, offset2i;
/* Sometimes the above trickery is smarter than alias analysis. Take
advantage of that. */
if (!ranges_maybe_overlap_p (offset, maxsize, offset2,
@@ -2618,7 +2622,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
tree val;
if (integer_zerop (gimple_call_arg (def_stmt, 1)))
val = build_zero_cst (vr->type);
- else if (INTEGRAL_TYPE_P (vr->type) && known_eq (ref->size, 8))
+ else if (INTEGRAL_TYPE_P (vr->type)
+ && known_eq (ref->size, 8)
+ && offseti % BITS_PER_UNIT == 0)
{
gimple_match_op res_op (gimple_match_cond::UNCOND, NOP_EXPR,
vr->type, gimple_call_arg (def_stmt, 1));
@@ -2630,10 +2636,34 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
}
else
{
- unsigned buflen = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (vr->type));
+ unsigned buflen = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (vr->type)) + 1;
+ if (INTEGRAL_TYPE_P (vr->type))
+ buflen = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (vr->type)) + 1;
unsigned char *buf = XALLOCAVEC (unsigned char, buflen);
memset (buf, TREE_INT_CST_LOW (gimple_call_arg (def_stmt, 1)),
buflen);
+ if (BYTES_BIG_ENDIAN)
+ {
+ unsigned int amnt
+ = (((unsigned HOST_WIDE_INT) offseti + sizei)
+ % BITS_PER_UNIT);
+ if (amnt)
+ {
+ shift_bytes_in_array_right (buf, buflen,
+ BITS_PER_UNIT - amnt);
+ buf++;
+ buflen--;
+ }
+ }
+ else if (offseti % BITS_PER_UNIT != 0)
+ {
+ unsigned int amnt
+ = BITS_PER_UNIT - ((unsigned HOST_WIDE_INT) offseti
+ % BITS_PER_UNIT);
+ shift_bytes_in_array_left (buf, buflen, amnt);
+ buf++;
+ buflen--;
+ }
val = native_interpret_expr (vr->type, buf, buflen);
if (!val)
return (void *)-1;