diff mbox

Teach PTA and aliasing about strdup/strndup

Message ID 20110929211737.GX2687@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Sept. 29, 2011, 9:17 p.m. UTC
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.


	Jakub

Comments

Richard Biener Sept. 30, 2011, 8:25 a.m. UTC | #1
On Thu, Sep 29, 2011 at 11:17 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> 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);

You don't want to deal with call-uses at this point.  I think you want
a similar effect as
         p = malloc (...);
         memcpy (p, src, ...);
thus,

   if (gimple_call_lhs (t))
     {
        /* The result gets a heap tag assigned.  */
        handle_lhs_call (t, gimple_call_lhs (t), gimple_call_flags
(t), NULL, fndecl);
        /* Transfer all pointers from the source to the destination memory.  */
        get_constraint_for_ptr_offset (gimple_call_lhs (t), NULL_TREE, &lhsc);
        get_constraint_for_ptr_offset (gimple_call_rhs1 (t), NULL_TREE, &rhsc);
        do_deref (&lhsc);
        do_deref (&rhsc);
        process_all_all_constraints (lhsc, rhsc);
     }
   return true;

Richard.

> +         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
>
diff mbox

Patch

--- 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" } } */