+2008-05-08 Richard Guenther <rguenther@suse.de>
+
+ * tree-data-ref.c (dr_analyze_alias): Do not set DR_SUBVARS.
+ * tree-data-ref.h (struct dr_alias): Remove subvars field.
+ (DR_SUBVARS): Remove.
+ * tree-dfa.c (dump_subvars_for): Remove.
+ (debug_subvars_for): Likewise.
+ (dump_variable): Do not dump subvars.
+ (remove_referenced_var): Do not remove subvars.
+ * tree-flow-inline.h (clear_call_clobbered): SFTs no longer exist.
+ (lookup_subvars_for_var): Remove.
+ (get_subvars_for_var): Likewise.
+ (get_subvars_at): Likewise.
+ (get_first_overlapping_subvar): Likewise.
+ (overlap_subvar): Likewise.
+ * tree-flow.h (subvar_t): Remove.
+ (struct var_ann_d): Remove subvars field.
+ * tree-ssa-alias.c (mark_aliases_call_clobbered): Remove queued
+ argument. Remove special handling of SFTs.
+ (compute_tag_properties): Likewise.
+ (set_initial_properties): Likewise.
+ (compute_call_clobbered): Likewise.
+ (count_mem_refs): Likewise.
+ (compute_memory_partitions): Likewise.
+ (compute_flow_insensitive_aliasing): Likewise.
+ (setup_pointers_and_addressables): Likewise.
+ (new_type_alias): Likewise.
+ (struct used_part): Remove.
+ (used_portions): Likewise.
+ (struct used_part_map): Likewise.
+ (used_part_map_eq): Likewise.
+ (used_part_map_hash): Likewise.
+ (free_used_part_map): Likewise.
+ (up_lookup): Likewise.
+ (up_insert): Likewise.
+ (get_or_create_used_part_for): Likewise.
+ (create_sft): Likewise.
+ (create_overlap_variables_for): Likewise.
+ (find_used_portions): Likewise.
+ (create_structure_vars): Likewise.
+ * tree.def (STRUCT_FIELD_TAG): Remove.
+ * tree.h (MTAG_P): Adjust.
+ (struct tree_memory_tag): Remove base_for_components and
+ unpartitionable flags.
+ (struct tree_struct_field_tag): Remove.
+ (SFT_PARENT_VAR): Likewise.
+ (SFT_OFFSET): Likewise.
+ (SFT_SIZE): Likewise.
+ (SFT_NONADDRESSABLE_P): Likewise.
+ (SFT_ALIAS_SET): Likewise.
+ (SFT_UNPARTITIONABLE_P): Likewise.
+ (SFT_BASE_FOR_COMPONENTS_P): Likewise.
+ (union tree_node): Remove sft field.
+ * alias.c (get_alias_set): Remove special handling of SFTs.
+ * print-tree.c (print_node): Remove handling of SFTs.
+ * tree-dump.c (dequeue_and_dump): Likewise.
+ * tree-into-ssa.c (mark_sym_for_renaming): Likewise.
+ * tree-nrv.c (dest_safe_for_nrv_p): Remove special handling of SFTs.
+ * tree-predcom.c (set_alias_info): Do not set subvars.
+ * tree-pretty-print.c (dump_generic_node): Do not handle SFTs.
+ * tree-ssa-loop-ivopts.c (get_ref_tag): Likewise.
+ * tree-ssa-operands.c (access_can_touch_variable): Likewise.
+ (add_vars_for_offset): Remove.
+ (add_virtual_operand): Remove special handling of SFTs.
+ (add_call_clobber_ops): Likewise.
+ (add_call_read_ops): Likewise.
+ (get_asm_expr_operands): Likewise.
+ (get_modify_stmt_operands): Likewise.
+ (get_expr_operands): Likewise.
+ (add_to_addressable_set): Likewise.
+ * tree-ssa.c (verify_ssa_name): Do not handle SFTs.
+ * tree-tailcall.c (suitable_for_tail_opt_p): Likewise.
+ * tree-vect-transform.c (vect_create_data_ref_ptr): Do not
+ set subvars.
+ * tree.c (init_ttree): Remove STRUCT_FIELD_TAG initialization.
+ (tree_code_size): Remove STRUCT_FIELD_TAG handling.
+ (tree_node_structure): Likewise.
+ * tree-ssa-structalias.c (set_uids_in_ptset): Remove special
+ handling of SFTs.
+ (find_what_p_points_to): Likewise.
+
2008-05-08 Sa Liu <saliu@de.ibm.com>
* config/spu/spu.md: Fixed subti3 pattern.
return 0;
}
- /* For non-addressable fields we return the alias set of the
- outermost object that could have its address taken. If this
- is an SFT use the precomputed value. */
- if (TREE_CODE (t) == STRUCT_FIELD_TAG
- && SFT_NONADDRESSABLE_P (t))
- return SFT_ALIAS_SET (t);
-
/* Otherwise, pick up the outermost object that we could have a pointer
to, processing conversions as above. */
while (component_uses_parent_alias_set (t))
&& DECL_HAS_VALUE_EXPR_P (node))
print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4);
- if (TREE_CODE (node) == STRUCT_FIELD_TAG)
- {
- fprintf (file, " sft size " HOST_WIDE_INT_PRINT_DEC,
- SFT_SIZE (node));
- fprintf (file, " sft offset " HOST_WIDE_INT_PRINT_DEC,
- SFT_OFFSET (node));
- print_node_brief (file, "parent var", SFT_PARENT_VAR (node),
- indent + 4);
- }
/* Print the decl chain only if decl is at second level. */
if (indent == 4)
print_node (file, "chain", TREE_CHAIN (node), indent + 4);
}
DR_SYMBOL_TAG (dr) = smt;
- if (smt && var_can_have_subvars (smt))
- DR_SUBVARS (dr) = get_subvars_for_var (smt);
vops = BITMAP_ALLOC (NULL);
FOR_EACH_SSA_TREE_OPERAND (op, stmt, it, SSA_OP_VIRTUAL_USES)
/* The alias information that should be used for new pointers to this
location. SYMBOL_TAG is either a DECL or a SYMBOL_MEMORY_TAG. */
tree symbol_tag;
- subvar_t subvars;
struct ptr_info_def *ptr_info;
/* The set of virtual operands corresponding to this memory reference,
#define DR_STEP(DR) (DR)->innermost.step
#define DR_SYMBOL_TAG(DR) (DR)->alias.symbol_tag
#define DR_PTR_INFO(DR) (DR)->alias.ptr_info
-#define DR_SUBVARS(DR) (DR)->alias.subvars
#define DR_VOPS(DR) (DR)->alias.vops
#define DR_ALIGNED_TO(DR) (DR)->innermost.aligned_to
}
-/* Dump sub-variables for VAR to FILE. */
-
-void
-dump_subvars_for (FILE *file, tree var)
-{
- subvar_t sv = get_subvars_for_var (var);
- tree subvar;
- unsigned int i;
-
- if (!sv)
- return;
-
- fprintf (file, "{ ");
-
- for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
- {
- print_generic_expr (file, subvar, dump_flags);
- fprintf (file, "@" HOST_WIDE_INT_PRINT_UNSIGNED, SFT_OFFSET (subvar));
- if (SFT_BASE_FOR_COMPONENTS_P (subvar))
- fprintf (file, "[B]");
- fprintf (file, " ");
- }
-
- fprintf (file, "}");
-}
-
-
-/* Dumb sub-variables for VAR to stderr. */
-
-void
-debug_subvars_for (tree var)
-{
- dump_subvars_for (stderr, var);
-}
-
-
/* Dump variable VAR and its may-aliases to FILE. */
void
dump_may_aliases_for (file, var);
}
- if (get_subvars_for_var (var))
- {
- fprintf (file, ", sub-vars: ");
- dump_subvars_for (file, var);
- }
-
if (!is_gimple_reg (var))
{
if (memory_partition (var))
fprintf (file, ", partition symbols: ");
dump_decl_set (file, MPT_SYMBOLS (var));
}
-
- if (TREE_CODE (var) == STRUCT_FIELD_TAG)
- {
- fprintf (file, ", offset: " HOST_WIDE_INT_PRINT_UNSIGNED,
- SFT_OFFSET (var));
- fprintf (file, ", base for components: %s",
- SFT_BASE_FOR_COMPONENTS_P (var) ? "NO" : "YES");
- fprintf (file, ", partitionable: %s",
- SFT_UNPARTITIONABLE_P (var) ? "NO" : "YES");
- }
}
fprintf (file, "\n");
struct tree_decl_minimal in;
void **loc;
unsigned int uid = DECL_UID (var);
- subvar_t sv;
-
- /* If we remove a var, we should also remove its subvars, as we kill
- their parent var and its annotation. */
- if (var_can_have_subvars (var)
- && (sv = get_subvars_for_var (var)))
- {
- unsigned int i;
- tree subvar;
- for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
- remove_referenced_var (subvar);
- }
clear_call_clobbered (var);
if ((v_ann = var_ann (var)))
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
- case STRUCT_FIELD_TAG:
break;
case VAR_DECL:
{
var_ann_t ann = var_ann (var);
ann->escape_mask = 0;
- if (MTAG_P (var) && TREE_CODE (var) != STRUCT_FIELD_TAG)
+ if (MTAG_P (var))
MTAG_GLOBAL (var) = 0;
if (!MTAG_P (var))
var_ann (var)->call_clobbered = false;
return false;
}
-/* Given a variable VAR, lookup and return a pointer to the list of
- subvariables for it. */
-
-static inline subvar_t *
-lookup_subvars_for_var (const_tree var)
-{
- var_ann_t ann = var_ann (var);
- gcc_assert (ann);
- return &ann->subvars;
-}
-
-/* Given a variable VAR, return a linked list of subvariables for VAR, or
- NULL, if there are no subvariables. */
-
-static inline subvar_t
-get_subvars_for_var (tree var)
-{
- subvar_t subvars;
-
- gcc_assert (SSA_VAR_P (var));
-
- if (TREE_CODE (var) == SSA_NAME)
- subvars = *(lookup_subvars_for_var (SSA_NAME_VAR (var)));
- else
- subvars = *(lookup_subvars_for_var (var));
- return subvars;
-}
-
-/* Return the subvariable of VAR at offset OFFSET. */
-
-static inline tree
-get_subvar_at (tree var, unsigned HOST_WIDE_INT offset)
-{
- subvar_t sv = get_subvars_for_var (var);
- int low, high;
-
- low = 0;
- high = VEC_length (tree, sv) - 1;
- while (low <= high)
- {
- int mid = (low + high) / 2;
- tree subvar = VEC_index (tree, sv, mid);
- if (SFT_OFFSET (subvar) == offset)
- return subvar;
- else if (SFT_OFFSET (subvar) < offset)
- low = mid + 1;
- else
- high = mid - 1;
- }
-
- return NULL_TREE;
-}
-
-
-/* Return the first subvariable in SV that overlaps [offset, offset + size[.
- NULL_TREE is returned, if there is no overlapping subvariable, else *I
- is set to the index in the SV vector of the first overlap. */
-
-static inline tree
-get_first_overlapping_subvar (subvar_t sv, unsigned HOST_WIDE_INT offset,
- unsigned HOST_WIDE_INT size, unsigned int *i)
-{
- int low = 0;
- int high = VEC_length (tree, sv) - 1;
- int mid;
- tree subvar;
-
- if (low > high)
- return NULL_TREE;
-
- /* Binary search for offset. */
- do
- {
- mid = (low + high) / 2;
- subvar = VEC_index (tree, sv, mid);
- if (SFT_OFFSET (subvar) == offset)
- {
- *i = mid;
- return subvar;
- }
- else if (SFT_OFFSET (subvar) < offset)
- low = mid + 1;
- else
- high = mid - 1;
- }
- while (low <= high);
-
- /* As we didn't find a subvar with offset, adjust to return the
- first overlapping one. */
- if (SFT_OFFSET (subvar) < offset
- && SFT_OFFSET (subvar) + SFT_SIZE (subvar) <= offset)
- {
- mid += 1;
- if ((unsigned)mid >= VEC_length (tree, sv))
- return NULL_TREE;
- subvar = VEC_index (tree, sv, mid);
- }
- else if (SFT_OFFSET (subvar) > offset
- && size <= SFT_OFFSET (subvar) - offset)
- {
- mid -= 1;
- if (mid < 0)
- return NULL_TREE;
- subvar = VEC_index (tree, sv, mid);
- }
-
- if (overlap_subvar (offset, size, subvar, NULL))
- {
- *i = mid;
- return subvar;
- }
-
- return NULL_TREE;
-}
-
/* Return true if V is a tree that we can have subvars for.
Normally, this is any aggregate type. Also complex
return false;
}
-
-/* Return true if OFFSET and SIZE define a range that overlaps with some
- portion of the range of SV, a subvar. If there was an exact overlap,
- *EXACT will be set to true upon return. */
-
-static inline bool
-overlap_subvar (unsigned HOST_WIDE_INT offset, unsigned HOST_WIDE_INT size,
- const_tree sv, bool *exact)
-{
- /* There are three possible cases of overlap.
- 1. We can have an exact overlap, like so:
- |offset, offset + size |
- |sv->offset, sv->offset + sv->size |
-
- 2. We can have offset starting after sv->offset, like so:
-
- |offset, offset + size |
- |sv->offset, sv->offset + sv->size |
-
- 3. We can have offset starting before sv->offset, like so:
-
- |offset, offset + size |
- |sv->offset, sv->offset + sv->size|
- */
-
- if (exact)
- *exact = false;
- if (offset == SFT_OFFSET (sv) && size == SFT_SIZE (sv))
- {
- if (exact)
- *exact = true;
- return true;
- }
- else if (offset >= SFT_OFFSET (sv)
- && offset < (SFT_OFFSET (sv) + SFT_SIZE (sv)))
- {
- return true;
- }
- else if (offset < SFT_OFFSET (sv)
- && (size > SFT_OFFSET (sv) - offset))
- {
- return true;
- }
- return false;
-
-}
-
/* Return the memory tag associated with symbol SYM. */
static inline tree
};
-typedef VEC(tree,gc) *subvar_t;
-
struct var_ann_d GTY(())
{
struct tree_ann_common_d common;
/* During into-ssa and the dominator optimizer, this field holds the
current version of this variable (an SSA_NAME). */
tree current_def;
-
- /* If this variable is a structure, this fields holds an array
- of symbols representing each of the fields of the structure. */
- VEC(tree,gc) *subvars;
};
/* Container for variable annotation used by hashtable for annotations for
extern void dump_referenced_vars (FILE *);
extern void dump_variable (FILE *, tree);
extern void debug_variable (tree);
-extern void dump_subvars_for (FILE *, tree);
-extern void debug_subvars_for (tree);
extern tree get_virtual_var (tree);
extern void add_referenced_var (tree);
extern void remove_referenced_var (tree);
extern void new_type_alias (tree, tree, tree);
extern void count_uses_and_derefs (tree, tree, unsigned *, unsigned *,
unsigned *);
-static inline subvar_t get_subvars_for_var (tree);
-static inline tree get_subvar_at (tree, unsigned HOST_WIDE_INT);
static inline bool ref_contains_array_ref (const_tree);
static inline bool array_ref_contains_indirect_ref (const_tree);
extern tree get_ref_base_and_extent (tree, HOST_WIDE_INT *,
HOST_WIDE_INT *, HOST_WIDE_INT *);
static inline bool var_can_have_subvars (const_tree);
-static inline bool overlap_subvar (unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT,
- const_tree, bool *);
extern tree create_tag_raw (enum tree_code, tree, const char *);
extern void delete_mem_ref_stats (struct function *);
extern void dump_mem_ref_stats (FILE *);
if (need_to_initialize_update_ssa_p)
init_update_ssa ();
- /* FIXME. Why do we need this? */
- {
- subvar_t svars;
- if (var_can_have_subvars (sym) && (svars = get_subvars_for_var (sym)))
- {
- unsigned int i;
- tree subvar;
-
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- mark_sym_for_renaming (subvar);
- }
- }
-
bitmap_set_bit (syms_to_rename, DECL_UID (sym));
if (!is_gimple_reg (sym))
optimization, where DEST is expected to be the LHS of a modify
expression where the RHS is a function returning an aggregate.
- We search for a base VAR_DECL and look to see if it, or any of its
- subvars are clobbered. Note that we could do better, for example, by
+ We search for a base VAR_DECL and look to see if it is call clobbered.
+ Note that we could do better, for example, by
attempting to doing points-to analysis on INDIRECT_REFs. */
static bool
dest_safe_for_nrv_p (tree dest)
{
- subvar_t sv;
- unsigned int i;
- tree subvar;
-
while (handled_component_p (dest))
dest = TREE_OPERAND (dest, 0);
if (is_call_clobbered (dest))
return false;
- sv = get_subvars_for_var (dest);
- for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
- if (is_call_clobbered (subvar))
- return false;
-
return true;
}
new_type_alias (var, tag, ref);
else
var_ann (var)->symbol_mem_tag = tag;
-
- var_ann (var)->subvars = DR_SUBVARS (dr);
}
/* Prepare initializers for CHAIN in LOOP. Returns false if this is
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
- case STRUCT_FIELD_TAG:
case VAR_DECL:
case PARM_DECL:
case FIELD_DECL:
static void
mark_aliases_call_clobbered (tree tag, VEC (tree, heap) **worklist,
- VEC (int, heap) **worklist2,
- bitmap on_worklist, bitmap queued)
+ VEC (int, heap) **worklist2, bitmap on_worklist)
{
bitmap aliases;
bitmap_iterator bi;
the world a particularly nice place, it is necessary
in order to allow C/C++ tricks that involve
pointer arithmetic to work. */
- if (TREE_CODE (entry) == STRUCT_FIELD_TAG)
- bitmap_set_bit (queued, DECL_UID (SFT_PARENT_VAR (entry)));
- else if (!unmodifiable_var_p (entry))
+ if (!unmodifiable_var_p (entry))
{
add_to_worklist (entry, worklist, worklist2, ta->escape_mask,
on_worklist);
mark_call_clobbered (entry, ta->escape_mask);
}
}
- if (!bitmap_empty_p (queued))
- {
- EXECUTE_IF_SET_IN_BITMAP (queued, 0, i, bi)
- {
- subvar_t svars = get_subvars_for_var (referenced_var (i));
- unsigned int i;
- tree subvar;
-
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- if (!unmodifiable_var_p (subvar))
- mark_call_clobbered (subvar, ta->escape_mask);
- }
- bitmap_clear (queued);
- }
}
/* Tags containing global vars need to be marked as global.
FOR_EACH_REFERENCED_VAR (tag, rvi)
{
- if (!MTAG_P (tag) || TREE_CODE (tag) == STRUCT_FIELD_TAG)
+ if (!MTAG_P (tag))
continue;
VEC_safe_push (tree, heap, taglist, tag);
}
referenced_var_iterator rvi;
tree var;
tree ptr;
- bitmap queued;
-
- /* Temporary bitmap to avoid quadratic behavior in marking
- call clobbers. */
- queued = BITMAP_ALLOC (&alias_bitmap_obstack);
FOR_EACH_REFERENCED_VAR (var, rvi)
{
- if (is_global_var (var)
- && (!var_can_have_subvars (var)
- || get_subvars_for_var (var) == NULL))
+ if (is_global_var (var))
{
if (!unmodifiable_var_p (var))
mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
the world a particularly nice place, it is necessary
in order to allow C/C++ tricks that involve
pointer arithmetic to work. */
- if (TREE_CODE (alias) == STRUCT_FIELD_TAG)
- bitmap_set_bit (queued, DECL_UID (SFT_PARENT_VAR (alias)));
- else if (!unmodifiable_var_p (alias))
+ if (!unmodifiable_var_p (alias))
mark_call_clobbered (alias, pi->escape_mask);
}
- /* Process variables we need to clobber all parts of. */
- if (!bitmap_empty_p (queued))
- {
- EXECUTE_IF_SET_IN_BITMAP (queued, 0, j, bi)
- {
- subvar_t svars = get_subvars_for_var (referenced_var (j));
- unsigned int i;
- tree subvar;
-
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- if (!unmodifiable_var_p (subvar))
- mark_call_clobbered (subvar, pi->escape_mask);
- }
- bitmap_clear (queued);
- }
}
}
MTAG_GLOBAL (tag) = true;
}
}
-
- BITMAP_FREE (queued);
}
/* Compute which variables need to be marked call clobbered because
{
VEC (tree, heap) *worklist = NULL;
VEC (int,heap) *worklist2 = NULL;
- bitmap on_worklist, queued;
+ bitmap on_worklist;
timevar_push (TV_CALL_CLOBBER);
on_worklist = BITMAP_ALLOC (NULL);
- queued = BITMAP_ALLOC (NULL);
set_initial_properties (ai);
init_transitive_clobber_worklist (&worklist, &worklist2, on_worklist);
bitmap_clear_bit (on_worklist, DECL_UID (curr));
mark_call_clobbered (curr, reason);
- mark_aliases_call_clobbered (curr, &worklist, &worklist2,
- on_worklist, queued);
+ mark_aliases_call_clobbered (curr, &worklist, &worklist2, on_worklist);
}
VEC_free (tree, heap, worklist);
VEC_free (int, heap, worklist2);
BITMAP_FREE (on_worklist);
- BITMAP_FREE (queued);
compute_tag_properties ();
timevar_pop (TV_CALL_CLOBBER);
}
static inline long
mem_sym_score (mem_sym_stats_t mp)
{
- /* Unpartitionable SFTs are automatically thrown to the bottom of
- the list. They are not stored in partitions, but they are used
- for computing overall statistics. */
- if (TREE_CODE (mp->var) == STRUCT_FIELD_TAG
- && SFT_UNPARTITIONABLE_P (mp->var))
- return LONG_MAX;
-
return mp->frequency_writes * 64 + mp->frequency_reads * 32
+ mp->num_direct_writes * 16 + mp->num_direct_reads * 8
+ mp->num_indirect_writes * 4 + mp->num_indirect_reads * 2
if (!need_to_partition_p (mem_ref_stats))
break;
- /* SFTs that are marked unpartitionable should not be added to
- partitions. These SFTs are special because they mark the
- first SFT into a structure where a pointer is pointing to.
- This is needed by the operand scanner to find adjacent
- fields. See add_vars_for_offset for details. */
- if (TREE_CODE (mp_p->var) == STRUCT_FIELD_TAG
- && SFT_UNPARTITIONABLE_P (mp_p->var))
- continue;
-
mpt = find_partition_for (mp_p);
estimate_vop_reduction (mem_ref_stats, mp_p, mpt);
}
if (may_alias_p (p_map->var, p_map->set, var, v_map->set, false))
{
- /* We should never have a var with subvars here, because
- they shouldn't get into the set of addressable vars */
- gcc_assert (!var_can_have_subvars (var)
- || get_subvars_for_var (var) == NULL);
-
/* Add VAR to TAG's may-aliases set. */
add_may_alias (tag, var);
}
FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, srvi)
{
- subvar_t svars;
-
/* Name memory tags already have flow-sensitive aliasing
information, so they need not be processed by
compute_flow_insensitive_aliasing. Similarly, symbol memory
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) && TREE_CODE (var) != STRUCT_FIELD_TAG)
+ if (MTAG_P (var))
continue;
/* Remove the ADDRESSABLE flag from every addressable variable whose
to rename VAR into SSA afterwards. */
mark_sym_for_renaming (var);
- /* If VAR can have sub-variables, and any of its
- sub-variables has its address taken, then we cannot
- remove the addressable flag from VAR. */
- if (var_can_have_subvars (var)
- && (svars = get_subvars_for_var (var)))
- {
- unsigned int i;
- tree subvar;
-
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- {
- if (bitmap_bit_p (gimple_addressable_vars (cfun),
- DECL_UID (subvar)))
- okay_to_mark = false;
- mark_sym_for_renaming (subvar);
- }
- }
-
/* The address of VAR is not needed, remove the
addressable bit, so that it can be optimized as a
regular variable. */
entry in ADDRESSABLE_VARS for VAR. */
if (may_be_aliased (var))
{
- if (!var_can_have_subvars (var)
- || get_subvars_for_var (var) == NULL)
- create_alias_map_for (var, ai);
-
+ create_alias_map_for (var, ai);
mark_sym_for_renaming (var);
}
{
tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
tree tag;
- subvar_t svars;
tree ali = NULL_TREE;
HOST_WIDE_INT offset, size, maxsize;
tree ref;
- VEC (tree, heap) *overlaps = NULL;
- unsigned int len, i;
- tree subvar;
-
gcc_assert (symbol_mem_tag (ptr) == NULL_TREE);
gcc_assert (!MTAG_P (var));
tag = create_memory_tag (tag_type, true);
set_symbol_mem_tag (ptr, tag);
- /* Add VAR to the may-alias set of PTR's new symbol tag. If VAR has
- subvars, add the subvars to the tag instead of the actual var. */
- if (var_can_have_subvars (ref)
- && (svars = get_subvars_for_var (ref)))
- {
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- {
- bool exact;
-
- if (overlap_subvar (offset, maxsize, subvar, &exact))
- VEC_safe_push (tree, heap, overlaps, subvar);
- }
- gcc_assert (overlaps != NULL);
- }
- else if (var_can_have_subvars (var)
- && (svars = get_subvars_for_var (var)))
- {
- /* If the REF is not a direct access to VAR (e.g., it is a dereference
- of a pointer), we should scan the virtual operands of REF the same
- way as tree-ssa-operands do. At the moment, this is somewhat
- difficult, so we just give up and add all the subvars of VAR.
- On mem-ssa branch, the scanning for virtual operands have been
- split from the rest of tree-ssa-operands, so it should be much
- easier to fix this problem correctly once mem-ssa is merged. */
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- VEC_safe_push (tree, heap, overlaps, subvar);
-
- gcc_assert (overlaps != NULL);
- }
- else
- ali = add_may_alias_for_new_tag (tag, var);
-
- len = VEC_length (tree, overlaps);
- if (len > 0)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "\nnumber of overlapping subvars = %u\n", len);
-
- if (len == 1)
- ali = add_may_alias_for_new_tag (tag, VEC_index (tree, overlaps, 0));
- else if (len > 1)
- {
- unsigned int k;
- tree sv_var;
-
- for (k = 0; VEC_iterate (tree, overlaps, k, sv_var); k++)
- {
- ali = add_may_alias_for_new_tag (tag, sv_var);
-
- if (ali != tag)
- {
- /* Can happen only if 'Case 1' of add_may_alias_for_new_tag
- took place. Since more than one svar was found, we add
- 'ali' as one of the may_aliases of the new tag. */
- add_may_alias (tag, ali);
- ali = tag;
- }
- }
- }
- VEC_free (tree, heap, overlaps);
- }
+ ali = add_may_alias_for_new_tag (tag, var);
set_symbol_mem_tag (ptr, ali);
TREE_READONLY (tag) = TREE_READONLY (var);
MTAG_GLOBAL (tag) = is_global_var (var);
}
-/* This represents the used range of a variable. */
-
-typedef struct used_part
-{
- HOST_WIDE_INT minused;
- HOST_WIDE_INT maxused;
- /* True if we have an explicit use/def of some portion of this variable,
- even if it is all of it. i.e. a.b = 5 or temp = a.b. */
- bool explicit_uses;
- /* True if we have an implicit use/def of some portion of this
- variable. Implicit uses occur when we can't tell what part we
- are referencing, and have to make conservative assumptions. */
- bool implicit_uses;
- /* True if the structure is only written to or taken its address. */
- bool write_only;
-} *used_part_t;
-
-/* An array of used_part structures, indexed by variable uid. */
-
-static htab_t used_portions;
-
-struct used_part_map
-{
- unsigned int uid;
- used_part_t to;
-};
-
-/* Return true if the uid in the two used part maps are equal. */
-
-static int
-used_part_map_eq (const void *va, const void *vb)
-{
- const struct used_part_map *a = (const struct used_part_map *) va;
- const struct used_part_map *b = (const struct used_part_map *) vb;
- return (a->uid == b->uid);
-}
-
-/* Hash a from uid in a used_part_map. */
-
-static unsigned int
-used_part_map_hash (const void *item)
-{
- return ((const struct used_part_map *)item)->uid;
-}
-
-/* Free a used part map element. */
-
-static void
-free_used_part_map (void *item)
-{
- free (((struct used_part_map *)item)->to);
- free (item);
-}
-
-/* Lookup a used_part structure for a UID. */
-
-static used_part_t
-up_lookup (unsigned int uid)
-{
- struct used_part_map *h, in;
- in.uid = uid;
- h = (struct used_part_map *) htab_find_with_hash (used_portions, &in, uid);
- if (!h)
- return NULL;
- return h->to;
-}
-
-/* Insert the pair UID, TO into the used part hashtable. */
-
-static void
-up_insert (unsigned int uid, used_part_t to)
-{
- struct used_part_map *h;
- void **loc;
-
- h = XNEW (struct used_part_map);
- h->uid = uid;
- h->to = to;
- loc = htab_find_slot_with_hash (used_portions, h,
- uid, INSERT);
- if (*loc != NULL)
- free (*loc);
- *(struct used_part_map **) loc = h;
-}
-
-
-/* Given a variable uid, UID, get or create the entry in the used portions
- table for the variable. */
-
-static used_part_t
-get_or_create_used_part_for (size_t uid)
-{
- used_part_t up;
- if ((up = up_lookup (uid)) == NULL)
- {
- up = XCNEW (struct used_part);
- up->minused = INT_MAX;
- up->maxused = 0;
- up->explicit_uses = false;
- up->implicit_uses = false;
- up->write_only = true;
- }
-
- return up;
-}
-
-
-/* Create and return a structure sub-variable for field type FIELD at
- offset OFFSET, with size SIZE, of variable VAR. If ALIAS_SET not
- -1 this field is non-addressable and we should use this alias set
- with this field. */
-
-static tree
-create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
- unsigned HOST_WIDE_INT size, alias_set_type alias_set,
- bool base_for_components)
-{
- tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT");
-
- /* We need to copy the various flags from VAR to SUBVAR, so that
- they are is_global_var iff the original variable was. */
- DECL_CONTEXT (subvar) = DECL_CONTEXT (var);
- MTAG_GLOBAL (subvar) = DECL_EXTERNAL (var);
- TREE_PUBLIC (subvar) = TREE_PUBLIC (var);
- TREE_STATIC (subvar) = TREE_STATIC (var);
- TREE_READONLY (subvar) = TREE_READONLY (var);
- TREE_ADDRESSABLE (subvar) = TREE_ADDRESSABLE (var);
-
- /* Add the new variable to REFERENCED_VARS. */
- set_symbol_mem_tag (subvar, NULL);
- add_referenced_var (subvar);
- SFT_PARENT_VAR (subvar) = var;
- SFT_OFFSET (subvar) = offset;
- SFT_SIZE (subvar) = size;
- SFT_ALIAS_SET (subvar) = alias_set;
- SFT_BASE_FOR_COMPONENTS_P (subvar) = base_for_components;
- SFT_UNPARTITIONABLE_P (subvar) = false;
-
- return subvar;
-}
-
-
-/* Given an aggregate VAR, create the subvariables that represent its
- fields. */
-
-static void
-create_overlap_variables_for (tree var)
-{
- VEC(fieldoff_s,heap) *fieldstack = NULL;
- used_part_t up;
- size_t uid = DECL_UID (var);
-
- up = up_lookup (uid);
- if (!up
- || up->write_only)
- return;
-
- push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL,
- TREE_TYPE (var));
- /* Make sure to not create SFTs for structs we won't generate variable
- infos for. See tree-ssa-structalias.c:create_variable_info_for (). */
- if (VEC_length (fieldoff_s, fieldstack) > 1
- && VEC_length (fieldoff_s, fieldstack) <= MAX_FIELDS_FOR_FIELD_SENSITIVE)
- {
- subvar_t *subvars;
- fieldoff_s *fo;
- bool notokay = false;
- int fieldcount = 0;
- int i;
- HOST_WIDE_INT lastfooffset = -1;
- HOST_WIDE_INT lastfosize = -1;
- tree lastfotype = NULL_TREE;
-
- /* Not all fields have DECL_SIZE set, and those that don't, we don't
- know their size, and thus, can't handle.
- The same is true of fields with DECL_SIZE that is not an integer
- constant (such as variable sized fields).
- Fields with offsets which are not constant will have an offset < 0
- We *could* handle fields that are constant sized arrays, but
- currently don't. Doing so would require some extra changes to
- tree-ssa-operands.c. */
-
- for (i = 0; VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
- {
- if (!fo->size
- || TREE_CODE (fo->size) != INTEGER_CST
- || fo->offset < 0)
- {
- notokay = true;
- break;
- }
- fieldcount++;
- }
-
- /* The current heuristic we use is as follows:
- If the variable has no used portions in this function, no
- structure vars are created for it.
- Otherwise,
- If the variable has less than SALIAS_MAX_IMPLICIT_FIELDS,
- we always create structure vars for them.
- If the variable has more than SALIAS_MAX_IMPLICIT_FIELDS, and
- some explicit uses, we create structure vars for them.
- If the variable has more than SALIAS_MAX_IMPLICIT_FIELDS, and
- no explicit uses, we do not create structure vars for them.
- */
-
- if (fieldcount >= SALIAS_MAX_IMPLICIT_FIELDS
- && !up->explicit_uses)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Variable ");
- print_generic_expr (dump_file, var, 0);
- fprintf (dump_file, " has no explicit uses in this function, and is > SALIAS_MAX_IMPLICIT_FIELDS, so skipping\n");
- }
- notokay = true;
- }
-
- /* Bail out, if we can't create overlap variables. */
- if (notokay)
- {
- VEC_free (fieldoff_s, heap, fieldstack);
- return;
- }
-
- /* Otherwise, create the variables. */
- subvars = lookup_subvars_for_var (var);
- *subvars = VEC_alloc (tree, gc, VEC_length (fieldoff_s, fieldstack));
-
- sort_fieldstack (fieldstack);
-
- for (i = 0; VEC_iterate (fieldoff_s, fieldstack, i, fo); ++i)
- {
- HOST_WIDE_INT fosize;
- tree currfotype, subvar;
-
- fosize = TREE_INT_CST_LOW (fo->size);
- currfotype = fo->type;
-
- /* If this field isn't in the used portion,
- or it has the exact same offset and size as the last
- field, skip it. Note that we always need the field at
- offset 0 so we can properly handle pointers to the
- structure. */
-
- if ((fo->offset != 0
- && ((fo->offset <= up->minused
- && fo->offset + fosize <= up->minused)
- || fo->offset >= up->maxused))
- || (fo->offset == lastfooffset
- && fosize == lastfosize
- && currfotype == lastfotype))
- continue;
- subvar = create_sft (var, fo->type, fo->offset,
- fosize, fo->alias_set, fo->base_for_components);
- VEC_quick_push (tree, *subvars, subvar);
-
- if (dump_file)
- {
- fprintf (dump_file, "structure field tag %s created for var %s",
- get_name (subvar), get_name (var));
- fprintf (dump_file, " offset " HOST_WIDE_INT_PRINT_DEC,
- SFT_OFFSET (subvar));
- fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
- SFT_SIZE (subvar));
- fprintf (dump_file, "\n");
- }
-
- lastfotype = currfotype;
- lastfooffset = fo->offset;
- lastfosize = fosize;
- }
-
- /* Once we have created subvars, the original is no longer call
- clobbered on its own. Its call clobbered status depends
- completely on the call clobbered status of the subvars.
-
- add_referenced_var in the above loop will take care of
- marking subvars of global variables as call clobbered for us
- to start, since they are global as well. */
- clear_call_clobbered (var);
- }
-
- VEC_free (fieldoff_s, heap, fieldstack);
-}
-
-
-/* Find the conservative answer to the question of what portions of what
- structures are used by this statement. We assume that if we have a
- component ref with a known size + offset, that we only need that part
- of the structure. For unknown cases, or cases where we do something
- to the whole structure, we assume we need to create fields for the
- entire structure. */
-
-static tree
-find_used_portions (tree *tp, int *walk_subtrees, void *lhs_p)
-{
- switch (TREE_CODE (*tp))
- {
- case GIMPLE_MODIFY_STMT:
- /* Recurse manually here to track whether the use is in the
- LHS of an assignment. */
- find_used_portions (&GIMPLE_STMT_OPERAND (*tp, 0), walk_subtrees, tp);
- return find_used_portions (&GIMPLE_STMT_OPERAND (*tp, 1),
- walk_subtrees, NULL);
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- case COMPONENT_REF:
- case ARRAY_REF:
- {
- HOST_WIDE_INT bitsize;
- HOST_WIDE_INT bitmaxsize;
- HOST_WIDE_INT bitpos;
- tree ref;
- ref = get_ref_base_and_extent (*tp, &bitpos, &bitsize, &bitmaxsize);
- if (DECL_P (ref)
- && var_can_have_subvars (ref)
- && bitmaxsize != -1)
- {
- size_t uid = DECL_UID (ref);
- used_part_t up;
-
- up = get_or_create_used_part_for (uid);
-
- if (bitpos <= up->minused)
- up->minused = bitpos;
- if ((bitpos + bitmaxsize >= up->maxused))
- up->maxused = bitpos + bitmaxsize;
-
- if (bitsize == bitmaxsize)
- up->explicit_uses = true;
- else
- up->implicit_uses = true;
- if (!lhs_p)
- up->write_only = false;
- up_insert (uid, up);
-
- *walk_subtrees = 0;
- return NULL_TREE;
- }
- }
- break;
- /* This is here to make sure we mark the entire base variable as used
- when you take its address. Because our used portion analysis is
- simple, we aren't looking at casts or pointer arithmetic to see what
- happens when you take the address. */
- case ADDR_EXPR:
- {
- tree var = get_base_address (TREE_OPERAND (*tp, 0));
-
- if (var
- && DECL_P (var)
- && DECL_SIZE (var)
- && var_can_have_subvars (var)
- && TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
- {
- used_part_t up;
- size_t uid = DECL_UID (var);
-
- up = get_or_create_used_part_for (uid);
-
- up->minused = 0;
- up->maxused = TREE_INT_CST_LOW (DECL_SIZE (var));
- up->implicit_uses = true;
- if (!lhs_p)
- up->write_only = false;
-
- up_insert (uid, up);
- *walk_subtrees = 0;
- return NULL_TREE;
- }
- }
- break;
- case CALL_EXPR:
- {
- int i;
- int nargs = call_expr_nargs (*tp);
- for (i = 0; i < nargs; i++)
- {
- tree *arg = &CALL_EXPR_ARG (*tp, i);
- if (TREE_CODE (*arg) == ADDR_EXPR)
- find_used_portions (arg, walk_subtrees, NULL);
- }
- *walk_subtrees = 0;
- return NULL_TREE;
- }
- case VAR_DECL:
- case PARM_DECL:
- case RESULT_DECL:
- {
- tree var = *tp;
- if (DECL_SIZE (var)
- && var_can_have_subvars (var)
- && TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
- {
- used_part_t up;
- size_t uid = DECL_UID (var);
-
- up = get_or_create_used_part_for (uid);
-
- up->minused = 0;
- up->maxused = TREE_INT_CST_LOW (DECL_SIZE (var));
- up->implicit_uses = true;
-
- up_insert (uid, up);
- *walk_subtrees = 0;
- return NULL_TREE;
- }
- }
- break;
-
- default:
- break;
-
- }
- return NULL_TREE;
-}
-
-/* Create structure field variables for structures used in this function. */
+/* ??? Stub. */
static unsigned int
create_structure_vars (void)
{
- basic_block bb;
- safe_referenced_var_iterator rvi;
- VEC (tree, heap) *varvec = NULL;
- tree var;
-
- used_portions = htab_create (10, used_part_map_hash, used_part_map_eq,
- free_used_part_map);
-
- FOR_EACH_BB (bb)
- {
- block_stmt_iterator bsi;
- tree phi;
-
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- {
- use_operand_p use;
- ssa_op_iter iter;
-
- FOR_EACH_PHI_ARG (use, phi, iter, SSA_OP_USE)
- {
- tree op = USE_FROM_PTR (use);
- walk_tree_without_duplicates (&op, find_used_portions,
- NULL);
- }
- }
-
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
- find_used_portions,
- NULL);
- }
- }
- FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, rvi)
- {
- /* The C++ FE creates vars without DECL_SIZE set, for some reason. */
- if (var
- && DECL_SIZE (var)
- && var_can_have_subvars (var)
- && !MTAG_P (var)
- && TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
- create_overlap_variables_for (var);
- }
- htab_delete (used_portions);
- VEC_free (tree, heap, varvec);
-
- /* Update SSA operands of statements mentioning variables we split. */
- if (gimple_in_ssa_p (cfun))
- FOR_EACH_BB (bb)
- {
- block_stmt_iterator bsi;
- for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- {
- tree stmt = bsi_stmt (bsi);
- bool update = false;
- unsigned int i;
- bitmap_iterator bi;
-
- if (STORED_SYMS (stmt))
- EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi)
- {
- tree sym = referenced_var_lookup (i);
- if (get_subvars_for_var (sym))
- {
- update = true;
- break;
- }
- }
-
- if (LOADED_SYMS (stmt) && !update)
- EXECUTE_IF_SET_IN_BITMAP (LOADED_SYMS (stmt), 0, i, bi)
- {
- tree sym = referenced_var_lookup (i);
- if (get_subvars_for_var (sym))
- {
- update = true;
- break;
- }
- }
-
- if (stmt_ann (stmt)->addresses_taken && !update)
- EXECUTE_IF_SET_IN_BITMAP (stmt_ann (stmt)->addresses_taken,
- 0, i, bi)
- {
- tree sym = referenced_var_lookup (i);
- if (get_subvars_for_var (sym))
- {
- update = true;
- break;
- }
- }
-
- if (update)
- update_stmt (stmt);
- }
- }
-
return TODO_rebuild_alias;
}
break;
}
- if (aref && SSA_VAR_P (aref) && get_subvars_for_var (aref))
- return aref;
-
if (!var)
return NULL_TREE;
if (ref && TREE_CODE (ref) == TARGET_MEM_REF)
return true;
- /* If ALIAS is an SFT, it can't be touched if the offset
- and size of the access is not overlapping with the SFT offset and
- size. This is only true if we are accessing through a pointer
- to a type that is the same as SFT_PARENT_VAR. Otherwise, we may
- be accessing through a pointer to some substruct of the
- structure, and if we try to prune there, we will have the wrong
- offset, and get the wrong answer.
- i.e., we can't prune without more work if we have something like
-
- struct gcc_target
- {
- struct asm_out
- {
- const char *byte_op;
- struct asm_int_op
- {
- const char *hi;
- } aligned_op;
- } asm_out;
- } targetm;
-
- foo = &targetm.asm_out.aligned_op;
- return foo->hi;
-
- SFT.1, which represents hi, will have SFT_OFFSET=32 because in
- terms of SFT_PARENT_VAR, that is where it is.
- However, the access through the foo pointer will be at offset 0. */
- if (size != -1
- && TREE_CODE (alias) == STRUCT_FIELD_TAG
- && base
- && TREE_TYPE (base) == TREE_TYPE (SFT_PARENT_VAR (alias))
- && !overlap_subvar (offset, size, alias, NULL))
- {
-#ifdef ACCESS_DEBUGGING
- fprintf (stderr, "Access to ");
- print_generic_expr (stderr, ref, 0);
- fprintf (stderr, " may not touch ");
- print_generic_expr (stderr, alias, 0);
- fprintf (stderr, " in function %s\n", get_name (current_function_decl));
-#endif
- return false;
- }
-
/* Without strict aliasing, it is impossible for a component access
through a pointer to touch a random variable, unless that
variable *is* a structure or a pointer.
my_char_ref_1 = (char[1:1] &) &my_char;
D.874_2 = (*my_char_ref_1)[1]{lb: 1 sz: 1};
*/
- else if (ref
+ if (ref
&& flag_strict_aliasing
&& TREE_CODE (ref) != INDIRECT_REF
&& !MTAG_P (alias)
return true;
}
-/* Add the actual variables accessed, given a member of a points-to set
- that is the SFT VAR, where the access is of SIZE at OFFSET from VAR.
- IS_CALL_SITE is true if this is a call, and IS_DEF is true if this is
- supposed to be a vdef, and false if this should be a VUSE.
-
- The real purpose of this function is to take a points-to set for a
- pointer to a structure, say
-
- struct s {
- int a;
- int b;
- } foo, *foop = &foo;
-
- and discover which variables an access, such as foop->b, can alias.
-
- This is necessary because foop only actually points to foo's first
- member, so that is all the points-to set contains. However, an access
- to foop->a may be touching some single SFT if we have created some
- SFT's for a structure. */
-
-static bool
-add_vars_for_offset (tree var, unsigned HOST_WIDE_INT offset,
- unsigned HOST_WIDE_INT size, bool is_def)
-{
- bool added = false;
- tree subvar;
- subvar_t sv;
- unsigned int i;
-
- /* Adjust offset by the pointed-to location. */
- offset += SFT_OFFSET (var);
-
- /* Add all subvars of var that overlap with the access.
- Binary search for the first relevant SFT. */
- sv = get_subvars_for_var (SFT_PARENT_VAR (var));
- if (!get_first_overlapping_subvar (sv, offset, size, &i))
- return false;
-
- for (; VEC_iterate (tree, sv, i, subvar); ++i)
- {
- if (SFT_OFFSET (subvar) > offset
- && size <= SFT_OFFSET (subvar) - offset)
- break;
-
- if (is_def)
- append_vdef (subvar);
- else
- append_vuse (subvar);
- added = true;
- }
-
- return added;
-}
-
-
/* Add VAR to the virtual operands array. FLAGS is as in
get_expr_operands. FULL_REF is a tree that contains the entire
pointer dereference expression, if available, or NULL otherwise.
{
tree al = referenced_var (i);
- /* For SFTs we have to consider all subvariables of the parent var
- if it is a potential points-to location. */
- if (TREE_CODE (al) == STRUCT_FIELD_TAG
- && TREE_CODE (var) == NAME_MEMORY_TAG)
- {
- if (SFT_BASE_FOR_COMPONENTS_P (al))
- {
- /* If AL is the first SFT of a component, it can be used
- to find other SFTs at [offset, size] adjacent to it. */
- none_added &= !add_vars_for_offset (al, offset, size,
- flags & opf_def);
- }
- else if ((unsigned HOST_WIDE_INT)offset < SFT_SIZE (al))
- {
- /* Otherwise, we only need to consider it if
- [offset, size] overlaps with AL. */
- if (flags & opf_def)
- append_vdef (al);
- else
- append_vuse (al);
- none_added = false;
- }
- }
+ /* Call-clobbered tags may have non-call-clobbered
+ symbols in their alias sets. Ignore them if we are
+ adding VOPs for a call site. */
+ if (is_call_site && !is_call_clobbered (al))
+ continue;
+
+ /* If we do not know the full reference tree or if the access is
+ unspecified [0, -1], we cannot prune it. Otherwise try doing
+ so using access_can_touch_variable. */
+ if (full_ref
+ && !access_can_touch_variable (full_ref, al, offset, size))
+ continue;
+
+ if (flags & opf_def)
+ append_vdef (al);
else
- {
- /* Call-clobbered tags may have non-call-clobbered
- symbols in their alias sets. Ignore them if we are
- adding VOPs for a call site. */
- if (is_call_site && !is_call_clobbered (al))
- continue;
-
- /* If we do not know the full reference tree or if the access is
- unspecified [0, -1], we cannot prune it. Otherwise try doing
- so using access_can_touch_variable. */
- if (full_ref
- && !access_can_touch_variable (full_ref, al, offset, size))
- continue;
-
- if (flags & opf_def)
- append_vdef (al);
- else
- append_vuse (al);
- none_added = false;
- }
+ append_vuse (al);
+ none_added = false;
}
if (flags & opf_def)
tree real_var = var;
bool not_read;
bool not_written;
-
- /* Not read and not written are computed on regular vars, not
- subvars, so look at the parent var if this is an SFT. */
- if (TREE_CODE (var) == STRUCT_FIELD_TAG)
- real_var = SFT_PARENT_VAR (var);
not_read = not_read_b
? bitmap_bit_p (not_read_b, DECL_UID (real_var))
clobber_stats.readonly_clobbers++;
- /* Not read and not written are computed on regular vars, not
- subvars, so look at the parent var if this is an SFT. */
-
- if (TREE_CODE (var) == STRUCT_FIELD_TAG)
- real_var = SFT_PARENT_VAR (var);
-
not_read = not_read_b ? bitmap_bit_p (not_read_b, DECL_UID (real_var))
: false;
EXECUTE_IF_SET_IN_BITMAP (gimple_addressable_vars (cfun), 0, i, bi)
{
tree var = referenced_var (i);
-
- /* Subvars are explicitly represented in this list, so we
- don't need the original to be added to the clobber ops,
- but the original *will* be in this list because we keep
- the addressability of the original variable up-to-date
- to avoid confusing the back-end. */
- if (var_can_have_subvars (var)
- && get_subvars_for_var (var) != NULL)
- continue;
-
add_stmt_operand (&var, s_ann, opf_def | opf_implicit);
}
break;
a preserving definition (VDEF).
Preserving definitions are those that modify a part of an
- aggregate object for which no subvars have been computed (or the
- reference does not correspond exactly to one of them). Stores
- through a pointer are also represented with VDEF operators.
+ aggregate object. Stores through a pointer are also represented
+ with VDEF operators.
We used to distinguish between preserving and killing definitions.
We always emit preserving definitions now. */
return;
case SSA_NAME:
- case STRUCT_FIELD_TAG:
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
add_stmt_operand (expr_p, s_ann, flags);
case VAR_DECL:
case PARM_DECL:
case RESULT_DECL:
- {
- subvar_t svars;
-
- /* Add the subvars for a variable, if it has subvars, to DEFS
- or USES. Otherwise, add the variable itself. Whether it
- goes to USES or DEFS depends on the operand flags. */
- if (var_can_have_subvars (expr)
- && (svars = get_subvars_for_var (expr)))
- {
- unsigned int i;
- tree subvar;
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- add_stmt_operand (&subvar, s_ann, flags);
- }
- else
- add_stmt_operand (expr_p, s_ann, flags);
-
- return;
- }
+ add_stmt_operand (expr_p, s_ann, flags);
+ return;
case MISALIGNED_INDIRECT_REF:
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags);
{
tree ref;
HOST_WIDE_INT offset, size, maxsize;
- bool none = true;
if (TREE_THIS_VOLATILE (expr))
s_ann->has_volatile_ops = true;
- /* This component reference becomes an access to all of the
- subvariables it can touch, if we can determine that, but
- *NOT* the real one. If we can't determine which fields we
- could touch, the recursion will eventually get to a
- variable and add *all* of its subvars, or whatever is the
- minimum correct subset. */
ref = get_ref_base_and_extent (expr, &offset, &size, &maxsize);
- if (SSA_VAR_P (ref) && get_subvars_for_var (ref))
- {
- subvar_t svars = get_subvars_for_var (ref);
- unsigned int i;
- tree subvar;
-
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- {
- bool exact;
-
- if (overlap_subvar (offset, maxsize, subvar, &exact))
- {
- int subvar_flags = flags;
- none = false;
- add_stmt_operand (&subvar, s_ann, subvar_flags);
- }
- }
-
- if (!none)
- flags |= opf_no_vops;
-
- if ((DECL_P (ref) && TREE_THIS_VOLATILE (ref))
- || (TREE_CODE (ref) == SSA_NAME
- && TREE_THIS_VOLATILE (SSA_NAME_VAR (ref))))
- s_ann->has_volatile_ops = true;
- }
- else if (TREE_CODE (ref) == INDIRECT_REF)
+ if (TREE_CODE (ref) == INDIRECT_REF)
{
get_indirect_ref_operands (stmt, ref, flags, expr, offset,
maxsize, false);
flags |= opf_no_vops;
}
- /* Even if we found subvars above we need to ensure to see
- immediate uses for d in s.a[d]. In case of s.a having
- a subvar or we would miss it otherwise. */
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags);
if (code == COMPONENT_REF)
add_to_addressable_set (tree ref, bitmap *addresses_taken)
{
tree var;
- subvar_t svars;
gcc_assert (addresses_taken);
{
if (*addresses_taken == NULL)
*addresses_taken = BITMAP_GGC_ALLOC ();
-
- if (var_can_have_subvars (var)
- && (svars = get_subvars_for_var (var)))
- {
- unsigned int i;
- tree subvar;
- for (i = 0; VEC_iterate (tree, svars, i, subvar); ++i)
- {
- bitmap_set_bit (*addresses_taken, DECL_UID (subvar));
- TREE_ADDRESSABLE (subvar) = 1;
- }
- }
- else
- {
- bitmap_set_bit (*addresses_taken, DECL_UID (var));
- TREE_ADDRESSABLE (var) = 1;
- }
+ bitmap_set_bit (*addresses_taken, DECL_UID (var));
+ TREE_ADDRESSABLE (var) = 1;
}
}
{
unsigned int i;
bitmap_iterator bi;
- alias_set_type ptr_alias_set;
gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
- ptr_alias_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
{
varinfo_t vi = get_varinfo (i);
- alias_set_type var_alias_set;
/* 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;
- if (vi->has_union && get_subvars_for_var (vi->decl) != NULL)
+ if (TREE_CODE (vi->decl) == VAR_DECL
+ || TREE_CODE (vi->decl) == PARM_DECL
+ || TREE_CODE (vi->decl) == RESULT_DECL)
{
- unsigned int i;
- tree subvar;
- subvar_t sv = get_subvars_for_var (vi->decl);
-
- /* Variables containing unions may need to be converted to
- their SFT's, because SFT's can have unions and we cannot. */
- for (i = 0; VEC_iterate (tree, sv, i, subvar); ++i)
- bitmap_set_bit (into, DECL_UID (subvar));
- }
- else if (TREE_CODE (vi->decl) == VAR_DECL
- || TREE_CODE (vi->decl) == PARM_DECL
- || TREE_CODE (vi->decl) == RESULT_DECL)
- {
- subvar_t sv;
- if (var_can_have_subvars (vi->decl)
- && (sv = get_subvars_for_var (vi->decl)))
- {
- /* If VI->DECL is an aggregate for which we created
- SFTs, add the SFT corresponding to VI->OFFSET.
- If we didn't do field-sensitive PTA we need to to
- add all overlapping SFTs. */
- unsigned int j;
- tree sft = get_first_overlapping_subvar (sv, vi->offset,
- vi->size, &j);
- gcc_assert (sft);
- for (; VEC_iterate (tree, sv, j, sft); ++j)
- {
- if (SFT_OFFSET (sft) > vi->offset
- && vi->size <= SFT_OFFSET (sft) - vi->offset)
- break;
-
- var_alias_set = get_alias_set (sft);
- if (no_tbaa_pruning
- || (!is_derefed && !vi->directly_dereferenced)
- || alias_sets_conflict_p (ptr_alias_set, var_alias_set))
- {
- bitmap_set_bit (into, DECL_UID (sft));
-
- /* Pointed-to SFTs are needed by the operand scanner
- to adjust offsets when adding operands to memory
- expressions that dereference PTR. This means
- that memory partitioning may not partition
- this SFT because the operand scanner will not
- be able to find the other SFTs next to this
- one. But we only need to do this if the pointed
- to type is aggregate. */
- if (SFT_BASE_FOR_COMPONENTS_P (sft))
- SFT_UNPARTITIONABLE_P (sft) = true;
- }
- }
- }
+ /* Just add VI->DECL to the alias set.
+ Don't type prune artificial vars. */
+ if (vi->is_artificial_var)
+ bitmap_set_bit (into, DECL_UID (vi->decl));
else
{
- /* Otherwise, just add VI->DECL to the alias set.
- Don't type prune artificial vars. */
- if (vi->is_artificial_var)
- bitmap_set_bit (into, DECL_UID (vi->decl));
- else
- {
- var_alias_set = get_alias_set (vi->decl);
- if (no_tbaa_pruning
- || (!is_derefed && !vi->directly_dereferenced)
- || alias_sets_conflict_p (ptr_alias_set, var_alias_set))
- bitmap_set_bit (into, DECL_UID (vi->decl));
- }
+ alias_set_type var_alias_set, ptr_alias_set;
+ var_alias_set = get_alias_set (vi->decl);
+ ptr_alias_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
+ if (no_tbaa_pruning
+ || (!is_derefed && !vi->directly_dereferenced)
+ || alias_sets_conflict_p (ptr_alias_set, var_alias_set))
+ bitmap_set_bit (into, DECL_UID (vi->decl));
}
}
}
/* 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;
+ return false;
}
else
{
return true;
}
- if (is_virtual && var_ann (SSA_NAME_VAR (ssa_name))
- && get_subvars_for_var (SSA_NAME_VAR (ssa_name)) != NULL)
- {
- error ("found real variable when subvariables should have appeared");
- return true;
- }
-
if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)
&& !IS_EMPTY_STMT (SSA_NAME_DEF_STMT (ssa_name)))
{
FOR_EACH_REFERENCED_VAR (var, rvi)
{
if (!is_global_var (var)
- && (!MTAG_P (var) || TREE_CODE (var) == STRUCT_FIELD_TAG)
+ && !MTAG_P (var)
&& (gimple_aliases_computed_p (cfun) ? is_call_clobbered (var)
: TREE_ADDRESSABLE (var)))
return false;
else
set_symbol_mem_tag (vect_ptr, tag);
- var_ann (vect_ptr)->subvars = DR_SUBVARS (dr);
-
/** Note: If the dataref is in an inner-loop nested in LOOP, and we are
vectorizing LOOP (i.e. outer-loop vectorization), we need to create two
def-use update cycles for the pointer: One relative to the outer-loop
tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[LABEL_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[FIELD_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[NAME_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[SYMBOL_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[SYMBOL_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_STRUCT_FIELD_TAG] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_PARTITION_TAG] = 1;
tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
case NAME_MEMORY_TAG:
case SYMBOL_MEMORY_TAG:
return sizeof (struct tree_memory_tag);
- case STRUCT_FIELD_TAG:
- return sizeof (struct tree_struct_field_tag);
case MEMORY_PARTITION_TAG:
return sizeof (struct tree_memory_partition_tag);
default:
return TS_FUNCTION_DECL;
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
- case STRUCT_FIELD_TAG:
case MEMORY_PARTITION_TAG:
return TS_MEMORY_TAG;
default:
/* Memory tags used in tree-ssa to represent memory locations in
virtual SSA. */
-DEFTREECODE (STRUCT_FIELD_TAG, "struct_field_tag", tcc_declaration, 0)
DEFTREECODE (NAME_MEMORY_TAG, "name_memory_tag", tcc_declaration, 0)
DEFTREECODE (SYMBOL_MEMORY_TAG, "symbol_memory_tag", tcc_declaration, 0)
DEFTREECODE (MEMORY_PARTITION_TAG, "memory_partition_tag", tcc_declaration, 0)
/* Nonzero if CODE represents a memory tag. */
#define MTAG_P(CODE) \
- (TREE_CODE (CODE) == STRUCT_FIELD_TAG \
- || TREE_CODE (CODE) == NAME_MEMORY_TAG \
+ (TREE_CODE (CODE) == NAME_MEMORY_TAG \
|| TREE_CODE (CODE) == SYMBOL_MEMORY_TAG \
|| TREE_CODE (CODE) == MEMORY_PARTITION_TAG)
/* True if this tag has global scope. */
unsigned int is_global : 1;
-
- /* True if this tag is the first field of an aggregate type that
- can be used to find adjacent SFTs belonging to the same aggregate. */
- unsigned int base_for_components : 1;
-
- /* True if this tag should not be grouped into a memory partition. */
- unsigned int unpartitionable : 1;
};
#define MTAG_GLOBAL(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.is_global)
#define MTAG_ALIASES(NODE) (TREE_MEMORY_TAG_CHECK (NODE)->mtag.aliases)
-struct tree_struct_field_tag GTY(())
-{
- struct tree_memory_tag common;
-
- /* Parent variable. */
- tree parent_var;
-
- /* Offset inside structure. */
- unsigned HOST_WIDE_INT offset;
-
- /* Size of the field. */
- unsigned HOST_WIDE_INT size;
-
- /* Alias set for a DECL_NONADDRESSABLE_P field. Otherwise -1. */
- alias_set_type alias_set;
-};
-#define SFT_PARENT_VAR(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.parent_var)
-#define SFT_OFFSET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.offset)
-#define SFT_SIZE(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.size)
-#define SFT_NONADDRESSABLE_P(NODE) \
- (STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set != -1)
-#define SFT_ALIAS_SET(NODE) (STRUCT_FIELD_TAG_CHECK (NODE)->sft.alias_set)
-#define SFT_UNPARTITIONABLE_P(NODE) \
- (STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.unpartitionable)
-#define SFT_BASE_FOR_COMPONENTS_P(NODE) \
- (STRUCT_FIELD_TAG_CHECK (NODE)->sft.common.base_for_components)
-
/* Memory Partition Tags (MPTs) group memory symbols under one
common name for the purposes of placing memory PHI nodes. */
struct tree_value_handle GTY ((tag ("TS_VALUE_HANDLE"))) value_handle;
struct tree_constructor GTY ((tag ("TS_CONSTRUCTOR"))) constructor;
struct tree_memory_tag GTY ((tag ("TS_MEMORY_TAG"))) mtag;
- struct tree_struct_field_tag GTY ((tag ("TS_STRUCT_FIELD_TAG"))) sft;
struct tree_omp_clause GTY ((tag ("TS_OMP_CLAUSE"))) omp_clause;
struct tree_memory_partition_tag GTY ((tag ("TS_MEMORY_PARTITION_TAG"))) mpt;
};