+2010-03-18 Martin Jambor <mjambor@suse.cz>
+
+ PR middle-end/42450
+ * cgraph.h (cgraph_redirect_edge_call_stmt_to_callee): Declare.
+ * cgraphunit.c (cgraph_materialize_all_clones): Update calls in
+ all non-clones. Moved call redirection...
+ (cgraph_redirect_edge_call_stmt_to_callee): ...to this new
+ function.
+ (cgraph_materialize_all_clones): Dispose of all
+ combined_args_to_skip bitmaps.
+ (verify_cgraph_node): Do not check for edges pointing to wrong
+ nodes in inline clones.
+ * tree-inline.c (copy_bb): Call
+ cgraph_redirect_edge_call_stmt_to_callee.
+ * ipa.c (cgraph_remove_unreachable_nodes): Call
+ cgraph_node_remove_callees even when there are used clones.
+
2010-03-18 H.J. Lu <hongjiu.lu@intel.com>
* config/i386/libgcc-glibc.ver: Make GCC_4.5.0 inherit GCC_4.4.0.
/* Callgraph handling code.
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Jan Hubicka
#ifndef GCC_CGRAPH_H
#define GCC_CGRAPH_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
{
struct GTY(()) cgraph_local_info {
/* File stream where this node is being written to. */
- struct lto_file_decl_data * lto_file_data;
+ struct lto_file_decl_data * GTY ((skip)) lto_file_data;
struct inline_summary inline_summary;
/* False when there something makes inlining impossible (such as va_arg). */
unsigned inlinable : 1;
- /* False when there something makes versioning impossible.
- Currently computed and used only by ipa-cp. */
- unsigned versionable : 1;
-
/* True when function should be inlined independently on its size. */
unsigned disregard_inline_limits : 1;
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;
/* 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;
};
-enum node_frequency {
- /* This function most likely won't be executed at all.
- (set only when profile feedback is available or via function attribute). */
- NODE_FREQUENCY_UNLIKELY_EXECUTED,
- /* For functions that are known to be executed once (i.e. constructors, destructors
- and main function. */
- NODE_FREQUENCY_EXECUTED_ONCE,
- /* The default value. */
- NODE_FREQUENCY_NORMAL,
- /* Optimize this function hard
- (set only when profile feedback is available or via function attribute). */
- NODE_FREQUENCY_HOT
-};
-
-
/* 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. */
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;
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. */
- 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. */
/* Set for alias and thunk nodes, same_body points to the node they are alias
of and they are linked through the next/previous pointers. */
unsigned same_body_alias : 1;
- /* How commonly executed the node is. Initialized during branch
- probabilities pass. */
- ENUM_BITFIELD (node_frequency) frequency : 2;
};
typedef struct cgraph_node *cgraph_node_ptr;
PTR GTY ((skip)) aux;
};
-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 GTY(()) varpool_node_set_def
-{
- htab_t GTY((param_is (struct varpool_node_set_element_def))) hashtab;
- VEC(varpool_node_ptr, gc) *nodes;
- PTR GTY ((skip)) aux;
-};
-
typedef struct cgraph_node_set_def *cgraph_node_set;
DEF_VEC_P(cgraph_node_set);
DEF_VEC_ALLOC_P(cgraph_node_set,gc);
DEF_VEC_ALLOC_P(cgraph_node_set,heap);
-typedef struct varpool_node_set_def *varpool_node_set;
-
-DEF_VEC_P(varpool_node_set);
-DEF_VEC_ALLOC_P(varpool_node_set,gc);
-DEF_VEC_ALLOC_P(varpool_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
unsigned index;
} cgraph_node_set_iterator;
-/* A varpool node set element contains an index in the vector of nodes in
- the set. */
-struct GTY(()) varpool_node_set_element_def
-{
- struct varpool_node *node;
- HOST_WIDE_INT index;
-};
-
-typedef struct varpool_node_set_element_def *varpool_node_set_element;
-typedef const struct varpool_node_set_element_def *const_varpool_node_set_element;
-
-/* 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 {
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;
- /* 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_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. */
int uid;
/* Depth of loop nest, 1 means no loop nest. */
unsigned short int loop_nest;
- /* 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 */
+ /* Whether this edge describes a call that was originally indirect. */
+ unsigned int indirect_call : 1;
/* True if the corresponding CALL stmt cannot be inlined. */
unsigned int call_stmt_cannot_inline_p : 1;
/* Can this call throw externally? */
/* The varpool data structure.
Each static variable decl has assigned varpool_node. */
-struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
+struct GTY((chain_next ("%h.next"))) varpool_node {
tree decl;
/* Pointer to the next function in varpool_nodes. */
- struct varpool_node *next, *prev;
+ struct varpool_node *next;
/* Pointer to the next function in varpool_nodes_queue. */
- struct varpool_node *next_needed, *prev_needed;
+ struct varpool_node *next_needed;
/* For normal nodes a pointer to the first extra name alias. For alias
nodes a pointer to the normal node. */
struct varpool_node *extra_name;
- /* Circular list of nodes in the same comdat group if non-NULL. */
- struct varpool_node *same_comdat_group;
- struct ipa_ref_list ref_list;
- PTR GTY ((skip)) aux;
/* Ordering of all cgraph nodes. */
int order;
/* Set for aliases once they got through assemble_alias. Also set for
extra name aliases in varpool_extra_name_alias. */
unsigned 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. */
- unsigned in_other_partition : 1;
};
/* Every top level asm statement is put into a cgraph_asm_node. */
struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
struct cgraph_node *,
gimple, gcov_type, int, int);
-struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int,
- gcov_type, int, int);
+
struct cgraph_node * cgraph_get_node (tree);
struct cgraph_node *cgraph_node (tree);
bool cgraph_same_body_alias (tree, tree);
struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *,
struct cgraph_node *, gimple,
unsigned, gcov_type, int, int, bool);
-struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type, int,
+struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int,
int, bool, VEC(cgraph_edge_p,heap) *);
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
-void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *);
struct cgraph_asm_node *cgraph_add_asm_node (tree);
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);
void dump_cgraph_node_set (FILE *, cgraph_node_set);
void debug_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 ipa_discover_readonly_nonaddressable_vars (void);
/* In predict.c */
bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
void cgraph_make_node_local (struct cgraph_node *);
bool cgraph_node_can_be_local_p (struct cgraph_node *);
-
-struct varpool_node * varpool_get_node (tree decl);
-void varpool_remove_node (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_empty_needed_queue (void);
bool varpool_extra_name_alias (tree, tree);
const char * varpool_node_name (struct varpool_node *node);
-void varpool_reset_queue (void);
/* Walk all reachable static variables. */
#define FOR_EACH_STATIC_VARIABLE(node) \
/* Create a new static variable of type TYPE. */
tree add_new_static_var (tree type);
+/* lto-cgraph.c */
+
+enum LTO_cgraph_tags
+{
+ /* Must leave 0 for the stopper. */
+ LTO_cgraph_avail_node = 1,
+ LTO_cgraph_overwritable_node,
+ LTO_cgraph_unavail_node,
+ LTO_cgraph_edge,
+ LTO_cgraph_last_tag
+};
+
+extern const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag];
+
+#define LCC_NOT_FOUND (-1)
+
+
/* Return true if iterator CSI points to nothing. */
static inline bool
csi_end_p (cgraph_node_set_iterator csi)
return htab_elements (set->hashtab);
}
-/* 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 htab_elements (set->hashtab);
-}
-
/* Uniquize all constants that appear in memory.
Each constant in memory thus far output is recorded
in `const_desc_table'. */
hashval_t hash;
};
-/* Return true if set is nonempty. */
-static inline bool
-cgraph_node_set_nonempty_p (cgraph_node_set set)
-{
- return VEC_length (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_length (varpool_node_ptr, set->nodes);
-}
-
/* Return true when function NODE is only called directly.
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_p (struct cgraph_node *node)
{
- return !node->needed && !node->address_taken && !node->local.externally_visible;
-}
-
-/* Return true when function NODE can be removed from callgraph
- if all direct calls are eliminated. */
-
-static inline bool
-cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
-{
- return (!node->needed && !node->reachable_from_other_partition
- && (DECL_COMDAT (node->decl) || !node->local.externally_visible));
+ return !node->needed && !node->local.externally_visible;
}
/* Return true when function NODE can be removed from callgraph
static inline bool
cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
{
- return !node->address_taken && cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
-}
-
-/* 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 sumarized in force_output flag. */
-
-static inline bool
-varpool_all_refs_explicit_p (struct varpool_node *vnode)
-{
- return (!vnode->externally_visible
- && !vnode->used_from_other_partition
- && !vnode->force_output);
+ return (!node->needed
+ && (DECL_COMDAT (node->decl) || !node->local.externally_visible));
}
/* Constant pool accessor function. */
htab_t constant_pool_htab (void);
-/* FIXME: inappropriate dependency of cgraph on IPA. */
-#include "ipa-ref-inline.h"
-
#endif /* GCC_CGRAPH_H */
#include "target.h"
#include "cgraph.h"
#include "diagnostic.h"
-#include "tree-pretty-print.h"
-#include "gimple-pretty-print.h"
#include "timevar.h"
#include "params.h"
#include "fibheap.h"
tree fndecl;
struct cgraph_node *node;
- varpool_analyze_pending_decls ();
/* Note that this queue may grow as its being processed, as the new
functions may generate new ones. */
while (cgraph_new_nodes)
break;
}
cgraph_call_function_insertion_hooks (node);
- varpool_analyze_pending_decls ();
}
return output;
}
error ("Inline clone is needed");
error_found = true;
}
- for (e = node->indirect_calls; e; e = e->next_callee)
- {
- if (e->aux)
- {
- error ("aux field set for indirect edge from %s",
- identifier_to_locale (cgraph_node_name (e->caller)));
- error_found = true;
- }
- if (!e->indirect_unknown_callee
- || !e->indirect_info)
- {
- error ("An indirect edge from %s is not marked as indirect or has "
- "associated indirect_info, the corresponding statement is: ",
- identifier_to_locale (cgraph_node_name (e->caller)));
- debug_gimple_stmt (e->call_stmt);
- error_found = true;
- }
- }
for (e = node->callers; e; e = e->next_caller)
{
if (e->count < 0)
error ("double linked list of clones corrupted");
error_found = true;
}
- if (node->same_comdat_group)
- {
- struct cgraph_node *n = node->same_comdat_group;
-
- if (!DECL_ONE_ONLY (node->decl))
- {
- error ("non-DECL_ONE_ONLY node in a same_comdat_group list");
- error_found = true;
- }
- if (n == node)
- {
- error ("node is alone in a comdat group");
- error_found = true;
- }
- do
- {
- if (!n->same_comdat_group)
- {
- error ("same_comdat_group is not a circular list");
- error_found = true;
- break;
- }
- n = n->same_comdat_group;
- }
- while (n != node);
- }
if (node->analyzed && gimple_has_body_p (node->decl)
&& !TREE_ASM_WRITTEN (node->decl)
gsi_next (&gsi))
{
gimple stmt = gsi_stmt (gsi);
- if (is_gimple_call (stmt))
+ tree decl;
+ if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
{
struct cgraph_edge *e = cgraph_edge (node, stmt);
- tree decl = gimple_call_fndecl (stmt);
if (e)
{
if (e->aux)
debug_gimple_stmt (stmt);
error_found = true;
}
- if (!e->indirect_unknown_callee)
+ if (e->callee->same_body_alias)
{
- if (e->callee->same_body_alias)
- {
- error ("edge points to same body alias:");
- debug_tree (e->callee->decl);
- error_found = true;
- }
- else if (!node->global.inlined_to
- && !e->callee->global.inlined_to
- && decl
- && !clone_of_p (cgraph_node (decl),
- e->callee))
- {
- error ("edge points to wrong declaration:");
- debug_tree (e->callee->decl);
- fprintf (stderr," Instead of:");
- debug_tree (decl);
- error_found = true;
- }
+ error ("edge points to same body alias:");
+ debug_tree (e->callee->decl);
+ error_found = true;
}
- else if (decl)
+ else if (!node->global.inlined_to
+ && !e->callee->global.inlined_to
+ && !clone_of_p (cgraph_node (decl), e->callee))
{
- error ("an indirect edge with unknown callee "
- "corresponding to a call_stmt with "
- "a known declaration:");
+ error ("edge points to wrong declaration:");
+ debug_tree (e->callee->decl);
+ fprintf (stderr," Instead of:");
+ debug_tree (decl);
error_found = true;
- debug_gimple_stmt (e->call_stmt);
}
e->aux = (void *)1;
}
- else if (decl)
+ else
{
error ("missing callgraph edge for call stmt:");
debug_gimple_stmt (stmt);
for (e = node->callees; e; e = e->next_callee)
{
- if (!e->aux)
+ if (!e->aux && !e->indirect_call)
{
error ("edge %s->%s has no corresponding call_stmt",
identifier_to_locale (cgraph_node_name (e->caller)),
}
e->aux = 0;
}
- for (e = node->indirect_calls; e; e = e->next_callee)
- {
- if (!e->aux)
- {
- error ("an indirect edge from %s has no corresponding call_stmt",
- identifier_to_locale (cgraph_node_name (e->caller)));
- debug_gimple_stmt (e->call_stmt);
- error_found = true;
- }
- e->aux = 0;
- }
}
if (error_found)
{
{
tree decl = node->decl;
if (DECL_PRESERVE_P (decl))
- cgraph_mark_needed_node (node);
+ {
+ mark_decl_referenced (decl);
+ if (node->local.finalized)
+ cgraph_mark_needed_node (node);
+ }
if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
{
if (! TREE_PUBLIC (node->decl))
tree decl = vnode->decl;
if (DECL_PRESERVE_P (decl))
{
+ mark_decl_referenced (decl);
vnode->force_output = true;
if (vnode->finalized)
varpool_mark_needed_node (vnode);
outside the current compilation unit. */
if (node->analyzed
&& !node->global.inlined_to
- && (node->needed || node->reachable_from_other_partition
- || node->address_taken
+ && (node->needed
|| (e && node->reachable))
&& !TREE_ASM_WRITTEN (decl)
&& !DECL_EXTERNAL (decl))
#ifdef ENABLE_CHECKING
if (!node->global.inlined_to
&& gimple_has_body_p (decl)
- /* FIXME: in ltrans unit when offline copy is outside partition but inline copies
- are inside partition, we can end up not removing the body since we no longer
- have analyzed node pointing to it. */
- && !node->in_other_partition
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
#endif
gcc_assert (node->global.inlined_to
|| !gimple_has_body_p (decl)
- || node->in_other_partition
|| DECL_EXTERNAL (decl));
}
tree decl = node->decl;
if (!node->global.inlined_to
&& gimple_has_body_p (decl)
- /* FIXME: in ltrans unit when offline copy is outside partition but inline copies
- are inside partition, we can end up not removing the body since we no longer
- have analyzed node pointing to it. */
- && !node->in_other_partition
&& !DECL_EXTERNAL (decl))
{
dump_cgraph_node (stderr, node);
cgraph_remove_same_body_alias (node);
/* Since we want to emit the thunk, we explicitly mark its name as
referenced. */
+ mark_decl_referenced (thunk_fndecl);
cgraph_add_new_function (thunk_fndecl, true);
bitmap_obstack_release (NULL);
}
cgraph_output_in_order (void)
{
int max;
+ size_t size;
struct cgraph_order_sort *nodes;
int i;
struct cgraph_node *pf;
struct cgraph_asm_node *pa;
max = cgraph_order;
- nodes = XCNEWVEC (struct cgraph_order_sort, max);
+ size = max * sizeof (struct cgraph_order_sort);
+ nodes = (struct cgraph_order_sort *) alloca (size);
+ memset (nodes, 0, size);
varpool_analyze_pending_decls ();
}
cgraph_asm_nodes = NULL;
- free (nodes);
}
/* Return true when function body of DECL still needs to be kept around
execute_ipa_summary_passes
((struct ipa_opt_pass_d *) all_regular_ipa_passes);
}
-
- /* Some targets need to handle LTO assembler output specially. */
- if (flag_generate_lto)
- targetm.asm_out.lto_start ();
-
execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes);
if (!in_lto_p)
ipa_write_summaries ();
- if (flag_generate_lto)
- targetm.asm_out.lto_end ();
-
if (!flag_ltrans)
execute_ipa_pass_list (all_regular_ipa_passes);
invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL);
DECL_ARTIFICIAL (decl) = 1;
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
DECL_SAVED_TREE (decl) = body;
- if (!targetm.have_ctors_dtors)
- {
- TREE_PUBLIC (decl) = 1;
- DECL_PRESERVE_P (decl) = 1;
- }
+ TREE_PUBLIC (decl) = ! targetm.have_ctors_dtors;
DECL_UNINLINABLE (decl) = 1;
DECL_INITIAL (decl) = make_node (BLOCK);
VEC(cgraph_edge_p,heap) *redirect_callers)
{
struct cgraph_node *new_version;
- struct cgraph_edge *e;
+ struct cgraph_edge *e, *new_e;
struct cgraph_edge *next_callee;
unsigned i;
also cloned. */
for (e = old_version->callees;e; e=e->next_callee)
{
- cgraph_clone_edge (e, new_version, e->call_stmt,
- e->lto_stmt_uid, REG_BR_PROB_BASE,
- CGRAPH_FREQ_BASE,
- e->loop_nest, true);
+ new_e = cgraph_clone_edge (e, new_version, e->call_stmt,
+ e->lto_stmt_uid, 0, e->frequency,
+ e->loop_nest, true);
+ new_e->count = e->count;
}
/* Fix recursive calls.
If OLD_VERSION has a recursive call after the
gsi = gsi_for_stmt (e->call_stmt);
gsi_replace (&gsi, new_stmt, true);
- update_stmt (new_stmt);
/* Update EH information too, just in case. */
maybe_clean_or_replace_eh_stmt (e->call_stmt, new_stmt);
}
}
cgraph_materialize_clone (node);
- stabilized = false;
}
+ else
+ stabilized = false;
}
}
}
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
for (e = node->callees; e; e = e->next_callee)
cgraph_redirect_edge_call_stmt_to_callee (e);
- gcc_assert (!need_ssa_update_p (cfun));
pop_cfun ();
current_function_decl = NULL;
#ifdef ENABLE_CHECKING
/* Basic IPA optimizations and utilities.
- Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+ Inc.
This file is part of GCC.
#include "timevar.h"
#include "gimple.h"
#include "ggc.h"
-#include "flags.h"
/* Fill array order with all nodes with output flag set in the reverse
topological order. */
node2->aux = edge->next_caller;
else
node2->aux = &last;
- /* Break possible cycles involving always-inline
- functions by ignoring edges from always-inline
- functions to non-always-inline functions. */
- if (edge->caller->local.disregard_inline_limits
- && !edge->callee->local.disregard_inline_limits)
- continue;
if (!edge->caller->aux)
{
if (!edge->caller->callers)
}
}
-/* Add cgraph NODE to queue starting at FIRST.
-
- The queue is linked via AUX pointers and terminated by pointer to 1.
- We enqueue nodes at two occasions: when we find them reachable or when we find
- their bodies needed for further clonning. In the second case we mark them
- by pointer to 2 after processing so they are re-queue when they become
- reachable. */
-
-static void
-enqueue_cgraph_node (struct cgraph_node *node, struct cgraph_node **first)
-{
- /* Node is still in queue; do nothing. */
- if (node->aux && node->aux != (void *) 2)
- return;
- /* Node was already processed as unreachable, re-enqueue
- only if it became reachable now. */
- if (node->aux == (void *)2 && !node->reachable)
- return;
- node->aux = *first;
- *first = node;
-}
-
-/* Add varpool NODE to queue starting at FIRST. */
-
-static void
-enqueue_varpool_node (struct varpool_node *node, struct varpool_node **first)
-{
- node->aux = *first;
- *first = node;
-}
-
-/* Process references. */
-
-static void
-process_references (struct ipa_ref_list *list,
- struct cgraph_node **first,
- struct varpool_node **first_varpool,
- bool before_inlining_p)
-{
- int i;
- struct ipa_ref *ref;
- for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
- {
- if (ref->refered_type == IPA_REF_CGRAPH)
- {
- struct cgraph_node *node = ipa_ref_node (ref);
- if (!node->reachable
- && (!DECL_EXTERNAL (node->decl)
- || before_inlining_p))
- {
- node->reachable = true;
- enqueue_cgraph_node (node, first);
- }
- }
- else
- {
- struct varpool_node *node = ipa_ref_varpool_node (ref);
- if (!node->needed)
- {
- varpool_mark_needed_node (node);
- enqueue_varpool_node (node, first_varpool);
- }
- }
- }
-}
-
-/* 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
- && (DECL_COMDAT (node->decl) || !node->externally_visible));
-}
-
-/* Return true when function can be marked local. */
-
-static bool
-cgraph_local_node_p (struct cgraph_node *node)
-{
- return (cgraph_only_called_directly_p (node)
- && node->analyzed
- && !DECL_EXTERNAL (node->decl)
- && !node->local.externally_visible
- && !node->reachable_from_other_partition
- && !node->in_other_partition);
-}
-
/* Perform reachability analysis and reclaim all unreachable nodes.
If BEFORE_INLINING_P is true this function is called before inlining
decisions has been made. If BEFORE_INLINING_P is false this function also
cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
{
struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
- struct varpool_node *first_varpool = (struct varpool_node *) (void *) 1;
+ struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
struct cgraph_node *node, *next;
- struct varpool_node *vnode, *vnext;
bool changed = false;
#ifdef ENABLE_CHECKING
#ifdef ENABLE_CHECKING
for (node = cgraph_nodes; node; node = node->next)
gcc_assert (!node->aux);
- for (vnode = varpool_nodes; vnode; vnode = vnode->next)
- gcc_assert (!vnode->aux);
#endif
- varpool_reset_queue ();
for (node = cgraph_nodes; node; node = node->next)
- if (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
+ if (!cgraph_can_remove_if_no_direct_calls_p (node)
&& ((!DECL_EXTERNAL (node->decl))
+ || !node->analyzed
|| before_inlining_p))
{
gcc_assert (!node->global.inlined_to);
- enqueue_cgraph_node (node, &first);
+ node->aux = first;
+ first = node;
node->reachable = true;
}
else
gcc_assert (!node->aux);
node->reachable = false;
}
- for (vnode = varpool_nodes; vnode; vnode = vnode->next)
- {
- vnode->next_needed = NULL;
- vnode->prev_needed = NULL;
- if (!varpool_can_remove_if_no_refs (vnode))
- {
- vnode->needed = false;
- varpool_mark_needed_node (vnode);
- enqueue_varpool_node (vnode, &first_varpool);
- }
- else
- vnode->needed = false;
- }
/* Perform reachability analysis. As a special case do not consider
extern inline functions not inlined as live because we won't output
- them at all.
-
- We maintain two worklist, one for cgraph nodes other for varpools and
- are finished once both are empty. */
-
- while (first != (struct cgraph_node *) (void *) 1
- || first_varpool != (struct varpool_node *) (void *) 1)
+ them at all. */
+ while (first != (void *) 1)
{
- if (first != (struct cgraph_node *) (void *) 1)
- {
- struct cgraph_edge *e;
- node = first;
- first = (struct cgraph_node *) first->aux;
- if (!node->reachable)
- node->aux = (void *)2;
-
- /* If we found this node reachable, first mark on the callees
- reachable too, unless they are direct calls to extern inline functions
- we decided to not inline. */
- if (node->reachable)
- for (e = node->callees; e; e = e->next_callee)
- if (!e->callee->reachable
- && node->analyzed
- && (!e->inline_failed || !e->callee->analyzed
- || (!DECL_EXTERNAL (e->callee->decl))
- || before_inlining_p))
- {
- e->callee->reachable = true;
- enqueue_cgraph_node (e->callee, &first);
- }
-
- /* If any function in a comdat group is reachable, force
- all other functions in the same comdat group to be
- also reachable. */
- if (node->same_comdat_group
- && node->reachable
- && !node->global.inlined_to)
+ struct cgraph_edge *e;
+ node = first;
+ first = (struct cgraph_node *) first->aux;
+ node->aux = processed;
+
+ if (node->reachable)
+ for (e = node->callees; e; e = e->next_callee)
+ if (!e->callee->reachable
+ && node->analyzed
+ && (!e->inline_failed || !e->callee->analyzed
+ || (!DECL_EXTERNAL (e->callee->decl))
+ || before_inlining_p))
{
- for (next = node->same_comdat_group;
- next != node;
- next = next->same_comdat_group)
- if (!next->reachable)
- {
- next->reachable = true;
- enqueue_cgraph_node (next, &first);
- }
+ bool prev_reachable = e->callee->reachable;
+ e->callee->reachable |= node->reachable;
+ if (!e->callee->aux
+ || (e->callee->aux == processed
+ && prev_reachable != e->callee->reachable))
+ {
+ e->callee->aux = first;
+ first = e->callee;
+ }
}
- /* We can freely remove inline clones even if they are cloned, however if
- function is clone of real clone, we must keep it around in order to
- make materialize_clones produce function body with the changes
- applied. */
- while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
- {
- bool noninline = node->clone_of->decl != node->decl;
- node = node->clone_of;
- if (noninline && !node->reachable && !node->aux)
- {
- enqueue_cgraph_node (node, &first);
- break;
- }
- }
- process_references (&node->ref_list, &first, &first_varpool, before_inlining_p);
- }
- if (first_varpool != (struct varpool_node *) (void *) 1)
+ /* If any function in a comdat group is reachable, force
+ all other functions in the same comdat group to be
+ also reachable. */
+ if (node->same_comdat_group
+ && node->reachable
+ && !node->global.inlined_to)
{
- vnode = first_varpool;
- first_varpool = (struct varpool_node *)first_varpool->aux;
- vnode->aux = NULL;
- process_references (&vnode->ref_list, &first, &first_varpool, before_inlining_p);
- /* If any function in a comdat group is reachable, force
- all other functions in the same comdat group to be
- also reachable. */
- if (vnode->same_comdat_group)
+ for (next = node->same_comdat_group;
+ next != node;
+ next = next->same_comdat_group)
+ if (!next->reachable)
+ {
+ next->aux = first;
+ first = next;
+ next->reachable = true;
+ }
+ }
+
+ /* We can freely remove inline clones even if they are cloned, however if
+ function is clone of real clone, we must keep it around in order to
+ make materialize_clones produce function body with the changes
+ applied. */
+ while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
+ {
+ bool noninline = node->clone_of->decl != node->decl;
+ node = node->clone_of;
+ if (noninline)
{
- struct varpool_node *next;
- for (next = vnode->same_comdat_group;
- next != vnode;
- next = next->same_comdat_group)
- if (!next->needed)
- {
- varpool_mark_needed_node (next);
- enqueue_varpool_node (next, &first_varpool);
- }
+ node->aux = first;
+ first = node;
+ break;
}
}
}
- /* Remove unreachable nodes.
-
- Completely unreachable functions can be fully removed from the callgraph.
- Extern inline functions that we decided to not inline need to become unanalyzed nodes of
- callgraph (so we still have edges to them). We remove function body then.
-
- Also we need to care functions that are unreachable but we need to keep them around
- for later clonning. In this case we also turn them to unanalyzed nodes, but
- keep the body around. */
+ /* Remove unreachable nodes. Extern inline functions need special care;
+ Unreachable extern inline functions shall be removed.
+ Reachable extern inline functions we never inlined shall get their bodies
+ eliminated.
+ Reachable extern inline functions we sometimes inlined will be turned into
+ unanalyzed nodes so they look like for true extern functions to the rest
+ of code. Body of such functions is released via remove_node once the
+ inline clones are eliminated. */
for (node = cgraph_nodes; node; node = next)
{
next = node->next;
/* See if there is reachable caller. */
for (e = node->callers; e; e = e->next_caller)
- if (e->caller->reachable)
+ if (e->caller->aux)
break;
/* If so, we need to keep node in the callgraph. */
node->analyzed = false;
node->local.inlinable = false;
}
- else
- gcc_assert (!clone->in_other_partition);
cgraph_node_remove_callees (node);
- ipa_remove_all_references (&node->ref_list);
if (node->prev_sibling_clone)
node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
else if (node->clone_of)
}
node->aux = NULL;
}
-
- if (file)
- fprintf (file, "\n");
-
- /* We must release unused extern inlines or sanity checking will fail. Rest of transformations
- are undesirable at -O0 since we do not want to remove anything. */
- if (!optimize)
- return changed;
-
- if (file)
- fprintf (file, "Reclaiming variables:");
- for (vnode = varpool_nodes; vnode; vnode = vnext)
- {
- vnext = vnode->next;
- if (!vnode->needed)
- {
- if (file)
- fprintf (file, " %s", varpool_node_name (vnode));
- varpool_remove_node (vnode);
- changed = true;
- }
- }
-
- /* Now update address_taken flags and try to promote functions to be local. */
-
- if (file)
- fprintf (file, "\nClearing address taken flags:");
- for (node = cgraph_nodes; node; node = node->next)
- if (node->address_taken
- && !node->reachable_from_other_partition)
- {
- int i;
- struct ipa_ref *ref;
- bool found = false;
- for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref)
- && !found; i++)
- {
- gcc_assert (ref->use == IPA_REF_ADDR);
- found = true;
- }
- if (!found)
- {
- if (file)
- fprintf (file, " %s", cgraph_node_name (node));
- node->address_taken = false;
- changed = true;
- if (cgraph_local_node_p (node))
- {
- node->local.local = true;
- if (file)
- fprintf (file, " (local)");
- }
- }
- }
-
#ifdef ENABLE_CHECKING
verify_cgraph ();
#endif
return changed;
}
-/* Discover variables that have no longer address taken or that are read only
- and update their flags.
-
- FIXME: This can not be done in between gimplify and omp_expand since
- readonly flag plays role on what is shared and what is not. Currently we do
- this transformation as part of ipa-reference pass, but it would make sense
- to do it before early optimizations. */
-
-void
-ipa_discover_readonly_nonaddressable_vars (void)
-{
- struct varpool_node *vnode;
- if (dump_file)
- fprintf (dump_file, "Clearing variable flags:");
- for (vnode = varpool_nodes; vnode; vnode = vnode->next)
- if (vnode->finalized && varpool_all_refs_explicit_p (vnode)
- && (TREE_ADDRESSABLE (vnode->decl) || !TREE_READONLY (vnode->decl)))
- {
- bool written = false;
- bool address_taken = false;
- int i;
- struct ipa_ref *ref;
- for (i = 0; ipa_ref_list_refering_iterate (&vnode->ref_list, i, ref)
- && (!written || !address_taken); i++)
- switch (ref->use)
- {
- case IPA_REF_ADDR:
- address_taken = true;
- break;
- case IPA_REF_LOAD:
- break;
- case IPA_REF_STORE:
- written = true;
- break;
- }
- if (TREE_ADDRESSABLE (vnode->decl) && !address_taken)
- {
- if (dump_file)
- fprintf (dump_file, " %s (addressable)", varpool_node_name (vnode));
- TREE_ADDRESSABLE (vnode->decl) = 0;
- }
- if (!TREE_READONLY (vnode->decl) && !address_taken && !written
- /* Making variable in explicit section readonly can cause section
- type conflict.
- See e.g. gcc.c-torture/compile/pr23237.c */
- && DECL_SECTION_NAME (vnode->decl) == NULL)
- {
- if (dump_file)
- fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode));
- TREE_READONLY (vnode->decl) = 1;
- }
- }
- if (dump_file)
- fprintf (dump_file, "\n");
-}
-
-/* Return true when function NODE should be considered externally visible. */
-
static bool
cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
{
return false;
if (!whole_program)
return true;
- if (DECL_PRESERVE_P (node->decl))
- return true;
/* COMDAT functions must be shared only if they have address taken,
otherwise we can produce our own private implementation with
-fwhole-program. */
return false;
}
-/* Dissolve the same_comdat_group list in which NODE resides. */
-
-static void
-dissolve_same_comdat_group_list (struct cgraph_node *node)
-{
- struct cgraph_node *n = node, *next;
- do
- {
- next = n->same_comdat_group;
- n->same_comdat_group = NULL;
- n = next;
- }
- while (n != node);
-}
-
/* Mark visibility of all functions.
A local function is one whose calls can occur only in the current
and simplifies later passes. */
if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
{
-#ifdef ENABLE_CHECKING
- struct cgraph_node *n;
-
- for (n = node->same_comdat_group;
- n != node;
- n = n->same_comdat_group)
+ struct cgraph_node *n = node, *next;
+ do
+ {
/* If at least one of same comdat group functions is external,
all of them have to be, otherwise it is a front-end bug. */
gcc_assert (DECL_EXTERNAL (n->decl));
-#endif
- dissolve_same_comdat_group_list (node);
+ next = n->same_comdat_group;
+ n->same_comdat_group = NULL;
+ n = next;
+ }
+ while (n != node);
}
gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
|| TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
if (!node->local.externally_visible && node->analyzed
&& !DECL_EXTERNAL (node->decl))
{
- struct cgraph_node *alias;
gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
cgraph_make_decl_local (node->decl);
- for (alias = node->same_body; alias; alias = alias->next)
- cgraph_make_decl_local (alias->decl);
- if (node->same_comdat_group)
- /* cgraph_externally_visible_p has already checked all other nodes
- in the group and they will all be made local. We need to
- dissolve the group at once so that the predicate does not
- segfault though. */
- dissolve_same_comdat_group_list (node);
}
- node->local.local = cgraph_local_node_p (node);
+ node->local.local = (cgraph_only_called_directly_p (node)
+ && node->analyzed
+ && !DECL_EXTERNAL (node->decl)
+ && !node->local.externally_visible);
}
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
{
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_remove_functions | TODO_dump_cgraph
- | TODO_ggc_collect /* todo_flags_finish */
+ TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
}
};
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_remove_functions | TODO_dump_cgraph
- | TODO_ggc_collect /* todo_flags_finish */
+ TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
},
NULL, /* generate_summary */
NULL, /* write_summary */
NULL, /* read_summary */
- NULL, /* write_optimization_summary */
- NULL, /* read_optimization_summary */
+ NULL, /* function_read_summary */
NULL, /* stmt_fixup */
0, /* TODOs */
NULL, /* function_transform */
dump_cgraph_node_set (stderr, set);
}
-/* Hash a varpool node set element. */
-
-static hashval_t
-hash_varpool_node_set_element (const void *p)
-{
- const_varpool_node_set_element element = (const_varpool_node_set_element) p;
- return htab_hash_pointer (element->node);
-}
-
-/* Compare two varpool node set elements. */
-
-static int
-eq_varpool_node_set_element (const void *p1, const void *p2)
-{
- const_varpool_node_set_element e1 = (const_varpool_node_set_element) p1;
- const_varpool_node_set_element e2 = (const_varpool_node_set_element) p2;
-
- return e1->node == e2->node;
-}
-
-/* Create a new varpool node set. */
-
-varpool_node_set
-varpool_node_set_new (void)
-{
- varpool_node_set new_node_set;
-
- new_node_set = GGC_NEW (struct varpool_node_set_def);
- new_node_set->hashtab = htab_create_ggc (10,
- hash_varpool_node_set_element,
- eq_varpool_node_set_element,
- NULL);
- new_node_set->nodes = NULL;
- return new_node_set;
-}
-
-/* Add varpool_node NODE to varpool_node_set SET. */
-
-void
-varpool_node_set_add (varpool_node_set set, struct varpool_node *node)
-{
- void **slot;
- varpool_node_set_element element;
- struct varpool_node_set_element_def dummy;
-
- dummy.node = node;
- slot = htab_find_slot (set->hashtab, &dummy, INSERT);
-
- if (*slot != HTAB_EMPTY_ENTRY)
- {
- element = (varpool_node_set_element) *slot;
- gcc_assert (node == element->node
- && (VEC_index (varpool_node_ptr, set->nodes, element->index)
- == node));
- return;
- }
-
- /* Insert node into hash table. */
- element =
- (varpool_node_set_element) GGC_NEW (struct varpool_node_set_element_def);
- element->node = node;
- element->index = VEC_length (varpool_node_ptr, set->nodes);
- *slot = element;
-
- /* Insert into node vector. */
- VEC_safe_push (varpool_node_ptr, gc, set->nodes, node);
-}
-
-/* Remove varpool_node NODE from varpool_node_set SET. */
-
-void
-varpool_node_set_remove (varpool_node_set set, struct varpool_node *node)
-{
- void **slot, **last_slot;
- varpool_node_set_element element, last_element;
- struct varpool_node *last_node;
- struct varpool_node_set_element_def dummy;
-
- dummy.node = node;
- slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
- if (slot == NULL)
- return;
-
- element = (varpool_node_set_element) *slot;
- gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
- == node);
-
- /* Remove from vector. We do this by swapping node with the last element
- of the vector. */
- last_node = VEC_pop (varpool_node_ptr, set->nodes);
- if (last_node != node)
- {
- dummy.node = last_node;
- last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
- last_element = (varpool_node_set_element) *last_slot;
- gcc_assert (last_element);
-
- /* Move the last element to the original spot of NODE. */
- last_element->index = element->index;
- VEC_replace (varpool_node_ptr, set->nodes, last_element->index,
- last_node);
- }
-
- /* Remove element from hash table. */
- htab_clear_slot (set->hashtab, slot);
- ggc_free (element);
-}
-
-/* Find NODE in SET and return an iterator to it if found. A null iterator
- is returned if NODE is not in SET. */
-
-varpool_node_set_iterator
-varpool_node_set_find (varpool_node_set set, struct varpool_node *node)
-{
- void **slot;
- struct varpool_node_set_element_def dummy;
- varpool_node_set_element element;
- varpool_node_set_iterator vsi;
-
- dummy.node = node;
- slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
- if (slot == NULL)
- vsi.index = (unsigned) ~0;
- else
- {
- element = (varpool_node_set_element) *slot;
- gcc_assert (VEC_index (varpool_node_ptr, set->nodes, element->index)
- == node);
- vsi.index = element->index;
- }
- vsi.set = set;
-
- return vsi;
-}
-
-/* Dump content of SET to file F. */
-
-void
-dump_varpool_node_set (FILE *f, varpool_node_set set)
-{
- varpool_node_set_iterator iter;
-
- for (iter = vsi_start (set); !vsi_end_p (iter); vsi_next (&iter))
- {
- struct varpool_node *node = vsi_node (iter);
- dump_varpool_node (f, node);
- }
-}
-
-/* Dump content of SET to stderr. */
-
-void
-debug_varpool_node_set (varpool_node_set set)
-{
- dump_varpool_node_set (stderr, set);
-}
-
-
-/* Simple ipa profile pass propagating frequencies across the callgraph. */
-
-static unsigned int
-ipa_profile (void)
-{
- struct cgraph_node **order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
- struct cgraph_edge *e;
- int order_pos;
- bool something_changed = false;
- int i;
-
- order_pos = cgraph_postorder (order);
- for (i = order_pos - 1; i >= 0; i--)
- {
- if (order[i]->local.local && cgraph_propagate_frequency (order[i]))
- {
- for (e = order[i]->callees; e; e = e->next_callee)
- if (e->callee->local.local && !e->callee->aux)
- {
- something_changed = true;
- e->callee->aux = (void *)1;
- }
- }
- order[i]->aux = NULL;
- }
-
- while (something_changed)
- {
- something_changed = false;
- for (i = order_pos - 1; i >= 0; i--)
- {
- if (order[i]->aux && cgraph_propagate_frequency (order[i]))
- {
- for (e = order[i]->callees; e; e = e->next_callee)
- if (e->callee->local.local && !e->callee->aux)
- {
- something_changed = true;
- e->callee->aux = (void *)1;
- }
- }
- order[i]->aux = NULL;
- }
- }
- free (order);
- return 0;
-}
-
-static bool
-gate_ipa_profile (void)
-{
- return flag_ipa_profile;
-}
-
-struct ipa_opt_pass_d pass_ipa_profile =
-{
- {
- IPA_PASS,
- "ipa-profile", /* name */
- gate_ipa_profile, /* gate */
- ipa_profile, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_IPA_PROFILE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- },
- NULL, /* generate_summary */
- NULL, /* write_summary */
- NULL, /* read_summary */
- NULL, /* write_optimization_summary */
- NULL, /* read_optimization_summary */
- NULL, /* stmt_fixup */
- 0, /* TODOs */
- NULL, /* function_transform */
- NULL /* variable_transform */
-};
+2010-03-18 Martin Jambor <mjambor@suse.cz>
+
+ PR middle-end/42450
+ * g++.dg/torture/pr42450.C: New test.
+
2010-03-18 Michael Matz <matz@suse.de>
PR middle-end/43419