re PR tree-optimization/19831 (Missing DSE/malloc/free optimization)
authorRichard Guenther <rguenther@suse.de>
Thu, 8 Sep 2011 13:00:23 +0000 (13:00 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 8 Sep 2011 13:00:23 +0000 (13:00 +0000)
2011-09-08  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/19831
* tree-ssa-dce.c (mark_all_reaching_defs_necessary_1): Also
skip builtins with vdefs that do not really store something.
(propagate_necessity): For calls to free that we can associate
with an allocation function do not mark the freed pointer
definition necessary.
(eliminate_unnecessary_stmts): Remove a call to free if
the associated call to an allocation function is not necessary.

* gcc.dg/tree-ssa/pr19831-1.c: New testcase.
* gcc.dg/tree-ssa/pr19831-2.c: Likewise.
* gcc.dg/tree-ssa/pr19831-3.c: Likewise.
* gcc.dg/errno-1.c: Adjust.

From-SVN: r178687

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/errno-1.c
gcc/testsuite/gcc.dg/tree-ssa/pr19831-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c [new file with mode: 0644]
gcc/tree-ssa-dce.c

index f4416030d23c1c91d2f35123114a7e840c6dd0fb..561c3dbecc1b36ca46539a35dd77ef8596c1417f 100644 (file)
@@ -1,3 +1,14 @@
+2011-09-08  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/19831
+       * tree-ssa-dce.c (mark_all_reaching_defs_necessary_1): Also
+       skip builtins with vdefs that do not really store something.
+       (propagate_necessity): For calls to free that we can associate
+       with an allocation function do not mark the freed pointer
+       definition necessary.
+       (eliminate_unnecessary_stmts): Remove a call to free if
+       the associated call to an allocation function is not necessary.
+
 2011-09-08  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/19831
index b432683ced97eb67902b48a8f988ddf614481462..c6109a6e52585955eedd99fb20f0fc9f89a714c5 100644 (file)
@@ -1,3 +1,11 @@
+2011-09-08  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/19831
+       * gcc.dg/tree-ssa/pr19831-1.c: New testcase.
+       * gcc.dg/tree-ssa/pr19831-2.c: Likewise.
+       * gcc.dg/tree-ssa/pr19831-3.c: Likewise.
+       * gcc.dg/errno-1.c: Adjust.
+
 2011-09-08  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/19831
index d0365bed45b066681a13180f097707df96bbc570..295deefbe78af68d514b95c987caaaff4efdaf2c 100644 (file)
@@ -6,7 +6,7 @@
 
 int main()
 {
-  void *p;
+  void * volatile p;
   errno = 0;
   p = malloc (-1);
   if (errno != 0)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-1.c
new file mode 100644 (file)
index 0000000..1c8f972
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+void test1(void)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  int *q = p;
+  *q++ = 4;
+  *q++ = 4;
+  __builtin_free (p);
+}
+
+void test3(int b)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  if (b)
+    __builtin_free (p);
+  *p = 5;
+}
+
+void test4(int b)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  if (b)
+    __builtin_free (p);
+  *p = 5;
+  __builtin_free (p);
+}
+
+/* { dg-final { scan-tree-dump-times "free" 0 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "malloc" 0 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c
new file mode 100644 (file)
index 0000000..bc7c4cc
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+void test1(void)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  *p++ = 4;
+  __builtin_free (p);
+}
+
+/* Undefined.  We can't do anything here.  */
+
+/* { dg-final { scan-tree-dump-times "free" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "malloc" 1 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c
new file mode 100644 (file)
index 0000000..02b5572
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+void test2(void)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  if (p == (void *)0)
+    __builtin_abort ();
+  __builtin_free (p);
+}
+
+void test5(int b)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  if (p)
+    __builtin_free (p);
+}
+
+void test6(void)
+{
+  int *p = __builtin_malloc (sizeof (int) * 4);
+  if (p == (void *)0)
+    __builtin_abort ();
+  if (p)
+    __builtin_free (p);
+}
+
+/* We should be able to remove all malloc/free pairs with CDDCE.
+   Assume p was non-NULL for test2.
+   For test5, it doesn't matter if p is NULL or non-NULL.  */
+
+/* { dg-final { scan-tree-dump-times "free" 0 "optimized" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "malloc" 0 "optimized" { xfail *-*-* } } } */
+
+/* But make sure we don't partially optimize for now.  */
+
+/* { dg-final { scan-tree-dump-times "free" 3 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "malloc" 3 "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index e29f3659be8b753b6dfeb5fb1df197c31943b59e..f225030de681ac7d1622995e97189db15ce710b4 100644 (file)
@@ -309,6 +309,8 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
            case BUILT_IN_CALLOC:
            case BUILT_IN_ALLOCA:
              return;
+
+           default:;
            }
        /* Most, but not all function calls are required.  Function calls that
           produce no result and have no side effects (i.e. const pure
@@ -625,6 +627,25 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
        return false;
     }
 
+  /* We want to skip statments that do not constitute stores but have
+     a virtual definition.  */
+  if (is_gimple_call (def_stmt))
+    {
+      tree callee = gimple_call_fndecl (def_stmt);
+      if (callee != NULL_TREE
+         && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+       switch (DECL_FUNCTION_CODE (callee))
+         {
+         case BUILT_IN_MALLOC:
+         case BUILT_IN_CALLOC:
+         case BUILT_IN_ALLOCA:
+         case BUILT_IN_FREE:
+           return false;
+
+         default:;
+         }
+    }
+
   mark_operand_necessary (vdef);
 
   return false;
@@ -805,6 +826,25 @@ propagate_necessity (struct edge_list *el)
          ssa_op_iter iter;
          tree use;
 
+         /* If this is a call to free which is directly fed by an
+            allocation function do not mark that necessary through
+            processing the argument.  */
+         if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+           {
+             tree ptr = gimple_call_arg (stmt, 0);
+             gimple def_stmt;
+             tree def_callee;
+             /* If the pointer we free is defined by an allocation
+                function do not add the call to the worklist.  */
+             if (TREE_CODE (ptr) == SSA_NAME
+                 && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
+                 && (def_callee = gimple_call_fndecl (def_stmt))
+                 && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+                 && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+                     || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+               continue;
+           }
+
          FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
            mark_operand_necessary (use);
 
@@ -1218,6 +1258,29 @@ eliminate_unnecessary_stmts (void)
 
          stats.total++;
 
+         /* We can mark a call to free as not necessary if the
+            defining statement of its argument is an allocation
+            function and that is not necessary itself.  */
+         if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+           {
+             tree ptr = gimple_call_arg (stmt, 0);
+             tree callee2;
+             gimple def_stmt;
+             if (TREE_CODE (ptr) != SSA_NAME)
+               continue;
+             def_stmt = SSA_NAME_DEF_STMT (ptr);
+             if (!is_gimple_call (def_stmt)
+                 || gimple_plf (def_stmt, STMT_NECESSARY))
+               continue;
+             callee2 = gimple_call_fndecl (def_stmt);
+             if (callee2 == NULL_TREE
+                 || DECL_BUILT_IN_CLASS (callee2) != BUILT_IN_NORMAL
+                 || (DECL_FUNCTION_CODE (callee2) != BUILT_IN_MALLOC
+                     && DECL_FUNCTION_CODE (callee2) != BUILT_IN_CALLOC))
+               continue;
+             gimple_set_plf (stmt, STMT_NECESSARY, false);
+           }
+
          /* If GSI is not necessary then remove it.  */
          if (!gimple_plf (stmt, STMT_NECESSARY))
            {