aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-07-26 16:45:43 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-07-26 10:45:43 -0600
commitaca8570e11d28b8c33d26593df6d4725a6140aab (patch)
treebea2270f62332f8d85e1bcd3adcb0c246cb32648 /gcc/tree.c
parent4b8b1f5997e7f16713be5c05e7fd40c122fa9381 (diff)
downloadgcc-aca8570e11d28b8c33d26593df6d4725a6140aab.zip
gcc-aca8570e11d28b8c33d26593df6d4725a6140aab.tar.gz
gcc-aca8570e11d28b8c33d26593df6d4725a6140aab.tar.bz2
PR tree-optimization/86043 - strlen after memcpy partially overwriting a string not optimized
PR tree-optimization/86043 - strlen after memcpy partially overwriting a string not optimized PR tree-optimization/86042 - missing strlen optimization after second strcpy gcc/ChangeLog: PR tree-optimization/86043 PR tree-optimization/86042 * tree-ssa-strlen.c (handle_builtin_memcpy): Handle strict overlaps. (get_string_cst_length): Rename... (get_min_string_length): ...to this. Add argument. (handle_char_store): Extend to handle multi-character stores by MEM_REF. * tree.c (initializer_zerop): Use new argument. Handle MEM_REF. * tree.h (initializer_zerop): Add argument. gcc/testsuite/ChangeLog: PR tree-optimization/86043 PR tree-optimization/86042 * gcc/testsuite/gcc.dg/attr-nonstring-2.c: Xfail test cases due to pr86688. * gcc.dg/strlenopt-44.c: New test. From-SVN: r263018
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c103
1 files changed, 83 insertions, 20 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index bace9c8..28952e5 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -10643,61 +10643,124 @@ vector_cst_elt (const_tree t, unsigned int i)
}
/* Given an initializer INIT, return TRUE if INIT is zero or some
- aggregate of zeros. Otherwise return FALSE. */
+ aggregate of zeros. Otherwise return FALSE. If NONZERO is not
+ null, set *NONZERO if and only if INIT is known not to be all
+ zeros. The combination of return value of false and *NONZERO
+ false implies that INIT may but need not be all zeros. Other
+ combinations indicate definitive answers. */
+
bool
-initializer_zerop (const_tree init)
+initializer_zerop (const_tree init, bool *nonzero /* = NULL */)
{
- tree elt;
+ bool dummy;
+ if (!nonzero)
+ nonzero = &dummy;
+
+ /* Conservatively clear NONZERO and set it only if INIT is definitely
+ not all zero. */
+ *nonzero = false;
STRIP_NOPS (init);
+ unsigned HOST_WIDE_INT off = 0;
+
switch (TREE_CODE (init))
{
case INTEGER_CST:
- return integer_zerop (init);
+ if (integer_zerop (init))
+ return true;
+
+ *nonzero = true;
+ return false;
case REAL_CST:
/* ??? Note that this is not correct for C4X float formats. There,
a bit pattern of all zeros is 1.0; 0.0 is encoded with the most
negative exponent. */
- return real_zerop (init)
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
+ if (real_zerop (init)
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)))
+ return true;
+
+ *nonzero = true;
+ return false;
case FIXED_CST:
- return fixed_zerop (init);
+ if (fixed_zerop (init))
+ return true;
+
+ *nonzero = true;
+ return false;
case COMPLEX_CST:
- return integer_zerop (init)
- || (real_zerop (init)
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
+ if (integer_zerop (init)
+ || (real_zerop (init)
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init)))))
+ return true;
+
+ *nonzero = true;
+ return false;
case VECTOR_CST:
- return (VECTOR_CST_NPATTERNS (init) == 1
- && VECTOR_CST_DUPLICATE_P (init)
- && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)));
+ if (VECTOR_CST_NPATTERNS (init) == 1
+ && VECTOR_CST_DUPLICATE_P (init)
+ && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)))
+ return true;
+
+ *nonzero = true;
+ return false;
case CONSTRUCTOR:
{
- unsigned HOST_WIDE_INT idx;
-
if (TREE_CLOBBER_P (init))
return false;
+
+ unsigned HOST_WIDE_INT idx;
+ tree elt;
+
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
- if (!initializer_zerop (elt))
+ if (!initializer_zerop (elt, nonzero))
return false;
+
return true;
}
+ case MEM_REF:
+ {
+ tree arg = TREE_OPERAND (init, 0);
+ if (TREE_CODE (arg) != ADDR_EXPR)
+ return false;
+ tree offset = TREE_OPERAND (init, 1);
+ if (TREE_CODE (offset) != INTEGER_CST
+ || !tree_fits_uhwi_p (offset))
+ return false;
+ off = tree_to_uhwi (offset);
+ if (INT_MAX < off)
+ return false;
+ arg = TREE_OPERAND (arg, 0);
+ if (TREE_CODE (arg) != STRING_CST)
+ return false;
+ init = arg;
+ }
+ /* Fall through. */
+
case STRING_CST:
{
- int i;
+ gcc_assert (off <= INT_MAX);
+
+ int i = off;
+ int n = TREE_STRING_LENGTH (init);
+ if (n <= i)
+ return false;
/* We need to loop through all elements to handle cases like
"\0" and "\0foobar". */
- for (i = 0; i < TREE_STRING_LENGTH (init); ++i)
+ for (i = 0; i < n; ++i)
if (TREE_STRING_POINTER (init)[i] != '\0')
- return false;
+ {
+ *nonzero = true;
+ return false;
+ }
return true;
}