[PATCH][LTO] Fix ICE in output_node of lto-cgraph.c

Doug Kwan (關振德) dougkwan@google.com
Tue Dec 2 08:59:00 GMT 2008


Hi Diego,

    This patch fixes an ICE in output_node of lto-cgraph.c.  When we
add the master clone of an inlined function F to a cgraph node set S,
F itself may contain other inlined functions.  The inlines of F may
not be in S.  We redirect all such inlines to their master clones and
make the edges appear non-inlined.  This is done so that we don't have
boundary nodes that are (non-master) clones.  Essentially we disable
any inlining across the boundary of the set S.  We only care about
inlining inside S.

   This is a tested on i686-unknown-linux-gnu.

-Doug

2008-12-01  Doug Kwan  <dougkwan@google.com>
	
ChangeLog.lto:

	* lto-cgraph.c (maybe_redirect_inlined_node): New.
	(output_edge): Add new parameter SET.  Redirect an inlined callee
	which is outside of SET to its master clone.  Fix-up INLINE_FAILED
	if callee is redirected.
	(output_cgraph): Redirect an inlined callee which is outside of SET to
	its master clone.  Adjust call to output_edge for new parameter.

testsuite/ChangeLog.lto:

	* gcc.dg/lto/20081201-1_0.c: New.
	* gcc.dg/lto/20081201-1_1.c: New.
	* gcc.dg/lto/20081201-1_2.c: New.
	* gcc.dg/lto/20081201-2_0.c: New.
	* gcc.dg/lto/20081201-2_1.c: New.
-------------- next part --------------
Index: gcc/gcc/testsuite/gcc.dg/lto/20081201-1_0.c
===================================================================
--- gcc/gcc/testsuite/gcc.dg/lto/20081201-1_0.c	(revision 0)
+++ gcc/gcc/testsuite/gcc.dg/lto/20081201-1_0.c	(revision 0)
@@ -0,0 +1,33 @@
+/* { dg-options "{-O2 -DOPTIMIZE -fwhopr} {-O0 -fwhopr}" } */
+
+extern void abort (void);
+
+int
+f (void)
+{
+ return 1;
+}
+
+extern inline int
+e_inline_baz (void)
+{
+ return 1 + f();
+}
+
+int
+bar (void)
+{
+ return e_inline_baz ();
+}
+
+main ()
+{
+#ifdef OPTIMIZE
+ if (bar () != 2 || foo () != 3)
+   abort ();
+#else
+ if (bar () != 0 || foo () != 0)
+   abort ();
+#endif
+ return 0;
+}
Index: gcc/gcc/testsuite/gcc.dg/lto/20081201-1_1.c
===================================================================
--- gcc/gcc/testsuite/gcc.dg/lto/20081201-1_1.c	(revision 0)
+++ gcc/gcc/testsuite/gcc.dg/lto/20081201-1_1.c	(revision 0)
@@ -0,0 +1,13 @@
+extern int f (void);
+
+extern inline int
+e_inline_baz (void)
+{
+ return 2 + f ();
+}
+
+int
+foo (void)
+{
+ return e_inline_baz ();
+}
Index: gcc/gcc/testsuite/gcc.dg/lto/20081201-2_0.c
===================================================================
--- gcc/gcc/testsuite/gcc.dg/lto/20081201-2_0.c	(revision 0)
+++ gcc/gcc/testsuite/gcc.dg/lto/20081201-2_0.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-options "{-O3 -fwhopr}" } */
+
+/* Test that cross-TU inlining works.  */
+
+extern void abort ();
+extern void exit (int);
+extern void *foo (void);
+
+int
+main ()
+{
+  if (foo () != __builtin_return_address (0))
+    abort ();
+
+  exit (0);
+}
Index: gcc/gcc/testsuite/gcc.dg/lto/20081201-2_1.c
===================================================================
--- gcc/gcc/testsuite/gcc.dg/lto/20081201-2_1.c	(revision 0)
+++ gcc/gcc/testsuite/gcc.dg/lto/20081201-2_1.c	(revision 0)
@@ -0,0 +1,5 @@
+void *
+foo (void)
+{
+  return __builtin_return_address (0);
+}
Index: gcc/gcc/testsuite/gcc.dg/lto/20081201-1_2.c
===================================================================
--- gcc/gcc/testsuite/gcc.dg/lto/20081201-1_2.c	(revision 0)
+++ gcc/gcc/testsuite/gcc.dg/lto/20081201-1_2.c	(revision 0)
@@ -0,0 +1,7 @@
+int
+e_inline_baz (void)
+{
+ return 0;
+}
+
+
Index: gcc/gcc/lto-cgraph.c
===================================================================
--- gcc/gcc/lto-cgraph.c	(revision 142345)
+++ gcc/gcc/lto-cgraph.c	(working copy)
@@ -157,16 +157,35 @@ const char * LTO_cgraph_tag_names[LTO_cg
 {"", "avail", "overwrite", "unavail", "edge"};
 #endif
 
+/* Redirect inlined NODE to its master clone if it is not in SET. 
+   Return NODE itself if it is in SET or it is not inlined.  */
+
+static struct cgraph_node *
+maybe_redirect_inlined_node (struct cgraph_node *node, cgraph_node_set set)
+{
+  struct cgraph_node *master_clone;
+
+  if (!cgraph_node_in_set_p (node, set) && node->global.inlined_to != NULL)
+    {
+      master_clone = node->master_clone;
+      gcc_assert (master_clone && master_clone != node);
+      return master_clone;
+    }
+  else
+    return node;
+}
 
 /* Output the cgraph EDGE to OB using ENCODER.  */
 
 static void
 output_edge (struct lto_simple_output_block *ob,
-	     struct cgraph_edge *edge, lto_cgraph_encoder_t encoder)
+	     struct cgraph_edge *edge, lto_cgraph_encoder_t encoder,
+	     cgraph_node_set set)
 {
   unsigned int uid;
   intptr_t ref;
   unsigned HOST_WIDEST_INT flags = 0;
+  struct cgraph_node *callee;
 
   lto_output_uleb128_stream (ob->main_stream, LTO_cgraph_edge);
   LTO_DEBUG_INDENT (LTO_cgraph_edge);
@@ -177,15 +196,23 @@ output_edge (struct lto_simple_output_bl
   lto_output_sleb128_stream (ob->main_stream, ref);
 
   LTO_DEBUG_TOKEN ("callee");
-  ref = lto_cgraph_encoder_lookup (encoder, edge->callee);
+  callee = maybe_redirect_inlined_node (edge->callee, set);
+  ref = lto_cgraph_encoder_lookup (encoder, callee);
   gcc_assert (ref != LCC_NOT_FOUND); 
   lto_output_sleb128_stream (ob->main_stream, ref);
 
   LTO_DEBUG_TOKEN ("stmt");
   uid = flag_wpa ? edge->lto_stmt_uid : gimple_uid (edge->call_stmt);
   lto_output_uleb128_stream (ob->main_stream, uid);
+
+  /* If we have redirected an inlined callee outside SET to its master
+     clone, mark edge as not inlined.  */
   LTO_DEBUG_TOKEN ("inline_failed");
-  lto_output_uleb128_stream (ob->main_stream, edge->inline_failed);
+  if (callee != edge->callee)
+    lto_output_uleb128_stream (ob->main_stream, CIF_UNSPECIFIED);
+  else
+    lto_output_uleb128_stream (ob->main_stream, edge->inline_failed);
+
   LTO_DEBUG_TOKEN ("count");
   lto_output_uleb128_stream (ob->main_stream, edge->count);
   LTO_DEBUG_TOKEN ("frequency");
@@ -392,7 +419,7 @@ output_cgraph_verify_node (cgraph_node_s
 static void
 output_cgraph (cgraph_node_set set)
 {
-  struct cgraph_node *node, *master_clone;
+  struct cgraph_node *node, *callee, *master_clone;
   struct lto_simple_output_block *ob 
     = lto_create_simple_output_block (LTO_section_cgraph);
   cgraph_node_set_iterator csi;
@@ -419,12 +446,17 @@ output_cgraph (cgraph_node_set set)
 	lto_cgraph_encoder_encode (encoder, node);
     }
 
-  /* Go over all the nodes again to include callees that are not in SET.  */
+  /* Go over all the nodes again to include callees that are not in SET.
+     For inlined callee that are not in the set, redirect the edge to 
+     its master clone.  */
   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
       node = csi_node (csi);
       for (edge = node->callees; edge; edge = edge->next_callee)
-	lto_cgraph_encoder_encode (encoder, edge->callee);
+	{
+	  callee = maybe_redirect_inlined_node (edge->callee, set);
+	  lto_cgraph_encoder_encode (encoder, callee);
+	}
     }
 
   /* Write out the nodes */
@@ -443,7 +475,7 @@ output_cgraph (cgraph_node_set set)
     {
       node = csi_node (csi);
       for (edge = node->callees; edge; edge = edge->next_callee)
-	output_edge (ob, edge, encoder);
+	output_edge (ob, edge, encoder, set);
     }
 
   lto_output_uleb128_stream (ob->main_stream, 0);


More information about the Gcc-patches mailing list