diff options
| author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-07-01 05:50:51 +0000 |
|---|---|---|
| committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-07-01 05:50:51 +0000 |
| commit | e49e8bd540832217538f9720f502da8c20f1f9b0 (patch) | |
| tree | 8f6bc6f898cfafd809ea3bf6f2a7660a896f9a40 /gcc/tree-ssa-alias.c | |
| parent | b528597c9f3f2e3a64a664c7be6c82a7c2688287 (diff) | |
| download | gcc-e49e8bd540832217538f9720f502da8c20f1f9b0.tar.gz | |
2008-07-01 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk r137307
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@137309 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-alias.c')
| -rw-r--r-- | gcc/tree-ssa-alias.c | 337 |
1 files changed, 323 insertions, 14 deletions
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 748ff31684e..ee0f4a7316a 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -166,6 +166,40 @@ along with GCC; see the file COPYING3. If not see Lastly, we delete partitions with no symbols, and clean up after ourselves. */ + +/* Alias information used by compute_may_aliases and its helpers. */ +struct alias_info +{ + /* SSA names visited while collecting points-to information. If bit I + is set, it means that SSA variable with version I has already been + visited. */ + sbitmap ssa_names_visited; + + /* Array of SSA_NAME pointers processed by the points-to collector. */ + VEC(tree,heap) *processed_ptrs; + + /* ADDRESSABLE_VARS contains all the global variables and locals that + have had their address taken. */ + struct alias_map_d **addressable_vars; + size_t num_addressable_vars; + + /* POINTERS contains all the _DECL pointers with unique memory tags + that have been referenced in the program. */ + struct alias_map_d **pointers; + size_t num_pointers; + + /* Variables that have been written to directly (i.e., not through a + pointer dereference). */ + struct pointer_set_t *written_vars; + + /* Pointers that have been used in an indirect store operation. */ + struct pointer_set_t *dereferenced_ptrs_store; + + /* Pointers that have been used in an indirect load operation. */ + struct pointer_set_t *dereferenced_ptrs_load; +}; + + /* Structure to map a variable to its alias set. */ struct alias_map_d { @@ -205,6 +239,7 @@ static struct alias_info *init_alias_info (void); static void delete_alias_info (struct alias_info *); static void compute_flow_sensitive_aliasing (struct alias_info *); static void setup_pointers_and_addressables (struct alias_info *); +static void update_alias_info (struct alias_info *); static void create_global_var (void); static void maybe_create_global_var (void); static void set_pt_anything (tree); @@ -505,7 +540,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. */ @@ -537,6 +572,14 @@ set_initial_properties (struct alias_info *ai) } } + if (!clobber_what_escaped ()) + { + any_pt_anything = true; + 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); @@ -557,18 +600,6 @@ set_initial_properties (struct alias_info *ai) if (tag) mark_call_clobbered (tag, pi->escape_mask); - - /* Defer to points-to analysis if possible, otherwise - clobber all addressable variables. Parameters cannot - point to local memory though. - ??? Properly tracking which pointers point to non-local - memory only would make a big difference here. */ - if (!clobber_what_p_points_to (ptr) - && !(pi->escape_mask & ESCAPE_IS_PARM)) - { - any_pt_anything = true; - pt_anything_mask |= pi->escape_mask; - } } /* If the name tag is call clobbered, so is the symbol tag @@ -1726,7 +1757,12 @@ compute_may_aliases (void) address of V escapes the current function, making V call-clobbered (i.e., whether &V is stored in a global variable or if its passed as a function call argument). */ - compute_points_to_sets (ai); + compute_points_to_sets (); + + /* Update various related attributes like escaped addresses, + pointer dereferences for loads and stores. This is used + when creating name tags and alias sets. */ + update_alias_info (ai); /* Collect all pointers and addressable variables, compute alias sets, create memory tags for pointers and promote variables whose address is @@ -2006,6 +2042,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++) { @@ -2439,6 +2478,270 @@ create_alias_map_for (tree var, struct alias_info *ai) } +/* Update related alias information kept in AI. This is used when + building name tags, alias sets and deciding grouping heuristics. + STMT is the statement to process. This function also updates + ADDRESSABLE_VARS. */ + +static void +update_alias_info_1 (tree stmt, struct alias_info *ai) +{ + bitmap addr_taken; + use_operand_p use_p; + ssa_op_iter iter; + bool stmt_dereferences_ptr_p; + enum escape_type stmt_escape_type = is_escape_site (stmt); + struct mem_ref_stats_d *mem_ref_stats = gimple_mem_ref_stats (cfun); + + stmt_dereferences_ptr_p = false; + + if (stmt_escape_type == ESCAPE_TO_CALL + || stmt_escape_type == ESCAPE_TO_PURE_CONST) + { + mem_ref_stats->num_call_sites++; + if (stmt_escape_type == ESCAPE_TO_PURE_CONST) + mem_ref_stats->num_pure_const_call_sites++; + } + else if (stmt_escape_type == ESCAPE_TO_ASM) + mem_ref_stats->num_asm_sites++; + + /* Mark all the variables whose address are taken by the statement. */ + addr_taken = addresses_taken (stmt); + if (addr_taken) + bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken); + + /* Process each operand use. For pointers, determine whether they + are dereferenced by the statement, or whether their value + escapes, etc. */ + FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE) + { + tree op, var; + var_ann_t v_ann; + struct ptr_info_def *pi; + unsigned num_uses, num_loads, num_stores; + + op = USE_FROM_PTR (use_p); + + /* If STMT is a PHI node, OP may be an ADDR_EXPR. If so, add it + to the set of addressable variables. */ + if (TREE_CODE (op) == ADDR_EXPR) + { + bitmap addressable_vars = gimple_addressable_vars (cfun); + + gcc_assert (TREE_CODE (stmt) == PHI_NODE); + gcc_assert (addressable_vars); + + /* PHI nodes don't have annotations for pinning the set + of addresses taken, so we collect them here. + + FIXME, should we allow PHI nodes to have annotations + so that they can be treated like regular statements? + Currently, they are treated as second-class + statements. */ + add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars); + continue; + } + + /* Ignore constants (they may occur in PHI node arguments). */ + if (TREE_CODE (op) != SSA_NAME) + continue; + + var = SSA_NAME_VAR (op); + v_ann = var_ann (var); + + /* The base variable of an SSA name must be a GIMPLE register, and thus + it cannot be aliased. */ + gcc_assert (!may_be_aliased (var)); + + /* We are only interested in pointers. */ + if (!POINTER_TYPE_P (TREE_TYPE (op))) + continue; + + pi = get_ptr_info (op); + + /* Add OP to AI->PROCESSED_PTRS, if it's not there already. */ + if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op))) + { + SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)); + VEC_safe_push (tree, heap, ai->processed_ptrs, op); + } + + /* If STMT is a PHI node, then it will not have pointer + dereferences and it will not be an escape point. */ + if (TREE_CODE (stmt) == PHI_NODE) + continue; + + /* Determine whether OP is a dereferenced pointer, and if STMT + is an escape point, whether OP escapes. */ + count_uses_and_derefs (op, stmt, &num_uses, &num_loads, &num_stores); + + /* For directly dereferenced pointers we can apply + TBAA-pruning to their points-to set. We may not count the + implicit dereferences &PTR->FLD here. */ + if (num_loads + num_stores > 0) + pi->is_dereferenced = 1; + + /* Handle a corner case involving address expressions of the + form '&PTR->FLD'. The problem with these expressions is that + they do not represent a dereference of PTR. However, if some + other transformation propagates them into an INDIRECT_REF + expression, we end up with '*(&PTR->FLD)' which is folded + into 'PTR->FLD'. + + So, if the original code had no other dereferences of PTR, + the aliaser will not create memory tags for it, and when + &PTR->FLD gets propagated to INDIRECT_REF expressions, the + memory operations will receive no VDEF/VUSE operands. + + One solution would be to have count_uses_and_derefs consider + &PTR->FLD a dereference of PTR. But that is wrong, since it + is not really a dereference but an offset calculation. + + What we do here is to recognize these special ADDR_EXPR + nodes. Since these expressions are never GIMPLE values (they + are not GIMPLE invariants), they can only appear on the RHS + of an assignment and their base address is always an + INDIRECT_REF expression. */ + if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT + && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == ADDR_EXPR + && !is_gimple_val (GIMPLE_STMT_OPERAND (stmt, 1))) + { + /* If the RHS if of the form &PTR->FLD and PTR == OP, then + this represents a potential dereference of PTR. */ + tree rhs = GIMPLE_STMT_OPERAND (stmt, 1); + tree base = get_base_address (TREE_OPERAND (rhs, 0)); + if (TREE_CODE (base) == INDIRECT_REF + && TREE_OPERAND (base, 0) == op) + num_loads++; + } + + if (num_loads + num_stores > 0) + { + /* Mark OP as dereferenced. In a subsequent pass, + dereferenced pointers that point to a set of + variables will be assigned a name tag to alias + all the variables OP points to. */ + pi->memory_tag_needed = 1; + + /* ??? For always executed direct dereferences we can + apply TBAA-pruning to their escape set. */ + + /* If this is a store operation, mark OP as being + dereferenced to store, otherwise mark it as being + dereferenced to load. */ + if (num_stores > 0) + pointer_set_insert (ai->dereferenced_ptrs_store, var); + else + pointer_set_insert (ai->dereferenced_ptrs_load, var); + + /* Update the frequency estimate for all the dereferences of + pointer OP. */ + update_mem_sym_stats_from_stmt (op, stmt, num_loads, num_stores); + + /* Indicate that STMT contains pointer dereferences. */ + stmt_dereferences_ptr_p = true; + } + + if (stmt_escape_type != NO_ESCAPE && num_loads + num_stores < num_uses) + { + /* If STMT is an escape point and STMT contains at + least one direct use of OP, then the value of OP + escapes and so the pointed-to variables need to + be marked call-clobbered. */ + pi->value_escapes_p = 1; + pi->escape_mask |= stmt_escape_type; + + /* If the statement makes a function call, assume + that pointer OP will be dereferenced in a store + operation inside the called function. */ + if (get_call_expr_in (stmt) + || stmt_escape_type == ESCAPE_STORED_IN_GLOBAL) + { + pointer_set_insert (ai->dereferenced_ptrs_store, var); + pi->memory_tag_needed = 1; + } + } + } + + if (TREE_CODE (stmt) == PHI_NODE) + return; + + /* Mark stored variables in STMT as being written to and update the + memory reference stats for all memory symbols referenced by STMT. */ + if (stmt_references_memory_p (stmt)) + { + unsigned i; + bitmap_iterator bi; + + mem_ref_stats->num_mem_stmts++; + + /* Notice that we only update memory reference stats for symbols + loaded and stored by the statement if the statement does not + contain pointer dereferences and it is not a call/asm site. + This is to avoid double accounting problems when creating + memory partitions. After computing points-to information, + pointer dereference statistics are used to update the + reference stats of the pointed-to variables, so here we + should only update direct references to symbols. + + Indirect references are not updated here for two reasons: (1) + The first time we compute alias information, the sets + LOADED/STORED are empty for pointer dereferences, (2) After + partitioning, LOADED/STORED may have references to + partitions, not the original pointed-to variables. So, if we + always counted LOADED/STORED here and during partitioning, we + would count many symbols more than once. + + This does cause some imprecision when a statement has a + combination of direct symbol references and pointer + dereferences (e.g., MEMORY_VAR = *PTR) or if a call site has + memory symbols in its argument list, but these cases do not + occur so frequently as to constitute a serious problem. */ + if (STORED_SYMS (stmt)) + EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi) + { + tree sym = referenced_var (i); + pointer_set_insert (ai->written_vars, sym); + if (!stmt_dereferences_ptr_p + && stmt_escape_type != ESCAPE_TO_CALL + && stmt_escape_type != ESCAPE_TO_PURE_CONST + && stmt_escape_type != ESCAPE_TO_ASM) + update_mem_sym_stats_from_stmt (sym, stmt, 0, 1); + } + + if (!stmt_dereferences_ptr_p + && LOADED_SYMS (stmt) + && stmt_escape_type != ESCAPE_TO_CALL + && stmt_escape_type != ESCAPE_TO_PURE_CONST + && stmt_escape_type != ESCAPE_TO_ASM) + EXECUTE_IF_SET_IN_BITMAP (LOADED_SYMS (stmt), 0, i, bi) + update_mem_sym_stats_from_stmt (referenced_var (i), stmt, 1, 0); + } +} + +/* Update various related attributes like escaped addresses, + pointer dereferences for loads and stores. This is used + when creating name tags and alias sets. */ + +static void +update_alias_info (struct alias_info *ai) +{ + basic_block bb; + + FOR_EACH_BB (bb) + { + block_stmt_iterator bsi; + tree phi; + + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + if (is_gimple_reg (PHI_RESULT (phi))) + update_alias_info_1 (phi, ai); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + update_alias_info_1 (bsi_stmt (bsi), ai); + } +} + /* Create memory tags for all the dereferenced pointers and build the ADDRESSABLE_VARS and POINTERS arrays used for building the may-alias sets. Based on the address escape and points-to information collected @@ -2906,6 +3209,12 @@ is_escape_site (tree stmt) if (TREE_CODE (lhs) == SSA_NAME) return NO_ESCAPE; + /* If the LHS is a non-global decl, it isn't a non-local memory store. + If the LHS escapes, the RHS escape is dealt with in the PTA solver. */ + if (DECL_P (lhs) + && !is_global_var (lhs)) + return NO_ESCAPE; + /* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a local variables we cannot be sure if it will escape, because we don't have information about objects not in SSA form. Need to |
