#include "tree-ssa-propagate.h"
#include "gimple-pretty-print.h"
#include "params.h"
+#include "expr.h"
/* A vector indexed by SSA_NAME_VERSION. 0 means unknown, positive value
is an index into strinfo vector, negative value stands for
static int
get_stridx (tree exp)
{
- tree l;
+ tree s, o;
if (TREE_CODE (exp) == SSA_NAME)
return VEC_index (int, ssa_ver_to_stridx, SSA_NAME_VERSION (exp));
return idx;
}
- l = c_strlen (exp, 0);
- if (l != NULL_TREE
- && host_integerp (l, 1))
+ s = string_constant (exp, &o);
+ if (s != NULL_TREE
+ && (o == NULL_TREE || host_integerp (o, 0))
+ && TREE_STRING_LENGTH (s) > 0)
{
- unsigned HOST_WIDE_INT len = tree_low_cst (l, 1);
- if (len == (unsigned int) len
- && (int) len >= 0)
- return ~(int) len;
+ HOST_WIDE_INT offset = o ? tree_low_cst (o, 0) : 0;
+ const char *p = TREE_STRING_POINTER (s);
+ int max = TREE_STRING_LENGTH (s) - 1;
+
+ if (p[max] == '\0' && offset >= 0 && offset <= max)
+ return ~(int) strlen (p + offset);
}
return 0;
}
callee = gimple_call_fndecl (stmt);
gcc_assert (callee && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL);
lhs = gimple_call_lhs (stmt);
- gcc_assert (implicit_built_in_decls[BUILT_IN_STRCPY] != NULL_TREE);
+ gcc_assert (builtin_decl_implicit_p (BUILT_IN_STPCPY));
/* unshare_strinfo is intentionally not called here. The (delayed)
transformation of strcpy or strcat into stpcpy is done at the place
of the former strcpy/strcat call and so can affect all the strinfos
case BUILT_IN_STRCAT:
case BUILT_IN_STRCAT_CHK:
gsi = gsi_for_stmt (stmt);
- fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+ fn = builtin_decl_implicit (BUILT_IN_STRLEN);
gcc_assert (lhs == NULL_TREE);
lhs_var = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)), NULL);
add_referenced_var (lhs_var);
case BUILT_IN_STRCPY:
case BUILT_IN_STRCPY_CHK:
if (gimple_call_num_args (stmt) == 2)
- fn = implicit_built_in_decls[BUILT_IN_STPCPY];
+ fn = builtin_decl_implicit (BUILT_IN_STPCPY);
else
- fn = built_in_decls[BUILT_IN_STPCPY_CHK];
+ fn = builtin_decl_explicit (BUILT_IN_STPCPY_CHK);
gcc_assert (lhs == NULL_TREE);
if (dump_file && (dump_flags & TDF_DETAILS) != 0)
{
|| si->prev != chainsi->idx)
break;
}
- gcc_assert (chainsi->length);
+ gcc_assert (chainsi->length || chainsi->stmt);
if (chainsi->endptr == NULL_TREE)
{
chainsi = unshare_strinfo (chainsi);
chainsi->endptr = ptr;
}
- if (integer_zerop (chainsi->length))
+ if (chainsi->length && integer_zerop (chainsi->length))
{
if (chainsi->next)
{
if (chainsi->first == 0)
chainsi->first = chainsi->idx;
chainsi->next = idx;
+ if (chainsi->endptr == NULL_TREE)
+ chainsi->endptr = ptr;
si->prev = chainsi->idx;
si->first = chainsi->first;
si->writable = chainsi->writable;
tree tem;
si = unshare_strinfo (si);
- gcc_assert (si->length);
- tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
- si->length = fold_build2_loc (loc, PLUS_EXPR,
- TREE_TYPE (si->length), si->length,
- tem);
+ if (si->length)
+ {
+ tem = fold_convert_loc (loc, TREE_TYPE (si->length), adj);
+ si->length = fold_build2_loc (loc, PLUS_EXPR,
+ TREE_TYPE (si->length), si->length,
+ tem);
+ }
+ else if (si->stmt != NULL)
+ /* Delayed length computation is unaffected. */
+ ;
+ else
+ gcc_unreachable ();
+
si->endptr = NULL_TREE;
si->dont_invalidate = true;
}
{
case SSA_NAME:
break;
+ CASE_CONVERT:
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+ return;
+ if (TREE_CODE (ptr) == SSA_NAME)
+ break;
+ if (TREE_CODE (ptr) != ADDR_EXPR)
+ return;
+ /* FALLTHRU */
case ADDR_EXPR:
{
int *pidx = addr_stridxptr (TREE_OPERAND (ptr, 0));
*pidx = idx;
return;
}
- CASE_CONVERT:
- if (POINTER_TYPE_P (TREE_TYPE (ptr)))
- break;
- return;
default:
return;
}
{
case BUILT_IN_STRCPY:
case BUILT_IN_STRCPY_CHK:
- if (implicit_built_in_decls[BUILT_IN_STPCPY] == NULL_TREE
- || lhs != NULL_TREE)
+ if (lhs != NULL_TREE || !builtin_decl_implicit_p (BUILT_IN_STPCPY))
return;
break;
case BUILT_IN_STPCPY:
if (dsi->length == NULL_TREE)
{
+ strinfo chainsi;
+
/* If string length of src is unknown, use delayed length
computation. If string lenth of dst will be needed, it
can be computed by transforming this strcpy call into
stpcpy and subtracting dst from the return value. */
+
+ /* Look for earlier strings whose length could be determined if
+ this strcpy is turned into an stpcpy. */
+
+ if (dsi->prev != 0 && (chainsi = verify_related_strinfos (dsi)) != NULL)
+ {
+ for (; chainsi && chainsi != dsi; chainsi = get_strinfo (chainsi->next))
+ {
+ /* When setting a stmt for delayed length computation
+ prevent all strinfos through dsi from being
+ invalidated. */
+ chainsi = unshare_strinfo (chainsi);
+ chainsi->stmt = stmt;
+ chainsi->length = NULL_TREE;
+ chainsi->endptr = NULL_TREE;
+ chainsi->dont_invalidate = true;
+ }
+ }
dsi->stmt = stmt;
return;
}
switch (bcode)
{
case BUILT_IN_STRCPY:
- fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
if (lhs)
VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
break;
case BUILT_IN_STRCPY_CHK:
- fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+ fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
if (lhs)
VEC_replace (int, ssa_ver_to_stridx, SSA_NAME_VERSION (lhs), didx);
break;
/* This would need adjustment of the lhs (subtract one),
or detection that the trailing '\0' doesn't need to be
written, if it will be immediately overwritten.
- fn = built_in_decls[BUILT_IN_MEMPCPY]; */
+ fn = builtin_decl_explicit (BUILT_IN_MEMPCPY); */
if (lhs)
{
dsi->endptr = lhs;
/* This would need adjustment of the lhs (subtract one),
or detection that the trailing '\0' doesn't need to be
written, if it will be immediately overwritten.
- fn = built_in_decls[BUILT_IN_MEMPCPY_CHK]; */
+ fn = builtin_decl_explicit (BUILT_IN_MEMPCPY_CHK); */
if (lhs)
{
dsi->endptr = lhs;
if (si != NULL)
newlen = si->length;
else
- newlen = build_int_cst (TREE_TYPE (len), ~idx);
+ newlen = build_int_cst (size_type_node, ~idx);
oldlen = NULL_TREE;
if (olddsi != NULL)
{
with length endptr - p if we need to compute the length
later on. Don't do this transformation if we don't need
it. */
- if (implicit_built_in_decls[BUILT_IN_STPCPY] != NULL_TREE
- && lhs == NULL_TREE)
+ if (builtin_decl_implicit_p (BUILT_IN_STPCPY) && lhs == NULL_TREE)
{
if (didx == 0)
{
else
{
dsi->length = NULL;
- if (implicit_built_in_decls[BUILT_IN_STPCPY] != NULL_TREE
- && lhs == NULL_TREE)
+ if (lhs == NULL_TREE && builtin_decl_implicit_p (BUILT_IN_STPCPY))
dsi->dont_invalidate = true;
}
{
case BUILT_IN_STRCAT:
if (srclen != NULL_TREE)
- fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
else
- fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+ fn = builtin_decl_implicit (BUILT_IN_STRCPY);
break;
case BUILT_IN_STRCAT_CHK:
if (srclen != NULL_TREE)
- fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
+ fn = builtin_decl_explicit (BUILT_IN_MEMCPY_CHK);
else
- fn = built_in_decls[BUILT_IN_STRCPY_CHK];
+ fn = builtin_decl_explicit (BUILT_IN_STRCPY_CHK);
objsz = gimple_call_arg (stmt, 2);
break;
default: