/* Callgraph handling code.
- Copyright (C) 2003-2019 Free Software Foundation, Inc.
+ Copyright (C) 2003-2020 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
public:
friend class symbol_table;
+ /* Constructor. */
+ explicit symtab_node (symtab_type t)
+ : type (t), resolution (LDPR_UNKNOWN), definition (false), alias (false),
+ transparent_alias (false), weakref (false), cpp_implicit_alias (false),
+ symver (false), analyzed (false), writeonly (false),
+ refuse_visibility_changes (false), externally_visible (false),
+ no_reorder (false), force_output (false), forced_by_abi (false),
+ unique_name (false), implicit_section (false), body_removed (false),
+ used_from_other_partition (false), in_other_partition (false),
+ address_taken (false), in_init_priority_hash (false),
+ need_lto_streaming (false), offloadable (false), ifunc_resolver (false),
+ order (false), next_sharing_asm_name (NULL),
+ previous_sharing_asm_name (NULL), same_comdat_group (NULL), ref_list (),
+ alias_target (NULL), lto_file_data (NULL), aux (NULL),
+ x_comdat_group (NULL_TREE), x_section (NULL)
+ {}
+
/* Return name. */
const char *name () const;
and their visibility needs to be copied from their "masters" at
the end of parsing. */
unsigned cpp_implicit_alias : 1;
+ /* The alias is a symbol version. */
+ unsigned symver : 1;
/* Set once the definition was analyzed. The list of references and
other properties are built during analysis. */
unsigned analyzed : 1;
{
friend class symbol_table;
+ /* Constructor. */
+ explicit cgraph_node (int uid)
+ : symtab_node (SYMTAB_FUNCTION), callees (NULL), callers (NULL),
+ indirect_calls (NULL), origin (NULL), nested (NULL), next_nested (NULL),
+ next_sibling_clone (NULL), prev_sibling_clone (NULL), clones (NULL),
+ clone_of (NULL), call_site_hash (NULL), former_clone_of (NULL),
+ simdclone (NULL), simd_clones (NULL), ipa_transforms_to_apply (vNULL),
+ inlined_to (NULL), rtl (NULL), clone (), thunk (),
+ count (profile_count::uninitialized ()),
+ count_materialization_scale (REG_BR_PROB_BASE), profile_id (0),
+ unit_id (0), tp_first_run (0), used_as_abstract_origin (false),
+ lowered (false), process (false), frequency (NODE_FREQUENCY_NORMAL),
+ only_called_at_startup (false), only_called_at_exit (false),
+ tm_clone (false), dispatcher_function (false), calls_comdat_local (false),
+ icf_merged (false), nonfreeing_fn (false), merged_comdat (false),
+ merged_extern_inline (false), parallelized_function (false),
+ split_part (false), indirect_call_target (false), local (false),
+ versionable (false), can_change_signature (false),
+ redefined_extern_inline (false), tm_may_enter_irr (false),
+ ipcp_clone (false), declare_variant_alt (false),
+ calls_declare_variant_alt (false), m_uid (uid), m_summary_id (-1)
+ {}
+
/* Remove the node from cgraph and all inline clones inlined into it.
Skip however removal of FORBIDDEN_NODE and return true if it needs to be
removed. This allows to call the function from outer loop walking clone
ipa_param_adjustments *param_adjustments,
const char * suffix, unsigned num_suffix);
+ /* Remove the node from the tree of virtual and inline clones and make it a
+ standalone node - not a clone any more. */
+ void remove_from_clone_tree ();
+
/* cgraph node being removed from symbol table; see if its entry can be
replaced by other inline clone. */
cgraph_node *find_replacement (void);
/* Return true if this node represents a former, i.e. an expanded, thunk. */
inline bool former_thunk_p (void);
+ /* Check if function calls comdat local. This is used to recompute
+ calls_comdat_local flag after function transformations. */
+ bool check_calls_comdat_local_p ();
+
/* Return true if function should be optimized for size. */
bool optimize_for_size_p (void);
int count_materialization_scale;
/* ID assigned by the profiling. */
unsigned int profile_id;
+ /* ID of the translation unit. */
+ int unit_id;
/* Time profiler: first run of function. */
int tp_first_run;
unsigned nonfreeing_fn : 1;
/* True if there was multiple COMDAT bodies merged by lto-symtab. */
unsigned merged_comdat : 1;
+ /* True if this def was merged with extern inlines. */
+ unsigned merged_extern_inline : 1;
/* True if function was created to be executed in parallel. */
unsigned parallelized_function : 1;
/* True if function is part split out by ipa-split. */
unsigned tm_may_enter_irr : 1;
/* True if this was a clone created by ipa-cp. */
unsigned ipcp_clone : 1;
+ /* True if this is the deferred declare variant resolution artificial
+ function. */
+ unsigned declare_variant_alt : 1;
+ /* True if the function calls declare_variant_alt functions. */
+ unsigned calls_declare_variant_alt : 1;
private:
/* Unique id of the node. */
int param_index;
/* ECF flags determined from the caller. */
int ecf_flags;
- /* Profile_id of common target obtained from profile. */
- int common_target_id;
- /* Probability that call will land in function with COMMON_TARGET_ID. */
- int common_target_probability;
+
+ /* Number of speculative call targets, it's less than GCOV_TOPN_VALUES. */
+ unsigned num_speculative_call_targets : 16;
/* Set when the call is a virtual call with the parameter being the
associated object pointer rather than a simple direct call. */
friend struct cgraph_node;
friend class symbol_table;
- /* Remove the edge in the cgraph. */
- void remove (void);
+ /* Remove EDGE from the cgraph. */
+ static void remove (cgraph_edge *edge);
- /* Change field call_stmt of edge to NEW_STMT.
- If UPDATE_SPECULATIVE and E is any component of speculative
- edge, then update all components. */
- void set_call_stmt (gcall *new_stmt, bool update_speculative = true);
+ /* Change field call_stmt of edge E to NEW_STMT. If UPDATE_SPECULATIVE and E
+ is any component of speculative edge, then update all components.
+ Speculations can be resolved in the process and EDGE can be removed and
+ deallocated. Return the edge that now represents the call. */
+ static cgraph_edge *set_call_stmt (cgraph_edge *e, gcall *new_stmt,
+ bool update_speculative = true);
/* Redirect callee of the edge to N. The function does not update underlying
call expression. */
void redirect_callee_duplicating_thunks (cgraph_node *n);
/* Make an indirect edge with an unknown callee an ordinary edge leading to
- CALLEE. DELTA is an integer constant that is to be added to the this
- pointer (first parameter) to compensate for skipping
- a thunk adjustment. */
- cgraph_edge *make_direct (cgraph_node *callee);
+ CALLEE. Speculations can be resolved in the process and EDGE can be
+ removed and deallocated. Return the edge that now represents the
+ call. */
+ static cgraph_edge *make_direct (cgraph_edge *edge, cgraph_node *callee);
/* Turn edge into speculative call calling N2. Update
the profile so the direct call is taken COUNT times
- with FREQUENCY. */
- cgraph_edge *make_speculative (cgraph_node *n2, profile_count direct_count);
+ with FREQUENCY. speculative_id is used to link direct calls with their
+ corresponding IPA_REF_ADDR references when representing speculative calls.
+ */
+ cgraph_edge *make_speculative (cgraph_node *n2, profile_count direct_count,
+ unsigned int speculative_id = 0);
+
+ /* Speculative call consists of an indirect edge and one or more
+ direct edge+ref pairs. Speculative will expand to the following sequence:
+
+ if (call_dest == target1) // reference to target1
+ target1 (); // direct call to target1
+ else if (call_dest == target2) // reference to targt2
+ target2 (); // direct call to target2
+ else
+ call_dest (); // indirect call
+
+ Before the expansion we will have indirect call and the direct call+ref
+ pairs all linked to single statement.
+
+ Note that ref may point to different symbol than the corresponding call
+ becuase the speculated edge may have been optimized (redirected to
+ a clone) or inlined.
- /* Given speculative call edge, return all three components. */
- void speculative_call_info (cgraph_edge *&direct, cgraph_edge *&indirect,
- ipa_ref *&reference);
+ Given an edge which is part of speculative call, return the first
+ direct call edge in the speculative call sequence.
- /* Speculative call edge turned out to be direct call to CALLEE_DECL.
- Remove the speculative call sequence and return edge representing the call.
- It is up to caller to redirect the call as appropriate. */
- cgraph_edge *resolve_speculation (tree callee_decl = NULL);
+ In the example above called on any cgraph edge in the sequence it will
+ return direct call to target1. */
+ cgraph_edge *first_speculative_call_target ();
+
+ /* Return next speculative call target or NULL if there is none.
+ All targets are required to form an interval in the callee list.
+
+ In example above, if called on call to target1 it will return call to
+ target2. */
+ cgraph_edge *next_speculative_call_target ()
+ {
+ cgraph_edge *e = this;
+ gcc_checking_assert (speculative && callee);
+
+ if (e->next_callee && e->next_callee->speculative
+ && e->next_callee->call_stmt == e->call_stmt
+ && e->next_callee->lto_stmt_uid == e->lto_stmt_uid)
+ return e->next_callee;
+ return NULL;
+ }
+
+ /* When called on any edge in the speculative call return the (unique)
+ indirect call edge in the speculative call sequence. */
+ cgraph_edge *speculative_call_indirect_edge ()
+ {
+ gcc_checking_assert (speculative);
+ if (!callee)
+ return this;
+ for (cgraph_edge *e2 = caller->indirect_calls;
+ true; e2 = e2->next_callee)
+ if (e2->speculative
+ && call_stmt == e2->call_stmt
+ && lto_stmt_uid == e2->lto_stmt_uid)
+ return e2;
+ }
+
+ /* When called on any edge in speculative call and when given any target
+ of ref which is speculated to it returns the corresponding direct call.
+
+ In example above if called on function target2 it will return call to
+ target2. */
+ cgraph_edge *speculative_call_for_target (cgraph_node *);
+
+ /* Return REF corresponding to direct call in the specualtive call
+ sequence. */
+ ipa_ref *speculative_call_target_ref ()
+ {
+ ipa_ref *ref;
+
+ gcc_checking_assert (speculative);
+ for (unsigned int i = 0; caller->iterate_reference (i, ref); i++)
+ if (ref->speculative && ref->speculative_id == speculative_id
+ && ref->stmt == (gimple *)call_stmt
+ && ref->lto_stmt_uid == lto_stmt_uid)
+ return ref;
+ gcc_unreachable ();
+ }
+
+ /* Speculative call edge turned out to be direct call to CALLEE_DECL. Remove
+ the speculative call sequence and return edge representing the call, the
+ original EDGE can be removed and deallocated. It is up to caller to
+ redirect the call as appropriate. Return the edge that now represents the
+ call.
+
+ For "speculative" indirect call that contains multiple "speculative"
+ targets (i.e. edge->indirect_info->num_speculative_call_targets > 1),
+ decrease the count and only remove current direct edge.
+
+ If no speculative direct call left to the speculative indirect call, remove
+ the speculative of both the indirect call and corresponding direct edge.
+
+ It is up to caller to iteratively resolve each "speculative" direct call
+ and redirect the call as appropriate. */
+ static cgraph_edge *resolve_speculation (cgraph_edge *edge,
+ tree callee_decl = NULL);
/* If necessary, change the function declaration in the call statement
- associated with the edge so that it corresponds to the edge callee. */
- gimple *redirect_call_stmt_to_callee (void);
+ associated with edge E so that it corresponds to the edge callee.
+ Speculations can be resolved in the process and EDGE can be removed and
+ deallocated.
+
+ The edge could be one of speculative direct call generated from speculative
+ indirect call. In this circumstance, decrease the speculative targets
+ count (i.e. num_speculative_call_targets) and redirect call stmt to the
+ corresponding i-th target. If no speculative direct call left to the
+ speculative indirect call, remove "speculative" of the indirect call and
+ also redirect stmt to it's final direct target.
+
+ It is up to caller to iteratively transform each "speculative"
+ direct call as appropriate. */
+ static gimple *redirect_call_stmt_to_callee (cgraph_edge *e);
/* Create clone of edge in the node N represented
by CALL_EXPR the callgraph. */
be internal to the current translation unit. */
bool possibly_call_in_translation_unit_p (void);
+ /* Return num_speculative_targets of this edge. */
+ int num_speculative_call_targets_p (void);
+
/* Expected number of executions: calculated in profile.c. */
profile_count count;
cgraph_node *caller;
/* The stmt_uid of call_stmt. This is used by LTO to recover the call_stmt
when the function is serialized in. */
unsigned int lto_stmt_uid;
+ /* speculative id is used to link direct calls with their corresponding
+ IPA_REF_ADDR references when representing speculative calls. */
+ unsigned int speculative_id : 16;
/* Whether this edge was made direct by indirect inlining. */
unsigned int indirect_inlining_edge : 1;
/* Whether this edge describes an indirect call with an undetermined
struct GTY((tag ("SYMTAB_VARIABLE"))) varpool_node : public symtab_node
{
+ /* Constructor. */
+ explicit varpool_node ()
+ : symtab_node (SYMTAB_VARIABLE), output (0), dynamically_initialized (0),
+ tls_model (TLS_MODEL_NONE), used_by_single_function (0)
+ {}
+
/* Dump given varpool node to F. */
void dump (FILE *f);
edges_count (0), edges_max_uid (1), edges_max_summary_id (0),
cgraph_released_summary_ids (), edge_released_summary_ids (),
nodes (NULL), asmnodes (NULL), asm_last_node (NULL),
- order (0), global_info_ready (false), state (PARSING),
+ order (0), max_unit (0), global_info_ready (false), state (PARSING),
function_flags_ready (false), cpp_implicit_aliases_done (false),
section_hash (NULL), assembler_name_hash (NULL), init_priority_hash (NULL),
dump_file (NULL), ipa_clones_dump_file (NULL), cloned_nodes (),
them, to support -fno-toplevel-reorder. */
int order;
+ /* Maximal unit ID used. */
+ int max_unit;
+
/* Set when whole unit has been analyzed so we can access global info. */
bool global_info_ready;
/* What state callgraph is in right now. */
hash_set <const cgraph_node *> GTY ((skip)) cloned_nodes;
private:
- /* Allocate new callgraph node. */
- inline cgraph_node * allocate_cgraph_symbol (void);
-
/* Allocate a cgraph_edge structure and fill it with data according to the
parameters of which only CALLEE can be NULL (when creating an indirect
call edge). CLONING_P should be set if properties that are copied from an
/* In cgraphunit.c */
void cgraphunit_c_finalize (void);
+int tp_first_run_node_cmp (const void *pa, const void *pb);
/* Initialize datastructures so DECL is a function in lowered gimple form.
IN_SSA is true if the gimple is in SSA. */
ggc_free (node);
}
-/* Allocate new callgraph node. */
-
-inline cgraph_node *
-symbol_table::allocate_cgraph_symbol (void)
-{
- cgraph_node *node;
-
- node = ggc_cleared_alloc<cgraph_node> ();
- node->type = SYMTAB_FUNCTION;
- node->m_summary_id = -1;
- node->m_uid = cgraph_max_uid++;
- return node;
-}
-
-
/* Return first static symbol with definition. */
inline symtab_node *
symbol_table::first_symbol (void)
return false;
/* Only COMDAT functions can be removed if externally visible. */
if (externally_visible
- && (!DECL_COMDAT (decl)
+ && ((!DECL_COMDAT (decl) || ifunc_resolver)
|| forced_by_abi
|| used_from_object_file_p ()))
return false;
callee = n;
}
-/* Redirect callee of the edge to N. The function does not update underlying
- call expression. */
-
-inline void
-cgraph_edge::redirect_callee (cgraph_node *n)
-{
- /* Remove from callers list of the current callee. */
- remove_callee ();
-
- /* Insert to callers list of the new callee. */
- set_callee (n);
-}
-
/* Return true when the edge represents a direct recursion. */
inline bool