aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-structalias.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-structalias.c')
-rw-r--r--gcc/tree-ssa-structalias.c142
1 files changed, 115 insertions, 27 deletions
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index c70f5af..153ddf5 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4060,48 +4060,117 @@ static void
handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
int callescape_id, bool writes_global_memory)
{
+ int relevant_indirect_flags = EAF_NO_INDIRECT_CLOBBER | EAF_NO_INDIRECT_READ
+ | EAF_NO_INDIRECT_ESCAPE;
+ int relevant_flags = relevant_indirect_flags
+ | EAF_NO_DIRECT_CLOBBER
+ | EAF_NO_DIRECT_READ
+ | EAF_NO_DIRECT_ESCAPE;
+ if (gimple_call_lhs (stmt))
+ {
+ relevant_flags |= EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY;
+ relevant_indirect_flags |= EAF_NOT_RETURNED_INDIRECTLY;
+
+ /* If value is never read from it can not be returned indirectly
+ (except through the escape solution).
+ For all flags we get these implications right except for
+ not_returned because we miss return functions in ipa-prop. */
+
+ if (flags & EAF_NO_DIRECT_READ)
+ flags |= EAF_NOT_RETURNED_INDIRECTLY;
+ }
+
/* If the argument is not used we can ignore it.
Similarly argument is invisile for us if it not clobbered, does not
escape, is not read and can not be returned. */
- if ((flags & EAF_UNUSED)
- || ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
- | EAF_NOT_RETURNED))
- == (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
- | EAF_NOT_RETURNED)))
+ if ((flags & EAF_UNUSED) || ((flags & relevant_flags) == relevant_flags))
return;
+ /* Produce varinfo for direct accesses to ARG. */
varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
tem->is_reg_var = true;
make_constraint_to (tem->id, arg);
make_any_offset_constraints (tem);
- if (!(flags & EAF_DIRECT))
- make_transitive_closure_constraints (tem);
+ bool callarg_transitive = false;
+
+ /* As an compile time optimization if we make no difference between
+ direct and indirect accesses make arg transitively closed.
+ This avoids the need to build indir arg and do everything twice. */
+ if (((flags & EAF_NO_INDIRECT_CLOBBER) != 0)
+ == ((flags & EAF_NO_DIRECT_CLOBBER) != 0)
+ && (((flags & EAF_NO_INDIRECT_READ) != 0)
+ == ((flags & EAF_NO_DIRECT_READ) != 0))
+ && (((flags & EAF_NO_INDIRECT_ESCAPE) != 0)
+ == ((flags & EAF_NO_DIRECT_ESCAPE) != 0))
+ && (((flags & EAF_NOT_RETURNED_INDIRECTLY) != 0)
+ == ((flags & EAF_NOT_RETURNED_DIRECTLY) != 0)))
+ {
+ make_transitive_closure_constraints (tem);
+ callarg_transitive = true;
+ gcc_checking_assert (!(flags & EAF_NO_DIRECT_READ));
+ }
+
+ /* If necessary, produce varinfo for indirect accesses to ARG. */
+ varinfo_t indir_tem = NULL;
+ if (!callarg_transitive
+ && (flags & relevant_indirect_flags) != relevant_indirect_flags)
+ {
+ struct constraint_expr lhs, rhs;
+ indir_tem = new_var_info (NULL_TREE, "indircallarg", true);
+ indir_tem->is_reg_var = true;
+
+ /* indir_term = *tem. */
+ lhs.type = SCALAR;
+ lhs.var = indir_tem->id;
+ lhs.offset = 0;
+
+ rhs.type = DEREF;
+ rhs.var = tem->id;
+ rhs.offset = UNKNOWN_OFFSET;
+ process_constraint (new_constraint (lhs, rhs));
+
+ make_any_offset_constraints (indir_tem);
- if (!(flags & EAF_NOT_RETURNED))
+ /* If we do not read indirectly there is no need for transitive closure.
+ We know there is only one level of indirection. */
+ if (!(flags & EAF_NO_INDIRECT_READ))
+ make_transitive_closure_constraints (indir_tem);
+ gcc_checking_assert (!(flags & EAF_NO_DIRECT_READ));
+ }
+
+ if (gimple_call_lhs (stmt))
{
- struct constraint_expr cexpr;
- cexpr.var = tem->id;
- if (flags & EAF_NOT_RETURNED_DIRECTLY)
+ if (!(flags & EAF_NOT_RETURNED_DIRECTLY))
{
- cexpr.type = DEREF;
- cexpr.offset = UNKNOWN_OFFSET;
+ struct constraint_expr cexpr;
+ cexpr.var = tem->id;
+ cexpr.type = SCALAR;
+ cexpr.offset = 0;
+ results->safe_push (cexpr);
}
- else
+ if (!callarg_transitive & !(flags & EAF_NOT_RETURNED_INDIRECTLY))
{
+ struct constraint_expr cexpr;
+ cexpr.var = indir_tem->id;
cexpr.type = SCALAR;
cexpr.offset = 0;
+ results->safe_push (cexpr);
}
- results->safe_push (cexpr);
}
- if (!(flags & EAF_NOREAD))
+ if (!(flags & EAF_NO_DIRECT_READ))
{
varinfo_t uses = get_call_use_vi (stmt);
make_copy_constraint (uses, tem->id);
+ if (!callarg_transitive & !(flags & EAF_NO_INDIRECT_READ))
+ make_copy_constraint (uses, indir_tem->id);
}
+ else
+ /* To read indirectly we need to read directly. */
+ gcc_checking_assert (flags & EAF_NO_INDIRECT_READ);
- if (!(flags & EAF_NOCLOBBER))
+ if (!(flags & EAF_NO_DIRECT_CLOBBER))
{
struct constraint_expr lhs, rhs;
@@ -4118,8 +4187,25 @@ handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
/* callclobbered = arg. */
make_copy_constraint (get_call_clobber_vi (stmt), tem->id);
}
+ if (!callarg_transitive & !(flags & EAF_NO_INDIRECT_CLOBBER))
+ {
+ struct constraint_expr lhs, rhs;
- if (!(flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
+ /* *indir_arg = callescape. */
+ lhs.type = DEREF;
+ lhs.var = indir_tem->id;
+ lhs.offset = 0;
+
+ rhs.type = SCALAR;
+ rhs.var = callescape_id;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
+
+ /* callclobbered = indir_arg. */
+ make_copy_constraint (get_call_clobber_vi (stmt), indir_tem->id);
+ }
+
+ if (!(flags & (EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE)))
{
struct constraint_expr lhs, rhs;
@@ -4136,18 +4222,18 @@ handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
if (writes_global_memory)
make_escape_constraint (arg);
}
- else if (!(flags & EAF_NOESCAPE))
+ else if (!callarg_transitive & !(flags & EAF_NO_INDIRECT_ESCAPE))
{
struct constraint_expr lhs, rhs;
- /* callescape = *(arg + UNKNOWN); */
+ /* callescape = *(indir_arg + UNKNOWN); */
lhs.var = callescape_id;
lhs.offset = 0;
lhs.type = SCALAR;
- rhs.var = tem->id;
- rhs.offset = UNKNOWN_OFFSET;
- rhs.type = DEREF;
+ rhs.var = indir_tem->id;
+ rhs.offset = 0;
+ rhs.type = SCALAR;
process_constraint (new_constraint (lhs, rhs));
if (writes_global_memory)
@@ -4264,20 +4350,22 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results,
&& TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
{
int flags = gimple_call_retslot_flags (stmt);
- if ((flags & (EAF_NOESCAPE | EAF_NOT_RETURNED))
- != (EAF_NOESCAPE | EAF_NOT_RETURNED))
+ const int relevant_flags = EAF_NO_DIRECT_ESCAPE
+ | EAF_NOT_RETURNED_DIRECTLY;
+
+ if (!(flags & EAF_UNUSED) && (flags & relevant_flags) != relevant_flags)
{
auto_vec<ce_s> tmpc;
get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
- if (!(flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
+ if (!(flags & EAF_NO_DIRECT_ESCAPE))
{
make_constraints_to (callescape->id, tmpc);
if (writes_global_memory)
make_constraints_to (escaped_id, tmpc);
}
- if (!(flags & EAF_NOT_RETURNED))
+ if (!(flags & EAF_NOT_RETURNED_DIRECTLY))
{
struct constraint_expr *c;
unsigned i;