On Thu, Sep 29, 2011 at 11:17 PM, Jakub Jelinek <ja...@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 <ja...@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 >