cgraphbuild.c (record_reference_ctx): Add varpool_node.

* cgraphbuild.c (record_reference_ctx): Add varpool_node.
	(record_reference, mark_address, mark_load, mark_store): Record
	references.
	(record_references_in_initializer): Update call of record_references.
	(rebuild_cgraph_edges): Remove all references before rebuiding.
	* cgraph.c (cgraph_create_node): Clear ref list.
	(cgraph_remove_node): Remove references.
	(dump_cgraph_node): Dump references.
	(cgraph_clone_node): Clone references.
	* cgraph.h: Include ipa-ref.h and ipa-ref-inline.h
	(struct cgraph_node, varpool_node): Add ref_lst.
	* ipa-ref.c: New file.
	* ipa-ref.h: New file.
	* ipa-ref-inline.h: New file.
	* lto-cgraph.c (output_varpool): Take cgrag node set argument.
	(referenced_from_other_partition_p): New function.
	(lto_output_varpool_node): Take set arugment; call
	referenced_from_other_partition.
	(lto_output_ref): New.
	(add_references): New.
	(output_refs): New.
	(output_cgraph): Compute boundary based on references;
	output refs.
	(output_varpool): Accept cgraph_node_set argument.
	(input_ref): New.
	(input_refs): New.
	(input_cgraph): Call input_refs.
	* lto-section-in.c (lto_section_name): Add refs.
	* Makefile.in: (cgraph.h): Include ipa-ref.h and ipa-ref-inline.h
	(ipa-ref.o): New file.
	* varpool.c (varpool_node): Clear ipa ref list.
	(varpool_remove_node): Remove references.
	(dump_varpool_node): Dump references.
	(varpool_assemble_decl): Only compile finalized ones.
	(varpool_extra_name_alias): Initialize ref list.
	* lto-streamer.c (lto-get_section_name): Add .refs section.
	* lto-streamer.h (lto_section_type): Add LTO_section_refs.
	(referenced_from_other_partition_p): Declared.

From-SVN: r159097
This commit is contained in:
Jan Hubicka 2010-05-06 10:39:32 +02:00 committed by Jan Hubicka
parent 03a904b5a6
commit 369451ec60
16 changed files with 807 additions and 33 deletions

View File

@ -1,3 +1,44 @@
2010-05-06 Jan Hubicka <jh@suse.cz>
* cgraphbuild.c (record_reference_ctx): Add varpool_node.
(record_reference, mark_address, mark_load, mark_store): Record
references.
(record_references_in_initializer): Update call of record_references.
(rebuild_cgraph_edges): Remove all references before rebuiding.
* cgraph.c (cgraph_create_node): Clear ref list.
(cgraph_remove_node): Remove references.
(dump_cgraph_node): Dump references.
(cgraph_clone_node): Clone references.
* cgraph.h: Include ipa-ref.h and ipa-ref-inline.h
(struct cgraph_node, varpool_node): Add ref_lst.
* ipa-ref.c: New file.
* ipa-ref.h: New file.
* ipa-ref-inline.h: New file.
* lto-cgraph.c (output_varpool): Take cgrag node set argument.
(referenced_from_other_partition_p): New function.
(lto_output_varpool_node): Take set arugment; call
referenced_from_other_partition.
(lto_output_ref): New.
(add_references): New.
(output_refs): New.
(output_cgraph): Compute boundary based on references;
output refs.
(output_varpool): Accept cgraph_node_set argument.
(input_ref): New.
(input_refs): New.
(input_cgraph): Call input_refs.
* lto-section-in.c (lto_section_name): Add refs.
* Makefile.in: (cgraph.h): Include ipa-ref.h and ipa-ref-inline.h
(ipa-ref.o): New file.
* varpool.c (varpool_node): Clear ipa ref list.
(varpool_remove_node): Remove references.
(dump_varpool_node): Dump references.
(varpool_assemble_decl): Only compile finalized ones.
(varpool_extra_name_alias): Initialize ref list.
* lto-streamer.c (lto-get_section_name): Add .refs section.
* lto-streamer.h (lto_section_type): Add LTO_section_refs.
(referenced_from_other_partition_p): Declared.
2010-05-06 Ira Rosen <irar@il.ibm.com>
PR tree-optimization/43901

View File

@ -904,7 +904,7 @@ CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $(RTL_H) vecprim.h double-int.h
IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H)
IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H)
IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H)
CGRAPH_H = cgraph.h $(TREE_H) $(BASIC_BLOCK_H) cif-code.def
CGRAPH_H = cgraph.h $(TREE_H) $(BASIC_BLOCK_H) cif-code.def ipa-ref.h ipa-ref-inline.h
DF_H = df.h $(BITMAP_H) $(BASIC_BLOCK_H) alloc-pool.h $(TIMEVAR_H)
RESOURCE_H = resource.h hard-reg-set.h $(DF_H)
DDG_H = ddg.h sbitmap.h $(DF_H)
@ -1425,6 +1425,7 @@ OBJS-archive = \
ipa-prop.o \
ipa-pure-const.o \
ipa-reference.o \
ipa-ref.o \
ipa-struct-reorg.o \
ipa-type-escape.o \
ipa-utils.o \
@ -2902,6 +2903,9 @@ ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(DIAGNOSTIC_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) \
$(TREE_INLINE_H) $(TIMEVAR_H)
ipa-ref.o : ipa-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) $(TREE_H) $(TARGET_H) \
$(TREE_FLOW_H) $(TM_H) $(TREE_PASS_H) $(FLAGS_H) $(TREE_H) $(GGC_H)
ipa-cp.o : ipa-cp.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TREE_H) $(TARGET_H) $(CGRAPH_H) $(IPA_PROP_H) $(TREE_FLOW_H) \
$(TREE_PASS_H) $(FLAGS_H) $(TIMEVAR_H) $(DIAGNOSTIC_H) $(TREE_DUMP_H) \
@ -3584,7 +3588,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/real.h $(srcdir)/function.h $(srcdir)/insn-addr.h $(srcdir)/hwint.h \
$(srcdir)/fixed-value.h \
$(srcdir)/ipa-reference.h $(srcdir)/output.h $(srcdir)/cfgloop.h \
$(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/cgraph.h \
$(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \
$(srcdir)/reload.h $(srcdir)/caller-save.c \
$(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
$(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-inline.c $(srcdir)/matrix-reorg.c \

View File

@ -463,6 +463,7 @@ cgraph_create_node (void)
node->previous = NULL;
node->global.estimated_growth = INT_MIN;
node->frequency = NODE_FREQUENCY_NORMAL;
ipa_empty_ref_list (&node->ref_list);
cgraph_nodes = node;
cgraph_n_nodes++;
return node;
@ -1412,6 +1413,8 @@ cgraph_remove_node (struct cgraph_node *node)
cgraph_call_node_removal_hooks (node);
cgraph_node_remove_callers (node);
cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->ref_list);
ipa_remove_all_refering (&node->ref_list);
VEC_free (ipa_opt_pass, heap,
node->ipa_transforms_to_apply);
@ -1853,6 +1856,10 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
fprintf(f, "(can throw external) ");
}
fprintf (f, "\n");
fprintf (f, " References: ");
ipa_dump_references (f, &node->ref_list);
fprintf (f, " Refering this function: ");
ipa_dump_refering (f, &node->ref_list);
for (edge = node->indirect_calls; edge; edge = edge->next_callee)
indirect_calls_count++;
@ -2081,6 +2088,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
for (e = n->indirect_calls; e; e = e->next_callee)
cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid,
count_scale, freq, loop_nest, update_original);
ipa_clone_references (new_node, NULL, &n->ref_list);
new_node->next_sibling_clone = n->clones;
if (n->clones)

View File

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_CGRAPH_H
#include "tree.h"
#include "basic-block.h"
#include "ipa-ref.h"
enum availability
{
@ -224,6 +225,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
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;
@ -427,7 +429,7 @@ DEF_VEC_ALLOC_P(cgraph_edge_p,heap);
/* 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;
/* Pointer to the next function in varpool_nodes. */
struct varpool_node *next, *prev;
@ -436,6 +438,7 @@ struct GTY((chain_next ("%h.next"))) varpool_node {
/* 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;
struct ipa_ref_list ref_list;
/* Ordering of all cgraph nodes. */
int order;
@ -864,4 +867,6 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
/* Constant pool accessor function. */
htab_t constant_pool_htab (void);
#include "ipa-ref-inline.h"
#endif /* GCC_CGRAPH_H */

View File

@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
struct record_reference_ctx
{
bool only_vars;
struct varpool_node *varpool_node;
};
/* Walk tree and record all calls and references to functions/variables.
@ -63,15 +64,26 @@ record_reference (tree *tp, int *walk_subtrees, void *data)
/* Record dereferences to the functions. This makes the
functions reachable unconditionally. */
decl = get_base_var (*tp);
if (TREE_CODE (decl) == FUNCTION_DECL && !ctx->only_vars)
cgraph_mark_address_taken_node (cgraph_node (decl));
if (TREE_CODE (decl) == FUNCTION_DECL)
{
if (!ctx->only_vars)
cgraph_mark_address_taken_node (cgraph_node (decl));
ipa_record_reference (NULL, ctx->varpool_node,
cgraph_node (decl), NULL,
IPA_REF_ADDR, NULL);
}
if (TREE_CODE (decl) == VAR_DECL)
{
gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
struct varpool_node *vnode = varpool_node (decl);
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&decl, walk_subtrees);
varpool_mark_needed_node (varpool_node (decl));
varpool_mark_needed_node (vnode);
if (vnode->alias && vnode->extra_name)
vnode = vnode->extra_name;
ipa_record_reference (NULL, ctx->varpool_node,
NULL, vnode,
IPA_REF_ADDR, NULL);
}
*walk_subtrees = 0;
break;
@ -148,6 +160,9 @@ mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr,
{
struct cgraph_node *node = cgraph_node (addr);
cgraph_mark_address_taken_node (node);
ipa_record_reference ((struct cgraph_node *)data, NULL,
node, NULL,
IPA_REF_ADDR, stmt);
}
else
{
@ -161,6 +176,11 @@ mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr,
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&addr, &walk_subtrees);
varpool_mark_needed_node (vnode);
if (vnode->alias && vnode->extra_name)
vnode = vnode->extra_name;
ipa_record_reference ((struct cgraph_node *)data, NULL,
NULL, vnode,
IPA_REF_ADDR, stmt);
}
}
@ -183,6 +203,11 @@ mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t,
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
varpool_mark_needed_node (vnode);
if (vnode->alias && vnode->extra_name)
vnode = vnode->extra_name;
ipa_record_reference ((struct cgraph_node *)data, NULL,
NULL, vnode,
IPA_REF_LOAD, stmt);
}
return false;
}
@ -203,6 +228,11 @@ mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t,
if (lang_hooks.callgraph.analyze_expr)
lang_hooks.callgraph.analyze_expr (&t, &walk_subtrees);
varpool_mark_needed_node (vnode);
if (vnode->alias && vnode->extra_name)
vnode = vnode->extra_name;
ipa_record_reference ((struct cgraph_node *)data, NULL,
NULL, vnode,
IPA_REF_STORE, NULL);
}
return false;
}
@ -299,8 +329,10 @@ void
record_references_in_initializer (tree decl, bool only_vars)
{
struct pointer_set_t *visited_nodes = pointer_set_create ();
struct record_reference_ctx ctx = {false};
struct varpool_node *node = varpool_node (decl);
struct record_reference_ctx ctx = {false, NULL};
ctx.varpool_node = node;
ctx.only_vars = only_vars;
walk_tree (&DECL_INITIAL (decl), record_reference,
&ctx, visited_nodes);
@ -318,6 +350,7 @@ rebuild_cgraph_edges (void)
gimple_stmt_iterator gsi;
cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->ref_list);
node->count = ENTRY_BLOCK_PTR->count;

View File

@ -0,0 +1,119 @@
/* IPA reference lists.
Copyright (C) 2010
Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* Return callgraph node REF is refering. */
static inline struct cgraph_node *
ipa_ref_node (struct ipa_ref *ref)
{
gcc_assert (ref->refered_type == IPA_REF_CGRAPH);
return ref->refered.cgraph_node;
}
/* Return varpool node REF is refering. */
static inline struct varpool_node *
ipa_ref_varpool_node (struct ipa_ref *ref)
{
gcc_assert (ref->refered_type == IPA_REF_VARPOOL);
return ref->refered.varpool_node;
}
/* Return cgraph node REF is in. */
static inline struct cgraph_node *
ipa_ref_refering_node (struct ipa_ref *ref)
{
gcc_assert (ref->refering_type == IPA_REF_CGRAPH);
return ref->refering.cgraph_node;
}
/* Return varpool node REF is in. */
static inline struct varpool_node *
ipa_ref_refering_varpool_node (struct ipa_ref *ref)
{
gcc_assert (ref->refering_type == IPA_REF_VARPOOL);
return ref->refering.varpool_node;
}
/* Return reference list REF is in. */
static inline struct ipa_ref_list *
ipa_ref_refering_ref_list (struct ipa_ref *ref)
{
if (ref->refering_type == IPA_REF_CGRAPH)
return &ipa_ref_refering_node (ref)->ref_list;
else
return &ipa_ref_refering_varpool_node (ref)->ref_list;
}
/* Return reference list REF is in. */
static inline struct ipa_ref_list *
ipa_ref_refered_ref_list (struct ipa_ref *ref)
{
if (ref->refered_type == IPA_REF_CGRAPH)
return &ipa_ref_node (ref)->ref_list;
else
return &ipa_ref_varpool_node (ref)->ref_list;
}
/* Return first reference in LIST or NULL if empty. */
static inline struct ipa_ref *
ipa_ref_list_first_reference (struct ipa_ref_list *list)
{
if (!VEC_length (ipa_ref_t, list->references))
return NULL;
return VEC_index (ipa_ref_t, list->references, 0);
}
/* Return first refering ref in LIST or NULL if empty. */
static inline struct ipa_ref *
ipa_ref_list_first_refering (struct ipa_ref_list *list)
{
if (!VEC_length (ipa_ref_ptr, list->refering))
return NULL;
return VEC_index (ipa_ref_ptr, list->refering, 0);
}
/* Clear reference list. */
static inline void
ipa_empty_ref_list (struct ipa_ref_list *list)
{
list->refering = NULL;
list->references = NULL;
}
/* Clear reference list. */
static inline unsigned int
ipa_ref_list_nreferences (struct ipa_ref_list *list)
{
return VEC_length (ipa_ref_t, list->references);
}
#define ipa_ref_list_reference_iterate(L,I,P) \
VEC_iterate(ipa_ref_t, (L)->references, (I), (P))
#define ipa_ref_list_refering_iterate(L,I,P) \
VEC_iterate(ipa_ref_ptr, (L)->refering, (I), (P))

View File

@ -0,0 +1,235 @@
/* Interprocedural reference lists.
Copyright (C) 2010
Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "ggc.h"
#include "target.h"
#include "cgraph.h"
static const char *ipa_ref_use_name[] = {"read","write","addr"};
/* Return ipa reference from REFERING_NODE or REFERING_VARPOOL_NODE
to REFERED_NODE or REFERED_VARPOOL_NODE. USE_TYPE specify type
of the use and STMT the statement (if it exists). */
struct ipa_ref *
ipa_record_reference (struct cgraph_node *refering_node,
struct varpool_node *refering_varpool_node,
struct cgraph_node *refered_node,
struct varpool_node *refered_varpool_node,
enum ipa_ref_use use_type, gimple stmt)
{
struct ipa_ref *ref;
struct ipa_ref_list *list, *list2;
VEC(ipa_ref_t,gc) *old_references;
gcc_assert ((!refering_node) ^ (!refering_varpool_node));
gcc_assert ((!refered_node) ^ (!refered_varpool_node));
gcc_assert (!stmt || refering_node);
list = (refering_node ? &refering_node->ref_list
: &refering_varpool_node->ref_list);
old_references = list->references;
VEC_safe_grow (ipa_ref_t, gc, list->references,
VEC_length (ipa_ref_t, list->references) + 1);
ref = VEC_last (ipa_ref_t, list->references);
list2 = (refered_node ? &refered_node->ref_list
: &refered_varpool_node->ref_list);
VEC_safe_push (ipa_ref_ptr, heap, list2->refering, ref);
ref->refered_index = VEC_length (ipa_ref_ptr, list2->refering) - 1;
if (refering_node)
{
ref->refering.cgraph_node = refering_node;
ref->refering_type = IPA_REF_CGRAPH;
}
else
{
ref->refering.varpool_node = refering_varpool_node;
ref->refering_type = IPA_REF_VARPOOL;
gcc_assert (use_type == IPA_REF_ADDR);
}
if (refered_node)
{
ref->refered.cgraph_node = refered_node;
ref->refered_type = IPA_REF_CGRAPH;
gcc_assert (use_type == IPA_REF_ADDR);
}
else
{
varpool_mark_needed_node (refered_varpool_node);
ref->refered.varpool_node = refered_varpool_node;
ref->refered_type = IPA_REF_VARPOOL;
}
ref->stmt = stmt;
ref->use = use_type;
/* If vector was moved in memory, update pointers. */
if (old_references != list->references)
{
int i;
for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
VEC_replace (ipa_ref_ptr,
ipa_ref_refered_ref_list (ref)->refering,
ref->refered_index, ref);
}
return ref;
}
/* Remove reference REF. */
void
ipa_remove_reference (struct ipa_ref *ref)
{
struct ipa_ref_list *list = ipa_ref_refered_ref_list (ref);
struct ipa_ref_list *list2 = ipa_ref_refering_ref_list (ref);
VEC(ipa_ref_t,gc) *old_references = list2->references;
struct ipa_ref *last;
gcc_assert (VEC_index (ipa_ref_ptr, list->refering, ref->refered_index) == ref);
last = VEC_last (ipa_ref_ptr, list->refering);
if (ref != last)
{
VEC_replace (ipa_ref_ptr, list->refering,
ref->refered_index,
VEC_last (ipa_ref_ptr, list->refering));
VEC_index (ipa_ref_ptr, list->refering,
ref->refered_index)->refered_index = ref->refered_index;
}
VEC_pop (ipa_ref_ptr, list->refering);
last = VEC_last (ipa_ref_t, list2->references);
if (ref != last)
{
*ref = *last;
VEC_replace (ipa_ref_ptr,
ipa_ref_refered_ref_list (ref)->refering,
ref->refered_index, ref);
}
VEC_pop (ipa_ref_t, list2->references);
gcc_assert (list2->references == old_references);
}
/* Remove all references in ref list LIST. */
void
ipa_remove_all_references (struct ipa_ref_list *list)
{
while (VEC_length (ipa_ref_t, list->references))
ipa_remove_reference (VEC_last (ipa_ref_t, list->references));
VEC_free (ipa_ref_t, gc, list->references);
list->references = NULL;
}
/* Remove all references in ref list LIST. */
void
ipa_remove_all_refering (struct ipa_ref_list *list)
{
while (VEC_length (ipa_ref_ptr, list->refering))
ipa_remove_reference (VEC_last (ipa_ref_ptr, list->refering));
VEC_free (ipa_ref_ptr, heap, list->refering);
list->refering = NULL;
}
/* Dump references in LIST to FILE. */
void
ipa_dump_references (FILE * file, struct ipa_ref_list *list)
{
struct ipa_ref *ref;
int i;
for (i = 0; ipa_ref_list_reference_iterate (list, i, ref); i++)
{
if (ref->refered_type == IPA_REF_CGRAPH)
{
fprintf (file, " fn:%s/%i (%s)", cgraph_node_name (ipa_ref_node (ref)),
ipa_ref_node (ref)->uid,
ipa_ref_use_name [ref->use]);
}
else
fprintf (file, " var:%s (%s)",
varpool_node_name (ipa_ref_varpool_node (ref)),
ipa_ref_use_name [ref->use]);
}
fprintf (file, "\n");
}
/* Dump refering in LIST to FILE. */
void
ipa_dump_refering (FILE * file, struct ipa_ref_list *list)
{
struct ipa_ref *ref;
int i;
for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++)
{
if (ref->refering_type == IPA_REF_CGRAPH)
fprintf (file, " fn:%s/%i (%s)",
cgraph_node_name (ipa_ref_refering_node (ref)),
ipa_ref_refering_node (ref)->uid,
ipa_ref_use_name [ref->use]);
else
fprintf (file, " var:%s (%s)",
varpool_node_name (ipa_ref_refering_varpool_node (ref)),
ipa_ref_use_name [ref->use]);
}
fprintf (file, "\n");
}
/* Clone all references from SRC to DEST_NODE or DEST_VARPOL_NODE. */
void
ipa_clone_references (struct cgraph_node *dest_node,
struct varpool_node *dest_varpool_node,
struct ipa_ref_list *src)
{
struct ipa_ref *ref;
int i;
for (i = 0; ipa_ref_list_reference_iterate (src, i, ref); i++)
ipa_record_reference (dest_node, dest_varpool_node,
ref->refered_type == IPA_REF_CGRAPH
? ipa_ref_node (ref) : NULL,
ref->refered_type == IPA_REF_VARPOOL
? ipa_ref_varpool_node (ref) : NULL,
ref->use, ref->stmt);
}
/* Clone all refering from SRC to DEST_NODE or DEST_VARPOL_NODE. */
void
ipa_clone_refering (struct cgraph_node *dest_node,
struct varpool_node *dest_varpool_node,
struct ipa_ref_list *src)
{
struct ipa_ref *ref;
int i;
for (i = 0; ipa_ref_list_refering_iterate (src, i, ref); i++)
ipa_record_reference (
ref->refering_type == IPA_REF_CGRAPH
? ipa_ref_refering_node (ref) : NULL,
ref->refering_type == IPA_REF_VARPOOL
? ipa_ref_refering_varpool_node (ref) : NULL,
dest_node, dest_varpool_node,
ref->use, ref->stmt);
}

View File

@ -0,0 +1,91 @@
/* IPA reference lists.
Copyright (C) 2010
Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
struct cgraph_node;
struct varpool_node;
/* How the reference is done. */
enum GTY(()) ipa_ref_use
{
IPA_REF_LOAD,
IPA_REF_STORE,
IPA_REF_ADDR
};
/* Type of refering or refered type. */
enum GTY(()) ipa_ref_type
{
IPA_REF_CGRAPH,
IPA_REF_VARPOOL
};
/* We can have references spanning both callgraph and varpool,
so all pointers needs to be of both types. */
union GTY(()) ipa_ref_ptr_u
{
struct cgraph_node * GTY((tag ("IPA_REF_CGRAPH"))) cgraph_node;
struct varpool_node * GTY((tag ("IPA_REF_VARPOOL"))) varpool_node;
};
/* Record of reference in callgraph or varpool. */
struct GTY(()) ipa_ref
{
union ipa_ref_ptr_u GTY ((desc ("%1.refering_type"))) refering;
union ipa_ref_ptr_u GTY ((desc ("%1.refered_type"))) refered;
gimple stmt;
unsigned int refered_index;
ENUM_BITFIELD (ipa_ref_type) refering_type:1;
ENUM_BITFIELD (ipa_ref_type) refered_type:1;
ENUM_BITFIELD (ipa_ref_use) use:2;
};
typedef struct ipa_ref ipa_ref_t;
typedef struct ipa_ref *ipa_ref_ptr;
DEF_VEC_O(ipa_ref_t);
DEF_VEC_ALLOC_O(ipa_ref_t,gc);
DEF_VEC_P(ipa_ref_ptr);
DEF_VEC_ALLOC_P(ipa_ref_ptr,heap);
/* List of references. This is stored in both callgraph and varpool nodes. */
struct GTY(()) ipa_ref_list
{
/* Store actual references in references vector. */
VEC(ipa_ref_t,gc) *references;
/* Refering is vector of pointers to references. It must not live in GGC space
or GGC will try to mark middle of references vectors. */
VEC(ipa_ref_ptr,heap) * GTY((skip)) refering;
};
struct ipa_ref * ipa_record_reference (struct cgraph_node *,
struct varpool_node *,
struct cgraph_node *,
struct varpool_node *,
enum ipa_ref_use, gimple);
void ipa_remove_reference (struct ipa_ref *);
void ipa_remove_all_references (struct ipa_ref_list *);
void ipa_remove_all_refering (struct ipa_ref_list *);
void ipa_dump_references (FILE *, struct ipa_ref_list *);
void ipa_dump_refering (FILE *, struct ipa_ref_list *);
void ipa_clone_references (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);
void ipa_clone_refering (struct cgraph_node *, struct varpool_node *, struct ipa_ref_list *);

View File

@ -46,7 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "lto-streamer.h"
#include "gcov-io.h"
static void output_varpool (varpool_node_set);
static void output_varpool (cgraph_node_set, varpool_node_set);
/* Cgraph streaming is organized as set of record whose type
is indicated by a tag. */
@ -286,6 +286,30 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
bitpack_delete (bp);
}
/* Return if LIST contain references from other partitions. */
bool
referenced_from_other_partition_p (struct ipa_ref_list *list, cgraph_node_set set,
varpool_node_set vset)
{
int i;
struct ipa_ref *ref;
for (i = 0; ipa_ref_list_refering_iterate (list, i, ref); i++)
{
if (ref->refering_type == IPA_REF_CGRAPH)
{
if (!cgraph_node_in_set_p (ipa_ref_refering_node (ref), set))
return true;
}
else
{
if (!varpool_node_in_set_p (ipa_ref_refering_varpool_node (ref),
vset))
return true;
}
}
return false;
}
/* Return true when node is reachable from other partition. */
static bool
@ -460,9 +484,9 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
static void
lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node *node,
varpool_node_set set)
cgraph_node_set set, varpool_node_set vset)
{
bool boundary_p = !varpool_node_in_set_p (node, set) && node->analyzed;
bool boundary_p = !varpool_node_in_set_p (node, vset) && node->analyzed;
struct bitpack_d *bp;
struct varpool_node *alias;
int count = 0;
@ -486,9 +510,9 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
}
else
{
/* FIXME: We have no idea how we move references around. For moment assume that
everything is used externally. */
bp_pack_value (bp, flag_wpa, 1); /* used_from_other_parition. */
bp_pack_value (bp, node->analyzed
&& referenced_from_other_partition_p (&node->ref_list,
set, vset), 1);
bp_pack_value (bp, boundary_p, 1); /* in_other_partition. */
}
/* Also emit any extra name aliases. */
@ -506,6 +530,34 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
}
}
/* Output the varpool NODE to OB.
If NODE is not in SET, then NODE is a boundary. */
static void
lto_output_ref (struct lto_simple_output_block *ob, struct ipa_ref *ref,
lto_cgraph_encoder_t encoder,
lto_varpool_encoder_t varpool_encoder)
{
struct bitpack_d *bp = bitpack_create ();
bp_pack_value (bp, ref->refered_type, 1);
bp_pack_value (bp, ref->use, 2);
lto_output_bitpack (ob->main_stream, bp);
bitpack_delete (bp);
if (ref->refered_type == IPA_REF_CGRAPH)
{
int nref = lto_cgraph_encoder_lookup (encoder, ipa_ref_node (ref));
gcc_assert (nref != LCC_NOT_FOUND);
lto_output_sleb128_stream (ob->main_stream, nref);
}
else
{
int nref = lto_varpool_encoder_lookup (varpool_encoder,
ipa_ref_varpool_node (ref));
gcc_assert (nref != LCC_NOT_FOUND);
lto_output_sleb128_stream (ob->main_stream, nref);
}
}
/* Stream out profile_summary to OB. */
static void
@ -534,6 +586,25 @@ add_node_to (lto_cgraph_encoder_t encoder, struct cgraph_node *node)
lto_cgraph_encoder_encode (encoder, node);
}
/* Add all references in LIST to encoders. */
static void
add_references (lto_cgraph_encoder_t encoder,
lto_varpool_encoder_t varpool_encoder,
struct ipa_ref_list *list)
{
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)
add_node_to (encoder, ipa_ref_node (ref));
else
{
struct varpool_node *vnode = ipa_ref_varpool_node (ref);
lto_varpool_encoder_encode (varpool_encoder, vnode);
}
}
/* Output all callees or indirect outgoing edges. EDGE must be the first such
edge. */
@ -553,6 +624,61 @@ output_outgoing_cgraph_edges (struct cgraph_edge *edge,
lto_output_edge (ob, edge, encoder);
}
/* Output the part of the cgraph in SET. */
static void
output_refs (cgraph_node_set set, varpool_node_set vset,
lto_cgraph_encoder_t encoder,
lto_varpool_encoder_t varpool_encoder)
{
cgraph_node_set_iterator csi;
varpool_node_set_iterator vsi;
struct lto_simple_output_block *ob;
int count;
struct ipa_ref *ref;
int i;
ob = lto_create_simple_output_block (LTO_section_refs);
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
struct cgraph_node *node = csi_node (csi);
count = ipa_ref_list_nreferences (&node->ref_list);
if (count)
{
lto_output_uleb128_stream (ob->main_stream, count);
lto_output_uleb128_stream (ob->main_stream,
lto_cgraph_encoder_lookup (encoder, node));
for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
lto_output_ref (ob, ref, encoder, varpool_encoder);
}
}
lto_output_uleb128_stream (ob->main_stream, 0);
for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
{
struct varpool_node *node = vsi_node (vsi);
count = ipa_ref_list_nreferences (&node->ref_list);
if (count)
{
lto_output_uleb128_stream (ob->main_stream, count);
lto_output_uleb128_stream (ob->main_stream,
lto_varpool_encoder_lookup (varpool_encoder,
node));
for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
lto_output_ref (ob, ref, encoder, varpool_encoder);
}
}
lto_output_uleb128_stream (ob->main_stream, 0);
lto_destroy_simple_output_block (ob);
}
/* Output the part of the cgraph in SET. */
void
@ -591,6 +717,7 @@ output_cgraph (cgraph_node_set set, varpool_node_set vset)
{
node = csi_node (csi);
add_node_to (encoder, node);
add_references (encoder, varpool_encoder, &node->ref_list);
}
for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
{
@ -598,9 +725,10 @@ output_cgraph (cgraph_node_set set, varpool_node_set vset)
gcc_assert (!vnode->alias);
lto_varpool_encoder_encode (varpool_encoder, vnode);
lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
add_references (encoder, varpool_encoder, &vnode->ref_list);
}
/* FIXME: We do not track references, so for now we need to include all possibly
used variables in the encoder set. */
/* FIXME: We can not currenlty remove any varpool nodes or we get ICE merging
binfos. */
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
if (vnode->needed)
lto_varpool_encoder_encode (varpool_encoder, vnode);
@ -617,6 +745,7 @@ output_cgraph (cgraph_node_set set, varpool_node_set vset)
|| TREE_READONLY (vnode->decl)))
{
lto_set_varpool_encoder_encode_initializer (varpool_encoder, vnode);
add_references (encoder, varpool_encoder, &vnode->ref_list);
}
}
@ -672,7 +801,8 @@ output_cgraph (cgraph_node_set set, varpool_node_set vset)
lto_output_uleb128_stream (ob->main_stream, 0);
lto_destroy_simple_output_block (ob);
output_varpool (vset);
output_varpool (set, vset);
output_refs (set, vset, encoder, varpool_encoder);
}
/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
@ -727,7 +857,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
/* Output the part of the cgraph in SET. */
static void
output_varpool (varpool_node_set vset)
output_varpool (cgraph_node_set set, varpool_node_set vset)
{
struct lto_simple_output_block *ob = lto_create_simple_output_block (LTO_section_varpool);
lto_varpool_encoder_t varpool_encoder = ob->decl_state->varpool_node_encoder;
@ -741,7 +871,7 @@ output_varpool (varpool_node_set vset)
for (i = 0; i < len; i++)
{
lto_output_varpool_node (ob, lto_varpool_encoder_deref (varpool_encoder, i),
vset);
set, vset);
}
lto_destroy_simple_output_block (ob);
@ -889,6 +1019,33 @@ input_varpool_node (struct lto_file_decl_data *file_data,
return node;
}
/* Read a node from input_block IB. TAG is the node's tag just read.
Return the node read or overwriten. */
static void
input_ref (struct lto_input_block *ib,
struct cgraph_node *refering_node,
struct varpool_node *refering_varpool_node,
VEC(cgraph_node_ptr, heap) *nodes,
VEC(varpool_node_ptr, heap) *varpool_nodes)
{
struct cgraph_node *node = NULL;
struct varpool_node *varpool_node = NULL;
struct bitpack_d *bp;
enum ipa_ref_type type;
enum ipa_ref_use use;
bp = lto_input_bitpack (ib);
type = (enum ipa_ref_type) bp_unpack_value (bp, 1);
use = (enum ipa_ref_use) bp_unpack_value (bp, 2);
bitpack_delete (bp);
if (type == IPA_REF_CGRAPH)
node = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
else
varpool_node = VEC_index (varpool_node_ptr, varpool_nodes, lto_input_sleb128 (ib));
ipa_record_reference (refering_node, refering_varpool_node,
node, varpool_node, use, NULL);
}
/* Read an edge from IB. NODES points to a vector of previously read nodes for
decoding caller and callee of the edge to be read. If INDIRECT is true, the
@ -1036,6 +1193,44 @@ input_varpool_1 (struct lto_file_decl_data *file_data,
return varpool;
}
/* Input ipa_refs. */
static void
input_refs (struct lto_input_block *ib,
VEC(cgraph_node_ptr, heap) *nodes,
VEC(varpool_node_ptr, heap) *varpool)
{
int count;
int idx;
while (true)
{
struct cgraph_node *node;
count = lto_input_uleb128 (ib);
if (!count)
break;
idx = lto_input_uleb128 (ib);
node = VEC_index (cgraph_node_ptr, nodes, idx);
while (count)
{
input_ref (ib, node, NULL, nodes, varpool);
count--;
}
}
while (true)
{
struct varpool_node *node;
count = lto_input_uleb128 (ib);
if (!count)
break;
node = VEC_index (varpool_node_ptr, varpool, lto_input_uleb128 (ib));
while (count)
{
input_ref (ib, NULL, node, nodes, varpool);
count--;
}
}
}
static struct gcov_ctr_summary lto_gcov_summary;
@ -1100,6 +1295,11 @@ input_cgraph (void)
lto_destroy_simple_input_block (file_data, LTO_section_varpool,
ib, data, len);
ib = lto_create_simple_input_block (file_data, LTO_section_refs,
&data, &len);
input_refs (ib, nodes, varpool);
lto_destroy_simple_input_block (file_data, LTO_section_refs,
ib, data, len);
VEC_free (cgraph_node_ptr, heap, nodes);
VEC_free (varpool_node_ptr, heap, varpool);
}

View File

@ -53,6 +53,7 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
"static_initializer",
"cgraph",
"varpool",
"refs",
"jump_funcs"
"ipa_pure_const",
"ipa_reference",

View File

@ -163,6 +163,9 @@ lto_get_section_name (int section_type, const char *name)
case LTO_section_varpool:
return concat (LTO_SECTION_NAME_PREFIX, ".vars", NULL);
case LTO_section_refs:
return concat (LTO_SECTION_NAME_PREFIX, ".refs", NULL);
case LTO_section_jump_functions:
return concat (LTO_SECTION_NAME_PREFIX, ".jmpfuncs", NULL);

View File

@ -257,6 +257,7 @@ enum lto_section_type
LTO_section_static_initializer,
LTO_section_cgraph,
LTO_section_varpool,
LTO_section_refs,
LTO_section_jump_functions,
LTO_section_ipa_pure_const,
LTO_section_ipa_reference,
@ -855,6 +856,9 @@ bool lto_varpool_encoder_encode_initializer_p (lto_varpool_encoder_t,
struct varpool_node *);
void output_cgraph (cgraph_node_set, varpool_node_set);
void input_cgraph (void);
bool referenced_from_other_partition_p (struct ipa_ref_list *,
cgraph_node_set,
varpool_node_set vset);
/* In lto-symtab.c. */

View File

@ -214,6 +214,8 @@ lto_cgraph_replace_node (struct cgraph_node *node,
next = e->next_caller;
cgraph_redirect_edge_callee (e, prevailing_node);
}
/* Redirect incomming references. */
ipa_clone_refering (prevailing_node, NULL, &node->ref_list);
if (node->same_body)
{
@ -273,6 +275,12 @@ lto_varpool_replace_node (struct varpool_node *vnode,
gcc_assert (!vnode->finalized || prevailing_node->finalized);
gcc_assert (!vnode->analyzed || prevailing_node->analyzed);
/* When replacing by an alias, the references goes to the original
variable. */
if (prevailing_node->alias && prevailing_node->extra_name)
prevailing_node = prevailing_node->extra_name;
ipa_clone_refering (NULL, prevailing_node, &vnode->ref_list);
/* Finally remove the replaced node. */
varpool_remove_node (vnode);
}

View File

@ -1,3 +1,7 @@
2010-05-05 Jan Hubicka <jh@suse.cz>
* lto.c (lto_promote_cross_file_statics): Compute boundary based on refs.
2010-05-05 Jan Hubicka <jh@suse.cz>
* lto.c (lto_1_to_1_map): Partition only needed nodes.

View File

@ -718,36 +718,30 @@ lto_promote_cross_file_statics (void)
struct varpool_node *vnode;
unsigned i, n_sets;
cgraph_node_set set;
varpool_node_set vset;
cgraph_node_set_iterator csi;
varpool_node_set_iterator vsi;
gcc_assert (flag_wpa);
/* At moment we make no attempt to figure out who is refering the variables,
so all must become global.
Constant pool references use internal labels and thus can not be made global.
It is sensible to keep those ltrans local to allow better optimization. */
for (vnode = varpool_nodes; vnode; vnode = vnode->next)
if (!vnode->externally_visible && vnode->analyzed
&& !DECL_IN_CONSTANT_POOL (vnode->decl))
{
TREE_PUBLIC (vnode->decl) = 1;
DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
}
n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets);
for (i = 0; i < n_sets; i++)
{
set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i);
vset = VEC_index (varpool_node_set, lto_varpool_node_sets, i);
/* If node has either address taken (and we have no clue from where)
or it is called from other partition, it needs to be globalized. */
for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
{
struct cgraph_node *node = csi_node (csi);
bool globalize = node->address_taken || node->local.vtable_method;
bool globalize = node->local.vtable_method;
struct cgraph_edge *e;
if (node->local.externally_visible)
continue;
if (!globalize
&& referenced_from_other_partition_p (&node->ref_list, set, vset))
globalize = true;
for (e = node->callers; e && !globalize; e = e->next_caller)
{
struct cgraph_node *caller = e->caller;
@ -758,6 +752,7 @@ lto_promote_cross_file_statics (void)
}
if (globalize)
{
gcc_assert (flag_wpa);
TREE_PUBLIC (node->decl) = 1;
DECL_VISIBILITY (node->decl) = VISIBILITY_HIDDEN;
if (node->same_body)
@ -772,6 +767,21 @@ lto_promote_cross_file_statics (void)
}
}
}
for (vsi = vsi_start (vset); !vsi_end_p (vsi); vsi_next (&vsi))
{
vnode = vsi_node (vsi);
/* Constant pool references use internal labels and thus can not
be made global. It is sensible to keep those ltrans local to
allow better optimization. */
if (!DECL_IN_CONSTANT_POOL (vnode->decl)
&& !vnode->externally_visible && vnode->analyzed
&& referenced_from_other_partition_p (&vnode->ref_list, set, vset))
{
gcc_assert (flag_wpa);
TREE_PUBLIC (vnode->decl) = 1;
DECL_VISIBILITY (vnode->decl) = VISIBILITY_HIDDEN;
}
}
}
}
@ -1457,7 +1467,7 @@ lto_fixup_tree (tree *tp, int *walk_subtrees, void *data)
t = *tp;
*walk_subtrees = 0;
if (pointer_set_contains (fixup_data->seen, t))
if (!t || pointer_set_contains (fixup_data->seen, t))
return NULL;
if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)

View File

@ -141,6 +141,7 @@ varpool_node (tree decl)
node->decl = decl;
node->order = cgraph_order++;
node->next = varpool_nodes;
ipa_empty_ref_list (&node->ref_list);
if (varpool_nodes)
varpool_nodes->prev = node;
varpool_nodes = node;
@ -193,6 +194,8 @@ varpool_remove_node (struct varpool_node *node)
gcc_assert (varpool_nodes_queue == node);
varpool_nodes_queue = node->next_needed;
}
ipa_remove_all_references (&node->ref_list);
ipa_remove_all_refering (&node->ref_list);
if (DECL_INITIAL (node->decl))
DECL_INITIAL (node->decl) = error_mark_node;
ggc_free (node);
@ -228,6 +231,10 @@ dump_varpool_node (FILE *f, struct varpool_node *node)
else if (node->used_from_other_partition)
fprintf (f, " used_from_other_partition");
fprintf (f, "\n");
fprintf (f, " References: ");
ipa_dump_references (f, &node->ref_list);
fprintf (f, " Refering this var: ");
ipa_dump_refering (f, &node->ref_list);
}
/* Dump the variable pool. */
@ -633,6 +640,7 @@ varpool_extra_name_alias (tree alias, tree decl)
alias_node->alias = 1;
alias_node->extra_name = decl_node;
alias_node->next = decl_node->extra_name;
ipa_empty_ref_list (&alias_node->ref_list);
if (decl_node->extra_name)
decl_node->extra_name->prev = alias_node;
decl_node->extra_name = alias_node;