diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-02-22 10:02:31 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-02-22 10:02:31 +0000 |
commit | ae01b312a9d64f7653dd7eb24ec60330d5942d87 (patch) | |
tree | 257ede1e5a0927db4b10d7b84ff244d229c10cd4 | |
parent | 98a0862274bfa202bdf32399af47737bd3e9a731 (diff) | |
download | gcc-ae01b312a9d64f7653dd7eb24ec60330d5942d87.tar.gz |
* expmed.c (expand_divmod): Undo sign extensions for unsigned operands
* cfgcleanup.c (try_forward_edges): Don't check loop structures
when not optimizing.
(cleanup_cfg): Do not iterate trought delete_trivially_dead_insns
when not expensive.
* toplev.c (rest_of_compilation): Duplicate loop headers only when
optimizing; Delete trivially dead insns early; fix optimize check.
* Makefile.in (c-decl.o, c-objc-common.o, cgraph.o, tree-inline.o): Add
dependency on cgraph.h
* c-decl.c: Include cgraph.h
(finish_function): Update call of tree_inlinable_function_p.
* c-objc-common.c: Include cgraph.h
* cgraph.h: New file.
* cgraphunit.c: New file.
* cgraph.c (cgraph_node, cgraph_edge): Move into cgraph.h
(cgraph_nodes, cgraph_n_nodes): Globalize.
(cgraph_finalize_function, cgraph_finalize_compilation_unit
cgraph_create_edges, cgraph_optimize, cgraph_mark_needed_node):
Move into cgraphunit.c
* tree-inline.c: Include cgraph.h
* tree-inline.c: Include cgraph.h
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@63281 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 26 | ||||
-rw-r--r-- | gcc/Makefile.in | 12 | ||||
-rw-r--r-- | gcc/c-decl.c | 1 | ||||
-rw-r--r-- | gcc/c-objc-common.c | 1 | ||||
-rw-r--r-- | gcc/cfgcleanup.c | 3 | ||||
-rw-r--r-- | gcc/cgraph.c | 377 | ||||
-rw-r--r-- | gcc/cgraph.h | 80 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 360 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 4 | ||||
-rw-r--r-- | gcc/expmed.c | 17 | ||||
-rw-r--r-- | gcc/toplev.c | 13 | ||||
-rw-r--r-- | gcc/tree-inline.c | 1 | ||||
-rw-r--r-- | gcc/tree.h | 10 |
13 files changed, 506 insertions, 399 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f52abfad2cf..59050a52dbd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +Sat Feb 22 03:13:36 CET 2003 Jan Hubicka <jh@suse.cz> + + * expmed.c (expand_divmod): Undo sign extensions for unsigned operands + + * cfgcleanup.c (try_forward_edges): Don't check loop structures + when not optimizing. + (cleanup_cfg): Do not iterate trought delete_trivially_dead_insns + when not expensive. + * toplev.c (rest_of_compilation): Duplicate loop headers only when + optimizing; Delete trivially dead insns early; fix optimize check. + + * Makefile.in (c-decl.o, c-objc-common.o, cgraph.o, tree-inline.o): Add + dependency on cgraph.h + * c-decl.c: Include cgraph.h + (finish_function): Update call of tree_inlinable_function_p. + * c-objc-common.c: Include cgraph.h + * cgraph.h: New file. + * cgraphunit.c: New file. + * cgraph.c (cgraph_node, cgraph_edge): Move into cgraph.h + (cgraph_nodes, cgraph_n_nodes): Globalize. + (cgraph_finalize_function, cgraph_finalize_compilation_unit + cgraph_create_edges, cgraph_optimize, cgraph_mark_needed_node): + Move into cgraphunit.c + * tree-inline.c: Include cgraph.h + * tree-inline.c: Include cgraph.h + 2003-02-22 Josef Zlomek <zlomekj@suse.cz> * config/i386/i386.md: Use gen_lowpart instead of gen_rtx_REG diff --git a/gcc/Makefile.in b/gcc/Makefile.in index e00b2883356..271f3e040a7 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -785,7 +785,7 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ sibcall.o simplify-rtx.o sreal.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \ stor-layout.o stringpool.o timevar.o toplev.o tracer.o tree.o tree-dump.o \ tree-inline.o unroll.o varasm.o varray.o version.o vmsdbgout.o xcoffout.o \ - alloc-pool.o et-forest.o cgraph.o \ + alloc-pool.o et-forest.o cgraph.o cgraphunit.o \ $(GGC) $(out_object_file) $(EXTRA_OBJS) $(host_hook_obj) BACKEND = main.o libbackend.a @@ -1221,7 +1221,7 @@ $(parsedir)/c-parse.y: c-parse.in c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \ $(C_TREE_H) $(GGC_H) $(TARGET_H) flags.h function.h output.h $(EXPR_H) \ debug.h toplev.h intl.h $(TM_P_H) tree-inline.h $(TIMEVAR_H) c-pragma.h \ - gt-c-decl.h + gt-c-decl.h cgraph.h c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \ $(TARGET_H) flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h $(TM_P_H) c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \ @@ -1233,7 +1233,7 @@ c-lex.o : c-lex.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) c-objc-common.o : c-objc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) $(RTL_H) insn-config.h integrate.h $(EXPR_H) $(C_TREE_H) \ flags.h toplev.h tree-inline.h diagnostic.h integrate.h $(VARRAY_H) \ - langhooks.h $(GGC_H) gt-c-objc-common.h $(TARGET_H) + langhooks.h $(GGC_H) gt-c-objc-common.h $(TARGET_H) cgraph.h c-aux-info.o : c-aux-info.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(C_TREE_H) flags.h toplev.h c-convert.o : c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ @@ -1413,7 +1413,7 @@ tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) expr.h flags.h params.h input.h insn-config.h $(INTEGRATE_H) \ $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h langhooks.h \ - $(C_COMMON_H) tree-inline.h + $(C_COMMON_H) tree-inline.h cgraph.h print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(GGC_H) langhooks.h real.h stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ @@ -1532,7 +1532,9 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RT $(REGS_H) hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ output.h function.h $(GGC_H) $(OBSTACK_H) $(TM_P_H) $(TREE_H) $(TARGET_H) cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - langhooks.h tree-inline.h toplev.h flags.h ggc.h $(TARGET_H) + langhooks.h tree-inline.h toplev.h flags.h ggc.h $(TARGET_H) cgraph.h +cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + langhooks.h tree-inline.h toplev.h flags.h ggc.h $(TARGET_H) cgraph.h cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \ hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ output.h function.h cselib.h $(GGC_H) $(TM_P_H) gt-cselib.h diff --git a/gcc/c-decl.c b/gcc/c-decl.c index a0c1d56c131..df3390c2121 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -48,6 +48,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "timevar.h" #include "c-common.h" #include "c-pragma.h" +#include "cgraph.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context diff --git a/gcc/c-objc-common.c b/gcc/c-objc-common.c index a84ddc8fd70..4ef748ca44a 100644 --- a/gcc/c-objc-common.c +++ b/gcc/c-objc-common.c @@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ggc.h" #include "langhooks.h" #include "target.h" +#include "cgraph.h" static bool c_tree_printer PARAMS ((output_buffer *, text_info *)); static tree inline_forbidden_p PARAMS ((tree *, int *, void *)); diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 3607fc3fcdd..eaefdf2e381 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -502,7 +502,7 @@ try_forward_edges (mode, b) For fallthru forwarders, the LOOP_BEG note must appear between the header of block and CODE_LABEL of the loop, for non forwarders it must appear before the JUMP_INSN. */ - if (mode & CLEANUP_PRE_LOOP) + if ((mode & CLEANUP_PRE_LOOP) && optimize) { rtx insn = (target->succ->flags & EDGE_FALLTHRU ? target->head : prev_nonnote_insn (target->end)); @@ -1795,6 +1795,7 @@ cleanup_cfg (mode) break; } else if (!(mode & (CLEANUP_NO_INSN_DEL | CLEANUP_PRE_SIBCALL)) + && (mode & CLEANUP_EXPENSIVE) && !reload_completed) { if (!delete_trivially_dead_insns (get_insns(), max_reg_num ())) diff --git a/gcc/cgraph.c b/gcc/cgraph.c index f1fffcac421..7df18f14891 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -32,67 +32,22 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "ggc.h" #include "debug.h" #include "target.h" - -/* The cgraph data strutcture. - Each function decl has assigned cgraph_node listing calees and callers. */ - -struct cgraph_node -{ - tree decl; - struct cgraph_edge *callees; - struct cgraph_edge *callers; - struct cgraph_node *next; - /* 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 *nested; - /* Pointer to the next function with same origin, if any. */ - struct cgraph_node *next_nested; - void *aux; - - /* Set when function must be output - it is externally visible - or it's address is taken. */ - bool needed; - /* Set when function is reachable by call from other function - that is eighter reachable or needed. */ - bool reachable; - /* Set when the frontend has been asked to lower representation of this - function into trees. Callees lists are not available when lowered - is not set. */ - bool lowered; - /* Set when function is scheduled to be assembled. */ - bool output; -}; - -struct cgraph_edge -{ - struct cgraph_node *caller, *callee; - struct cgraph_edge *next_caller; - struct cgraph_edge *next_callee; -}; +#include "cgraph.h" /* Hash table used to convert declarations into nodes. */ static htab_t cgraph_hash = 0; /* The linked list of cgraph nodes. */ -static struct cgraph_node *cgraph_nodes; +struct cgraph_node *cgraph_nodes; /* Number of nodes in existence. */ -static int cgraph_n_nodes; +int cgraph_n_nodes; -static struct cgraph_node *cgraph_node PARAMS ((tree decl)); static struct cgraph_edge *create_edge PARAMS ((struct cgraph_node *, struct cgraph_node *)); static void remove_edge PARAMS ((struct cgraph_node *, struct cgraph_node *)); -static struct cgraph_edge *record_call PARAMS ((tree, tree)); -static tree record_call_1 PARAMS ((tree *, int *, void *)); static hashval_t hash_node PARAMS ((const PTR)); static int eq_node PARAMS ((const PTR, const PTR)); -static struct cgraph_node *cgraph_node PARAMS ((tree)); -static void cgraph_expand_functions PARAMS ((void)); -static void cgraph_mark_functions_to_output PARAMS ((void)); -static void cgraph_expand_function PARAMS ((struct cgraph_node *)); -static void cgraph_mark_needed_node PARAMS ((struct cgraph_node *, int)); /* Returns a hash code for P. */ @@ -117,7 +72,7 @@ eq_node (p1, p2) } /* Return cgraph node assigned to DECL. Create new one when needed. */ -static struct cgraph_node * +struct cgraph_node * cgraph_node (decl) tree decl; { @@ -190,8 +145,8 @@ remove_edge (caller, callee) /* Record call from CALLER to CALLEE */ -static struct cgraph_edge * -record_call (caller, callee) +struct cgraph_edge * +cgraph_record_call (caller, callee) tree caller, callee; { return create_edge (cgraph_node (caller), cgraph_node (callee)); @@ -220,66 +175,6 @@ cgraph_calls_p (caller_decl, callee_decl) return edge != NULL; } -/* Walk tree and record all calls. Called via walk_tree. */ -static tree -record_call_1 (tp, walk_subtrees, data) - tree *tp; - int *walk_subtrees; - void *data; -{ - /* Record dereferences to the functions. This makes the functions - reachable unconditionally. */ - if (TREE_CODE (*tp) == ADDR_EXPR) - { - tree decl = TREE_OPERAND (*tp, 0); - if (TREE_CODE (decl) == FUNCTION_DECL) - cgraph_mark_needed_node (cgraph_node (decl), 1); - } - else if (TREE_CODE (*tp) == CALL_EXPR) - { - tree decl = TREE_OPERAND (*tp, 0); - if (TREE_CODE (decl) == ADDR_EXPR) - decl = TREE_OPERAND (decl, 0); - if (TREE_CODE (decl) == FUNCTION_DECL) - { - if (DECL_BUILT_IN (decl)) - return NULL; - record_call (data, decl); - walk_tree (&TREE_OPERAND (*tp, 1), record_call_1, data, NULL); - *walk_subtrees = 0; - } - } - return NULL; -} - -/* Create cgraph edges for function calles via BODY. */ - -void -cgraph_create_edges (decl, body) - tree decl; - tree body; -{ - walk_tree (&body, record_call_1, decl, NULL); -} - -/* Analyze function once it is parsed. Set up the local information - available - create cgraph edges for function calles via BODY. */ - -void -cgraph_finalize_function (decl, body) - tree decl; - tree body ATTRIBUTE_UNUSED; -{ - struct cgraph_node *node = cgraph_node (decl); - - node->decl = decl; - - /* Set TREE_UNINLINABLE flag. */ - tree_inlinable_function_p (decl); - - (*debug_hooks->deferred_inline_function) (decl); -} - /* Dump the callgraph. */ void @@ -315,263 +210,3 @@ dump_cgraph (f) fprintf (f, "\n"); } } - -static struct cgraph_node *queue = NULL; - -/* Notify finalize_compilation_unit that given node is reachable - or needed. */ -static void -cgraph_mark_needed_node (node, needed) - struct cgraph_node *node; - int needed; -{ - if (needed) - { - if (DECL_SAVED_TREE (node->decl)) - announce_function (node->decl); - node->needed = 1; - } - if (!node->reachable) - { - node->reachable = 1; - if (DECL_SAVED_TREE (node->decl)) - { - node->aux = queue; - queue = node; - } - } -} - -/* Analyze the whole compilation unit once it is parsed completely. */ - -void -cgraph_finalize_compilation_unit () -{ - struct cgraph_node *node; - struct cgraph_edge *edge; - - /* Collect entry points to the unit. */ - - if (!quiet_flag) - fprintf (stderr, "\n\nUnit entry points:"); - - for (node = cgraph_nodes; node; node = node->next) - { - tree decl = node->decl; - - if (!DECL_SAVED_TREE (decl)) - continue; - if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) - || (DECL_ASSEMBLER_NAME_SET_P (decl) - && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) - { - cgraph_mark_needed_node (node, 1); - } - } - - /* Propagate reachability flag and lower representation of all reachable - functions. In the future, lowering will introduce new functions and - new entry points on the way (by template instantiation and virtual - method table generation for instance). */ - while (queue) - { - tree decl = queue->decl; - - node = queue; - queue = queue->aux; - if (node->lowered || !node->reachable || !DECL_SAVED_TREE (decl)) - abort (); - - /* At the moment frontend automatically emits all nested functions. */ - if (node->nested) - { - struct cgraph_node *node2; - - for (node2 = node->nested; node2; node2 = node2->next_nested) - if (!node2->reachable) - cgraph_mark_needed_node (node2, 0); - } - - if (lang_hooks.callgraph.lower_function) - (*lang_hooks.callgraph.lower_function) (decl); - /* First kill forward declaration so reverse inling works properly. */ - cgraph_create_edges (decl, DECL_SAVED_TREE (decl)); - - for (edge = node->callees; edge; edge = edge->next_callee) - { - if (!edge->callee->reachable) - cgraph_mark_needed_node (edge->callee, 0); - } - node->lowered = true; - } - if (!quiet_flag) - fprintf (stderr, "\n\nReclaiming functions:"); - - for (node = cgraph_nodes; node; node = node->next) - { - tree decl = node->decl; - - if (!node->reachable && DECL_SAVED_TREE (decl)) - { - DECL_SAVED_TREE (decl) = NULL; - announce_function (decl); - } - } - ggc_collect (); -} - -/* Figure out what functions we want to assemble. */ - -static void -cgraph_mark_functions_to_output () -{ - struct cgraph_node *node; - - /* Figure out functions we want to assemble. */ - for (node = cgraph_nodes; node; node = node->next) - { - tree decl = node->decl; - - if (DECL_SAVED_TREE (decl) - && (node->needed - || (DECL_UNINLINABLE (decl) && node->reachable) - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) - && !TREE_ASM_WRITTEN (decl) && !node->origin - && !DECL_EXTERNAL (decl)) - node->output = 1; - } -} - -/* Expand function specified by NODE. */ -static void -cgraph_expand_function (node) - struct cgraph_node *node; -{ - tree decl = node->decl; - - announce_function (decl); - if (flag_inline_trees) - optimize_inline_calls (decl); - (*lang_hooks.callgraph.expand_function) (decl); - if (DECL_UNINLINABLE (decl)) - DECL_SAVED_TREE (decl) = NULL; - current_function_decl = NULL; -} - - -/* Expand all functions that must be output. - - Attempt to topologically sort the nodes so function is output when - all called functions are already assembled to allow data to be propagated - accross the callgraph. Use stack to get smaller distance between function - and it's callees (later we may use more sophisticated algorithm for - function reordering, we will likely want to use subsections to make output - functions to appear in top-down order, not bottom-up they are assembled). */ - -static void -cgraph_expand_functions () -{ - struct cgraph_node *node, *node2; - struct cgraph_node **stack = - xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes); - struct cgraph_node **order = - xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes); - int stack_size = 0; - int order_pos = 0; - struct cgraph_edge *edge, last; - int i; - - cgraph_mark_functions_to_output (); - - /* We have to deal with cycles nicely, so use depth first traversal - algorithm. Ignore the fact that some functions won't need to be output - and put them into order as well, so we get dependencies right trought inlined - functions. */ - for (node = cgraph_nodes; node; node = node->next) - node->aux = NULL; - for (node = cgraph_nodes; node; node = node->next) - if (node->output && !node->aux) - { - node2 = node; - if (!node->callers) - node->aux = &last; - else - node->aux = node->callers; - while (node2) - { - while (node2->aux != &last) - { - edge = node2->aux; - if (edge->next_caller) - node2->aux = edge->next_caller; - else - node2->aux = &last; - if (!edge->caller->aux) - { - if (!edge->caller->callers) - edge->caller->aux = &last; - else - edge->caller->aux = edge->caller->callers; - stack[stack_size++] = node2; - node2 = edge->caller; - break; - } - } - if (node2->aux == &last) - { - order[order_pos++] = node2; - if (stack_size) - node2 = stack[--stack_size]; - else - node2 = NULL; - } - } - } - for (i = order_pos - 1; i >=0; i--) - { - node = order[i]; - if (node->output) - { - if (!node->reachable) - abort (); - node->output = 0; - cgraph_expand_function (node); - } - } - free (stack); - free (order); -} - -/* Perform simple optimizations based on callgraph. */ - -void -cgraph_optimize () -{ - struct cgraph_node *node; - bool changed = true; - struct cgraph_edge *edge; - - if (!quiet_flag) - fprintf (stderr, "\n\nAssembling functions:"); - - /* Output everything. - ??? Our inline heuristic may decide to not inline functions previously - marked as inlinable thus adding new function bodies that must be output. - Later we should move all inlining decisions to callgraph code to make - this impossible. */ - cgraph_expand_functions (); - while (changed) - { - changed = false; - for (node = cgraph_nodes; node; node = node->next) - { - if (!node->needed) - continue; - - for (edge = node->callees; edge; edge = edge->next_callee) - if (!edge->callee->needed) - changed = edge->callee->needed = true; - } - } - cgraph_expand_functions (); -} diff --git a/gcc/cgraph.h b/gcc/cgraph.h new file mode 100644 index 00000000000..8dd37ed9e32 --- /dev/null +++ b/gcc/cgraph.h @@ -0,0 +1,80 @@ +/* Callgraph handling code. + Copyright (C) 2003 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 2, 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 COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef GCC_CGRAPH_H +#define GCC_CGRAPH_H + +/* The cgraph data strutcture. + Each function decl has assigned cgraph_node listing calees and callers. */ + +struct cgraph_node +{ + tree decl; + struct cgraph_edge *callees; + struct cgraph_edge *callers; + struct cgraph_node *next; + /* 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 *nested; + /* Pointer to the next function with same origin, if any. */ + struct cgraph_node *next_nested; + void *aux; + + /* Set when function must be output - it is externally visible + or it's address is taken. */ + bool needed; + /* Set when function is reachable by call from other function + that is eighter reachable or needed. */ + bool reachable; + /* Set when the frontend has been asked to lower representation of this + function into trees. Callees lists are not available when lowered + is not set. */ + bool lowered; + /* Set when function is scheduled to be assembled. */ + bool output; +}; + +struct cgraph_edge +{ + struct cgraph_node *caller, *callee; + struct cgraph_edge *next_caller; + struct cgraph_edge *next_callee; +}; + +extern struct cgraph_node *cgraph_nodes; +extern int cgraph_n_nodes; + +/* In cgraph.c */ +void dump_cgraph PARAMS ((FILE *)); +void cgraph_remove_call PARAMS ((tree, tree)); +struct cgraph_edge *cgraph_record_call PARAMS ((tree, tree)); +struct cgraph_node *cgraph_node PARAMS ((tree decl)); +bool cgraph_calls_p PARAMS ((tree, tree)); + +/* In cgraphunit.c */ +void cgraph_finalize_function PARAMS ((tree, tree)); +void cgraph_finalize_compilation_unit PARAMS ((void)); +void cgraph_create_edges PARAMS ((tree, tree)); +void cgraph_optimize PARAMS ((void)); +void cgraph_mark_needed_node PARAMS ((struct cgraph_node *, int)); + +#endif /* GCC_CGRAPH_H */ diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c new file mode 100644 index 00000000000..0a12ddad856 --- /dev/null +++ b/gcc/cgraphunit.c @@ -0,0 +1,360 @@ +/* Callgraph handling code. + Copyright (C) 2003 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 2, 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 COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "tree-inline.h" +#include "langhooks.h" +#include "hashtab.h" +#include "toplev.h" +#include "flags.h" +#include "ggc.h" +#include "debug.h" +#include "target.h" +#include "cgraph.h" + +static void cgraph_expand_functions PARAMS ((void)); +static void cgraph_mark_functions_to_output PARAMS ((void)); +static void cgraph_expand_function PARAMS ((struct cgraph_node *)); +static tree record_call_1 PARAMS ((tree *, int *, void *)); + +/* Analyze function once it is parsed. Set up the local information + available - create cgraph edges for function calles via BODY. */ + +void +cgraph_finalize_function (decl, body) + tree decl; + tree body ATTRIBUTE_UNUSED; +{ + struct cgraph_node *node = cgraph_node (decl); + + node->decl = decl; + + /* Set TREE_UNINLINABLE flag. */ + tree_inlinable_function_p (decl); + + (*debug_hooks->deferred_inline_function) (decl); +} + +static struct cgraph_node *queue = NULL; + +/* Notify finalize_compilation_unit that given node is reachable + or needed. */ +void +cgraph_mark_needed_node (node, needed) + struct cgraph_node *node; + int needed; +{ + if (needed) + { + if (DECL_SAVED_TREE (node->decl)) + announce_function (node->decl); + node->needed = 1; + } + if (!node->reachable) + { + node->reachable = 1; + if (DECL_SAVED_TREE (node->decl)) + { + node->aux = queue; + queue = node; + } + } +} + +/* Walk tree and record all calls. Called via walk_tree. */ +static tree +record_call_1 (tp, walk_subtrees, data) + tree *tp; + int *walk_subtrees; + void *data; +{ + /* Record dereferences to the functions. This makes the functions + reachable unconditionally. */ + if (TREE_CODE (*tp) == ADDR_EXPR) + { + tree decl = TREE_OPERAND (*tp, 0); + if (TREE_CODE (decl) == FUNCTION_DECL) + cgraph_mark_needed_node (cgraph_node (decl), 1); + } + else if (TREE_CODE (*tp) == CALL_EXPR) + { + tree decl = TREE_OPERAND (*tp, 0); + if (TREE_CODE (decl) == ADDR_EXPR) + decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (DECL_BUILT_IN (decl)) + return NULL; + cgraph_record_call (data, decl); + walk_tree (&TREE_OPERAND (*tp, 1), record_call_1, data, NULL); + *walk_subtrees = 0; + } + } + return NULL; +} + +/* Create cgraph edges for function calles via BODY. */ + +void +cgraph_create_edges (decl, body) + tree decl; + tree body; +{ + walk_tree (&body, record_call_1, decl, NULL); +} + +/* Analyze the whole compilation unit once it is parsed completely. */ + +void +cgraph_finalize_compilation_unit () +{ + struct cgraph_node *node; + struct cgraph_edge *edge; + + /* Collect entry points to the unit. */ + + if (!quiet_flag) + fprintf (stderr, "\n\nUnit entry points:"); + + for (node = cgraph_nodes; node; node = node->next) + { + tree decl = node->decl; + + if (!DECL_SAVED_TREE (decl)) + continue; + if ((TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) + || (DECL_ASSEMBLER_NAME_SET_P (decl) + && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) + { + cgraph_mark_needed_node (node, 1); + } + } + + /* Propagate reachability flag and lower representation of all reachable + functions. In the future, lowering will introduce new functions and + new entry points on the way (by template instantiation and virtual + method table generation for instance). */ + while (queue) + { + tree decl = queue->decl; + + node = queue; + queue = queue->aux; + if (node->lowered || !node->reachable || !DECL_SAVED_TREE (decl)) + abort (); + + /* At the moment frontend automatically emits all nested functions. */ + if (node->nested) + { + struct cgraph_node *node2; + + for (node2 = node->nested; node2; node2 = node2->next_nested) + if (!node2->reachable) + cgraph_mark_needed_node (node2, 0); + } + + if (lang_hooks.callgraph.lower_function) + (*lang_hooks.callgraph.lower_function) (decl); + /* First kill forward declaration so reverse inling works properly. */ + cgraph_create_edges (decl, DECL_SAVED_TREE (decl)); + + for (edge = node->callees; edge; edge = edge->next_callee) + { + if (!edge->callee->reachable) + cgraph_mark_needed_node (edge->callee, 0); + } + node->lowered = true; + } + if (!quiet_flag) + fprintf (stderr, "\n\nReclaiming functions:"); + + for (node = cgraph_nodes; node; node = node->next) + { + tree decl = node->decl; + + if (!node->reachable && DECL_SAVED_TREE (decl)) + { + DECL_SAVED_TREE (decl) = NULL; + announce_function (decl); + } + } + ggc_collect (); +} + +/* Figure out what functions we want to assemble. */ + +static void +cgraph_mark_functions_to_output () +{ + struct cgraph_node *node; + + /* Figure out functions we want to assemble. */ + for (node = cgraph_nodes; node; node = node->next) + { + tree decl = node->decl; + + if (DECL_SAVED_TREE (decl) + && (node->needed + || (DECL_UNINLINABLE (decl) && node->reachable) + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + && !TREE_ASM_WRITTEN (decl) && !node->origin + && !DECL_EXTERNAL (decl)) + node->output = 1; + } +} + +/* Expand function specified by NODE. */ +static void +cgraph_expand_function (node) + struct cgraph_node *node; +{ + tree decl = node->decl; + + announce_function (decl); + if (flag_inline_trees) + optimize_inline_calls (decl); + (*lang_hooks.callgraph.expand_function) (decl); + if (DECL_UNINLINABLE (decl)) + DECL_SAVED_TREE (decl) = NULL; + current_function_decl = NULL; +} + + +/* Expand all functions that must be output. + + Attempt to topologically sort the nodes so function is output when + all called functions are already assembled to allow data to be propagated + accross the callgraph. Use stack to get smaller distance between function + and it's callees (later we may use more sophisticated algorithm for + function reordering, we will likely want to use subsections to make output + functions to appear in top-down order, not bottom-up they are assembled). */ + +static void +cgraph_expand_functions () +{ + struct cgraph_node *node, *node2; + struct cgraph_node **stack = + xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes); + struct cgraph_node **order = + xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes); + int stack_size = 0; + int order_pos = 0; + struct cgraph_edge *edge, last; + int i; + + cgraph_mark_functions_to_output (); + + /* We have to deal with cycles nicely, so use depth first traversal + algorithm. Ignore the fact that some functions won't need to be output + and put them into order as well, so we get dependencies right trought inlined + functions. */ + for (node = cgraph_nodes; node; node = node->next) + node->aux = NULL; + for (node = cgraph_nodes; node; node = node->next) + if (node->output && !node->aux) + { + node2 = node; + if (!node->callers) + node->aux = &last; + else + node->aux = node->callers; + while (node2) + { + while (node2->aux != &last) + { + edge = node2->aux; + if (edge->next_caller) + node2->aux = edge->next_caller; + else + node2->aux = &last; + if (!edge->caller->aux) + { + if (!edge->caller->callers) + edge->caller->aux = &last; + else + edge->caller->aux = edge->caller->callers; + stack[stack_size++] = node2; + node2 = edge->caller; + break; + } + } + if (node2->aux == &last) + { + order[order_pos++] = node2; + if (stack_size) + node2 = stack[--stack_size]; + else + node2 = NULL; + } + } + } + for (i = order_pos - 1; i >=0; i--) + { + node = order[i]; + if (node->output) + { + if (!node->reachable) + abort (); + node->output = 0; + cgraph_expand_function (node); + } + } + free (stack); + free (order); +} + +/* Perform simple optimizations based on callgraph. */ + +void +cgraph_optimize () +{ + struct cgraph_node *node; + bool changed = true; + struct cgraph_edge *edge; + + if (!quiet_flag) + fprintf (stderr, "\n\nAssembling functions:"); + + /* Output everything. + ??? Our inline heuristic may decide to not inline functions previously + marked as inlinable thus adding new function bodies that must be output. + Later we should move all inlining decisions to callgraph code to make + this impossible. */ + cgraph_expand_functions (); + while (changed) + { + changed = false; + for (node = cgraph_nodes; node; node = node->next) + { + if (!node->needed) + continue; + + for (edge = node->callees; edge; edge = edge->next_callee) + if (!edge->callee->needed) + changed = edge->callee->needed = true; + } + } + cgraph_expand_functions (); +} diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index e6f1412ed18..09cd54ebb58 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -22864,7 +22864,7 @@ "@ movq\t{%1, %0|%0, %1} movdq2q\t{%1, %0|%0, %1} - movq\t{%1, %0|%0, %1}" + movd\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt") (set_attr "mode" "TI")]) @@ -22887,7 +22887,7 @@ "@ movq\t{%1, %0|%0, %1} movq2dq\t{%1, %0|%0, %1} - movq\t{%1, %0|%0, %1}" + movd\t{%1, %0|%0, %1}" [(set_attr "type" "ssecvt,ssemov,ssecvt") (set_attr "mode" "TI")]) diff --git a/gcc/expmed.c b/gcc/expmed.c index 9fe87b68ffb..33d815280bf 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -2955,14 +2955,20 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) int size; rtx insn, set; optab optab1, optab2; - int op1_is_constant, op1_is_pow2; + int op1_is_constant, op1_is_pow2 = 0; int max_cost, extra_cost; static HOST_WIDE_INT last_div_const = 0; + static HOST_WIDE_INT ext_op1; op1_is_constant = GET_CODE (op1) == CONST_INT; - op1_is_pow2 = (op1_is_constant - && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)) - || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))); + if (op1_is_constant) + { + ext_op1 = INTVAL (op1); + if (unsignedp) + ext_op1 &= GET_MODE_MASK (mode); + op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1) + || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1)))); + } /* This is the structure of expand_divmod: @@ -3142,7 +3148,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) unsigned HOST_WIDE_INT mh, ml; int pre_shift, post_shift; int dummy; - unsigned HOST_WIDE_INT d = INTVAL (op1); + unsigned HOST_WIDE_INT d = (INTVAL (op1) + & GET_MODE_MASK (compute_mode)); if (EXACT_POWER_OF_2_OR_ZERO_P (d)) { diff --git a/gcc/toplev.c b/gcc/toplev.c index e55d2658983..acb98eec96b 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -2697,16 +2697,19 @@ rest_of_compilation (decl) reg_scan (insns, max_reg_num (), 0); rebuild_jump_labels (insns); find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + delete_trivially_dead_insns (insns, max_reg_num ()); if (rtl_dump_file) dump_flow_info (rtl_dump_file); cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP | (flag_thread_jumps ? CLEANUP_THREADING : 0)); - /* CFG is no longer maintained up-to-date. */ - free_bb_for_insn (); - copy_loop_headers (insns); + if (optimize) + { + free_bb_for_insn (); + copy_loop_headers (insns); + find_basic_blocks (insns, max_reg_num (), rtl_dump_file); + } purge_line_number_notes (insns); - find_basic_blocks (insns, max_reg_num (), rtl_dump_file); timevar_pop (TV_JUMP); close_dump_file (DFI_jump, print_rtl, insns); @@ -3052,7 +3055,7 @@ rest_of_compilation (decl) close_dump_file (DFI_bp, print_rtl_with_bb, insns); timevar_pop (TV_BRANCH_PROB); } - if (optimize >= 0) + if (optimize > 0) { open_dump_file (DFI_ce1, decl); if (flag_if_conversion) diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 19b7a4f8fc8..71c4018d98f 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA. */ #include "hashtab.h" #include "splay-tree.h" #include "langhooks.h" +#include "cgraph.h" /* This should be eventually be generalized to other languages, but this would require a shared function-as-trees infrastructure. */ diff --git a/gcc/tree.h b/gcc/tree.h index 6cdf2c8b017..de9668b3918 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3157,16 +3157,6 @@ extern const char *dump_flag_name PARAMS ((enum tree_dump_index)); /* Assign the RTX to declaration. */ extern void set_decl_rtl PARAMS ((tree, rtx)); - -/* In callgraph.c */ -void cgraph_finalize_function PARAMS ((tree, tree)); -void cgraph_finalize_compilation_unit PARAMS ((void)); -void cgraph_create_edges PARAMS ((tree, tree)); -void dump_cgraph PARAMS ((FILE *)); -void cgraph_optimize PARAMS ((void)); -void cgraph_remove_call PARAMS ((tree, tree)); -bool cgraph_calls_p PARAMS ((tree, tree)); - /* Redefine abort to report an internal error w/o coredump, and reporting the location of the error in the source file. This logic |