#include "obstack.h"
#include "bitmap.h"
#include "flags.h"
+#include "rtl.h"
#include "tm_p.h"
+#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
#include "tree.h"
#include "tree-flow.h"
#include "tree-inline.h"
+#include "varray.h"
#include "diagnostic.h"
#include "toplev.h"
#include "gimple.h"
/* True if this field may contain pointers. */
unsigned int may_have_pointers : 1;
- /* True if this field has only restrict qualified pointers. */
- unsigned int only_restrict_pointers : 1;
-
/* True if this represents a global variable. */
unsigned int is_global_var : 1;
ret->is_heap_var = false;
ret->is_restrict_var = false;
ret->may_have_pointers = true;
- ret->only_restrict_pointers = false;
ret->is_global_var = (t == NULL_TREE);
ret->is_fn_info = false;
if (t && DECL_P (t))
ret->oldsolution = BITMAP_ALLOC (&oldpta_obstack);
ret->next = NULL;
- stats.total_vars++;
-
VEC_safe_push (varinfo_t, heap, varmap, ret);
return ret;
unsigned int j;
bitmap_iterator bi;
HOST_WIDE_INT loff = c->lhs.offset;
- bool escaped_p = false;
/* Our IL does not allow this. */
gcc_assert (c->rhs.offset == 0);
unsigned int t;
HOST_WIDE_INT fieldoffset = v->offset + loff;
+ /* If v is a global variable then this is an escape point. */
+ if (v->is_global_var)
+ {
+ t = find (escaped_id);
+ if (add_graph_edge (graph, t, rhs)
+ && bitmap_ior_into (get_varinfo (t)->solution, sol)
+ && !TEST_BIT (changed, t))
+ {
+ SET_BIT (changed, t);
+ changed_count++;
+ }
+ }
+
+ if (v->is_special_var)
+ continue;
+
if (v->is_full_var)
fieldoffset = v->offset;
else if (loff != 0)
{
if (v->may_have_pointers)
{
- /* If v is a global variable then this is an escape point. */
- if (v->is_global_var
- && !escaped_p)
- {
- t = find (escaped_id);
- if (add_graph_edge (graph, t, rhs)
- && bitmap_ior_into (get_varinfo (t)->solution, sol)
- && !TEST_BIT (changed, t))
- {
- SET_BIT (changed, t);
- changed_count++;
- }
- /* Enough to let rhs escape once. */
- escaped_p = true;
- }
-
- if (v->is_special_var)
- break;
-
t = find (v->id);
if (add_graph_edge (graph, t, rhs)
&& bitmap_ior_into (get_varinfo (t)->solution, sol)
static const char *
alias_get_name (tree decl)
{
- const char *res;
+ const char *res = get_name (decl);
char *temp;
int num_printed = 0;
- if (DECL_ASSEMBLER_NAME_SET_P (decl))
- res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- else
- res= get_name (decl);
if (res != NULL)
return res;
if (TREE_CODE (type) == ARRAY_TYPE)
return type_could_have_pointers (TREE_TYPE (type));
- /* A function or method can consume pointers.
- ??? We could be more precise here. */
- if (TREE_CODE (type) == FUNCTION_TYPE
- || TREE_CODE (type) == METHOD_TYPE)
- return true;
-
return AGGREGATE_TYPE_P (type);
}
static bool
could_have_pointers (tree t)
{
- return (((TREE_CODE (t) == VAR_DECL
- || TREE_CODE (t) == PARM_DECL
- || TREE_CODE (t) == RESULT_DECL)
- && (TREE_PUBLIC (t) || DECL_EXTERNAL (t) || TREE_ADDRESSABLE (t)))
- || type_could_have_pointers (TREE_TYPE (t)));
+ return type_could_have_pointers (TREE_TYPE (t));
}
/* Return the position, in bits, of FIELD_DECL from the beginning of its
in that case *NULL does not fail, so it _should_ alias *anything.
It is not worth adding a new option or renaming the existing one,
since this case is relatively obscure. */
- if ((TREE_CODE (t) == INTEGER_CST
- && integer_zerop (t))
- /* The only valid CONSTRUCTORs in gimple with pointer typed
- elements are zero-initializer. But in IPA mode we also
- process global initializers, so verify at least. */
- || (TREE_CODE (t) == CONSTRUCTOR
- && CONSTRUCTOR_NELTS (t) == 0))
- {
- if (flag_delete_null_pointer_checks)
- temp.var = nothing_id;
- else
- temp.var = anything_id;
+ if (flag_delete_null_pointer_checks
+ && ((TREE_CODE (t) == INTEGER_CST
+ && integer_zerop (t))
+ /* The only valid CONSTRUCTORs in gimple with pointer typed
+ elements are zero-initializer. */
+ || TREE_CODE (t) == CONSTRUCTOR))
+ {
+ temp.var = nothing_id;
temp.type = ADDRESSOF;
temp.offset = 0;
VEC_safe_push (ce_s, heap, *results, &temp);
get_constraint_for_ssa_var (t, results, address_p);
return;
}
- case CONSTRUCTOR:
- {
- unsigned int i;
- tree val;
- VEC (ce_s, heap) *tmp = NULL;
- FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (t), i, val)
- {
- struct constraint_expr *rhsp;
- unsigned j;
- get_constraint_for_1 (val, &tmp, address_p);
- for (j = 0; VEC_iterate (ce_s, tmp, j, rhsp); ++j)
- VEC_safe_push (ce_s, heap, *results, rhsp);
- VEC_truncate (ce_s, tmp, 0);
- }
- VEC_free (ce_s, heap, tmp);
- /* We do not know whether the constructor was complete,
- so technically we have to add &NOTHING or &ANYTHING
- like we do for an empty constructor as well. */
- return;
- }
default:;
}
break;
process_constraint (new_constraint (lhs, rhs));
}
-/* Create a new artificial heap variable with NAME.
- Return the created variable. */
+/* Create a new artificial heap variable with NAME and make a
+ constraint from it to LHS. Return the created variable. */
static varinfo_t
-make_heapvar_for (varinfo_t lhs, const char *name)
+make_constraint_from_heapvar (varinfo_t lhs, const char *name)
{
varinfo_t vi;
tree heapvar = heapvar_lookup (lhs->decl, lhs->offset);
vi->is_full_var = true;
insert_vi_for_tree (heapvar, vi);
- return vi;
-}
-
-/* Create a new artificial heap variable with NAME and make a
- constraint from it to LHS. Return the created variable. */
-
-static varinfo_t
-make_constraint_from_heapvar (varinfo_t lhs, const char *name)
-{
- varinfo_t vi = make_heapvar_for (lhs, name);
make_constraint_from (lhs, vi->id);
return vi;
else if (TREE_CODE (fi->decl) == FUNCTION_DECL)
{
varinfo_t ai = first_vi_for_offset (fi, part);
- if (ai)
- c.var = ai->id;
- else
- c.var = anything_id;
+ c.var = ai ? ai->id : anything_id;
c.offset = 0;
c.type = SCALAR;
}
{
struct constraint_expr rhsc;
unsigned i;
- bool returns_uses = false;
for (i = 0; i < gimple_call_num_args (stmt); ++i)
{
tree arg = gimple_call_arg (stmt, i);
- int flags = gimple_call_arg_flags (stmt, i);
- /* If the argument is not used or it does not contain pointers
- we can ignore it. */
- if ((flags & EAF_UNUSED)
- || !could_have_pointers (arg))
- continue;
-
- /* As we compute ESCAPED context-insensitive we do not gain
- any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
- set. The argument would still get clobbered through the
- escape solution.
- ??? We might get away with less (and more precise) constraints
- if using a temporary for transitively closing things. */
- if ((flags & EAF_NOCLOBBER)
- && (flags & EAF_NOESCAPE))
- {
- varinfo_t uses = get_call_use_vi (stmt);
- if (!(flags & EAF_DIRECT))
- make_transitive_closure_constraints (uses);
- make_constraint_to (uses->id, arg);
- returns_uses = true;
- }
- else if (flags & EAF_NOESCAPE)
- {
- varinfo_t uses = get_call_use_vi (stmt);
- varinfo_t clobbers = get_call_clobber_vi (stmt);
- if (!(flags & EAF_DIRECT))
- {
- make_transitive_closure_constraints (uses);
- make_transitive_closure_constraints (clobbers);
- }
- make_constraint_to (uses->id, arg);
- make_constraint_to (clobbers->id, arg);
- returns_uses = true;
- }
- else
+ /* Find those pointers being passed, and make sure they end up
+ pointing to anything. */
+ if (could_have_pointers (arg))
make_escape_constraint (arg);
}
- /* If we added to the calls uses solution make sure we account for
- pointers to it to be returned. */
- if (returns_uses)
- {
- rhsc.var = get_call_use_vi (stmt)->id;
- rhsc.offset = 0;
- rhsc.type = SCALAR;
- VEC_safe_push (ce_s, heap, *results, &rhsc);
- }
-
/* The static chain escapes as well. */
if (gimple_call_chain (stmt))
make_escape_constraint (gimple_call_chain (stmt));
the LHS point to global and escaped variables. */
static void
-handle_lhs_call (gimple stmt, tree lhs, int flags, VEC(ce_s, heap) *rhsc,
- tree fndecl)
+handle_lhs_call (tree lhs, int flags, VEC(ce_s, heap) *rhsc, tree fndecl)
{
VEC(ce_s, heap) *lhsc = NULL;
get_constraint_for (lhs, &lhsc);
- /* If the store is to a global decl make sure to
- add proper escape constraints. */
- lhs = get_base_address (lhs);
- if (lhs
- && DECL_P (lhs)
- && is_global_var (lhs))
- {
- struct constraint_expr tmpc;
- tmpc.var = escaped_id;
- tmpc.offset = 0;
- tmpc.type = SCALAR;
- VEC_safe_push (ce_s, heap, lhsc, &tmpc);
- }
-
- /* If the call returns an argument unmodified override the rhs
- constraints. */
- flags = gimple_call_return_flags (stmt);
- if (flags & ERF_RETURNS_ARG
- && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (stmt))
- {
- tree arg;
- rhsc = NULL;
- arg = gimple_call_arg (stmt, flags & ERF_RETURN_ARG_MASK);
- get_constraint_for (arg, &rhsc);
- process_all_all_constraints (lhsc, rhsc);
- VEC_free (ce_s, heap, rhsc);
- }
- else if (flags & ERF_NOALIAS)
+
+ if (flags & ECF_MALLOC)
{
varinfo_t vi;
- struct constraint_expr tmpc;
- rhsc = NULL;
- vi = make_heapvar_for (get_vi_for_tree (lhs), "HEAP");
+ vi = make_constraint_from_heapvar (get_vi_for_tree (lhs), "HEAP");
/* We delay marking allocated storage global until we know if
it escapes. */
DECL_EXTERNAL (vi->decl) = 0;
vi->is_global_var = 0;
/* If this is not a real malloc call assume the memory was
- initialized and thus may point to global memory. All
+ initialized and thus may point to global memory. All
builtin functions with the malloc attribute behave in a sane way. */
if (!fndecl
|| DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL)
make_constraint_from (vi, nonlocal_id);
- tmpc.var = vi->id;
- tmpc.offset = 0;
- tmpc.type = ADDRESSOF;
- VEC_safe_push (ce_s, heap, rhsc, &tmpc);
}
-
- process_all_all_constraints (lhsc, rhsc);
-
+ else if (VEC_length (ce_s, rhsc) > 0)
+ {
+ /* If the store is to a global decl make sure to
+ add proper escape constraints. */
+ lhs = get_base_address (lhs);
+ if (lhs
+ && DECL_P (lhs)
+ && is_global_var (lhs))
+ {
+ struct constraint_expr tmpc;
+ tmpc.var = escaped_id;
+ tmpc.offset = 0;
+ tmpc.type = SCALAR;
+ VEC_safe_push (ce_s, heap, lhsc, &tmpc);
+ }
+ process_all_all_constraints (lhsc, rhsc);
+ }
VEC_free (ce_s, heap, lhsc);
}
handle_rhs_call (t, &rhsc);
if (gimple_call_lhs (t)
&& could_have_pointers (gimple_call_lhs (t)))
- handle_lhs_call (t, gimple_call_lhs (t), flags, rhsc, fndecl);
+ handle_lhs_call (gimple_call_lhs (t), flags, rhsc, fndecl);
VEC_free (ce_s, heap, rhsc);
}
else
/* If we are returning a value, assign it to the result. */
lhsop = gimple_call_lhs (t);
if (lhsop
- && type_could_have_pointers (TREE_TYPE (lhsop)))
+ && could_have_pointers (lhsop))
{
struct constraint_expr rhs;
struct constraint_expr *lhsp;
operations with pointer result, others are dealt with as escape
points if they have pointer operands. */
else if (is_gimple_assign (t)
- && type_could_have_pointers (TREE_TYPE (gimple_assign_lhs (t))))
+ && could_have_pointers (gimple_assign_lhs (t)))
{
/* Otherwise, just a regular assignment statement. */
tree lhsop = gimple_assign_lhs (t);
}
+/* Insert the varinfo FIELD into the field list for BASE, at the front
+ of the list. */
+
+static void
+insert_into_field_list (varinfo_t base, varinfo_t field)
+{
+ varinfo_t prev = base;
+ varinfo_t curr = base->next;
+
+ field->next = curr;
+ prev->next = field;
+}
+
/* This structure is used during pushing fields onto the fieldstack
to track the offset of the field, since bitpos_of_field gives it
relative to its immediate containing type, and we want it relative
OFFSET is used to keep track of the offset in this entire
structure, rather than just the immediately containing structure.
- Returns false if the caller is supposed to handle the field we
- recursed for. */
+ Returns the number of fields pushed. */
-static bool
+static int
push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
- HOST_WIDE_INT offset, bool must_have_pointers_p)
+ HOST_WIDE_INT offset)
{
tree field;
- bool empty_p = true;
+ int count = 0;
if (TREE_CODE (type) != RECORD_TYPE)
- return false;
+ return 0;
/* If the vector of fields is growing too big, bail out early.
Callers check for VEC_length <= MAX_FIELDS_FOR_FIELD_SENSITIVE, make
sure this fails. */
if (VEC_length (fieldoff_s, *fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
- return false;
+ return 0;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
bool push = false;
+ int pushed = 0;
HOST_WIDE_INT foff = bitpos_of_field (field);
if (!var_can_have_subvars (field)
|| TREE_CODE (TREE_TYPE (field)) == QUAL_UNION_TYPE
|| TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
push = true;
- else if (!push_fields_onto_fieldstack
- (TREE_TYPE (field), fieldstack, offset + foff,
- must_have_pointers_p)
+ else if (!(pushed = push_fields_onto_fieldstack
+ (TREE_TYPE (field), fieldstack, offset + foff))
&& (DECL_SIZE (field)
&& !integer_zerop (DECL_SIZE (field))))
/* Empty structures may have actual size, like in C++. So
/* If adjacent fields do not contain pointers merge them. */
if (pair
&& !pair->may_have_pointers
+ && !could_have_pointers (field)
&& !pair->has_unknown_size
&& !has_unknown_size
- && pair->offset + (HOST_WIDE_INT)pair->size == offset + foff
- && !must_have_pointers_p
- && !could_have_pointers (field))
+ && pair->offset + (HOST_WIDE_INT)pair->size == offset + foff)
{
+ pair = VEC_last (fieldoff_s, *fieldstack);
pair->size += TREE_INT_CST_LOW (DECL_SIZE (field));
}
else
pair->size = TREE_INT_CST_LOW (DECL_SIZE (field));
else
pair->size = -1;
- pair->may_have_pointers
- = must_have_pointers_p || could_have_pointers (field);
+ pair->may_have_pointers = could_have_pointers (field);
pair->only_restrict_pointers
= (!has_unknown_size
&& POINTER_TYPE_P (TREE_TYPE (field))
&& TYPE_RESTRICT (TREE_TYPE (field)));
+ count++;
}
}
-
- empty_p = false;
+ else
+ count += pushed;
}
- return !empty_p;
+ return count;
}
/* Count the number of arguments DECL has, and set IS_VARARGS to true
/* Creation function node for DECL, using NAME, and return the index
of the variable we've created for the function. */
-static varinfo_t
+static unsigned int
create_function_info_for (tree decl, const char *name)
{
struct function *fn = DECL_STRUCT_FUNCTION (decl);
vi->fullsize = ~0;
insert_vi_for_tree (vi->decl, vi);
+ stats.total_vars++;
+
prev_vi = vi;
/* Create a variable for things the function clobbers and one for
gcc_assert (prev_vi->offset < clobbervi->offset);
prev_vi->next = clobbervi;
prev_vi = clobbervi;
+ stats.total_vars++;
asprintf (&tempname, "%s.use", name);
newname = ggc_strdup (tempname);
gcc_assert (prev_vi->offset < usevi->offset);
prev_vi->next = usevi;
prev_vi = usevi;
+ stats.total_vars++;
}
/* And one for the static chain. */
gcc_assert (prev_vi->offset < chainvi->offset);
prev_vi->next = chainvi;
prev_vi = chainvi;
+ stats.total_vars++;
insert_vi_for_tree (fn->static_chain_decl, chainvi);
}
gcc_assert (prev_vi->offset < resultvi->offset);
prev_vi->next = resultvi;
prev_vi = resultvi;
+ stats.total_vars++;
if (DECL_RESULT (decl))
insert_vi_for_tree (DECL_RESULT (decl), resultvi);
}
gcc_assert (prev_vi->offset < argvi->offset);
prev_vi->next = argvi;
prev_vi = argvi;
+ stats.total_vars++;
if (arg)
{
insert_vi_for_tree (arg, argvi);
gcc_assert (prev_vi->offset < argvi->offset);
prev_vi->next = argvi;
prev_vi = argvi;
+ stats.total_vars++;
}
- return vi;
+ return vi->id;
}
This will also create any varinfo structures necessary for fields
of DECL. */
-static varinfo_t
-create_variable_info_for_1 (tree decl, const char *name)
+static unsigned int
+create_variable_info_for (tree decl, const char *name)
{
- varinfo_t vi, newvi;
+ varinfo_t vi;
tree decl_type = TREE_TYPE (decl);
tree declsize = DECL_P (decl) ? DECL_SIZE (decl) : TYPE_SIZE (decl_type);
VEC (fieldoff_s,heap) *fieldstack = NULL;
- fieldoff_s *fo;
- unsigned int i;
+ if (var_can_have_subvars (decl) && use_field_sensitive)
+ push_fields_onto_fieldstack (decl_type, &fieldstack, 0);
+
+ /* If the variable doesn't have subvars, we may end up needing to
+ sort the field list and create fake variables for all the
+ fields. */
+ vi = new_var_info (decl, name);
+ vi->offset = 0;
+ vi->may_have_pointers = could_have_pointers (decl);
if (!declsize
|| !host_integerp (declsize, 1))
{
- vi = new_var_info (decl, name);
- vi->offset = 0;
- vi->size = ~0;
- vi->fullsize = ~0;
vi->is_unknown_size_var = true;
- vi->is_full_var = true;
- vi->may_have_pointers = could_have_pointers (decl);
- return vi;
- }
-
- /* Collect field information. */
- if (use_field_sensitive
- && var_can_have_subvars (decl)
- /* ??? Force us to not use subfields for global initializers
- in IPA mode. Else we'd have to parse arbitrary initializers. */
- && !(in_ipa_mode
- && is_global_var (decl)
- && DECL_INITIAL (decl)))
- {
- fieldoff_s *fo = NULL;
- bool notokay = false;
- unsigned int i;
-
- push_fields_onto_fieldstack (decl_type, &fieldstack, 0,
- TREE_PUBLIC (decl)
- || DECL_EXTERNAL (decl)
- || TREE_ADDRESSABLE (decl));
-
- for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
- if (fo->has_unknown_size
- || fo->offset < 0)
- {
- notokay = true;
- break;
- }
-
- /* We can't sort them if we have a field with a variable sized type,
- which will make notokay = true. In that case, we are going to return
- without creating varinfos for the fields anyway, so sorting them is a
- waste to boot. */
- if (!notokay)
- {
- sort_fieldstack (fieldstack);
- /* Due to some C++ FE issues, like PR 22488, we might end up
- what appear to be overlapping fields even though they,
- in reality, do not overlap. Until the C++ FE is fixed,
- we will simply disable field-sensitivity for these cases. */
- notokay = check_for_overlaps (fieldstack);
- }
-
- if (notokay)
- VEC_free (fieldoff_s, heap, fieldstack);
+ vi->fullsize = ~0;
+ vi->size = ~0;
}
-
- /* If we didn't end up collecting sub-variables create a full
- variable for the decl. */
- if (VEC_length (fieldoff_s, fieldstack) <= 1
- || VEC_length (fieldoff_s, fieldstack) > MAX_FIELDS_FOR_FIELD_SENSITIVE)
+ else
{
- vi = new_var_info (decl, name);
- vi->offset = 0;
- vi->may_have_pointers = could_have_pointers (decl);
vi->fullsize = TREE_INT_CST_LOW (declsize);
vi->size = vi->fullsize;
- vi->is_full_var = true;
- VEC_free (fieldoff_s, heap, fieldstack);
- return vi;
- }
-
- vi = new_var_info (decl, name);
- vi->fullsize = TREE_INT_CST_LOW (declsize);
- for (i = 0, newvi = vi;
- VEC_iterate (fieldoff_s, fieldstack, i, fo);
- ++i, newvi = newvi->next)
- {
- const char *newname = "NULL";
- char *tempname;
-
- if (dump_file)
- {
- asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
- "+" HOST_WIDE_INT_PRINT_DEC, name, fo->offset, fo->size);
- newname = ggc_strdup (tempname);
- free (tempname);
- }
- newvi->name = newname;
- newvi->offset = fo->offset;
- newvi->size = fo->size;
- newvi->fullsize = vi->fullsize;
- newvi->may_have_pointers = fo->may_have_pointers;
- newvi->only_restrict_pointers = fo->only_restrict_pointers;
- if (i + 1 < VEC_length (fieldoff_s, fieldstack))
- newvi->next = new_var_info (decl, name);
}
- VEC_free (fieldoff_s, heap, fieldstack);
-
- return vi;
-}
-
-static unsigned int
-create_variable_info_for (tree decl, const char *name)
-{
- varinfo_t vi = create_variable_info_for_1 (decl, name);
- unsigned int id = vi->id;
-
- insert_vi_for_tree (decl, vi);
+ insert_vi_for_tree (vi->decl, vi);
- /* Create initial constraints for globals. */
- for (; vi; vi = vi->next)
+ /* ??? The setting of vi->may_have_pointers is too conservative here
+ and may get refined below. Thus we have superfluous constraints
+ here sometimes which triggers the commented assert in
+ dump_sa_points_to_info. */
+ if (vi->is_global_var
+ && vi->may_have_pointers)
{
- if (!vi->may_have_pointers
- || !vi->is_global_var)
- continue;
-
/* Mark global restrict qualified pointers. */
- if ((POINTER_TYPE_P (TREE_TYPE (decl))
- && TYPE_RESTRICT (TREE_TYPE (decl)))
- || vi->only_restrict_pointers)
+ if (POINTER_TYPE_P (TREE_TYPE (decl))
+ && TYPE_RESTRICT (TREE_TYPE (decl)))
make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
/* For escaped variables initialize them from nonlocal. */
IPA mode generate constraints for it. In non-IPA mode
the initializer from nonlocal is all we need. */
if (in_ipa_mode
- && DECL_INITIAL (decl))
+ && DECL_INITIAL (vi->decl))
{
VEC (ce_s, heap) *rhsc = NULL;
struct constraint_expr lhs, *rhsp;
unsigned i;
- get_constraint_for (DECL_INITIAL (decl), &rhsc);
+ get_constraint_for (DECL_INITIAL (vi->decl), &rhsc);
lhs.var = vi->id;
lhs.offset = 0;
lhs.type = SCALAR;
process_constraint (new_constraint (lhs, *rhsp));
}
VEC_free (ce_s, heap, rhsc);
+ /* ??? Force us to not use subfields. Else we'd have to parse
+ arbitrary initializers. */
+ VEC_free (fieldoff_s, heap, fieldstack);
}
}
- return id;
+ stats.total_vars++;
+ if (use_field_sensitive
+ && !vi->is_unknown_size_var
+ && var_can_have_subvars (decl)
+ && VEC_length (fieldoff_s, fieldstack) > 1
+ && VEC_length (fieldoff_s, fieldstack) <= MAX_FIELDS_FOR_FIELD_SENSITIVE)
+ {
+ fieldoff_s *fo = NULL;
+ bool notokay = false;
+ unsigned int i;
+
+ for (i = 0; !notokay && VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+ {
+ if (fo->has_unknown_size
+ || fo->offset < 0)
+ {
+ notokay = true;
+ break;
+ }
+ }
+
+ /* We can't sort them if we have a field with a variable sized type,
+ which will make notokay = true. In that case, we are going to return
+ without creating varinfos for the fields anyway, so sorting them is a
+ waste to boot. */
+ if (!notokay)
+ {
+ sort_fieldstack (fieldstack);
+ /* Due to some C++ FE issues, like PR 22488, we might end up
+ what appear to be overlapping fields even though they,
+ in reality, do not overlap. Until the C++ FE is fixed,
+ we will simply disable field-sensitivity for these cases. */
+ notokay = check_for_overlaps (fieldstack);
+ }
+
+
+ if (VEC_length (fieldoff_s, fieldstack) != 0)
+ fo = VEC_index (fieldoff_s, fieldstack, 0);
+
+ if (fo == NULL || notokay)
+ {
+ vi->is_unknown_size_var = 1;
+ vi->fullsize = ~0;
+ vi->size = ~0;
+ vi->is_full_var = true;
+ VEC_free (fieldoff_s, heap, fieldstack);
+ return vi->id;
+ }
+
+ vi->size = fo->size;
+ vi->offset = fo->offset;
+ vi->may_have_pointers = fo->may_have_pointers;
+ if (vi->is_global_var
+ && vi->may_have_pointers)
+ {
+ if (fo->only_restrict_pointers)
+ make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+ }
+ for (i = VEC_length (fieldoff_s, fieldstack) - 1;
+ i >= 1 && VEC_iterate (fieldoff_s, fieldstack, i, fo);
+ i--)
+ {
+ varinfo_t newvi;
+ const char *newname = "NULL";
+ char *tempname;
+
+ if (dump_file)
+ {
+ asprintf (&tempname, "%s." HOST_WIDE_INT_PRINT_DEC
+ "+" HOST_WIDE_INT_PRINT_DEC,
+ vi->name, fo->offset, fo->size);
+ newname = ggc_strdup (tempname);
+ free (tempname);
+ }
+ newvi = new_var_info (decl, newname);
+ newvi->offset = fo->offset;
+ newvi->size = fo->size;
+ newvi->fullsize = vi->fullsize;
+ newvi->may_have_pointers = fo->may_have_pointers;
+ insert_into_field_list (vi, newvi);
+ if ((newvi->is_global_var || TREE_CODE (decl) == PARM_DECL)
+ && newvi->may_have_pointers)
+ {
+ if (fo->only_restrict_pointers)
+ make_constraint_from_restrict (newvi, "GLOBAL_RESTRICT");
+ if (newvi->is_global_var && !in_ipa_mode)
+ make_copy_constraint (newvi, nonlocal_id);
+ }
+
+ stats.total_vars++;
+ }
+ }
+ else
+ vi->is_full_var = true;
+
+ VEC_free (fieldoff_s, heap, fieldstack);
+
+ return vi->id;
}
/* Print out the points-to solution for VAR to FILE. */
}
for (p = get_vi_for_tree (t); p; p = p->next)
- {
- if (p->may_have_pointers)
- make_constraint_from (p, nonlocal_id);
- if (p->only_restrict_pointers)
- make_constraint_from_restrict (p, "PARM_RESTRICT");
- }
+ if (p->may_have_pointers)
+ make_constraint_from (p, nonlocal_id);
if (POINTER_TYPE_P (TREE_TYPE (t))
&& TYPE_RESTRICT (TREE_TYPE (t)))
make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
/* Build the constraints. */
for (node = cgraph_nodes; node; node = node->next)
{
- struct cgraph_node *alias;
- varinfo_t vi;
-
/* Nodes without a body are not interesting. Especially do not
visit clones at this point for now - we get duplicate decls
there for inline clones at least. */
|| node->clone_of)
continue;
- vi = create_function_info_for (node->decl,
- alias_get_name (node->decl));
-
- /* Associate the varinfo node with all aliases. */
- for (alias = node->same_body; alias; alias = alias->next)
- insert_vi_for_tree (alias->decl, vi);
+ create_function_info_for (node->decl,
+ cgraph_node_name (node));
}
/* Create constraints for global variables and their initializers. */
for (var = varpool_nodes; var; var = var->next)
- {
- struct varpool_node *alias;
- varinfo_t vi;
-
- vi = get_vi_for_tree (var->decl);
-
- /* Associate the varinfo node with all aliases. */
- for (alias = var->extra_name; alias; alias = alias->next)
- insert_vi_for_tree (alias->decl, vi);
- }
+ get_vi_for_tree (var->decl);
if (dump_file)
{
continue;
if (dump_file)
- {
- fprintf (dump_file,
- "Generating constraints for %s", cgraph_node_name (node));
- if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
- fprintf (dump_file, " (%s)",
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
- fprintf (dump_file, "\n");
- }
+ fprintf (dump_file,
+ "Generating constraints for %s\n",
+ cgraph_node_name (node));
func = DECL_STRUCT_FUNCTION (node->decl);
old_func_decl = current_function_decl;