aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-structalias.c
diff options
context:
space:
mode:
authorDiego Novillo <dnovillo@redhat.com>2005-07-10 00:28:01 +0000
committerDiego Novillo <dnovillo@gcc.gnu.org>2005-07-09 20:28:01 -0400
commite8ca41599546a7131d276d99fd4e7bbf402190d3 (patch)
tree9008332e0b51567fbab3eeb7dddef5739f208581 /gcc/tree-ssa-structalias.c
parent87f8dcd06e27dbf222d8bf4564400122ec387c00 (diff)
downloadgcc-e8ca41599546a7131d276d99fd4e7bbf402190d3.zip
gcc-e8ca41599546a7131d276d99fd4e7bbf402190d3.tar.gz
gcc-e8ca41599546a7131d276d99fd4e7bbf402190d3.tar.bz2
Makefile.in (tree-ssa-alias.o): Depend on tree-ssa-structalias.h
* Makefile.in (tree-ssa-alias.o): Depend on tree-ssa-structalias.h * tree-cfg.c (CHECK_OP): Only test for is_gimple_val. * tree-dfa.c (dump_subvars_for): New. (debug_subvars_for): New. (dump_variable): Show subvariables if VAR has them. * tree-flow-inline.h (get_subvar_at): New. (overlap_subvar): Change offset and size to unsigned HOST_WIDE_INT. * tree-flow.h (struct ptr_info_def): Remove field pt_malloc. Update all users. (struct subvar): Change fields offset and size to unsigned HOST_WIDE_INT. (dump_subvars_for): Declare. (debug_subvars_for): Declare. (get_subvar_at): Declare. (okay_component_ref_for_subvars): Change 2nd and 3rd argument to unsigned HOST_WIDE_INT *. (overlap_subvar): Likewise. * tree-gimple.c (is_gimple_reg): Always return false for SFTs and memory tags. * tree-pass.h (pass_build_pta, pass_del_pta): Remove. Update all callers. * tree-ssa-alias.c: Include tree-ssa-structalias.h. (compute_may_aliases): Call compute_points_to_sets. (collect_points_to_info_for): Remove. (compute_points_to_and_addr_escape): Remove. (delete_alias_info): Call delete_points_to_sets. (compute_flow_sensitive_aliasing): If the call to find_what_p_points_to returns false, call set_pt_anything. (add_may_alias): Set TREE_ADDRESSABLE when adding a new alias. (set_pt_anything): Clear pi->pt_vars. (set_pt_malloc): Remove. (merge_pointed_to_info): Remove. (add_pointed_to_expr): Remove. (add_pointed_to_var): Remove. (collect_points_to_info_r): Remove. (is_escape_site): Make extern. (create_sft): New. (create_overlap_variables_for): Call it. * tree-ssa-copy.c (merge_alias_info): Never merge flow-sensitive alias information. * tree-ssa-operands.c (get_expr_operands): Adjust variables offset and size to be unsigned HOST_WIDE_INT. (add_to_addressable_set): Rename from note_addressable. Set TREE_ADDRESSABLE as the variables are added to the set. Update all users. (add_stmt_operand): Do not try to micro-optimize unmodifiable operands into VUSEs when adding V_MAY_DEFs for members in an alias set. * tree-ssa-operands.h (add_to_addressable_set): Declare. * tree-ssa-structalias.c: Include tree-ssa-structalias.h last. (struct variable_info): Add bitfield is_heap_var. (var_anyoffset, anyoffset_tree, anyoffset_id): Declare. (new_var_info): Initialize is_heap_var. (get_constraint_for): Add HEAP variables to the symbol table. Mark them with is_heap_var. (update_alias_info): New. Taken mostly from the old compute_points_to_and_addr_escape. (handle_ptr_arith): New. (find_func_aliases): Call update_alias_info. Call handle_ptr_info for tcc_binary expressions. Call mark_stmt_modified. (create_variable_info_for): If DECL has subvars, do not create variables for its subvars. Always add all the fields. (set_uids_in_ptset): If the solution includes ANYOFFSET and SFTs, then add all the SFTs of the structure. If VI->DECL is an aggregate with subvariables, add the SFT at VI->OFFSET. (find_what_p_points_to): If VI is an artificial variable, translate to bitfields in SSA_NAME_PTR_INFO. If the solution is empty, set pi->pt_vars to NULL (init_base_vars): Create ANYOFFSET. (compute_points_to_sets): Rename from create_alias_vars. Make extern. (pass_build_pta): Remove. (delete_points_to_sets): Rename from delete_alias_vars. (pass_del_pta): Remove. * tree-ssa-structalias.h (struct alias_info): Move from tree-ssa-alias.h. (NUM_REFERENCES, NUM_REFERENCES_CLEAR, NUM_REFERENCES_INC, NUM_REFERENCES_SET): Likewise. (compute_points_to_sets, delete_points_to_sets): Declare. testsuite/ChangeLog * gcc.dg/tree-ssa/pta-fp.c: Use -fdump-tree-alias1. From-SVN: r101841
Diffstat (limited to 'gcc/tree-ssa-structalias.c')
-rw-r--r--gcc/tree-ssa-structalias.c650
1 files changed, 449 insertions, 201 deletions
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index efa2238..7ec5270 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "ggc.h"
#include "obstack.h"
#include "bitmap.h"
-#include "tree-ssa-structalias.h"
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
@@ -49,6 +48,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#include "timevar.h"
#include "alloc-pool.h"
#include "splay-tree.h"
+#include "tree-ssa-structalias.h"
/* The idea behind this analyzer is to generate set constraints from the
program, then solve the resulting constraints in order to generate the
@@ -223,6 +223,9 @@ struct variable_info
/* True for variables that have unions somewhere in them. */
unsigned int has_union:1;
+ /* True if this is a heap variable. */
+ unsigned int is_heap_var:1;
+
/* Points-to set for this variable. */
bitmap solution;
@@ -270,6 +273,12 @@ static varinfo_t var_integer;
static tree integer_tree;
static unsigned int integer_id;
+/* Variable that represents arbitrary offsets into an object. Used to
+ represent pointer arithmetic, which may not legally escape the
+ bounds of an object. */
+static varinfo_t var_anyoffset;
+static tree anyoffset_tree;
+static unsigned int anyoffset_id;
/* Return a new variable info structure consisting for a variable
named NAME, and using constraint graph node NODE. */
@@ -286,6 +295,7 @@ new_var_info (tree t, unsigned int id, const char *name, unsigned int node)
ret->address_taken = false;
ret->indirect_target = false;
ret->is_artificial_var = false;
+ ret->is_heap_var = false;
ret->is_unknown_size_var = false;
ret->solution = BITMAP_ALLOC (&ptabitmap_obstack);
bitmap_clear (ret->solution);
@@ -941,8 +951,11 @@ build_constraint_graph (void)
constraint_t c;
graph = ggc_alloc (sizeof (struct constraint_graph));
- graph->succs = ggc_alloc_cleared (VEC_length (varinfo_t, varmap) * sizeof (*graph->succs));
- graph->preds = ggc_alloc_cleared (VEC_length (varinfo_t, varmap) * sizeof (*graph->preds));
+ graph->succs = ggc_alloc_cleared (VEC_length (varinfo_t, varmap)
+ * sizeof (*graph->succs));
+ graph->preds = ggc_alloc_cleared (VEC_length (varinfo_t, varmap)
+ * sizeof (*graph->preds));
+
for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
{
struct constraint_expr lhs = c->lhs;
@@ -983,6 +996,8 @@ build_constraint_graph (void)
}
}
}
+
+
/* Changed variables on the last iteration. */
static unsigned int changed_count;
static sbitmap changed;
@@ -2137,11 +2152,18 @@ get_constraint_for (tree t)
&ANYTHING added. */
if (call_expr_flags (t) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))
{
- tree heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
+ varinfo_t vi;
+ tree heapvar;
+
+ heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
+ DECL_EXTERNAL (heapvar) = 1;
+ add_referenced_tmp_var (heapvar);
temp.var = create_variable_info_for (heapvar,
alias_get_name (heapvar));
- get_varinfo (temp.var)->is_artificial_var = 1;
+ vi = get_varinfo (temp.var);
+ vi->is_artificial_var = 1;
+ vi->is_heap_var = 1;
temp.type = ADDRESSOF;
temp.offset = 0;
return temp;
@@ -2191,9 +2213,11 @@ get_constraint_for (tree t)
/* Cast from non-pointer to pointers are bad news for us.
Anything else, we see through */
- if (!(POINTER_TYPE_P (TREE_TYPE (t)) &&
- ! POINTER_TYPE_P (TREE_TYPE (op))))
+ if (!(POINTER_TYPE_P (TREE_TYPE (t))
+ && ! POINTER_TYPE_P (TREE_TYPE (op))))
return get_constraint_for (op);
+
+ /* FALLTHRU */
}
default:
{
@@ -2467,81 +2491,300 @@ ref_contains_indirect_ref (tree ref)
}
-/* Tree walker that is the heart of the aliasing infrastructure.
- TP is a pointer to the current tree.
- WALK_SUBTREES specifies whether to continue traversing subtrees or
- not.
- Returns NULL_TREE when we should stop.
-
- This function is the main part of the constraint builder. It
- walks the trees, calling the appropriate building functions
- to process various statements. */
+/* 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;
+ def_operand_p def_p;
+ ssa_op_iter iter;
+ bool stmt_escapes_p = is_escape_site (stmt, ai);
+
+ /* Mark all the variables whose address are taken by the statement. */
+ addr_taken = addresses_taken (stmt);
+ if (addr_taken)
+ {
+ bitmap_ior_into (addressable_vars, addr_taken);
+
+ /* If STMT is an escape point, all the addresses taken by it are
+ call-clobbered. */
+ if (stmt_escapes_p)
+ {
+ bitmap_iterator bi;
+ unsigned i;
+
+ EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
+ mark_call_clobbered (referenced_var (i));
+ }
+ }
+
+ /* Process each operand use. If an operand may be aliased, keep
+ track of how many times it's being used. 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;
+ bool is_store;
+ unsigned num_uses, num_derefs;
+
+ 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)
+ {
+ gcc_assert (TREE_CODE (stmt) == PHI_NODE);
+
+ /* 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. */
+ if (TREE_CODE (op) != SSA_NAME)
+ continue;
+
+ var = SSA_NAME_VAR (op);
+ v_ann = var_ann (var);
+
+ /* If the operand's variable may be aliased, keep track of how
+ many times we've referenced it. This is used for alias
+ grouping in compute_flow_insensitive_aliasing. */
+ if (may_be_aliased (var))
+ NUM_REFERENCES_INC (v_ann);
+
+ /* 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));
+ VARRAY_PUSH_TREE (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_derefs, &is_store);
+
+ if (num_derefs > 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->is_dereferenced = 1;
+
+ /* Keep track of how many time we've dereferenced each
+ pointer. */
+ NUM_REFERENCES_INC (v_ann);
+
+ /* If this is a store operation, mark OP as being
+ dereferenced to store, otherwise mark it as being
+ dereferenced to load. */
+ if (is_store)
+ bitmap_set_bit (ai->dereferenced_ptrs_store, DECL_UID (var));
+ else
+ bitmap_set_bit (ai->dereferenced_ptrs_load, DECL_UID (var));
+ }
+
+ if (stmt_escapes_p && num_derefs < 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;
+
+ /* 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))
+ {
+ bitmap_set_bit (ai->dereferenced_ptrs_store, DECL_UID (var));
+ pi->is_dereferenced = 1;
+ }
+ }
+ }
+
+ /* Update reference counter for definitions to any potentially
+ aliased variable. This is used in the alias grouping heuristics. */
+ FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, iter, SSA_OP_ALL_DEFS)
+ {
+ tree op = DEF_FROM_PTR (def_p);
+ tree var = SSA_NAME_VAR (op);
+ var_ann_t ann = var_ann (var);
+ bitmap_set_bit (ai->written_vars, DECL_UID (var));
+ if (may_be_aliased (var))
+ NUM_REFERENCES_INC (ann);
+ }
+}
+
+
+/* Handle pointer arithmetic EXPR when creating aliasing constraints.
+ Expressions of the type PTR + CST can be handled in two ways:
+
+ 1- If the constraint for PTR is ADDRESSOF for a non-structure
+ variable, then we can use it directly because adding or
+ subtracting a constant may not alter the original ADDRESSOF
+ constraing (i.e., pointer arithmetic may not legally go outside
+ an object's boundaries).
+
+ 2- If the constraint for PTR is ADDRESSOF for a structure variable,
+ then if CST is a compile-time constant that can be used as an
+ offset, we can determine which sub-variable will be pointed-to
+ by the expression.
+
+ Return true if the expression is handled. For any other kind of
+ expression, return false so that each operand can be added as a
+ separate constraint by the caller. */
+
+static bool
+handle_ptr_arith (struct constraint_expr lhs, tree expr)
+{
+ tree op0, op1;
+ struct constraint_expr base, offset;
+
+ if (TREE_CODE (expr) != PLUS_EXPR)
+ return false;
+
+ op0 = TREE_OPERAND (expr, 0);
+ op1 = TREE_OPERAND (expr, 1);
+
+ base = get_constraint_for (op0);
+
+ offset.var = anyoffset_id;
+ offset.type = ADDRESSOF;
+ offset.offset = 0;
+
+ process_constraint (new_constraint (lhs, base));
+ process_constraint (new_constraint (lhs, offset));
+
+ return true;
+}
+
+
+/* Walk statement T setting up aliasing constraints according to the
+ references found in T. This function is the main part of the
+ constraint builder. AI points to auxiliary alias information used
+ when building alias sets and computing alias grouping heuristics. */
static void
-find_func_aliases (tree t)
+find_func_aliases (tree t, struct alias_info *ai)
{
struct constraint_expr lhs, rhs;
- switch (TREE_CODE (t))
- {
- case PHI_NODE:
- {
- int i;
- /* Only care about pointers and structures containing
- pointers. */
- if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t)))
- || AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))))
- {
- lhs = get_constraint_for (PHI_RESULT (t));
- for (i = 0; i < PHI_NUM_ARGS (t); i++)
- {
- rhs = get_constraint_for (PHI_ARG_DEF (t, i));
- process_constraint (new_constraint (lhs, rhs));
- }
- }
- }
- break;
+ /* 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 (t, ai);
- case MODIFY_EXPR:
- {
- tree lhsop = TREE_OPERAND (t, 0);
- tree rhsop = TREE_OPERAND (t, 1);
- int i;
+ /* Now build constraints expressions. */
+ if (TREE_CODE (t) == PHI_NODE)
+ {
+ /* Only care about pointers and structures containing
+ pointers. */
+ if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t)))
+ || AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))))
+ {
+ int i;
- if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
- && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
- {
- do_structure_copy (lhsop, rhsop);
- }
- else
- {
- /* Only care about operations with pointers, structures
- containing pointers, dereferences, and call
- expressions. */
- if (POINTER_TYPE_P (TREE_TYPE (lhsop))
- || AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
- || ref_contains_indirect_ref (lhsop)
- || TREE_CODE (rhsop) == CALL_EXPR)
- {
- lhs = get_constraint_for (lhsop);
- switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
- {
- /* RHS that consist of unary operations,
- exceptional types, or bare decls/constants, get
- handled directly by get_constraint_for. */
+ lhs = get_constraint_for (PHI_RESULT (t));
+ for (i = 0; i < PHI_NUM_ARGS (t); i++)
+ {
+ rhs = get_constraint_for (PHI_ARG_DEF (t, i));
+ process_constraint (new_constraint (lhs, rhs));
+ }
+ }
+ }
+ else if (TREE_CODE (t) == MODIFY_EXPR)
+ {
+ tree lhsop = TREE_OPERAND (t, 0);
+ tree rhsop = TREE_OPERAND (t, 1);
+ int i;
+
+ if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
+ && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
+ {
+ do_structure_copy (lhsop, rhsop);
+ }
+ else
+ {
+ /* Only care about operations with pointers, structures
+ containing pointers, dereferences, and call expressions. */
+ if (POINTER_TYPE_P (TREE_TYPE (lhsop))
+ || AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
+ || ref_contains_indirect_ref (lhsop)
+ || TREE_CODE (rhsop) == CALL_EXPR)
+ {
+ lhs = get_constraint_for (lhsop);
+ switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
+ {
+ /* RHS that consist of unary operations,
+ exceptional types, or bare decls/constants, get
+ handled directly by get_constraint_for. */
case tcc_reference:
case tcc_declaration:
case tcc_constant:
case tcc_exceptional:
case tcc_expression:
case tcc_unary:
- {
- rhs = get_constraint_for (rhsop);
- process_constraint (new_constraint (lhs, rhs));
- }
+ {
+ rhs = get_constraint_for (rhsop);
+ process_constraint (new_constraint (lhs, rhs));
+
+ /* When taking the address of an aggregate
+ type, from the LHS we can access any field
+ of the RHS. */
+ if (rhs.type == ADDRESSOF
+ && rhs.var > anything_id
+ && AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (rhsop))))
+ {
+ rhs.var = anyoffset_id;
+ rhs.type = ADDRESSOF;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
+ }
+ }
break;
- /* Otherwise, walk each operand. */
+ case tcc_binary:
+ {
+ /* For pointer arithmetic of the form
+ PTR + CST, we can simply use PTR's
+ constraint because pointer arithmetic is
+ not allowed to go out of bounds. */
+ if (handle_ptr_arith (lhs, rhsop))
+ break;
+ }
+ /* FALLTHRU */
+
+ /* Otherwise, walk each operand. Notice that we
+ can't use the operand interface because we need
+ to process expressions other than simple operands
+ (e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR). */
default:
for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (rhsop)); i++)
{
@@ -2549,15 +2792,16 @@ find_func_aliases (tree t)
rhs = get_constraint_for (op);
process_constraint (new_constraint (lhs, rhs));
}
- }
- }
- }
- }
- break;
-
- default:
- break;
+ }
+ }
+ }
}
+
+ /* After promoting variables and computing aliasing we will
+ need to re-scan most statements. FIXME: Try to minimize the
+ number of statements re-scanned. It's not really necessary to
+ re-scan *all* statements. */
+ mark_stmt_modified (t);
}
@@ -2718,12 +2962,12 @@ create_variable_info_for (tree decl, const char *name)
tree decltype = TREE_TYPE (decl);
bool notokay = false;
bool hasunion;
- subvar_t svars;
bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
VEC (fieldoff_s,heap) *fieldstack = NULL;
- hasunion = TREE_CODE (decltype) == UNION_TYPE || TREE_CODE (decltype) == QUAL_UNION_TYPE;
+ hasunion = TREE_CODE (decltype) == UNION_TYPE
+ || TREE_CODE (decltype) == QUAL_UNION_TYPE;
if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion)
{
push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion);
@@ -2733,62 +2977,6 @@ create_variable_info_for (tree decl, const char *name)
notokay = true;
}
}
-
- /* If this variable already has subvars, just create the variables for the
- subvars and we are done.
- NOTE: This assumes things haven't generated uses of previously
- unused structure fields. */
- if (use_field_sensitive
- && !notokay
- && var_can_have_subvars (decl)
- && var_ann (decl)
- && (svars = get_subvars_for_var (decl)))
- {
- subvar_t sv;
- varinfo_t base = NULL;
- unsigned int firstindex = index;
-
- for (sv = svars; sv; sv = sv->next)
- {
- /* For debugging purposes, this will print the names of the
- fields as "<var>.<offset>.<size>"
- This is only for debugging purposes. */
-#define PRINT_LONG_NAMES
-#ifdef PRINT_LONG_NAMES
- char *tempname;
- const char *newname;
-
- asprintf (&tempname,
- "%s." HOST_WIDE_INT_PRINT_DEC "." HOST_WIDE_INT_PRINT_DEC,
- alias_get_name (decl), sv->offset, sv->size);
- newname = ggc_strdup (tempname);
- free (tempname);
- vi = new_var_info (sv->var, index, newname, index);
-#else
- vi = new_var_info (sv->var, index, alias_get_name (sv->var), index);
-#endif
- vi->decl = sv->var;
- vi->fullsize = TREE_INT_CST_LOW (TYPE_SIZE (decltype));
- vi->size = sv->size;
- vi->offset = sv->offset;
- if (!base)
- {
- base = vi;
- insert_id_for_tree (decl, index);
- }
- else
- {
- insert_into_field_list (base, vi);
- }
- insert_id_for_tree (sv->var, index);
- VEC_safe_push (varinfo_t, gc, varmap, vi);
- if (is_global)
- make_constraint_to_anything (vi);
- index++;
-
- }
- return firstindex;
- }
/* If the variable doesn't have subvars, we may end up needing to
@@ -2935,7 +3123,6 @@ intra_create_variable_infos (void)
lhs.type = SCALAR;
lhs.var = create_variable_info_for (t, alias_get_name (t));
- get_varinfo (lhs.var)->is_artificial_var = true;
rhs.var = anything_id;
rhs.type = ADDRESSOF;
rhs.offset = 0;
@@ -2958,30 +3145,67 @@ set_uids_in_ptset (bitmap into, bitmap from)
{
unsigned int i;
bitmap_iterator bi;
+ bool found_anyoffset = false;
+ subvar_t sv;
EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
{
varinfo_t vi = get_varinfo (i);
+
+ /* If we find ANYOFFSET in the solution and the solution
+ includes SFTs for some structure, then all the SFTs in that
+ structure will need to be added to the alias set. */
+ if (vi->id == anyoffset_id)
+ {
+ found_anyoffset = true;
+ continue;
+ }
+
+ /* The only artificial variables that are allowed in a may-alias
+ set are heap variables. */
+ if (vi->is_artificial_var && !vi->is_heap_var)
+ continue;
- /* Variables containing unions may need to be converted to their
- SFT's, because SFT's can have unions and we cannot. */
if (vi->has_union && get_subvars_for_var (vi->decl) != NULL)
{
- subvar_t svars = get_subvars_for_var (vi->decl);
- subvar_t sv;
- for (sv = svars; sv; sv = sv->next)
+ /* Variables containing unions may need to be converted to
+ their SFT's, because SFT's can have unions and we cannot. */
+ for (sv = get_subvars_for_var (vi->decl); sv; sv = sv->next)
bitmap_set_bit (into, DECL_UID (sv->var));
}
- /* We may end up with labels in the points-to set because people
- take their address, and they are _DECL's. */
else if (TREE_CODE (vi->decl) == VAR_DECL
- || TREE_CODE (vi->decl) == PARM_DECL)
- bitmap_set_bit (into, DECL_UID (vi->decl));
-
-
+ || TREE_CODE (vi->decl) == PARM_DECL)
+ {
+ if (found_anyoffset
+ && var_can_have_subvars (vi->decl)
+ && get_subvars_for_var (vi->decl))
+ {
+ /* If ANYOFFSET is in the solution set and VI->DECL is
+ an aggregate variable with sub-variables, then any of
+ the SFTs inside VI->DECL may have been accessed. Add
+ all the sub-vars for VI->DECL. */
+ for (sv = get_subvars_for_var (vi->decl); sv; sv = sv->next)
+ bitmap_set_bit (into, DECL_UID (sv->var));
+ }
+ else if (var_can_have_subvars (vi->decl)
+ && get_subvars_for_var (vi->decl))
+ {
+ /* If VI->DECL is an aggregate for which we created
+ SFTs, add the SFT corresponding to VI->OFFSET. */
+ tree sft = get_subvar_at (vi->decl, vi->offset);
+ bitmap_set_bit (into, DECL_UID (sft));
+ }
+ else
+ {
+ /* Otherwise, just add VI->DECL to the alias set. */
+ bitmap_set_bit (into, DECL_UID (vi->decl));
+ }
+ }
}
}
-static int have_alias_info = false;
+
+
+static bool have_alias_info = false;
/* Given a pointer variable P, fill in its points-to set, or return
false if we can't. */
@@ -2990,8 +3214,10 @@ bool
find_what_p_points_to (tree p)
{
unsigned int id = 0;
+
if (!have_alias_info)
return false;
+
if (lookup_id_for_tree (p, &id))
{
varinfo_t vi = get_varinfo (id);
@@ -2999,14 +3225,15 @@ find_what_p_points_to (tree p)
if (vi->is_artificial_var)
return false;
- /* See if this is a field or a structure */
+ /* See if this is a field or a structure. */
if (vi->size != vi->fullsize)
{
+ /* Nothing currently asks about structure fields directly,
+ but when they do, we need code here to hand back the
+ points-to set. */
if (!var_can_have_subvars (vi->decl)
|| get_subvars_for_var (vi->decl) == NULL)
return false;
- /* Nothing currently asks about structure fields directly, but when
- they do, we need code here to hand back the points-to set. */
}
else
{
@@ -3018,21 +3245,45 @@ find_what_p_points_to (tree p)
variable. */
vi = get_varinfo (vi->node);
- /* Make sure there aren't any artificial vars in the points to set.
- XXX: Note that we need to translate our heap variables to
- something. */
+ /* Translate artificial variables into SSA_NAME_PTR_INFO
+ attributes. */
EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
{
- if (get_varinfo (i)->is_artificial_var)
- return false;
+ varinfo_t vi = get_varinfo (i);
+
+ if (vi->is_artificial_var)
+ {
+ /* FIXME. READONLY should be handled better so that
+ flow insensitive aliasing can disregard writeable
+ aliases. */
+ if (vi->id == nothing_id)
+ pi->pt_null = 1;
+ else if (vi->id == anything_id)
+ pi->pt_anything = 1;
+ else if (vi->id == readonly_id)
+ pi->pt_anything = 1;
+ else if (vi->id == integer_id)
+ pi->pt_anything = 1;
+ else if (vi->is_heap_var)
+ pi->pt_global_mem = 1;
+ }
}
- pi->pt_anything = false;
+
+ if (pi->pt_anything)
+ return false;
+
if (!pi->pt_vars)
pi->pt_vars = BITMAP_GGC_ALLOC ();
+
set_uids_in_ptset (pi->pt_vars, vi->solution);
+
+ if (bitmap_empty_p (pi->pt_vars))
+ pi->pt_vars = NULL;
+
return true;
}
}
+
return false;
}
@@ -3053,7 +3304,7 @@ dump_sa_points_to_info (FILE *outfile)
{
unsigned int i;
- fprintf (outfile, "\nPoints-to information\n\n");
+ fprintf (outfile, "\nPoints-to sets\n\n");
if (dump_flags & TDF_STATS)
{
@@ -3124,6 +3375,7 @@ init_base_vars (void)
rhs.var = anything_id;
rhs.offset = 0;
var_anything->address_taken = true;
+
/* This specifically does not use process_constraint because
process_constraint ignores all anything = anything constraints, since all
but this one are redundant. */
@@ -3177,17 +3429,44 @@ init_base_vars (void)
rhs.var = anything_id;
rhs.offset = 0;
process_constraint (new_constraint (lhs, rhs));
+
+ /* Create the ANYOFFSET variable, used to represent an arbitrary offset
+ inside an object. This is similar to ANYTHING, but less drastic.
+ It means that the pointer can point anywhere inside an object,
+ but not outside of it. */
+ anyoffset_tree = create_tmp_var_raw (void_type_node, "ANYOFFSET");
+ anyoffset_id = 4;
+ var_anyoffset = new_var_info (anyoffset_tree, anyoffset_id, "ANYOFFSET",
+ anyoffset_id);
+ insert_id_for_tree (anyoffset_tree, anyoffset_id);
+ var_anyoffset->is_artificial_var = 1;
+ var_anyoffset->size = ~0;
+ var_anyoffset->offset = 0;
+ var_anyoffset->next = NULL;
+ var_anyoffset->fullsize = ~0;
+ VEC_safe_push (varinfo_t, gc, varmap, var_anyoffset);
+
+ /* ANYOFFSET points to ANYOFFSET. */
+ lhs.type = SCALAR;
+ lhs.var = anyoffset_id;
+ lhs.offset = 0;
+ rhs.type = ADDRESSOF;
+ rhs.var = anyoffset_id;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
}
/* Create points-to sets for the current function. See the comments
at the start of the file for an algorithmic overview. */
-static void
-create_alias_vars (void)
+void
+compute_points_to_sets (struct alias_info *ai)
{
basic_block bb;
-
+
+ timevar_push (TV_TREE_PTA);
+
init_alias_vars ();
constraint_pool = create_alloc_pool ("Constraint pool",
@@ -3201,7 +3480,7 @@ create_alias_vars (void)
varmap = VEC_alloc (varinfo_t, gc, 8);
id_for_tree = htab_create (10, tree_id_hash, tree_id_eq, free);
memset (&stats, 0, sizeof (stats));
-
+
init_base_vars ();
intra_create_variable_infos ();
@@ -3214,28 +3493,29 @@ create_alias_vars (void)
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
if (is_gimple_reg (PHI_RESULT (phi)))
- find_func_aliases (phi);
+ find_func_aliases (phi, ai);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- find_func_aliases (bsi_stmt (bsi));
+ find_func_aliases (bsi_stmt (bsi), ai);
}
build_constraint_graph ();
if (dump_file)
{
- fprintf (dump_file, "Constraints:\n");
+ fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
dump_constraints (dump_file);
}
if (dump_file)
- fprintf (dump_file, "Collapsing static cycles and doing variable substitution:\n");
+ fprintf (dump_file, "\nCollapsing static cycles and doing variable "
+ "substitution:\n");
find_and_collapse_graph_cycles (graph, false);
perform_var_substitution (graph);
if (dump_file)
- fprintf (dump_file, "Solving graph:\n");
+ fprintf (dump_file, "\nSolving graph:\n");
solve_graph (graph);
@@ -3243,30 +3523,15 @@ create_alias_vars (void)
dump_sa_points_to_info (dump_file);
have_alias_info = true;
+
+ timevar_pop (TV_TREE_PTA);
}
-struct tree_opt_pass pass_build_pta =
-{
- "pta", /* name */
- NULL, /* gate */
- create_alias_vars, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_PTA, /* tv_id */
- PROP_cfg, /* properties_required */
- PROP_pta, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};
-
/* Delete created points-to sets. */
-static void
-delete_alias_vars (void)
+void
+delete_points_to_sets (void)
{
htab_delete (id_for_tree);
free_alloc_pool (variable_info_pool);
@@ -3275,20 +3540,3 @@ delete_alias_vars (void)
bitmap_obstack_release (&ptabitmap_obstack);
have_alias_info = false;
}
-
-struct tree_opt_pass pass_del_pta =
-{
- NULL, /* name */
- NULL, /* gate */
- delete_alias_vars, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_TREE_PTA, /* tv_id */
- PROP_pta, /* properties_required */
- 0, /* properties_provided */
- PROP_pta, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
-};