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>
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
allocation functions as necessary.
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
* gcc.dg/tree-ssa/ssa-dce-8.c: New testcase.
2011-09-08 Tobias Burnus <burnus@net-b.de>
......
......@@ -6,7 +6,7 @@
int main()
{
void *p;
void * volatile p;
errno = 0;
p = malloc (-1);
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)
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))
{
......
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