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
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)
{
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
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. */
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. */
{
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;