From: Richard Guenther Date: Sat, 28 Jun 2008 13:17:20 +0000 (+0000) Subject: tree-ssa-structalias.c (callused_id, [...]): Add. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=15c151967dd1cde61b79d26374f608f63a29d411;p=gcc.git tree-ssa-structalias.c (callused_id, [...]): Add. 2008-06-28 Richard Guenther * tree-ssa-structalias.c (callused_id, var_callused, callused_tree): Add. (handle_pure_call): New function. (find_func_aliases): Call it. (find_what_p_points_to): Handle the call-used set. (clobber_what_escaped): Likewise. (compute_call_used_vars): New function. (init_base_vars): Init the call-used variable. (do_sd_constraint): Do not propagate the solution from CALLUSED but use CALLUSED as a placeholder. (solve_graph): Likewise. * tree-flow-inline.h (gimple_call_used_vars): New function. * tree-flow.h (struct gimple_df): Add call_used_vars bitmap. (compute_call_used_vars): Declare. * tree-ssa-alias.c (set_initial_properties): Call compute_call_used_vars. (reset_alias_info): Clear call-used variables. (add_call_clobber_ops): Assert we are not called for const/pure functions. Remove handling of them. (add_call_read_ops): Handle pure functions by adding the call-used set of variables as VUSEs. * tree-ssa.c (init_tree_ssa): Allocate call-used bitmap. (delete_tree_ssa): Free it. * tree-dfa.c (remove_referenced_var): Clear the var from the call-used bitmap. * gcc.dg/tree-ssa/pr24287.c: Remove XFAIL. From-SVN: r137222 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3dc9e8f6603..8a53395b23f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2008-06-28 Richard Guenther + + * tree-ssa-structalias.c (callused_id, var_callused, + callused_tree): Add. + (handle_pure_call): New function. + (find_func_aliases): Call it. + (find_what_p_points_to): Handle the call-used set. + (clobber_what_escaped): Likewise. + (compute_call_used_vars): New function. + (init_base_vars): Init the call-used variable. + (do_sd_constraint): Do not propagate the solution from CALLUSED + but use CALLUSED as a placeholder. + (solve_graph): Likewise. + * tree-flow-inline.h (gimple_call_used_vars): New function. + * tree-flow.h (struct gimple_df): Add call_used_vars bitmap. + (compute_call_used_vars): Declare. + * tree-ssa-alias.c (set_initial_properties): Call + compute_call_used_vars. + (reset_alias_info): Clear call-used variables. + (add_call_clobber_ops): Assert we are not called for const/pure + functions. Remove handling of them. + (add_call_read_ops): Handle pure functions by adding the + call-used set of variables as VUSEs. + * tree-ssa.c (init_tree_ssa): Allocate call-used bitmap. + (delete_tree_ssa): Free it. + * tree-dfa.c (remove_referenced_var): Clear the var from the + call-used bitmap. + 2008-06-28 Kai Tietz * tree.c (build_varargs_function_type_list): New. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d4de302f794..e3f8556acac 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2008-06-28 Richard Guenther + + * gcc.dg/tree-ssa/pr24287.c: Remove XFAIL. + 2008-06-27 Mark Mitchell * g++.dg/abi/arm_cxa_vec2.C: New test. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c b/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c index c4b172295b4..63120457c4d 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr24287.c @@ -21,5 +21,5 @@ int g(void) link_error (); return t2 == 2; } -/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" } } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index a1780399cc6..285af39b3ca 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -746,6 +746,7 @@ remove_referenced_var (tree var) unsigned int uid = DECL_UID (var); clear_call_clobbered (var); + bitmap_clear_bit (gimple_call_used_vars (cfun), uid); if ((v_ann = var_ann (var))) { /* Preserve var_anns of globals, but clear their alias info. */ diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index c84964c1cdd..bff697db5ae 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -66,6 +66,15 @@ gimple_call_clobbered_vars (const struct function *fun) return fun->gimple_df->call_clobbered_vars; } +/* Call-used variables in the function. If bit I is set, then + REFERENCED_VARS (I) is call-used at pure function call-sites. */ +static inline bitmap +gimple_call_used_vars (const struct function *fun) +{ + gcc_assert (fun && fun->gimple_df); + return fun->gimple_df->call_used_vars; +} + /* Array of all variables referenced in the function. */ static inline htab_t gimple_referenced_vars (const struct function *fun) diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index ded7687b75e..961054703db 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -162,6 +162,10 @@ struct gimple_df GTY(()) REFERENCED_VARS (I) is call-clobbered. */ bitmap call_clobbered_vars; + /* Call-used variables in the function. If bit I is set, then + REFERENCED_VARS (I) is call-used at pure function call-sites. */ + bitmap call_used_vars; + /* Addressable variables in the function. If bit I is set, then REFERENCED_VARS (I) has had its address taken. Note that CALL_CLOBBERED_VARS and ADDRESSABLE_VARS are not related. An @@ -1174,6 +1178,7 @@ tree gimple_fold_indirect_ref (tree); /* In tree-ssa-structalias.c */ bool find_what_p_points_to (tree); bool clobber_what_escaped (void); +void compute_call_used_vars (void); /* In tree-ssa-live.c */ extern void remove_unused_locals (void); diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 7c24739e407..9a6552bb9d5 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -505,7 +505,7 @@ compute_tag_properties (void) VEC_free (tree, heap, taglist); } -/* Set up the initial variable clobbers and globalness. +/* Set up the initial variable clobbers, call-uses and globalness. When this function completes, only tags whose aliases need to be clobbered will be set clobbered. Tags clobbered because they contain call clobbered vars are handled in compute_tag_properties. */ @@ -543,6 +543,8 @@ set_initial_properties (struct alias_info *ai) pt_anything_mask |= ESCAPE_TO_CALL; } + compute_call_used_vars (); + for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++) { struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr); @@ -2000,6 +2002,9 @@ reset_alias_info (void) /* There should be no call-clobbered variable left. */ gcc_assert (bitmap_empty_p (gimple_call_clobbered_vars (cfun))); + /* Clear the call-used variables. */ + bitmap_clear (gimple_call_used_vars (cfun)); + /* Clear flow-sensitive points-to information from each SSA name. */ for (i = 1; i < num_ssa_names; i++) { diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index 71fb883f84a..0aeea9f7f93 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -1660,7 +1660,10 @@ add_call_clobber_ops (tree stmt, tree callee) bitmap_iterator bi; stmt_ann_t s_ann = stmt_ann (stmt); bitmap not_read_b, not_written_b; - + tree call = get_call_expr_in (stmt); + + gcc_assert (!(call_expr_flags (call) & (ECF_PURE | ECF_CONST))); + /* If we created .GLOBAL_VAR earlier, just use it. */ if (gimple_global_var (cfun)) { @@ -1674,12 +1677,10 @@ add_call_clobber_ops (tree stmt, tree callee) or write that variable. */ not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL; not_written_b = callee ? ipa_reference_get_not_written_global (callee) : NULL; - /* Add a VDEF operand for every call clobbered variable. */ EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi) { tree var = referenced_var_lookup (u); - unsigned int escape_mask = var_ann (var)->escape_mask; tree real_var = var; bool not_read; bool not_written; @@ -1697,24 +1698,6 @@ add_call_clobber_ops (tree stmt, tree callee) /* See if this variable is really clobbered by this function. */ - /* Trivial case: Things escaping only to pure/const are not - clobbered by non-pure-const, and only read by pure/const. */ - if ((escape_mask & ~(ESCAPE_TO_PURE_CONST)) == 0) - { - tree call = get_call_expr_in (stmt); - if (call_expr_flags (call) & (ECF_CONST | ECF_PURE)) - { - add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true); - clobber_stats.unescapable_clobbers_avoided++; - continue; - } - else - { - clobber_stats.unescapable_clobbers_avoided++; - continue; - } - } - if (not_written) { clobber_stats.static_write_clobbers_avoided++; @@ -1739,18 +1722,47 @@ add_call_read_ops (tree stmt, tree callee) bitmap_iterator bi; stmt_ann_t s_ann = stmt_ann (stmt); bitmap not_read_b; + tree call = get_call_expr_in (stmt); + + /* Const functions do not reference memory. */ + if (call_expr_flags (call) & ECF_CONST) + return; - /* if the function is not pure, it may reference memory. Add - a VUSE for .GLOBAL_VAR if it has been created. See add_referenced_var - for the heuristic used to decide whether to create .GLOBAL_VAR. */ + not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL; + + /* For pure functions we compute non-escaped uses separately. */ + if (call_expr_flags (call) & ECF_PURE) + EXECUTE_IF_SET_IN_BITMAP (gimple_call_used_vars (cfun), 0, u, bi) + { + tree var = referenced_var_lookup (u); + tree real_var = var; + bool not_read; + + if (unmodifiable_var_p (var)) + continue; + + not_read = not_read_b + ? bitmap_bit_p (not_read_b, DECL_UID (real_var)) + : false; + + clobber_stats.readonly_clobbers++; + + /* See if this variable is really used by this function. */ + if (!not_read) + add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true); + else + clobber_stats.static_readonly_clobbers_avoided++; + } + + /* Add a VUSE for .GLOBAL_VAR if it has been created. See + add_referenced_var for the heuristic used to decide whether to + create .GLOBAL_VAR. */ if (gimple_global_var (cfun)) { tree var = gimple_global_var (cfun); add_virtual_operand (var, s_ann, opf_use, NULL, 0, -1, true); return; } - - not_read_b = callee ? ipa_reference_get_not_read_global (callee) : NULL; /* Add a VUSE for each call-clobbered variable. */ EXECUTE_IF_SET_IN_BITMAP (gimple_call_clobbered_vars (cfun), 0, u, bi) diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 2b6c56fa1a7..4a3896bc440 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -296,7 +296,7 @@ get_varinfo_fc (unsigned int n) /* Static IDs for the special variables. */ enum { nothing_id = 0, anything_id = 1, readonly_id = 2, - escaped_id = 3, nonlocal_id = 4, integer_id = 5 }; + escaped_id = 3, nonlocal_id = 4, callused_id = 5, integer_id = 6 }; /* Variable that represents the unknown pointer. */ static varinfo_t var_anything; @@ -318,6 +318,10 @@ static tree escaped_tree; static varinfo_t var_nonlocal; static tree nonlocal_tree; +/* Variable that represents call-used memory. */ +static varinfo_t var_callused; +static tree callused_tree; + /* Variable that represents integers. This is used for when people do things like &0->a.b. */ static varinfo_t var_integer; @@ -1429,11 +1433,13 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c, if (get_varinfo (t)->is_special_var) flag |= bitmap_ior_into (sol, get_varinfo (t)->solution); /* Merging the solution from ESCAPED needlessly increases - the set. Use ESCAPED as representative instead. */ - else if (get_varinfo (t)->id == escaped_id + the set. Use ESCAPED as representative instead. + Same for CALLUSED. */ + else if ((get_varinfo (t)->id == escaped_id + || get_varinfo (t)->id == callused_id) && !bitmap_bit_p (sol, get_varinfo (t)->id)) { - bitmap_set_bit (sol, escaped_id); + bitmap_set_bit (sol, get_varinfo (t)->id); flag = true; } else if (add_graph_edge (graph, lhs, t)) @@ -2369,8 +2375,9 @@ solve_graph (constraint_graph_t graph) solution_empty = bitmap_empty_p (solution); if (!solution_empty - /* Do not propagate the ESCAPED solution. */ - && i != escaped_id) + /* Do not propagate the ESCAPED/CALLUSED solutions. */ + && i != escaped_id + && i != callused_id) { bitmap_iterator bi; @@ -3702,6 +3709,61 @@ handle_const_call (tree stmt) VEC_free (ce_s, heap, lhsc); } +/* For non-IPA mode, generate constraints necessary for a call to a + pure function in statement STMT. */ + +static void +handle_pure_call (tree stmt) +{ + tree call = get_call_expr_in (stmt); + tree arg; + call_expr_arg_iterator iter; + + /* Memory reached from pointer arguments is call-used. */ + FOR_EACH_CALL_EXPR_ARG (arg, iter, call) + if (could_have_pointers (arg)) + make_constraint_to (callused_id, arg); + + /* The static chain is used as well. */ + if (CALL_EXPR_STATIC_CHAIN (call)) + make_constraint_to (callused_id, CALL_EXPR_STATIC_CHAIN (call)); + + /* If the call returns a pointer it may point to reachable memory + from the arguments. */ + if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT + && could_have_pointers (GIMPLE_STMT_OPERAND (stmt, 0))) + { + tree lhs = GIMPLE_STMT_OPERAND (stmt, 0); + VEC(ce_s, heap) *lhsc = NULL; + struct constraint_expr rhsc; + struct constraint_expr *lhsp; + unsigned j; + + get_constraint_for (lhs, &lhsc); + + /* If this is a nested function then it can return anything. */ + if (CALL_EXPR_STATIC_CHAIN (call)) + { + rhsc.var = anything_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint_1 (new_constraint (*lhsp, rhsc), true); + VEC_free (ce_s, heap, lhsc); + return; + } + + /* Else just add the call-used memory here. Escaped variables + and globals will be dealt with in handle_lhs_call. */ + rhsc.var = callused_id; + rhsc.offset = 0; + rhsc.type = ADDRESSOF; + for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) + process_constraint_1 (new_constraint (*lhsp, rhsc), true); + VEC_free (ce_s, heap, lhsc); + } +} + /* Walk statement T setting up aliasing constraints according to the references found in T. This function is the main part of the constraint builder. AI points to auxiliary alias information used @@ -3778,6 +3840,13 @@ find_func_aliases (tree origt) && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1))) handle_const_call (t); } + else if (flags & ECF_PURE) + { + handle_pure_call (t); + if (TREE_CODE (t) == GIMPLE_MODIFY_STMT + && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1))) + handle_lhs_call (GIMPLE_STMT_OPERAND (t, 0)); + } /* Pure functions can return addresses in and of memory reachable from their arguments, but they are not an escape point for reachable memory of their arguments. But as we @@ -4940,7 +5009,8 @@ find_what_p_points_to (tree p) pi->pt_null = 1; else if (vi->id == anything_id || vi->id == nonlocal_id - || vi->id == escaped_id) + || vi->id == escaped_id + || vi->id == callused_id) was_pt_anything = 1; else if (vi->id == readonly_id) was_pt_anything = 1; @@ -5007,6 +5077,15 @@ clobber_what_escaped (void) variable for escaped_id. */ vi = get_varinfo (find (escaped_id)); + /* If call-used memory escapes we need to include it in the + set of escaped variables. This can happen if a pure + function returns a pointer and this pointer escapes. */ + if (bitmap_bit_p (vi->solution, callused_id)) + { + varinfo_t cu_vi = get_varinfo (find (callused_id)); + bitmap_ior_into (vi->solution, cu_vi->solution); + } + /* Mark variables in the solution call-clobbered. */ EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi) { @@ -5036,6 +5115,54 @@ clobber_what_escaped (void) return true; } +/* Compute the call-used variables. */ + +void +compute_call_used_vars (void) +{ + varinfo_t vi; + unsigned int i; + bitmap_iterator bi; + bool has_anything_id = false; + + if (!have_alias_info) + return; + + /* This variable may have been collapsed, let's get the real + variable for escaped_id. */ + vi = get_varinfo (find (callused_id)); + + /* Mark variables in the solution call-clobbered. */ + EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi) + { + varinfo_t vi = get_varinfo (i); + + if (vi->is_artificial_var) + { + /* For anything_id and integer_id we need to make + all local addressable vars call-used. */ + if (vi->id == anything_id + || vi->id == integer_id) + has_anything_id = true; + } + + /* Only artificial heap-vars are further interesting. */ + if (vi->is_artificial_var && !vi->is_heap_var) + continue; + + if ((TREE_CODE (vi->decl) == VAR_DECL + || TREE_CODE (vi->decl) == PARM_DECL + || TREE_CODE (vi->decl) == RESULT_DECL) + && !unmodifiable_var_p (vi->decl)) + bitmap_set_bit (gimple_call_used_vars (cfun), DECL_UID (vi->decl)); + } + + /* If anything is call-used, add all addressable locals to the set. */ + if (has_anything_id) + bitmap_ior_into (gimple_call_used_vars (cfun), + gimple_addressable_vars (cfun)); +} + /* Dump points-to information to OUTFILE. */ @@ -5193,6 +5320,27 @@ init_base_vars (void) rhs.offset = 0; process_constraint (new_constraint (lhs, rhs)); + /* Create the CALLUSED variable, used to represent the set of call-used + memory. */ + callused_tree = create_tmp_var_raw (void_type_node, "CALLUSED"); + var_callused = new_var_info (callused_tree, callused_id, "CALLUSED"); + insert_vi_for_tree (callused_tree, var_callused); + var_callused->is_artificial_var = 1; + var_callused->offset = 0; + var_callused->size = ~0; + var_callused->fullsize = ~0; + var_callused->is_special_var = 0; + VEC_safe_push (varinfo_t, heap, varmap, var_callused); + + /* CALLUSED = *CALLUSED, because call-used is may-deref'd at calls, etc. */ + lhs.type = SCALAR; + lhs.var = callused_id; + lhs.offset = 0; + rhs.type = DEREF; + rhs.var = callused_id; + rhs.offset = 0; + process_constraint_1 (new_constraint (lhs, rhs), true); + /* Create the INTEGER variable, used to represent that a variable points to an INTEGER. */ integer_tree = create_tmp_var_raw (void_type_node, "INTEGER"); diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 5a744648271..7f567b57a2e 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -937,6 +937,7 @@ init_tree_ssa (struct function *fn) fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash, uid_ssaname_map_eq, NULL); fn->gimple_df->call_clobbered_vars = BITMAP_GGC_ALLOC (); + fn->gimple_df->call_used_vars = BITMAP_GGC_ALLOC (); fn->gimple_df->addressable_vars = BITMAP_GGC_ALLOC (); init_ssanames (fn, 0); init_phinodes (); @@ -1009,6 +1010,7 @@ delete_tree_ssa (void) htab_delete (cfun->gimple_df->default_defs); cfun->gimple_df->default_defs = NULL; cfun->gimple_df->call_clobbered_vars = NULL; + cfun->gimple_df->call_used_vars = NULL; cfun->gimple_df->addressable_vars = NULL; cfun->gimple_df->modified_noreturn_calls = NULL; if (gimple_aliases_computed_p (cfun))