This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tree-ssa, will commit] Sanity checking of callgraph


Hi,
this patch adds somewhat extensive sanity checking into cgraph code.  It verify
that cgraph nodes match the underlying code and also verify that memory
management properly release all function bodies before end of compilation.
Little is done for sanity checking of callgraph itself as all except for
trivial invariants depend on particular stage of compilation and thus they
are somewhat impractical to sanity check.

The patch also fixes some of more minnor problems checking code noticed.  Not
all functions were relased from memory; we somtimes end up marking inline
functions having no bodies in presence of renaming; we counted nnumber of nodes
incorrectly and such.

The inlining mess fixed yesterday and some of earlier patches has been also
noticed by these checks.

There are still some major problems accepted by this code.  In particular
fortran fromtend is bypassing cgraph code completely that is really not
supposed to work at all now.  The dumping code requires function bodies to not
be cleared that in turn causes a lot of sanity checks to be disabled when
dumping file that ineed may be confusing.  Finally objc frontend is also
bypassing in some special cases I wouls like to avoid too.

The verify_cgraph call is pretty expensive as it involves walking of all
functions bodies not output yet.  It adds 4 seconds out of 3 minute compilation
of GCC components.  I may consider removing some of verify_cgraph calls later
but I would like to check it for a while so we know that everything is working
correctly; I will also add separate timevar variables for each verifier by
separate patch so we keep checking code under controll.

Bootstrapped/regtested i686-pc-gnu-linux.  I plan commit this at evening.

Honza 

2003-12-13  Jan Hubicka  <jh@suse.cz>
	* cgraph.c (cgraph_create_edge): Sanity check for duplicates;
	initialize aux.
	(cgraph_remove_node): Decrease cgraph_n_nodes; do not clear
	DECL_SAVED_TREE when dumping.
	(cgraph_dump_node): Break out from ...; print more information.
	(cgraph_dump): ... here.
	* cgraph.h (cgraph_node): Add aux field.
	(dump_cgraph_node, verify_cgraph, verify_cgraph_node): Declare.
	(cgraph_mark_inline_edge): Declare
	* cgraphunit.c (error_found): New static variable.
	(verify_cgraph_node_1): New static function.
	(verify_cgraph_node, verify_cgraph): New global function.
	(cgraph_expand_function): More sanity checks.
	(cgraph_clone_inline_nodes): Destructivly clone DECL_EXTERNAL nodes.
	(cgraph_mark_inline_edge): Make global.
	(cgraph_decide_inlining): Remove extern inline functions never inlined.
	(cgraph_decide_inlining_incrementally): Verify that function body is
	still present.
	(expand_all_functions): Verify that all nodes are reachable.
	(cgraph_optimize): Verify cgraph and memory management.
	* tree-inline.c (copy_body_r): All edges must be present.
	(expand_call_inline): Sanity check newly created edges and nodes
	being inlined.
	(optimize_inline_calls): Sanity check that we've inlined everything.
	* tree-optimize.c (tree_rest_of_compilation): Clone functions inlined
	into cloned node.
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.4.4.12
diff -c -3 -p -r1.4.4.12 cgraph.c
*** cgraph.c	10 Dec 2003 23:22:23 -0000	1.4.4.12
--- cgraph.c	13 Dec 2003 13:46:33 -0000
*************** cgraph_create_edge (struct cgraph_node *
*** 184,194 ****
--- 184,202 ----
  		    tree call_expr)
  {
    struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
+ #ifdef ENABLE_CHECKING
+   struct cgraph_edge *e;
+ 
+   for (e = caller->callees; e; e = e->next_callee)
+     if (e->call_expr == call_expr)
+       abort ();
+ #endif
  
    if (TREE_CODE (call_expr) != CALL_EXPR)
      abort ();
  
    edge->inline_call = false;
+   edge->aux = NULL;
  
    edge->caller = caller;
    edge->callee = callee;
*************** cgraph_remove_node (struct cgraph_node *
*** 279,285 ****
        else
  	{
            htab_clear_slot (cgraph_hash, slot);
!           DECL_SAVED_TREE (node->decl) = NULL;
  	  check_dead = false;
  	}
      }
--- 287,294 ----
        else
  	{
            htab_clear_slot (cgraph_hash, slot);
! 	  if (!dump_enabled_p (TDI_all))
!             DECL_SAVED_TREE (node->decl) = NULL;
  	  check_dead = false;
  	}
      }
*************** cgraph_remove_node (struct cgraph_node *
*** 302,310 ****
  	if (n->global.inlined_to
  	    || (!n->global.inlined_to && !TREE_ASM_WRITTEN (n->decl)))
  	  break;
!       if (!n)
          DECL_SAVED_TREE (node->decl) = NULL;
      }
    /* Do not free the structure itself so the walk over chain can continue.  */
  }
  
--- 311,320 ----
  	if (n->global.inlined_to
  	    || (!n->global.inlined_to && !TREE_ASM_WRITTEN (n->decl)))
  	  break;
!       if (!n && !dump_enabled_p (TDI_all))
          DECL_SAVED_TREE (node->decl) = NULL;
      }
+   cgraph_n_nodes--;
    /* Do not free the structure itself so the walk over chain can continue.  */
  }
  
*************** cgraph_node_name (struct cgraph_node *no
*** 404,409 ****
--- 414,473 ----
    return (*lang_hooks.decl_printable_name) (node->decl, 2);
  }
  
+ /* Dump given cgraph node.  */
+ void
+ dump_cgraph_node (FILE *f, struct cgraph_node *node)
+ {
+   struct cgraph_edge *edge;
+   fprintf (f, "%s/%i:", cgraph_node_name (node), node->uid);
+   if (node->global.inlined_to)
+     fprintf (f, " (inline copy in %s/%i)",
+ 	     cgraph_node_name (node->global.inlined_to),
+ 	     node->global.inlined_to->uid);
+   if (node->local.self_insns)
+     fprintf (f, " %i insns", node->local.self_insns);
+   if (node->global.insns && node->global.insns != node->local.self_insns)
+     fprintf (f, " (%i after inlining)", node->global.insns);
+   if (node->origin)
+     fprintf (f, " nested in: %s", cgraph_node_name (node->origin));
+   if (node->needed)
+     fprintf (f, " needed");
+   else if (node->reachable)
+     fprintf (f, " reachable");
+   if (DECL_SAVED_TREE (node->decl))
+     fprintf (f, " tree");
+   if (node->output)
+     fprintf (f, " output");
+ 
+   if (node->local.local)
+     fprintf (f, " local");
+   if (node->local.disregard_inline_limits)
+     fprintf (f, " always_inline");
+   else if (node->local.inlinable)
+     fprintf (f, " inlinable");
+   if (TREE_ASM_WRITTEN (node->decl))
+     fprintf (f, " asm_written");
+ 
+   fprintf (f, "\n  called by: ");
+   for (edge = node->callers; edge; edge = edge->next_caller)
+     {
+       fprintf (f, "%s/%i ", cgraph_node_name (edge->caller),
+ 	       edge->caller->uid);
+       if (edge->inline_call)
+ 	fprintf(f, "(inlined) ");
+     }
+ 
+   fprintf (f, "\n  calls: ");
+   for (edge = node->callees; edge; edge = edge->next_callee)
+     {
+       fprintf (f, "%s/%i ", cgraph_node_name (edge->callee),
+ 	       edge->callee->uid);
+       if (edge->inline_call)
+ 	fprintf(f, "(inlined) ");
+     }
+   fprintf (f, "\n");
+ }
+ 
  /* Dump the callgraph.  */
  
  void
*************** dump_cgraph (FILE *f)
*** 413,462 ****
  
    fprintf (f, "callgraph:\n\n");
    for (node = cgraph_nodes; node; node = node->next)
!     {
!       struct cgraph_edge *edge;
!       fprintf (f, "%s/%i:", cgraph_node_name (node), node->uid);
!       if (node->global.inlined_to)
!         fprintf (f, " (inline copy in %s)", cgraph_node_name (node->global.inlined_to));
!       if (node->local.self_insns)
!         fprintf (f, " %i insns", node->local.self_insns);
!       if (node->global.insns && node->global.insns != node->local.self_insns)
! 	fprintf (f, " (%i after inlining)", node->global.insns);
!       if (node->origin)
! 	fprintf (f, " nested in: %s", cgraph_node_name (node->origin));
!       if (node->needed)
! 	fprintf (f, " needed");
!       else if (node->reachable)
! 	fprintf (f, " reachable");
!       if (DECL_SAVED_TREE (node->decl))
! 	fprintf (f, " tree");
! 
!       if (node->local.local)
! 	fprintf (f, " local");
!       if (node->local.disregard_inline_limits)
! 	fprintf (f, " always_inline");
!       else if (node->local.inlinable)
! 	fprintf (f, " inlinable");
! 
!       fprintf (f, "\n  called by: ");
!       for (edge = node->callers; edge; edge = edge->next_caller)
! 	{
! 	  fprintf (f, "%s/%i ", cgraph_node_name (edge->caller),
! 		   edge->caller->uid);
! 	  if (edge->inline_call)
! 	    fprintf(f, "(inlined) ");
! 	}
! 
!       fprintf (f, "\n  calls: ");
!       for (edge = node->callees; edge; edge = edge->next_callee)
! 	{
! 	  fprintf (f, "%s/%i ", cgraph_node_name (edge->callee),
! 		   edge->callee->uid);
! 	  if (edge->inline_call)
! 	    fprintf(f, "(inlined) ");
! 	}
!       fprintf (f, "\n");
!     }
  }
  
  /* Returns a hash code for P.  */
--- 477,483 ----
  
    fprintf (f, "callgraph:\n\n");
    for (node = cgraph_nodes; node; node = node->next)
!     dump_cgraph_node (f, node);
  }
  
  /* Returns a hash code for P.  */
Index: cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.1.4.11
diff -c -3 -p -r1.1.4.11 cgraph.h
*** cgraph.h	9 Dec 2003 15:39:11 -0000	1.1.4.11
--- cgraph.h	13 Dec 2003 13:46:33 -0000
*************** struct cgraph_edge GTY((chain_next ("%h.
*** 116,121 ****
--- 116,122 ----
    struct cgraph_edge *next_callee;
    tree call_expr;
    bool inline_call;
+   PTR GTY ((skip (""))) aux;
  };
  
  /* The cgraph_varpool data strutcture.
*************** extern GTY((param_is (union tree_node)))
*** 150,155 ****
--- 151,157 ----
  
  /* In cgraph.c  */
  void dump_cgraph (FILE *);
+ void dump_cgraph_node (FILE *, struct cgraph_node *);
  void cgraph_remove_edge (struct cgraph_edge *);
  void cgraph_remove_node (struct cgraph_node *);
  struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
*************** void cgraph_mark_needed_node (struct cgr
*** 185,189 ****
--- 187,194 ----
  void cgraph_mark_reachable_node (struct cgraph_node *);
  bool cgraph_inline_p (struct cgraph_edge *);
  bool cgraph_preserve_function_body_p (tree);
+ void verify_cgraph (void);
+ void verify_cgraph_node (struct cgraph_node *);
+ void cgraph_mark_inline_edge (struct cgraph_edge *e);
  
  #endif  /* GCC_CGRAPH_H  */
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.1.4.19
diff -c -3 -p -r1.1.4.19 cgraphunit.c
*** cgraphunit.c	12 Dec 2003 01:14:14 -0000	1.1.4.19
--- cgraphunit.c	13 Dec 2003 13:46:33 -0000
*************** cgraph_create_edges (struct cgraph_node 
*** 304,309 ****
--- 304,448 ----
    visited_nodes = NULL;
  }
  
+ static bool error_found;
+ 
+ /* Callbrack of verify_cgraph_node.  Check that all call_exprs have cgraph nodes.  */
+ static tree
+ verify_cgraph_node_1 (tree *tp, int *walk_subtrees, void *data)
+ {
+   tree t = *tp;
+   tree decl;
+ 
+   if (TREE_CODE (t) == CALL_EXPR && (decl = get_callee_fndecl (t)))
+     {
+       struct cgraph_edge *e = cgraph_edge (data, t);
+       if (e)
+ 	{
+ 	  if (e->aux)
+ 	    {
+ 	      error ("Shared call_expr:");
+ 	      debug_tree (t);
+ 	      error_found = true;
+ 	    }
+ 	  if (e->callee->decl != cgraph_node (decl)->decl)
+ 	    {
+ 	      error ("Edge points to wrong declaration:");
+ 	      debug_tree (e->callee->decl);
+ 	      fprintf (stderr," Instead of:");
+ 	      debug_tree (decl);
+ 	    }
+ 	  e->aux = (void *)1;
+ 	}
+       else
+ 	{
+ 	  error ("Missing callgraph edge for call expr:");
+ 	  debug_tree (t);
+ 	  error_found = true;
+ 	}
+     }
+   /* Save some cycles by not walking types and declaration as we
+      won't find anything useful there anyway.  */
+   if (DECL_P (*tp) || TYPE_P (*tp))
+     {
+       *walk_subtrees = 0;
+     }
+   return NULL_TREE;
+ }
+ 
+ /* Verify cgraph nodes of given cgraph node.  */
+ void
+ verify_cgraph_node (struct cgraph_node *node)
+ {
+   struct cgraph_edge *e;
+   struct cgraph_node *main_clone;
+ 
+   error_found = false;
+   for (e = node->callees; e; e = e->next_callee)
+     if (e->aux)
+       {
+ 	error ("Aux field set for edge %s->%s",
+ 	       cgraph_node_name (e->caller), cgraph_node_name (e->callee));
+ 	error_found = true;
+       }
+   for (e = node->callers; e; e = e->next_caller)
+     {
+       if (e->inline_call)
+ 	{
+ 	  if (node->global.inlined_to
+ 	      != (e->caller->global.inlined_to
+ 		  ? e->caller->global.inlined_to : e->caller))
+ 	    {
+ 	      error ("Inlined_to pointer is wrong");
+ 	      error_found = true;
+ 	    }
+ 	  if (node->callers->next_caller)
+ 	    {
+ 	      error ("Multiple inline callers");
+ 	      error_found = true;
+ 	    }
+ 	}
+       else
+ 	if (node->global.inlined_to)
+ 	  {
+ 	    error ("Inlined_to pointer set for noninline callers");
+ 	    error_found = true;
+ 	  }
+     }
+   if (!node->callers && node->global.inlined_to)
+     {
+       error ("Inlined_to pointer is set but no predecesors found");
+       error_found = true;
+     }
+   if (node->global.inlined_to == node)
+     {
+       error ("Inlined_to pointer reffers to itself");
+       error_found = true;
+     }
+ 
+   for (main_clone = cgraph_node (node->decl); main_clone;
+        main_clone = main_clone->next_clone)
+     if (main_clone == node)
+       break;
+   if (!node)
+     {
+       error ("Node not found in DECL_ASSEMBLER_NAME hash");
+       error_found = true;
+     }
+   
+   if (node->analyzed
+       && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl))
+     {
+       walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl),
+ 				    verify_cgraph_node_1, node);
+       for (e = node->callees; e; e = e->next_callee)
+ 	{
+ 	  if (!e->aux)
+ 	    {
+ 	      error ("Edge %s->%s has no corresponding call_expr",
+ 		     cgraph_node_name (e->caller),
+ 		     cgraph_node_name (e->callee));
+ 	      error_found = true;
+ 	    }
+ 	  e->aux = 0;
+ 	}
+     }
+   if (error_found)
+     {
+       dump_cgraph_node (stderr, node);
+       internal_error ("verify_cgraph_node failed.");
+     }
+ }
+ 
+ /* Verify whole cgraph structure.  */
+ void
+ verify_cgraph (void)
+ {
+   struct cgraph_node *node;
+ 
+   for (node = cgraph_nodes; node; node = node->next)
+     verify_cgraph_node (node);
+ }
+ 
  /* Analyze the function scheduled to be output.  */
  static void
  cgraph_analyze_function (struct cgraph_node *node)
*************** cgraph_mark_functions_to_output (void)
*** 451,456 ****
--- 590,602 ----
  	  && !TREE_ASM_WRITTEN (decl) && !node->origin
  	  && !DECL_EXTERNAL (decl))
  	node->output = 1;
+       /* We should've reclaimed all functions that are not needed.  */
+       else if (!node->global.inlined_to && DECL_SAVED_TREE (decl)
+ 	       && !node->origin)
+ 	{
+ 	  dump_cgraph_node (stderr, node);
+ 	  abort ();
+ 	}
      }
  }
  
*************** cgraph_expand_function (struct cgraph_no
*** 461,466 ****
--- 607,616 ----
  {
    tree decl = node->decl;
  
+   /* We ought to not compile any inline clones.  */
+   if (node->global.inlined_to)
+     abort ();
+ 
    if (flag_unit_at_a_time)
      announce_function (decl);
  
*************** cgraph_expand_function (struct cgraph_no
*** 468,473 ****
--- 618,627 ----
       via lang_expand_decl_stmt.  */
    (*lang_hooks.callgraph.expand_function) (decl);
  
+   /* Make sure that BE didn't gave up on compiling.  */
+   if (!TREE_ASM_WRITTEN (node->decl))
+     abort ();
+ 
    current_function_decl = NULL;
  }
  
*************** cgraph_clone_inlined_nodes (struct cgrap
*** 575,581 ****
  
    /* We may elliminate the need for out-of-line copy to be output.  In that
       case just go ahead and re-use it.  */
!   if (!e->callee->callers->next_caller && !e->callee->needed
        && !e->callee->origin
        && duplicate
        && flag_unit_at_a_time)
--- 729,736 ----
  
    /* We may elliminate the need for out-of-line copy to be output.  In that
       case just go ahead and re-use it.  */
!   if (!e->callee->callers->next_caller
!       && (!e->callee->needed || DECL_EXTERNAL (e->callee->decl))
        && !e->callee->origin
        && duplicate
        && flag_unit_at_a_time)
*************** cgraph_clone_inlined_nodes (struct cgrap
*** 605,611 ****
  
  /* Mark edge E as inlined and update callgraph accordingly.  */
  
! static void
  cgraph_mark_inline_edge (struct cgraph_edge *e)
  {
    int old_insns = 0, new_insns = 0;
--- 760,766 ----
  
  /* Mark edge E as inlined and update callgraph accordingly.  */
  
! void
  cgraph_mark_inline_edge (struct cgraph_edge *e)
  {
    int old_insns = 0, new_insns = 0;
*************** cgraph_decide_inlining (void)
*** 985,990 ****
--- 1140,1158 ----
  	}
      }
  
+   /* We will never output extern functions we didn't inline. 
+      ??? Perhaps we can prevent accounting of growth of external
+      inline functions.  */
+   for (node = cgraph_nodes; node; node = node->next)
+     {
+       if (node->global.inlined_to
+ 	  && DECL_EXTERNAL (node->global.inlined_to->decl))
+         cgraph_remove_node (node);
+       if (!node->global.inlined_to && DECL_EXTERNAL (node->decl)
+ 	  && !dump_enabled_p (TDI_all))
+ 	DECL_SAVED_TREE (node->decl) = NULL_TREE;
+     }
+ 
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
  	     "\nInlined %i calls, eliminated %i functions, "
*************** cgraph_decide_inlining_incrementally (st
*** 1006,1012 ****
    for (e = node->callees; e; e = e->next_callee)
      if (e->callee->local.disregard_inline_limits
  	&& !e->inline_call
!         && !cgraph_recursive_inlining_p (node, e->callee))
        cgraph_mark_inline (node, e->callee);
  
    /* Now do the automatic inlining.  */
--- 1174,1183 ----
    for (e = node->callees; e; e = e->next_callee)
      if (e->callee->local.disregard_inline_limits
  	&& !e->inline_call
!         && !cgraph_recursive_inlining_p (node, e->callee)
! 	/* ??? It is possible that renaming variable removed the function body
! 	   in duplicate_decls. See gcc.c-torture/compile/20011119-2.c  */
! 	&& DECL_SAVED_TREE (e->callee->decl))
        cgraph_mark_inline (node, e->callee);
  
    /* Now do the automatic inlining.  */
*************** cgraph_decide_inlining_incrementally (st
*** 1015,1021 ****
  	&& !e->inline_call
          && !cgraph_recursive_inlining_p (node, e->callee)
          && cgraph_default_inline_p (e->callee)
! 	&& cgraph_check_inline_limits (node, e->callee))
        cgraph_mark_inline (node, e->callee);
  }
  
--- 1186,1193 ----
  	&& !e->inline_call
          && !cgraph_recursive_inlining_p (node, e->callee)
          && cgraph_default_inline_p (e->callee)
! 	&& cgraph_check_inline_limits (node, e->callee)
! 	&& DECL_SAVED_TREE (e->callee->decl))
        cgraph_mark_inline (node, e->callee);
  }
  
*************** cgraph_expand_all_functions (void)
*** 1049,1054 ****
--- 1221,1228 ----
    cgraph_mark_functions_to_output ();
  
    order_pos = cgraph_postorder (order);
+   if (order_pos != cgraph_n_nodes)
+     abort ();
  
    /* Garbage collector may remove inline clones we elliminate during
       optimization.  So we must be sure to not reference them.  */
*************** cgraph_preserve_function_body_p (tree de
*** 1121,1126 ****
--- 1295,1303 ----
  void
  cgraph_optimize (void)
  {
+ #ifdef ENABLE_CHECKING
+   verify_cgraph ();
+ #endif
    if (!flag_unit_at_a_time)
      return;
    timevar_push (TV_CGRAPHOPT);
*************** cgraph_optimize (void)
*** 1147,1156 ****
--- 1324,1361 ----
    /* Output everything.  */
    if (!quiet_flag)
      fprintf (stderr, "Assembling functions:\n");
+ #ifdef ENABLE_CHECKING
+   verify_cgraph ();
+ #endif
    cgraph_expand_all_functions ();
    if (cgraph_dump_file)
      {
        fprintf (cgraph_dump_file, "\nFinal ");
        dump_cgraph (cgraph_dump_file);
      }
+ #ifdef ENABLE_CHECKING
+   verify_cgraph ();
+   /* Double check that all inline clones are gone and that all function bodies
+      has been released from memory.  */
+   if (flag_unit_at_a_time && !dump_enabled_p (TDI_all))
+     {
+       struct cgraph_node *node;
+       bool error_found = false;
+ 
+       for (node = cgraph_nodes; node; node = node->next)
+ 	if (node->analyzed
+ 	    /* ??? We don't handle memory management of nested functions quite
+ 	       right.  It probably does not worth the effort as these functions
+ 	       should go away soon.  */
+ 	    && !node->origin
+ 	    && (node->global.inlined_to
+ 	        || DECL_SAVED_TREE (node->decl)))
+ 	  {
+ 	    error_found = true;
+ 	    dump_cgraph_node (stderr, node);
+  	  }
+       if (error_found)
+ 	internal_error ("Nodes with no released memory found.");
+     }
+ #endif
  }
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.26.2.71
diff -c -3 -p -r1.26.2.71 tree-inline.c
*** tree-inline.c	12 Dec 2003 23:32:15 -0000	1.26.2.71
--- tree-inline.c	13 Dec 2003 13:46:34 -0000
*************** copy_body_r (tree *tp, int *walk_subtree
*** 643,648 ****
--- 643,650 ----
  		  edge = cgraph_edge (node, old_node);
  		  if (edge)
  		    edge->call_expr = *tp;
+ 		  else
+ 		    abort ();
  		}
  	    }
  	  else
*************** expand_call_inline (tree *tp, int *walk_
*** 1437,1452 ****
        && DECL_SAVED_TREE (DECL_ABSTRACT_ORIGIN (fn)))
      fn = DECL_ABSTRACT_ORIGIN (fn);
  
    edge = cgraph_edge (id->current_node, t);
  
    /* Constant propagation on argument done during previous inlining
       may create new direct call.  Produce an edge for it.  */
    if (!edge)
      {
!       cgraph_create_edge (id->node, cgraph_node (fn), t);
        goto egress;
      }
-     
  
    /* Don't try to inline functions that are not well-suited to
       inlining.  */
--- 1439,1463 ----
        && DECL_SAVED_TREE (DECL_ABSTRACT_ORIGIN (fn)))
      fn = DECL_ABSTRACT_ORIGIN (fn);
  
+   /* Objective C and fortran still calls tree_rest_of_compilation directly.
+      Kill this check once this is fixed.  */
+   if (!id->current_node->analyzed)
+     goto egress;
+ 
    edge = cgraph_edge (id->current_node, t);
  
    /* Constant propagation on argument done during previous inlining
       may create new direct call.  Produce an edge for it.  */
    if (!edge)
      {
!       struct cgraph_node *dest = cgraph_node (fn);
! 
!       /* FN must have address taken so it can be passed as argument.  */
!       if (!dest->needed)
! 	abort ();
!       cgraph_create_edge (id->node, dest, t);
        goto egress;
      }
  
    /* Don't try to inline functions that are not well-suited to
       inlining.  */
*************** expand_call_inline (tree *tp, int *walk_
*** 1461,1466 ****
--- 1472,1481 ----
        goto egress;
      }
  
+ #ifdef ENABLE_CHECKING
+   verify_cgraph_node (edge->callee);
+ #endif
+ 
    if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
      goto egress;
  
*************** optimize_inline_calls (tree fn)
*** 1801,1806 ****
--- 1816,1834 ----
  		VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
        DECL_INLINED_FNS (fn) = ifn;
      }
+ 
+ #ifdef ENABLE_CHECKING
+     {
+       struct cgraph_edge *e;
+ 
+       verify_cgraph_node (id.node);
+ 
+       /* Double check that we inlined everything we are supposed to inline.  */
+       for (e = id.node->callees; e; e = e->next_callee)
+ 	if (e->inline_call)
+ 	  abort ();
+     }
+ #endif
  }
  
  /* FN is a function that has a complete body, and CLONE is a function
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.92
diff -c -3 -p -r1.1.4.92 tree-optimize.c
*** tree-optimize.c	9 Dec 2003 15:39:11 -0000	1.1.4.92
--- tree-optimize.c	13 Dec 2003 13:46:34 -0000
*************** tree_rest_of_compilation (tree fndecl, b
*** 345,351 ****
    if (cgraph_preserve_function_body_p (fndecl))
      {
        if (!flag_unit_at_a_time)
! 	saved_node = cgraph_clone_node (node);
        cfun->saved_tree = save_body (fndecl, &cfun->saved_args);
      }
  
--- 345,361 ----
    if (cgraph_preserve_function_body_p (fndecl))
      {
        if (!flag_unit_at_a_time)
! 	{
! 	  struct cgraph_edge *e;
! 
! 	  saved_node = cgraph_clone_node (node);
! 	  for (e = saved_node->callees; e; e = e->next_callee)
! 	    if (e->inline_call)
! 	      {
! 		e->inline_call = 0;
! 		cgraph_mark_inline_edge (e);
! 	      }
! 	}
        cfun->saved_tree = save_body (fndecl, &cfun->saved_args);
      }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]