aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2011-09-30 14:58:27 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2011-09-30 14:58:27 +0000
commit77efe8191baab106cf0444cf66cf9d466d2b742a (patch)
tree547d9c6e16c8da1b5c7e98044325a0f5be53cc1e
parent65d1b157e98fd9f131bb9021f5d1d29f335ffaa0 (diff)
* tree-ssa-structalias.c (find_func_aliases_for_builtin_call): Handle
BUILT_IN_STRDUP and BUILT_IN_STRNDUP. * tree-ssa-alias.c (call_may_clobber_ref_p_1): Likewise. Fix handling of BUILT_IN_STRNCAT and BUILT_IN_STRNCAT_CHK. (ref_maybe_used_by_call_p_1): Fix handling of BUILT_IN_STRCAT, BUILT_IN_STRNCAT, BUILT_IN_STRCAT_CHK and BUILT_IN_STRNCAT_CHK. * gcc.dg/strlenopt-21.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@179387 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-21.c66
-rw-r--r--gcc/tree-ssa-alias.c60
-rw-r--r--gcc/tree-ssa-structalias.c18
5 files changed, 150 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 52d80822bac..525ca80ba6b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2011-09-30 Jakub Jelinek <jakub@redhat.com>
+ Richard Guenther <rguenther@suse.de>
+
+ * tree-ssa-structalias.c (find_func_aliases_for_builtin_call): Handle
+ BUILT_IN_STRDUP and BUILT_IN_STRNDUP.
+ * tree-ssa-alias.c (call_may_clobber_ref_p_1): Likewise. Fix
+ handling of BUILT_IN_STRNCAT and BUILT_IN_STRNCAT_CHK.
+ (ref_maybe_used_by_call_p_1): Fix handling of BUILT_IN_STRCAT,
+ BUILT_IN_STRNCAT, BUILT_IN_STRCAT_CHK and BUILT_IN_STRNCAT_CHK.
+
2011-09-30 Jan Beulich <jbeulich@suse.com>
* lto-cgraph.c (output_cgraph): Remove processing of
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0b1e69f154e..2d8e0664f1c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2011-09-30 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.dg/strlenopt-21.c: New test.
+
2011-09-30 Revital Eres <revital.eres@linaro.org>
* gcc.dg/sms-10.c: New file
diff --git a/gcc/testsuite/gcc.dg/strlenopt-21.c b/gcc/testsuite/gcc.dg/strlenopt-21.c
new file mode 100644
index 00000000000..cd5fc5d928f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-21.c
@@ -0,0 +1,66 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-strlen -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+struct S { char *p; size_t l; };
+
+__attribute__((noinline, noclone)) struct S
+foo (char *x, int n)
+{
+ int i;
+ char a[64];
+ char *p = strchr (x, '\0');
+ struct S s;
+ /* strcpy here is optimized into memcpy, length computed as p - x + 1. */
+ strcpy (a, x);
+ /* strcat here is optimized into memcpy. */
+ strcat (p, "abcd");
+ for (i = 0; i < n; i++)
+ if ((i % 123) == 53)
+ /* strcat here is optimized into strlen and memcpy. */
+ strcat (a, "efg");
+ s.p = strdup (a);
+ /* The strlen should be optimized here into 4. */
+ s.l = strlen (p);
+ return s;
+}
+
+int
+main ()
+{
+ char buf[32];
+ struct S s;
+ buf[0] = 'z';
+ buf[1] = '\0';
+ s = foo (buf, 0);
+ if (s.l != 4 || memcmp (buf, "zabcd", 6) != 0)
+ abort ();
+ if (s.p == NULL)
+ return 0;
+ if (memcmp (s.p, "z", 2) != 0)
+ abort ();
+ s = foo (buf, 60);
+ if (s.l != 4 || memcmp (buf, "zabcdabcd", 10) != 0)
+ abort ();
+ if (s.p == NULL)
+ return 0;
+ if (memcmp (s.p, "zabcdefg", 9) != 0)
+ abort ();
+ s = foo (buf, 240);
+ if (s.l != 4 || memcmp (buf, "zabcdabcdabcd", 14) != 0)
+ abort ();
+ if (s.p == NULL)
+ return 0;
+ if (memcmp (s.p, "zabcdabcdefgefg", 16) != 0)
+ abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "strlen \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "memcpy \\(" 3 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcpy \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "strchr \\(" 1 "strlen" } } */
+/* { dg-final { scan-tree-dump-times "stpcpy \\(" 0 "strlen" } } */
+/* { dg-final { cleanup-tree-dump "strlen" } } */
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 10c529b114f..82307decaf4 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -1178,8 +1178,20 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
&& DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (callee))
{
- /* All the following functions clobber memory pointed to by
- their first argument. */
+ /* All the following functions read memory pointed to by
+ their second argument. strcat/strncat additionally
+ reads memory pointed to by the first argument. */
+ case BUILT_IN_STRCAT:
+ case BUILT_IN_STRNCAT:
+ {
+ ao_ref dref;
+ ao_ref_init_from_ptr_and_size (&dref,
+ gimple_call_arg (call, 0),
+ NULL_TREE);
+ if (refs_may_alias_p_1 (&dref, ref, false))
+ return true;
+ }
+ /* FALLTHRU */
case BUILT_IN_STRCPY:
case BUILT_IN_STRNCPY:
case BUILT_IN_MEMCPY:
@@ -1187,8 +1199,6 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
case BUILT_IN_MEMPCPY:
case BUILT_IN_STPCPY:
case BUILT_IN_STPNCPY:
- case BUILT_IN_STRCAT:
- case BUILT_IN_STRNCAT:
{
ao_ref dref;
tree size = NULL_TREE;
@@ -1199,14 +1209,23 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
size);
return refs_may_alias_p_1 (&dref, ref, false);
}
+ case BUILT_IN_STRCAT_CHK:
+ case BUILT_IN_STRNCAT_CHK:
+ {
+ ao_ref dref;
+ ao_ref_init_from_ptr_and_size (&dref,
+ gimple_call_arg (call, 0),
+ NULL_TREE);
+ if (refs_may_alias_p_1 (&dref, ref, false))
+ return true;
+ }
+ /* FALLTHRU */
case BUILT_IN_STRCPY_CHK:
case BUILT_IN_STRNCPY_CHK:
case BUILT_IN_MEMCPY_CHK:
case BUILT_IN_MEMMOVE_CHK:
case BUILT_IN_MEMPCPY_CHK:
case BUILT_IN_STPCPY_CHK:
- case BUILT_IN_STRCAT_CHK:
- case BUILT_IN_STRNCAT_CHK:
{
ao_ref dref;
tree size = NULL_TREE;
@@ -1226,6 +1245,19 @@ ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
size);
return refs_may_alias_p_1 (&dref, ref, false);
}
+ /* These read memory pointed to by the first argument. */
+ case BUILT_IN_STRDUP:
+ case BUILT_IN_STRNDUP:
+ {
+ ao_ref dref;
+ tree size = NULL_TREE;
+ if (gimple_call_num_args (call) == 2)
+ size = gimple_call_arg (call, 1);
+ ao_ref_init_from_ptr_and_size (&dref,
+ gimple_call_arg (call, 0),
+ size);
+ return refs_may_alias_p_1 (&dref, ref, false);
+ }
/* The following builtins do not read from memory. */
case BUILT_IN_FREE:
case BUILT_IN_MALLOC:
@@ -1467,7 +1499,12 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
{
ao_ref dref;
tree size = NULL_TREE;
- if (gimple_call_num_args (call) == 3)
+ /* Don't pass in size for strncat, as the maximum size
+ is strlen (dest) + n + 1 instead of n, resp.
+ n + 1 at dest + strlen (dest), but strlen (dest) isn't
+ known. */
+ if (gimple_call_num_args (call) == 3
+ && DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT)
size = gimple_call_arg (call, 2);
ao_ref_init_from_ptr_and_size (&dref,
gimple_call_arg (call, 0),
@@ -1486,7 +1523,12 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
{
ao_ref dref;
tree size = NULL_TREE;
- if (gimple_call_num_args (call) == 4)
+ /* Don't pass in size for __strncat_chk, as the maximum size
+ is strlen (dest) + n + 1 instead of n, resp.
+ n + 1 at dest + strlen (dest), but strlen (dest) isn't
+ known. */
+ if (gimple_call_num_args (call) == 4
+ && DECL_FUNCTION_CODE (callee) != BUILT_IN_STRNCAT_CHK)
size = gimple_call_arg (call, 2);
ao_ref_init_from_ptr_and_size (&dref,
gimple_call_arg (call, 0),
@@ -1506,6 +1548,8 @@ call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
being the definition point for the pointer. */
case BUILT_IN_MALLOC:
case BUILT_IN_CALLOC:
+ case BUILT_IN_STRDUP:
+ case BUILT_IN_STRNDUP:
/* Unix98 specifies that errno is set on allocation failure. */
if (flag_errno_math
&& targetm.ref_may_alias_errno (ref))
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 1023acfab19..821fc7d92b2 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4130,6 +4130,24 @@ find_func_aliases_for_builtin_call (gimple t)
case BUILT_IN_REMQUOL:
case BUILT_IN_FREE:
return true;
+ case BUILT_IN_STRDUP:
+ case BUILT_IN_STRNDUP:
+ if (gimple_call_lhs (t))
+ {
+ handle_lhs_call (t, gimple_call_lhs (t), gimple_call_flags (t),
+ NULL, fndecl);
+ get_constraint_for_ptr_offset (gimple_call_lhs (t),
+ NULL_TREE, &lhsc);
+ get_constraint_for_ptr_offset (gimple_call_arg (t, 0),
+ NULL_TREE, &rhsc);
+ do_deref (&lhsc);
+ do_deref (&rhsc);
+ process_all_all_constraints (lhsc, rhsc);
+ VEC_free (ce_s, heap, lhsc);
+ VEC_free (ce_s, heap, rhsc);
+ return true;
+ }
+ break;
/* Trampolines are special - they set up passing the static
frame. */
case BUILT_IN_INIT_TRAMPOLINE: