This implements removal of malloc/free pairs when allowed for a
subset of all possible cases.  The idea is to identify possible
candidates (we free the return value of an allocation call) and
for them do not make the allocation function necessary because
of the free.  If nothing else made the allocation necessary,
go ahead and make the free call not necessary as well after
propagation.

Integrating this with control-dependence is much harder but
would then handle also if (p) free (p).  The testcases contain
some tricky cases that break when you do it too simple-minded.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

Richard.

2011-09-08  Richard Guenther  <rguent...@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.

Index: gcc/tree-ssa-dce.c
===================================================================
*** gcc/tree-ssa-dce.c  (revision 178684)
--- gcc/tree-ssa-dce.c  (working copy)
*************** mark_stmt_if_obviously_necessary (gimple
*** 309,314 ****
--- 309,316 ----
            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
*************** mark_all_reaching_defs_necessary_1 (ao_r
*** 625,630 ****
--- 627,651 ----
        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;
*************** propagate_necessity (struct edge_list *e
*** 805,810 ****
--- 826,850 ----
          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);
  
*************** eliminate_unnecessary_stmts (void)
*** 1218,1223 ****
--- 1258,1286 ----
  
          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))
            {
Index: gcc/testsuite/gcc.dg/tree-ssa/pr19831-1.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pr19831-1.c   (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/pr19831-1.c   (revision 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" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c   (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/pr19831-2.c   (revision 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" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c   (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/pr19831-3.c   (revision 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" } } */

Reply via email to