/* True if this is a heap variable. */
unsigned int is_heap_var : 1;
- /* True if this is a variable tracking a restrict pointer source. */
- unsigned int is_restrict_var : 1;
-
/* True if this field may contain pointers. */
unsigned int may_have_pointers : 1;
static varinfo_t first_or_preceding_vi_for_offset (varinfo_t,
unsigned HOST_WIDE_INT);
static varinfo_t lookup_vi_for_tree (tree);
+static inline bool type_can_have_subvars (const_tree);
/* Pool of variable info structures. */
static alloc_pool variable_info_pool;
ret->is_unknown_size_var = false;
ret->is_full_var = (t == NULL_TREE);
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);
}
/* Lookup a equivalence class in TABLE by the bitmap of LABELS it
- contains. */
+ contains. Sets *REF_LABELS to the bitmap LABELS is equivalent to. */
static unsigned int
-equiv_class_lookup (htab_t table, bitmap labels)
+equiv_class_lookup (htab_t table, bitmap labels, bitmap *ref_labels)
{
void **slot;
struct equiv_class_label ecl;
slot = htab_find_slot_with_hash (table, &ecl,
ecl.hashcode, NO_INSERT);
if (!slot)
- return 0;
+ {
+ if (ref_labels)
+ *ref_labels = NULL;
+ return 0;
+ }
else
- return ((equiv_class_label_t) *slot)->equivalence_class;
+ {
+ equiv_class_label_t ec = (equiv_class_label_t) *slot;
+ if (ref_labels)
+ *ref_labels = ec->labels;
+ return ec->equivalence_class;
+ }
}
if (!bitmap_empty_p (graph->points_to[n]))
{
+ bitmap ref_points_to;
unsigned int label = equiv_class_lookup (pointer_equiv_class_table,
- graph->points_to[n]);
+ graph->points_to[n],
+ &ref_points_to);
if (!label)
{
label = pointer_equiv_class++;
equiv_class_add (pointer_equiv_class_table,
label, graph->points_to[n]);
}
+ else
+ {
+ BITMAP_FREE (graph->points_to[n]);
+ graph->points_to[n] = ref_points_to;
+ }
graph->pointer_label[n] = label;
}
}
/* Look up the location equivalence label if one exists, or make
one otherwise. */
label = equiv_class_lookup (location_equiv_class_table,
- pointed_by);
+ pointed_by, NULL);
if (label == 0)
{
label = location_equiv_class++;
return;
cs = *VEC_last (ce_s, *results);
- if (cs.type == DEREF)
+ if (cs.type == DEREF
+ && type_can_have_subvars (TREE_TYPE (t)))
{
/* For dereferences this means we have to defer it
to solving time. */
}
/* Create a new artificial heap variable with NAME and make a
- constraint from it to LHS. Return the created variable. */
+ constraint from it to LHS. Set flags according to a tag used
+ for tracking restrict pointers. */
static varinfo_t
-make_constraint_from_heapvar (varinfo_t lhs, const char *name)
+make_constraint_from_restrict (varinfo_t lhs, const char *name)
{
varinfo_t vi = make_heapvar (name);
+ vi->is_global_var = 1;
+ vi->may_have_pointers = 1;
make_constraint_from (lhs, vi->id);
-
return vi;
}
/* Create a new artificial heap variable with NAME and make a
constraint from it to LHS. Set flags according to a tag used
- for tracking restrict pointers. */
+ for tracking restrict pointers and make the artificial heap
+ point to global memory. */
-static void
-make_constraint_from_restrict (varinfo_t lhs, const char *name)
+static varinfo_t
+make_constraint_from_global_restrict (varinfo_t lhs, const char *name)
{
- varinfo_t vi;
- vi = make_constraint_from_heapvar (lhs, name);
- vi->is_restrict_var = 1;
- vi->is_global_var = 0;
- vi->is_special_var = 1;
- vi->may_have_pointers = 0;
+ varinfo_t vi = make_constraint_from_restrict (lhs, name);
+ make_copy_constraint (vi, nonlocal_id);
+ return vi;
}
/* In IPA mode there are varinfos for different aspects of reach
/* 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. */
+ escape solution. */
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);
+ {
+ varinfo_t tem = new_var_info (NULL_TREE, "callarg");
+ make_constraint_to (tem->id, arg);
+ make_transitive_closure_constraints (tem);
+ make_copy_constraint (uses, tem->id);
+ }
+ else
+ make_constraint_to (uses->id, arg);
returns_uses = true;
}
else if (flags & EAF_NOESCAPE)
{
+ struct constraint_expr lhs, rhs;
varinfo_t uses = get_call_use_vi (stmt);
varinfo_t clobbers = get_call_clobber_vi (stmt);
+ varinfo_t tem = new_var_info (NULL_TREE, "callarg");
+ make_constraint_to (tem->id, arg);
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);
+ make_transitive_closure_constraints (tem);
+ make_copy_constraint (uses, tem->id);
+ make_copy_constraint (clobbers, tem->id);
+ /* Add *tem = nonlocal, do not add *tem = callused as
+ EAF_NOESCAPE parameters do not escape to other parameters
+ and all other uses appear in NONLOCAL as well. */
+ lhs.type = DEREF;
+ lhs.var = tem->id;
+ lhs.offset = 0;
+ rhs.type = SCALAR;
+ rhs.var = nonlocal_id;
+ rhs.offset = 0;
+ process_constraint (new_constraint (lhs, rhs));
returns_uses = true;
}
else
tmpc.offset = 0;
tmpc.type = ADDRESSOF;
VEC_safe_push (ce_s, heap, rhsc, &tmpc);
+ process_all_all_constraints (lhsc, rhsc);
+ VEC_free (ce_s, heap, rhsc);
}
-
- process_all_all_constraints (lhsc, rhsc);
+ else
+ process_all_all_constraints (lhsc, rhsc);
VEC_free (ce_s, heap, lhsc);
}
VEC(ce_s, heap) *rhsc = NULL;
varinfo_t fi;
- if (fndecl != NULL_TREE
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ if (gimple_call_builtin_class_p (t, BUILT_IN_NORMAL))
/* ??? All builtins that are handled here need to be handled
in the alias-oracle query functions explicitly! */
switch (DECL_FUNCTION_CODE (fndecl))
case BUILT_IN_MEMMOVE_CHK:
case BUILT_IN_MEMPCPY_CHK:
case BUILT_IN_STPCPY_CHK:
+ case BUILT_IN_STPNCPY_CHK:
case BUILT_IN_STRCAT_CHK:
case BUILT_IN_STRNCAT_CHK:
+ case BUILT_IN_TM_MEMCPY:
+ case BUILT_IN_TM_MEMMOVE:
{
tree res = gimple_call_lhs (t);
tree dest = gimple_call_arg (t, (DECL_FUNCTION_CODE (fndecl)
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MEMPCPY_CHK
- || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK)
+ || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPCPY_CHK
+ || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STPNCPY_CHK)
get_constraint_for_ptr_offset (dest, NULL_TREE, &rhsc);
else
get_constraint_for (dest, &rhsc);
}
case BUILT_IN_MEMSET:
case BUILT_IN_MEMSET_CHK:
+ case BUILT_IN_TM_MEMSET:
{
tree res = gimple_call_lhs (t);
tree dest = gimple_call_arg (t, 0);
}
return true;
}
+ CASE_BUILT_IN_TM_STORE (1):
+ CASE_BUILT_IN_TM_STORE (2):
+ CASE_BUILT_IN_TM_STORE (4):
+ CASE_BUILT_IN_TM_STORE (8):
+ CASE_BUILT_IN_TM_STORE (FLOAT):
+ CASE_BUILT_IN_TM_STORE (DOUBLE):
+ CASE_BUILT_IN_TM_STORE (LDOUBLE):
+ CASE_BUILT_IN_TM_STORE (M64):
+ CASE_BUILT_IN_TM_STORE (M128):
+ CASE_BUILT_IN_TM_STORE (M256):
+ {
+ tree addr = gimple_call_arg (t, 0);
+ tree src = gimple_call_arg (t, 1);
+
+ get_constraint_for (addr, &lhsc);
+ do_deref (&lhsc);
+ get_constraint_for (src, &rhsc);
+ process_all_all_constraints (lhsc, rhsc);
+ VEC_free (ce_s, heap, lhsc);
+ VEC_free (ce_s, heap, rhsc);
+ return true;
+ }
+ CASE_BUILT_IN_TM_LOAD (1):
+ CASE_BUILT_IN_TM_LOAD (2):
+ CASE_BUILT_IN_TM_LOAD (4):
+ CASE_BUILT_IN_TM_LOAD (8):
+ CASE_BUILT_IN_TM_LOAD (FLOAT):
+ CASE_BUILT_IN_TM_LOAD (DOUBLE):
+ CASE_BUILT_IN_TM_LOAD (LDOUBLE):
+ CASE_BUILT_IN_TM_LOAD (M64):
+ CASE_BUILT_IN_TM_LOAD (M128):
+ CASE_BUILT_IN_TM_LOAD (M256):
+ {
+ tree dest = gimple_call_lhs (t);
+ tree addr = gimple_call_arg (t, 0);
+
+ get_constraint_for (dest, &lhsc);
+ get_constraint_for (addr, &rhsc);
+ do_deref (&rhsc);
+ process_all_all_constraints (lhsc, rhsc);
+ VEC_free (ce_s, heap, lhsc);
+ VEC_free (ce_s, heap, rhsc);
+ return true;
+ }
/* Variadic argument handling needs to be handled in IPA
mode as well. */
case BUILT_IN_VA_START:
tree lhsop = gimple_assign_lhs (t);
tree rhsop = (gimple_num_ops (t) == 2) ? gimple_assign_rhs1 (t) : NULL;
- if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
+ if (rhsop && TREE_CLOBBER_P (rhsop))
+ /* Ignore clobbers, they don't actually store anything into
+ the LHS. */
+ ;
+ else if (rhsop && AGGREGATE_TYPE_P (TREE_TYPE (lhsop)))
do_structure_copy (lhsop, rhsop);
else
{
/* For builtins we do not have separate function info. For those
we do not generate escapes for we have to generate clobbers/uses. */
- if (decl
- && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+ if (gimple_call_builtin_class_p (t, BUILT_IN_NORMAL))
switch (DECL_FUNCTION_CODE (decl))
{
/* The following functions use and clobber memory pointed to
case BUILT_IN_MEMMOVE_CHK:
case BUILT_IN_MEMPCPY_CHK:
case BUILT_IN_STPCPY_CHK:
+ case BUILT_IN_STPNCPY_CHK:
case BUILT_IN_STRCAT_CHK:
case BUILT_IN_STRNCAT_CHK:
{
VEC_qsort (fieldoff_s, fieldstack, fieldoff_compare);
}
+/* Return true if T is a type that can have subvars. */
+
+static inline bool
+type_can_have_subvars (const_tree t)
+{
+ /* Aggregates without overlapping fields can have subvars. */
+ return TREE_CODE (t) == RECORD_TYPE;
+}
+
/* Return true if V is a tree that we can have subvars for.
Normally, this is any aggregate type. Also complex
types which are not gimple registers can have subvars. */
if (!DECL_P (v))
return false;
- /* Aggregates without overlapping fields can have subvars. */
- if (TREE_CODE (TREE_TYPE (v)) == RECORD_TYPE)
- return true;
-
- return false;
+ return type_can_have_subvars (TREE_TYPE (v));
}
/* Return true if T is a type that does contain pointers. */
if ((POINTER_TYPE_P (TREE_TYPE (decl))
&& TYPE_RESTRICT (TREE_TYPE (decl)))
|| vi->only_restrict_pointers)
- make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
+ {
+ make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
+ continue;
+ }
/* In non-IPA mode the initializer from nonlocal is all we need. */
if (!in_ipa_mode
|| DECL_HARD_REGISTER (decl))
make_copy_constraint (vi, nonlocal_id);
+ /* In IPA mode parse the initializer and generate proper constraints
+ for it. */
else
{
struct varpool_node *vnode = varpool_get_node (decl);
passed-by-reference argument. */
for (t = DECL_ARGUMENTS (current_function_decl); t; t = DECL_CHAIN (t))
{
- varinfo_t p;
+ varinfo_t p = get_vi_for_tree (t);
/* For restrict qualified pointers to objects passed by
reference build a real representative for the pointed-to object.
Treat restrict qualified references the same. */
if (TYPE_RESTRICT (TREE_TYPE (t))
&& ((DECL_BY_REFERENCE (t) && POINTER_TYPE_P (TREE_TYPE (t)))
- || TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE))
+ || TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
+ && !type_contains_placeholder_p (TREE_TYPE (TREE_TYPE (t))))
{
struct constraint_expr lhsc, rhsc;
varinfo_t vi;
DECL_EXTERNAL (heapvar) = 1;
vi = create_variable_info_for_1 (heapvar, "PARM_NOALIAS");
insert_vi_for_tree (heapvar, vi);
- lhsc.var = get_vi_for_tree (t)->id;
+ lhsc.var = p->id;
lhsc.type = SCALAR;
lhsc.offset = 0;
rhsc.var = vi->id;
rhsc.type = ADDRESSOF;
rhsc.offset = 0;
process_constraint (new_constraint (lhsc, rhsc));
- vi->is_restrict_var = 1;
for (; vi; vi = vi->next)
if (vi->may_have_pointers)
{
if (vi->only_restrict_pointers)
- make_constraint_from_restrict (vi, "GLOBAL_RESTRICT");
- make_copy_constraint (vi, nonlocal_id);
+ make_constraint_from_global_restrict (vi, "GLOBAL_RESTRICT");
+ else
+ make_copy_constraint (vi, nonlocal_id);
}
continue;
}
- 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 (POINTER_TYPE_P (TREE_TYPE (t))
&& TYPE_RESTRICT (TREE_TYPE (t)))
- make_constraint_from_restrict (get_vi_for_tree (t), "PARM_RESTRICT");
+ make_constraint_from_global_restrict (p, "PARM_RESTRICT");
+ else
+ {
+ for (; p; p = p->next)
+ {
+ if (p->only_restrict_pointers)
+ make_constraint_from_global_restrict (p, "PARM_RESTRICT");
+ else if (p->may_have_pointers)
+ make_constraint_from (p, nonlocal_id);
+ }
+ }
}
/* Add a constraint for a result decl that is passed by reference. */
|| vi->id == integer_id)
pt->anything = 1;
}
- if (vi->is_restrict_var)
- pt->vars_contains_restrict = true;
}
/* Instead of doing extra work, simply do not create
elaborate points-to information for pt_anything pointers. */
- if (pt->anything
- && (orig_vi->is_artificial_var
- || !pt->vars_contains_restrict))
+ if (pt->anything)
return;
/* Share the final set of variables when possible. */
it contains restrict tag variables. */
void
-pt_solution_set (struct pt_solution *pt, bitmap vars,
- bool vars_contains_global, bool vars_contains_restrict)
+pt_solution_set (struct pt_solution *pt, bitmap vars, bool vars_contains_global)
{
memset (pt, 0, sizeof (struct pt_solution));
pt->vars = vars;
pt->vars_contains_global = vars_contains_global;
- pt->vars_contains_restrict = vars_contains_restrict;
}
/* Set the points-to solution *PT to point only to the variable VAR. */
dest->ipa_escaped |= src->ipa_escaped;
dest->null |= src->null;
dest->vars_contains_global |= src->vars_contains_global;
- dest->vars_contains_restrict |= src->vars_contains_restrict;
if (!src->vars)
return;
return res;
}
-/* Return true if both points-to solutions PT1 and PT2 for two restrict
- qualified pointers are possibly based on the same pointer. */
-
-bool
-pt_solutions_same_restrict_base (struct pt_solution *pt1,
- struct pt_solution *pt2)
-{
- /* If we deal with points-to solutions of two restrict qualified
- pointers solely rely on the pointed-to variable bitmap intersection.
- For two pointers that are based on each other the bitmaps will
- intersect. */
- if (pt1->vars_contains_restrict
- && pt2->vars_contains_restrict)
- {
- gcc_assert (pt1->vars && pt2->vars);
- return bitmap_intersect_p (pt1->vars, pt2->vars);
- }
-
- return true;
-}
-
/* Dump points-to information to OUTFILE. */
/* Mark escaped HEAP variables as global. */
FOR_EACH_VEC_ELT (varinfo_t, varmap, i, vi)
if (vi->is_heap_var
- && !vi->is_restrict_var
&& !vi->is_global_var)
DECL_EXTERNAL (vi->decl) = vi->is_global_var
= pt_solution_includes (&cfun->gimple_df->escaped, vi->decl);
/* IPA PTA solutions for ESCAPED. */
struct pt_solution ipa_escaped_pt
- = { true, false, false, false, false, false, false, NULL };
+ = { true, false, false, false, false, false, NULL };
/* Associate node with varinfo DATA. Worker for
cgraph_for_node_and_aliases. */