summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-strlen.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2019-06-12 16:33:04 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2019-06-12 10:33:04 -0600
commit7802a8ec9a03e6ced5b5d8f9018c6b9f45677c3f (patch)
tree38646c19e96f5ea0cbd1edfaeeec89e7c2000611 /gcc/tree-ssa-strlen.c
parent4b557bcc0d0674011a45ad259f44b9830289bd1f (diff)
PR tree-optimization/90662 - strlen of a string in a vla plus offset not folded
gcc/ChangeLog: PR tree-optimization/90662 * tree-ssa-strlen.c (get_stridx): Handle simple VLAs and pointers to arrays. gcc/testsuite/ChangeLog: PR tree-optimization/90662 * gcc.dg/strlenopt-62.c: New test. * gcc.dg/strlenopt-63.c: New test. * gcc.dg/strlenopt-64.c: New test. From-SVN: r272197
Diffstat (limited to 'gcc/tree-ssa-strlen.c')
-rw-r--r--gcc/tree-ssa-strlen.c77
1 files changed, 60 insertions, 17 deletions
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 98d8420d8cf..944650cecd5 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -296,34 +296,77 @@ get_stridx (tree 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++)
+ HOST_WIDE_INT offset = 0;
+ /* Follow a chain of at most 5 assignments. */
+ for (int 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)
+ if (!is_gimple_assign (def_stmt))
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))
+
+ tree_code rhs_code = gimple_assign_rhs_code (def_stmt);
+ tree ptr, off;
+
+ if (rhs_code == ADDR_EXPR)
+ {
+ /* Handle indices/offsets into VLAs which are implemented
+ as pointers to arrays. */
+ ptr = gimple_assign_rhs1 (def_stmt);
+ ptr = TREE_OPERAND (ptr, 0);
+
+ /* Handle also VLAs of types larger than char. */
+ if (tree eltsize = TYPE_SIZE_UNIT (TREE_TYPE (ptr)))
+ {
+ if (TREE_CODE (ptr) == ARRAY_REF)
+ {
+ off = TREE_OPERAND (ptr, 1);
+ /* Scale the array index by the size of the element
+ type (normally 1 for char). */
+ off = fold_build2 (MULT_EXPR, TREE_TYPE (off), off,
+ eltsize);
+ ptr = TREE_OPERAND (ptr, 0);
+ }
+ else
+ off = integer_zero_node;
+ }
+ else
+ return 0;
+
+ if (TREE_CODE (ptr) != MEM_REF)
+ return 0;
+
+ /* Add the MEM_REF byte offset. */
+ tree mem_off = TREE_OPERAND (ptr, 1);
+ off = fold_build2 (PLUS_EXPR, TREE_TYPE (off), off, mem_off);
+ ptr = TREE_OPERAND (ptr, 0);
+ }
+ else if (rhs_code == POINTER_PLUS_EXPR)
+ {
+ ptr = gimple_assign_rhs1 (def_stmt);
+ off = gimple_assign_rhs2 (def_stmt);
+ }
+ else
+ return 0;
+
+ if (TREE_CODE (ptr) != SSA_NAME
+ || !tree_fits_shwi_p (off))
return 0;
- HOST_WIDE_INT this_off = tree_to_shwi (rhs2);
+ HOST_WIDE_INT this_off = tree_to_shwi (off);
if (this_off < 0)
return 0;
- off = (unsigned HOST_WIDE_INT) off + this_off;
- if (off < 0)
+ offset = (unsigned HOST_WIDE_INT) offset + this_off;
+ if (offset < 0)
return 0;
- if (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)])
+ if (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)])
{
strinfo *si
- = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (rhs1)]);
- if (si && compare_nonzero_chars (si, off) >= 0)
- return get_stridx_plus_constant (si, off, exp);
+ = get_strinfo (ssa_ver_to_stridx[SSA_NAME_VERSION (ptr)]);
+ if (si && compare_nonzero_chars (si, offset) >= 0)
+ return get_stridx_plus_constant (si, offset, exp);
}
- e = rhs1;
+ e = ptr;
}
return 0;
}