This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Teach PTA and aliasing about strdup/strndup
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 29 Sep 2011 23:17:37 +0200
- Subject: [PATCH] Teach PTA and aliasing about strdup/strndup
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
This patch teaches PTA/aliasing about strdup/strndup (that the passed in
string is just read and doesn't escape in any way, and that otherwise it
acts as malloc or other allocation calls.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2011-09-29 Jakub Jelinek <jakub@redhat.com>
* 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.
* gcc.dg/strlenopt-21.c: New test.
--- gcc/tree-ssa-structalias.c.jj 2011-09-29 15:27:17.000000000 +0200
+++ gcc/tree-ssa-structalias.c 2011-09-29 15:31:02.000000000 +0200
@@ -4130,6 +4130,16 @@ find_func_aliases_for_builtin_call (gimp
case BUILT_IN_REMQUOL:
case BUILT_IN_FREE:
return true;
+ case BUILT_IN_STRDUP:
+ case BUILT_IN_STRNDUP:
+ {
+ varinfo_t uses = get_call_use_vi (t);
+ make_constraint_to (uses->id, gimple_call_arg (t, 0));
+ if (gimple_call_lhs (t))
+ handle_lhs_call (t, gimple_call_lhs (t), gimple_call_flags (t),
+ NULL, fndecl);
+ return true;
+ }
/* Trampolines are special - they set up passing the static
frame. */
case BUILT_IN_INIT_TRAMPOLINE:
--- gcc/tree-ssa-alias.c.jj 2011-09-29 15:27:17.000000000 +0200
+++ gcc/tree-ssa-alias.c 2011-09-29 15:31:02.000000000 +0200
@@ -1506,6 +1506,8 @@ call_may_clobber_ref_p_1 (gimple call, a
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))
--- gcc/testsuite/gcc.dg/strlenopt-21.c.jj 2011-09-29 15:42:19.000000000 +0200
+++ gcc/testsuite/gcc.dg/strlenopt-21.c 2011-09-29 15:42:00.000000000 +0200
@@ -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" } } */
Jakub