Patchwork Speculative call support in the callgraph

login
register
mail settings
Submitter Jan Hubicka
Date Aug. 10, 2013, 8:53 p.m.
Message ID <20130810205309.GA6557@kam.mff.cuni.cz>
Download mbox | patch
Permalink /patch/266272/
State New
Headers show

Comments

Jan Hubicka - Aug. 10, 2013, 8:53 p.m.
> > Hi,
> > also I just became aware that this patch hits the following bug of gold
> > http://sourceware.org/bugzilla/show_bug.cgi?id=14342
> > It makes gcc.dg/tree-prof/crossmodule-indircall-1.c fail with the bogus
> > diagnostic on TLS and non-TLS use of the same symbol.  I attached the
> > details into the PR.  GNU-LD works.
> > 
> > I am not sure if I can workaround this problem except for convincing users to
> > always use -fno-lto with -fprofile-generate.  Shall we fix it in mainline
> > binutils + document that earlier binutils are broken with -fporfile-generate
> > -flto?
> Hi,
> it seems that the bug also appeared in later GNU-LDs.  So I made the following
> workaround that with -flto switches back to old API of indirect_call_profiler
> and it makes new hidden variables in profiling code.  This avoid mixing of
> accesses of the TLS variable from LTO and non-LTO code.
> 
> Unless someone suggests me a better solution soon, I will go with this hack.
> It ought to be essentially harmless just adding some extra overhead to -flto
> -fprofile-generate (same as we had before patch).  Things will also still break
> if you produce fat LTO -fprofile-generate objects and link some with LTO and
> others without.  I do not think we need to support this with binutils bug.
> 
> Honza

Hi,
this is what I commited after lto & profiled bootstrap with gold + 
regular testing on x86_64-linux

Patch

Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 201646)
+++ gcc/ChangeLog	(working copy)
@@ -1,3 +1,10 @@ 
+2013-08-10  Jan Hubicka  <jh@suse.cz>
+
+	Workaround binutils PR14342
+	* tree-profile.c (init_ic_make_global_vars): Add LTO path.
+	(gimple_init_edge_profiler): Likewise.
+	(gimple_gen_ic_func_profiler): Likewise.
+
 2013-08-09  Jan Hubicka  <jh@suse.cz>
 
 	* cgraph.c (cgraph_create_edge_1): Clear speculative flag.
Index: gcc/tree-profile.c
===================================================================
--- gcc/tree-profile.c	(revision 201646)
+++ gcc/tree-profile.c	(working copy)
@@ -67,13 +67,28 @@  init_ic_make_global_vars (void)
 
   ptr_void = build_pointer_type (void_type_node);
 
-  ic_void_ptr_var
-    = build_decl (UNKNOWN_LOCATION, VAR_DECL,
-		  get_identifier ("__gcov_indirect_call_callee"),
-		  ptr_void);
+  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
+  if (flag_lto)
+    {
+      ic_void_ptr_var
+	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		      get_identifier ("__gcov_indirect_call_callee_ltopriv"),
+		      ptr_void);
+      TREE_PUBLIC (ic_void_ptr_var) = 1;
+      DECL_COMMON (ic_void_ptr_var) = 1;
+      DECL_VISIBILITY (ic_void_ptr_var) = VISIBILITY_HIDDEN;
+      DECL_VISIBILITY_SPECIFIED (ic_void_ptr_var) = true;
+    }
+  else
+    {
+      ic_void_ptr_var
+	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		      get_identifier ("__gcov_indirect_call_callee"),
+		      ptr_void);
+      TREE_PUBLIC (ic_void_ptr_var) = 1;
+      DECL_EXTERNAL (ic_void_ptr_var) = 1;
+    }
   TREE_STATIC (ic_void_ptr_var) = 1;
-  TREE_PUBLIC (ic_void_ptr_var) = 1;
-  DECL_EXTERNAL (ic_void_ptr_var) = 1;
   DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
   DECL_INITIAL (ic_void_ptr_var) = NULL;
   if (targetm.have_tls)
@@ -83,13 +98,28 @@  init_ic_make_global_vars (void)
   varpool_finalize_decl (ic_void_ptr_var);
 
   gcov_type_ptr = build_pointer_type (get_gcov_type ());
-  ic_gcov_type_ptr_var
-    = build_decl (UNKNOWN_LOCATION, VAR_DECL,
-		  get_identifier ("__gcov_indirect_call_counters"),
-		  gcov_type_ptr);
+  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
+  if (flag_lto)
+    {
+      ic_gcov_type_ptr_var
+	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		      get_identifier ("__gcov_indirect_call_counters_ltopriv"),
+		      gcov_type_ptr);
+      TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
+      DECL_COMMON (ic_gcov_type_ptr_var) = 1;
+      DECL_VISIBILITY (ic_gcov_type_ptr_var) = VISIBILITY_HIDDEN;
+      DECL_VISIBILITY_SPECIFIED (ic_gcov_type_ptr_var) = true;
+    }
+  else
+    {
+      ic_gcov_type_ptr_var
+	= build_decl (UNKNOWN_LOCATION, VAR_DECL,
+		      get_identifier ("__gcov_indirect_call_counters"),
+		      gcov_type_ptr);
+      TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
+      DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
+    }
   TREE_STATIC (ic_gcov_type_ptr_var) = 1;
-  TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
-  DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
   DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
   DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
   if (targetm.have_tls)
@@ -157,15 +187,31 @@  gimple_init_edge_profiler (void)
 
       init_ic_make_global_vars ();
 
-      /* void (*) (gcov_type, void *)  */
-      ic_profiler_fn_type
-	       = build_function_type_list (void_type_node,
-					  gcov_type_node,
-					  ptr_void,
-					  NULL_TREE);
-      tree_indirect_call_profiler_fn
-	      = build_fn_decl ("__gcov_indirect_call_profiler_v2",
-				     ic_profiler_fn_type);
+      /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
+      if (flag_lto)
+        {
+	  /* void (*) (gcov_type, void *)  */
+	  ic_profiler_fn_type
+		   = build_function_type_list (void_type_node,
+					      gcov_type_ptr, gcov_type_node,
+					      ptr_void, ptr_void,
+					      NULL_TREE);
+	  tree_indirect_call_profiler_fn
+		  = build_fn_decl ("__gcov_indirect_call_profiler",
+					 ic_profiler_fn_type);
+        }
+      else
+        {
+	  /* void (*) (gcov_type, void *)  */
+	  ic_profiler_fn_type
+		   = build_function_type_list (void_type_node,
+					      gcov_type_node,
+					      ptr_void,
+					      NULL_TREE);
+	  tree_indirect_call_profiler_fn
+		  = build_fn_decl ("__gcov_indirect_call_profiler_v2",
+					 ic_profiler_fn_type);
+        }
       TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1;
       DECL_ATTRIBUTES (tree_indirect_call_profiler_fn)
 	= tree_cons (get_identifier ("leaf"), NULL,
@@ -375,8 +421,25 @@  gimple_gen_ic_func_profiler (void)
 				       true, GSI_SAME_STMT);
   tree_uid = build_int_cst
 	      (gcov_type_node, cgraph_get_node (current_function_decl)->profile_id);
-  stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2,
-			     tree_uid, cur_func);
+  /* Workaround for binutils bug 14342.  Once it is fixed, remove lto path.  */
+  if (flag_lto)
+    {
+      tree counter_ptr, ptr_var;
+      counter_ptr = force_gimple_operand_gsi (&gsi, ic_gcov_type_ptr_var,
+					      true, NULL_TREE, true,
+					      GSI_SAME_STMT);
+      ptr_var = force_gimple_operand_gsi (&gsi, ic_void_ptr_var,
+					  true, NULL_TREE, true,
+					  GSI_SAME_STMT);
+
+      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 4,
+				 counter_ptr, tree_uid, cur_func, ptr_var);
+    }
+  else
+    {
+      stmt1 = gimple_build_call (tree_indirect_call_profiler_fn, 2,
+				 tree_uid, cur_func);
+    }
   gsi_insert_before (&gsi, stmt1, GSI_SAME_STMT);
 
   /* Set __gcov_indirect_call_callee to 0,
Index: libgcc/Makefile.in
===================================================================
--- libgcc/Makefile.in	(revision 201647)
+++ libgcc/Makefile.in	(working copy)
@@ -858,7 +858,7 @@  LIBGCOV = _gcov _gcov_merge_add _gcov_me
     _gcov_execv _gcov_execvp _gcov_execve _gcov_reset _gcov_dump \
     _gcov_interval_profiler _gcov_pow2_profiler _gcov_one_value_profiler \
     _gcov_indirect_call_profiler _gcov_average_profiler _gcov_ior_profiler \
-    _gcov_merge_ior
+    _gcov_merge_ior _gcov_indirect_call_profiler_v2
 
 libgcov-objects = $(patsubst %,%$(objext),$(LIBGCOV))
 
Index: libgcc/libgcov.c
===================================================================
--- libgcc/libgcov.c	(revision 201647)
+++ libgcc/libgcov.c	(working copy)
@@ -1120,6 +1120,42 @@  __gcov_one_value_profiler (gcov_type *co
 #endif
 
 #ifdef L_gcov_indirect_call_profiler
+/* This function exist only for workaround of binutils bug 14342.
+   Once this compatibility hack is obsolette, it can be removed.  */
+
+/* By default, the C++ compiler will use function addresses in the
+   vtable entries.  Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
+   tells the compiler to use function descriptors instead.  The value
+   of this macro says how many words wide the descriptor is (normally 2),
+   but it may be dependent on target flags.  Since we do not have access
+   to the target flags here we just check to see if it is set and use
+   that to set VTABLE_USES_DESCRIPTORS to 0 or 1.
+
+   It is assumed that the address of a function descriptor may be treated
+   as a pointer to a function.  */
+
+#ifdef TARGET_VTABLE_USES_DESCRIPTORS
+#define VTABLE_USES_DESCRIPTORS 1
+#else
+#define VTABLE_USES_DESCRIPTORS 0
+#endif
+
+/* Tries to determine the most common value among its inputs. */
+void
+__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
+                               void* cur_func, void* callee_func)
+{
+  /* If the C++ virtual tables contain function descriptors then one
+     function may have multiple descriptors and we need to dereference
+     the descriptors to see if they point to the same function.  */
+  if (cur_func == callee_func
+      || (VTABLE_USES_DESCRIPTORS && callee_func
+          && *(void **) cur_func == *(void **) callee_func))
+    __gcov_one_value_profiler_body (counter, value);
+}
+
+#endif
+#ifdef L_gcov_indirect_call_profiler_v2
 
 /* These two variables are used to actually track caller and callee.  Keep
    them in TLS memory so races are not common (they are written to often).
@@ -1135,7 +1171,6 @@  __thread
 #endif
 gcov_type * __gcov_indirect_call_counters;
 
-
 /* By default, the C++ compiler will use function addresses in the
    vtable entries.  Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
    tells the compiler to use function descriptors instead.  The value
@@ -1167,7 +1202,6 @@  __gcov_indirect_call_profiler_v2 (gcov_t
 }
 #endif
 
-
 #ifdef L_gcov_average_profiler
 /* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
    to saturate up.  */
Index: libgcc/ChangeLog
===================================================================
--- libgcc/ChangeLog	(revision 201647)
+++ libgcc/ChangeLog	(working copy)
@@ -1,3 +1,10 @@ 
+2013-08-10  Jan Hubicka  <jh@suse.cz>
+
+	Work around binutils PR14342
+	* Makefile.in: Add _gcov_indirect_call_profiler_v2 symbol.
+	* libgcov.c (L_gcov_indirect_call_profiler): Restore original API.
+	(L_gcov_indirect_call_profiler_v2): New.
+
 2013-08-06  Jan Hubicka  <jh@suse.cz>
 
 	* libgcov.c (__gcov_indirect_call_callee,