-static hashval_t
-ptr_info_hash (const void *p)
-{
- const struct ptr_info_def *n = (const struct ptr_info_def *) p;
- return bitmap_hash (n->pt_vars);
-}
-
-
-/* Create name tags for all the pointers that have been dereferenced.
- We only create a name tag for a pointer P if P is found to point to
- a set of variables (so that we can alias them to *P) or if it is
- the result of a call to malloc (which means that P cannot point to
- anything else nor alias any other variable).
-
- If two pointers P and Q point to the same set of variables, they
- are assigned the same name tag. */
-
-static void
-create_name_tags (void)
-{
- size_t i;
- VEC (tree, heap) *with_ptvars = NULL;
- tree ptr;
- htab_t ptr_hash;
-
- /* Collect the list of pointers with a non-empty points to set. */
- for (i = 1; i < num_ssa_names; i++)
- {
- tree ptr = ssa_name (i);
- struct ptr_info_def *pi;
-
- if (!ptr
- || !POINTER_TYPE_P (TREE_TYPE (ptr))
- || !SSA_NAME_PTR_INFO (ptr))
- continue;
-
- pi = SSA_NAME_PTR_INFO (ptr);
-
- if (pi->pt_anything || !pi->is_dereferenced)
- {
- /* No name tags for pointers that have not been
- dereferenced or point to an arbitrary location. */
- pi->name_mem_tag = NULL_TREE;
- continue;
- }
-
- /* Set pt_anything on the pointers without pt_vars filled in so
- that they are assigned a symbol tag. */
- if (pi->pt_vars && !bitmap_empty_p (pi->pt_vars))
- VEC_safe_push (tree, heap, with_ptvars, ptr);
- else
- set_pt_anything (ptr);
- }
-
- /* If we didn't find any pointers with pt_vars set, we're done. */
- if (!with_ptvars)
- return;
-
- ptr_hash = htab_create (10, ptr_info_hash, eq_ptr_info, NULL);
-
- /* Now go through the pointers with pt_vars, and find a name tag
- with the same pt_vars as this pointer, or create one if one
- doesn't exist. */
- for (i = 0; VEC_iterate (tree, with_ptvars, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
- tree old_name_tag = pi->name_mem_tag;
- struct ptr_info_def **slot;
-
- /* If PTR points to a set of variables, check if we don't
- have another pointer Q with the same points-to set before
- creating a tag. If so, use Q's tag instead of creating a
- new one.
-
- This is important for not creating unnecessary symbols
- and also for copy propagation. If we ever need to
- propagate PTR into Q or vice-versa, we would run into
- problems if they both had different name tags because
- they would have different SSA version numbers (which
- would force us to take the name tags in and out of SSA). */
- slot = (struct ptr_info_def **) htab_find_slot (ptr_hash, pi, INSERT);
- if (*slot)
- pi->name_mem_tag = (*slot)->name_mem_tag;
- else
- {
- *slot = pi;
-
- /* If we didn't find a pointer with the same points-to set
- as PTR, create a new name tag if needed. */
- if (pi->name_mem_tag == NULL_TREE)
- pi->name_mem_tag = get_nmt_for (ptr);
- }
-
- /* If the new name tag computed for PTR is different than
- the old name tag that it used to have, then the old tag
- needs to be removed from the IL, so we mark it for
- renaming. */
- if (old_name_tag && old_name_tag != pi->name_mem_tag)
- mark_sym_for_renaming (old_name_tag);
-
- /* Inherit volatility from the pointed-to type. */
- TREE_THIS_VOLATILE (pi->name_mem_tag)
- |= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
-
- /* Mark the new name tag for renaming. */
- mark_sym_for_renaming (pi->name_mem_tag);
- }
-
- htab_delete (ptr_hash);
-
- VEC_free (tree, heap, with_ptvars);
-}
-
-
-/* Union the alias set SET into the may-aliases for TAG. */
-
-static void
-union_alias_set_into (tree tag, bitmap set)
-{
- bitmap ma = MTAG_ALIASES (tag);
-
- if (bitmap_empty_p (set))
- return;
-
- if (!ma)
- ma = MTAG_ALIASES (tag) = BITMAP_ALLOC (&alias_bitmap_obstack);
- bitmap_ior_into (ma, set);
-}
-
-
-/* For every pointer P_i in AI->PROCESSED_PTRS, create may-alias sets for
- the name memory tag (NMT) associated with P_i. If P_i escapes, then its
- name tag and the variables it points-to are call-clobbered. Finally, if
- P_i escapes and we could not determine where it points to, then all the
- variables in the same alias set as *P_i are marked call-clobbered. This
- is necessary because we must assume that P_i may take the address of any
- variable in the same alias set. */
-
-static void
-compute_flow_sensitive_aliasing (struct alias_info *ai)
-{
- size_t i;
- tree ptr;
-
- timevar_push (TV_FLOW_SENSITIVE);
- set_used_smts ();
-
- for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
- {
- if (!find_what_p_points_to (ptr))
- set_pt_anything (ptr);
- }
-
- create_name_tags ();
-
- for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
- {
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
-
- /* Set up aliasing information for PTR's name memory tag (if it has
- one). Note that only pointers that have been dereferenced will
- have a name memory tag. */
- if (pi->name_mem_tag && pi->pt_vars)
- {
- if (!bitmap_empty_p (pi->pt_vars))
- union_alias_set_into (pi->name_mem_tag, pi->pt_vars);
- }
- }
- timevar_pop (TV_FLOW_SENSITIVE);
-}
-
-
-/* Return TRUE if at least one symbol in TAG2's alias set is also
- present in TAG1's alias set. */
-
-static bool
-have_common_aliases_p (bitmap tag1aliases, bitmap tag2aliases)
-{
-
- /* This is the old behavior of have_common_aliases_p, which is to
- return false if both sets are empty, or one set is and the other
- isn't. */
- if (tag1aliases == NULL || tag2aliases == NULL)
- return false;
-
- return bitmap_intersect_p (tag1aliases, tag2aliases);
-}
-
-/* Compute type-based alias sets. Traverse all the pointers and
- addressable variables found in setup_pointers_and_addressables.
-
- For every pointer P in AI->POINTERS and addressable variable V in
- AI->ADDRESSABLE_VARS, add V to the may-alias sets of P's symbol
- memory tag (SMT) if their alias sets conflict. V is then marked as
- an aliased symbol so that the operand scanner knows that statements
- containing V have aliased operands. */
-
-static void
-compute_flow_insensitive_aliasing (struct alias_info *ai)
-{
- size_t i;
-
- timevar_push (TV_FLOW_INSENSITIVE);
- /* For every pointer P, determine which addressable variables may alias
- with P's symbol memory tag. */
- for (i = 0; i < ai->num_pointers; i++)
- {
- size_t j;
- struct alias_map_d *p_map = ai->pointers[i];
- tree tag = symbol_mem_tag (p_map->var);
- tree var;
-
- for (j = 0; j < ai->num_addressable_vars; j++)
- {
- struct alias_map_d *v_map;
- var_ann_t v_ann;
- bool tag_stored_p, var_stored_p;
-
- v_map = ai->addressable_vars[j];
- var = v_map->var;
- v_ann = var_ann (var);
-
- /* Skip memory tags and variables that have never been
- written to. We also need to check if the variables are
- call-clobbered because they may be overwritten by
- function calls. */
- tag_stored_p = pointer_set_contains (ai->written_vars, tag)
- || is_call_clobbered (tag);
- var_stored_p = pointer_set_contains (ai->written_vars, var)
- || is_call_clobbered (var);
- if (!tag_stored_p && !var_stored_p)
- continue;
-
- if (may_alias_p (p_map->var, p_map->set, var, v_map->set, false))
- {
- /* Add VAR to TAG's may-aliases set. */
- add_may_alias (tag, var);
- }
- }
- }
-
- /* Since this analysis is based exclusively on symbols, it fails to
- handle cases where two pointers P and Q have different memory
- tags with conflicting alias set numbers but no aliased symbols in
- common.
-
- For example, suppose that we have two memory tags SMT.1 and SMT.2
- such that
-
- may-aliases (SMT.1) = { a }
- may-aliases (SMT.2) = { b }
-
- and the alias set number of SMT.1 conflicts with that of SMT.2.
- Since they don't have symbols in common, loads and stores from
- SMT.1 and SMT.2 will seem independent of each other, which will
- lead to the optimizers making invalid transformations (see
- testsuite/gcc.c-torture/execute/pr15262-[12].c).
-
- To avoid this problem, we do a final traversal of AI->POINTERS
- looking for pairs of pointers that have no aliased symbols in
- common and yet have conflicting alias set numbers. */
- for (i = 0; i < ai->num_pointers; i++)
- {
- size_t j;
- struct alias_map_d *p_map1 = ai->pointers[i];
- tree tag1 = symbol_mem_tag (p_map1->var);
- bitmap may_aliases1 = MTAG_ALIASES (tag1);
-
- for (j = 0; j < ai->num_pointers; j++)
- {
- struct alias_map_d *p_map2 = ai->pointers[j];
- tree tag2 = symbol_mem_tag (p_map2->var);
- bitmap may_aliases2 = may_aliases (tag2);
-
- /* By convention tags don't alias themselves. */
- if (tag1 == tag2)
- continue;
-
- /* If the pointers may not point to each other, do nothing. */
- if (!may_alias_p (p_map1->var, p_map1->set, tag2, p_map2->set, true))
- continue;
-
- /* The two pointers may alias each other. If they already have
- symbols in common, do nothing. */
- if (have_common_aliases_p (may_aliases1, may_aliases2))
- continue;
-
- add_may_alias (tag1, tag2);
- }
- }
- timevar_pop (TV_FLOW_INSENSITIVE);
-}
-
-
-/* Create a new alias set entry for VAR in AI->ADDRESSABLE_VARS. */
-
-static void
-create_alias_map_for (tree var, struct alias_info *ai)
-{
- struct alias_map_d *alias_map;
- alias_map = XCNEW (struct alias_map_d);
- alias_map->var = var;
- alias_map->set = get_alias_set (var);
- ai->addressable_vars[ai->num_addressable_vars++] = alias_map;
-}
-
-
-/* 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
- earlier, this pass will also clear the TREE_ADDRESSABLE flag from those
- variables whose address is not needed anymore. */
-
-static void
-setup_pointers_and_addressables (struct alias_info *ai)
-{
- size_t num_addressable_vars, num_pointers;
- referenced_var_iterator rvi;
- tree var;
- VEC (tree, heap) *varvec = NULL;
- safe_referenced_var_iterator srvi;
-
- /* Size up the arrays ADDRESSABLE_VARS and POINTERS. */
- num_addressable_vars = num_pointers = 0;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (may_be_aliased (var))
- num_addressable_vars++;
-
- if (POINTER_TYPE_P (TREE_TYPE (var)))
- {
- /* Since we don't keep track of volatile variables, assume that
- these pointers are used in indirect store operations. */
- if (TREE_THIS_VOLATILE (var))
- pointer_set_insert (ai->dereferenced_ptrs_store, var);
-
- num_pointers++;
- }
- }
-
- /* Create ADDRESSABLE_VARS and POINTERS. Note that these arrays are
- always going to be slightly bigger than we actually need them
- because some TREE_ADDRESSABLE variables will be marked
- non-addressable below and only pointers with unique symbol tags are
- going to be added to POINTERS. */
- ai->addressable_vars = XCNEWVEC (struct alias_map_d *, num_addressable_vars);
- ai->pointers = XCNEWVEC (struct alias_map_d *, num_pointers);
- ai->num_addressable_vars = 0;
- ai->num_pointers = 0;
-
- FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, srvi)
- {
- /* Name memory tags already have flow-sensitive aliasing
- information, so they need not be processed by
- compute_flow_insensitive_aliasing. Similarly, symbol memory
- tags are already accounted for when we process their
- associated pointer.
-
- Structure fields, on the other hand, have to have some of this
- information processed for them, but it's pointless to mark them
- non-addressable (since they are fake variables anyway). */
- if (MTAG_P (var))
- continue;
-
- /* Remove the ADDRESSABLE flag from every addressable variable whose
- address is not needed anymore. This is caused by the propagation
- of ADDR_EXPR constants into INDIRECT_REF expressions and the
- removal of dead pointer assignments done by the early scalar
- cleanup passes. */
- if (TREE_ADDRESSABLE (var))
- {
- if (!bitmap_bit_p (gimple_addressable_vars (cfun), DECL_UID (var))
- && TREE_CODE (var) != RESULT_DECL
- && !is_global_var (var))
- {
- bool okay_to_mark = true;
-
- /* Since VAR is now a regular GIMPLE register, we will need
- to rename VAR into SSA afterwards. */
- mark_sym_for_renaming (var);
-
- /* The address of VAR is not needed, remove the
- addressable bit, so that it can be optimized as a
- regular variable. */
- if (okay_to_mark)
- {
- /* The memory partition holding VAR will no longer
- contain VAR, and statements referencing it will need
- to be updated. */
- if (memory_partition (var))
- mark_sym_for_renaming (memory_partition (var));
-
- mark_non_addressable (var);
- }
- }
- }
-
- /* Global variables and addressable locals may be aliased. Create an
- entry in ADDRESSABLE_VARS for VAR. */
- if (may_be_aliased (var))
- {
- create_alias_map_for (var, ai);
- mark_sym_for_renaming (var);
- }
-
- /* Add pointer variables that have been dereferenced to the POINTERS
- array and create a symbol memory tag for them. */
- if (POINTER_TYPE_P (TREE_TYPE (var)))
- {
- if ((pointer_set_contains (ai->dereferenced_ptrs_store, var)
- || pointer_set_contains (ai->dereferenced_ptrs_load, var)))
- {
- tree tag, old_tag;
- var_ann_t t_ann;
-
- /* If pointer VAR still doesn't have a memory tag
- associated with it, create it now or re-use an
- existing one. */
- tag = get_smt_for (var, ai);
- t_ann = var_ann (tag);
-
- /* The symbol tag will need to be renamed into SSA
- afterwards. Note that we cannot do this inside
- get_smt_for because aliasing may run multiple times
- and we only create symbol tags the first time. */
- mark_sym_for_renaming (tag);
-
- /* Similarly, if pointer VAR used to have another type
- tag, we will need to process it in the renamer to
- remove the stale virtual operands. */
- old_tag = symbol_mem_tag (var);
- if (old_tag)
- mark_sym_for_renaming (old_tag);
-
- /* Associate the tag with pointer VAR. */
- set_symbol_mem_tag (var, tag);
-
- /* If pointer VAR has been used in a store operation,
- then its memory tag must be marked as written-to. */
- if (pointer_set_contains (ai->dereferenced_ptrs_store, var))
- pointer_set_insert (ai->written_vars, tag);
- }
- else
- {
- /* The pointer has not been dereferenced. If it had a
- symbol memory tag, remove it and mark the old tag for
- renaming to remove it out of the IL. */
- tree tag = symbol_mem_tag (var);
- if (tag)
- {
- mark_sym_for_renaming (tag);
- set_symbol_mem_tag (var, NULL_TREE);
- }
- }
- }
- }
-
- VEC_free (tree, heap, varvec);
-}
-
-
-/* Determine whether to use .GLOBAL_VAR to model call clobbering
- semantics. If the function makes no references to global
- variables and contains at least one call to a non-pure function,
- then we need to mark the side-effects of the call using .GLOBAL_VAR
- to represent all possible global memory referenced by the callee. */
-
-static void
-maybe_create_global_var (void)
-{
- /* No need to create it, if we have one already. */
- if (gimple_global_var (cfun) == NULL_TREE)
- {
- struct mem_ref_stats_d *stats = gimple_mem_ref_stats (cfun);
-
- /* Create .GLOBAL_VAR if there are no call-clobbered
- variables and the program contains a mixture of pure/const
- and regular function calls. This is to avoid the problem
- described in PR 20115:
-
- int X;
- int func_pure (void) { return X; }
- int func_non_pure (int a) { X += a; }
- int foo ()
- {
- int a = func_pure ();
- func_non_pure (a);
- a = func_pure ();
- return a;
- }
-
- Since foo() has no call-clobbered variables, there is
- no relationship between the calls to func_pure and
- func_non_pure. Since func_pure has no side-effects, value
- numbering optimizations elide the second call to func_pure.
- So, if we have some pure/const and some regular calls in the
- program we create .GLOBAL_VAR to avoid missing these
- relations. */
- if (bitmap_empty_p (gimple_call_clobbered_vars (cfun))
- && stats->num_call_sites > 0
- && stats->num_pure_const_call_sites > 0
- && stats->num_call_sites > stats->num_pure_const_call_sites)
- create_global_var ();
- }
-}
-
-
-/* Return TRUE if pointer PTR may point to variable VAR.
-
- MEM_ALIAS_SET is the alias set for the memory location pointed-to by PTR
- This is needed because when checking for type conflicts we are
- interested in the alias set of the memory location pointed-to by
- PTR. The alias set of PTR itself is irrelevant.
-
- VAR_ALIAS_SET is the alias set for VAR. */
-
-static bool
-may_alias_p (tree ptr, alias_set_type mem_alias_set,
- tree var, alias_set_type var_alias_set,
- bool alias_set_only)
-{
- tree mem;
-
- alias_stats.alias_queries++;
- alias_stats.simple_queries++;
-
- /* By convention, a variable cannot alias itself. */
- mem = symbol_mem_tag (ptr);
- if (mem == var)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If -fargument-noalias-global is > 2, pointer arguments may
- not point to anything else. */
- if (flag_argument_noalias > 2 && TREE_CODE (ptr) == PARM_DECL)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If -fargument-noalias-global is > 1, pointer arguments may
- not point to global variables. */
- if (flag_argument_noalias > 1 && is_global_var (var)
- && TREE_CODE (ptr) == PARM_DECL)
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If either MEM or VAR is a read-only global and the other one
- isn't, then PTR cannot point to VAR. */
- if ((unmodifiable_var_p (mem) && !unmodifiable_var_p (var))
- || (unmodifiable_var_p (var) && !unmodifiable_var_p (mem)))
- {
- alias_stats.alias_noalias++;
- alias_stats.simple_resolved++;
- return false;
- }
-
- /* If the pointed to memory has alias set zero, or the pointer
- is ref-all, or the pointer decl is marked that no TBAA is to
- be applied, the MEM can alias VAR. */
- if (mem_alias_set == 0
- || DECL_POINTER_ALIAS_SET (ptr) == 0
- || TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))
- || DECL_NO_TBAA_P (ptr))
- {
- alias_stats.alias_mayalias++;
- alias_stats.simple_resolved++;
- return true;
- }
-
- gcc_assert (TREE_CODE (mem) == SYMBOL_MEMORY_TAG);
-
- alias_stats.tbaa_queries++;
-
- /* If the alias sets don't conflict then MEM cannot alias VAR. */
- if (mem_alias_set != var_alias_set
- && !alias_set_subset_of (mem_alias_set, var_alias_set))
- {
- alias_stats.alias_noalias++;
- alias_stats.tbaa_resolved++;
- return false;
- }
-
- /* If VAR is a record or union type, PTR cannot point into VAR
- unless there is some explicit address operation in the
- program that can reference a field of the type pointed-to by
- PTR. This also assumes that the types of both VAR and PTR
- are contained within the compilation unit, and that there is
- no fancy addressing arithmetic associated with any of the
- types involved. */
- if (mem_alias_set != 0 && var_alias_set != 0)
- {
- tree ptr_type = TREE_TYPE (ptr);
- tree var_type = TREE_TYPE (var);
-
- /* The star count is -1 if the type at the end of the
- pointer_to chain is not a record or union type. */
- if (!alias_set_only
- && ipa_type_escape_star_count_of_interesting_type (var_type) >= 0)
- {
- int ptr_star_count = 0;
-
- /* ipa_type_escape_star_count_of_interesting_type is a
- little too restrictive for the pointer type, need to
- allow pointers to primitive types as long as those
- types cannot be pointers to everything. */
- while (POINTER_TYPE_P (ptr_type))
- {
- /* Strip the *s off. */
- ptr_type = TREE_TYPE (ptr_type);
- ptr_star_count++;
- }
-
- /* There does not appear to be a better test to see if
- the pointer type was one of the pointer to everything
- types. */
- if (ptr_star_count > 0)
- {
- alias_stats.structnoaddress_queries++;
- if (ipa_type_escape_field_does_not_clobber_p (var_type,
- TREE_TYPE (ptr)))
- {
- alias_stats.structnoaddress_resolved++;
- alias_stats.alias_noalias++;
- return false;
- }
- }
- else if (ptr_star_count == 0)
- {
- /* If PTR_TYPE was not really a pointer to type, it cannot
- alias. */
- alias_stats.structnoaddress_queries++;
- alias_stats.structnoaddress_resolved++;
- alias_stats.alias_noalias++;
- return false;
- }
- }
- }
-
- alias_stats.alias_mayalias++;
- return true;
-}
-
-
-/* Add ALIAS to the set of variables that may alias VAR. */
-
-static void
-add_may_alias (tree var, tree alias)
-{
- /* Don't allow self-referential aliases. */
- gcc_assert (var != alias);
-
- /* ALIAS must be addressable if it's being added to an alias set. */
-#if 1
- TREE_ADDRESSABLE (alias) = 1;
-#else
- gcc_assert (may_be_aliased (alias));
-#endif
-
- /* VAR must be a symbol or a name tag. */
- gcc_assert (TREE_CODE (var) == SYMBOL_MEMORY_TAG
- || TREE_CODE (var) == NAME_MEMORY_TAG);
-
- if (MTAG_ALIASES (var) == NULL)
- MTAG_ALIASES (var) = BITMAP_ALLOC (&alias_bitmap_obstack);
-
- bitmap_set_bit (MTAG_ALIASES (var), DECL_UID (alias));
-}
-
-
-/* Mark pointer PTR as pointing to an arbitrary memory location. */
-
-static void
-set_pt_anything (tree ptr)
-{
- struct ptr_info_def *pi = get_ptr_info (ptr);
-
- pi->pt_anything = 1;
- pi->pt_vars = NULL;
-
- /* The pointer used to have a name tag, but we now found it pointing
- to an arbitrary location. The name tag needs to be renamed and
- disassociated from PTR. */
- if (pi->name_mem_tag)
- {
- mark_sym_for_renaming (pi->name_mem_tag);
- pi->name_mem_tag = NULL_TREE;
- }
-}
-
-
-/* Return true if STMT is an "escape" site from the current function. Escape
- sites those statements which might expose the address of a variable
- outside the current function. STMT is an escape site iff:
-
- 1- STMT is a function call, or
- 2- STMT is an __asm__ expression, or
- 3- STMT is an assignment to a non-local variable, or
- 4- STMT is a return statement.
-
- Return the type of escape site found, if we found one, or NO_ESCAPE
- if none. */
-
-enum escape_type
-is_escape_site (tree stmt)
-{
- tree call = get_call_expr_in (stmt);
- if (call != NULL_TREE)
- {
- if (!TREE_SIDE_EFFECTS (call))
- return ESCAPE_TO_PURE_CONST;
-
- return ESCAPE_TO_CALL;
- }
- else if (TREE_CODE (stmt) == ASM_EXPR)
- return ESCAPE_TO_ASM;
- else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
- {
- tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-
- /* Get to the base of _REF nodes. */
- if (TREE_CODE (lhs) != SSA_NAME)
- lhs = get_base_address (lhs);
-
- /* If we couldn't recognize the LHS of the assignment, assume that it
- is a non-local store. */
- if (lhs == NULL_TREE)
- return ESCAPE_UNKNOWN;
-
- if (CONVERT_EXPR_P (GIMPLE_STMT_OPERAND (stmt, 1))
- || TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == VIEW_CONVERT_EXPR)
- {
- tree from
- = TREE_TYPE (TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0));
- tree to = TREE_TYPE (GIMPLE_STMT_OPERAND (stmt, 1));
-
- /* If the RHS is a conversion between a pointer and an integer, the
- pointer escapes since we can't track the integer. */
- if (POINTER_TYPE_P (from) && !POINTER_TYPE_P (to))
- return ESCAPE_BAD_CAST;
- }
-
- /* If the LHS is an SSA name, it can't possibly represent a non-local
- memory store. */
- if (TREE_CODE (lhs) == SSA_NAME)
- return NO_ESCAPE;
-
- /* FIXME: LHS is not an SSA_NAME. Even if it's an assignment to a
- local variables we cannot be sure if it will escape, because we
- don't have information about objects not in SSA form. Need to
- implement something along the lines of
-
- J.-D. Choi, M. Gupta, M. J. Serrano, V. C. Sreedhar, and S. P.
- Midkiff, ``Escape analysis for java,'' in Proceedings of the
- Conference on Object-Oriented Programming Systems, Languages, and
- Applications (OOPSLA), pp. 1-19, 1999. */
- return ESCAPE_STORED_IN_GLOBAL;
- }
- else if (TREE_CODE (stmt) == RETURN_EXPR)
- return ESCAPE_TO_RETURN;
-
- return NO_ESCAPE;
-}
-
-/* Create a new memory tag of type TYPE.
- Does NOT push it into the current binding. */
-
-tree
-create_tag_raw (enum tree_code code, tree type, const char *prefix)
-{
- tree tmp_var;
-
- tmp_var = build_decl (code, create_tmp_var_name (prefix), type);
-
- /* Make the variable writable. */
- TREE_READONLY (tmp_var) = 0;
-
- /* It doesn't start out global. */
- MTAG_GLOBAL (tmp_var) = 0;
- TREE_STATIC (tmp_var) = 0;
- TREE_USED (tmp_var) = 1;
-
- return tmp_var;
-}
-
-/* Create a new memory tag of type TYPE. If IS_TYPE_TAG is true, the tag
- is considered to represent all the pointers whose pointed-to types are
- in the same alias set class. Otherwise, the tag represents a single
- SSA_NAME pointer variable. */
-
-static tree
-create_memory_tag (tree type, bool is_type_tag)
-{
- tree tag = create_tag_raw (is_type_tag ? SYMBOL_MEMORY_TAG : NAME_MEMORY_TAG,
- type, (is_type_tag) ? "SMT" : "NMT");
-
- /* By default, memory tags are local variables. Alias analysis will
- determine whether they should be considered globals. */
- DECL_CONTEXT (tag) = current_function_decl;
-
- /* Memory tags are by definition addressable. */
- TREE_ADDRESSABLE (tag) = 1;
-
- set_symbol_mem_tag (tag, NULL_TREE);
-
- /* Add the tag to the symbol table. */
- add_referenced_var (tag);
-
- return tag;
-}
-
-
-/* Create a name memory tag to represent a specific SSA_NAME pointer P_i.
- This is used if P_i has been found to point to a specific set of
- variables or to a non-aliased memory location like the address returned
- by malloc functions. */
-
-static tree
-get_nmt_for (tree ptr)
-{
- struct ptr_info_def *pi = get_ptr_info (ptr);
- tree tag = pi->name_mem_tag;
-
- if (tag == NULL_TREE)
- tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
- return tag;
-}
-
-
-/* Return the symbol memory tag associated to pointer PTR. A memory
- tag is an artificial variable that represents the memory location
- pointed-to by PTR. It is used to model the effects of pointer
- de-references on addressable variables.
-
- AI points to the data gathered during alias analysis. This
- function populates the array AI->POINTERS. */
-
-static tree
-get_smt_for (tree ptr, struct alias_info *ai)
-{
- size_t i;
- tree tag;
- tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
- alias_set_type tag_set = get_alias_set (tag_type);
-
- /* To avoid creating unnecessary memory tags, only create one memory tag
- per alias set class. Note that it may be tempting to group
- memory tags based on conflicting alias sets instead of
- equivalence. That would be wrong because alias sets are not
- necessarily transitive (as demonstrated by the libstdc++ test
- 23_containers/vector/cons/4.cc). Given three alias sets A, B, C
- such that conflicts (A, B) == true and conflicts (A, C) == true,
- it does not necessarily follow that conflicts (B, C) == true. */
- for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++)
- {
- struct alias_map_d *curr = ai->pointers[i];
- tree curr_tag = symbol_mem_tag (curr->var);
- if (tag_set == curr->set)
- {
- tag = curr_tag;
- break;
- }
- }
-
- /* If VAR cannot alias with any of the existing memory tags, create a new
- tag for PTR and add it to the POINTERS array. */
- if (tag == NULL_TREE)
- {
- struct alias_map_d *alias_map;
-
- /* If PTR did not have a symbol tag already, create a new SMT.*
- artificial variable representing the memory location
- pointed-to by PTR. */
- tag = symbol_mem_tag (ptr);
- if (tag == NULL_TREE)
- tag = create_memory_tag (tag_type, true);
-
- /* Add PTR to the POINTERS array. Note that we are not interested in
- PTR's alias set. Instead, we cache the alias set for the memory that
- PTR points to. */
- alias_map = XCNEW (struct alias_map_d);
- alias_map->var = ptr;
- alias_map->set = tag_set;
- ai->pointers[ai->num_pointers++] = alias_map;
- }
-
- /* If the pointed-to type is volatile, so is the tag. */
- TREE_THIS_VOLATILE (tag) |= TREE_THIS_VOLATILE (tag_type);
-
- /* Make sure that the symbol tag has the same alias set as the
- pointed-to type or at least accesses through the pointer will
- alias that set. The latter can happen after the vectorizer
- created pointers of vector type. */
- gcc_assert (tag_set == get_alias_set (tag)
- || alias_set_subset_of (tag_set, get_alias_set (tag)));
-
- return tag;
-}
-
-
-/* Create GLOBAL_VAR, an artificial global variable to act as a
- representative of all the variables that may be clobbered by function
- calls. */
-
-static void
-create_global_var (void)
-{
- tree global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"),
- void_type_node);
- DECL_ARTIFICIAL (global_var) = 1;
- TREE_READONLY (global_var) = 0;
- DECL_EXTERNAL (global_var) = 1;
- TREE_STATIC (global_var) = 1;
- TREE_USED (global_var) = 1;
- DECL_CONTEXT (global_var) = NULL_TREE;
- TREE_THIS_VOLATILE (global_var) = 0;
- TREE_ADDRESSABLE (global_var) = 0;
-
- create_var_ann (global_var);
- mark_call_clobbered (global_var, ESCAPE_UNKNOWN);
- add_referenced_var (global_var);
- mark_sym_for_renaming (global_var);
- cfun->gimple_df->global_var = global_var;
-}
-
-
-/* Dump alias statistics on FILE. */
-
-static void
-dump_alias_stats (FILE *file)
-{
- const char *funcname
- = lang_hooks.decl_printable_name (current_function_decl, 2);
- fprintf (file, "\nAlias statistics for %s\n\n", funcname);
- fprintf (file, "Total alias queries:\t%u\n", alias_stats.alias_queries);
- fprintf (file, "Total alias mayalias results:\t%u\n",
- alias_stats.alias_mayalias);
- fprintf (file, "Total alias noalias results:\t%u\n",
- alias_stats.alias_noalias);
- fprintf (file, "Total simple queries:\t%u\n",
- alias_stats.simple_queries);
- fprintf (file, "Total simple resolved:\t%u\n",
- alias_stats.simple_resolved);
- fprintf (file, "Total TBAA queries:\t%u\n",
- alias_stats.tbaa_queries);
- fprintf (file, "Total TBAA resolved:\t%u\n",
- alias_stats.tbaa_resolved);
- fprintf (file, "Total non-addressable structure type queries:\t%u\n",
- alias_stats.structnoaddress_queries);
- fprintf (file, "Total non-addressable structure type resolved:\t%u\n",
- alias_stats.structnoaddress_resolved);
-}
-
-
-/* Dump alias information on FILE. */
-
-void
-dump_alias_info (FILE *file)
-{
- size_t i;
- const char *funcname
- = lang_hooks.decl_printable_name (current_function_decl, 2);
- referenced_var_iterator rvi;
- tree var;
-
- fprintf (file, "\nAlias information for %s\n\n", funcname);
-
- dump_memory_partitions (file);
-
- fprintf (file, "\nFlow-insensitive alias information for %s\n\n", funcname);
-
- fprintf (file, "Aliased symbols\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (may_be_aliased (var))
- dump_variable (file, var);
- }
-
- fprintf (file, "\nDereferenced pointers\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- if (symbol_mem_tag (var))
- dump_variable (file, var);
-
- fprintf (file, "\nSymbol memory tags\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_CODE (var) == SYMBOL_MEMORY_TAG)
- dump_variable (file, var);
- }
-
- fprintf (file, "\n\nFlow-sensitive alias information for %s\n\n", funcname);
-
- fprintf (file, "SSA_NAME pointers\n\n");
- for (i = 1; i < num_ssa_names; i++)
- {
- tree ptr = ssa_name (i);
- struct ptr_info_def *pi;
-
- if (ptr == NULL_TREE)
- continue;
-
- pi = SSA_NAME_PTR_INFO (ptr);
- if (!SSA_NAME_IN_FREE_LIST (ptr)
- && pi
- && pi->name_mem_tag)
- dump_points_to_info_for (file, ptr);
- }
-
- fprintf (file, "\nName memory tags\n\n");
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (TREE_CODE (var) == NAME_MEMORY_TAG)
- dump_variable (file, var);
- }
-
- fprintf (file, "\n");
-}
-
-
-/* Dump alias information on stderr. */
-
-void
-debug_alias_info (void)
-{
- dump_alias_info (stderr);
-}
-
-
-/* Return the alias information associated with pointer T. It creates a
- new instance if none existed. */
-
-struct ptr_info_def *
-get_ptr_info (tree t)
-{
- struct ptr_info_def *pi;
-
- gcc_assert (POINTER_TYPE_P (TREE_TYPE (t)));
-
- pi = SSA_NAME_PTR_INFO (t);
- if (pi == NULL)
- {
- pi = GGC_CNEW (struct ptr_info_def);
- SSA_NAME_PTR_INFO (t) = pi;
- }
-
- return pi;
-}
-
-
-/* Dump points-to information for SSA_NAME PTR into FILE. */
-
-void
-dump_points_to_info_for (FILE *file, tree ptr)
-{
- struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
-
- print_generic_expr (file, ptr, dump_flags);
-
- if (pi)
- {
- if (pi->name_mem_tag)
- {
- fprintf (file, ", name memory tag: ");
- print_generic_expr (file, pi->name_mem_tag, dump_flags);
- }
-
- if (pi->is_dereferenced)
- fprintf (file, ", is dereferenced");
-
- if (pi->value_escapes_p)
- fprintf (file, ", its value escapes");
-
- if (pi->pt_anything)
- fprintf (file, ", points-to anything");
-
- if (pi->pt_null)
- fprintf (file, ", points-to NULL");
-
- if (pi->pt_vars)
- {
- fprintf (file, ", points-to vars: ");
- dump_decl_set (file, pi->pt_vars);
- }
- }
-
- fprintf (file, "\n");
-}
-
-
-/* Dump points-to information for VAR into stderr. */
-
-void
-debug_points_to_info_for (tree var)
-{
- dump_points_to_info_for (stderr, var);
-}
-
-
-/* Dump points-to information into FILE. NOTE: This function is slow, as
- it needs to traverse the whole CFG looking for pointer SSA_NAMEs. */
-
-void
-dump_points_to_info (FILE *file)
-{
- basic_block bb;
- block_stmt_iterator si;
- ssa_op_iter iter;
- const char *fname =
- lang_hooks.decl_printable_name (current_function_decl, 2);
- referenced_var_iterator rvi;
- tree var;
-
- fprintf (file, "\n\nPointed-to sets for pointers in %s\n\n", fname);
-
- /* First dump points-to information for the default definitions of
- pointer variables. This is necessary because default definitions are
- not part of the code. */
- FOR_EACH_REFERENCED_VAR (var, rvi)
- {
- if (POINTER_TYPE_P (TREE_TYPE (var)))
- {
- tree def = gimple_default_def (cfun, var);
- if (def)
- dump_points_to_info_for (file, def);
- }
- }
-
- /* Dump points-to information for every pointer defined in the program. */
- FOR_EACH_BB (bb)
- {
- tree phi;
-
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- tree ptr = PHI_RESULT (phi);
- if (POINTER_TYPE_P (TREE_TYPE (ptr)))
- dump_points_to_info_for (file, ptr);
- }
-
- for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- {
- tree stmt = bsi_stmt (si);
- tree def;
- FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
- if (TREE_CODE (def) == SSA_NAME
- && POINTER_TYPE_P (TREE_TYPE (def)))
- dump_points_to_info_for (file, def);
- }
- }
-
- fprintf (file, "\n");
-}
-
-
-/* Dump points-to info pointed to by PTO into STDERR. */
-
-void
-debug_points_to_info (void)
-{
- dump_points_to_info (stderr);
-}
-
-/* Dump to FILE the list of variables that may be aliasing VAR. */
-
-void
-dump_may_aliases_for (FILE *file, tree var)
-{
- bitmap aliases;
-
- aliases = MTAG_ALIASES (var);
- if (aliases)
- {
- bitmap_iterator bi;
- unsigned int i;
- tree al;
-
- fprintf (file, "{ ");
- EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
- {
- al = referenced_var (i);
- print_generic_expr (file, al, dump_flags);
- fprintf (file, " ");
- }
- fprintf (file, "}");
- }
-}
-
-
-/* Dump to stderr the list of variables that may be aliasing VAR. */
-
-void
-debug_may_aliases_for (tree var)
-{
- dump_may_aliases_for (stderr, var);
-}
-
-
-/* Return true if VAR may be aliased. */
-
-bool
-may_be_aliased (tree var)
-{
- /* Obviously. */
- if (TREE_ADDRESSABLE (var))
- return true;
-
- /* Globally visible variables can have their addresses taken by other
- translation units. */
- if (MTAG_P (var)
- && (MTAG_GLOBAL (var) || TREE_PUBLIC (var)))
- return true;
- else if (!MTAG_P (var)
- && (DECL_EXTERNAL (var) || TREE_PUBLIC (var)))
- return true;
-
- /* Automatic variables can't have their addresses escape any other
- way. This must be after the check for global variables, as
- extern declarations do not have TREE_STATIC set. */
- if (!TREE_STATIC (var))
- return false;
-
- /* If we're in unit-at-a-time mode, then we must have seen all
- occurrences of address-of operators, and so we can trust
- TREE_ADDRESSABLE. Otherwise we can only be sure the variable
- isn't addressable if it's local to the current function. */
- if (flag_unit_at_a_time)
- return false;
-
- if (decl_function_context (var) == current_function_decl)
- return false;
-
- return true;
-}
-
-/* The following is based on code in add_stmt_operand to ensure that the
- same defs/uses/vdefs/vuses will be found after replacing a reference
- to var (or ARRAY_REF to var) with an INDIRECT_REF to ptr whose value
- is the address of var. Return a memtag for the ptr, after adding the
- proper may_aliases to it (which are the aliases of var, if it has any,
- or var itself). */
-
-static tree
-add_may_alias_for_new_tag (tree tag, tree var)
-{
- bitmap aliases = NULL;
-
- if (MTAG_P (var))
- aliases = may_aliases (var);
-
- /* Case 1: |aliases| == 1 */
- if (aliases
- && bitmap_single_bit_set_p (aliases))
- {
- tree ali = referenced_var (bitmap_first_set_bit (aliases));
- if (TREE_CODE (ali) == SYMBOL_MEMORY_TAG)
- return ali;
- }
-
- /* Case 2: |aliases| == 0 */
- if (aliases == NULL)
- add_may_alias (tag, var);
- else
- {
- /* Case 3: |aliases| > 1 */
- union_alias_set_into (tag, aliases);
- }
- return tag;
-}
-
-/* Create a new symbol tag for PTR. Construct the may-alias list of
- this type tag so that it has the aliasing of VAR according to the
- location accessed by EXPR.
-
- Note, the set of aliases represented by the new symbol tag are not
- marked for renaming. */
-
-void
-new_type_alias (tree ptr, tree var, tree expr)
-{
- tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
- tree tag;
- tree ali = NULL_TREE;
- HOST_WIDE_INT offset, size, maxsize;
- tree ref;
-
- gcc_assert (symbol_mem_tag (ptr) == NULL_TREE);
- gcc_assert (!MTAG_P (var));
-
- ref = get_ref_base_and_extent (expr, &offset, &size, &maxsize);
- gcc_assert (ref);
-
- tag = create_memory_tag (tag_type, true);
- set_symbol_mem_tag (ptr, tag);
-
- ali = add_may_alias_for_new_tag (tag, var);
-
- set_symbol_mem_tag (ptr, ali);
- MTAG_GLOBAL (tag) = is_global_var (var);
-}
-
-
-/* Reset the call_clobbered flags on our referenced vars. In
- theory, this only needs to be done for globals. */
-
-static unsigned int
-reset_cc_flags (void)
-{
- tree var;
- referenced_var_iterator rvi;
-
- FOR_EACH_REFERENCED_VAR (var, rvi)
- var_ann (var)->call_clobbered = false;
- return 0;
-}
-
-struct gimple_opt_pass pass_reset_cc_flags =
-{
- {
- GIMPLE_PASS,
- NULL, /* name */
- NULL, /* gate */
- reset_cc_flags, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_referenced_vars |PROP_cfg, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
-
-
-/* A dummy pass to cause aliases to be computed via TODO_rebuild_alias. */
-
-struct gimple_opt_pass pass_build_alias =
-{
- {
- GIMPLE_PASS,
- "alias", /* name */
- NULL, /* gate */
- NULL, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
- PROP_alias, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_rebuild_alias | TODO_dump_func /* todo_flags_finish */
- }
-};