/* Callgraph handling code.
- Copyright (C) 2003-2015 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"
+
+class ipa_opt_pass_d;
+typedef ipa_opt_pass_d *ipa_opt_pass;
/* Symbol table consists of functions and variables.
TODO: add labels and CONST_DECLs. */
/* Section names are stored as reference counted strings in GGC safe hashtable
(to make them survive through PCH). */
-struct GTY((for_user)) section_hash_entry_d
+struct GTY((for_user)) section_hash_entry
{
int ref_count;
char *name; /* As long as this datastructure stays in GGC, we can not put
way */
};
-typedef struct section_hash_entry_d section_hash_entry;
-
-struct section_name_hasher : ggc_hasher<section_hash_entry *>
+struct section_name_hasher : ggc_ptr_hash<section_hash_entry>
{
typedef const char *compare_type;
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. */
REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
of the use and STMT the statement (if it exists). */
ipa_ref *create_reference (symtab_node *referred_node,
- enum ipa_ref_use use_type, gimple stmt);
+ 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);
void clone_referring (symtab_node *node);
/* Clone reference REF to this symtab_node and set its stmt to STMT. */
- ipa_ref *clone_reference (ipa_ref *ref, gimple stmt);
+ ipa_ref *clone_reference (ipa_ref *ref, gimple *stmt);
/* Find the structure describing a reference to REFERRED_NODE
and associated with statement STMT. */
- ipa_ref *find_reference (symtab_node *referred_node, gimple stmt,
+ ipa_ref *find_reference (symtab_node *referred_node, gimple *stmt,
unsigned int lto_stmt_uid);
/* Remove all references that are associated with statement STMT. */
- void remove_stmt_references (gimple stmt);
+ void remove_stmt_references (gimple *stmt);
/* Remove all stmt references in non-speculative references.
Those are not maintained during inlining & clonning.
/* Walk the alias chain to return the symbol NODE is alias of.
If NODE is not an alias, return NODE.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
- symtab_node *ultimate_alias_target (enum availability *avail = NULL);
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
+ symtab_node *ultimate_alias_target (enum availability *avail = NULL,
+ struct symtab_node *ref = NULL);
/* Return next reachable static symbol with initializer after NODE. */
inline symtab_node *next_defined_symbol (void);
/* Add reference recording that symtab node is alias of TARGET.
+ If TRANSPARENT is true make the alias to be transparent alias.
The function can fail in the case of aliasing cycles; in this case
it returns false. */
- bool resolve_alias (symtab_node *target);
+ bool resolve_alias (symtab_node *target, bool transparent = false);
/* C++ FE sometimes change linkage flags after producing same
body aliases. */
/* Return the initialization priority. */
priority_type get_init_priority ();
- /* Return availability of NODE. */
- enum availability get_availability (void);
+ /* Return availability of NODE when referenced from REF. */
+ enum availability get_availability (symtab_node *ref = NULL);
+
+ /* Return true if NODE binds to current definition in final executable
+ when referenced from REF. If REF is NULL return conservative value
+ for any reference. */
+ bool binds_to_current_def_p (symtab_node *ref = NULL);
/* Make DECL local. */
void make_decl_local (void);
+ /* Copy visibility from N. */
+ void copy_visibility_from (symtab_node *n);
+
/* Return desired alignment of the definition. This is NOT alignment useful
to access THIS, because THIS may be interposable and DECL_ALIGN should
be used instead. It however must be guaranteed when output definition
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 (void);
+ bool referred_to_p (bool include_self = true);
- /* Return true if NODE can be discarded by linker from the binary. */
+ /* Return true if symbol can be discarded by linker from the binary.
+ Assume that symbol is used (so there is no need to take into account
+ garbage collecting linkers)
+
+ This can happen for comdats, commons and weaks when they are previaled
+ by other definition at static linking time. */
inline bool
can_be_discarded_p (void)
{
return (DECL_EXTERNAL (decl)
- || (get_comdat_group ()
- && resolution != LDPR_PREVAILING_DEF
- && resolution != LDPR_PREVAILING_DEF_IRONLY
- && resolution != LDPR_PREVAILING_DEF_IRONLY_EXP));
+ || ((get_comdat_group ()
+ || DECL_COMMON (decl)
+ || (DECL_SECTION_NAME (decl) && DECL_WEAK (decl)))
+ && ((resolution != LDPR_PREVAILING_DEF
+ && resolution != LDPR_PREVAILING_DEF_IRONLY_EXP)
+ || flag_incremental_link)
+ && resolution != LDPR_PREVAILING_DEF_IRONLY));
}
/* Return true if NODE is local to a particular COMDAT group, and must not
/* Return 0 if symbol is known to have different address than S2,
Return 1 if symbol is known to have same address as S2,
- return 2 otherwise. */
- int equal_address_to (symtab_node *s2);
+ return 2 otherwise.
+
+ If MEMORY_ACCESSED is true, assume that both memory pointer to THIS
+ and S2 is going to be accessed. This eliminates the situations when
+ either THIS or S2 is NULL and is seful for comparing bases when deciding
+ about memory aliasing. */
+ int equal_address_to (symtab_node *s2, bool memory_accessed = false);
/* Return true if symbol's address may possibly be compared to other
symbol's address. */
and NULL otherwise. */
static inline symtab_node *get (const_tree decl)
{
-#ifdef ENABLE_CHECKING
/* Check that we are called for sane type of object - functions
and static or external variables. */
gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL
memcpy/memset on the tree nodes. */
gcc_checking_assert (!decl->decl_with_vis.symtab_node
|| decl->decl_with_vis.symtab_node->decl == decl);
-#endif
return decl->decl_with_vis.symtab_node;
}
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);
+ /* Perform internal consistency checks, if they are enabled. */
+ static inline void checking_verify_symtab_nodes (void);
+
/* Type of the symbol. */
ENUM_BITFIELD (symtab_type) type : 8;
/* True when symbol is an alias.
Set by ssemble_alias. */
unsigned alias : 1;
+ /* When true the alias is translated into its target symbol either by GCC
+ or assembler (it also may just be a duplicate declaration of the same
+ linker name).
+
+ Currently transparent aliases come in three different flavors
+ - aliases having the same assembler name as their target (aka duplicated
+ declarations). In this case the assembler names compare via
+ assembler_names_equal_p and weakref is false
+ - aliases that are renamed at a time being output to final file
+ by varasm.c. For those DECL_ASSEMBLER_NAME have
+ IDENTIFIER_TRANSPARENT_ALIAS set and thus also their assembler
+ name must be unique.
+ Weakrefs belong to this cateogry when we target assembler without
+ .weakref directive.
+ - weakrefs that are renamed by assembler via .weakref directive.
+ In this case the alias may or may not be definition (depending if
+ target declaration was seen by the compiler), weakref is set.
+ Unless we are before renaming statics, assembler names are different.
+
+ Given that we now support duplicate declarations, the second option is
+ redundant and will be removed. */
+ unsigned transparent_alias : 1;
/* True when alias is a weakref. */
unsigned weakref : 1;
/* C++ frontend produce same body aliases and extra name aliases for
/* 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;
static bool noninterposable_alias (symtab_node *node, void *data);
/* Worker for ultimate_alias_target. */
- symtab_node *ultimate_alias_target_1 (enum availability *avail = NULL);
+ 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
+symtab_node::checking_verify_symtab_nodes (void)
+{
+ if (flag_checking)
+ symtab_node::verify_symtab_nodes ();
+}
+
/* Walk all aliases for NODE. */
#define FOR_EACH_ALIAS(node, alias) \
for (unsigned x_i = 0; node->iterate_direct_aliases (x_i, alias); x_i++)
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;
};
Available after function is analyzed. */
struct GTY(()) cgraph_local_info {
- /* Set when function function is visible in current compilation unit only
- and its address is never taken. */
+ /* Set when function is visible in current compilation unit only and
+ its address is never taken. */
unsigned local : 1;
/* False when there is something makes versioning impossible. */
cgraph_node *inlined_to;
};
-/* Information about the function that is propagated by the RTL backend.
- Available only for functions that has been already assembled. */
-
-struct GTY(()) cgraph_rtl_info {
- unsigned int preferred_incoming_stack_boundary;
-
- /* Call unsaved hard registers really used by the corresponding
- function (including ones used by functions called by the
- function). */
- HARD_REG_SET function_used_regs;
- /* Set if function_used_regs is valid. */
- unsigned function_used_regs_valid: 1;
-};
-
/* Represent which DECL tree (or reference to such tree)
will be replaced by another tree while versioning. */
struct GTY(()) ipa_replace_map
{
SIMD_CLONE_ARG_TYPE_VECTOR,
SIMD_CLONE_ARG_TYPE_UNIFORM,
+ /* These are only for integer/pointer arguments passed by value. */
SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP,
SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP,
+ /* These 6 are only for reference type arguments or arguments passed
+ by reference. */
+ SIMD_CLONE_ARG_TYPE_LINEAR_REF_CONSTANT_STEP,
+ SIMD_CLONE_ARG_TYPE_LINEAR_REF_VARIABLE_STEP,
+ SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP,
+ SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP,
+ SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP,
+ SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP,
SIMD_CLONE_ARG_TYPE_MASK
};
variable), uniform, or vector. */
enum cgraph_simd_clone_arg_type arg_type;
- /* For arg_type SIMD_CLONE_ARG_TYPE_LINEAR_CONSTANT_STEP this is
+ /* For arg_type SIMD_CLONE_ARG_TYPE_LINEAR_*CONSTANT_STEP this is
the constant linear step, if arg_type is
- SIMD_CLONE_ARG_TYPE_LINEAR_VARIABLE_STEP, this is index of
+ SIMD_CLONE_ARG_TYPE_LINEAR_*VARIABLE_STEP, this is index of
the uniform argument holding the step, otherwise 0. */
HOST_WIDE_INT linear_step;
/* Max hardware vector size in bits for floating point vectors. */
unsigned int vecsize_float;
- /* The mangling character for a given vector size. This is is used
+ /* Machine mode of the mask argument(s), if they are to be passed
+ as bitmasks in integer argument(s). VOIDmode if masks are passed
+ as vectors of characteristic type. */
+ machine_mode mask_mode;
+
+ /* The mangling character for a given vector size. This is used
to determine the ISA mangling bit as specified in the Intel
Vector ABI. */
unsigned char vecsize_mangle;
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 cgraph_edge;
-struct cgraph_edge_hasher : ggc_hasher<cgraph_edge *>
+struct cgraph_edge_hasher : ggc_ptr_hash<cgraph_edge>
{
- typedef gimple compare_type;
+ typedef gimple *compare_type;
static hashval_t hash (cgraph_edge *);
- static hashval_t hash (gimple);
- static bool equal (cgraph_edge *, gimple);
+ static hashval_t hash (gimple *);
+ static bool equal (cgraph_edge *, gimple *);
};
/* The cgraph data structure.
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
/* Record all references from cgraph_node that are taken
in statement STMT. */
- void record_stmt_references (gimple stmt);
+ void record_stmt_references (gimple *stmt);
/* Like cgraph_set_call_stmt but walk the clone tree and update all
clones sharing the same function body.
When WHOLE_SPECULATIVE_EDGES is true, all three components of
speculative edge gets updated. Otherwise we update only direct
call. */
- void set_call_stmt_including_clones (gimple old_stmt, gcall *new_stmt,
+ void set_call_stmt_including_clones (gimple *old_stmt, gcall *new_stmt,
bool update_speculative = true);
/* Walk the alias chain to return the function cgraph_node is alias of.
Walk through thunk, too.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
- cgraph_node *function_symbol (enum availability *avail = NULL);
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
+ cgraph_node *function_symbol (enum availability *avail = NULL,
+ struct symtab_node *ref = NULL);
/* Walk the alias chain to return the function cgraph_node is alias of.
Walk through non virtual thunks, too. Thus we return either a function
or a virtual thunk node.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
cgraph_node *function_or_virtual_thunk_symbol
- (enum availability *avail = NULL);
+ (enum availability *avail = NULL,
+ struct symtab_node *ref = NULL);
/* Create node representing clone of N executed COUNT times. Decrease
the execution counts from original node too.
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,
/* Given function symbol, walk the alias chain to return the function node
is alias of. Do not walk through thunks.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
- cgraph_node *ultimate_alias_target (availability *availability = NULL);
+ cgraph_node *ultimate_alias_target (availability *availability = NULL,
+ symtab_node *ref = NULL);
/* Expand thunk NODE to gimple if possible.
When FORCE_GIMPLE_THUNK is true, gimple thunk is created and
/* 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
same function body. If clones already have edge for OLD_STMT; only
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,
+ gimple *old_stmt, gcall *stmt,
+ profile_count count,
cgraph_inline_failed_t reason);
/* Return the callgraph edge representing the GIMPLE_CALL statement
CALL_STMT. */
- cgraph_edge *get_edge (gimple call_stmt);
+ cgraph_edge *get_edge (gimple *call_stmt);
/* Collect all callers of cgraph_node and its aliases that are known to lead
- to NODE (i.e. are not overwritable). */
+ to NODE (i.e. are not overwritable) and that are not thunks. */
vec<cgraph_edge *> collect_callers (void);
/* Remove all callers from the node. */
/* Return function availability. See cgraph.h for description of individual
return values. */
- enum availability get_availability (void);
+ enum availability get_availability (symtab_node *ref = NULL);
/* Set TREE_NOTHROW on cgraph_node's decl and on aliases of the node
if any to NOTHROW. */
- void set_nothrow_flag (bool 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.
+
+ When setting the flag be careful about possible interposition and
+ do not set the flag for functions that can be interposet and set pure
+ flag for functions that can bind to other definition.
+
+ Return true if any change was done. */
- /* Set TREE_READONLY on cgraph_node's decl and on aliases of the node
- if any to READONLY. */
- void set_const_flag (bool readonly, bool looping);
+ bool set_const_flag (bool set_const, bool looping);
/* Set DECL_PURE_P on cgraph_node's decl and on aliases of the node
- if any to PURE. */
- void set_pure_flag (bool pure, bool looping);
+ if any to PURE.
+
+ When setting the flag, be careful about possible interposition.
+ Return true if any change was done. */
+
+ bool set_pure_flag (bool pure, bool looping);
/* Call callback on function and aliases associated to the function.
When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
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
static cgraph_local_info *local_info (tree decl);
/* Return local info for the compiled function. */
- static cgraph_rtl_info *rtl_info (tree);
+ static struct cgraph_rtl_info *rtl_info (tree);
/* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
Return NULL if there's no such node. */
/* Verify whole cgraph structure. */
static void DEBUG_FUNCTION verify_cgraph_nodes (void);
+ /* Verify cgraph, if consistency checking is enabled. */
+ static inline void checking_verify_cgraph_nodes (void);
+
/* Worker to bring NODE local. */
static bool make_local (cgraph_node *node, void *);
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_local_info local;
cgraph_global_info global;
- cgraph_rtl_info rtl;
+ struct cgraph_rtl_info *rtl;
cgraph_clone_info clone;
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 nonfreeing_fn : 1;
/* True if there was multiple COMDAT bodies merged by lto-symtab. */
- unsigned merged : 1;
+ unsigned merged_comdat : 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 split_part : 1;
+ /* True if the function appears as possible target of indirect call. */
+ 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 *),
/* Build context for pointer REF contained in FNDECL at statement STMT.
if INSTANCE is non-NULL, return pointer to the object described by
the context. */
- ipa_polymorphic_call_context (tree fndecl, tree ref, gimple stmt,
+ ipa_polymorphic_call_context (tree fndecl, tree ref, gimple *stmt,
tree *instance = NULL);
/* Look for vtable stores or constructor calls to work out dynamic type
of memory location. */
- bool get_dynamic_type (tree, tree, tree, gimple);
+ bool get_dynamic_type (tree, tree, tree, gimple *);
/* Make context non-speculative. */
void clear_speculation ();
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
unsigned agg_contents : 1;
/* Set when this is a call through a member pointer. */
unsigned member_ptr : 1;
- /* When the previous bit is set, this one determines whether the destination
- is loaded from a parameter passed by reference. */
+ /* When the agg_contents bit is set, this one determines whether the
+ destination is loaded from a parameter passed by reference. */
unsigned by_ref : 1;
+ /* When the agg_contents bit is set, this one determines whether we can
+ deduce from the function body that the loaded value from the reference is
+ never modified between the invocation of the function and the load
+ point. */
+ unsigned guaranteed_unmodified : 1;
/* For polymorphic calls this specify whether the virtual table pointer
may have changed in between function entry and the call. */
unsigned vptr_changed : 1;
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,
/* 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);
+ gimple *redirect_call_stmt_to_callee (void);
/* 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
type. */
unsigned in_polymorphic_cdtor : 1;
+ /* 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);
void analyze (void);
/* Return variable availability. */
- availability get_availability (void);
+ availability get_availability (symtab_node *ref = NULL);
/* When doing LTO, read variable's constructor from disk if
it is not already present. */
/* For given variable pool node, walk the alias chain to return the function
the variable is alias of. Do not walk through thunks.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
inline varpool_node *ultimate_alias_target
- (availability *availability = NULL);
+ (availability *availability = NULL, symtab_node *ref = NULL);
/* Return node that alias is aliasing. */
inline varpool_node *get_alias_target (void);
FINISHED
};
-struct asmname_hasher
+struct asmname_hasher : ggc_ptr_hash <symtab_node>
{
- typedef symtab_node *value_type;
typedef const_tree compare_type;
static hashval_t hash (symtab_node *n);
static bool equal (symtab_node *n, const_tree t);
- static void ggc_mx (symtab_node *n);
- static void pch_nx (symtab_node *&);
- static void pch_nx (symtab_node *&, gt_pointer_operator, void *);
- static void remove (symtab_node *) {}
};
class GTY((tag ("SYMTAB"))) symbol_table
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)
{
}
/* Once all functions from compilation unit are in memory, produce all clones
and update all calls. We might also do this on demand if we don't want to
bring all functions to memory prior compilation, but current WHOPR
- implementation does that and it is is bit easier to keep everything right
+ implementation does that and it is bit easier to keep everything right
in this order. */
void materialize_all_clones (void);
/* 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;
FILE* GTY ((skip)) dump_file;
+ /* 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. */
return symbol_table::decl_assembler_name_equal (n->decl, t);
}
-extern void gt_ggc_mx (symtab_node *&);
-
-inline void
-asmname_hasher::ggc_mx (symtab_node *n)
-{
- gt_ggc_mx (n);
-}
-
-extern void gt_pch_nx (symtab_node *&);
-
-inline void
-asmname_hasher::pch_nx (symtab_node *&n)
-{
- gt_pch_nx (n);
-}
-
-inline void
-asmname_hasher::pch_nx (symtab_node *&n, gt_pointer_operator op, void *cookie)
-{
- op (&n, cookie);
-}
-
/* In cgraph.c */
void cgraph_c_finalize (void);
void release_function_body (tree);
cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void);
-void cgraph_update_edges_for_call_stmt (gimple, tree, gimple);
+void cgraph_update_edges_for_call_stmt (gimple *, tree, gimple *);
bool cgraph_function_possibly_inlined_p (tree);
const char* cgraph_inline_failed_string (cgraph_inline_failed_t);
cgraph_inline_failed_type_t cgraph_inline_failed_type (cgraph_inline_failed_t);
-extern bool gimple_check_call_matching_types (gimple, tree, bool);
+extern bool gimple_check_call_matching_types (gimple *, tree, bool);
/* In cgraphunit.c */
void cgraphunit_c_finalize (void);
/* 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 */
tree clone_function_name_1 (const char *, const char *);
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. */
if (DECL_ABSTRACT_P (decl))
return false;
+ if (transparent_alias && definition)
+ return false;
if (!is_a <cgraph_node *> (this))
return true;
cnode = dyn_cast <cgraph_node *> (this);
{
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 true;
}
+/* Verify cgraph, if consistency checking is enabled. */
+
+inline void
+cgraph_node::checking_verify_cgraph_nodes (void)
+{
+ if (flag_checking)
+ cgraph_node::verify_cgraph_nodes ();
+}
+
/* Return true when variable can be removed from variable pool
if all direct calls are eliminated. */
&& !force_output);
}
-struct tree_descriptor_hasher : ggc_hasher<constant_descriptor_tree *>
+struct tree_descriptor_hasher : ggc_ptr_hash<constant_descriptor_tree>
{
static hashval_t hash (constant_descriptor_tree *);
static bool equal (constant_descriptor_tree *, constant_descriptor_tree *);
/* Walk the alias chain to return the symbol NODE is alias of.
If NODE is not an alias, return NODE.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
inline symtab_node *
-symtab_node::ultimate_alias_target (enum availability *availability)
+symtab_node::ultimate_alias_target (enum availability *availability,
+ symtab_node *ref)
{
if (!alias)
{
if (availability)
- *availability = get_availability ();
+ *availability = get_availability (ref);
return this;
}
- return ultimate_alias_target_1 (availability);
+ return ultimate_alias_target_1 (availability, ref);
}
/* Given function symbol, walk the alias chain to return the function node
is alias of. Do not walk through thunks.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
inline cgraph_node *
-cgraph_node::ultimate_alias_target (enum availability *availability)
+cgraph_node::ultimate_alias_target (enum availability *availability,
+ symtab_node *ref)
{
cgraph_node *n = dyn_cast <cgraph_node *>
- (symtab_node::ultimate_alias_target (availability));
+ (symtab_node::ultimate_alias_target (availability, ref));
if (!n && availability)
*availability = AVAIL_NOT_AVAILABLE;
return n;
/* For given variable pool node, walk the alias chain to return the function
the variable is alias of. Do not walk through thunks.
- When AVAILABILITY is non-NULL, get minimal availability in the chain. */
+ When AVAILABILITY is non-NULL, get minimal availability in the chain.
+ When REF is non-NULL, assume that reference happens in symbol REF
+ when determining the availability. */
inline varpool_node *
-varpool_node::ultimate_alias_target (availability *availability)
+varpool_node::ultimate_alias_target (availability *availability,
+ symtab_node *ref)
{
varpool_node *n = dyn_cast <varpool_node *>
- (symtab_node::ultimate_alias_target (availability));
+ (symtab_node::ultimate_alias_target (availability, ref));
if (!n && availability)
*availability = AVAIL_NOT_AVAILABLE;
callee->callers = next_caller;
}
+/* Return true if call must bind to current definition. */
+
+inline bool
+cgraph_edge::binds_to_current_def_p ()
+{
+ if (callee)
+ return callee->binds_to_current_def_p (caller);
+ else
+ 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 cgraph_node::get_create (node);
}
-/* Return availability of NODE. */
+/* Return availability of NODE when referenced from REF. */
inline enum availability
-symtab_node::get_availability (void)
+symtab_node::get_availability (symtab_node *ref)
{
if (is_a <cgraph_node *> (this))
- return dyn_cast <cgraph_node *> (this)->get_availability ();
+ return dyn_cast <cgraph_node *> (this)->get_availability (ref);
else
- return dyn_cast <varpool_node *> (this)->get_availability ();;
+ return dyn_cast <varpool_node *> (this)->get_availability (ref);
}
/* Call calback on symtab node and aliases associated to this node.
- When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
- skipped. */
+ When INCLUDE_OVERWRITABLE is false, overwritable symbols are skipped. */
inline bool
symtab_node::call_for_symbol_and_aliases (bool (*callback) (symtab_node *,
void *data,
bool include_overwritable)
{
- if (callback (this, data))
- return true;
+ if (include_overwritable
+ || get_availability () > AVAIL_INTERPOSABLE)
+ {
+ if (callback (this, data))
+ return true;
+ }
if (has_aliases_p ())
return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
return false;
}
/* Call callback on function and aliases associated to the function.
- When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+ When INCLUDE_OVERWRITABLE is false, overwritable symbols are
skipped. */
inline bool
void *data,
bool include_overwritable)
{
- if (callback (this, data))
- return true;
+ if (include_overwritable
+ || get_availability () > AVAIL_INTERPOSABLE)
+ {
+ if (callback (this, data))
+ return true;
+ }
if (has_aliases_p ())
return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
return false;
}
/* Call calback on varpool symbol and aliases associated to varpool symbol.
- When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
+ When INCLUDE_OVERWRITABLE is false, overwritable symbols are
skipped. */
inline bool
void *data,
bool include_overwritable)
{
- if (callback (this, data))
- return true;
+ if (include_overwritable
+ || get_availability () > AVAIL_INTERPOSABLE)
+ {
+ if (callback (this, data))
+ return true;
+ }
if (has_aliases_p ())
return call_for_symbol_and_aliases_1 (callback, data, include_overwritable);
return false;
}
-/* Return true if NODE's address can be compared. */
-
-inline bool
-symtab_node::address_can_be_compared_p ()
-{
- /* Address of virtual tables and functions is never compared. */
- if (DECL_VIRTUAL_P (decl))
- return false;
- /* Address of C++ cdtors is never compared. */
- if (is_a <cgraph_node *> (this)
- && (DECL_CXX_CONSTRUCTOR_P (decl)
- || DECL_CXX_DESTRUCTOR_P (decl)))
- return false;
- /* Constant pool symbols addresses are never compared.
- flag_merge_constants permits us to assume the same on readonly vars. */
- if (is_a <varpool_node *> (this)
- && (DECL_IN_CONSTANT_POOL (decl)
- || (flag_merge_constants >= 2
- && TREE_READONLY (decl) && !TREE_THIS_VOLATILE (decl))))
- return false;
- return true;
-}
-
/* Return true if refernece may be used in address compare. */
inline bool
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