aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Glisse <marc.glisse@inria.fr>2014-06-24 20:50:00 +0200
committerMarc Glisse <glisse@gcc.gnu.org>2014-06-24 18:50:00 +0000
commit24314386b32b93c759c6722a2c18facae15128ea (patch)
tree81ba342aeb4db1f2fe70e25917fc6972499cd2d2
parent84e0f57e35738500e44fd21753e31295d4700bfb (diff)
downloadgcc-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/ChangeLog8
-rw-r--r--gcc/passes.def2
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/calloc.C50
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-9.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/calloc-1.c29
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/calloc-2.c27
-rw-r--r--gcc/tree-ssa-strlen.c85
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;
}