diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 53eb2f29a19..33ba9dae10a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2015-01-08 Jakub Jelinek + 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 diff --git a/gcc/params.def b/gcc/params.def index 4e68273d074..cbdc4774047 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -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, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6ec4ba2ba32..c3ab41832ad 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-01-08 Jakub Jelinek + + PR tree-optimization/63989 + * gcc.dg/strlenopt-27.c: New test. + 2015-01-08 David Malcolm * jit.dg/harness.h (set_up_logging): New function. diff --git a/gcc/testsuite/gcc.dg/strlenopt-27.c b/gcc/testsuite/gcc.dg/strlenopt-27.c new file mode 100644 index 00000000000..8d06aac2611 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-27.c @@ -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" } } */ diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index acf4f588690..c9e8f1e5292 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -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;