diff options
author | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-04-13 09:53:19 +0000 |
---|---|---|
committer | rguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-04-13 09:53:19 +0000 |
commit | c4ec6acaf5d36a3c86963c4fab281f04062d1eed (patch) | |
tree | 9973b986af305de702b32cdd7c195a7acf7ab078 /gcc/tree-ssa-structalias.c | |
parent | 91a74fc6ef3473f7087e00a5861d01550afd166f (diff) | |
download | gcc-c4ec6acaf5d36a3c86963c4fab281f04062d1eed.tar.gz |
2010-04-13 Richard Guenther <rguenther@suse.de>
* tree-ssa-structalias.c (callused_id): Remove.
(call_stmt_vars): New.
(get_call_vi): Likewise.
(lookup_call_use_vi): Likewise.
(lookup_call_clobber_vi): Likewise.
(get_call_use_vi): Likewise.
(get_call_clobber_vi): Likewise.
(make_transitive_closure_constraints): Likewise.
(handle_const_call): Adjust to do per-call call-used handling.
(handle_pure_call): Likewise.
(find_what_var_points_to): Remove general callused handling.
(init_base_vars): Likewise.
(init_alias_vars): Initialize call_stmt_vars.
(compute_points_to_sets): Process call-used and call-clobbered
vars for call statements.
(delete_points_to_sets): Free call_stmt_vars.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158260 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-structalias.c')
-rw-r--r-- | gcc/tree-ssa-structalias.c | 205 |
1 files changed, 151 insertions, 54 deletions
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index e14b97a97f5..85493a2dd50 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -288,8 +288,8 @@ get_varinfo (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, callused_id = 5, - storedanything_id = 6, integer_id = 7 }; + escaped_id = 3, nonlocal_id = 4, + storedanything_id = 5, integer_id = 6 }; struct GTY(()) heapvar_map { struct tree_map map; @@ -379,6 +379,86 @@ new_var_info (tree t, const char *name) return ret; } + +/* A map mapping call statements to per-stmt variables for uses + and clobbers specific to the call. */ +struct pointer_map_t *call_stmt_vars; + +/* Lookup or create the variable for the call statement CALL. */ + +static varinfo_t +get_call_vi (gimple call) +{ + void **slot_p; + varinfo_t vi, vi2; + + slot_p = pointer_map_insert (call_stmt_vars, call); + if (*slot_p) + return (varinfo_t) *slot_p; + + vi = new_var_info (NULL_TREE, "CALLUSED"); + vi->offset = 0; + vi->size = 1; + vi->fullsize = 2; + vi->is_full_var = true; + + vi->next = vi2 = new_var_info (NULL_TREE, "CALLCLOBBERED"); + vi2->offset = 1; + vi2->size = 1; + vi2->fullsize = 2; + vi2->is_full_var = true; + + *slot_p = (void *) vi; + return vi; +} + +/* Lookup the variable for the call statement CALL representing + the uses. Returns NULL if there is nothing special about this call. */ + +static varinfo_t +lookup_call_use_vi (gimple call) +{ + void **slot_p; + + slot_p = pointer_map_contains (call_stmt_vars, call); + if (slot_p) + return (varinfo_t) *slot_p; + + return NULL; +} + +/* Lookup the variable for the call statement CALL representing + the clobbers. Returns NULL if there is nothing special about this call. */ + +static varinfo_t +lookup_call_clobber_vi (gimple call) +{ + varinfo_t uses = lookup_call_use_vi (call); + if (!uses) + return NULL; + + return uses->next; +} + +/* Lookup or create the variable for the call statement CALL representing + the uses. */ + +static varinfo_t +get_call_use_vi (gimple call) +{ + return get_call_vi (call); +} + +/* Lookup or create the variable for the call statement CALL representing + the clobbers. */ + +static varinfo_t ATTRIBUTE_UNUSED +get_call_clobber_vi (gimple call) +{ + return get_call_vi (call)->next; +} + + typedef enum {SCALAR, DEREF, ADDRESSOF} constraint_expr_type; /* An expression that appears in a constraint. */ @@ -3377,6 +3457,32 @@ make_escape_constraint (tree op) make_constraint_to (escaped_id, op); } +/* Add constraints to that the solution of VI is transitively closed. */ + +static void +make_transitive_closure_constraints (varinfo_t vi) +{ + struct constraint_expr lhs, rhs; + + /* VAR = *VAR; */ + lhs.type = SCALAR; + lhs.var = vi->id; + lhs.offset = 0; + rhs.type = DEREF; + rhs.var = vi->id; + rhs.offset = 0; + process_constraint (new_constraint (lhs, rhs)); + + /* VAR = VAR + UNKNOWN; */ + lhs.type = SCALAR; + lhs.var = vi->id; + lhs.offset = 0; + rhs.type = SCALAR; + rhs.var = vi->id; + rhs.offset = UNKNOWN_OFFSET; + process_constraint (new_constraint (lhs, rhs)); +} + /* Create a new artificial heap variable with NAME and make a constraint from it to LHS. Return the created variable. */ @@ -3538,8 +3644,10 @@ handle_const_call (gimple stmt, VEC(ce_s, heap) **results) as the static chain is concerned. */ if (gimple_call_chain (stmt)) { - make_constraint_to (callused_id, gimple_call_chain (stmt)); - rhsc.var = callused_id; + varinfo_t uses = get_call_use_vi (stmt); + make_transitive_closure_constraints (uses); + make_constraint_to (uses->id, gimple_call_chain (stmt)); + rhsc.var = uses->id; rhsc.offset = 0; rhsc.type = SCALAR; VEC_safe_push (ce_s, heap, *results, &rhsc); @@ -3577,7 +3685,7 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results) { struct constraint_expr rhsc; unsigned i; - bool need_callused = false; + varinfo_t uses = NULL; /* Memory reached from pointer arguments is call-used. */ for (i = 0; i < gimple_call_num_args (stmt); ++i) @@ -3586,22 +3694,30 @@ handle_pure_call (gimple stmt, VEC(ce_s, heap) **results) if (could_have_pointers (arg)) { - make_constraint_to (callused_id, arg); - need_callused = true; + if (!uses) + { + uses = get_call_use_vi (stmt); + make_transitive_closure_constraints (uses); + } + make_constraint_to (uses->id, arg); } } /* The static chain is used as well. */ if (gimple_call_chain (stmt)) { - make_constraint_to (callused_id, gimple_call_chain (stmt)); - need_callused = true; + if (!uses) + { + uses = get_call_use_vi (stmt); + make_transitive_closure_constraints (uses); + } + make_constraint_to (uses->id, gimple_call_chain (stmt)); } - /* Pure functions may return callused and nonlocal memory. */ - if (need_callused) + /* Pure functions may return call-used and nonlocal memory. */ + if (uses) { - rhsc.var = callused_id; + rhsc.var = uses->id; rhsc.offset = 0; rhsc.type = SCALAR; VEC_safe_push (ce_s, heap, *results, &rhsc); @@ -4004,8 +4120,8 @@ find_func_aliases (gimple origt) if (!allows_reg && allows_mem) make_escape_constraint (build_fold_addr_expr (op)); /* Strictly we'd only need the constraint to ESCAPED if - the asm clobbers memory, otherwise using CALLUSED - would be enough. */ + the asm clobbers memory, otherwise using something + along the lines of per-call clobbers/uses would be enough. */ else if (op && could_have_pointers (op)) make_escape_constraint (op); } @@ -4811,8 +4927,6 @@ find_what_var_points_to (varinfo_t orig_vi, struct pt_solution *pt) pt->null = 1; else if (vi->id == escaped_id) pt->escaped = 1; - else if (vi->id == callused_id) - gcc_unreachable (); else if (vi->id == nonlocal_id) pt->nonlocal = 1; else if (vi->is_heap_var) @@ -5138,7 +5252,6 @@ init_base_vars (void) varinfo_t var_readonly; varinfo_t var_escaped; varinfo_t var_nonlocal; - varinfo_t var_callused; varinfo_t var_storedanything; varinfo_t var_integer; @@ -5265,35 +5378,6 @@ 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. */ - var_callused = new_var_info (NULL_TREE, "CALLUSED"); - gcc_assert (var_callused->id == callused_id); - var_callused->is_artificial_var = 1; - var_callused->offset = 0; - var_callused->size = ~0; - var_callused->fullsize = ~0; - var_callused->is_special_var = 0; - - /* 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 (new_constraint (lhs, rhs)); - - /* CALLUSED = CALLUSED + UNKNOWN, because if a sub-field is call-used the - whole variable is call-used. */ - lhs.type = SCALAR; - lhs.var = callused_id; - lhs.offset = 0; - rhs.type = SCALAR; - rhs.var = callused_id; - rhs.offset = UNKNOWN_OFFSET; - process_constraint (new_constraint (lhs, rhs)); - /* Create the STOREDANYTHING variable, used to represent the set of variables stored to *ANYTHING. */ var_storedanything = new_var_info (NULL_TREE, "STOREDANYTHING"); @@ -5344,6 +5428,7 @@ init_alias_vars (void) constraints = VEC_alloc (constraint_t, heap, 8); varmap = VEC_alloc (varinfo_t, heap, 8); vi_for_tree = pointer_map_create (); + call_stmt_vars = pointer_map_create (); memset (&stats, 0, sizeof (stats)); shared_bitmap_table = htab_create (511, shared_bitmap_hash, @@ -5480,7 +5565,6 @@ compute_points_to_sets (void) basic_block bb; unsigned i; varinfo_t vi; - struct pt_solution callused; timevar_push (TV_TREE_PTA); @@ -5513,11 +5597,9 @@ compute_points_to_sets (void) /* From the constraints compute the points-to sets. */ solve_constraints (); - /* Compute the points-to sets for ESCAPED and CALLUSED used for - call-clobber analysis. */ + /* Compute the points-to set for ESCAPED used for call-clobber analysis. */ find_what_var_points_to (get_varinfo (escaped_id), &cfun->gimple_df->escaped); - find_what_var_points_to (get_varinfo (callused_id), &callused); /* Make sure the ESCAPED solution (which is used as placeholder in other solutions) does not reference itself. This simplifies @@ -5556,11 +5638,11 @@ compute_points_to_sets (void) pt = gimple_call_use_set (stmt); if (gimple_call_flags (stmt) & ECF_CONST) memset (pt, 0, sizeof (struct pt_solution)); - else if (gimple_call_flags (stmt) & ECF_PURE) + else if ((vi = lookup_call_use_vi (stmt)) != NULL) { - /* For const calls we should now be able to compute the - call-used set per function. */ - *pt = callused; + find_what_var_points_to (vi, pt); + /* Escaped (and thus nonlocal) variables are always + implicitly used by calls. */ /* ??? ESCAPED can be empty even though NONLOCAL always escaped. */ pt->nonlocal = 1; @@ -5568,6 +5650,8 @@ compute_points_to_sets (void) } else { + /* If there is nothing special about this call then + we have made everything that is used also escape. */ *pt = cfun->gimple_df->escaped; pt->nonlocal = 1; } @@ -5575,8 +5659,20 @@ compute_points_to_sets (void) pt = gimple_call_clobber_set (stmt); if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS)) memset (pt, 0, sizeof (struct pt_solution)); + else if ((vi = lookup_call_clobber_vi (stmt)) != NULL) + { + find_what_var_points_to (vi, pt); + /* Escaped (and thus nonlocal) variables are always + implicitly clobbered by calls. */ + /* ??? ESCAPED can be empty even though NONLOCAL + always escaped. */ + pt->nonlocal = 1; + pt->escaped = 1; + } else { + /* If there is nothing special about this call then + we have made everything that is used also escape. */ *pt = cfun->gimple_df->escaped; pt->nonlocal = 1; } @@ -5600,6 +5696,7 @@ delete_points_to_sets (void) stats.points_to_sets_created); pointer_map_destroy (vi_for_tree); + pointer_map_destroy (call_stmt_vars); bitmap_obstack_release (&pta_obstack); VEC_free (constraint_t, heap, constraints); |