From faf2ecc57e3ef478efebee6f83c440df073152c2 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Sun, 29 Jun 2008 15:44:00 +0000 Subject: [PATCH] tree-ssa-structalias.h (compute_points_to_sets): Adjust prototype. 2008-06-29 Richard Guenther * tree-ssa-structalias.h (compute_points_to_sets): Adjust prototype. (struct alias_info): Move ... * tree-ssa-alias.c: ... here. (update_alias_info): Declare. (compute_may_aliases): Call it. (update_alias_info): New function. * tree-ssa-structalias.c (update_alias_info): Move ... * tree-ssa-alias.c (update_alias_info_1): ... here. * tree-ssa-structalias.c (process_constraint_1): Remove unused from_call argument. Rename to ... (process_constraint): ... this. Delete old wrapper. (make_constraint_to): Adjust callers. (handle_const_call): Likewise. (handle_pure_call): Likewise. (init_base_vars): Likewise. (handle_lhs_call): Likewise. Remove unnecessary constraint. (find_func_aliases): We don't need structure copies for complex types. (make_constraint_from_anything): Remove. (create_variable_info_for): For globals make constraints from escaped, not from anything. (compute_points_to_sets): Do not call update_alias_info. (ipa_pta_execute): Use make_constraint_from. From-SVN: r137252 --- gcc/ChangeLog | 27 +++ gcc/tree-ssa-alias.c | 306 ++++++++++++++++++++++++++++++++- gcc/tree-ssa-structalias.c | 344 ++++--------------------------------- gcc/tree-ssa-structalias.h | 34 +--- 4 files changed, 364 insertions(+), 347 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 26a22dbf4da..99e5011cdbd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2008-06-29 Richard Guenther + + * tree-ssa-structalias.h (compute_points_to_sets): Adjust + prototype. + (struct alias_info): Move ... + * tree-ssa-alias.c: ... here. + (update_alias_info): Declare. + (compute_may_aliases): Call it. + (update_alias_info): New function. + * tree-ssa-structalias.c (update_alias_info): Move ... + * tree-ssa-alias.c (update_alias_info_1): ... here. + * tree-ssa-structalias.c (process_constraint_1): Remove + unused from_call argument. Rename to ... + (process_constraint): ... this. Delete old wrapper. + (make_constraint_to): Adjust callers. + (handle_const_call): Likewise. + (handle_pure_call): Likewise. + (init_base_vars): Likewise. + (handle_lhs_call): Likewise. Remove unnecessary constraint. + (find_func_aliases): We don't need structure copies for + complex types. + (make_constraint_from_anything): Remove. + (create_variable_info_for): For globals make constraints + from escaped, not from anything. + (compute_points_to_sets): Do not call update_alias_info. + (ipa_pta_execute): Use make_constraint_from. + 2008-06-29 Kaveh R. Ghazi * Makefile.in (CXX_COMPAT_WARN, cxx_compat_warn): Delete. diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 9a6552bb9d5..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); @@ -1722,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 @@ -2438,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 diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index 4a3896bc440..b2ba20423b4 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -2526,13 +2526,11 @@ get_constraint_exp_from_ssa_var (tree t) return cexpr; } -/* Process a completed constraint T, and add it to the constraint - list. FROM_CALL is true if this is a constraint coming from a - call, which means any DEREFs we see are "may-deref's", not - "must-deref"'s. */ +/* Process constraint T, performing various simplifications and then + adding it to our list of overall constraints. */ static void -process_constraint_1 (constraint_t t, bool from_call) +process_constraint (constraint_t t) { struct constraint_expr rhs = t->rhs; struct constraint_expr lhs = t->lhs; @@ -2556,7 +2554,7 @@ process_constraint_1 (constraint_t t, bool from_call) rhs = t->lhs; t->lhs = t->rhs; t->rhs = rhs; - process_constraint_1 (t, from_call); + process_constraint (t); } /* This can happen in our IR with things like n->a = *p */ else if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id) @@ -2574,8 +2572,8 @@ process_constraint_1 (constraint_t t, bool from_call) gcc_assert (!AGGREGATE_TYPE_P (pointedtotype) || get_varinfo (rhs.var)->is_unknown_size_var); - process_constraint_1 (new_constraint (tmplhs, rhs), from_call); - process_constraint_1 (new_constraint (lhs, tmplhs), from_call); + process_constraint (new_constraint (tmplhs, rhs)); + process_constraint (new_constraint (lhs, tmplhs)); } else if (rhs.type == ADDRESSOF && lhs.type == DEREF) { @@ -2585,8 +2583,8 @@ process_constraint_1 (constraint_t t, bool from_call) tree tmpvar = create_tmp_var_raw (pointertype, "derefaddrtmp"); struct constraint_expr tmplhs = get_constraint_exp_from_ssa_var (tmpvar); - process_constraint_1 (new_constraint (tmplhs, rhs), from_call); - process_constraint_1 (new_constraint (lhs, tmplhs), from_call); + process_constraint (new_constraint (tmplhs, rhs)); + process_constraint (new_constraint (lhs, tmplhs)); } else { @@ -2595,16 +2593,6 @@ process_constraint_1 (constraint_t t, bool from_call) } } - -/* Process constraint T, performing various simplifications and then - adding it to our list of overall constraints. */ - -static void -process_constraint (constraint_t t) -{ - process_constraint_1 (t, false); -} - /* Return true if T is a variable of a type that could contain pointers. */ @@ -3267,248 +3255,6 @@ do_structure_copy (tree lhsop, tree rhsop) } -/* 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 (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); - } -} - - /* Handle pointer arithmetic EXPR when creating aliasing constraints. Expressions of the type PTR + CST can be handled in two ways: @@ -3598,7 +3344,7 @@ make_constraint_to (unsigned id, tree op) get_constraint_for (op, &rhsc); for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++) - process_constraint_1 (new_constraint (includes, *c), true); + process_constraint (new_constraint (includes, *c)); VEC_free (ce_s, heap, rhsc); } @@ -3643,16 +3389,11 @@ handle_lhs_call (tree lhs) struct constraint_expr *lhsp; get_constraint_for (lhs, &lhsc); - rhsc.var = nonlocal_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); rhsc.var = escaped_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); + process_constraint (new_constraint (*lhsp, rhsc)); VEC_free (ce_s, heap, lhsc); } @@ -3680,7 +3421,7 @@ handle_const_call (tree stmt) 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); + process_constraint (new_constraint (*lhsp, rhsc)); VEC_free (ce_s, heap, lhsc); return; } @@ -3690,7 +3431,7 @@ handle_const_call (tree stmt) 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); + process_constraint (new_constraint (*lhsp, rhsc)); /* May return arguments. */ FOR_EACH_CALL_EXPR_ARG (arg, iter, call) @@ -3702,7 +3443,7 @@ handle_const_call (tree stmt) get_constraint_for (arg, &argc); for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++) for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++) - process_constraint_1 (new_constraint (*lhsp, *argp), true); + process_constraint (new_constraint (*lhsp, *argp)); VEC_free (ce_s, heap, argc); } @@ -3748,7 +3489,7 @@ handle_pure_call (tree stmt) 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); + process_constraint (new_constraint (*lhsp, rhsc)); VEC_free (ce_s, heap, lhsc); return; } @@ -3759,7 +3500,7 @@ handle_pure_call (tree stmt) 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); + process_constraint (new_constraint (*lhsp, rhsc)); VEC_free (ce_s, heap, lhsc); } } @@ -3957,10 +3698,8 @@ find_func_aliases (tree origt) tree rhsop = GIMPLE_STMT_OPERAND (t, 1); int i; - if ((AGGREGATE_TYPE_P (TREE_TYPE (lhsop)) - || TREE_CODE (TREE_TYPE (lhsop)) == COMPLEX_TYPE) - && (AGGREGATE_TYPE_P (TREE_TYPE (rhsop)) - || TREE_CODE (TREE_TYPE (lhsop)) == COMPLEX_TYPE)) + if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)) + && AGGREGATE_TYPE_P (TREE_TYPE (rhsop))) { do_structure_copy (lhsop, rhsop); } @@ -4340,13 +4079,6 @@ make_constraint_from (varinfo_t vi, int from) process_constraint (new_constraint (lhs, rhs)); } -/* Create a constraint from ANYTHING variable to VI. */ -static void -make_constraint_from_anything (varinfo_t vi) -{ - make_constraint_from (vi, anything_id); -} - /* Count the number of arguments DECL has, and set IS_VARARGS to true if it is a varargs function. */ @@ -4552,8 +4284,9 @@ create_variable_info_for (tree decl, const char *name) insert_vi_for_tree (vi->decl, vi); VEC_safe_push (varinfo_t, heap, varmap, vi); - if (is_global && (!flag_whole_program || !in_ipa_mode)) - make_constraint_from_anything (vi); + if (is_global && (!flag_whole_program || !in_ipa_mode) + && could_have_pointers (decl)) + make_constraint_from (vi, escaped_id); stats.total_vars++; if (use_field_sensitive @@ -4633,8 +4366,9 @@ create_variable_info_for (tree decl, const char *name) newvi->fullsize = vi->fullsize; insert_into_field_list (vi, newvi); VEC_safe_push (varinfo_t, heap, varmap, newvi); - if (is_global && (!flag_whole_program || !in_ipa_mode)) - make_constraint_from_anything (newvi); + if (is_global && (!flag_whole_program || !in_ipa_mode) + && (!fo->decl || could_have_pointers (fo->decl))) + make_constraint_from (newvi, escaped_id); stats.total_vars++; } @@ -5296,7 +5030,7 @@ init_base_vars (void) rhs.type = DEREF; rhs.var = escaped_id; rhs.offset = 0; - process_constraint_1 (new_constraint (lhs, rhs), true); + process_constraint (new_constraint (lhs, rhs)); /* Create the NONLOCAL variable, used to represent the set of nonlocal memory. */ @@ -5339,7 +5073,7 @@ init_base_vars (void) rhs.type = DEREF; rhs.var = callused_id; rhs.offset = 0; - process_constraint_1 (new_constraint (lhs, rhs), true); + process_constraint (new_constraint (lhs, rhs)); /* Create the INTEGER variable, used to represent that a variable points to an INTEGER. */ @@ -5372,7 +5106,7 @@ init_base_vars (void) rhs.type = ADDRESSOF; rhs.var = escaped_id; rhs.offset = 0; - process_constraint_1 (new_constraint (lhs, rhs), true); + process_constraint (new_constraint (lhs, rhs)); /* *ESCAPED = &NONLOCAL. This is true because we have to assume everything pointed to by escaped can also point to nonlocal. */ @@ -5382,7 +5116,7 @@ init_base_vars (void) rhs.type = ADDRESSOF; rhs.var = nonlocal_id; rhs.offset = 0; - process_constraint_1 (new_constraint (lhs, rhs), true); + process_constraint (new_constraint (lhs, rhs)); } /* Initialize things necessary to perform PTA */ @@ -5581,7 +5315,7 @@ compute_tbaa_pruning (void) at the start of the file for an algorithmic overview. */ void -compute_points_to_sets (struct alias_info *ai) +compute_points_to_sets (void) { struct scc_info *si; basic_block bb; @@ -5600,18 +5334,8 @@ compute_points_to_sets (struct alias_info *ai) tree phi; for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) - { - if (is_gimple_reg (PHI_RESULT (phi))) - { - find_func_aliases (phi); - - /* 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 (phi, ai); - } - } + if (is_gimple_reg (PHI_RESULT (phi))) + find_func_aliases (phi); for (bsi = bsi_start (bb); !bsi_end_p (bsi); ) { @@ -5619,12 +5343,6 @@ compute_points_to_sets (struct alias_info *ai) find_func_aliases (stmt); - /* 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 (stmt, ai); - /* The information in CHANGE_DYNAMIC_TYPE_EXPR nodes has now been captured, and we can remove them. */ if (TREE_CODE (stmt) == CHANGE_DYNAMIC_TYPE_EXPR) @@ -5761,7 +5479,7 @@ ipa_pta_execute (void) { varinfo_t fi = get_varinfo (varid); for (; fi; fi = fi->next) - make_constraint_from_anything (fi); + make_constraint_from (fi, anything_id); } } } diff --git a/gcc/tree-ssa-structalias.h b/gcc/tree-ssa-structalias.h index 737135bdc87..7d468b42f91 100644 --- a/gcc/tree-ssa-structalias.h +++ b/gcc/tree-ssa-structalias.h @@ -24,44 +24,12 @@ struct constraint; typedef struct constraint *constraint_t; -/* 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; -}; - /* In tree-ssa-alias.c. */ enum escape_type is_escape_site (tree); void update_mem_sym_stats_from_stmt (tree, tree, long, long); /* In tree-ssa-structalias.c. */ -extern void compute_points_to_sets (struct alias_info *); +extern void compute_points_to_sets (void); extern void delete_points_to_sets (void); extern void dump_constraint (FILE *, constraint_t); extern void dump_constraints (FILE *);