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]

IPA merge: cgraph_add_function improvement


Hi,
this patch make cgraph_add_new_function to work in more contextes than gomp.
We currently do add functions via cgraph_build_static_cdtor, via
cgraph_add_function and via clonning.  THis is somewhat painful as the
logic of what needs to be done is duplicated across those places and also
dependent on stage of compilation. 

This patch moves all the logic into one place so it is not dependent on
stage of compilation the function is called and form of function passed
to it and thus we can move passes around more easilly (on IPA-SSA I do
GOMP before inlining).  The function is inherently somewhat add-hoc (ie
whole plan behind cgraph was to make all functions to be noticed early),
but I hope to simplify it once IPA is more converted to pass manager and
add some ability to execute all local passes that should be done up to
current IPA pass.

Bootstrapped/regtested i686-linux, will commit it tomorrow if there are no
complains.

Honza

	* cgraph.c (cgraph_exapnd_queue): Rename to...
	(cgraph_new_nodes): ... this one.
	(cgraph_state): New global variable.
	(cgraph_add_new_function): Work in more cases.
	* cgraph.h (cgraph_expand_queue): Rename to ...
	(cgraph_new_nodes): ... this one.
	(cgraph_state): New enum and static variable.
	(cgraph_add_new_function): Update prototype.
	(cgraph_process_new_functions): New.
	* omp-low.c (expand_omp_parallel): Update.
	* cgraphunit.c (initialize_inline_failed): Declare early.
	(cgraph_process_new_functions): New function.
	(cgraph_assemble_pending_functions): Use it.
	(cgraph_expand_all_functions): Use it.
	(cgraph_optimize): Use it; set cgraph_state.
	* passes.c (execute_one_pass, execute_ipa_pass_list): Process new
	functions
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 120243)
--- cgraph.c	(working copy)
*************** struct cgraph_node *cgraph_nodes;
*** 97,106 ****
  /* Queue of cgraph nodes scheduled to be lowered.  */
  struct cgraph_node *cgraph_nodes_queue;
  
! /* Queue of cgraph nodes scheduled to be expanded.  This is a
     secondary queue used during optimization to accommodate passes that
     may generate new functions that need to be optimized and expanded.  */
! struct cgraph_node *cgraph_expand_queue;
  
  /* Number of nodes in existence.  */
  int cgraph_n_nodes;
--- 97,106 ----
  /* Queue of cgraph nodes scheduled to be lowered.  */
  struct cgraph_node *cgraph_nodes_queue;
  
! /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
     secondary queue used during optimization to accommodate passes that
     may generate new functions that need to be optimized and expanded.  */
! struct cgraph_node *cgraph_new_nodes;
  
  /* Number of nodes in existence.  */
  int cgraph_n_nodes;
*************** int cgraph_max_uid;
*** 111,116 ****
--- 111,119 ----
  /* Set when whole unit has been analyzed so we can access global info.  */
  bool cgraph_global_info_ready = false;
  
+ /* What state callgraph is in right now.  */
+ enum cgraph_state cgraph_state = CGRAPH_STATE_CONSTRUCTION;
+ 
  /* Set when the cgraph is fully build and the basic flags are computed.  */
  bool cgraph_function_flags_ready = false;
  
*************** cgraph_function_body_availability (struc
*** 911,933 ****
    return avail;
  }
  
! /* Add the function FNDECL to the call graph.  FNDECL is assumed to be
!    in low GIMPLE form and ready to be processed by cgraph_finalize_function.
  
!    When operating in unit-at-a-time, a new callgraph node is added to
!    CGRAPH_EXPAND_QUEUE, which is processed after all the original
!    functions in the call graph .
  
!    When not in unit-at-a-time, the new callgraph node is added to
!    CGRAPH_NODES_QUEUE for cgraph_assemble_pending_functions to
!    process.  */
  
  void
! cgraph_add_new_function (tree fndecl)
  {
!   struct cgraph_node *n = cgraph_node (fndecl);
!   n->next_needed = cgraph_expand_queue;
!   cgraph_expand_queue = n;
  }
  
  #include "gt-cgraph.h"
--- 914,973 ----
    return avail;
  }
  
! /* Add the function FNDECL to the call graph.
!    Unlike cgraph_finalize_function, this function is intended to be used
!    by middle end and allows insertion of new function at arbitrary point
!    of compilation.  The function can be either in high, low or SSA form
!    GIMPLE.
  
!    The function is assumed to be reachable and have address taken (so no
!    API breaking optimizations are performed on it).  
  
!    Main work done by this function is to enqueue the function for later
!    processing to avoid need the passes to be re-entrant.  */
  
  void
! cgraph_add_new_function (tree fndecl, bool lowered)
  {
!   struct cgraph_node *node;
!   switch (cgraph_state)
!     {
!       case CGRAPH_STATE_CONSTRUCTION:
! 	/* Just enqueue function to be processed at nearest occurence.  */
! 	node = cgraph_node (fndecl);
! 	node->next_needed = cgraph_new_nodes;
! 	if (lowered)
! 	  node->lowered = true;
! 	cgraph_new_nodes = node;
!         break;
! 
!       case CGRAPH_STATE_IPA:
!       case CGRAPH_STATE_EXPANSION:
! 	/* Bring the function into finalized state and enqueue for later
! 	   analyzing and compilation.  */
! 	node = cgraph_node (fndecl);
! 	node->local.local = false;
! 	node->local.finalized = true;
! 	node->reachable = node->needed = true;
! 	if (lowered)
! 	  node->lowered = true;
! 	node->next_needed = cgraph_new_nodes;
! 	cgraph_new_nodes = node;
!         break;
! 
!       case CGRAPH_STATE_FINISHED:
! 	/* At the very end of compilation we have to do all the work up
! 	   to expansion.  */
! 	push_cfun (DECL_STRUCT_FUNCTION (fndecl));
! 	current_function_decl = fndecl;
! 	tree_register_cfg_hooks ();
! 	if (!lowered)
!           tree_lowering_passes (fndecl);
! 	tree_rest_of_compilation (fndecl);
! 	pop_cfun ();
! 	current_function_decl = NULL;
! 	break;
!     }
  }
  
  #include "gt-cgraph.h"
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 120243)
--- cgraph.h	(working copy)
*************** extern GTY(()) struct cgraph_node *cgrap
*** 254,262 ****
  extern GTY(()) int cgraph_n_nodes;
  extern GTY(()) int cgraph_max_uid;
  extern bool cgraph_global_info_ready;
  extern bool cgraph_function_flags_ready;
  extern GTY(()) struct cgraph_node *cgraph_nodes_queue;
! extern GTY(()) struct cgraph_node *cgraph_expand_queue;
  
  extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
  extern GTY(()) int cgraph_order;
--- 254,274 ----
  extern GTY(()) int cgraph_n_nodes;
  extern GTY(()) int cgraph_max_uid;
  extern bool cgraph_global_info_ready;
+ enum cgraph_state
+ {
+   /* Callgraph is being constructed.  It is safe to add new functions.  */
+   CGRAPH_STATE_CONSTRUCTION,
+   /* Callgraph is built and IPA passes are being run.  */
+   CGRAPH_STATE_IPA,
+   /* Functions are now ordered and being passed to RTL expanders.  */
+   CGRAPH_STATE_EXPANSION,
+   /* All cgraph expansion is done.  */
+   CGRAPH_STATE_FINISHED
+ };
+ extern enum cgraph_state cgraph_state;
  extern bool cgraph_function_flags_ready;
  extern GTY(()) struct cgraph_node *cgraph_nodes_queue;
! extern GTY(()) struct cgraph_node *cgraph_new_nodes;
  
  extern GTY(()) struct cgraph_asm_node *cgraph_asm_nodes;
  extern GTY(()) int cgraph_order;
*************** void cgraph_unnest_node (struct cgraph_n
*** 295,301 ****
  enum availability cgraph_function_body_availability (struct cgraph_node *);
  bool cgraph_is_master_clone (struct cgraph_node *);
  struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
! void cgraph_add_new_function (tree);
  
  /* In cgraphunit.c  */
  void cgraph_finalize_function (tree, bool);
--- 307,313 ----
  enum availability cgraph_function_body_availability (struct cgraph_node *);
  bool cgraph_is_master_clone (struct cgraph_node *);
  struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
! void cgraph_add_new_function (tree, bool);
  
  /* In cgraphunit.c  */
  void cgraph_finalize_function (tree, bool);
*************** struct cgraph_node *cgraph_function_vers
*** 316,321 ****
--- 328,334 ----
  void cgraph_analyze_function (struct cgraph_node *);
  struct cgraph_node *save_inline_function_body (struct cgraph_node *);
  void record_references_in_initializer (tree);
+ bool cgraph_process_new_functions (void);
  
  /* In ipa.c  */
  bool cgraph_remove_unreachable_nodes (bool, FILE *);
Index: omp-low.c
===================================================================
*** omp-low.c	(revision 120243)
--- omp-low.c	(working copy)
*************** expand_omp_parallel (struct omp_region *
*** 2533,2539 ****
  	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
        DECL_STRUCT_FUNCTION (child_fn)->curr_properties
  	= cfun->curr_properties;
!       cgraph_add_new_function (child_fn);
  
        /* Convert OMP_RETURN into a RETURN_EXPR.  */
        if (exit_bb)
--- 2533,2539 ----
  	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
        DECL_STRUCT_FUNCTION (child_fn)->curr_properties
  	= cfun->curr_properties;
!       cgraph_add_new_function (child_fn, true);
  
        /* Convert OMP_RETURN into a RETURN_EXPR.  */
        if (exit_bb)
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 120243)
--- cgraphunit.c	(working copy)
*************** static void cgraph_expand_function (stru
*** 167,172 ****
--- 167,173 ----
  static tree record_reference (tree *, int *, void *);
  static void cgraph_output_pending_asms (void);
  static void cgraph_increase_alignment (void);
+ static void initialize_inline_failed (struct cgraph_node *);
  
  /* Records tree nodes seen in record_reference.  Simply using
     walk_tree_without_duplicates doesn't guarantee each node is visited
*************** decide_is_function_needed (struct cgraph
*** 262,267 ****
--- 263,339 ----
    return false;
  }
  
+ /* Process CGRAPH_NEW_FUNCTIONS and perform actions neccesary to add these
+    functions into callgraph in a way so they look like ordinary reachable
+    functions inserted into callgraph already at construction time.  */
+ 
+ bool
+ cgraph_process_new_functions (void)
+ {
+   bool output = false;
+   tree fndecl;
+   struct cgraph_node *node;
+ 
+   /*  Note that this queue may grow as its being processed, as the new
+       functions may generate new ones.  */
+   while (cgraph_new_nodes)
+     {
+       node = cgraph_new_nodes;
+       fndecl = node->decl;
+       cgraph_new_nodes = cgraph_new_nodes->next_needed;
+       switch (cgraph_state)
+ 	{
+ 	case CGRAPH_STATE_CONSTRUCTION:
+ 	  /* At construction time we just need to finalize function and move
+ 	     it into reachable functions list.  */
+ 
+ 	  node->next_needed = NULL;
+ 	  cgraph_finalize_function (fndecl, false);
+ 	  cgraph_mark_reachable_node (node);
+ 	  output = true;
+ 	  break;
+ 
+ 	case CGRAPH_STATE_IPA:
+ 	  /* When IPA optimization already started, do all essential
+ 	     transformations that has been already performed on the whole
+ 	     cgraph but not on this function.  */
+ 
+ 	  tree_register_cfg_hooks ();
+ 	  if (!node->analyzed)
+ 	    cgraph_analyze_function (node);
+ 	  push_cfun (DECL_STRUCT_FUNCTION (fndecl));
+ 	  current_function_decl = fndecl;
+ 	  node->local.inlinable = tree_inlinable_function_p (fndecl);
+ 	  node->local.self_insns = estimate_num_insns (fndecl);
+ 	  node->local.disregard_inline_limits
+ 	    = lang_hooks.tree_inlining.disregard_inline_limits (fndecl);
+ 	  /* Inlining characteristics are maintained by the
+ 	     cgraph_mark_inline.  */
+ 	  node->global.insns = node->local.self_insns;
+ 	  initialize_inline_failed (node);
+ 	  if (flag_really_no_inline && !node->local.disregard_inline_limits)
+ 	     node->local.inlinable = 0;
+ 	  free_dominance_info (CDI_POST_DOMINATORS);
+ 	  free_dominance_info (CDI_DOMINATORS);
+ 	  pop_cfun ();
+ 	  current_function_decl = NULL;
+ 	  break;
+ 
+ 	case CGRAPH_STATE_EXPANSION:
+ 	  /* Functions created during expansion shall be compiled
+ 	     directly.  */
+ 	  node->output = 0;
+ 	  cgraph_expand_function (node);
+ 	  break;
+ 
+ 	default:
+ 	  gcc_unreachable ();
+ 	  break;
+ 	}
+     }
+   return output;
+ }
+ 
  /* When not doing unit-at-a-time, output all functions enqueued.
     Return true when such a functions were found.  */
  
*************** cgraph_assemble_pending_functions (void)
*** 288,305 ****
  	  cgraph_expand_function (n);
  	  output = true;
  	}
!     }
! 
!   /* Process CGRAPH_EXPAND_QUEUE, these are functions created during
!      the expansion process.  Note that this queue may grow as its
!      being processed, as the new functions may generate new ones.  */
!   while (cgraph_expand_queue)
!     {
!       struct cgraph_node *n = cgraph_expand_queue;
!       cgraph_expand_queue = cgraph_expand_queue->next_needed;
!       n->next_needed = NULL;
!       cgraph_finalize_function (n->decl, false);
!       output = true;
      }
  
    return output;
--- 360,366 ----
  	  cgraph_expand_function (n);
  	  output = true;
  	}
!       output |= cgraph_process_new_functions ();
      }
  
    return output;
*************** cgraph_expand_all_functions (void)
*** 1159,1181 ****
  	  gcc_assert (node->reachable);
  	  node->output = 0;
  	  cgraph_expand_function (node);
  	}
      }
  
    free (order);
  
-   /* Process CGRAPH_EXPAND_QUEUE, these are functions created during
-      the expansion process.  Note that this queue may grow as its
-      being processed, as the new functions may generate new ones.  */
-   while (cgraph_expand_queue)
-     {
-       node = cgraph_expand_queue;
-       cgraph_expand_queue = cgraph_expand_queue->next_needed;
-       node->next_needed = NULL;
-       node->output = 0;
-       node->lowered = DECL_STRUCT_FUNCTION (node->decl)->cfg != NULL;
-       cgraph_expand_function (node);
-     }
  }
  
  /* This is used to sort the node types by the cgraph order number.  */
--- 1229,1241 ----
  	  gcc_assert (node->reachable);
  	  node->output = 0;
  	  cgraph_expand_function (node);
+ 	  cgraph_process_new_functions ();
  	}
      }
+   cgraph_process_new_functions ();
  
    free (order);
  
  }
  
  /* This is used to sort the node types by the cgraph order number.  */
*************** cgraph_optimize (void)
*** 1383,1388 ****
--- 1443,1451 ----
  #endif
    if (!flag_unit_at_a_time)
      {
+       cgraph_assemble_pending_functions ();
+       cgraph_process_new_functions ();
+       cgraph_state = CGRAPH_STATE_FINISHED;
        cgraph_output_pending_asms ();
        varpool_assemble_pending_decls ();
        varpool_output_debug_info ();
*************** cgraph_optimize (void)
*** 1408,1413 ****
--- 1471,1477 ----
        fprintf (cgraph_dump_file, "Marked ");
        dump_cgraph (cgraph_dump_file);
      }
+   cgraph_state = CGRAPH_STATE_IPA;
      
    /* Don't run the IPA passes if there was any error or sorry messages.  */
    if (errorcount == 0 && sorrycount == 0)
*************** cgraph_optimize (void)
*** 1440,1445 ****
--- 1504,1510 ----
  
    cgraph_mark_functions_to_output ();
  
+   cgraph_state = CGRAPH_STATE_EXPANSION;
    if (!flag_toplevel_reorder)
      cgraph_output_in_order ();
    else
*************** cgraph_optimize (void)
*** 1452,1457 ****
--- 1517,1524 ----
        varpool_assemble_pending_decls ();
        varpool_output_debug_info ();
      }
+   cgraph_process_new_functions ();
+   cgraph_state = CGRAPH_STATE_FINISHED;
  
    if (cgraph_dump_file)
      {
*************** cgraph_build_static_cdtor (char which, t
*** 1581,1594 ****
  
    gimplify_function_tree (decl);
  
!   /* ??? We will get called LATE in the compilation process.  */
!   if (cgraph_global_info_ready)
!     {
!       tree_lowering_passes (decl);
!       tree_rest_of_compilation (decl);
!     }
!   else
!     cgraph_finalize_function (decl, 0);
  
    if (targetm.have_ctors_dtors)
      {
--- 1648,1655 ----
  
    gimplify_function_tree (decl);
  
!   cgraph_add_new_function (decl, false);
!   cgraph_mark_needed_node (cgraph_node (decl));
  
    if (targetm.have_ctors_dtors)
      {
Index: passes.c
===================================================================
*** passes.c	(revision 120243)
--- passes.c	(working copy)
*************** execute_one_pass (struct tree_opt_pass *
*** 947,952 ****
--- 947,955 ----
    /* Run post-pass cleanup and verification.  */
    execute_todo (todo_after | pass->todo_flags_finish);
  
+   if (!current_function_decl)
+     cgraph_process_new_functions ();
+ 
    /* Flush and close dump file.  */
    if (dump_file_name)
      {
*************** execute_ipa_pass_list (struct tree_opt_p
*** 986,991 ****
--- 989,996 ----
        gcc_assert (!cfun);
        if (execute_one_pass (pass) && pass->sub)
  	do_per_function ((void (*)(void *))execute_pass_list, pass->sub);
+       if (!current_function_decl)
+ 	cgraph_process_new_functions ();
        pass = pass->next;
      }
    while (pass);


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