diff options
Diffstat (limited to 'gcc/tree-ssa-structalias.c')
-rw-r--r-- | gcc/tree-ssa-structalias.c | 142 |
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; |