diff options
author | Marc Glisse <marc.glisse@inria.fr> | 2014-06-24 20:50:00 +0200 |
---|---|---|
committer | Marc Glisse <glisse@gcc.gnu.org> | 2014-06-24 18:50:00 +0000 |
commit | 24314386b32b93c759c6722a2c18facae15128ea (patch) | |
tree | 81ba342aeb4db1f2fe70e25917fc6972499cd2d2 | |
parent | 84e0f57e35738500e44fd21753e31295d4700bfb (diff) | |
download | gcc-24314386b32b93c759c6722a2c18facae15128ea.zip gcc-24314386b32b93c759c6722a2c18facae15128ea.tar.gz gcc-24314386b32b93c759c6722a2c18facae15128ea.tar.bz2 |
re PR tree-optimization/57742 (memset(malloc(n),0,n) -> calloc(n,1))
2014-06-24 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/57742
gcc/
* tree-ssa-strlen.c (get_string_length): Ignore malloc.
(handle_builtin_malloc, handle_builtin_memset): New functions.
(strlen_optimize_stmt): Call them.
* passes.def: Move strlen after loop+dom but before vrp.
gcc/testsuite/
* g++.dg/tree-ssa/calloc.C: New testcase.
* gcc.dg/tree-ssa/calloc-1.c: Likewise.
* gcc.dg/tree-ssa/calloc-2.c: Likewise.
* gcc.dg/strlenopt-9.c: Adapt.
From-SVN: r211956
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/passes.def | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/tree-ssa/calloc.C | 50 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/strlenopt-9.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/calloc-1.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/calloc-2.c | 27 | ||||
-rw-r--r-- | gcc/tree-ssa-strlen.c | 85 |
8 files changed, 210 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e29fcaf..48330ec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2014-06-24 Marc Glisse <marc.glisse@inria.fr> + + PR tree-optimization/57742 + * tree-ssa-strlen.c (get_string_length): Ignore malloc. + (handle_builtin_malloc, handle_builtin_memset): New functions. + (strlen_optimize_stmt): Call them. + * passes.def: Move strlen after loop+dom but before vrp. + 2014-06-24 Jakub Jelinek <jakub@redhat.com> PR target/61570 diff --git a/gcc/passes.def b/gcc/passes.def index de4c69d..280cf16 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -188,7 +188,6 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_dce); NEXT_PASS (pass_forwprop); NEXT_PASS (pass_phiopt); - NEXT_PASS (pass_strlen); NEXT_PASS (pass_ccp); /* After CCP we rewrite no longer addressed locals into SSA form if possible. */ @@ -251,6 +250,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_reassoc); NEXT_PASS (pass_strength_reduction); NEXT_PASS (pass_dominator); + NEXT_PASS (pass_strlen); NEXT_PASS (pass_vrp); /* The only const/copy propagation opportunities left after DOM and VRP should be due to degenerate PHI nodes. So rather than diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 913a9a6..e90b44f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2014-06-24 Marc Glisse <marc.glisse@inria.fr> + + PR tree-optimization/57742 + * g++.dg/tree-ssa/calloc.C: New testcase. + * gcc.dg/tree-ssa/calloc-1.c: Likewise. + * gcc.dg/tree-ssa/calloc-2.c: Likewise. + * gcc.dg/strlenopt-9.c: Adapt. + 2014-06-24 Yufeng Zhang <yufeng.zhang@arm.com> * gcc.target/aarch64/aapcs64/abitest-2.h (saved_return_address): New diff --git a/gcc/testsuite/g++.dg/tree-ssa/calloc.C b/gcc/testsuite/g++.dg/tree-ssa/calloc.C new file mode 100644 index 0000000..818ca41 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/calloc.C @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-optimized" } */ + +typedef __SIZE_TYPE__ size_t; +inline void* operator new(size_t, void* p) throw() { return p; } + +typedef void (*handler_t)(void); +extern handler_t get_handle(); + +inline void* operator new(size_t sz) +{ + void *p; + + if (sz == 0) + sz = 1; + + while ((p = __builtin_malloc (sz)) == 0) + { + handler_t handler = get_handle (); + if (! handler) + throw 42; + handler (); + } + return p; +} + +struct vect { + int *start, *end; + vect(size_t n) { + start = end = 0; + if (n > (size_t)-1 / sizeof(int)) + throw 33; + if (n != 0) + start = static_cast<int*> (operator new (n * sizeof(int))); + end = start + n; + int *p = start; + for (size_t l = n; l > 0; --l, ++p) + *p = 0; + } +}; + +void f (void *p, int n) +{ + new (p) vect(n); +} + +/* { dg-final { scan-tree-dump-times "calloc" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "malloc" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "memset" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/strlenopt-9.c b/gcc/testsuite/gcc.dg/strlenopt-9.c index 6590d70..2610f6e 100644 --- a/gcc/testsuite/gcc.dg/strlenopt-9.c +++ b/gcc/testsuite/gcc.dg/strlenopt-9.c @@ -18,7 +18,7 @@ fn2 (int r) char *p, q[10]; strcpy (q, "abc"); p = r ? "a" : q; - /* String length for p varies, therefore strlen below isn't + /* String length is constant for both alternatives, and strlen is optimized away. */ return strlen (p); } @@ -98,7 +98,7 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "strlen \\(" 4 "strlen" } } */ +/* { dg-final { scan-tree-dump-times "strlen \\(" 3 "strlen" } } */ /* { dg-final { scan-tree-dump-times "memcpy \\(" 6 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/calloc-1.c b/gcc/testsuite/gcc.dg/tree-ssa/calloc-1.c new file mode 100644 index 0000000..cfeee33 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/calloc-1.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +extern int a; +extern int *b; +int n; +void* f(long *q) +{ + int *p = __builtin_malloc (n); + ++*q; + if (p) + { + ++*q; + a = 2; + __builtin_memset (p, 0, n); + *b = 3; + } + return p; +} +void* g(void) +{ + float *p = __builtin_calloc (8, 4); + return __builtin_memset (p, 0, 24); // not 32 +} + +/* { dg-final { scan-tree-dump-times "calloc" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "malloc" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "memset" "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/calloc-2.c b/gcc/testsuite/gcc.dg/tree-ssa/calloc-2.c new file mode 100644 index 0000000..10f9d18 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/calloc-2.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int n, nn; +void* f() +{ + char *p = __builtin_calloc (n, 1); + p[42] = '\n'; + __builtin_memset (p, 0, nn); + return p; +} + +void* g(int m1, int m2) +{ + char *p = __builtin_malloc (m2); + while (--m1) + { + __builtin_memset (p, 0, m2); + p[n] = 'b'; + } + return p; +} + +/* { dg-final { scan-tree-dump-times "malloc" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "calloc" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "memset" 2 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index dc659c9..6d7b852 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -483,6 +483,9 @@ get_string_length (strinfo si) si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node, lhs, si->length); break; + case BUILT_IN_MALLOC: + break; + /* BUILT_IN_CALLOC always has si->length set. */ default: gcc_unreachable (); break; @@ -508,6 +511,7 @@ maybe_invalidate (gimple stmt) if (!si->dont_invalidate) { ao_ref r; + /* Do not use si->length. */ ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE); if (stmt_may_clobber_ref_p_1 (stmt, &r)) { @@ -1595,6 +1599,79 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi) fprintf (dump_file, "not possible.\n"); } +/* Handle a call to malloc or calloc. */ + +static void +handle_builtin_malloc (enum built_in_function bcode, gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + tree lhs = gimple_call_lhs (stmt); + gcc_assert (get_stridx (lhs) == 0); + int idx = new_stridx (lhs); + tree length = NULL_TREE; + if (bcode == BUILT_IN_CALLOC) + length = build_int_cst (size_type_node, 0); + strinfo si = new_strinfo (lhs, idx, length); + if (bcode == BUILT_IN_CALLOC) + si->endptr = lhs; + set_strinfo (idx, si); + si->writable = true; + si->stmt = stmt; + si->dont_invalidate = true; +} + +/* Handle a call to memset. + After a call to calloc, memset(,0,) is unnecessary. + memset(malloc(n),0,n) is calloc(n,1). */ + +static bool +handle_builtin_memset (gimple_stmt_iterator *gsi) +{ + gimple stmt2 = gsi_stmt (*gsi); + if (!integer_zerop (gimple_call_arg (stmt2, 1))) + return true; + tree ptr = gimple_call_arg (stmt2, 0); + int idx1 = get_stridx (ptr); + if (idx1 <= 0) + return true; + strinfo si1 = get_strinfo (idx1); + if (!si1) + return true; + gimple stmt1 = si1->stmt; + if (!stmt1 || !is_gimple_call (stmt1)) + return true; + tree callee1 = gimple_call_fndecl (stmt1); + if (!gimple_call_builtin_p (stmt1, BUILT_IN_NORMAL)) + return true; + enum built_in_function code1 = DECL_FUNCTION_CODE (callee1); + tree size = gimple_call_arg (stmt2, 2); + if (code1 == BUILT_IN_CALLOC) + /* Not touching stmt1 */ ; + else if (code1 == BUILT_IN_MALLOC + && operand_equal_p (gimple_call_arg (stmt1, 0), size, 0)) + { + gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt1); + update_gimple_call (&gsi1, builtin_decl_implicit (BUILT_IN_CALLOC), 2, + size, build_one_cst (size_type_node)); + } + else + return true; + tree lhs = gimple_call_lhs (stmt2); + unlink_stmt_vdef (stmt2); + if (lhs) + { + gimple assign = gimple_build_assign (lhs, ptr); + gsi_replace (gsi, assign, false); + } + else + { + gsi_remove (gsi, true); + release_defs (stmt2); + } + + return false; +} + /* Handle a POINTER_PLUS_EXPR statement. For p = "abcd" + 2; compute associated length, or if p = q + off is pointing to a '\0' character of a string, call @@ -1832,6 +1909,14 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi) case BUILT_IN_STRCAT_CHK: handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi); break; + case BUILT_IN_MALLOC: + case BUILT_IN_CALLOC: + handle_builtin_malloc (DECL_FUNCTION_CODE (callee), gsi); + break; + case BUILT_IN_MEMSET: + if (!handle_builtin_memset (gsi)) + return false; + break; default: break; } |