Symtab cleanups 10/17 - ipa ref verifier

Jan Hubicka hubicka@ucw.cz
Thu Aug 8 14:26:00 GMT 2013


Hi,
this patch implements (very basic) IPA REF verifier. It only checks if all references
corresopnds to a real statement. It does not yet check if all statements have proper
references attached to them. 
Even this simple testing found quite few positives where we leave stale references in
callgraph. Fixed thus.

Bootstrapped/regtested x86_64-linux, commited. Hope there won't be too much of other
positives ;)

	* cgraphbuild.c (build_cgraph_edges): Do not walk into debugs.
	(make_pass_rebuild_cgraph_edges): Also clear references.
	* cgraph.c (verify_cgraph_node): Add basic ipa-ref verifier.
	* ipa-inline-transform.c (inline_transform): Remove all references
	after inlining.
	* cgraphunit.c (expand_function): Remove all references after expansion.
	* ipa-ref.c (ipa_ref_has_aliases_p): Fix formatting.
	(ipa_find_reference): Rewrite to iterator.
	(remove_stmt_references): Likewise.
	(ipa_clear_stmts_in_references): New function.
	* ipa-ref.h (ipa_clear_stmts_in_references): Declare.
	* cgraphclones.c (cgraph_materialize_all_clones): Remove or clear references.
	* ipa-split.c (split_function): Remove references in split function.
Index: cgraphbuild.c
===================================================================
*** cgraphbuild.c	(revision 201568)
--- cgraphbuild.c	(working copy)
*************** build_cgraph_edges (void)
*** 318,323 ****
--- 318,326 ----
  	  gimple stmt = gsi_stmt (gsi);
  	  tree decl;
  
+ 	  if (is_gimple_debug (stmt))
+ 	    continue;
+ 
  	  if (is_gimple_call (stmt))
  	    {
  	      int freq = compute_call_stmt_bb_frequency (current_function_decl,
*************** make_pass_rebuild_cgraph_edges (gcc::con
*** 537,543 ****
  static unsigned int
  remove_cgraph_callee_edges (void)
  {
!   cgraph_node_remove_callees (cgraph_get_node (current_function_decl));
    return 0;
  }
  
--- 540,548 ----
  static unsigned int
  remove_cgraph_callee_edges (void)
  {
!   struct cgraph_node *node = cgraph_get_node (current_function_decl);
!   cgraph_node_remove_callees (node);
!   ipa_remove_all_references (&node->symbol.ref_list);
    return 0;
  }
  
Index: cgraph.c
===================================================================
*** cgraph.c	(revision 201568)
--- cgraph.c	(working copy)
*************** verify_cgraph_node (struct cgraph_node *
*** 2537,2591 ****
      {
        if (this_cfun->cfg)
  	{
  	  /* Reach the trees by walking over the CFG, and note the
  	     enclosing basic-blocks in the call edges.  */
  	  FOR_EACH_BB_FN (this_block, this_cfun)
! 	    for (gsi = gsi_start_bb (this_block);
!                  !gsi_end_p (gsi);
!                  gsi_next (&gsi))
! 	      {
! 		gimple stmt = gsi_stmt (gsi);
! 		if (is_gimple_call (stmt))
! 		  {
! 		    struct cgraph_edge *e = cgraph_edge (node, stmt);
! 		    tree decl = gimple_call_fndecl (stmt);
! 		    if (e)
! 		      {
! 			if (e->aux)
! 			  {
! 			    error ("shared call_stmt:");
! 			    cgraph_debug_gimple_stmt (this_cfun, stmt);
! 			    error_found = true;
! 			  }
! 			if (!e->indirect_unknown_callee)
! 			  {
! 			    if (verify_edge_corresponds_to_fndecl (e, decl))
! 			      {
! 				error ("edge points to wrong declaration:");
! 				debug_tree (e->callee->symbol.decl);
! 				fprintf (stderr," Instead of:");
! 				debug_tree (decl);
! 				error_found = true;
! 			      }
! 			  }
! 			else if (decl)
! 			  {
! 			    error ("an indirect edge with unknown callee "
! 				   "corresponding to a call_stmt with "
! 				   "a known declaration:");
! 			    error_found = true;
! 			    cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
! 			  }
! 			e->aux = (void *)1;
! 		      }
! 		    else if (decl)
! 		      {
! 			error ("missing callgraph edge for call stmt:");
! 			cgraph_debug_gimple_stmt (this_cfun, stmt);
! 			error_found = true;
! 		      }
! 		  }
  	      }
  	}
        else
  	/* No CFG available?!  */
--- 2537,2611 ----
      {
        if (this_cfun->cfg)
  	{
+ 	  pointer_set_t *stmts = pointer_set_create ();
+ 	  int i;
+ 	  struct ipa_ref *ref;
+ 
  	  /* Reach the trees by walking over the CFG, and note the
  	     enclosing basic-blocks in the call edges.  */
  	  FOR_EACH_BB_FN (this_block, this_cfun)
! 	    {
! 	      for (gsi = gsi_start_phis (this_block);
! 		   !gsi_end_p (gsi); gsi_next (&gsi))
! 		pointer_set_insert (stmts, gsi_stmt (gsi));
! 	      for (gsi = gsi_start_bb (this_block);
! 		   !gsi_end_p (gsi);
! 		   gsi_next (&gsi))
! 		{
! 		  gimple stmt = gsi_stmt (gsi);
! 		  pointer_set_insert (stmts, stmt);
! 		  if (is_gimple_call (stmt))
! 		    {
! 		      struct cgraph_edge *e = cgraph_edge (node, stmt);
! 		      tree decl = gimple_call_fndecl (stmt);
! 		      if (e)
! 			{
! 			  if (e->aux)
! 			    {
! 			      error ("shared call_stmt:");
! 			      cgraph_debug_gimple_stmt (this_cfun, stmt);
! 			      error_found = true;
! 			    }
! 			  if (!e->indirect_unknown_callee)
! 			    {
! 			      if (verify_edge_corresponds_to_fndecl (e, decl))
! 				{
! 				  error ("edge points to wrong declaration:");
! 				  debug_tree (e->callee->symbol.decl);
! 				  fprintf (stderr," Instead of:");
! 				  debug_tree (decl);
! 				  error_found = true;
! 				}
! 			    }
! 			  else if (decl)
! 			    {
! 			      error ("an indirect edge with unknown callee "
! 				     "corresponding to a call_stmt with "
! 				     "a known declaration:");
! 			      error_found = true;
! 			      cgraph_debug_gimple_stmt (this_cfun, e->call_stmt);
! 			    }
! 			  e->aux = (void *)1;
! 			}
! 		      else if (decl)
! 			{
! 			  error ("missing callgraph edge for call stmt:");
! 			  cgraph_debug_gimple_stmt (this_cfun, stmt);
! 			  error_found = true;
! 			}
! 		    }
! 		}
  	      }
+ 	    for (i = 0;
+ 		 ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref);
+ 		 i++)
+ 	      if (ref->stmt && !pointer_set_contains (stmts, ref->stmt))
+ 		{
+ 		  error ("reference to dead statement");
+ 		  cgraph_debug_gimple_stmt (this_cfun, ref->stmt);
+ 		  error_found = true;
+ 		}
+ 	    pointer_set_destroy (stmts);
  	}
        else
  	/* No CFG available?!  */
Index: ipa-inline-transform.c
===================================================================
*** ipa-inline-transform.c	(revision 201568)
--- ipa-inline-transform.c	(working copy)
*************** inline_transform (struct cgraph_node *no
*** 414,419 ****
--- 414,420 ----
  
    for (e = node->callees; e; e = e->next_callee)
      cgraph_redirect_edge_call_stmt_to_callee (e);
+   ipa_remove_all_references (&node->symbol.ref_list);
  
    timevar_push (TV_INTEGRATION);
    if (node->callees)
Index: cgraphunit.c
===================================================================
*** cgraphunit.c	(revision 201568)
--- cgraphunit.c	(working copy)
*************** expand_function (struct cgraph_node *nod
*** 1677,1682 ****
--- 1677,1683 ----
    /* Eliminate all call edges.  This is important so the GIMPLE_CALL no longer
       points to the dead function body.  */
    cgraph_node_remove_callees (node);
+   ipa_remove_all_references (&node->symbol.ref_list);
  }
  
  
Index: ipa-ref.c
===================================================================
*** ipa-ref.c	(revision 201568)
--- ipa-ref.c	(working copy)
*************** ipa_ref_has_aliases_p (struct ipa_ref_li
*** 218,223 ****
--- 218,224 ----
  {
    struct ipa_ref *ref;
    int i;
+ 
    for (i = 0; ipa_ref_list_referring_iterate (ref_list, i, ref); i++)
      if (ref->use == IPA_REF_ALIAS)
        return true;
*************** ipa_find_reference (symtab_node referrin
*** 234,240 ****
    struct ipa_ref *r = NULL;
    int i;
  
!   FOR_EACH_VEC_SAFE_ELT (referring_node->symbol.ref_list.references, i, r)
      if (r->referred == referred_node
  	&& (in_lto_p || r->stmt == stmt))
        return r;
--- 235,241 ----
    struct ipa_ref *r = NULL;
    int i;
  
!   for (i = 0; ipa_ref_list_reference_iterate (&referring_node->symbol.ref_list, i, r); i++)
      if (r->referred == referred_node
  	&& (in_lto_p || r->stmt == stmt))
        return r;
*************** ipa_remove_stmt_references (symtab_node
*** 250,256 ****
    struct ipa_ref *r = NULL;
    int i;
  
!   FOR_EACH_VEC_SAFE_ELT (referring_node->symbol.ref_list.references, i, r)
      if (r->stmt == stmt)
        ipa_remove_reference (r);
  }
--- 251,270 ----
    struct ipa_ref *r = NULL;
    int i;
  
!   for (i = 0; ipa_ref_list_reference_iterate (&referring_node->symbol.ref_list, i, r); i++)
      if (r->stmt == stmt)
        ipa_remove_reference (r);
  }
+ 
+ /* Remove all stmt references in non-speculative references.
+    Those are not maintained during inlining & clonning. */
+ 
+ void
+ ipa_clear_stmts_in_references (symtab_node referring_node)
+ {
+   struct ipa_ref *r = NULL;
+   int i;
+ 
+   for (i = 0; ipa_ref_list_reference_iterate (&referring_node->symbol.ref_list, i, r); i++)
+     r->stmt = NULL;
+ }
Index: ipa-ref.h
===================================================================
*** ipa-ref.h	(revision 201568)
--- ipa-ref.h	(working copy)
*************** bool ipa_ref_cannot_lead_to_return (stru
*** 75,77 ****
--- 75,78 ----
  bool ipa_ref_has_aliases_p (struct ipa_ref_list *);
  struct ipa_ref * ipa_find_reference (symtab_node, symtab_node, gimple);
  void ipa_remove_stmt_references (symtab_node, gimple);
+ void ipa_clear_stmts_in_references (symtab_node);
Index: cgraphclones.c
===================================================================
*** cgraphclones.c	(revision 201568)
--- cgraphclones.c	(working copy)
*************** cgraph_materialize_all_clones (void)
*** 876,882 ****
      }
    FOR_EACH_FUNCTION (node)
      if (!node->symbol.analyzed && node->callees)
!       cgraph_node_remove_callees (node);
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file, "Materialization Call site updates done.\n");
  #ifdef ENABLE_CHECKING
--- 876,887 ----
      }
    FOR_EACH_FUNCTION (node)
      if (!node->symbol.analyzed && node->callees)
!       {
!         cgraph_node_remove_callees (node);
! 	ipa_remove_all_references (&node->symbol.ref_list);
!       }
!     else
!       ipa_clear_stmts_in_references ((symtab_node)node);
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file, "Materialization Call site updates done.\n");
  #ifdef ENABLE_CHECKING
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 201568)
--- ipa-inline.c	(working copy)
*************** early_inliner (void)
*** 2011,2016 ****
--- 2011,2017 ----
  #ifdef ENABLE_CHECKING
    verify_cgraph_node (node);
  #endif
+   ipa_remove_all_references (&node->symbol.ref_list);
  
    /* Even when not optimizing or not inlining inline always-inline
       functions.  */
Index: ipa-split.c
===================================================================
*** ipa-split.c	(revision 201568)
--- ipa-split.c	(working copy)
*************** split_function (struct split_point *spli
*** 1223,1228 ****
--- 1223,1229 ----
        DECL_FUNCTION_CODE (node->symbol.decl) = (enum built_in_function) 0;
      }
    cgraph_node_remove_callees (cur_node);
+   ipa_remove_all_references (&cur_node->symbol.ref_list);
    if (!split_part_return_p)
      TREE_THIS_VOLATILE (node->symbol.decl) = 1;
    if (dump_file)



More information about the Gcc-patches mailing list