From 4d6b11ab420f373787b369905fe1271927ae671c Mon Sep 17 00:00:00 2001
From: hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Fri, 18 Mar 2005 20:15:06 +0000
Subject: [PATCH] 	* basic-block.h (scale_bbs_frequencies_int, 
 scale_bbs_frequencies_gcov_type): Declare. 	* cfg.c (RDIV): New macro. 
 (update_bb_frequency_for_threading): Fix. 	* basic-block.h
 (scale_bbs_frequencies_int, 	scale_bbs_frequencies_gcov_type): New. 	*
 cfgloopmanip.c (scale_bbs_frequencies): Kill. 	(scale_loop_frequencies,
 duplicate_loop_to_header_edge): Use 	scale_bbs_frequencies_int. 	*
 tree-ssa-loop-ch.c (copy_loop_headers): Fix profiling info.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@96700 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog          | 14 ++++++++++++++
 gcc/basic-block.h      |  3 +++
 gcc/cfg.c              | 43 ++++++++++++++++++++++++++++++++++++++++--
 gcc/cfgloopmanip.c     | 25 +++---------------------
 gcc/tree-ssa-loop-ch.c | 34 +++++++++++++++++++++++++++++----
 5 files changed, 91 insertions(+), 28 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6540e9da330f..73d040985354 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2005-03-18  Jan Hubicka  <jh@suse.cz>
+	    Dale Johannesen  <dalej@apple.com>
+
+	* basic-block.h (scale_bbs_frequencies_int,
+	scale_bbs_frequencies_gcov_type): Declare.
+	* cfg.c (RDIV): New macro.
+	(update_bb_frequency_for_threading): Fix.
+	* basic-block.h (scale_bbs_frequencies_int,
+	scale_bbs_frequencies_gcov_type): New.
+	* cfgloopmanip.c (scale_bbs_frequencies): Kill.
+	(scale_loop_frequencies, duplicate_loop_to_header_edge): Use
+	scale_bbs_frequencies_int.
+	* tree-ssa-loop-ch.c (copy_loop_headers): Fix profiling info.
+
 2005-03-18  Kazu Hirata  <kazu@cs.umass.edu>
 
 	* config/m32r/m32r-protos.h: Remove the prototypes for
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index 45c511a1975a..a767c6b7fa13 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -468,6 +468,9 @@ extern void dump_edge_info (FILE *, edge, int);
 extern void brief_dump_cfg (FILE *);
 extern void clear_edges (void);
 extern rtx first_insn_after_basic_block_note (basic_block);
+extern void scale_bbs_frequencies_int (basic_block *, int, int, int);
+extern void scale_bbs_frequencies_gcov_type (basic_block *, int, gcov_type, 
+					     gcov_type);
 
 /* Structure to group all of the information to process IF-THEN and
    IF-THEN-ELSE blocks for the conditional execution support.  This
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 03f1ee1f9d2e..c0e38f2910f9 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -96,6 +96,8 @@ static void free_edge (edge);
 /* Indicate the presence of the profile.  */
 enum profile_status profile_status;
 
+#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
+
 /* Called once at initialization time.  */
 
 void
@@ -933,10 +935,10 @@ update_bb_profile_for_threading (basic_block bb, int edge_frequency,
     }
   else if (prob != REG_BR_PROB_BASE)
     {
-      int scale = REG_BR_PROB_BASE / prob;
+      int scale = 65536 * REG_BR_PROB_BASE / prob;
 
       FOR_EACH_EDGE (c, ei, bb->succs)
-	c->probability *= scale;
+	c->probability *= scale / 65536;
     }
 
   if (bb != taken_edge->src)
@@ -945,3 +947,40 @@ update_bb_profile_for_threading (basic_block bb, int edge_frequency,
   if (taken_edge->count < 0)
     taken_edge->count = 0;
 }
+
+/* Multiply all frequencies of basic blocks in array BBS of length NBBS
+   by NUM/DEN, in int arithmetic.  May lose some accuracy.  */
+void
+scale_bbs_frequencies_int (basic_block *bbs, int nbbs, int num, int den)
+{
+  int i;
+  edge e;
+  for (i = 0; i < nbbs; i++)
+    {
+      edge_iterator ei;
+      bbs[i]->frequency = (bbs[i]->frequency * num) / den;
+      bbs[i]->count = RDIV (bbs[i]->count * num, den);
+      FOR_EACH_EDGE (e, ei, bbs[i]->succs)
+	e->count = (e->count * num) /den;
+    }
+}
+
+/* Multiply all frequencies of basic blocks in array BBS of length NBBS
+   by NUM/DEN, in gcov_type arithmetic.  More accurate than previous
+   function but considerably slower.  */
+void
+scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num, 
+			         gcov_type den)
+{
+  int i;
+  edge e;
+
+  for (i = 0; i < nbbs; i++)
+    {
+      edge_iterator ei;
+      bbs[i]->frequency = (bbs[i]->frequency * num) / den;
+      bbs[i]->count = RDIV (bbs[i]->count * num, den);
+      FOR_EACH_EDGE (e, ei, bbs[i]->succs)
+	e->count = (e->count * num) /den;
+    }
+}
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index bd55788483d2..14769067279d 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -45,7 +45,6 @@ static bool fix_bb_placement (struct loops *, basic_block);
 static void fix_bb_placements (struct loops *, basic_block);
 static void place_new_loop (struct loops *, struct loop *);
 static void scale_loop_frequencies (struct loop *, int, int);
-static void scale_bbs_frequencies (basic_block *, int, int, int);
 static basic_block create_preheader (struct loop *, int);
 static void fix_irreducible_loops (basic_block);
 static void unloop (struct loops *, struct loop *);
@@ -450,24 +449,6 @@ add_loop (struct loops *loops, struct loop *loop)
   free (bbs);
 }
 
-/* Multiply all frequencies of basic blocks in array BBS of length NBBS
-   by NUM/DEN.  */
-static void
-scale_bbs_frequencies (basic_block *bbs, int nbbs, int num, int den)
-{
-  int i;
-  edge e;
-
-  for (i = 0; i < nbbs; i++)
-    {
-      edge_iterator ei;
-      bbs[i]->frequency = (bbs[i]->frequency * num) / den;
-      bbs[i]->count = RDIV (bbs[i]->count * num, den);
-      FOR_EACH_EDGE (e, ei, bbs[i]->succs)
-	e->count = (e->count * num) /den;
-    }
-}
-
 /* Multiply all frequencies in LOOP by NUM/DEN.  */
 static void
 scale_loop_frequencies (struct loop *loop, int num, int den)
@@ -475,7 +456,7 @@ scale_loop_frequencies (struct loop *loop, int num, int den)
   basic_block *bbs;
 
   bbs = get_loop_body (loop);
-  scale_bbs_frequencies (bbs, loop->num_nodes, num, den);
+  scale_bbs_frequencies_int (bbs, loop->num_nodes, num, den);
   free (bbs);
 }
 
@@ -1059,7 +1040,7 @@ duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops,
       /* Set counts and frequencies.  */
       if (flags & DLTHE_FLAG_UPDATE_FREQ)
 	{
-	  scale_bbs_frequencies (new_bbs, n, scale_act, REG_BR_PROB_BASE);
+	  scale_bbs_frequencies_int (new_bbs, n, scale_act, REG_BR_PROB_BASE);
 	  scale_act = RDIV (scale_act * scale_step[j], REG_BR_PROB_BASE);
 	}
     }
@@ -1071,7 +1052,7 @@ duplicate_loop_to_header_edge (struct loop *loop, edge e, struct loops *loops,
     set_immediate_dominator (CDI_DOMINATORS, e->dest, e->src);
   if (flags & DLTHE_FLAG_UPDATE_FREQ)
     {
-      scale_bbs_frequencies (bbs, n, scale_main, REG_BR_PROB_BASE);
+      scale_bbs_frequencies_int (bbs, n, scale_main, REG_BR_PROB_BASE);
       free (scale_step);
     }
 
diff --git a/gcc/tree-ssa-loop-ch.c b/gcc/tree-ssa-loop-ch.c
index 6d122711db7c..fb5f7f68fb51 100644
--- a/gcc/tree-ssa-loop-ch.c
+++ b/gcc/tree-ssa-loop-ch.c
@@ -127,9 +127,11 @@ copy_loop_headers (void)
   unsigned i;
   struct loop *loop;
   basic_block header;
-  edge exit;
-  basic_block *bbs;
+  edge exit, entry;
+  basic_block *bbs, *copied_bbs;
   unsigned n_bbs;
+  unsigned bbs_size;
+  gcov_type entry_count, body_count, total_count;
 
   loops = loop_optimizer_init (dump_file);
   if (!loops)
@@ -145,6 +147,8 @@ copy_loop_headers (void)
 #endif
 
   bbs = xmalloc (sizeof (basic_block) * n_basic_blocks);
+  copied_bbs = xmalloc (sizeof (basic_block) * n_basic_blocks);
+  bbs_size = n_basic_blocks;
 
   for (i = 1; i < loops->num; i++)
     {
@@ -180,6 +184,7 @@ copy_loop_headers (void)
 	  else
 	    exit = EDGE_SUCC (header, 1);
 	  bbs[n_bbs++] = header;
+	  gcc_assert (bbs_size > n_bbs);
 	  header = exit->dest;
 	}
 
@@ -196,13 +201,33 @@ copy_loop_headers (void)
       if (!single_pred_p (exit->dest))
 	exit = single_succ_edge (loop_split_edge_with (exit, NULL));
 
-      if (!tree_duplicate_sese_region (loop_preheader_edge (loop), exit,
-				       bbs, n_bbs, NULL))
+      entry = loop_preheader_edge (loop);
+      entry_count = entry->src->count;
+      body_count = exit->dest->count;
+
+      if (!tree_duplicate_sese_region (entry, exit, bbs, n_bbs, copied_bbs))
 	{
 	  fprintf (dump_file, "Duplication failed.\n");
 	  continue;
 	}
 
+      /* Fix profiling info.  Scaling is done in gcov_type arithmetic to
+	 avoid losing information; this is slow, but is done at most
+	 once per loop.  We special case 0 to avoid division by 0;
+         probably other special cases exist.  */
+      total_count = body_count + entry_count;
+      if (total_count == 0LL)
+	{
+	  scale_bbs_frequencies_int (bbs, n_bbs, 0, 1);
+	  scale_bbs_frequencies_int (copied_bbs, n_bbs, 0, 1);
+	}
+      else
+	{
+	  scale_bbs_frequencies_gcov_type (bbs, n_bbs, body_count, total_count);
+	  scale_bbs_frequencies_gcov_type (copied_bbs, n_bbs, entry_count, 
+				           total_count);
+	}
+
       /* Ensure that the latch and the preheader is simple (we know that they
 	 are not now, since there was the loop exit condition.  */
       loop_split_edge_with (loop_preheader_edge (loop), NULL);
@@ -210,6 +235,7 @@ copy_loop_headers (void)
     }
 
   free (bbs);
+  free (copied_bbs);
 
 #ifdef ENABLE_CHECKING
   verify_loop_closed_ssa ();
-- 
GitLab