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;
if (node && node->alias)
{
node = varpool_variable_node (node, NULL);
- t = node->decl;
+ t = node->symbol.decl;
}
}
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. */
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
{
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 this is a global variable with an initializer and we are in
IPA mode generate constraints for it. */
- if (DECL_INITIAL (decl))
+ if (DECL_INITIAL (decl)
+ && vnode->analyzed)
{
VEC (ce_s, heap) *rhsc = NULL;
struct constraint_expr lhs, *rhsp;
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;
associate_varinfo_to_alias (struct cgraph_node *node, void *data)
{
if (node->alias || node->thunk.thunk_p)
- insert_vi_for_tree (node->decl, (varinfo_t)data);
+ insert_vi_for_tree (node->symbol.decl, (varinfo_t)data);
return false;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
- dump_cgraph (dump_file);
+ dump_symtab (dump_file);
fprintf (dump_file, "\n");
}
/* Build the constraints. */
- for (node = cgraph_nodes; node; node = node->next)
+ FOR_EACH_DEFINED_FUNCTION (node)
{
varinfo_t vi;
/* Nodes without a body are not interesting. Especially do not
gcc_assert (!node->clone_of);
- vi = create_function_info_for (node->decl,
- alias_get_name (node->decl));
+ vi = create_function_info_for (node->symbol.decl,
+ alias_get_name (node->symbol.decl));
cgraph_for_node_and_aliases (node, associate_varinfo_to_alias, vi, true);
}
/* Create constraints for global variables and their initializers. */
- for (var = varpool_nodes; var; var = var->next)
+ FOR_EACH_VARIABLE (var)
{
if (var->alias)
continue;
- get_vi_for_tree (var->decl);
+ get_vi_for_tree (var->symbol.decl);
}
if (dump_file)
}
from = VEC_length (constraint_t, constraints);
- for (node = cgraph_nodes; node; node = node->next)
+ FOR_EACH_DEFINED_FUNCTION (node)
{
struct function *func;
basic_block bb;
{
fprintf (dump_file,
"Generating constraints for %s", cgraph_node_name (node));
- if (DECL_ASSEMBLER_NAME_SET_P (node->decl))
+ if (DECL_ASSEMBLER_NAME_SET_P (node->symbol.decl))
fprintf (dump_file, " (%s)",
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl)));
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (node->symbol.decl)));
fprintf (dump_file, "\n");
}
- func = DECL_STRUCT_FUNCTION (node->decl);
+ func = DECL_STRUCT_FUNCTION (node->symbol.decl);
old_func_decl = current_function_decl;
push_cfun (func);
- current_function_decl = node->decl;
+ current_function_decl = node->symbol.decl;
/* For externally visible or attribute used annotated functions use
local constraints for their arguments.
For local functions we see all callers and thus do not need initial
constraints for parameters. */
- if (node->reachable_from_other_partition
- || node->local.externally_visible
- || node->needed)
+ if (node->symbol.used_from_other_partition
+ || node->symbol.externally_visible
+ || node->symbol.force_output)
{
intra_create_variable_infos ();
/* We also need to make function return values escape. Nothing
escapes by returning from main though. */
- if (!MAIN_NAME_P (DECL_NAME (node->decl)))
+ if (!MAIN_NAME_P (DECL_NAME (node->symbol.decl)))
{
varinfo_t fi, rvi;
- fi = lookup_vi_for_tree (node->decl);
+ fi = lookup_vi_for_tree (node->symbol.decl);
rvi = first_vi_for_offset (fi, fi_result);
if (rvi && rvi->offset == fi_result)
{
ipa_escaped_pt.ipa_escaped = 0;
/* Assign the points-to sets to the SSA names in the unit. */
- for (node = cgraph_nodes; node; node = node->next)
+ FOR_EACH_DEFINED_FUNCTION (node)
{
tree ptr;
struct function *fn;
if (!cgraph_function_with_gimple_body_p (node))
continue;
- fn = DECL_STRUCT_FUNCTION (node->decl);
+ fn = DECL_STRUCT_FUNCTION (node->symbol.decl);
/* Compute the points-to sets for pointer SSA_NAMEs. */
FOR_EACH_VEC_ELT (tree, fn->gimple_df->ssa_names, i, ptr)
}
/* Compute the call-use and call-clobber sets for all direct calls. */
- fi = lookup_vi_for_tree (node->decl);
+ fi = lookup_vi_for_tree (node->symbol.decl);
gcc_assert (fi->is_fn_info);
find_what_var_points_to (first_vi_for_offset (fi, fi_clobbers),
&clobbers);