if (fnspec.arg_direct_p (arg))
flags |= EAF_DIRECT;
if (fnspec.arg_noescape_p (arg))
- flags |= EAF_NOESCAPE;
+ flags |= EAF_NOESCAPE | EAF_NODIRECTESCAPE;
if (fnspec.arg_readonly_p (arg))
flags |= EAF_NOCLOBBER;
}
fprintf (out, " noclobber");
if (flags & EAF_NOESCAPE)
fprintf (out, " noescape");
+ if (flags & EAF_NODIRECTESCAPE)
+ fprintf (out, " nodirectescape");
if (flags & EAF_UNUSED)
fprintf (out, " unused");
if (newline)
static int
deref_flags (int flags, bool ignore_stores)
{
- int ret = 0;
+ int ret = EAF_NODIRECTESCAPE;
if (flags & EAF_UNUSED)
ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE;
else
void
modref_lattice::init ()
{
- flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED;
+ flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED
+ | EAF_NODIRECTESCAPE;
open = true;
known = false;
}
{
int call_flags = gimple_call_arg_flags (call, i);
if (ignore_stores)
- call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+ call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE
+ | EAF_NODIRECTESCAPE;
if (!record_ipa)
lattice[index].merge (call_flags);
/* For pure functions we have implicit NOCLOBBER
and NOESCAPE. */
if (ecf_flags & ECF_PURE)
- flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE);
+ flags &= ~(EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE);
if (flags)
{
if (!ee->direct)
flags = deref_flags (flags, ignore_stores);
else if (ignore_stores)
- flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+ flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
flags |= ee->min_flags;
to_info->arg_flags[ee->parm_index] &= flags;
if (to_info->arg_flags[ee->parm_index])
if (!ee->direct)
flags = deref_flags (flags, ignore_stores);
else if (ignore_stores)
- flags |= EAF_NOCLOBBER | EAF_NOESCAPE;
+ flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE;
flags |= ee->min_flags;
to_info_lto->arg_flags[ee->parm_index] &= flags;
if (to_info_lto->arg_flags[ee->parm_index])
}
else if (ignore_stores)
{
- flags |= EAF_NOESCAPE | EAF_NOCLOBBER;
- flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER;
+ flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
+ flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE;
}
flags |= ee->min_flags;
flags_lto |= ee->min_flags;
/* Nonzero if the argument is not used by the function. */
#define EAF_UNUSED (1 << 3)
+/* Nonzero if the argument itself does not escape but memory
+ referenced by it can escape. */
+#define EAF_NODIRECTESCAPE (1 << 4)
+
/* Call return flags. */
/* Mask for the argument number that is returned. Lower two bits of
the return flags, encodes argument slots zero to three. */
make_constraint_to (escaped_id, op);
}
+/* Make constraint necessary to make all indirect references
+ from VI escape. */
+
+static void
+make_indirect_escape_constraint (varinfo_t vi)
+{
+ struct constraint_expr lhs, rhs;
+ /* escaped = *(VAR + UNKNOWN); */
+ lhs.type = SCALAR;
+ lhs.var = escaped_id;
+ lhs.offset = 0;
+ rhs.type = DEREF;
+ rhs.var = vi->id;
+ rhs.offset = UNKNOWN_OFFSET;
+ process_constraint (new_constraint (lhs, rhs));
+}
+
/* Add constraints to that the solution of VI is transitively closed. */
static void
set. The argument would still get clobbered through the
escape solution. */
if ((flags & EAF_NOCLOBBER)
- && (flags & EAF_NOESCAPE))
+ && (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
{
varinfo_t uses = get_call_use_vi (stmt);
varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
if (!(flags & EAF_DIRECT))
make_transitive_closure_constraints (tem);
make_copy_constraint (uses, tem->id);
+ if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
+ make_indirect_escape_constraint (tem);
returns_uses = true;
}
- else if (flags & EAF_NOESCAPE)
+ else if (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE))
{
struct constraint_expr lhs, rhs;
varinfo_t uses = get_call_use_vi (stmt);
rhs.var = nonlocal_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
+ if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
+ make_indirect_escape_constraint (tem);
returns_uses = true;
}
else