This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Some cleanups after the PTA patches
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 29 Jun 2008 17:34:04 +0200 (CEST)
- Subject: [PATCH] Some cleanups after the PTA patches
This is some pending source re-org I had laying around. The
from_call argument of process_constraint_1 is unused. We can
also separate tree-ssa-alias.c from tree-ssa-structalias.c some
more (the extra walk over the IL in tree-ssa-alias.c will be
used to implement the alias warnings of tree-ssa-aliaswarnings.c)
I also noticed that for globals we create still constraints from
anything where we only need from escaped. Fixed.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.
Richard.
2008-06-29 Richard Guenther <rguenther@suse.de>
* 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.
Index: tree-ssa-alias.c
===================================================================
*** tree-ssa-alias.c (revision 137251)
--- tree-ssa-alias.c (working copy)
*************** along with GCC; see the file COPYING3.
*** 166,171 ****
--- 166,205 ----
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
{
*************** static struct alias_info *init_alias_inf
*** 205,210 ****
--- 239,245 ----
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);
*************** compute_may_aliases (void)
*** 1722,1728 ****
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);
/* Collect all pointers and addressable variables, compute alias sets,
create memory tags for pointers and promote variables whose address is
--- 1757,1768 ----
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 ();
!
! /* 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
*************** create_alias_map_for (tree var, struct a
*** 2438,2443 ****
--- 2478,2747 ----
}
+ /* 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
Index: tree-ssa-structalias.c
===================================================================
*** tree-ssa-structalias.c (revision 137251)
--- tree-ssa-structalias.c (working copy)
*************** get_constraint_exp_from_ssa_var (tree t)
*** 2526,2538 ****
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. */
static void
! process_constraint_1 (constraint_t t, bool from_call)
{
struct constraint_expr rhs = t->rhs;
struct constraint_expr lhs = t->lhs;
--- 2526,2536 ----
return cexpr;
}
! /* Process constraint T, performing various simplifications and then
! adding it to our list of overall constraints. */
static void
! process_constraint (constraint_t t)
{
struct constraint_expr rhs = t->rhs;
struct constraint_expr lhs = t->lhs;
*************** process_constraint_1 (constraint_t t, bo
*** 2556,2562 ****
rhs = t->lhs;
t->lhs = t->rhs;
t->rhs = rhs;
! process_constraint_1 (t, from_call);
}
/* This can happen in our IR with things like n->a = *p */
else if (rhs.type == DEREF && lhs.type == DEREF && rhs.var != anything_id)
--- 2554,2560 ----
rhs = t->lhs;
t->lhs = t->rhs;
t->rhs = rhs;
! 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)
*************** process_constraint_1 (constraint_t t, bo
*** 2574,2581 ****
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);
}
else if (rhs.type == ADDRESSOF && lhs.type == DEREF)
{
--- 2572,2579 ----
gcc_assert (!AGGREGATE_TYPE_P (pointedtotype)
|| get_varinfo (rhs.var)->is_unknown_size_var);
! process_constraint (new_constraint (tmplhs, rhs));
! process_constraint (new_constraint (lhs, tmplhs));
}
else if (rhs.type == ADDRESSOF && lhs.type == DEREF)
{
*************** process_constraint_1 (constraint_t t, bo
*** 2585,2592 ****
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);
}
else
{
--- 2583,2590 ----
tree tmpvar = create_tmp_var_raw (pointertype, "derefaddrtmp");
struct constraint_expr tmplhs = get_constraint_exp_from_ssa_var (tmpvar);
! process_constraint (new_constraint (tmplhs, rhs));
! process_constraint (new_constraint (lhs, tmplhs));
}
else
{
*************** process_constraint_1 (constraint_t t, bo
*** 2595,2610 ****
}
}
-
- /* 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. */
--- 2593,2598 ----
*************** do_structure_copy (tree lhsop, tree rhso
*** 3267,3514 ****
}
- /* 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:
--- 3255,3260 ----
*************** make_constraint_to (unsigned id, tree op
*** 3598,3604 ****
get_constraint_for (op, &rhsc);
for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
! process_constraint_1 (new_constraint (includes, *c), true);
VEC_free (ce_s, heap, rhsc);
}
--- 3344,3350 ----
get_constraint_for (op, &rhsc);
for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
! process_constraint (new_constraint (includes, *c));
VEC_free (ce_s, heap, rhsc);
}
*************** handle_lhs_call (tree lhs)
*** 3643,3658 ****
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);
VEC_free (ce_s, heap, lhsc);
}
--- 3389,3399 ----
struct constraint_expr *lhsp;
get_constraint_for (lhs, &lhsc);
rhsc.var = escaped_id;
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint (new_constraint (*lhsp, rhsc));
VEC_free (ce_s, heap, lhsc);
}
*************** handle_const_call (tree stmt)
*** 3680,3686 ****
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;
}
--- 3421,3427 ----
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint (new_constraint (*lhsp, rhsc));
VEC_free (ce_s, heap, lhsc);
return;
}
*************** handle_const_call (tree stmt)
*** 3690,3696 ****
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);
/* May return arguments. */
FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
--- 3431,3437 ----
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint (new_constraint (*lhsp, rhsc));
/* May return arguments. */
FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
*************** handle_const_call (tree stmt)
*** 3702,3708 ****
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);
VEC_free (ce_s, heap, argc);
}
--- 3443,3449 ----
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 (new_constraint (*lhsp, *argp));
VEC_free (ce_s, heap, argc);
}
*************** handle_pure_call (tree stmt)
*** 3748,3754 ****
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;
}
--- 3489,3495 ----
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint (new_constraint (*lhsp, rhsc));
VEC_free (ce_s, heap, lhsc);
return;
}
*************** handle_pure_call (tree stmt)
*** 3759,3765 ****
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);
}
}
--- 3500,3506 ----
rhsc.offset = 0;
rhsc.type = ADDRESSOF;
for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
! process_constraint (new_constraint (*lhsp, rhsc));
VEC_free (ce_s, heap, lhsc);
}
}
*************** find_func_aliases (tree origt)
*** 3957,3966 ****
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))
{
do_structure_copy (lhsop, rhsop);
}
--- 3698,3705 ----
tree rhsop = GIMPLE_STMT_OPERAND (t, 1);
int i;
! if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
! && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
{
do_structure_copy (lhsop, rhsop);
}
*************** make_constraint_from (varinfo_t vi, int
*** 4340,4352 ****
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. */
--- 4079,4084 ----
*************** create_variable_info_for (tree decl, con
*** 4552,4559 ****
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);
stats.total_vars++;
if (use_field_sensitive
--- 4284,4292 ----
insert_vi_for_tree (vi->decl, vi);
VEC_safe_push (varinfo_t, heap, varmap, 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
*************** create_variable_info_for (tree decl, con
*** 4633,4640 ****
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);
stats.total_vars++;
}
--- 4366,4374 ----
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)
! && (!fo->decl || could_have_pointers (fo->decl)))
! make_constraint_from (newvi, escaped_id);
stats.total_vars++;
}
*************** init_base_vars (void)
*** 5296,5302 ****
rhs.type = DEREF;
rhs.var = escaped_id;
rhs.offset = 0;
! process_constraint_1 (new_constraint (lhs, rhs), true);
/* Create the NONLOCAL variable, used to represent the set of nonlocal
memory. */
--- 5030,5036 ----
rhs.type = DEREF;
rhs.var = escaped_id;
rhs.offset = 0;
! process_constraint (new_constraint (lhs, rhs));
/* Create the NONLOCAL variable, used to represent the set of nonlocal
memory. */
*************** init_base_vars (void)
*** 5339,5345 ****
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. */
--- 5073,5079 ----
rhs.type = DEREF;
rhs.var = callused_id;
rhs.offset = 0;
! process_constraint (new_constraint (lhs, rhs));
/* Create the INTEGER variable, used to represent that a variable points
to an INTEGER. */
*************** init_base_vars (void)
*** 5372,5378 ****
rhs.type = ADDRESSOF;
rhs.var = escaped_id;
rhs.offset = 0;
! process_constraint_1 (new_constraint (lhs, rhs), true);
/* *ESCAPED = &NONLOCAL. This is true because we have to assume
everything pointed to by escaped can also point to nonlocal. */
--- 5106,5112 ----
rhs.type = ADDRESSOF;
rhs.var = escaped_id;
rhs.offset = 0;
! 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. */
*************** init_base_vars (void)
*** 5382,5388 ****
rhs.type = ADDRESSOF;
rhs.var = nonlocal_id;
rhs.offset = 0;
! process_constraint_1 (new_constraint (lhs, rhs), true);
}
/* Initialize things necessary to perform PTA */
--- 5116,5122 ----
rhs.type = ADDRESSOF;
rhs.var = nonlocal_id;
rhs.offset = 0;
! process_constraint (new_constraint (lhs, rhs));
}
/* Initialize things necessary to perform PTA */
*************** compute_tbaa_pruning (void)
*** 5581,5587 ****
at the start of the file for an algorithmic overview. */
void
! compute_points_to_sets (struct alias_info *ai)
{
struct scc_info *si;
basic_block bb;
--- 5315,5321 ----
at the start of the file for an algorithmic overview. */
void
! compute_points_to_sets (void)
{
struct scc_info *si;
basic_block bb;
*************** compute_points_to_sets (struct alias_inf
*** 5600,5617 ****
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);
! }
! }
for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
{
--- 5334,5341 ----
tree phi;
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
! if (is_gimple_reg (PHI_RESULT (phi)))
! find_func_aliases (phi);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
{
*************** compute_points_to_sets (struct alias_inf
*** 5619,5630 ****
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)
--- 5343,5348 ----
*************** ipa_pta_execute (void)
*** 5761,5767 ****
{
varinfo_t fi = get_varinfo (varid);
for (; fi; fi = fi->next)
! make_constraint_from_anything (fi);
}
}
}
--- 5479,5485 ----
{
varinfo_t fi = get_varinfo (varid);
for (; fi; fi = fi->next)
! make_constraint_from (fi, anything_id);
}
}
}
Index: tree-ssa-structalias.h
===================================================================
*** tree-ssa-structalias.h (revision 137251)
--- tree-ssa-structalias.h (working copy)
***************
*** 24,67 ****
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 delete_points_to_sets (void);
extern void dump_constraint (FILE *, constraint_t);
extern void dump_constraints (FILE *);
--- 24,35 ----
struct constraint;
typedef struct constraint *constraint_t;
/* 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 (void);
extern void delete_points_to_sets (void);
extern void dump_constraint (FILE *, constraint_t);
extern void dump_constraints (FILE *);