Updated version of -Winline warnings patch

Jan Hubicka jh@suse.cz
Sat Jan 3 16:53:00 GMT 2004


Hi,
I've managed to forget to commit the patch for proper -Winline warning.  Since
this is a regression relative to older GCC versions that used to produce
usefull messages, I've updated the patch and will commit it tomorrow.  I will
also prepare tree-ssa branch version.

Bootstrapped/regtested i686-pc-gnu-linux

Honza

/* { dg-do compile } */
/* { dg-options "-Winline -O2" } */

void q(void);
inline int t(void)
{
	int ret;
	q();
	ret = t();  /* We define sane semantics for inline keywork on recursive
		       functions, so do not warn here.  */
	q();
	return ret;
}

/* { dg-do compile } */
/* { dg-options "-Winline -O2" } */

inline int q(void);		 /* { dg-warning "body not available" "" } */
inline int t(void)
{
	return q();		 /* { dg-warning "called from here" "" } */
}

/* { dg-do compile } */
/* { dg-options "-Winline -O2 --param max-inline-insns-single=1" } */

void big (void);
inline int q(void)		
{				/* { dg-warning "max-inline-insns-single" "" } */
	big();
	big();
	big();
	big();
	big();
	big();
	big();
	big();
	big();
	big();
}
inline int t (void)
{
	return q ();		 /* { dg-warning "called from here" "" } */
}

/* { dg-do compile } */
/* { dg-options "-Winline -O1 -fno-unit-at-a-time" } */

inline int q(void);		 /* { dg-warning "body not available" } */
inline int t(void)
{
	return q();		 /* { dg-warning "called from here" } */
}
int q(void)
{
}

/* { dg-do compile } */
/* { dg-options "-Winline -O2 --param large-function-growth=0 --param large-function-insns=1" } */

void big (void);
inline int q(void)
{				/* { dg-warning "large-function-growth" } */
	big();
	big();
	big();
	big();
	big();
	big();
	big();
	big();
	big();
	big();
}
inline int t (void)
{
	return q ();		 /* { dg-warning "called from here" } */
}

/* { dg-do compile } */
/* { dg-options "-Winline -O2" } */

void big (void);
inline int q(void)
{				/* { dg-warning "(function not inlinable|alloca)" } */
	return (int)alloca(10);
}
inline int t (void)
{
	return q ();		 /* { dg-warning "called from here" } */
}

Tue Sep  9 18:50:42 CEST 2003  Jan Hubicka  <jh@suse.cz>
	* Makefile.in (cgraph.o, cgraphunit.o): Add intl.h dependency.
	* cgraph.c (create_edge, dump_cgraph): Update to use inline_failed
	* cgraph.h (cgraph_edge): Replace inline_call by inline_failed
	(cgraph_inline_p): Add extra argument reason.
	* cgraphunit.c: Minor formating fixes.
	cgraph_first_inlined_callee): New functions.
	(record_call_1): Record builtins too.
	(cgraph_analyze_function): Update inline_failed messages.
	(cgraph_mark_functions_to_output, cgraph_expand_function, cgraph_inlined_into,
	cgraph_inlined_callees, cgraph_estimate_growth): Update to use inline_failed.
	(cgraph_check_inline_limits): Likewise; Add argument reason.
	(cgraph_set_inline_failed): New static function.
	(cgraph_decide_inlining_of_small_function, cgraph_decide_inlining): Set
	reasons.
	(cgraph_inline_p): Add new argument reason.
	* tree-inline.c (expand_call_inline):  Update warning.
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1213
diff -c -3 -p -r1.1213 Makefile.in
*** Makefile.in	30 Dec 2003 10:40:46 -0000	1.1213
--- Makefile.in	3 Jan 2004 12:23:27 -0000
*************** simplify-rtx.o : simplify-rtx.c $(CONFIG
*** 1633,1641 ****
     $(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 toplev.h flags.h $(GGC_H)  $(TARGET_H) cgraph.h gt-cgraph.h output.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
  coverage.o : coverage.c gcov-io.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
     $(TM_H) $(RTL_H) $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \
     toplev.h $(GGC_H) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \
--- 1633,1642 ----
     $(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 toplev.h flags.h $(GGC_H)  $(TARGET_H) cgraph.h gt-cgraph.h \
!    output.h intl.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 intl.h
  coverage.o : coverage.c gcov-io.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
     $(TM_H) $(RTL_H) $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \
     toplev.h $(GGC_H) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.39
diff -c -3 -p -r1.39 cgraph.c
*** cgraph.c	1 Jan 2004 13:58:56 -0000	1.39
--- cgraph.c	3 Jan 2004 12:23:35 -0000
*************** Software Foundation, 59 Temple Place - S
*** 34,39 ****
--- 34,40 ----
  #include "cgraph.h"
  #include "varray.h"
  #include "output.h"
+ #include "intl.h"
  
  
  /* Hash table used to convert declarations into nodes.  */
*************** create_edge (struct cgraph_node *caller,
*** 156,162 ****
    struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
    struct cgraph_edge *edge2;
  
!   edge->inline_call = false;
    /* At the moment we don't associate calls with specific CALL_EXPRs
       as we probably ought to, so we must preserve inline_call flags to
       be the same in all copies of the same edge.  */
--- 157,169 ----
    struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
    struct cgraph_edge *edge2;
  
!   if (!DECL_SAVED_TREE (callee->decl))
!     edge->inline_failed = N_("function body not available");
!   else if (callee->local.inlinable)
!     edge->inline_failed = N_("function not considered for inlining");
!   else
!     edge->inline_failed = N_("function not inlinable");
! 
    /* At the moment we don't associate calls with specific CALL_EXPRs
       as we probably ought to, so we must preserve inline_call flags to
       be the same in all copies of the same edge.  */
*************** create_edge (struct cgraph_node *caller,
*** 164,170 ****
      for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee)
        if (edge2->callee == callee)
  	{
! 	  edge->inline_call = edge2->inline_call;
  	  break;
  	}
  
--- 171,177 ----
      for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee)
        if (edge2->callee == callee)
  	{
! 	  edge->inline_failed = edge2->inline_failed;
  	  break;
  	}
  
*************** dump_cgraph (FILE *f)
*** 381,387 ****
        for (edge = node->callers; edge; edge = edge->next_caller)
  	{
  	  fprintf (f, "%s ", cgraph_node_name (edge->caller));
! 	  if (edge->inline_call)
  	    fprintf(f, "(inlined) ");
  	}
  
--- 388,394 ----
        for (edge = node->callers; edge; edge = edge->next_caller)
  	{
  	  fprintf (f, "%s ", cgraph_node_name (edge->caller));
! 	  if (!edge->inline_failed)
  	    fprintf(f, "(inlined) ");
  	}
  
*************** dump_cgraph (FILE *f)
*** 389,395 ****
        for (edge = node->callees; edge; edge = edge->next_callee)
  	{
  	  fprintf (f, "%s ", cgraph_node_name (edge->callee));
! 	  if (edge->inline_call)
  	    fprintf(f, "(inlined) ");
  	}
        fprintf (f, "\n");
--- 396,402 ----
        for (edge = node->callees; edge; edge = edge->next_callee)
  	{
  	  fprintf (f, "%s ", cgraph_node_name (edge->callee));
! 	  if (!edge->inline_failed)
  	    fprintf(f, "(inlined) ");
  	}
        fprintf (f, "\n");
Index: cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.24
diff -c -3 -p -r1.24 cgraph.h
*** cgraph.h	13 Dec 2003 04:11:19 -0000	1.24
--- cgraph.h	3 Jan 2004 12:23:35 -0000
*************** struct cgraph_edge GTY(())
*** 119,125 ****
    struct cgraph_node *callee;
    struct cgraph_edge *next_caller;
    struct cgraph_edge *next_callee;
!   bool inline_call;
  };
  
  /* The cgraph_varpool data structure.
--- 119,127 ----
    struct cgraph_node *callee;
    struct cgraph_edge *next_caller;
    struct cgraph_edge *next_callee;
!   /* When NULL, inline this call.  When non-NULL, points to the explanation
!      why function was not inlined.  */
!   const char *inline_failed;
  };
  
  /* The cgraph_varpool data structure.
*************** void cgraph_create_edges (tree, tree);
*** 181,186 ****
  void cgraph_optimize (void);
  void cgraph_mark_needed_node (struct cgraph_node *);
  void cgraph_mark_reachable_node (struct cgraph_node *);
! bool cgraph_inline_p (tree, tree);
  
  #endif  /* GCC_CGRAPH_H  */
--- 183,188 ----
  void cgraph_optimize (void);
  void cgraph_mark_needed_node (struct cgraph_node *);
  void cgraph_mark_reachable_node (struct cgraph_node *);
! bool cgraph_inline_p (tree, tree, const char **reason);
  
  #endif  /* GCC_CGRAPH_H  */
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.41
diff -c -3 -p -r1.41 cgraphunit.c
*** cgraphunit.c	2 Jan 2004 18:06:16 -0000	1.41
--- cgraphunit.c	3 Jan 2004 12:23:35 -0000
*************** Software Foundation, 59 Temple Place - S
*** 38,43 ****
--- 38,44 ----
  #include "params.h"
  #include "fibheap.h"
  #include "c-common.h"
+ #include "intl.h"
  
  #define INSNS_PER_CALL 10
  
*************** record_call_1 (tree *tp, int *walk_subtr
*** 257,264 ****
  	tree decl = get_callee_fndecl (*tp);
  	if (decl && TREE_CODE (decl) == FUNCTION_DECL)
  	  {
- 	    if (DECL_BUILT_IN (decl))
- 	      return NULL;
  	    cgraph_record_call (data, decl);
  
  	    /* When we see a function call, we don't want to look at the
--- 258,263 ----
*************** static void
*** 311,316 ****
--- 310,316 ----
  cgraph_analyze_function (struct cgraph_node *node)
  {
    tree decl = node->decl;
+   struct cgraph_edge *e;
  
    current_function_decl = decl;
  
*************** cgraph_analyze_function (struct cgraph_n
*** 325,330 ****
--- 325,334 ----
    if (node->local.inlinable)
      node->local.disregard_inline_limits
        = (*lang_hooks.tree_inlining.disregard_inline_limits) (decl);
+   for (e = node->callers; e; e = e->next_caller)
+     if (e->inline_failed)
+       e->inline_failed = (!node->local.inlinable ? N_("function not inlinable")
+ 			  : N_("function not considered for inlining"));
    if (flag_really_no_inline && !node->local.disregard_inline_limits)
      node->local.inlinable = 0;
    /* Inlining characteristics are maintained by the cgraph_mark_inline.  */
*************** cgraph_mark_functions_to_output (void)
*** 442,452 ****
      {
        tree decl = node->decl;
        struct cgraph_edge *e;
        if (node->output)
  	abort ();
  
        for (e = node->callers; e; e = e->next_caller)
! 	if (!e->inline_call)
  	  break;
  
        /* We need to output all local functions that are used and not
--- 446,457 ----
      {
        tree decl = node->decl;
        struct cgraph_edge *e;
+ 
        if (node->output)
  	abort ();
  
        for (e = node->callers; e; e = e->next_caller)
! 	if (e->inline_failed)
  	  break;
  
        /* We need to output all local functions that are used and not
*************** cgraph_optimize_function (struct cgraph_
*** 476,482 ****
        struct cgraph_edge *e;
  
        for (e = node->callees; e; e = e->next_callee)
! 	if (e->inline_call || warn_inline)
  	  break;
        if (e)
          optimize_inline_calls (decl);
--- 481,487 ----
        struct cgraph_edge *e;
  
        for (e = node->callees; e; e = e->next_callee)
! 	if (!e->inline_failed || warn_inline)
  	  break;
        if (e)
          optimize_inline_calls (decl);
*************** cgraph_expand_function (struct cgraph_no
*** 512,517 ****
--- 517,523 ----
  
  /* Fill array order with all nodes with output flag set in the reverse
     topological order.  */
+ 
  static int
  cgraph_postorder (struct cgraph_node **order)
  {
*************** cgraph_inlined_into (struct cgraph_node 
*** 594,600 ****
    /* Fast path: since we traverse in mostly topological order, we will likely
       find no edges.  */
    for (e = node->callers; e; e = e->next_caller)
!     if (e->inline_call)
        break;
  
    if (!e)
--- 600,606 ----
    /* Fast path: since we traverse in mostly topological order, we will likely
       find no edges.  */
    for (e = node->callers; e; e = e->next_caller)
!     if (!e->inline_failed)
        break;
  
    if (!e)
*************** cgraph_inlined_into (struct cgraph_node 
*** 626,633 ****
        SET_INLINED_TIMES (caller, INLINED_TIMES (caller) + 1);
  
        for (e1 = caller->callers; e1; e1 = e1->next_caller)
! 	if (e1->inline_call)
  	  break;
        if (e1)
  	stack[sp++] = e1;
        else
--- 632,640 ----
        SET_INLINED_TIMES (caller, INLINED_TIMES (caller) + 1);
  
        for (e1 = caller->callers; e1; e1 = e1->next_caller)
! 	if (!e1->inline_failed)
  	  break;
+ 
        if (e1)
  	stack[sp++] = e1;
        else
*************** cgraph_inlined_into (struct cgraph_node 
*** 635,641 ****
  	  while (true)
  	    {
  	      for (e1 = e->next_caller; e1; e1 = e1->next_caller)
! 		if (e1->inline_call)
  		  break;
  
  	      if (e1)
--- 642,648 ----
  	  while (true)
  	    {
  	      for (e1 = e->next_caller; e1; e1 = e1->next_caller)
! 		if (!e1->inline_failed)
  		  break;
  
  	      if (e1)
*************** cgraph_inlined_callees (struct cgraph_no
*** 692,698 ****
    /* Fast path: since we traverse in mostly topological order, we will likely
       find no edges.  */
    for (e = node->callees; e; e = e->next_callee)
!     if (e->inline_call)
        break;
  
    if (!e)
--- 699,705 ----
    /* Fast path: since we traverse in mostly topological order, we will likely
       find no edges.  */
    for (e = node->callees; e; e = e->next_callee)
!     if (!e->inline_failed)
        break;
  
    if (!e)
*************** cgraph_inlined_callees (struct cgraph_no
*** 724,730 ****
        SET_INLINED_TIMES (callee, INLINED_TIMES (callee) + 1);
  
        for (e1 = callee->callees; e1; e1 = e1->next_callee)
! 	if (e1->inline_call)
  	  break;
        if (e1)
  	stack[sp++] = e1;
--- 731,737 ----
        SET_INLINED_TIMES (callee, INLINED_TIMES (callee) + 1);
  
        for (e1 = callee->callees; e1; e1 = e1->next_callee)
! 	if (!e1->inline_failed)
  	  break;
        if (e1)
  	stack[sp++] = e1;
*************** cgraph_inlined_callees (struct cgraph_no
*** 733,739 ****
  	  while (true)
  	    {
  	      for (e1 = e->next_callee; e1; e1 = e1->next_callee)
! 		if (e1->inline_call)
  		  break;
  
  	      if (e1)
--- 740,746 ----
  	  while (true)
  	    {
  	      for (e1 = e->next_callee; e1; e1 = e1->next_callee)
! 		if (!e1->inline_failed)
  		  break;
  
  	      if (e1)
*************** cgraph_estimate_growth (struct cgraph_no
*** 791,797 ****
    struct cgraph_edge *e;
  
    for (e = node->callers; e; e = e->next_caller)
!     if (!e->inline_call)
        {
  	growth += ((cgraph_estimate_size_after_inlining (1, e->caller, node)
  		    -
--- 798,804 ----
    struct cgraph_edge *e;
  
    for (e = node->callers; e; e = e->next_caller)
!     if (e->inline_failed)
        {
  	growth += ((cgraph_estimate_size_after_inlining (1, e->caller, node)
  		    -
*************** cgraph_mark_inline (struct cgraph_node *
*** 833,845 ****
      {
        if (e->caller == to)
  	{
! 	  if (e->inline_call)
! 	    abort ();
! 	  e->inline_call = true;
  	  times++;
  	  clones += e->caller->global.cloned_times;
  	}
!       else if (!e->inline_call)
  	called = true;
      }
    if (!times)
--- 840,852 ----
      {
        if (e->caller == to)
  	{
! 	  if (!e->inline_failed)
! 	    continue;
! 	  e->inline_failed = NULL;
  	  times++;
  	  clones += e->caller->global.cloned_times;
  	}
!       else if (e->inline_failed)
  	called = true;
      }
    if (!times)
*************** cgraph_mark_inline (struct cgraph_node *
*** 884,890 ****
  
  static bool
  cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
! 			    struct cgraph_node **inlined, int ninlined)
  {
    int i;
    int times = 0;
--- 891,898 ----
  
  static bool
  cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
! 			    struct cgraph_node **inlined, int ninlined,
! 			    const char **reason)
  {
    int i;
    int times = 0;
*************** cgraph_check_inline_limits (struct cgrap
*** 908,914 ****
    newsize = cgraph_estimate_size_after_inlining (times, to, what);
    if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
        && newsize > limit)
!     return false;
    for (i = 0; i < ninlined; i++)
      {
        newsize =
--- 916,925 ----
    newsize = cgraph_estimate_size_after_inlining (times, to, what);
    if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
        && newsize > limit)
!     {
!       *reason = N_("--param large-function-growth limit reached");
!       return false;
!     }
    for (i = 0; i < ninlined; i++)
      {
        newsize =
*************** cgraph_check_inline_limits (struct cgrap
*** 918,924 ****
  	  && newsize >
  	  inlined[i]->local.self_insns *
  	  (100 + PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH)) / 100)
! 	return false;
      }
    return true;
  }
--- 929,938 ----
  	  && newsize >
  	  inlined[i]->local.self_insns *
  	  (100 + PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH)) / 100)
! 	{
! 	  *reason = N_("--param large-function-growth limit reached while inlining the caller");
! 	  return false;
! 	}
      }
    return true;
  }
*************** cgraph_default_inline_p (struct cgraph_n
*** 936,941 ****
--- 950,969 ----
      return n->global.insns < MAX_INLINE_INSNS_AUTO;
  }
  
+ /* Set inline_failed for all callers of given function to REASON.  */
+ 
+ static void
+ cgraph_set_inline_failed (struct cgraph_node *node, const char *reason)
+ {
+   struct cgraph_edge *e;
+ 
+   if (cgraph_dump_file)
+     fprintf (cgraph_dump_file, "Inlining failed: %s\n", reason);
+   for (e = node->callers; e; e = e->next_caller)
+     if (e->inline_failed)
+       e->inline_failed = reason;
+ }
+ 
  /* We use greedy algorithm for inlining of small functions:
     All inline candidates are put into prioritized heap based on estimated
     growth of the overall number of instructions and then update the estimates.
*************** cgraph_decide_inlining_of_small_function
*** 960,984 ****
  
    for (node = cgraph_nodes; node; node = node->next)
      {
-       struct cgraph_edge *e;
- 
        if (!node->local.inlinable || !node->callers
! 	  || !cgraph_default_inline_p (node))
  	continue;
  
!       /* Rule out always_inline functions we dealt with earlier.  */
!       for (e = node->callers; e; e = e->next_caller)
! 	if (e->inline_call)
! 	  break;
!       if (e)
! 	continue;
        heap_node[node->uid] =
  	fibheap_insert (heap, cgraph_estimate_growth (node), node);
      }
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file, "\nDeciding on smaller functions:\n");
!   while ((node = fibheap_extract_min (heap)) && overall_insns <= max_insns)
      {
        struct cgraph_edge *e;
        int old_insns = overall_insns;
--- 988,1010 ----
  
    for (node = cgraph_nodes; node; node = node->next)
      {
        if (!node->local.inlinable || !node->callers
! 	  || node->local.disregard_inline_limits)
  	continue;
  
!       if (!cgraph_default_inline_p (node))
! 	{
! 	  cgraph_set_inline_failed (node,
! 	    N_("--param max-inline-insns-single limit reached"));
! 	  continue;
! 	}
        heap_node[node->uid] =
  	fibheap_insert (heap, cgraph_estimate_growth (node), node);
      }
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file, "\nDeciding on smaller functions:\n");
!   while (overall_insns <= max_insns && (node = fibheap_extract_min (heap)))
      {
        struct cgraph_edge *e;
        int old_insns = overall_insns;
*************** cgraph_decide_inlining_of_small_function
*** 992,1009 ****
  		 cgraph_estimate_growth (node));
        if (!cgraph_default_inline_p (node))
  	{
! 	  if (cgraph_dump_file)
! 	    fprintf (cgraph_dump_file, " Function too large.\n");
  	  continue;
  	}
        ninlined_callees = cgraph_inlined_callees (node, inlined_callees);
        for (e = node->callers; e; e = e->next_caller)
! 	if (!e->inline_call && e->caller != node)
  	  {
  	    ninlined = cgraph_inlined_into (e->caller, inlined);
  	    if (e->callee->output
  		|| !cgraph_check_inline_limits (e->caller, node, inlined,
! 						ninlined))
  	      {
  		for (i = 0; i < ninlined; i++)
  		  inlined[i]->output = 0, node->aux = 0;
--- 1018,1044 ----
  		 cgraph_estimate_growth (node));
        if (!cgraph_default_inline_p (node))
  	{
! 	  cgraph_set_inline_failed (node,
! 	    N_("--param max-inline-insns-single limit reached after inlining into the callee"));
  	  continue;
  	}
        ninlined_callees = cgraph_inlined_callees (node, inlined_callees);
        for (e = node->callers; e; e = e->next_caller)
! 	if (e->inline_failed)
  	  {
+ 	    /* Marking recursive function inlinine has sane semantic and
+ 	       thus we should not warn on it.  */
+  	    if (e->caller == node)
+  	      {
+  	        e->inline_failed = "";
+  		continue;
+  	      }
  	    ninlined = cgraph_inlined_into (e->caller, inlined);
+ 	    if (e->callee->output)
+ 	      e->inline_failed = "";
  	    if (e->callee->output
  		|| !cgraph_check_inline_limits (e->caller, node, inlined,
! 						ninlined, &e->inline_failed))
  	      {
  		for (i = 0; i < ninlined; i++)
  		  inlined[i]->output = 0, node->aux = 0;
*************** cgraph_decide_inlining_of_small_function
*** 1039,1045 ****
           are now called more times; update keys.  */
  
        for (e = node->callees; e; e = e->next_callee)
! 	if (!e->inline_call && heap_node[e->callee->uid])
  	  fibheap_replace_key (heap, heap_node[e->callee->uid],
  			       cgraph_estimate_growth (e->callee));
  
--- 1074,1080 ----
           are now called more times; update keys.  */
  
        for (e = node->callees; e; e = e->next_callee)
! 	if (e->inline_failed && heap_node[e->callee->uid])
  	  fibheap_replace_key (heap, heap_node[e->callee->uid],
  			       cgraph_estimate_growth (e->callee));
  
*************** cgraph_decide_inlining_of_small_function
*** 1048,1054 ****
  	  struct cgraph_edge *e;
  
  	  for (e = inlined_callees[i]->callees; e; e = e->next_callee)
! 	    if (!e->inline_call && heap_node[e->callee->uid])
  	      fibheap_replace_key (heap, heap_node[e->callee->uid],
  				   cgraph_estimate_growth (e->callee));
  
--- 1083,1089 ----
  	  struct cgraph_edge *e;
  
  	  for (e = inlined_callees[i]->callees; e; e = e->next_callee)
! 	    if (e->inline_failed && heap_node[e->callee->uid])
  	      fibheap_replace_key (heap, heap_node[e->callee->uid],
  				   cgraph_estimate_growth (e->callee));
  
*************** cgraph_decide_inlining_of_small_function
*** 1059,1066 ****
  		 " Inlined %i times for a net change of %+i insns.\n",
  		 node->global.cloned_times, overall_insns - old_insns);
      }
!   if (cgraph_dump_file && !fibheap_empty (heap))
!     fprintf (cgraph_dump_file, "\nReached the inline-unit-growth limit.\n");
    fibheap_delete (heap);
    free (heap_node);
  }
--- 1094,1102 ----
  		 " Inlined %i times for a net change of %+i insns.\n",
  		 node->global.cloned_times, overall_insns - old_insns);
      }
!   while ((node = fibheap_extract_min (heap)) != NULL)
!     if (!node->local.disregard_inline_limits)
!       cgraph_set_inline_failed (node, N_("--param inline-unit-growth limit reached"));
    fibheap_delete (heap);
    free (heap_node);
  }
*************** cgraph_decide_inlining (void)
*** 1122,1131 ****
        for (; e; e = e->next_callee)
  	{
  	  old_insns = overall_insns;
! 	  if (e->inline_call || !e->callee->local.disregard_inline_limits)
! 	    continue;
! 	  if (e->callee->output || e->callee == node)
! 	    continue;
  	  ninlined_callees =
  	    cgraph_inlined_callees (e->callee, inlined_callees);
  	  cgraph_mark_inline (node, e->callee, inlined, ninlined,
--- 1158,1171 ----
        for (; e; e = e->next_callee)
  	{
  	  old_insns = overall_insns;
! 	  if (!e->inline_failed || !e->callee->local.inlinable
! 	      || !e->callee->local.disregard_inline_limits)
!   	    continue;
!   	  if (e->callee->output || e->callee == node)
! 	    {
! 	      e->inline_failed = N_("recursive inlining");
! 	      continue;
! 	    }
  	  ninlined_callees =
  	    cgraph_inlined_callees (e->callee, inlined_callees);
  	  cgraph_mark_inline (node, e->callee, inlined, ninlined,
*************** cgraph_decide_inlining (void)
*** 1160,1166 ****
  	  node = order[i];
  
  	  if (node->callers && !node->callers->next_caller && !node->needed
! 	      && node->local.inlinable && !node->callers->inline_call
  	      && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
  	    {
  	      bool ok = true;
--- 1200,1206 ----
  	  node = order[i];
  
  	  if (node->callers && !node->callers->next_caller && !node->needed
! 	      && node->local.inlinable && node->callers->inline_failed
  	      && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
  	    {
  	      bool ok = true;
*************** cgraph_decide_inlining (void)
*** 1168,1179 ****
  
  	      /* Verify that we won't duplicate the caller.  */
  	      for (node1 = node->callers->caller;
! 		   node1->callers && node1->callers->inline_call
  		   && ok; node1 = node1->callers->caller)
  		if (node1->callers->next_caller || node1->needed)
  		  ok = false;
  	      if (ok)
  		{
  		  if (cgraph_dump_file)
  		    fprintf (cgraph_dump_file,
  			     "\nConsidering %s %i insns.\n"
--- 1208,1220 ----
  
  	      /* Verify that we won't duplicate the caller.  */
  	      for (node1 = node->callers->caller;
! 		   node1->callers && node1->callers->inline_failed
  		   && ok; node1 = node1->callers->caller)
  		if (node1->callers->next_caller || node1->needed)
  		  ok = false;
  	      if (ok)
  		{
+ 		  const char *dummy_reason;
  		  if (cgraph_dump_file)
  		    fprintf (cgraph_dump_file,
  			     "\nConsidering %s %i insns.\n"
*************** cgraph_decide_inlining (void)
*** 1184,1191 ****
  		  ninlined = cgraph_inlined_into (node->callers->caller,
  		      				  inlined);
  		  old_insns = overall_insns;
  		  if (cgraph_check_inline_limits
! 		      (node->callers->caller, node, inlined, ninlined))
  		    {
  		      ninlined_callees =
  			cgraph_inlined_callees (node, inlined_callees);
--- 1225,1235 ----
  		  ninlined = cgraph_inlined_into (node->callers->caller,
  		      				  inlined);
  		  old_insns = overall_insns;
+ 
+ 		  /* Inlining functions once would never cause inlining warnings.  */
  		  if (cgraph_check_inline_limits
! 		      (node->callers->caller, node, inlined, ninlined,
! 		       &dummy_reason))
  		    {
  		      ninlined_callees =
  			cgraph_inlined_callees (node, inlined_callees);
*************** cgraph_decide_inlining_incrementally (st
*** 1245,1253 ****
  
    /* First of all look for always inline functions.  */
    for (e = node->callees; e; e = e->next_callee)
!     if (e->callee->local.disregard_inline_limits && !e->callee->output
! 	&& e->callee != node && !e->inline_call)
        {
  	ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees);
  	cgraph_mark_inline (node, e->callee, inlined, ninlined,
  			    inlined_callees, ninlined_callees);
--- 1289,1304 ----
  
    /* First of all look for always inline functions.  */
    for (e = node->callees; e; e = e->next_callee)
!     if (e->callee->local.disregard_inline_limits && e->inline_failed
! 	/* ??? 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))
        {
+ 	if (e->callee->output || e->callee == node)
+ 	  {
+  	    e->inline_failed = N_("recursive inlining");
+ 	    continue;
+ 	  }
  	ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees);
  	cgraph_mark_inline (node, e->callee, inlined, ninlined,
  			    inlined_callees, ninlined_callees);
*************** cgraph_decide_inlining_incrementally (st
*** 1259,1270 ****
      {
        /* Now do the automatic inlining.  */
        for (e = node->callees; e; e = e->next_callee)
! 	if (e->callee->local.inlinable && !e->callee->output
! 	    && e->callee != node && !e->inline_call
  	    && cgraph_default_inline_p (e->callee)
  	    && cgraph_check_inline_limits (node, e->callee, inlined,
! 					   ninlined))
  	  {
  	    ninlined_callees = cgraph_inlined_callees (e->callee,
  						       inlined_callees);
  	    cgraph_mark_inline (node, e->callee, inlined, ninlined,
--- 1310,1328 ----
      {
        /* Now do the automatic inlining.  */
        for (e = node->callees; e; e = e->next_callee)
! 	if (e->callee->local.inlinable && e->inline_failed
  	    && cgraph_default_inline_p (e->callee)
  	    && cgraph_check_inline_limits (node, e->callee, inlined,
! 					   ninlined, &e->inline_failed)
! 	    && DECL_SAVED_TREE (e->callee->decl))
  	  {
+ 	    /* Marking recursive function inlinine has sane semantic and thus
+ 	       we should not warn on it.  */
+ 	    if (e->callee->output || e->callee == node)
+ 	      {
+ 		e->inline_failed = "";
+ 		continue;
+ 	      }
  	    ninlined_callees = cgraph_inlined_callees (e->callee,
  						       inlined_callees);
  	    cgraph_mark_inline (node, e->callee, inlined, ninlined,
*************** cgraph_decide_inlining_incrementally (st
*** 1283,1292 ****
  }
  
  
! /* Return true when CALLER_DECL should be inlined into CALLEE_DECL.  */
  
  bool
! cgraph_inline_p (tree caller_decl, tree callee_decl)
  {
    struct cgraph_node *caller = cgraph_node (caller_decl);
    struct cgraph_node *callee = cgraph_node (callee_decl);
--- 1341,1352 ----
  }
  
  
! /* Return true when CALLER_DECL should be inlined into CALLEE_DECL.
!    When returned false and reason is non-NULL, set it to the reason
!    why the call was not inlined.  */
  
  bool
! cgraph_inline_p (tree caller_decl, tree callee_decl, const char **reason)
  {
    struct cgraph_node *caller = cgraph_node (caller_decl);
    struct cgraph_node *callee = cgraph_node (callee_decl);
*************** cgraph_inline_p (tree caller_decl, tree 
*** 1294,1303 ****
  
    for (e = caller->callees; e; e = e->next_callee)
      if (e->callee == callee)
!       return e->inline_call;
    /* We do not record builtins in the callgraph.  Perhaps it would make more
       sense to do so and then prune out those not overwritten by explicit
       function body.  */
    return false;
  }
  /* Expand all functions that must be output.
--- 1354,1369 ----
  
    for (e = caller->callees; e; e = e->next_callee)
      if (e->callee == callee)
!       {
! 	if (e->inline_failed && reason)
! 	  *reason = e->inline_failed;
!         return !e->inline_failed;
!       }
    /* We do not record builtins in the callgraph.  Perhaps it would make more
       sense to do so and then prune out those not overwritten by explicit
       function body.  */
+   if (reason)
+     *reason = "originally indirect function calls never inlined";
    return false;
  }
  /* Expand all functions that must be output.
*************** cgraph_expand_all_functions (void)
*** 1340,1346 ****
  /* Mark all local functions.
  
     A local function is one whose calls can occur only in the
!    current compilation unit, so we change its calling convention.
     We simply mark all static functions whose address is not taken
     as local.  */
  
--- 1406,1413 ----
  /* Mark all local functions.
  
     A local function is one whose calls can occur only in the
!    current compilation unit and all it's calls are explicit,
!    so we can change its calling convention.
     We simply mark all static functions whose address is not taken
     as local.  */
  
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.88
diff -c -3 -p -r1.88 tree-inline.c
*** tree-inline.c	13 Nov 2003 20:50:40 -0000	1.88
--- tree-inline.c	3 Jan 2004 12:24:01 -0000
*************** expand_call_inline (tree *tp, int *walk_
*** 1247,1252 ****
--- 1247,1253 ----
    splay_tree st;
    tree args;
    tree return_slot_addr;
+   const char *reason;
  
    /* See what we've got.  */
    id = (inline_data *) data;
*************** expand_call_inline (tree *tp, int *walk_
*** 1327,1338 ****
  
    /* Don't try to inline functions that are not well-suited to
       inlining.  */
!   if (!DECL_SAVED_TREE (fn) || !cgraph_inline_p (id->current_decl, fn))
      {
!       if (warn_inline && DECL_INLINE (fn) && DECL_DECLARED_INLINE_P (fn)
! 	  && !DECL_IN_SYSTEM_HEADER (fn))
  	{
! 	  warning ("%Jinlining failed in call to '%F'", fn, fn);
  	  warning ("called from here");
  	}
        return NULL_TREE;
--- 1328,1340 ----
  
    /* Don't try to inline functions that are not well-suited to
       inlining.  */
!   if (!cgraph_inline_p (id->current_decl, fn, &reason))
      {
!       if (warn_inline && DECL_DECLARED_INLINE_P (fn)
! 	  && !DECL_IN_SYSTEM_HEADER (fn)
! 	  && strlen (reason))
  	{
! 	  warning ("%Jinlining failed in call to '%F': %s", fn, fn, reason);
  	  warning ("called from here");
  	}
        return NULL_TREE;



More information about the Gcc-patches mailing list