Commit 24314386 by Marc Glisse Committed by Marc Glisse

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
parent 84e0f57e
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> 2014-06-24 Jakub Jelinek <jakub@redhat.com>
PR target/61570 PR target/61570
......
...@@ -188,7 +188,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -188,7 +188,6 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_dce); NEXT_PASS (pass_dce);
NEXT_PASS (pass_forwprop); NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt); NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_strlen);
NEXT_PASS (pass_ccp); NEXT_PASS (pass_ccp);
/* After CCP we rewrite no longer addressed locals into SSA /* After CCP we rewrite no longer addressed locals into SSA
form if possible. */ form if possible. */
...@@ -251,6 +250,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -251,6 +250,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_reassoc); NEXT_PASS (pass_reassoc);
NEXT_PASS (pass_strength_reduction); NEXT_PASS (pass_strength_reduction);
NEXT_PASS (pass_dominator); NEXT_PASS (pass_dominator);
NEXT_PASS (pass_strlen);
NEXT_PASS (pass_vrp); NEXT_PASS (pass_vrp);
/* The only const/copy propagation opportunities left after /* The only const/copy propagation opportunities left after
DOM and VRP should be due to degenerate PHI nodes. So rather than DOM and VRP should be due to degenerate PHI nodes. So rather than
......
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> 2014-06-24 Yufeng Zhang <yufeng.zhang@arm.com>
* gcc.target/aarch64/aapcs64/abitest-2.h (saved_return_address): New * gcc.target/aarch64/aapcs64/abitest-2.h (saved_return_address): New
......
/* { 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" } } */
...@@ -18,7 +18,7 @@ fn2 (int r) ...@@ -18,7 +18,7 @@ fn2 (int r)
char *p, q[10]; char *p, q[10];
strcpy (q, "abc"); strcpy (q, "abc");
p = r ? "a" : q; 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. */ optimized away. */
return strlen (p); return strlen (p);
} }
...@@ -98,7 +98,7 @@ main () ...@@ -98,7 +98,7 @@ main ()
return 0; 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 "memcpy \\(" 6 "strlen" } } */
/* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strcpy \\(" 1 "strlen" } } */
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */ /* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
......
/* { 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" } } */
/* { 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" } } */
...@@ -483,6 +483,9 @@ get_string_length (strinfo si) ...@@ -483,6 +483,9 @@ get_string_length (strinfo si)
si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node, si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
lhs, si->length); lhs, si->length);
break; break;
case BUILT_IN_MALLOC:
break;
/* BUILT_IN_CALLOC always has si->length set. */
default: default:
gcc_unreachable (); gcc_unreachable ();
break; break;
...@@ -508,6 +511,7 @@ maybe_invalidate (gimple stmt) ...@@ -508,6 +511,7 @@ maybe_invalidate (gimple stmt)
if (!si->dont_invalidate) if (!si->dont_invalidate)
{ {
ao_ref r; ao_ref r;
/* Do not use si->length. */
ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE); ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
if (stmt_may_clobber_ref_p_1 (stmt, &r)) 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) ...@@ -1595,6 +1599,79 @@ handle_builtin_strcat (enum built_in_function bcode, gimple_stmt_iterator *gsi)
fprintf (dump_file, "not possible.\n"); 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. /* Handle a POINTER_PLUS_EXPR statement.
For p = "abcd" + 2; compute associated length, or if For p = "abcd" + 2; compute associated length, or if
p = q + off is pointing to a '\0' character of a string, call p = q + off is pointing to a '\0' character of a string, call
...@@ -1832,6 +1909,14 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi) ...@@ -1832,6 +1909,14 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
case BUILT_IN_STRCAT_CHK: case BUILT_IN_STRCAT_CHK:
handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi); handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
break; 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: default:
break; break;
} }
......
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