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]

Use -funit-at-a-time to inline functions called once


Hi,
this patch implements inlining of functions that are static, whose
address is not taken and are called just once.  I will send benchmarks
once they are finished, but earlier and less aggressive version of the
patch got about 0.5% improvement on SpecINT.

I am enabling the transformation at -O3 and -Os, in the case it will pay
back in bootstrap time, I would like to see it enabled at -O2 too, but
at the moment this looks too intrusive.

I've rearanged some code, so callgraph code has it's own header and the
datastructure is exported so we don't have to put everything into single
file.
I also added local and global data for each function.  I plan to add
also data used purely by rtl backend in near future.

The patch has bootstrapped/regtested i386 with -O3 OK?

Honza

/* { dg-options "-O2 -finline-functions-called-once" } */
/* { dg-final { scan-assembler-not "bit_function_2" } } */
static void
big_function_2(void);
void
big_function_1()
{
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	big_function_2();
}
void
big_function_2()
{
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
	while (t());
}
Tue Feb 18 13:52:22 CET 2003  Jan Hubicka  <jh@suse.cz>
	* 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.
	* cgraph.c (cgraph_node, cgraph_edge): Move into cgraph.h
	(cgraph_nodes, cgraph_n_nodes): Globalize.
	(cgraph_mark_functions_to_inline_once): New static function.
	(cgraph_optimize): Call it.
	(cgraph_finalize_function):  Set inlinable flags.
	(cgraph_node): Put nodes into doubly linked chain.
	(remove_node): New function.
	(cgraph_finalize_compilation_unit):  Actually remove the reclaimed nodes.
	(cgraph_mark_functions_to_output):  Use new inlining heuristics flags.
	(cgraph_expand_function): Likewise.
	(cgraph_local_info, cgraph_global_info): New global functions.
	* flags.h (flag_inline_functions_called_once): Declare.
	* toplev.c (flag_inline_functions_called_once): New global variable.
	(lang_independent-options): Add inline-functions-called-once.
	(parse_options_and_default_flags): Set flag_inline_functions_called_once
	for -O3 and -Os.
	(process_options): Imply flag_unit_at_a_time when needed.
	* tree-inline.c: Include cgraph.h
	(inlinable_functions_p): Add extra argument to bypass limits.
	(expand_call_inline):  Obey cgraph flag.
	* tree-inline.h (tree_inlinable_function_p): Update prototype.
	* tree.h (cgraph*): Move into cgraph.h
	* doc/invoke.texi (-finline-functions-called-once):  Document.
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.996
diff -c -3 -p -r1.996 Makefile.in
*** Makefile.in	16 Feb 2003 00:58:29 -0000	1.996
--- Makefile.in	18 Feb 2003 14:33:24 -0000
*************** $(parsedir)/c-parse.y: c-parse.in
*** 1221,1227 ****
  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
  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) \
--- 1221,1227 ----
  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 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) \
*************** c-lex.o : c-lex.c $(CONFIG_H) $(SYSTEM_H
*** 1233,1239 ****
  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)
  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) \
--- 1233,1239 ----
  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) 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) \
*************** tree-dump.o: tree-dump.c $(CONFIG_H) $(S
*** 1413,1419 ****
  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
  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) \
--- 1413,1419 ----
  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 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) \
*************** simplify-rtx.o : simplify-rtx.c $(CONFIG
*** 1531,1537 ****
     $(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)
  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
--- 1531,1537 ----
     $(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) 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: c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.363
diff -c -3 -p -r1.363 c-decl.c
*** c-decl.c	12 Feb 2003 21:48:56 -0000	1.363
--- c-decl.c	18 Feb 2003 14:33:27 -0000
*************** Software Foundation, 59 Temple Place - S
*** 48,53 ****
--- 48,54 ----
  #include "timevar.h"
  #include "c-common.h"
  #include "c-pragma.h"
+ #include "cgraph.h"
  
  /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
  enum decl_context
*************** finish_function (nested, can_defer_p)
*** 6441,6447 ****
  	     predicates depend on cfun and current_function_decl to
  	     function completely.  */
  	  timevar_push (TV_INTEGRATION);
! 	  uninlinable = ! tree_inlinable_function_p (fndecl);
  	  
  	  if (! uninlinable && can_defer_p
  	      /* Save function tree for inlining.  Should return 0 if the
--- 6442,6448 ----
  	     predicates depend on cfun and current_function_decl to
  	     function completely.  */
  	  timevar_push (TV_INTEGRATION);
! 	  uninlinable = ! tree_inlinable_function_p (fndecl, 0);
  	  
  	  if (! uninlinable && can_defer_p
  	      /* Save function tree for inlining.  Should return 0 if the
Index: c-objc-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.21
diff -c -3 -p -r1.21 c-objc-common.c
*** c-objc-common.c	12 Feb 2003 21:48:57 -0000	1.21
--- c-objc-common.c	18 Feb 2003 14:33:27 -0000
*************** Software Foundation, 59 Temple Place - S
*** 37,42 ****
--- 37,43 ----
  #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: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 cgraph.c
*** cgraph.c	13 Feb 2003 12:28:26 -0000	1.2
--- cgraph.c	18 Feb 2003 14:33:27 -0000
*************** Software Foundation, 59 Temple Place - S
*** 32,89 ****
  #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;
! };
  
  /* 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;
  
  /* Number of nodes in existence.  */
! static 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));
--- 32,56 ----
  #include "ggc.h"
  #include "debug.h"
  #include "target.h"
! #include "cgraph.h"
  
  /* Hash table used to convert declarations into nodes.  */
  static htab_t cgraph_hash = 0;
  
  /* The linked list of cgraph nodes.  */
! struct cgraph_node *cgraph_nodes;
  
  /* Number of nodes in existence.  */
! int cgraph_n_nodes;
! 
! /* Set to true once global info is propagated.  */
! static bool global_info_ready = false;
  
  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 void remove_node PARAMS ((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 void cgraph_expand_functions PARA
*** 93,98 ****
--- 60,66 ----
  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));
+ static void cgraph_mark_functions_to_inline_once PARAMS ((void));
  
  /* Returns a hash code for P.  */
  
*************** cgraph_node (decl)
*** 137,142 ****
--- 105,113 ----
    node = xcalloc (sizeof (*node), 1);
    node->decl = decl;
    node->next = cgraph_nodes;
+   if (cgraph_nodes)
+     cgraph_nodes->previous = node;
+   node->previous = NULL;
    cgraph_nodes = node;
    cgraph_n_nodes++;
    *slot = node;
*************** remove_edge (caller, callee)
*** 188,193 ****
--- 159,194 ----
    *edge2 = (*edge2)->next_callee;
  }
  
+ /* Remove the node from cgraph.  */
+ 
+ static void
+ remove_node (node)
+      struct cgraph_node *node;
+ {
+   while (node->callers)
+     remove_edge (node->callers->caller, node);
+   while (node->callees)
+     remove_edge (node, node->callees->callee);
+   while (node->nested)
+     remove_node (node->nested);
+   if (node->origin)
+     {
+       struct cgraph_node **node2 = &node->origin->nested;
+ 
+       while (*node2 != node)
+ 	node2 = &(*node2)->next_nested;
+       (*node2)->next_nested = node->next_nested;
+     }
+   if (node->previous)
+     node->previous->next = node->next;
+   else
+     cgraph_nodes = node;
+   if (node->next)
+     node->next->previous = node->previous;
+   DECL_SAVED_TREE (node->decl) = NULL;
+   /* Do not free the structure itself so the walk over chain can continue.  */
+ }
+ 
  /* Record call from CALLER to CALLEE  */
  
  static struct cgraph_edge *
*************** cgraph_finalize_function (decl, body)
*** 274,283 ****
  
    node->decl = decl;
  
-   /* Set TREE_UNINLINABLE flag.  */
-   tree_inlinable_function_p (decl);
- 
    (*debug_hooks->deferred_inline_function) (decl);
  }
  
  /* Dump the callgraph.  */
--- 275,286 ----
  
    node->decl = decl;
  
    (*debug_hooks->deferred_inline_function) (decl);
+ 
+   if (flag_inline_functions_called_once)
+     node->local.can_inline_single = tree_inlinable_function_p (decl, 1);
+   if (flag_inline_trees)
+     node->local.inline_many = tree_inlinable_function_p (decl, 0);
  }
  
  /* Dump the callgraph.  */
*************** cgraph_finalize_compilation_unit ()
*** 413,419 ****
  
        if (!node->reachable && DECL_SAVED_TREE (decl))
  	{
! 	  DECL_SAVED_TREE (decl) = NULL;
  	  announce_function (decl);
  	}
      }
--- 416,422 ----
  
        if (!node->reachable && DECL_SAVED_TREE (decl))
  	{
! 	  remove_node (node);
  	  announce_function (decl);
  	}
      }
*************** cgraph_mark_functions_to_output ()
*** 439,446 ****
  
        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;
--- 442,449 ----
  
        if (DECL_SAVED_TREE (decl)
  	  && (node->needed
! 	      || (!node->local.inline_many && !node->global.inline_single
! 		  && node->reachable))
  	  && !TREE_ASM_WRITTEN (decl) && !node->origin
  	  && !DECL_EXTERNAL (decl))
  	node->output = 1;
*************** cgraph_expand_function (node)
*** 458,464 ****
    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;
  }
--- 461,473 ----
    if (flag_inline_trees)
      optimize_inline_calls (decl);
    (*lang_hooks.callgraph.expand_function) (decl);
! 
!   /* When we decided to inline the function once, we never ever should need to
!      output it separately.  */
!   if (node->global.inline_single)
!     abort ();
!   if (!node->local.inline_many
!       || !node->callers)
      DECL_SAVED_TREE (decl) = NULL;
    current_function_decl = NULL;
  }
*************** cgraph_expand_functions ()
*** 528,533 ****
--- 537,607 ----
      }
  }
  
+ /*  Decide what function should be inlined because they are invoked once
+     (so inlining won't result in duplication of the code).  */
+ 
+ static void
+ cgraph_mark_functions_to_inline_once ()
+ {
+   struct cgraph_node *node, *node1;
+ 
+   if (!quiet_flag)
+     fprintf (stderr, "\n\nMarking functions to inline once:");
+ 
+   /* Now look for function called only once and mark them to inline.  From this
+      point number of calls to given function won't grow.  */
+   for (node = cgraph_nodes; node; node = node->next)
+     {
+       if (node->callers && !node->callers->next_caller && !node->needed
+ 	  && node->local.can_inline_single)
+ 	{
+ 	  bool ok = true;
+ 
+ 	  /* Verify that we won't duplicate the caller.  */
+ 	  for (node1 = node->callers->caller;
+ 	       node1->local.inline_many && node1->callers && ok;
+ 	       node1 = node1->callers->caller)
+ 	    if (node1->callers->next_caller)
+ 	      ok = false;
+ 	  if (ok)
+ 	    {
+ 	      node->global.inline_single = true;
+ 	      announce_function (node->decl);
+ 	    }
+ 	}
+     }
+ }
+ 
+ /* Return local info for the compiled function.  */
+ 
+ struct cgraph_local_info *
+ cgraph_local_info (decl)
+      tree decl;
+ {
+   struct cgraph_node *node;
+   if (TREE_CODE (decl) != FUNCTION_DECL)
+     abort ();
+   if (!DECL_SAVED_TREE (decl))
+     return NULL;
+   node = cgraph_node (decl);
+   return &node->local;
+ }
+ 
+ /* Return local info for the compiled function.  */
+ 
+ struct cgraph_global_info *
+ cgraph_global_info (decl)
+      tree decl;
+ {
+   struct cgraph_node *node;
+   if (TREE_CODE (decl) != FUNCTION_DECL || !global_info_ready)
+     abort ();
+   if (!DECL_SAVED_TREE (decl))
+     return NULL;
+   node = cgraph_node (decl);
+   return &node->global;
+ }
+ 
  /* Perform simple optimizations based on callgraph.  */
  
  void
*************** cgraph_optimize ()
*** 537,542 ****
--- 611,621 ----
    bool changed = true;
    struct cgraph_edge *edge;
  
+   if (flag_inline_functions_called_once)
+     cgraph_mark_functions_to_inline_once ();
+ 
+   global_info_ready = true;
+ 
    if (!quiet_flag)
      fprintf (stderr, "\n\nAssembling functions:");
  
*************** cgraph_optimize ()
*** 556,562 ****
  
  	  for (edge = node->callees; edge; edge = edge->next_callee)
  	    if (!edge->callee->needed)
! 	      changed = edge->callee->needed = true;
  	}
      }
    cgraph_expand_functions ();
--- 635,645 ----
  
  	  for (edge = node->callees; edge; edge = edge->next_callee)
  	    if (!edge->callee->needed)
! 	      {
! 		if (edge->callee->global.inline_single)
! 		  abort ();
! 	        changed = edge->callee->needed = true;
! 	      }
  	}
      }
    cgraph_expand_functions ();
Index: cgraph.h
===================================================================
RCS file: cgraph.h
diff -N cgraph.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- cgraph.h	18 Feb 2003 14:33:27 -0000
***************
*** 0 ****
--- 1,100 ----
+ /* 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
+ 
+ /* Information about the function collected locally.
+    Available after function is lowered  */
+ 
+ struct cgraph_local_info
+ {
+   bool can_inline_single;
+   bool inline_many;
+ };
+ 
+ /* Information about the function that needs to be computed globally
+    once compilation is finished.  Available only with -funit-at-time.  */
+ 
+ struct cgraph_global_info
+ {
+   bool inline_single;
+ };
+ 
+ /* 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;
+   struct cgraph_node *previous;
+   /* 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_local_info local;
+   struct cgraph_global_info global;
+ };
+ 
+ struct cgraph_edge
+ {
+   struct cgraph_node *caller, *callee;
+   struct cgraph_edge *next_caller;
+   struct cgraph_edge *next_callee;
+ };
+ 
+ /* The linked list of cgraph nodes.  */
+ extern struct cgraph_node *cgraph_nodes;
+ 
+ /* Number of nodes in existence.  */
+ extern int cgraph_n_nodes;
+ 
+ /* 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));
+ struct cgraph_local_info *cgraph_local_info PARAMS ((tree));
+ struct cgraph_global_info *cgraph_global_info PARAMS ((tree));
+ #endif  /* GCC_CGRAPH_H  */
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.98
diff -c -3 -p -r1.98 flags.h
*** flags.h	12 Feb 2003 21:48:57 -0000	1.98
--- flags.h	18 Feb 2003 14:33:27 -0000
*************** extern int flag_rerun_loop_opt;
*** 378,383 ****
--- 378,388 ----
  
  extern int flag_inline_functions;
  
+ /* Nonzero means to inline functions that are known to be called only
+    once independently on their size.  */
+ 
+ extern int flag_inline_functions_called_once;
+ 
  /* Nonzero for -fkeep-inline-functions: even if we make a function
     go inline everywhere, keep its definition around for debugging
     purposes.  */
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.709
diff -c -3 -p -r1.709 toplev.c
*** toplev.c	12 Feb 2003 21:48:57 -0000	1.709
--- toplev.c	18 Feb 2003 14:33:29 -0000
*************** int flag_rerun_loop_opt;
*** 668,673 ****
--- 668,678 ----
  
  int flag_inline_functions;
  
+ /* Nonzero for -finline-functions-called-once: ok to inline functions
+    that are known to be called just once independently on their size.  */
+ 
+ int flag_inline_functions_called_once;
+ 
  /* Nonzero for -fkeep-inline-functions: even if we make a function
     go inline everywhere, keep its definition around for debugging
     purposes.  */
*************** static const lang_independent_options f_
*** 1029,1034 ****
--- 1034,1041 ----
     N_("Allow function addresses to be held in registers") },
    {"inline-functions", &flag_inline_functions, 1,
     N_("Integrate simple functions into their callers") },
+   {"inline-functions-called-once", &flag_inline_functions_called_once, 1,
+    N_("Integrate functions into their callers when they are known to be called just once") },
    {"keep-inline-functions", &flag_keep_inline_functions, 1,
     N_("Generate code for funcs even if they are fully inlined") },
    {"inline", &flag_no_inline, 0,
*************** parse_options_and_default_flags (argc, a
*** 4950,4955 ****
--- 4957,4968 ----
        flag_inline_functions = 1;
        flag_rename_registers = 1;
        flag_unswitch_loops = 1;
+       flag_inline_functions_called_once = 1;
+     }
+ 
+   if (optimize_size)
+     {
+       flag_inline_functions_called_once = 1;
      }
  
    if (optimize < 2 || optimize_size)
*************** process_options ()
*** 5129,5134 ****
--- 5142,5152 ----
      flag_asynchronous_unwind_tables = 1;
    if (flag_asynchronous_unwind_tables)
      flag_unwind_tables = 1;
+ 
+   /* Unrolling all loops implies that standard loop unrolling must also
+      be done.  */
+   if (flag_inline_functions_called_once)
+     flag_unit_at_a_time = 1;
  
    /* Disable unit-at-a-time mode for frontends not supporting callgraph
       interface.  */
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.44
diff -c -3 -p -r1.44 tree-inline.c
*** tree-inline.c	12 Feb 2003 21:48:57 -0000	1.44
--- tree-inline.c	18 Feb 2003 14:33:30 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 37,42 ****
--- 37,43 ----
  #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.  */
*************** static tree copy_body_r PARAMS ((tree *,
*** 114,120 ****
  static tree copy_body PARAMS ((inline_data *));
  static tree expand_call_inline PARAMS ((tree *, int *, void *));
  static void expand_calls_inline PARAMS ((tree *, inline_data *));
! static int inlinable_function_p PARAMS ((tree, inline_data *));
  static tree remap_decl PARAMS ((tree, inline_data *));
  #ifndef INLINER_FOR_JAVA
  static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree));
--- 115,121 ----
  static tree copy_body PARAMS ((inline_data *));
  static tree expand_call_inline PARAMS ((tree *, int *, void *));
  static void expand_calls_inline PARAMS ((tree *, inline_data *));
! static int inlinable_function_p PARAMS ((tree, inline_data *, int));
  static tree remap_decl PARAMS ((tree, inline_data *));
  #ifndef INLINER_FOR_JAVA
  static tree initialize_inlined_parameters PARAMS ((inline_data *, tree, tree));
*************** declare_return_variable (id, return_slot
*** 871,880 ****
  /* Returns nonzero if a function can be inlined as a tree.  */
  
  int
! tree_inlinable_function_p (fn)
       tree fn;
  {
!   return inlinable_function_p (fn, NULL);
  }
  
  /* If *TP is possibly call to alloca, return nonzero.  */
--- 872,882 ----
  /* Returns nonzero if a function can be inlined as a tree.  */
  
  int
! tree_inlinable_function_p (fn, nolimit)
       tree fn;
+      int nolimit;
  {
!   return inlinable_function_p (fn, NULL, nolimit);
  }
  
  /* If *TP is possibly call to alloca, return nonzero.  */
*************** find_builtin_longjmp_call (exp)
*** 928,936 ****
     can be inlined at all.  */
  
  static int
! inlinable_function_p (fn, id)
       tree fn;
       inline_data *id;
  {
    int inlinable;
    int currfn_insns;
--- 930,939 ----
     can be inlined at all.  */
  
  static int
! inlinable_function_p (fn, id, nolimit)
       tree fn;
       inline_data *id;
+      int nolimit;
  {
    int inlinable;
    int currfn_insns;
*************** inlinable_function_p (fn, id)
*** 955,966 ****
       front-end that must set DECL_INLINE in this case, because
       dwarf2out loses if a function is inlined that doesn't have
       DECL_INLINE set.  */
!   else if (! DECL_INLINE (fn))
      ;
    /* We can't inline functions that are too big.  Only allow a single
       function to be of MAX_INLINE_INSNS_SINGLE size.  Make special
       allowance for extern inline functions, though.  */
    else if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
  	   && currfn_insns > MAX_INLINE_INSNS_SINGLE)
      ;
    /* We can't inline functions that call __builtin_longjmp at all.
--- 958,970 ----
       front-end that must set DECL_INLINE in this case, because
       dwarf2out loses if a function is inlined that doesn't have
       DECL_INLINE set.  */
!   else if (! DECL_INLINE (fn) && !nolimit)
      ;
    /* We can't inline functions that are too big.  Only allow a single
       function to be of MAX_INLINE_INSNS_SINGLE size.  Make special
       allowance for extern inline functions, though.  */
    else if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
+ 	   && !nolimit
  	   && currfn_insns > MAX_INLINE_INSNS_SINGLE)
      ;
    /* We can't inline functions that call __builtin_longjmp at all.
*************** inlinable_function_p (fn, id)
*** 991,997 ****
    /* In case we don't disregard the inlining limits and we basically
       can inline this function, investigate further.  */
    if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
!       && inlinable)
      {
        int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
  		     + currfn_insns;
--- 995,1001 ----
    /* In case we don't disregard the inlining limits and we basically
       can inline this function, investigate further.  */
    if (! (*lang_hooks.tree_inlining.disregard_inline_limits) (fn)
!       && inlinable && !nolimit)
      {
        int sum_insns = (id ? id->inlined_stmts : 0) * INSNS_PER_STMT
  		     + currfn_insns;
*************** expand_call_inline (tp, walk_subtrees, d
*** 1140,1146 ****
  
    /* Don't try to inline functions that are not well-suited to
       inlining.  */
!   if (!inlinable_function_p (fn, id))
      return NULL_TREE;
  
    if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
--- 1144,1152 ----
  
    /* Don't try to inline functions that are not well-suited to
       inlining.  */
!   if ((!flag_unit_at_a_time || !DECL_SAVED_TREE (fn)
!        || !cgraph_global_info (fn)->inline_single)
!       && !inlinable_function_p (fn, id, 0))
      return NULL_TREE;
  
    if (! (*lang_hooks.tree_inlining.start_inlining) (fn))
Index: tree-inline.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.h,v
retrieving revision 1.4
diff -c -3 -p -r1.4 tree-inline.h
*** tree-inline.h	31 May 2002 22:15:38 -0000	1.4
--- tree-inline.h	18 Feb 2003 14:33:30 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 25,31 ****
  /* Function prototypes.  */
  
  void optimize_inline_calls PARAMS ((tree));
! int tree_inlinable_function_p PARAMS ((tree));
  tree walk_tree PARAMS ((tree*, walk_tree_fn, void*, void*));
  tree walk_tree_without_duplicates PARAMS ((tree*, walk_tree_fn, void*));
  tree copy_tree_r PARAMS ((tree*, int*, void*));
--- 25,31 ----
  /* Function prototypes.  */
  
  void optimize_inline_calls PARAMS ((tree));
! int tree_inlinable_function_p PARAMS ((tree, int));
  tree walk_tree PARAMS ((tree*, walk_tree_fn, void*, void*));
  tree walk_tree_without_duplicates PARAMS ((tree*, walk_tree_fn, void*));
  tree copy_tree_r PARAMS ((tree*, int*, void*));
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.381
diff -c -3 -p -r1.381 tree.h
*** tree.h	12 Feb 2003 21:48:58 -0000	1.381
--- tree.h	18 Feb 2003 14:33:32 -0000
*************** extern const char *dump_flag_name	PARAMS
*** 3163,3178 ****
  /* Assign the RTX to declaration.  */
  
  extern void set_decl_rtl		PARAMS ((tree, rtx));
- 
- /* In callgraph.c  */
- void cgraph_finalize_function		PARAMS ((tree, tree));
- void cgraph_finalize_compilation_unit	PARAMS ((void));
- void cgraph_create_edges		PARAMS ((tree, tree));
- void dump_cgraph			PARAMS ((FILE *));
- void cgraph_optimize			PARAMS ((void));
- void cgraph_remove_call			PARAMS ((tree, tree));
- bool cgraph_calls_p			PARAMS ((tree, tree));
- 
  
  /* Redefine abort to report an internal error w/o coredump, and
     reporting the location of the error in the source file.  This logic
--- 3163,3168 ----
Index: cp/cfns.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cfns.h,v
retrieving revision 1.3
diff -c -3 -p -r1.3 cfns.h
*** cp/cfns.h	10 Jan 2003 20:49:29 -0000	1.3
--- cp/cfns.h	18 Feb 2003 14:33:33 -0000
***************
*** 1,5 ****
  /* C code produced by gperf version 2.7.2 */
! /* Command-line: gperf -o -C -E -k '1-6,$' -j1 -D -N libc_name_p ../../gcc/gcc/cp/cfns.gperf  */
  #ifdef __GNUC__
  __inline
  #endif
--- 1,5 ----
  /* C code produced by gperf version 2.7.2 */
! /* Command-line: gperf -o -C -E -k '1-6,$' -j1 -D -N libc_name_p ../../gcc/cp/cfns.gperf  */
  #ifdef __GNUC__
  __inline
  #endif
Index: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.242
diff -c -3 -p -r1.242 invoke.texi
*** doc/invoke.texi	16 Feb 2003 01:11:41 -0000	1.242
--- doc/invoke.texi	18 Feb 2003 14:33:35 -0000
*************** in the following sections.
*** 271,278 ****
  -fexpensive-optimizations  -ffast-math  -ffloat-store @gol
  -fforce-addr  -fforce-mem  -ffunction-sections @gol
  -fgcse  -fgcse-lm  -fgcse-sm -floop-optimize -fcrossjumping @gol
! -fif-conversion -fif-conversion2 @gol
! -finline-functions  -finline-limit=@var{n}  -fkeep-inline-functions @gol
  -fkeep-static-consts  -fmerge-constants  -fmerge-all-constants @gol
  -fmove-all-movables  -fnew-ra  -fno-branch-count-reg @gol
  -fno-default-inline  -fno-defer-pop @gol
--- 271,278 ----
  -fexpensive-optimizations  -ffast-math  -ffloat-store @gol
  -fforce-addr  -fforce-mem  -ffunction-sections @gol
  -fgcse  -fgcse-lm  -fgcse-sm -floop-optimize -fcrossjumping @gol
! -fif-conversion -fif-conversion2 -finline-functions @gol
! -finline-functions-called-once  -finline-limit=@var{n}  -fkeep-inline-functions @gol
  -fkeep-static-consts  -fmerge-constants  -fmerge-all-constants @gol
  -fmove-all-movables  -fnew-ra  -fno-branch-count-reg @gol
  -fno-default-inline  -fno-defer-pop @gol
*************** invoking @option{-O2} on programs that u
*** 3495,3501 ****
  @item -O3
  @opindex O3
  Optimize yet more.  @option{-O3} turns on all optimizations specified by
! @option{-O2} and also turns on the @option{-finline-functions} and
  @option{-frename-registers} options.
  
  @item -O0
--- 3495,3502 ----
  @item -O3
  @opindex O3
  Optimize yet more.  @option{-O3} turns on all optimizations specified by
! @option{-O2} and also turns on the @option{-finline-functions},
! @option{-finline-functions-called-once}, @option{-funswitch-loops} and
  @option{-frename-registers} options.
  
  @item -O0
*************** declared @code{static}, then the functio
*** 3602,3607 ****
--- 3603,3618 ----
  assembler code in its own right.
  
  Enabled at level @option{-O3}.
+ 
+ @item -finline-functions-called-once
+ @opindex finline-functions-called-once
+ Integrate all functions that are known to be called once and whose address is
+ not taken, so the out of line copy of function won't be needed anymore.
+ This should result in both smaller and faster programs in most cases.
+ 
+ Enabled at level @option{-O3} and @option{-Os}.  The function implies
+ @option{-funit-at-a-time} and has effect only for language frontends supporting
+ this mode.
  
  @item -finline-limit=@var{n}
  @opindex finline-limit


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