diff options
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/strlenopt-21.c | 66 | ||||
-rw-r--r-- | gcc/tree-ssa-alias.c | 60 | ||||
-rw-r--r-- | gcc/tree-ssa-structalias.c | 18 |
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: |