/* Callgraph handling code.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
Contributed by Jan Hubicka
#ifndef GCC_CGRAPH_H
#define GCC_CGRAPH_H
+
+#include "plugin-api.h"
+#include "vec.h"
#include "tree.h"
#include "basic-block.h"
+#include "function.h"
+#include "ipa-ref.h" /* FIXME: inappropriate dependency of cgraph on IPA. */
enum availability
{
AVAIL_LOCAL
};
-extern const char * const cgraph_availability_names[];
-
-/* Function inlining information. */
+/* This is the information that is put into the cgraph local structure
+ to recover a function. */
+struct lto_file_decl_data;
-struct GTY(()) inline_summary
-{
- /* Estimated stack frame consumption by the function. */
- HOST_WIDE_INT estimated_self_stack_size;
-
- /* Size of the function body. */
- int self_size;
- /* How many instructions are likely going to disappear after inlining. */
- int size_inlining_benefit;
- /* Estimated time spent executing the function body. */
- int self_time;
- /* How much time is going to be saved by inlining. */
- int time_inlining_benefit;
+extern const char * const cgraph_availability_names[];
+extern const char * const ld_plugin_symbol_resolution_names[];
+
+/* Information about thunk, used only for same body aliases. */
+
+struct GTY(()) cgraph_thunk_info {
+ /* Information about the thunk. */
+ HOST_WIDE_INT fixed_offset;
+ HOST_WIDE_INT virtual_value;
+ tree alias;
+ bool this_adjusting;
+ bool virtual_offset_p;
+ /* Set to true when alias node is thunk. */
+ bool thunk_p;
};
/* Information about the function collected locally.
Available after function is analyzed. */
struct GTY(()) cgraph_local_info {
- struct inline_summary inline_summary;
+ /* File stream where this node is being written to. */
+ struct lto_file_decl_data * lto_file_data;
/* Set when function function is visible in current compilation unit only
and its address is never taken. */
/* Set when function is visible by other units. */
unsigned externally_visible : 1;
-
+
/* Set once it has been finalized so we consider it to be output. */
unsigned finalized : 1;
- /* False when there something makes inlining impossible (such as va_arg). */
- unsigned inlinable : 1;
-
- /* True when function should be inlined independently on its size. */
- unsigned disregard_inline_limits : 1;
+ /* False when function calling convention and signature can not be changed.
+ This is the case when __builtin_apply_args is used. */
+ unsigned can_change_signature : 1;
/* True when the function has been originally extern inline, but it is
redefined now. */
unsigned redefined_extern_inline : 1;
-
- /* True if statics_read_for_function and
- statics_written_for_function contain valid data. */
- unsigned for_functions_valid : 1;
-
- /* True if the function is going to be emitted in some other translation
- unit, referenced from vtable. */
- unsigned vtable_method : 1;
};
/* Information about the function that needs to be computed globally
once compilation is finished. Available only with -funit-at-a-time. */
struct GTY(()) cgraph_global_info {
- /* Estimated stack frame consumption by the function. */
- HOST_WIDE_INT estimated_stack_size;
- /* Expected offset of the stack frame of inlined function. */
- HOST_WIDE_INT stack_frame_offset;
-
/* For inline clones this points to the function they will be
inlined into. */
struct cgraph_node *inlined_to;
-
- /* Estimated size of the function after inlining. */
- int time;
- int size;
-
- /* Estimated growth after inlining. INT_MIN if not computed. */
- int estimated_growth;
-
- /* Set iff the function has been inlined at least once. */
- bool inlined;
};
/* Information about the function that is propagated by the RTL backend.
tree old_tree;
/* The new (replacing) tree. */
tree new_tree;
+ /* Parameter number to replace, when old_tree is NULL. */
+ int parm_num;
/* True when a substitution should be done, false otherwise. */
bool replace_p;
/* True when we replace a reference to old_tree. */
bitmap combined_args_to_skip;
};
+
/* The cgraph data structure.
Each function decl has assigned cgraph_node listing callees and callers. */
struct cgraph_edge *callers;
struct cgraph_node *next;
struct cgraph_node *previous;
+ /* List of edges representing indirect calls with a yet undetermined
+ callee. */
+ struct cgraph_edge *indirect_calls;
/* For nested functions points to function the node is nested in. */
struct cgraph_node *origin;
/* Points to first nested function, if any. */
struct cgraph_node *prev_sibling_clone;
struct cgraph_node *clones;
struct cgraph_node *clone_of;
+ /* Circular list of nodes in the same comdat group if non-NULL. */
+ struct cgraph_node *same_comdat_group;
/* For functions with many calls sites it holds map from call expression
to the edge to speed up cgraph_edge function. */
htab_t GTY((param_is (struct cgraph_edge))) call_site_hash;
+ /* Declaration node used to be clone of. */
+ tree former_clone_of;
PTR GTY ((skip)) aux;
+ /* Interprocedural passes scheduled to have their transform functions
+ applied next time we execute local pass on them. We maintain it
+ per-function in order to allow IPA passes to introduce new functions. */
+ VEC(ipa_opt_pass,heap) * GTY((skip)) ipa_transforms_to_apply;
+
+ struct ipa_ref_list ref_list;
struct cgraph_local_info local;
struct cgraph_global_info global;
struct cgraph_rtl_info rtl;
struct cgraph_clone_info clone;
+ struct cgraph_thunk_info thunk;
/* Expected number of executions: calculated in profile.c. */
gcov_type 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;
/* Ordering of all cgraph nodes. */
int order;
- /* unique id for profiling. pid is not suitable because of different
- number of cfg nodes with -fprofile-generate and -fprofile-use */
- int pid;
+ enum ld_plugin_symbol_resolution resolution;
- /* Set when function must be output - it is externally visible
- or its address is taken. */
+ /* Set when function must be output for some reason. The primary
+ use of this flag is to mark functions needed to be output for
+ non-standard reason. Functions that are externally visible
+ or reachable from functions needed to be output are marked
+ by specialized flags. */
unsigned needed : 1;
- /* Set when function has address taken. */
+ /* Set when function has address taken.
+ In current implementation it imply needed flag. */
unsigned address_taken : 1;
/* Set when decl is an abstract function pointed to by the
ABSTRACT_DECL_ORIGIN of a reachable function. */
unsigned abstract_and_needed : 1;
/* Set when function is reachable by call from other function
- that is either reachable or needed. */
+ that is either reachable or needed.
+ This flag is computed at original cgraph construction and then
+ updated in cgraph_remove_unreachable_nodes. Note that after
+ cgraph_remove_unreachable_nodes cgraph still can contain unreachable
+ nodes when they are needed for virtual clone instantiation. */
unsigned reachable : 1;
+ /* Set when function is reachable by call from other LTRANS partition. */
+ unsigned reachable_from_other_partition : 1;
/* Set once the function is lowered (i.e. its CFG is built). */
unsigned lowered : 1;
/* Set once the function has been instantiated and its callee
lists created. */
unsigned analyzed : 1;
+ /* Set when function is available in the other LTRANS partition.
+ During WPA output it is used to mark nodes that are present in
+ multiple partitions. */
+ unsigned in_other_partition : 1;
/* Set when function is scheduled to be processed by local passes. */
unsigned process : 1;
/* Set for aliases once they got through assemble_alias. */
unsigned alias : 1;
- /* Set for nodes that was constructed and finalized by frontend. */
- unsigned finalized_by_frontend : 1;
+ /* Set for aliases created as C++ same body aliases. */
+ unsigned same_body_alias : 1;
+ /* How commonly executed the node is. Initialized during branch
+ probabilities pass. */
+ ENUM_BITFIELD (node_frequency) frequency : 2;
+ /* True when function can only be called at startup (from static ctor). */
+ unsigned only_called_at_startup : 1;
+ /* True when function can only be called at startup (from static dtor). */
+ unsigned only_called_at_exit : 1;
};
typedef struct cgraph_node *cgraph_node_ptr;
/* A cgraph node set is a collection of cgraph nodes. A cgraph node
can appear in multiple sets. */
-struct GTY(()) cgraph_node_set_def
+struct cgraph_node_set_def
{
- htab_t GTY((param_is (struct cgraph_node_set_element_def))) hashtab;
- VEC(cgraph_node_ptr, gc) *nodes;
- PTR GTY ((skip)) aux;
+ struct pointer_map_t *map;
+ VEC(cgraph_node_ptr, heap) *nodes;
+};
+
+typedef struct varpool_node *varpool_node_ptr;
+
+DEF_VEC_P(varpool_node_ptr);
+DEF_VEC_ALLOC_P(varpool_node_ptr,heap);
+DEF_VEC_ALLOC_P(varpool_node_ptr,gc);
+
+/* A varpool node set is a collection of varpool nodes. A varpool node
+ can appear in multiple sets. */
+struct varpool_node_set_def
+{
+ struct pointer_map_t * map;
+ VEC(varpool_node_ptr, heap) *nodes;
};
typedef struct cgraph_node_set_def *cgraph_node_set;
DEF_VEC_ALLOC_P(cgraph_node_set,gc);
DEF_VEC_ALLOC_P(cgraph_node_set,heap);
-/* A cgraph node set element contains an index in the vector of nodes in
- the set. */
-struct GTY(()) cgraph_node_set_element_def
-{
- struct cgraph_node *node;
- HOST_WIDE_INT index;
-};
+typedef struct varpool_node_set_def *varpool_node_set;
-typedef struct cgraph_node_set_element_def *cgraph_node_set_element;
-typedef const struct cgraph_node_set_element_def *const_cgraph_node_set_element;
+DEF_VEC_P(varpool_node_set);
+DEF_VEC_ALLOC_P(varpool_node_set,gc);
+DEF_VEC_ALLOC_P(varpool_node_set,heap);
/* Iterator structure for cgraph node sets. */
typedef struct
unsigned index;
} cgraph_node_set_iterator;
+/* Iterator structure for varpool node sets. */
+typedef struct
+{
+ varpool_node_set set;
+ unsigned index;
+} varpool_node_set_iterator;
+
#define DEFCIFCODE(code, string) CIF_ ## code,
/* Reasons for inlining failures. */
-typedef enum {
+typedef enum cgraph_inline_failed_enum {
#include "cif-code.def"
CIF_N_REASONS
} cgraph_inline_failed_t;
+/* Structure containing additional information about an indirect call. */
+
+struct GTY(()) cgraph_indirect_call_info
+{
+ /* Offset accumulated from ancestor jump functions of inlined call graph
+ edges. */
+ HOST_WIDE_INT anc_offset;
+ /* OBJ_TYPE_REF_TOKEN of a polymorphic call (if polymorphic is set). */
+ HOST_WIDE_INT otr_token;
+ /* Delta by which must be added to this parameter to compensate for a skipped
+ this adjusting thunk. */
+ HOST_WIDE_INT thunk_delta;
+ /* Type of the object from OBJ_TYPE_REF_OBJECT. */
+ tree otr_type;
+ /* Index of the parameter that is called. */
+ int param_index;
+ /* ECF flags determined from the caller. */
+ int ecf_flags;
+
+ /* Set when the call is a virtual call with the parameter being the
+ associated object pointer rather than a simple direct call. */
+ unsigned polymorphic : 1;
+};
+
struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
+ /* Expected number of executions: calculated in profile.c. */
+ gcov_type count;
struct cgraph_node *caller;
struct cgraph_node *callee;
struct cgraph_edge *prev_caller;
struct cgraph_edge *prev_callee;
struct cgraph_edge *next_callee;
gimple call_stmt;
+ /* Additional information about an indirect call. Not cleared when an edge
+ becomes direct. */
+ struct cgraph_indirect_call_info *indirect_info;
PTR GTY ((skip (""))) aux;
/* When equal to CIF_OK, inline this call. Otherwise, points to the
explanation why function was not inlined. */
cgraph_inline_failed_t inline_failed;
- /* Expected number of executions: calculated in profile.c. */
- gcov_type count;
- /* Expected frequency of executions within the function.
+ /* 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;
- /* Depth of loop nest, 1 means no loop nest. */
- unsigned int loop_nest : 30;
- /* Whether this edge describes a call that was originally indirect. */
- unsigned int indirect_call : 1;
- /* Can this call throw externally? */
- unsigned int can_throw_external : 1;
/* 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
+ callee. */
+ unsigned int indirect_unknown_callee : 1;
+ /* Whether this edge is still a dangling */
+ /* True if the corresponding CALL stmt cannot be inlined. */
+ unsigned int call_stmt_cannot_inline_p : 1;
+ /* Can this call throw externally? */
+ unsigned int can_throw_external : 1;
};
#define CGRAPH_FREQ_BASE 1000
/* The varpool data structure.
Each static variable decl has assigned varpool_node. */
-struct GTY((chain_next ("%h.next"))) varpool_node {
+struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
tree decl;
+ /* For aliases points to declaration DECL is alias of. */
+ tree alias_of;
/* Pointer to the next function in varpool_nodes. */
- struct varpool_node *next;
+ struct varpool_node *next, *prev;
/* Pointer to the next function in varpool_nodes_queue. */
- struct varpool_node *next_needed;
+ struct varpool_node *next_needed, *prev_needed;
+ /* Circular list of nodes in the same comdat group if non-NULL. */
+ struct varpool_node *same_comdat_group;
+ struct ipa_ref_list ref_list;
+ /* File stream where this node is being written to. */
+ struct lto_file_decl_data * lto_file_data;
+ PTR GTY ((skip)) aux;
/* Ordering of all cgraph nodes. */
int order;
+ enum ld_plugin_symbol_resolution resolution;
/* Set when function must be output - it is externally visible
or its address is taken. */
unsigned output : 1;
/* Set when function is visible by other units. */
unsigned externally_visible : 1;
- /* Set for aliases once they got through assemble_alias. */
+ /* Set for aliases once they got through assemble_alias. Also set for
+ extra name aliases in varpool_extra_name_alias. */
unsigned alias : 1;
+ unsigned extra_name_alias : 1;
+ /* Set when variable is used from other LTRANS partition. */
+ unsigned used_from_other_partition : 1;
+ /* Set when variable is available in the other LTRANS partition.
+ During WPA output it is used to mark nodes that are present in
+ multiple partitions. */
+ unsigned in_other_partition : 1;
};
/* Every top level asm statement is put into a cgraph_asm_node. */
extern GTY(()) int cgraph_n_nodes;
extern GTY(()) int cgraph_max_uid;
extern GTY(()) int cgraph_edge_max_uid;
-extern GTY(()) int cgraph_max_pid;
extern bool cgraph_global_info_ready;
enum cgraph_state
{
extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
extern GTY(()) int cgraph_order;
+extern bool same_body_aliases_done;
/* In cgraph.c */
void dump_cgraph (FILE *);
void cgraph_insert_node_to_hashtable (struct cgraph_node *node);
void cgraph_remove_edge (struct cgraph_edge *);
void cgraph_remove_node (struct cgraph_node *);
+void cgraph_add_to_same_comdat_group (struct cgraph_node *, struct cgraph_node *);
void cgraph_remove_node_and_inline_clones (struct cgraph_node *);
void cgraph_release_function_body (struct cgraph_node *);
void cgraph_node_remove_callees (struct cgraph_node *node);
struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
struct cgraph_node *,
- gimple, gcov_type, int, int);
-struct cgraph_node *cgraph_node (tree);
-struct cgraph_node *cgraph_node_for_asm (tree asmname);
+ gimple, gcov_type, int);
+struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple,
+ int, gcov_type, int);
+struct cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void);
+struct cgraph_node * cgraph_get_node (const_tree);
+struct cgraph_node * cgraph_create_node (tree);
+struct cgraph_node * cgraph_get_create_node (tree);
+struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree);
+struct cgraph_node * cgraph_add_thunk (struct cgraph_node *, tree, tree, bool, HOST_WIDE_INT,
+ HOST_WIDE_INT, tree, tree);
+struct cgraph_node *cgraph_node_for_asm (tree);
struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
void cgraph_set_call_stmt (struct cgraph_edge *, gimple);
void cgraph_set_call_stmt_including_clones (struct cgraph_node *, gimple, gimple);
void cgraph_create_edge_including_clones (struct cgraph_node *,
struct cgraph_node *,
- gimple, gcov_type, int, int,
+ gimple, gimple, gcov_type, int,
cgraph_inline_failed_t);
void cgraph_update_edges_for_call_stmt (gimple, tree, gimple);
struct cgraph_local_info *cgraph_local_info (tree);
struct cgraph_rtl_info *cgraph_rtl_info (tree);
const char * cgraph_node_name (struct cgraph_node *);
struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *,
- struct cgraph_node *,
- gimple, gcov_type, int, int, bool);
-struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int,
- int, bool);
+ struct cgraph_node *, gimple,
+ unsigned, gcov_type, int, bool);
+struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
+ int, bool, VEC(cgraph_edge_p,heap) *,
+ bool);
+struct cgraph_node *cgraph_create_function_alias (tree, tree);
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
+void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
+ HOST_WIDE_INT);
+bool cgraph_only_called_directly_p (struct cgraph_node *);
struct cgraph_asm_node *cgraph_add_asm_node (tree);
struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node,
VEC(cgraph_edge_p,heap)*,
VEC(ipa_replace_map_p,gc)* tree_map,
- bitmap args_to_skip);
+ bitmap args_to_skip,
+ const char *clone_name);
+
+void cgraph_set_nothrow_flag (struct cgraph_node *, bool);
+void cgraph_set_const_flag (struct cgraph_node *, bool, bool);
+void cgraph_set_pure_flag (struct cgraph_node *, bool, bool);
+tree clone_function_name (tree decl, const char *);
+bool cgraph_node_cannot_return (struct cgraph_node *);
+bool cgraph_edge_cannot_lead_to_return (struct cgraph_edge *);
+bool cgraph_will_be_removed_from_program_if_no_direct_calls
+ (struct cgraph_node *node);
+bool cgraph_can_remove_if_no_direct_calls_and_refs_p
+ (struct cgraph_node *node);
+bool cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node);
+bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution);
+bool cgraph_used_from_object_file_p (struct cgraph_node *);
+bool varpool_used_from_object_file_p (struct varpool_node *);
+bool cgraph_for_node_thunks_and_aliases (struct cgraph_node *,
+ bool (*) (struct cgraph_node *, void *),
+ void *,
+ bool);
+bool cgraph_for_node_and_aliases (struct cgraph_node *,
+ bool (*) (struct cgraph_node *, void *),
+ void *, bool);
+VEC (cgraph_edge_p, heap) * collect_callers_of_node (struct cgraph_node *node);
+
/* In cgraphunit.c */
+extern FILE *cgraph_dump_file;
void cgraph_finalize_function (tree, bool);
void cgraph_mark_if_needed (tree);
+void cgraph_analyze_function (struct cgraph_node *);
void cgraph_finalize_compilation_unit (void);
+void cgraph_optimize (void);
void cgraph_mark_needed_node (struct cgraph_node *);
void cgraph_mark_address_taken_node (struct cgraph_node *);
void cgraph_mark_reachable_node (struct cgraph_node *);
bool cgraph_inline_p (struct cgraph_edge *, cgraph_inline_failed_t *reason);
-bool cgraph_preserve_function_body_p (tree);
+bool cgraph_preserve_function_body_p (struct cgraph_node *);
void verify_cgraph (void);
void verify_cgraph_node (struct cgraph_node *);
void cgraph_build_static_cdtor (char which, tree body, int priority);
struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
VEC(cgraph_edge_p,heap)*,
VEC(ipa_replace_map_p,gc)*,
- bitmap);
-void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bitmap);
-struct cgraph_node *save_inline_function_body (struct cgraph_node *);
-void record_references_in_initializer (tree);
+ bitmap, bitmap, basic_block,
+ const char *);
+void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bitmap,
+ bitmap, basic_block);
+void record_references_in_initializer (tree, bool);
bool cgraph_process_new_functions (void);
+void cgraph_process_same_body_aliases (void);
+
+bool cgraph_decide_is_function_needed (struct cgraph_node *, tree);
typedef void (*cgraph_edge_hook)(struct cgraph_edge *, void *);
typedef void (*cgraph_node_hook)(struct cgraph_node *, void *);
struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook (cgraph_2node_hook, void *);
void cgraph_remove_node_duplication_hook (struct cgraph_2node_hook_list *);
void cgraph_materialize_all_clones (void);
-
+gimple cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *);
+bool cgraph_propagate_frequency (struct cgraph_node *node);
/* In cgraphbuild.c */
unsigned int rebuild_cgraph_edges (void);
+void cgraph_rebuild_references (void);
+void reset_inline_failed (struct cgraph_node *);
int compute_call_stmt_bb_frequency (tree, basic_block bb);
/* In ipa.c */
bool cgraph_remove_unreachable_nodes (bool, FILE *);
-int cgraph_postorder (struct cgraph_node **);
cgraph_node_set cgraph_node_set_new (void);
cgraph_node_set_iterator cgraph_node_set_find (cgraph_node_set,
struct cgraph_node *);
void cgraph_node_set_remove (cgraph_node_set, struct cgraph_node *);
void dump_cgraph_node_set (FILE *, cgraph_node_set);
void debug_cgraph_node_set (cgraph_node_set);
-
+void free_cgraph_node_set (cgraph_node_set);
+
+varpool_node_set varpool_node_set_new (void);
+varpool_node_set_iterator varpool_node_set_find (varpool_node_set,
+ struct varpool_node *);
+void varpool_node_set_add (varpool_node_set, struct varpool_node *);
+void varpool_node_set_remove (varpool_node_set, struct varpool_node *);
+void dump_varpool_node_set (FILE *, varpool_node_set);
+void debug_varpool_node_set (varpool_node_set);
+void free_varpool_node_set (varpool_node_set);
+void ipa_discover_readonly_nonaddressable_vars (void);
+bool cgraph_comdat_can_be_unshared_p (struct cgraph_node *);
/* In predict.c */
bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
+bool cgraph_optimize_for_size_p (struct cgraph_node *);
/* In varpool.c */
extern GTY(()) struct varpool_node *varpool_nodes_queue;
void varpool_finalize_decl (tree);
bool decide_is_variable_needed (struct varpool_node *, tree);
enum availability cgraph_variable_initializer_availability (struct varpool_node *);
+void cgraph_make_decl_local (tree);
void cgraph_make_node_local (struct cgraph_node *);
bool cgraph_node_can_be_local_p (struct cgraph_node *);
+
+struct varpool_node * varpool_get_node (const_tree decl);
+void varpool_remove_node (struct varpool_node *node);
+void varpool_finalize_named_section_flags (struct varpool_node *node);
bool varpool_assemble_pending_decls (void);
bool varpool_assemble_decl (struct varpool_node *node);
bool varpool_analyze_pending_decls (void);
void varpool_remove_unreferenced_decls (void);
void varpool_empty_needed_queue (void);
+struct varpool_node * varpool_extra_name_alias (tree, tree);
+struct varpool_node * varpool_create_variable_alias (tree, tree);
+const char * varpool_node_name (struct varpool_node *node);
+void varpool_reset_queue (void);
+bool const_value_known_p (tree);
+bool varpool_for_node_and_aliases (struct varpool_node *,
+ bool (*) (struct varpool_node *, void *),
+ void *, bool);
/* Walk all reachable static variables. */
#define FOR_EACH_STATIC_VARIABLE(node) \
struct varpool_node *node;
for (node = varpool_nodes_queue; node; node = node->next_needed)
{
- gcc_assert (TREE_CODE (node->decl) == VAR_DECL);
+ gcc_checking_assert (TREE_CODE (node->decl) == VAR_DECL);
if (DECL_INITIAL (node->decl))
return node;
}
{
for (node = node->next_needed; node; node = node->next_needed)
{
- gcc_assert (TREE_CODE (node->decl) == VAR_DECL);
+ gcc_checking_assert (TREE_CODE (node->decl) == VAR_DECL);
if (DECL_INITIAL (node->decl))
return node;
}
for ((node) = varpool_first_static_initializer (); (node); \
(node) = varpool_next_static_initializer (node))
-/* In ipa-inline.c */
-void cgraph_clone_inlined_nodes (struct cgraph_edge *, bool, bool);
-unsigned int compute_inline_parameters (struct cgraph_node *);
+/* Return first function with body defined. */
+static inline struct cgraph_node *
+cgraph_first_defined_function (void)
+{
+ struct cgraph_node *node;
+ for (node = cgraph_nodes; node; node = node->next)
+ {
+ if (node->analyzed)
+ return node;
+ }
+ return NULL;
+}
+
+/* Return next reachable static variable with initializer after NODE. */
+static inline struct cgraph_node *
+cgraph_next_defined_function (struct cgraph_node *node)
+{
+ for (node = node->next; node; node = node->next)
+ {
+ if (node->analyzed)
+ return node;
+ }
+ return NULL;
+}
+
+/* Walk all functions with body defined. */
+#define FOR_EACH_DEFINED_FUNCTION(node) \
+ for ((node) = cgraph_first_defined_function (); (node); \
+ (node) = cgraph_next_defined_function (node))
+
+
+/* Return true when NODE is a function with Gimple body defined
+ in current unit. Functions can also be define externally or they
+ can be thunks with no Gimple representation.
+ Note that at WPA stage, the function body may not be present in memory. */
+
+static inline bool
+cgraph_function_with_gimple_body_p (struct cgraph_node *node)
+{
+ return node->analyzed && !node->thunk.thunk_p && !node->alias;
+}
+
+/* Return first function with body defined. */
+static inline struct cgraph_node *
+cgraph_first_function_with_gimple_body (void)
+{
+ struct cgraph_node *node;
+ for (node = cgraph_nodes; node; node = node->next)
+ {
+ if (cgraph_function_with_gimple_body_p (node))
+ return node;
+ }
+ return NULL;
+}
+
+/* Return next reachable static variable with initializer after NODE. */
+static inline struct cgraph_node *
+cgraph_next_function_with_gimple_body (struct cgraph_node *node)
+{
+ for (node = node->next; node; node = node->next)
+ {
+ if (cgraph_function_with_gimple_body_p (node))
+ return node;
+ }
+ return NULL;
+}
+
+/* Walk all functions with body defined. */
+#define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \
+ for ((node) = cgraph_first_function_with_gimple_body (); (node); \
+ (node) = cgraph_next_function_with_gimple_body (node))
/* Create a new static variable of type TYPE. */
tree add_new_static_var (tree type);
-
/* Return true if iterator CSI points to nothing. */
static inline bool
csi_end_p (cgraph_node_set_iterator csi)
static inline size_t
cgraph_node_set_size (cgraph_node_set set)
{
- return htab_elements (set->hashtab);
+ return VEC_length (cgraph_node_ptr, set->nodes);
+}
+
+/* Return true if iterator VSI points to nothing. */
+static inline bool
+vsi_end_p (varpool_node_set_iterator vsi)
+{
+ return vsi.index >= VEC_length (varpool_node_ptr, vsi.set->nodes);
+}
+
+/* Advance iterator VSI. */
+static inline void
+vsi_next (varpool_node_set_iterator *vsi)
+{
+ vsi->index++;
+}
+
+/* Return the node pointed to by VSI. */
+static inline struct varpool_node *
+vsi_node (varpool_node_set_iterator vsi)
+{
+ return VEC_index (varpool_node_ptr, vsi.set->nodes, vsi.index);
+}
+
+/* Return an iterator to the first node in SET. */
+static inline varpool_node_set_iterator
+vsi_start (varpool_node_set set)
+{
+ varpool_node_set_iterator vsi;
+
+ vsi.set = set;
+ vsi.index = 0;
+ return vsi;
+}
+
+/* Return true if SET contains NODE. */
+static inline bool
+varpool_node_in_set_p (struct varpool_node *node, varpool_node_set set)
+{
+ varpool_node_set_iterator vsi;
+ vsi = varpool_node_set_find (set, node);
+ return !vsi_end_p (vsi);
+}
+
+/* Return number of nodes in SET. */
+static inline size_t
+varpool_node_set_size (varpool_node_set set)
+{
+ return VEC_length (varpool_node_ptr, set->nodes);
}
/* Uniquize all constants that appear in memory.
struct GTY(()) constant_descriptor_tree {
/* A MEM for the constant. */
rtx rtl;
-
+
/* The value of the constant. */
tree value;
hashval_t hash;
};
+/* Return true if set is nonempty. */
+static inline bool
+cgraph_node_set_nonempty_p (cgraph_node_set set)
+{
+ return !VEC_empty (cgraph_node_ptr, set->nodes);
+}
+
+/* Return true if set is nonempty. */
+static inline bool
+varpool_node_set_nonempty_p (varpool_node_set set)
+{
+ return !VEC_empty (varpool_node_ptr, set->nodes);
+}
+
+/* Return true when function NODE is only called directly or it has alias.
+ i.e. it is not externally visible, address was not taken and
+ it is not used in any other non-standard way. */
+
+static inline bool
+cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node)
+{
+ gcc_assert (!node->global.inlined_to);
+ return (!node->needed && !node->address_taken
+ && !node->reachable_from_other_partition
+ && !DECL_STATIC_CONSTRUCTOR (node->decl)
+ && !DECL_STATIC_DESTRUCTOR (node->decl)
+ && !node->local.externally_visible);
+}
+
+/* Return true when function NODE can be removed from callgraph
+ if all direct calls are eliminated. */
+
+static inline bool
+varpool_can_remove_if_no_refs (struct varpool_node *node)
+{
+ return (!node->force_output && !node->used_from_other_partition
+ && (flag_toplevel_reorder || DECL_COMDAT (node->decl)
+ || DECL_ARTIFICIAL (node->decl))
+ && (DECL_COMDAT (node->decl) || !node->externally_visible));
+}
+
+/* Return true when all references to VNODE must be visible in ipa_ref_list.
+ i.e. if the variable is not externally visible or not used in some magic
+ way (asm statement or such).
+ The magic uses are all summarized in force_output flag. */
+
+static inline bool
+varpool_all_refs_explicit_p (struct varpool_node *vnode)
+{
+ return (vnode->analyzed
+ && !vnode->externally_visible
+ && !vnode->used_from_other_partition
+ && !vnode->force_output);
+}
+
/* Constant pool accessor function. */
htab_t constant_pool_htab (void);
+/* FIXME: inappropriate dependency of cgraph on IPA. */
+#include "ipa-ref-inline.h"
+
+/* Return node that alias N is aliasing. */
+
+static inline struct cgraph_node *
+cgraph_alias_aliased_node (struct cgraph_node *n)
+{
+ struct ipa_ref *ref;
+
+ ipa_ref_list_reference_iterate (&n->ref_list, 0, ref);
+ gcc_checking_assert (ref->use == IPA_REF_ALIAS);
+ if (ref->refered_type == IPA_REF_CGRAPH)
+ return ipa_ref_node (ref);
+ return NULL;
+}
+
+/* Return node that alias N is aliasing. */
+
+static inline struct varpool_node *
+varpool_alias_aliased_node (struct varpool_node *n)
+{
+ struct ipa_ref *ref;
+
+ ipa_ref_list_reference_iterate (&n->ref_list, 0, ref);
+ gcc_checking_assert (ref->use == IPA_REF_ALIAS);
+ if (ref->refered_type == IPA_REF_VARPOOL)
+ return ipa_ref_varpool_node (ref);
+ return NULL;
+}
+
+/* Given NODE, walk the alias chain to return the function NODE is alias of.
+ Walk through thunk, too.
+ When AVAILABILITY is non-NULL, get minimal availablity in the chain. */
+
+static inline struct cgraph_node *
+cgraph_function_node (struct cgraph_node *node, enum availability *availability)
+{
+ if (availability)
+ *availability = cgraph_function_body_availability (node);
+ while (node)
+ {
+ if (node->alias && node->analyzed)
+ node = cgraph_alias_aliased_node (node);
+ else if (node->thunk.thunk_p)
+ node = node->callees->callee;
+ else
+ return node;
+ if (node && availability)
+ {
+ enum availability a;
+ a = cgraph_function_body_availability (node);
+ if (a < *availability)
+ *availability = a;
+ }
+ }
+ if (availability)
+ *availability = AVAIL_NOT_AVAILABLE;
+ return NULL;
+}
+
+/* Given NODE, walk the alias chain to return the function NODE is alias of.
+ Do not walk through thunks.
+ When AVAILABILITY is non-NULL, get minimal availablity in the chain. */
+
+static inline struct cgraph_node *
+cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *availability)
+{
+ if (availability)
+ *availability = cgraph_function_body_availability (node);
+ while (node)
+ {
+ if (node->alias && node->analyzed)
+ node = cgraph_alias_aliased_node (node);
+ else
+ return node;
+ if (node && availability)
+ {
+ enum availability a;
+ a = cgraph_function_body_availability (node);
+ if (a < *availability)
+ *availability = a;
+ }
+ }
+ if (availability)
+ *availability = AVAIL_NOT_AVAILABLE;
+ return NULL;
+}
+
+/* Given NODE, walk the alias chain to return the function NODE is alias of.
+ Do not walk through thunks.
+ When AVAILABILITY is non-NULL, get minimal availablity in the chain. */
+
+static inline struct varpool_node *
+varpool_variable_node (struct varpool_node *node, enum availability *availability)
+{
+ if (availability)
+ *availability = cgraph_variable_initializer_availability (node);
+ while (node)
+ {
+ if (node->alias && node->analyzed)
+ node = varpool_alias_aliased_node (node);
+ else
+ return node;
+ if (node && availability)
+ {
+ enum availability a;
+ a = cgraph_variable_initializer_availability (node);
+ if (a < *availability)
+ *availability = a;
+ }
+ }
+ if (availability)
+ *availability = AVAIL_NOT_AVAILABLE;
+ return NULL;
+}
+
+/* Return true when the edge E represents a direct recursion. */
+static inline bool
+cgraph_edge_recursive_p (struct cgraph_edge *e)
+{
+ struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL);
+ if (e->caller->global.inlined_to)
+ return e->caller->global.inlined_to->decl == callee->decl;
+ else
+ return e->caller->decl == callee->decl;
+}
#endif /* GCC_CGRAPH_H */