if (aliases_computed_p)
{
unsigned i;
- basic_block bb;
- /* Make sure that every statement has a valid set of operands.
- If a statement needs to be scanned for operands while we
- compute aliases, it may get erroneous operands because all
- the alias relations are not built at that point.
- FIXME: This code will become obsolete when operands are not
- lazily updated. */
- FOR_EACH_BB (bb)
- {
- block_stmt_iterator si;
- for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- get_stmt_operands (bsi_stmt (si));
- }
-
/* Similarly, clear the set of addressable variables. In this
case, we can just clear the set because addressability is
only computed here. */
statement. Note that this will miss all the addresses taken
in PHI nodes (those are discovered while following the use-def
chains). */
- get_stmt_operands (stmt);
addr_taken = addresses_taken (stmt);
if (addr_taken)
EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
if (!tag_stored_p && !var_stored_p)
continue;
- if ((unmodifiable_var_p (tag) && !unmodifiable_var_p (var))
- || (unmodifiable_var_p (var) && !unmodifiable_var_p (tag)))
- continue;
-
if (may_alias_p (p_map->var, p_map->set, var, v_map->set))
{
subvar_t svars;
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;
+ }
+
m_ann = var_ann (mem);
gcc_assert (m_ann->mem_tag_kind == TYPE_TAG);
}
/* Neither operand is a pointer? VAR can be pointing anywhere.
- FIXME: Shouldn't we abort here? If we get here, we found
+ FIXME: Shouldn't we asserting here? If we get here, we found
PTR = INT_CST + INT_CST, which should not be a valid pointer
expression. */
if (!(POINTER_TYPE_P (TREE_TYPE (op0))
for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++)
{
struct alias_map_d *curr = ai->pointers[i];
- if (tag_set == curr->set)
+ tree curr_tag = var_ann (curr->var)->type_mem_tag;
+ if (tag_set == curr->set
+ && TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (curr_tag)))
{
- tag = var_ann (curr->var)->type_mem_tag;
+ tag = curr_tag;
break;
}
}
pointed-to type. */
gcc_assert (tag_set == get_alias_set (tag));
+ /* If PTR's pointed-to type is read-only, then TAG's type must also
+ be read-only. */
+ gcc_assert (TYPE_READONLY (tag_type) == TYPE_READONLY (TREE_TYPE (tag)));
+
return tag;
}
{
tree field;
HOST_WIDE_INT offset;
-} *fieldoff_t;
+} fieldoff_s;
-DEF_VEC_MALLOC_P(fieldoff_t);
+DEF_VEC_O (fieldoff_s);
+DEF_VEC_ALLOC_O(fieldoff_s,heap);
/* Return the position, in bits, of FIELD_DECL from the beginning of its
structure.
/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all the fields
of TYPE onto fieldstack, recording their offsets along the way.
OFFSET is used to keep track of the offset in this entire structure, rather
- than just the immediately containing structure. */
+ than just the immediately containing structure. Returns the number
+ of fields pushed. */
-static void
-push_fields_onto_fieldstack (tree type, VEC(fieldoff_t) **fieldstack,
+static int
+push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
HOST_WIDE_INT offset)
{
- fieldoff_t pair;
- tree field = TYPE_FIELDS (type);
- if (!field)
- return;
- if (var_can_have_subvars (field)
- && TREE_CODE (field) == FIELD_DECL)
- {
- size_t before = VEC_length (fieldoff_t, *fieldstack);
- /* Empty structures may have actual size, like in C++. So see if we
- actually end up pushing a field, and if not, if the size is nonzero,
- push the field onto the stack */
- push_fields_onto_fieldstack (TREE_TYPE (field), fieldstack, offset);
- if (before == VEC_length (fieldoff_t, *fieldstack)
- && DECL_SIZE (field)
- && !integer_zerop (DECL_SIZE (field)))
- {
- pair = xmalloc (sizeof (struct fieldoff));
- pair->field = field;
- pair->offset = offset;
- VEC_safe_push (fieldoff_t, *fieldstack, pair);
- }
- }
- else if (TREE_CODE (field) == FIELD_DECL)
- {
- pair = xmalloc (sizeof (struct fieldoff));
- pair->field = field;
- pair->offset = offset + bitpos_of_field (field);
- VEC_safe_push (fieldoff_t, *fieldstack, pair);
- }
- for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field))
- {
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
- if (var_can_have_subvars (field))
- {
- size_t before = VEC_length (fieldoff_t, *fieldstack);
- push_fields_onto_fieldstack (TREE_TYPE (field), fieldstack,
- offset + bitpos_of_field (field));
- /* Empty structures may have actual size, like in C++. So see if we
- actually end up pushing a field, and if not, if the size is nonzero,
- push the field onto the stack */
- if (before == VEC_length (fieldoff_t, *fieldstack)
- && DECL_SIZE (field)
- && !integer_zerop (DECL_SIZE (field)))
- {
- pair = xmalloc (sizeof (struct fieldoff));
- pair->field = field;
- pair->offset = offset + bitpos_of_field (field);
- VEC_safe_push (fieldoff_t, *fieldstack, pair);
- }
- }
- else
- {
- pair = xmalloc (sizeof (struct fieldoff));
- pair->field = field;
- pair->offset = offset + bitpos_of_field (field);
- VEC_safe_push (fieldoff_t, *fieldstack, pair);
- }
- }
+ tree field;
+ int count = 0;
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ bool push = false;
+
+ if (!var_can_have_subvars (field))
+ push = true;
+ else if (!(push_fields_onto_fieldstack
+ (TREE_TYPE (field), fieldstack,
+ offset + bitpos_of_field (field)))
+ && DECL_SIZE (field)
+ && !integer_zerop (DECL_SIZE (field)))
+ /* Empty structures may have actual size, like in C++. So
+ see if we didn't push any subfields and the size is
+ nonzero, push the field onto the stack */
+ push = true;
+
+ if (push)
+ {
+ fieldoff_s *pair;
+
+ pair = VEC_safe_push (fieldoff_s, heap, *fieldstack, NULL);
+ pair->field = field;
+ pair->offset = offset + bitpos_of_field (field);
+ count++;
+ }
+ }
+ return count;
}
return up;
}
-/* qsort comparison function for two fieldoff_t's PA and PB */
+/* qsort comparison function for two fieldoff's PA and PB */
static int
fieldoff_compare (const void *pa, const void *pb)
{
- const fieldoff_t foa = *(fieldoff_t *)pa;
- const fieldoff_t fob = *(fieldoff_t *)pb;
+ const fieldoff_s *foa = (const fieldoff_s *)pa;
+ const fieldoff_s *fob = (const fieldoff_s *)pb;
HOST_WIDE_INT foasize, fobsize;
+
if (foa->offset != fob->offset)
return foa->offset - fob->offset;
foasize = TREE_INT_CST_LOW (DECL_SIZE (foa->field));
fobsize = TREE_INT_CST_LOW (DECL_SIZE (fob->field));
- if (foasize != fobsize)
- return foasize - fobsize;
- return 0;
+ return foasize - fobsize;
}
/* Given an aggregate VAR, create the subvariables that represent its
static void
create_overlap_variables_for (tree var)
{
- VEC(fieldoff_t) *fieldstack = NULL;
+ VEC(fieldoff_s,heap) *fieldstack = NULL;
used_part_t up;
size_t uid = var_ann (var)->uid;
up = used_portions[uid];
push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0);
- if (VEC_length (fieldoff_t, fieldstack) != 0)
+ if (VEC_length (fieldoff_s, fieldstack) != 0)
{
subvar_t *subvars;
- fieldoff_t fo;
+ fieldoff_s *fo;
bool notokay = false;
int fieldcount = 0;
int i;
currently don't. Doing so would require some extra changes to
tree-ssa-operands.c. */
- for (i = 0; VEC_iterate (fieldoff_t, fieldstack, i, fo); i++)
+ for (i = 0; VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
{
if (!DECL_SIZE (fo->field)
|| TREE_CODE (DECL_SIZE (fo->field)) != INTEGER_CST
notokay = true;
}
-
- /* Cleanup after ourselves if we can't create overlap variables. */
+ /* Bail out, if we can't create overlap variables. */
if (notokay)
{
- while (VEC_length (fieldoff_t, fieldstack) != 0)
- {
- fo = VEC_pop (fieldoff_t, fieldstack);
- free (fo);
- }
- VEC_free (fieldoff_t, fieldstack);
+ VEC_free (fieldoff_s, heap, fieldstack);
return;
}
+
/* Otherwise, create the variables. */
subvars = lookup_subvars_for_var (var);
- qsort (VEC_address (fieldoff_t, fieldstack),
- VEC_length (fieldoff_t, fieldstack),
- sizeof (fieldoff_t),
+ qsort (VEC_address (fieldoff_s, fieldstack),
+ VEC_length (fieldoff_s, fieldstack),
+ sizeof (fieldoff_s),
fieldoff_compare);
- while (VEC_length (fieldoff_t, fieldstack) != 0)
+ for (i = VEC_length (fieldoff_s, fieldstack);
+ VEC_iterate (fieldoff_s, fieldstack, --i, fo);)
{
subvar_t sv;
HOST_WIDE_INT fosize;
var_ann_t ann;
tree currfotype;
- fo = VEC_pop (fieldoff_t, fieldstack);
fosize = TREE_INT_CST_LOW (DECL_SIZE (fo->field));
currfotype = TREE_TYPE (fo->field);
|| (fo->offset == lastfooffset
&& fosize == lastfosize
&& currfotype == lastfotype))
- {
- free (fo);
- continue;
- }
+ continue;
sv = ggc_alloc (sizeof (struct subvar));
sv->offset = fo->offset;
sv->size = fosize;
fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
sv->size);
fprintf (dump_file, "\n");
-
}
/* We need to copy the various flags from var to sv->var, so that
lastfooffset = fo->offset;
lastfosize = fosize;
*subvars = sv;
- free (fo);
}
/* Once we have created subvars, the original is no longer call
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_t, fieldstack);
+ VEC_free (fieldoff_s, heap, fieldstack);
}