On 1/2/19 12:50 PM, Jan Hubicka wrote:
>>
>> Honza, in order to make the test working I would need to backport
>> r267495. Is it a good idea?
> 
> Yes, my apologies for the mistake! I should stop looking for failures
> via grep and use test_summary consistently since I tend to miss
> unresolved tests.  Old habits are hard to change.
> 
> Honza
>>
>> Thanks,
>> Martin

Hi.

So there's a backport of 3 patches that fix the test-case.
Tested and bootstrapped on x86_64-linux-gnu, I'm going
to install the patches.

Martin
>From 5fd0285a53b7caee98625472adc44cb101bd4873 Mon Sep 17 00:00:00 2001
From: jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Wed, 2 Jan 2019 09:25:59 +0000
Subject: [PATCH 3/3] Backport r267507

gcc/testsuite/ChangeLog:

2019-01-02  Jakub Jelinek  <ja...@redhat.com>

	PR ipa/88561
	* g++.dg/tree-prof/devirt.C: Expect _ZThn16 only for lp64 and llp64
	targets and expect _ZThn8 for ilp32 targets.
---
 gcc/testsuite/g++.dg/tree-prof/devirt.C | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C
index 7d6797dd226..3de5dbcf688 100644
--- a/gcc/testsuite/g++.dg/tree-prof/devirt.C
+++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C
@@ -1,4 +1,6 @@
+/* PR ipa/88561 */
 /* { dg-options "-O3 -fdump-tree-dom3-details" } */
+
 struct nsISupports
 {
   virtual int QueryInterface (const int &aIID, void **aInstancePtr) = 0;
@@ -119,5 +121,6 @@ main ()
     __builtin_abort ();
 }
 
-/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 1 "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 1 "dom3" { target { lp64 || llp64 } } } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn8" 1 "dom3" { target ilp32 } } } */
 /* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 1 "dom3" } } */
-- 
2.20.1

>From f3a455cffaee5ac5af2ac188e08c51f3a662491a Mon Sep 17 00:00:00 2001
From: marxin <mli...@suse.cz>
Date: Wed, 2 Jan 2019 12:54:23 +0100
Subject: [PATCH 2/3] Backport r267495

gcc/ChangeLog:

2019-01-01  Jan Hubicka  <hubi...@ucw.cz>

	* coverage.c (get_coverage_counts): Use current_function_decl.
	* profile.c (read_thunk_profile): New function.
	(branch_prob): Add THUNK parameter.
	* tree-profile.c (tree_profiling): Handle thunks.
	* value-prof.c (init_node_map): Handle thunks.
	* value-prof.h (branch_prob): Upate prototype.
	(read_thunk_profile): Declare.

gcc/testsuite/ChangeLog:

2019-01-01  Jan Hubicka  <hubi...@ucw.cz>

	* g++.dg/tree-prof/devirt.C: Update testcase.
---
 gcc/coverage.c                          |   2 +-
 gcc/profile.c                           | 250 ++++++++++++++----------
 gcc/testsuite/g++.dg/tree-prof/devirt.C |   4 +-
 gcc/tree-profile.c                      |  28 ++-
 gcc/value-prof.c                        |   2 +-
 gcc/value-prof.h                        |   3 +-
 6 files changed, 177 insertions(+), 112 deletions(-)

diff --git a/gcc/coverage.c b/gcc/coverage.c
index 75628b1748f..592d3dcef84 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -368,7 +368,7 @@ get_coverage_counts (unsigned counter, unsigned expected,
   else
     {
       gcc_assert (coverage_node_map_initialized_p ());
-      elt.ident = cgraph_node::get (cfun->decl)->profile_id;
+      elt.ident = cgraph_node::get (current_function_decl)->profile_id;
     }
   elt.ctr = counter;
   entry = counts_hash->find (&elt);
diff --git a/gcc/profile.c b/gcc/profile.c
index 6fde0fd29d1..eb9f7d52668 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -977,6 +977,25 @@ compare_freqs (const void *p1, const void *p2)
   return e2->dest->index - e1->dest->index;
 }
 
+/* Only read execution count for thunks.  */
+
+void
+read_thunk_profile (struct cgraph_node *node)
+{
+  tree old = current_function_decl;
+  current_function_decl = node->decl;
+  gcov_type *counts = get_coverage_counts (GCOV_COUNTER_ARCS, 1, 0, 0, NULL);
+  if (counts)
+    {
+      node->callees->count = node->count
+	 = profile_count::from_gcov_type (counts[0]);
+      free (counts);
+    }
+  current_function_decl = old;
+  return;
+}
+
+
 /* Instrument and/or analyze program behavior based on program the CFG.
 
    This function creates a representation of the control flow graph (of
@@ -997,7 +1016,7 @@ compare_freqs (const void *p1, const void *p2)
    Main entry point of this file.  */
 
 void
-branch_prob (void)
+branch_prob (bool thunk)
 {
   basic_block bb;
   unsigned i;
@@ -1012,118 +1031,121 @@ branch_prob (void)
   flow_call_edges_add (NULL);
   add_noreturn_fake_exit_edges ();
 
-  /* We can't handle cyclic regions constructed using abnormal edges.
-     To avoid these we replace every source of abnormal edge by a fake
-     edge from entry node and every destination by fake edge to exit.
-     This keeps graph acyclic and our calculation exact for all normal
-     edges except for exit and entrance ones.
-
-     We also add fake exit edges for each call and asm statement in the
-     basic, since it may not return.  */
-
-  FOR_EACH_BB_FN (bb, cfun)
+  if (!thunk)
     {
-      int need_exit_edge = 0, need_entry_edge = 0;
-      int have_exit_edge = 0, have_entry_edge = 0;
-      edge e;
-      edge_iterator ei;
+      /* We can't handle cyclic regions constructed using abnormal edges.
+	 To avoid these we replace every source of abnormal edge by a fake
+	 edge from entry node and every destination by fake edge to exit.
+	 This keeps graph acyclic and our calculation exact for all normal
+	 edges except for exit and entrance ones.
 
-      /* Functions returning multiple times are not handled by extra edges.
-         Instead we simply allow negative counts on edges from exit to the
-         block past call and corresponding probabilities.  We can't go
-         with the extra edges because that would result in flowgraph that
-	 needs to have fake edges outside the spanning tree.  */
+	 We also add fake exit edges for each call and asm statement in the
+	 basic, since it may not return.  */
 
-      FOR_EACH_EDGE (e, ei, bb->succs)
+      FOR_EACH_BB_FN (bb, cfun)
 	{
-	  gimple_stmt_iterator gsi;
-	  gimple *last = NULL;
-
-	  /* It may happen that there are compiler generated statements
-	     without a locus at all.  Go through the basic block from the
-	     last to the first statement looking for a locus.  */
-	  for (gsi = gsi_last_nondebug_bb (bb);
-	       !gsi_end_p (gsi);
-	       gsi_prev_nondebug (&gsi))
+	  int need_exit_edge = 0, need_entry_edge = 0;
+	  int have_exit_edge = 0, have_entry_edge = 0;
+	  edge e;
+	  edge_iterator ei;
+
+	  /* Functions returning multiple times are not handled by extra edges.
+	     Instead we simply allow negative counts on edges from exit to the
+	     block past call and corresponding probabilities.  We can't go
+	     with the extra edges because that would result in flowgraph that
+	     needs to have fake edges outside the spanning tree.  */
+
+	  FOR_EACH_EDGE (e, ei, bb->succs)
 	    {
-	      last = gsi_stmt (gsi);
-	      if (!RESERVED_LOCATION_P (gimple_location (last)))
-		break;
-	    }
+	      gimple_stmt_iterator gsi;
+	      gimple *last = NULL;
+
+	      /* It may happen that there are compiler generated statements
+		 without a locus at all.  Go through the basic block from the
+		 last to the first statement looking for a locus.  */
+	      for (gsi = gsi_last_nondebug_bb (bb);
+		   !gsi_end_p (gsi);
+		   gsi_prev_nondebug (&gsi))
+		{
+		  last = gsi_stmt (gsi);
+		  if (!RESERVED_LOCATION_P (gimple_location (last)))
+		    break;
+		}
 
-	  /* Edge with goto locus might get wrong coverage info unless
-	     it is the only edge out of BB.
-	     Don't do that when the locuses match, so
-	     if (blah) goto something;
-	     is not computed twice.  */
-	  if (last
-	      && gimple_has_location (last)
-	      && !RESERVED_LOCATION_P (e->goto_locus)
-	      && !single_succ_p (bb)
-	      && (LOCATION_FILE (e->goto_locus)
-	          != LOCATION_FILE (gimple_location (last))
-		  || (LOCATION_LINE (e->goto_locus)
-		      != LOCATION_LINE (gimple_location (last)))))
+	      /* Edge with goto locus might get wrong coverage info unless
+		 it is the only edge out of BB.
+		 Don't do that when the locuses match, so
+		 if (blah) goto something;
+		 is not computed twice.  */
+	      if (last
+		  && gimple_has_location (last)
+		  && !RESERVED_LOCATION_P (e->goto_locus)
+		  && !single_succ_p (bb)
+		  && (LOCATION_FILE (e->goto_locus)
+		      != LOCATION_FILE (gimple_location (last))
+		      || (LOCATION_LINE (e->goto_locus)
+			  != LOCATION_LINE (gimple_location (last)))))
+		{
+		  basic_block new_bb = split_edge (e);
+		  edge ne = single_succ_edge (new_bb);
+		  ne->goto_locus = e->goto_locus;
+		}
+	      if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
+		   && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
+		need_exit_edge = 1;
+	      if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
+		have_exit_edge = 1;
+	    }
+	  FOR_EACH_EDGE (e, ei, bb->preds)
 	    {
-	      basic_block new_bb = split_edge (e);
-	      edge ne = single_succ_edge (new_bb);
-	      ne->goto_locus = e->goto_locus;
+	      if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
+		   && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+		need_entry_edge = 1;
+	      if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
+		have_entry_edge = 1;
 	    }
-	  if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
-	       && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
-	    need_exit_edge = 1;
-	  if (e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun))
-	    have_exit_edge = 1;
-	}
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	{
-	  if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL))
-	       && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
-	    need_entry_edge = 1;
-	  if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun))
-	    have_entry_edge = 1;
-	}
 
-      if (need_exit_edge && !have_exit_edge)
-	{
-	  if (dump_file)
-	    fprintf (dump_file, "Adding fake exit edge to bb %i\n",
-		     bb->index);
-	  make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
-	}
-      if (need_entry_edge && !have_entry_edge)
-	{
-	  if (dump_file)
-	    fprintf (dump_file, "Adding fake entry edge to bb %i\n",
-		     bb->index);
-	  make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FAKE);
-	  /* Avoid bbs that have both fake entry edge and also some
-	     exit edge.  One of those edges wouldn't be added to the
-	     spanning tree, but we can't instrument any of them.  */
-	  if (have_exit_edge || need_exit_edge)
+	  if (need_exit_edge && !have_exit_edge)
+	    {
+	      if (dump_file)
+		fprintf (dump_file, "Adding fake exit edge to bb %i\n",
+			 bb->index);
+	      make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
+	    }
+	  if (need_entry_edge && !have_entry_edge)
 	    {
-	      gimple_stmt_iterator gsi;
-	      gimple *first;
-
-	      gsi = gsi_start_nondebug_after_labels_bb (bb);
-	      gcc_checking_assert (!gsi_end_p (gsi));
-	      first = gsi_stmt (gsi);
-	      /* Don't split the bbs containing __builtin_setjmp_receiver
-		 or ABNORMAL_DISPATCHER calls.  These are very
-		 special and don't expect anything to be inserted before
-		 them.  */
-	      if (is_gimple_call (first)
-		  && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
-		      || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
-		      || (gimple_call_internal_p (first)
-			  && (gimple_call_internal_fn (first)
-			      == IFN_ABNORMAL_DISPATCHER))))
-		continue;
-
 	      if (dump_file)
-		fprintf (dump_file, "Splitting bb %i after labels\n",
+		fprintf (dump_file, "Adding fake entry edge to bb %i\n",
 			 bb->index);
-	      split_block_after_labels (bb);
+	      make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FAKE);
+	      /* Avoid bbs that have both fake entry edge and also some
+		 exit edge.  One of those edges wouldn't be added to the
+		 spanning tree, but we can't instrument any of them.  */
+	      if (have_exit_edge || need_exit_edge)
+		{
+		  gimple_stmt_iterator gsi;
+		  gimple *first;
+
+		  gsi = gsi_start_nondebug_after_labels_bb (bb);
+		  gcc_checking_assert (!gsi_end_p (gsi));
+		  first = gsi_stmt (gsi);
+		  /* Don't split the bbs containing __builtin_setjmp_receiver
+		     or ABNORMAL_DISPATCHER calls.  These are very
+		     special and don't expect anything to be inserted before
+		     them.  */
+		  if (is_gimple_call (first)
+		      && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
+			  || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
+			  || (gimple_call_internal_p (first)
+			      && (gimple_call_internal_fn (first)
+				  == IFN_ABNORMAL_DISPATCHER))))
+		    continue;
+
+		  if (dump_file)
+		    fprintf (dump_file, "Splitting bb %i after labels\n",
+			     bb->index);
+		  split_block_after_labels (bb);
+		}
 	    }
 	}
     }
@@ -1155,7 +1177,18 @@ branch_prob (void)
      on the spanning tree.  We insert as many abnormal and critical edges
      as possible to minimize number of edge splits necessary.  */
 
-  find_spanning_tree (el);
+  if (!thunk)
+    find_spanning_tree (el);
+  else
+    {
+      edge e;
+      edge_iterator ei;
+      /* Keep only edge from entry block to be instrumented.  */
+      FOR_EACH_BB_FN (bb, cfun)
+	FOR_EACH_EDGE (e, ei, bb->succs)
+	  EDGE_INFO (e)->ignore = true;
+    }
+
 
   /* Fake edges that are not on the tree will not be instrumented, so
      mark them ignored.  */
@@ -1195,8 +1228,17 @@ branch_prob (void)
      the checksum in only once place, since it depends on the shape
      of the control flow which can change during 
      various transformations.  */
-  cfg_checksum = coverage_compute_cfg_checksum (cfun);
-  lineno_checksum = coverage_compute_lineno_checksum ();
+  if (thunk)
+    {
+      /* At stream in time we do not have CFG, so we can not do checksums.  */
+      cfg_checksum = 0;
+      lineno_checksum = 0;
+    }
+  else
+    {
+      cfg_checksum = coverage_compute_cfg_checksum (cfun);
+      lineno_checksum = coverage_compute_lineno_checksum ();
+    }
 
   /* Write the data from which gcov can reconstruct the basic block
      graph and function line numbers (the gcno file).  */
diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C
index 86cba41452e..7d6797dd226 100644
--- a/gcc/testsuite/g++.dg/tree-prof/devirt.C
+++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C
@@ -119,5 +119,5 @@ main ()
     __builtin_abort ();
 }
 
-/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 3 "dom3" } } */
-/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 3 "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 1 "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 1 "dom3" } } */
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index f96bd4b9704..8f8bb4874cd 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -653,7 +653,8 @@ tree_profiling (void)
 
   FOR_EACH_DEFINED_FUNCTION (node)
     {
-      if (!gimple_has_body_p (node->decl))
+      bool thunk = false;
+      if (!gimple_has_body_p (node->decl) && !node->thunk.thunk_p)
 	continue;
 
       /* Don't profile functions produced for builtin stuff.  */
@@ -670,22 +671,43 @@ tree_profiling (void)
 	  && flag_test_coverage)
 	continue;
 
+      if (node->thunk.thunk_p)
+	{
+	  /* We can not expand variadic thunks to Gimple.  */
+	  if (stdarg_p (TREE_TYPE (node->decl)))
+	    continue;
+	  thunk = true;
+	  /* When generate profile, expand thunk to gimple so it can be
+	     instrumented same way as other functions.  */
+	  if (profile_arc_flag)
+	    node->expand_thunk (false, true);
+	  /* Read cgraph profile but keep function as thunk at profile-use
+	     time.  */
+	  else
+	    {
+	      read_thunk_profile (node);
+	      continue;
+	    }
+	}
+
       push_cfun (DECL_STRUCT_FUNCTION (node->decl));
 
       if (dump_file)
 	dump_function_header (dump_file, cfun->decl, dump_flags);
 
       /* Local pure-const may imply need to fixup the cfg.  */
-      if (execute_fixup_cfg () & TODO_cleanup_cfg)
+      if (gimple_has_body_p (node->decl)
+	  && (execute_fixup_cfg () & TODO_cleanup_cfg))
 	cleanup_tree_cfg ();
 
-      branch_prob ();
+      branch_prob (thunk);
 
       if (! flag_branch_probabilities
 	  && flag_profile_values)
 	gimple_gen_ic_func_profiler ();
 
       if (flag_branch_probabilities
+	  && !thunk
 	  && flag_profile_values
 	  && flag_value_profile_transformations)
 	gimple_value_profile_transformations ();
diff --git a/gcc/value-prof.c b/gcc/value-prof.c
index 16cdbd64f46..d845faf5568 100644
--- a/gcc/value-prof.c
+++ b/gcc/value-prof.c
@@ -1202,7 +1202,7 @@ init_node_map (bool local)
   cgraph_node_map = new hash_map<profile_id_hash, cgraph_node *>;
 
   FOR_EACH_DEFINED_FUNCTION (n)
-    if (n->has_gimple_body_p ())
+    if (n->has_gimple_body_p () || n->thunk.thunk_p)
       {
 	cgraph_node **val;
 	if (local)
diff --git a/gcc/value-prof.h b/gcc/value-prof.h
index d0b8cda181f..55b1dd18416 100644
--- a/gcc/value-prof.h
+++ b/gcc/value-prof.h
@@ -112,7 +112,8 @@ extern struct cgraph_node* find_func_by_profile_id (int func_id);
 
 /* In profile.c.  */
 extern void init_branch_prob (void);
-extern void branch_prob (void);
+extern void branch_prob (bool);
+extern void read_thunk_profile (struct cgraph_node *);
 extern void end_branch_prob (void);
 
 #endif	/* GCC_VALUE_PROF_H */
-- 
2.20.1

>From eb618a86fa1f59ee7046c325a4a6acfc696cd990 Mon Sep 17 00:00:00 2001
From: marxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 31 Dec 2018 14:11:09 +0000
Subject: [PATCH 1/3] Backport r267486

gcc/testsuite/ChangeLog:

2018-12-31  Martin Liska  <mli...@suse.cz>

	* g++.dg/tree-prof/devirt.C: Fix scan pattern and test options.
---
 gcc/testsuite/g++.dg/tree-prof/devirt.C | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/gcc/testsuite/g++.dg/tree-prof/devirt.C b/gcc/testsuite/g++.dg/tree-prof/devirt.C
index 05c9a26e7a4..86cba41452e 100644
--- a/gcc/testsuite/g++.dg/tree-prof/devirt.C
+++ b/gcc/testsuite/g++.dg/tree-prof/devirt.C
@@ -1,4 +1,4 @@
-/* { dg-options "-O3 -fdump-tree-dom3" } */
+/* { dg-options "-O3 -fdump-tree-dom3-details" } */
 struct nsISupports
 {
   virtual int QueryInterface (const int &aIID, void **aInstancePtr) = 0;
@@ -119,5 +119,5 @@ main ()
     __builtin_abort ();
 }
 
-/* { dg-final-use-not-autofdo { scan-ipa-dump-times 3 "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" "dom3" } } */
-/* { dg-final-use-not-autofdo { scan-ipa-dump-times 3 "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::_ZThn16" 3 "dom3" } } */
+/* { dg-final-use-not-autofdo { scan-tree-dump-times "folding virtual function call to virtual unsigned int mozPersonalDictionary::AddRef" 3 "dom3" } } */
-- 
2.20.1

Reply via email to