/* Callgraph handling code.
- Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ Copyright (C) 2003-2018 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
#ifndef GCC_CGRAPH_H
#define GCC_CGRAPH_H
+#include "profile-count.h"
#include "ipa-ref.h"
#include "plugin-api.h"
symtab_node
{
public:
+ friend class symbol_table;
+
/* Return name. */
const char *name () const;
+ /* Return dump name. */
+ const char *dump_name () const;
+
/* Return asm name. */
- const char * asm_name () const;
+ const char *asm_name () const;
+
+ /* Return dump name with assembler name. */
+ const char *dump_asm_name () const;
/* Add node into symbol table. This function is not used directly, but via
cgraph/varpool node creation routines. */
enum ipa_ref_use use_type, gimple *stmt);
/* If VAL is a reference to a function or a variable, add a reference from
- this symtab_node to the corresponding symbol table node. USE_TYPE specify
- type of the use and STMT the statement (if it exists). Return the new
+ this symtab_node to the corresponding symbol table node. Return the new
reference or NULL if none was created. */
- ipa_ref *maybe_create_reference (tree val, enum ipa_ref_use use_type,
- gimple *stmt);
+ ipa_ref *maybe_create_reference (tree val, gimple *stmt);
/* Clone all references from symtab NODE to this symtab_node. */
void clone_references (symtab_node *node);
or abstract function kept for debug info purposes only. */
bool real_symbol_p (void);
+ /* Return true when the symbol needs to be output to the LTO symbol table. */
+ bool output_to_lto_symbol_table_p (void);
+
/* Determine if symbol declaration is needed. That is, visible to something
either outside this translation unit, something magic in the system
configury. This function is used just during symbol creation. */
bool needed_p (void);
+ /* Return true if this symbol is a function from the C frontend specified
+ directly in RTL form (with "__RTL"). */
+ bool native_rtl_p () const;
+
/* Return true when there are references to the node. */
bool referred_to_p (bool include_self = true);
Return NULL if there's no such node. */
static symtab_node *get_for_asmname (const_tree asmname);
- /* Dump symbol table to F. */
- static void dump_table (FILE *);
-
- /* Dump symbol table to stderr. */
- static inline DEBUG_FUNCTION void debug_symtab (void)
- {
- dump_table (stderr);
- }
-
/* Verify symbol table for internal consistency. */
static DEBUG_FUNCTION void verify_symtab_nodes (void);
/* Set when symbol can be streamed into bytecode for offloading. */
unsigned offloadable : 1;
+ /* Set when symbol is an IFUNC resolver. */
+ unsigned ifunc_resolver : 1;
+
/* Ordering of all symtab entries. */
int order;
/* Worker for ultimate_alias_target. */
symtab_node *ultimate_alias_target_1 (enum availability *avail = NULL,
symtab_node *ref = NULL);
+
+ /* Get dump name with normal or assembly name. */
+ const char *get_dump_name (bool asm_name_p) const;
};
inline void
extern const char * const ld_plugin_symbol_resolution_names[];
extern const char * const tls_model_names[];
-/* Information about thunk, used only for same body aliases. */
+/* Sub-structure of cgraph_node. Holds information about thunk, used only for
+ same body aliases.
+
+ Thunks are basically wrappers around methods which are introduced in case
+ of multiple inheritance in order to adjust the value of the "this" pointer
+ or of the returned value.
+
+ In the case of this-adjusting thunks, each back-end can override the
+ can_output_mi_thunk/output_mi_thunk target hooks to generate a minimal thunk
+ (with a tail call for instance) directly as assembly. For the default hook
+ or for the case where the can_output_mi_thunk hooks return false, the thunk
+ is gimplified and lowered using the regular machinery. */
struct GTY(()) cgraph_thunk_info {
- /* Information about the thunk. */
+ /* Offset used to adjust "this". */
HOST_WIDE_INT fixed_offset;
+
+ /* Offset in the virtual table to get the offset to adjust "this". Valid iff
+ VIRTUAL_OFFSET_P is true. */
HOST_WIDE_INT virtual_value;
+
+ /* Thunk target, i.e. the method that this thunk wraps. Depending on the
+ TARGET_USE_LOCAL_THUNK_ALIAS_P macro, this may have to be a new alias. */
tree alias;
+
+ /* Nonzero for a "this" adjusting thunk and zero for a result adjusting
+ thunk. */
bool this_adjusting;
+
+ /* If true, this thunk is what we call a virtual thunk. In this case:
+ * for this-adjusting thunks, after the FIXED_OFFSET based adjustment is
+ done, add to the result the offset found in the vtable at:
+ vptr + VIRTUAL_VALUE
+ * for result-adjusting thunks, the FIXED_OFFSET adjustment is done after
+ the virtual one. */
bool virtual_offset_p;
+
+ /* ??? True for special kind of thunks, seems related to instrumentation. */
bool add_pointer_bounds_args;
- /* Set to true when alias node is thunk. */
+
+ /* Set to true when alias node (the cgraph_node to which this struct belong)
+ is a thunk. Access to any other fields is invalid if this is false. */
bool thunk_p;
};
otherwise false. */
unsigned int inbranch : 1;
- /* True if this is a Cilk Plus variant. */
- unsigned int cilk_elemental : 1;
-
/* Doubly linked list of SIMD clones. */
cgraph_node *prev_clone, *next_clone;
struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node {
public:
+ friend class symbol_table;
+
/* 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
If the new node is being inlined into another one, NEW_INLINED_TO should be
the outline function the new one is (even indirectly) inlined to.
All hooks will see this in node's global.inlined_to, when invoked.
- Can be NULL if the node is not inlined. */
- cgraph_node *create_clone (tree decl, gcov_type count, int freq,
+ Can be NULL if the node is not inlined. SUFFIX is string that is appended
+ to the original name. */
+ cgraph_node *create_clone (tree decl, profile_count count,
bool update_original,
vec<cgraph_edge *> redirect_callers,
bool call_duplication_hook,
cgraph_node *new_inlined_to,
- bitmap args_to_skip);
+ bitmap args_to_skip, const char *suffix = NULL);
/* Create callgraph node clone with new declaration. The actual body will
be copied later at compilation stage. */
If non-NULL BLOCK_TO_COPY determine what basic blocks
was copied to prevent duplications of calls that are dead
- in the clone. */
+ in the clone.
+
+ SUFFIX is string that is appended to the original name. */
cgraph_node *create_version_clone (tree new_decl,
vec<cgraph_edge *> redirect_callers,
- bitmap bbs_to_copy);
+ bitmap bbs_to_copy,
+ const char *suffix = NULL);
/* Perform function versioning.
Function versioning includes copying of the tree and
/* Add thunk alias into callgraph. The alias declaration is ALIAS and it
aliases DECL with an adjustments made into the first parameter.
- See comments in thunk_adjust for detail on the parameters. */
+ See comments in struct cgraph_thunk_info for detail on the parameters. */
cgraph_node * create_thunk (tree alias, tree, bool this_adjusting,
HOST_WIDE_INT fixed_offset,
HOST_WIDE_INT virtual_value,
/* Create edge from a given function to CALLEE in the cgraph. */
cgraph_edge *create_edge (cgraph_node *callee,
- gcall *call_stmt, gcov_type count,
- int freq);
+ gcall *call_stmt, profile_count count);
/* Create an indirect edge with a yet-undetermined callee where the call
statement destination is a formal parameter of the caller with index
PARAM_INDEX. */
cgraph_edge *create_indirect_edge (gcall *call_stmt, int ecf_flags,
- gcov_type count, int freq,
+ profile_count count,
bool compute_indirect_info = true);
/* Like cgraph_create_edge walk the clone tree and update all clones sharing
update the edge same way as cgraph_set_call_stmt_including_clones does. */
void create_edge_including_clones (cgraph_node *callee,
gimple *old_stmt, gcall *stmt,
- gcov_type count,
- int freq,
+ profile_count count,
cgraph_inline_failed_t reason);
/* Return the callgraph edge representing the GIMPLE_CALL statement
if any to NOTHROW. */
bool set_nothrow_flag (bool nothrow);
+ /* SET DECL_IS_MALLOC on cgraph_node's decl and on aliases of the node
+ if any. */
+ bool set_malloc_flag (bool malloc_p);
+
/* If SET_CONST is true, mark function, aliases and thunks to be ECF_CONST.
If SET_CONST if false, clear the flag.
dump_cgraph (stderr);
}
+ /* Get unique identifier of the node. */
+ inline int get_uid ()
+ {
+ return m_uid;
+ }
+
/* Record that DECL1 and DECL2 are semantically identical function
versions. */
static void record_function_versions (tree decl1, tree decl2);
/* Remove the cgraph_function_version_info and cgraph_node for DECL. This
DECL is a duplicate declaration. */
- static void delete_function_version (tree decl);
+ static void delete_function_version_by_decl (tree decl);
/* Add the function FNDECL to the call graph.
Unlike finalize_function, this function is intended to be used
cgraph_node *prev_sibling_clone;
cgraph_node *clones;
cgraph_node *clone_of;
- /* If instrumentation_clone is 1 then instrumented_version points
- to the original function used to make instrumented version.
- Otherwise points to instrumented version of the function. */
- cgraph_node *instrumented_version;
- /* If instrumentation_clone is 1 then orig_decl is the original
- function declaration. */
- tree orig_decl;
/* For functions with many calls sites it holds map from call expression
to the edge to speed up cgraph_edge function. */
hash_table<cgraph_edge_hasher> *GTY(()) call_site_hash;
cgraph_thunk_info thunk;
/* Expected number of executions: calculated in profile.c. */
- gcov_type count;
+ profile_count count;
/* How to scale counts at materialization time; used to merge
LTO units with different number of profile runs. */
int count_materialization_scale;
- /* Unique id of the node. */
- int uid;
- /* Summary unique id of the node. */
- int summary_uid;
/* ID assigned by the profiling. */
unsigned int profile_id;
/* Time profiler: first run of function. */
/* True if this decl is a dispatcher for function versions. */
unsigned dispatcher_function : 1;
/* True if this decl calls a COMDAT-local function. This is set up in
- compute_inline_parameters and inline_call. */
+ compute_fn_summary and inline_call. */
unsigned calls_comdat_local : 1;
/* True if node has been created by merge operation in IPA-ICF. */
unsigned icf_merged: 1;
- /* True when function is clone created for Pointer Bounds Checker
- instrumentation. */
- unsigned instrumentation_clone : 1;
/* True if call to node can't result in a call to free, munmap or
other operation that could make previously non-trapping memory
accesses trapping. */
unsigned indirect_call_target : 1;
private:
+ /* Unique id of the node. */
+ int m_uid;
+
/* Worker for call_for_symbol_and_aliases. */
bool call_for_symbol_and_aliases_1 (bool (*callback) (cgraph_node *,
void *),
Return true if resulting context is valid.
When CONSIDER_PLACEMENT_NEW is false, reject contexts that may be made
- valid only via alocation of new polymorphic type inside by means
+ valid only via allocation of new polymorphic type inside by means
of placement new.
When CONSIDER_BASES is false, only look for actual fields, not base types
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
for_user)) cgraph_edge {
friend class cgraph_node;
+ friend class symbol_table;
/* Remove the edge in the cgraph. */
void remove (void);
/* 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, gcov_type direct_count,
- int direct_frequency);
+ cgraph_edge *make_speculative (cgraph_node *n2, profile_count direct_count);
/* Given speculative call edge, return all three components. */
void speculative_call_info (cgraph_edge *&direct, cgraph_edge *&indirect,
/* Create clone of edge in the node N represented
by CALL_EXPR the callgraph. */
cgraph_edge * clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid,
- gcov_type count_scale, int freq_scale, bool update_original);
+ profile_count num, profile_count den,
+ bool update_original);
/* Verify edge count and frequency. */
- bool verify_count_and_frequency ();
+ bool verify_count ();
/* Return true when call of edge can not lead to return from caller
and thus it is safe to ignore its side effects for IPA analysis
/* Return true if the call can be hot. */
bool maybe_hot_p (void);
+ /* Get unique identifier of the edge. */
+ inline int get_uid ()
+ {
+ return m_uid;
+ }
+
/* Rebuild cgraph edges for current function node. This needs to be run after
passes that don't update the cgraph. */
static unsigned int rebuild_edges (void);
static void rebuild_references (void);
/* Expected number of executions: calculated in profile.c. */
- gcov_type count;
+ profile_count count;
cgraph_node *caller;
cgraph_node *callee;
cgraph_edge *prev_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;
- /* Expected frequency of executions within the function.
- When set to CGRAPH_FREQ_BASE, the edge is expected to be called once
- per function call. The range is 0 to CGRAPH_FREQ_MAX. */
- int frequency;
- /* Unique id of the edge. */
- int uid;
/* 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
/* Return true if call must bind to current definition. */
bool binds_to_current_def_p ();
+ /* Expected frequency of executions within the function.
+ When set to CGRAPH_FREQ_BASE, the edge is expected to be called once
+ per function call. The range is 0 to CGRAPH_FREQ_MAX. */
+ int frequency ();
+
+ /* Expected frequency of executions within the function. */
+ sreal sreal_frequency ();
private:
+ /* Unique id of the edge. */
+ int m_uid;
+
/* Remove the edge from the list of the callers of the callee. */
void remove_caller (void);
friend class cgraph_node;
friend class cgraph_edge;
- symbol_table (): cgraph_max_summary_uid (1)
+ symbol_table (): cgraph_max_uid (1), edges_max_uid (1)
{
}
/* Allocate new callgraph node and insert it into basic data structures. */
cgraph_node *create_empty (void);
- /* Release a callgraph NODE with UID and put in to the list
- of free nodes. */
- void release_symbol (cgraph_node *node, int uid);
+ /* Release a callgraph NODE. */
+ void release_symbol (cgraph_node *node);
/* Output all variables enqueued to be assembled. */
bool output_variables (void);
/* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */
void change_decl_assembler_name (tree decl, tree name);
+ /* Dump symbol table to F. */
+ void dump (FILE *f);
+
+ /* Dump symbol table to stderr. */
+ void DEBUG_FUNCTION debug (void);
+
/* Return true if assembler names NAME1 and NAME2 leads to the same symbol
name. */
static bool assembler_names_equal_p (const char *name1, const char *name2);
int cgraph_count;
int cgraph_max_uid;
- int cgraph_max_summary_uid;
int edges_count;
int edges_max_uid;
/* Return symbol used to separate symbol name from suffix. */
static char symbol_suffix_separator ();
+ FILE* GTY ((skip)) ipa_clones_dump_file;
+
+ hash_set <const cgraph_node *> GTY ((skip)) cloned_nodes;
+
private:
/* Allocate new callgraph node. */
inline cgraph_node * allocate_cgraph_symbol (void);
parameters of which only CALLEE can be NULL (when creating an indirect call
edge). */
cgraph_edge *create_edge (cgraph_node *caller, cgraph_node *callee,
- gcall *call_stmt, gcov_type count, int freq,
+ gcall *call_stmt, profile_count count,
bool indir_unknown_callee);
/* Put the edge onto the free list. */
/* Initialize datastructures so DECL is a function in lowered gimple form.
IN_SSA is true if the gimple is in SSA. */
-basic_block init_lowered_empty_function (tree, bool, gcov_type);
+basic_block init_lowered_empty_function (tree, bool, profile_count);
tree thunk_adjust (gimple_stmt_iterator *, tree, bool, HOST_WIDE_INT, tree);
/* In cgraphclones.c */
void tree_function_versioning (tree, tree, vec<ipa_replace_map *, va_gc> *,
bool, bitmap, bool, bitmap, basic_block);
+void dump_callgraph_transformation (const cgraph_node *original,
+ const cgraph_node *clone,
+ const char *suffix);
+tree cgraph_build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
+ bool skip_return);
+
/* In cgraphbuild.c */
int compute_call_stmt_bb_frequency (tree, basic_block bb);
void record_references_in_initializer (tree, bool);
/* In varpool.c */
tree ctor_for_folding (tree);
-/* In tree-chkp.c */
-extern bool chkp_function_instrumented_p (tree fndecl);
+/* In ipa-inline-analysis.c */
+void initialize_inline_failed (struct cgraph_edge *);
+bool speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining);
/* Return true when the symbol is real symbol, i.e. it is not inline clone
or abstract function kept for debug info purposes only. */
{
ipa_ref *ref = NULL;
iterate_reference (0, ref);
- if (ref->use == IPA_REF_CHKP)
- iterate_reference (1, ref);
gcc_checking_assert (ref->use == IPA_REF_ALIAS);
return ref->referred;
}
/* Release a callgraph NODE with UID and put in to the list of free nodes. */
inline void
-symbol_table::release_symbol (cgraph_node *node, int uid)
+symbol_table::release_symbol (cgraph_node *node)
{
cgraph_count--;
list. */
memset (node, 0, sizeof (*node));
node->type = SYMTAB_FUNCTION;
- node->uid = uid;
SET_NEXT_FREE_NODE (node, free_nodes);
free_nodes = node;
}
free_nodes = NEXT_FREE_NODE (node);
}
else
- {
- node = ggc_cleared_alloc<cgraph_node> ();
- node->uid = cgraph_max_uid++;
- }
+ node = ggc_cleared_alloc<cgraph_node> ();
- node->summary_uid = cgraph_max_summary_uid++;
+ node->m_uid = cgraph_max_uid++;
return node;
}
{
gcc_assert (!global.inlined_to);
return (!force_output && !address_taken
+ && !ifunc_resolver
&& !used_from_other_partition
&& !DECL_VIRTUAL_P (decl)
&& !DECL_STATIC_CONSTRUCTOR (decl)
cgraph_node::can_remove_if_no_direct_calls_and_refs_p (void)
{
gcc_checking_assert (!global.inlined_to);
- /* Instrumentation clones should not be removed before
- instrumentation happens. New callers may appear after
- instrumentation. */
- if (instrumentation_clone
- && !chkp_function_instrumented_p (decl))
- return false;
/* Extern inlines can always go, we will use the external definition. */
if (DECL_EXTERNAL (decl))
return true;
return false;
}
+/* Expected frequency of executions within the function.
+ When set to CGRAPH_FREQ_BASE, the edge is expected to be called once
+ per function call. The range is 0 to CGRAPH_FREQ_MAX. */
+
+inline int
+cgraph_edge::frequency ()
+{
+ return count.to_cgraph_frequency (caller->global.inlined_to
+ ? caller->global.inlined_to->count
+ : caller->count);
+}
+
+
/* Return true if the TM_CLONE bit is set for a given FNDECL. */
static inline bool
decl_is_tm_clone (const_tree fndecl)
return (!outer_type && !speculative_outer_type);
}
-/* Return true if NODE is local. Instrumentation clones are counted as local
- only when original function is local. */
-
-static inline bool
-cgraph_local_p (cgraph_node *node)
-{
- if (!node->instrumentation_clone || !node->instrumented_version)
- return node->local.local;
-
- return node->local.local && node->instrumented_version->local.local;
-}
-
/* When using fprintf (or similar), problems can arise with
transient generated strings. Many string-generation APIs
only support one result being alive at once (e.g. by