Commit 996e1de5 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/19831 (Missing DSE/malloc/free optimization)

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
parent c22c0db2
2011-09-08 Richard Guenther <rguenther@suse.de> 2011-09-08 Richard Guenther <rguenther@suse.de>
PR tree-optimization/19831 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
* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Do not mark * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Do not mark
allocation functions as necessary. allocation functions as necessary.
2011-09-08 Richard Guenther <rguenther@suse.de> 2011-09-08 Richard Guenther <rguenther@suse.de>
PR tree-optimization/19831 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
* gcc.dg/tree-ssa/ssa-dce-8.c: New testcase. * gcc.dg/tree-ssa/ssa-dce-8.c: New testcase.
2011-09-08 Tobias Burnus <burnus@net-b.de> 2011-09-08 Tobias Burnus <burnus@net-b.de>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
int main() int main()
{ {
void *p; void * volatile p;
errno = 0; errno = 0;
p = malloc (-1); p = malloc (-1);
if (errno != 0) if (errno != 0)
......
/* { 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" } } */
/* { 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" } } */
/* { 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" } } */
...@@ -309,6 +309,8 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive) ...@@ -309,6 +309,8 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive)
case BUILT_IN_CALLOC: case BUILT_IN_CALLOC:
case BUILT_IN_ALLOCA: case BUILT_IN_ALLOCA:
return; return;
default:;
} }
/* Most, but not all function calls are required. Function calls that /* Most, but not all function calls are required. Function calls that
produce no result and have no side effects (i.e. const pure 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, ...@@ -625,6 +627,25 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
return false; 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); mark_operand_necessary (vdef);
return false; return false;
...@@ -805,6 +826,25 @@ propagate_necessity (struct edge_list *el) ...@@ -805,6 +826,25 @@ propagate_necessity (struct edge_list *el)
ssa_op_iter iter; ssa_op_iter iter;
tree use; 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) FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
mark_operand_necessary (use); mark_operand_necessary (use);
...@@ -1218,6 +1258,29 @@ eliminate_unnecessary_stmts (void) ...@@ -1218,6 +1258,29 @@ eliminate_unnecessary_stmts (void)
stats.total++; 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 GSI is not necessary then remove it. */
if (!gimple_plf (stmt, STMT_NECESSARY)) if (!gimple_plf (stmt, STMT_NECESSARY))
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment