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
This commit is contained in:
parent
84e0f57e35
commit
24314386b3
|
@ -1,3 +1,11 @@
|
|||
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>
|
||||
|
||||
PR target/61570
|
||||
|
|
|
@ -188,7 +188,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
NEXT_PASS (pass_dce);
|
||||
NEXT_PASS (pass_forwprop);
|
||||
NEXT_PASS (pass_phiopt);
|
||||
NEXT_PASS (pass_strlen);
|
||||
NEXT_PASS (pass_ccp);
|
||||
/* After CCP we rewrite no longer addressed locals into SSA
|
||||
form if possible. */
|
||||
|
@ -251,6 +250,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
NEXT_PASS (pass_reassoc);
|
||||
NEXT_PASS (pass_strength_reduction);
|
||||
NEXT_PASS (pass_dominator);
|
||||
NEXT_PASS (pass_strlen);
|
||||
NEXT_PASS (pass_vrp);
|
||||
/* The only const/copy propagation opportunities left after
|
||||
DOM and VRP should be due to degenerate PHI nodes. So rather than
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
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>
|
||||
|
||||
* gcc.target/aarch64/aapcs64/abitest-2.h (saved_return_address): New
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* { 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)
|
|||
char *p, q[10];
|
||||
strcpy (q, "abc");
|
||||
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. */
|
||||
return strlen (p);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ main ()
|
|||
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 "strcpy \\(" 1 "strlen" } } */
|
||||
/* { dg-final { scan-tree-dump-times "strcat \\(" 0 "strlen" } } */
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* { 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" } } */
|
|
@ -0,0 +1,27 @@
|
|||
/* { 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)
|
|||
si->length = fold_build2_loc (loc, MINUS_EXPR, size_type_node,
|
||||
lhs, si->length);
|
||||
break;
|
||||
case BUILT_IN_MALLOC:
|
||||
break;
|
||||
/* BUILT_IN_CALLOC always has si->length set. */
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
break;
|
||||
|
@ -508,6 +511,7 @@ maybe_invalidate (gimple stmt)
|
|||
if (!si->dont_invalidate)
|
||||
{
|
||||
ao_ref r;
|
||||
/* Do not use si->length. */
|
||||
ao_ref_init_from_ptr_and_size (&r, si->ptr, NULL_TREE);
|
||||
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)
|
|||
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.
|
||||
For p = "abcd" + 2; compute associated length, or if
|
||||
p = q + off is pointing to a '\0' character of a string, call
|
||||
|
@ -1832,6 +1909,14 @@ strlen_optimize_stmt (gimple_stmt_iterator *gsi)
|
|||
case BUILT_IN_STRCAT_CHK:
|
||||
handle_builtin_strcat (DECL_FUNCTION_CODE (callee), gsi);
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue