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]

Some additional cgraph infrastructure


Hi,
this patch adds few infrastructure bits needed by Kenny's aliasing code.  There
is now availability notion on cgraph/varpool nodes so IPA passes can more
easilly decide what asusmption about the function/variable can be made.  Also
Kenny's code needs to maintain datastructures common for all inline clones.
While we seem to head in direction whre inlining is fully done before further
IPA passes so we won't see them, for now there is notion of master clone
that can be used to store data in.

Bootstrapped/regtested i686-pc-gnu-linux, will commit it shortly.

Kenny: I killed some bits from you original merge patch.  Mainly the cycle
variables as it don't make sense to have the field without the detector itself
(it might make sense to put this in in separate patch too) and the datastructures
used only by AA.  Just bring them in when they are needed.

2005-06-02  Jan Hubicka  <jh@suse.cz>
            Kenneth Zadeck <zadeck@naturalbridge.com>
	* cgraph.c (cgraph_node): Maintain master clones.
	(cgraph_remove_node): Likewise.
	(availability_names): New static variable.
	(dump_cgraph_node): Dump availability.
	(dump_cgraph_varpool_node): Likewise.
	(cgraph_is_master_clone, cgraph_master_clone,
	cgraph_function_body_availability,
	cgraph_variable_initializer_availability): New functions.
	* cgraph.h (availability): New enum.
	(struct cgraph_node): Add master_clone.
	(cgraph_is_master_clone, cgraph_master_clone,
	cgraph_function_body_availability,
	cgraph_variable_initializer_availability): Declare.
	* cgraphunit.c (cgraph_expand_function): Setcgraph_function_flags_ready.
	(cgraph_remove_unreachable_nodes): Remove unreachable nodes.
	* ipa-inline.c (cgraph_decide_inlining): Do not call
	cgraph_remove_unreachable_nodes.
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.75
diff -c -3 -p -r1.75 cgraph.c
*** cgraph.c	2 Jun 2005 10:59:00 -0000	1.75
--- cgraph.c	2 Jun 2005 12:44:11 -0000
*************** cgraph_node (tree decl)
*** 192,198 ****
    slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
  
    if (*slot)
!     return *slot;
  
    node = cgraph_create_node ();
    node->decl = decl;
--- 192,203 ----
    slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT);
  
    if (*slot)
!     {
!       node = *slot;
!       if (!node->master_clone)
! 	node->master_clone = node;
!       return node;
!     }
  
    node = cgraph_create_node ();
    node->decl = decl;
*************** cgraph_node (tree decl)
*** 202,207 ****
--- 207,213 ----
        node->origin = cgraph_node (DECL_CONTEXT (decl));
        node->next_nested = node->origin->nested;
        node->origin->nested = node;
+       node->master_clone = node;
      }
    return node;
  }
*************** cgraph_remove_node (struct cgraph_node *
*** 436,442 ****
      {
        if (node->next_clone)
        {
! 	*slot = node->next_clone;
  	node->next_clone->prev_clone = NULL;
        }
        else
--- 442,455 ----
      {
        if (node->next_clone)
        {
! 	struct cgraph_node *new_node = node->next_clone;
! 	struct cgraph_node *n;
! 
! 	/* Make the next clone be the master clone */
! 	for (n = new_node; n; n = n->next_clone) 
! 	  n->master_clone = new_node;
! 	
! 	*slot = new_node;
  	node->next_clone->prev_clone = NULL;
        }
        else
*************** cgraph_varpool_node_name (struct cgraph_
*** 553,558 ****
--- 566,575 ----
    return lang_hooks.decl_printable_name (node->decl, 2);
  }
  
+ /* Names used to print out the availability enum.  */
+ static const char * const availability_names[] = 
+   {"unset", "not_available", "overwrittable", "available", "local"};
+ 
  /* Dump given cgraph node.  */
  void
  dump_cgraph_node (FILE *f, struct cgraph_node *node)
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 563,568 ****
--- 580,590 ----
      fprintf (f, " (inline copy in %s/%i)",
  	     cgraph_node_name (node->global.inlined_to),
  	     node->global.inlined_to->uid);
+   if (cgraph_function_flags_ready)
+     fprintf (f, " availability:%s", 
+ 	     availability_names [cgraph_function_body_availability (node)]);
+   if (node->master_clone && node->master_clone->uid != node->uid)
+     fprintf (f, "(%i)", node->master_clone->uid);
    if (node->count)
      fprintf (f, " executed "HOST_WIDEST_INT_PRINT_DEC"x",
  	     (HOST_WIDEST_INT)node->count);
*************** dump_cgraph_node (FILE *f, struct cgraph
*** 614,619 ****
--- 636,646 ----
  	       edge->callee->uid);
        if (!edge->inline_failed)
  	fprintf(f, "(inlined) ");
+       if (edge->count)
+ 	fprintf (f, "("HOST_WIDEST_INT_PRINT_DEC"x) ",
+ 		 (HOST_WIDEST_INT)edge->count);
+       if (edge->loop_nest)
+ 	fprintf (f, "(nested in %i loops) ", edge->loop_nest);
      }
    fprintf (f, "\n");
  }
*************** void
*** 635,640 ****
--- 662,668 ----
  dump_cgraph_varpool_node (FILE *f, struct cgraph_varpool_node *node)
  {
    fprintf (f, "%s:", cgraph_varpool_node_name (node));
+   fprintf (f, " availability:%s", availability_names [cgraph_variable_initializer_availability (node)]);
    if (DECL_INITIAL (node->decl))
      fprintf (f, " initialized");
    if (node->needed)
*************** cgraph_clone_node (struct cgraph_node *n
*** 886,891 ****
--- 914,920 ----
    new->local = n->local;
    new->global = n->global;
    new->rtl = n->rtl;
+   new->master_clone = n->master_clone;
    new->count = count;
    if (n->count)
      count_scale = new->count * REG_BR_PROB_BASE / n->count;
*************** cgraph_clone_node (struct cgraph_node *n
*** 905,910 ****
--- 934,961 ----
    return new;
  }
  
+ /* Return true if N is an master_clone, (see cgraph_master_clone).  */
+ 
+ bool
+ cgraph_is_master_clone (struct cgraph_node *n)
+ {
+   return (n == cgraph_master_clone (n));
+ }
+ 
+ struct cgraph_node *
+ cgraph_master_clone (struct cgraph_node *n)
+ {
+   enum availability avail = cgraph_function_body_availability (n);
+    
+   if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
+     return NULL;
+ 
+   if (!n->master_clone) 
+     n->master_clone = cgraph_node (n->decl);
+   
+   return n->master_clone;
+ }
+ 
  /* NODE is no longer nested function; update cgraph accordingly.  */
  void
  cgraph_unnest_node (struct cgraph_node *node)
*************** cgraph_unnest_node (struct cgraph_node *
*** 917,920 ****
--- 968,1027 ----
    *node2 = node->next_nested;
    node->origin = NULL;
  }
+ 
+ /* Return function availability.  See cgraph.h for description of individual
+    return values.  */
+ enum availability
+ cgraph_function_body_availability (struct cgraph_node *node)
+ {
+   enum availability avail;
+   gcc_assert (cgraph_function_flags_ready);
+   if (!node->local.finalized)
+     avail = AVAIL_NOT_AVAILABLE;
+   else if (node->local.local)
+     avail = AVAIL_LOCAL;
+   else if (node->local.externally_visible)
+     avail = AVAIL_AVAILABLE;
+ 
+   /* If the function can be overwritten, return OVERWRITABLE.  Take
+      care at least of two notable extensions - the COMDAT functions
+      used to share template instantiations in C++ (this is symmetric
+      to code cp_cannot_inline_tree_fn and probably shall be shared and
+      the inlinability hooks completelly elliminated).
+ 
+      ??? Does the C++ one definition rule allow us to always return
+      AVAIL_AVAILABLE here?  That would be good reason to preserve this
+      hook Similarly deal with extern inline functions - this is again
+      neccesary to get C++ shared functions having keyed templates
+      right and in the C extension documentation we probably should
+      document the requirement of both versions of function (extern
+      inline and offline) having same side effect characteristics as
+      good optimization is what this optimization is about.  */
+   
+   else if (!(*targetm.binds_local_p) (node->decl)
+ 	   && !DECL_COMDAT (node->decl) && !DECL_EXTERNAL (node->decl))
+     avail = AVAIL_OVERWRITABLE;
+   else avail = AVAIL_AVAILABLE;
+ 
+   return avail;
+ }
+ 
+ /* Return variable availability.  See cgraph.h for description of individual
+    return values.  */
+ enum availability
+ cgraph_variable_initializer_availability (struct cgraph_varpool_node *node)
+ {
+   gcc_assert (cgraph_function_flags_ready);
+   if (!node->finalized)
+     return AVAIL_NOT_AVAILABLE;
+   if (!TREE_PUBLIC (node->decl))
+     return AVAIL_AVAILABLE;
+   /* If the variable can be overwritted, return OVERWRITABLE.  Takes
+      care of at least two notable extensions - the COMDAT variables
+      used to share template instantiations in C++.  */
+   if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
+     return AVAIL_OVERWRITABLE;
+   return AVAIL_AVAILABLE;
+ }
+ 
  #include "gt-cgraph.h"
Index: cgraph.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.h,v
retrieving revision 1.56
diff -c -3 -p -r1.56 cgraph.h
*** cgraph.h	2 Jun 2005 10:59:00 -0000	1.56
--- cgraph.h	2 Jun 2005 12:44:11 -0000
*************** Software Foundation, 59 Temple Place - S
*** 24,29 ****
--- 24,51 ----
  #include "tree.h"
  #include "basic-block.h"
  
+ enum availability
+ {
+   /* Not yet set by cgraph_function_body_availability.  */
+   AVAIL_UNSET,
+   /* Function body/variable initializer is unknown.  */
+   AVAIL_NOT_AVAILABLE,
+   /* Function body/variable initializer is known but might be replaced
+      by a different one from other compilation unit and thus needs to
+      be dealt with a care.  Like AVAIL_NOT_AVAILABLE it can have
+      arbitrary side effects on escaping variables and functions, while
+      like AVAILABLE it might access static variables.  */
+   AVAIL_OVERWRITABLE,
+   /* Function body/variable initializer is known and will be used in final
+      program.  */
+   AVAIL_AVAILABLE,
+   /* Function body/variable initializer is known and all it's uses are explicitly
+      visible within current unit (ie it's address is never taken and it is not
+      exported to other units).
+      Currently used only for functions.  */
+   AVAIL_LOCAL
+ };
+ 
  /* Information about the function collected locally.
     Available after function is analyzed.  */
  
*************** struct cgraph_node GTY((chain_next ("%h.
*** 110,115 ****
--- 132,141 ----
    /* Pointer to the next clone.  */
    struct cgraph_node *next_clone;
    struct cgraph_node *prev_clone;
+   /* Pointer to a single unique cgraph node for this function.  If the
+      function is to be output, this is the copy that will survive.  */
+   struct cgraph_node *master_clone;
+  
    PTR GTY ((skip)) aux;
  
    struct cgraph_local_info local;
*************** struct cgraph_varpool_node GTY(())
*** 178,184 ****
    bool analyzed;
    /* Set once it has been finalized so we consider it to be output.  */
    bool finalized;
!   /* Set when function is scheduled to be assembled.  */
    bool output;
    /* Set when function is visible by other units.  */
    bool externally_visible;
--- 204,210 ----
    bool analyzed;
    /* Set once it has been finalized so we consider it to be output.  */
    bool finalized;
!   /* Set when variable is scheduled to be assembled.  */
    bool output;
    /* Set when function is visible by other units.  */
    bool externally_visible;
*************** void cgraph_varpool_enqueue_needed_node 
*** 229,234 ****
--- 255,265 ----
  void cgraph_varpool_reset_queue (void);
  bool decide_is_variable_needed (struct cgraph_varpool_node *, tree);
  
+ enum availability cgraph_function_body_availability (struct cgraph_node *);
+ enum availability cgraph_variable_initializer_availability (struct cgraph_varpool_node *);
+ bool cgraph_is_master_clone (struct cgraph_node *);
+ struct cgraph_node *cgraph_master_clone (struct cgraph_node *);
+ 
  /* In cgraphunit.c  */
  bool cgraph_assemble_pending_functions (void);
  bool cgraph_varpool_assemble_pending_decls (void);
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.111
diff -c -3 -p -r1.111 cgraphunit.c
*** cgraphunit.c	2 Jun 2005 10:59:00 -0000	1.111
--- cgraphunit.c	2 Jun 2005 12:44:11 -0000
*************** cgraph_expand_function (struct cgraph_no
*** 967,972 ****
--- 967,974 ----
  	 points to the dead function body.  */
        cgraph_node_remove_callees (node);
      }
+ 
+   cgraph_function_flags_ready = true;
  }
  
  /* Return true when CALLER_DECL should be inlined into CALLEE_DECL.  */
*************** cgraph_optimize (void)
*** 1128,1133 ****
--- 1130,1138 ----
        dump_cgraph (cgraph_dump_file);
      }
    ipa_passes ();
+   /* This pass remove bodies of extern inline functions we never inlined.
+      Do this later so other IPA passes see what is really going on.  */
+   cgraph_remove_unreachable_nodes (false, dump_file);
    cgraph_global_info_ready = true;
    if (cgraph_dump_file)
      {
Index: ipa-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ipa-inline.c,v
retrieving revision 2.7
diff -c -3 -p -r2.7 ipa-inline.c
*** ipa-inline.c	29 May 2005 19:38:32 -0000	2.7
--- ipa-inline.c	2 Jun 2005 12:44:11 -0000
*************** cgraph_decide_inlining (void)
*** 857,868 ****
  	}
      }
  
-   /* We will never output extern functions we didn't inline. 
-      ??? Perhaps we can prevent accounting of growth of external
-      inline functions.  */
- 
-   cgraph_remove_unreachable_nodes (false, dump_file);
- 
    if (dump_file)
      fprintf (dump_file,
  	     "\nInlined %i calls, eliminated %i functions, "
--- 857,862 ----


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