re PR tree-optimization/63989 (tree-ssa-strlen.c doesn't handle constant pointer plus and array refs if constant offset is smaller than known constant string length)

PR tree-optimization/63989
	* params.def (PARAM_MAX_TRACKED_STRLENS): Increment default
	from 1000 to 10000.
	* tree-ssa-strlen.c (get_strinfo): Moved earlier.
	(get_stridx): If we don't have a record for certain SSA_NAME,
	but it is POINTER_PLUS_EXPR of some SSA_NAME we do with
	constant offset, call get_stridx_plus_constant.
	(get_stridx_plus_constant): New function.
	(zero_length_string): Don't use get_stridx here.

	* gcc.dg/strlenopt-27.c: New test.

From-SVN: r219362
This commit is contained in:
Jakub Jelinek 2015-01-08 22:30:56 +01:00 committed by Jakub Jelinek
parent 57534689d7
commit 204a913bda
5 changed files with 168 additions and 14 deletions

View File

@ -1,5 +1,15 @@
2015-01-08 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/63989
* params.def (PARAM_MAX_TRACKED_STRLENS): Increment default
from 1000 to 10000.
* tree-ssa-strlen.c (get_strinfo): Moved earlier.
(get_stridx): If we don't have a record for certain SSA_NAME,
but it is POINTER_PLUS_EXPR of some SSA_NAME we do with
constant offset, call get_stridx_plus_constant.
(get_stridx_plus_constant): New function.
(zero_length_string): Don't use get_stridx here.
PR target/55023
PR middle-end/64388
* dse.c (struct insn_info): Mention frame_read set also

View File

@ -1078,7 +1078,7 @@ DEFPARAM (PARAM_MAX_TRACKED_STRLENS,
"max-tracked-strlens",
"Maximum number of strings for which strlen optimization pass will "
"track string lengths",
1000, 0, 0)
10000, 0, 0)
/* Keep this in sync with the sched_pressure_algorithm enum. */
DEFPARAM (PARAM_SCHED_PRESSURE_ALGORITHM,

View File

@ -1,3 +1,8 @@
2015-01-08 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/63989
* gcc.dg/strlenopt-27.c: New test.
2015-01-08 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (set_up_logging): New function.

View File

@ -0,0 +1,23 @@
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-strlen" } */
#include "strlenopt.h"
__attribute__((noinline, noclone)) size_t
fn1 (char *p)
{
strcpy (p, "foobar");
return strlen (p + 2); // This strlen should be optimized into 4.
}
int
main (void)
{
char p[] = "barfoo";
if (fn1 (p) != 4)
abort ();
return 0;
}
/* { dg-final { scan-tree-dump-times "strlen \\(" 0 "strlen" } } */
/* { dg-final { cleanup-tree-dump "strlen" } } */

View File

@ -181,6 +181,18 @@ struct laststmt_struct
int stridx;
} laststmt;
static int get_stridx_plus_constant (strinfo, HOST_WIDE_INT, tree);
/* Return strinfo vector entry IDX. */
static inline strinfo
get_strinfo (int idx)
{
if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
return NULL;
return (*stridx_to_strinfo)[idx];
}
/* Helper function for get_stridx. */
static int
@ -219,7 +231,43 @@ get_stridx (tree exp)
tree s, o;
if (TREE_CODE (exp) == SSA_NAME)
return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
{
if (ssa_ver_to_stridx[SSA_NAME_VERSION (exp)])
return ssa_ver_to_stridx[SSA_NAME_VERSION (exp)];
int i;
tree e = exp;
HOST_WIDE_INT off = 0;
for (i = 0; i < 5; i++)
{
gimple def_stmt = SSA_NAME_DEF_STMT (e);
if (!is_gimple_assign (def_stmt)
|| gimple_assign_rhs_code (def_stmt) != POINTER_PLUS_EXPR)
return 0;
tree rhs1 = gimple_assign_rhs1 (def_stmt);
tree rhs2 = gimple_assign_rhs2 (def_stmt);
if (TREE_CODE (rhs1) != SSA_NAME
|| !tree_fits_shwi_p (rhs2))
return 0;
HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
if (this_off < 0)
return 0;
off = (unsigned HOST_WIDE_INT) off + this_off;
if (off < 0)
return 0;
if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
{
strinfo si
= get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
if (si
&& si->length
&& TREE_CODE (si->length) == INTEGER_CST
&& compare_tree_int (si->length, off) != -1)
return get_stridx_plus_constant (si, off, exp);
}
e = rhs1;
}
return 0;
}
if (TREE_CODE (exp) == ADDR_EXPR)
{
@ -388,16 +436,6 @@ free_strinfo (strinfo si)
pool_free (strinfo_pool, si);
}
/* Return strinfo vector entry IDX. */
static inline strinfo
get_strinfo (int idx)
{
if (vec_safe_length (stridx_to_strinfo) <= (unsigned int) idx)
return NULL;
return (*stridx_to_strinfo)[idx];
}
/* Set strinfo in the vector entry IDX to SI. */
static inline void
@ -555,7 +593,7 @@ maybe_invalidate (gimple stmt)
return nonempty;
}
/* Unshare strinfo record SI, if it has recount > 1 or
/* Unshare strinfo record SI, if it has refcount > 1 or
if stridx_to_strinfo vector is shared with some other
bbs. */
@ -605,6 +643,82 @@ verify_related_strinfos (strinfo origsi)
return si;
}
/* Attempt to create a new strinfo for BASESI + OFF, or find existing
strinfo if there is any. Return it's idx, or 0 if no strinfo has
been created. */
static int
get_stridx_plus_constant (strinfo basesi, HOST_WIDE_INT off, tree ptr)
{
gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME);
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
return 0;
if (basesi->length == NULL_TREE
|| TREE_CODE (basesi->length) != INTEGER_CST
|| compare_tree_int (basesi->length, off) == -1
|| !tree_fits_shwi_p (basesi->length))
return 0;
HOST_WIDE_INT len = tree_to_shwi (basesi->length) - off;
strinfo si = basesi, chainsi;
if (si->first || si->prev || si->next)
si = verify_related_strinfos (basesi);
if (si == NULL
|| si->length == NULL_TREE
|| TREE_CODE (si->length) != INTEGER_CST)
return 0;
if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
gcc_checking_assert (compare_tree_int (si->length, off) != -1);
for (chainsi = si; chainsi->next; chainsi = si)
{
si = get_strinfo (chainsi->next);
if (si == NULL
|| si->first != chainsi->first
|| si->prev != chainsi->idx
|| si->length == NULL_TREE
|| TREE_CODE (si->length) != INTEGER_CST)
break;
int r = compare_tree_int (si->length, len);
if (r != 1)
{
if (r == 0)
{
ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] = si->idx;
return si->idx;
}
break;
}
}
int idx = new_stridx (ptr);
if (idx == 0)
return 0;
si = new_strinfo (ptr, idx, build_int_cst (size_type_node, len));
set_strinfo (idx, si);
if (chainsi->next)
{
strinfo nextsi = unshare_strinfo (get_strinfo (chainsi->next));
si->next = nextsi->idx;
nextsi->prev = idx;
}
chainsi = unshare_strinfo (chainsi);
if (chainsi->first == 0)
chainsi->first = chainsi->idx;
chainsi->next = idx;
if (chainsi->endptr == NULL_TREE && len == 0)
chainsi->endptr = ptr;
si->endptr = chainsi->endptr;
si->prev = chainsi->idx;
si->first = chainsi->first;
si->writable = chainsi->writable;
return si->idx;
}
/* Note that PTR, a pointer SSA_NAME initialized in the current stmt, points
to a zero-length string and if possible chain it to a related strinfo
chain whose part is or might be CHAINSI. */
@ -614,8 +728,10 @@ zero_length_string (tree ptr, strinfo chainsi)
{
strinfo si;
int idx;
if (ssa_ver_to_stridx.length () <= SSA_NAME_VERSION (ptr))
ssa_ver_to_stridx.safe_grow_cleared (num_ssa_names);
gcc_checking_assert (TREE_CODE (ptr) == SSA_NAME
&& get_stridx (ptr) == 0);
&& ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)] == 0);
if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ptr))
return NULL;