expmed.c (expand_divmod): Undo sign extensions for unsigned operands
authorJan Hubicka <jh@suse.cz>
Sat, 22 Feb 2003 10:02:31 +0000 (11:02 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Sat, 22 Feb 2003 10:02:31 +0000 (10:02 +0000)
* 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

From-SVN: r63281

13 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-decl.c
gcc/c-objc-common.c
gcc/cfgcleanup.c
gcc/cgraph.c
gcc/cgraph.h [new file with mode: 0644]
gcc/cgraphunit.c [new file with mode: 0644]
gcc/config/i386/i386.md
gcc/expmed.c
gcc/toplev.c
gcc/tree-inline.c
gcc/tree.h

index f52abfad2cf724dbc4453a7386e6b8060b9ce615..59050a52dbd031f18d3cf6cf1b276d995031fbeb 100644 (file)
@@ -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
index e00b2883356e6cb49ab68d51404606615550bb50..271f3e040a7de9782752aa38e751ebbe0694d92c 100644 (file)
@@ -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
index a0c1d56c131b7c70fa0c133192fd3f7b01582dea..df3390c2121872e5d845a8a239e51a2fc4d0c1f5 100644 (file)
@@ -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
index a84ddc8fd70c9aa0f5614270e0fa37298f09d221..4ef748ca44ac4d5f3346eb4103e96d53ad06e857 100644 (file)
@@ -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 *));
index 3607fc3fcddd82b3fecc20aec3dfb8ec8dd30485..eaefdf2e381da13f70048e91eca6cbab3f771014 100644 (file)
@@ -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 ()))
index f1fffcac4215d0ee3ca592f128174e7dd8fac2c7..7df18f148911e5a3895645477f8c271800ee4179 100644 (file)
@@ -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 (file)
index 0000000..8dd37ed
--- /dev/null
@@ -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 (file)
index 0000000..0a12dda
--- /dev/null
@@ -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 ();
+}
index e6f1412ed188f97cd7eb1ba32efd3e46767b997e..09cd54ebb580293295f307d021eff82e2678dbda 100644 (file)
   "@
    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")])
 
   "@
    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")])
 
index 9fe87b68ffb370909149dba23c0ec8a7d5c0b014..33d815280bf0c3bf0d32ece6f972bffd26387859 100644 (file)
@@ -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))
                  {
index e55d26589831c7f87ff9ea8e359ab5bf7e16f1c4..acb98eec96b545899b9c40f45ec285c05e8359e0 100644 (file)
@@ -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)
index 19b7a4f8fc8d12e024932f7da714ab87f1fda787..71c4018d98f7455333412f764dbdbc4075f23249 100644 (file)
@@ -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.  */
index 6cdf2c8b01706191c12b7f3ba698ae1c69933c3f..de9668b391851c3119b1a688285f96551c1eba81 100644 (file)
@@ -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));
-
 \f
 /* Redefine abort to report an internal error w/o coredump, and
    reporting the location of the error in the source file.  This logic