From 5fefcf92fa6b75486291d2a898f9a0e4d541cf6c Mon Sep 17 00:00:00 2001
From: Jan Hubicka <jh@suse.cz>
Date: Mon, 26 Apr 2010 15:33:24 +0200
Subject: [PATCH] cgraph.c (cgraph_create_node): Set node frequency to normal.

	* cgraph.c (cgraph_create_node): Set node frequency to normal.
	(cgraph_clone_node): Copy function frequency.
	* cgraph.h (node_frequency): New enum
	(struct cgraph_node): Add.
	* final.c (rest_of_clean_state): Update.
	* lto-cgraph.c (lto_output_node): Output node frequency.
	(input_overwrite_node): Input node frequency.
	* tre-ssa-loop-ivopts (computation_cost): Update.
	* lto-streamer-out.c (output_function): Do not output function frequency.
	* predict.c (maybe_hot_frequency_p): Update and handle functions executed once.
	(cgraph_maybe_hot_edge_p): Likewise; use cgraph frequency instead of
	attribute lookup.
	(probably_never_executed_bb_p, optimize_function_for_size_p): Update.
	(compute_function_frequency): Set noreturn functions to be executed once.
	(choose_function_section): Update.
	* lto-streamer-in.c (input_function): Do not input function frequency.
	* function.c (allocate_struct_function): Do not initialize function frequency.
	* function.h (function_frequency): Remove.
	(struct function): Remove function frequency.
	* ipa-profile.c (CGRAPH_NODE_FREQUENCY): Remove.
	(try_update): Update.
	* tree-inline.c (initialize_cfun): Do not update function frequency.
	* passes.c (pass_init_dump_file): Update.
	* i386.c (ix86_compute_frame_layout): Update.
	(ix86_pad_returns): Update.

From-SVN: r158732
---
 gcc/ChangeLog              | 28 +++++++++++++++++++++
 gcc/cgraph.c               |  2 ++
 gcc/cgraph.h               | 18 ++++++++++++++
 gcc/config/i386/i386.c     |  7 +++---
 gcc/final.c                |  7 ++++--
 gcc/function.c             |  2 --
 gcc/function.h             | 15 ------------
 gcc/lto-cgraph.c           |  2 ++
 gcc/lto-streamer-in.c      |  1 -
 gcc/lto-streamer-out.c     |  1 -
 gcc/passes.c               |  7 ++++--
 gcc/predict.c              | 50 ++++++++++++++++++++++++++------------
 gcc/tree-inline.c          |  1 -
 gcc/tree-ssa-loop-ivopts.c |  7 +++---
 14 files changed, 103 insertions(+), 45 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 77d63554876f..07f762981453 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,31 @@
+2010-04-26  Jan Hubicka  <jh@suse.cz>
+
+	* cgraph.c (cgraph_create_node): Set node frequency to normal.
+	(cgraph_clone_node): Copy function frequency.
+	* cgraph.h (node_frequency): New enum
+	(struct cgraph_node): Add.
+	* final.c (rest_of_clean_state): Update.
+	* lto-cgraph.c (lto_output_node): Output node frequency.
+	(input_overwrite_node): Input node frequency.
+	* tre-ssa-loop-ivopts (computation_cost): Update.
+	* lto-streamer-out.c (output_function): Do not output function frequency.
+	* predict.c (maybe_hot_frequency_p): Update and handle functions executed once.
+	(cgraph_maybe_hot_edge_p): Likewise; use cgraph frequency instead of
+	attribute lookup.
+	(probably_never_executed_bb_p, optimize_function_for_size_p): Update.
+	(compute_function_frequency): Set noreturn functions to be executed once.
+	(choose_function_section): Update.
+	* lto-streamer-in.c (input_function): Do not input function frequency.
+	* function.c (allocate_struct_function): Do not initialize function frequency.
+	* function.h (function_frequency): Remove.
+	(struct function): Remove function frequency.
+	* ipa-profile.c (CGRAPH_NODE_FREQUENCY): Remove.
+	(try_update): Update.
+	* tree-inline.c (initialize_cfun): Do not update function frequency.
+	* passes.c (pass_init_dump_file): Update.
+	* i386.c (ix86_compute_frame_layout): Update.
+	(ix86_pad_returns): Update.
+
 2010-04-26  Jie Zhang  <jie@codesourcery.com>
 
 	PR tree-optimization/43833
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index c5e0f3d940c1..b58d4ee5516d 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -453,6 +453,7 @@ cgraph_create_node (void)
     cgraph_nodes->previous = node;
   node->previous = NULL;
   node->global.estimated_growth = INT_MIN;
+  node->frequency = NODE_FREQUENCY_NORMAL;
   cgraph_nodes = node;
   cgraph_n_nodes++;
   return node;
@@ -1899,6 +1900,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq,
   new_node->global = n->global;
   new_node->rtl = n->rtl;
   new_node->count = count;
+  new_node->frequency = n->frequency;
   new_node->clone = n->clone;
   new_node->clone.tree_map = 0;
   if (n->count)
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 6bc565a2d174..9b9bf4d42d71 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -175,6 +175,21 @@ struct GTY(()) cgraph_clone_info
   bitmap combined_args_to_skip;
 };
 
+enum node_frequency {
+  /* This function most likely won't be executed at all.
+     (set only when profile feedback is available or via function attribute). */
+  NODE_FREQUENCY_UNLIKELY_EXECUTED,
+  /* For functions that are known to be executed once (i.e. constructors, destructors
+     and main function.  */
+  NODE_FREQUENCY_EXECUTED_ONCE,
+  /* The default value.  */
+  NODE_FREQUENCY_NORMAL,
+  /* Optimize this function hard
+     (set only when profile feedback is available or via function attribute). */
+  NODE_FREQUENCY_HOT
+};
+
+
 /* The cgraph data structure.
    Each function decl has assigned cgraph_node listing callees and callers.  */
 
@@ -267,6 +282,9 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   /* Set for alias and thunk nodes, same_body points to the node they are alias
      of and they are linked through the next/previous pointers.  */
   unsigned same_body_alias : 1;
+  /* How commonly executed the node is.  Initialized during branch
+     probabilities pass.  */
+  ENUM_BITFIELD (node_frequency) frequency : 2;
 };
 
 typedef struct cgraph_node *cgraph_node_ptr;
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 3e887f81612b..d13ab18313da 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -8010,6 +8010,7 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
       && cfun->machine->use_fast_prologue_epilogue_nregs != frame->nregs)
     {
       int count = frame->nregs;
+      struct cgraph_node *node = cgraph_node (current_function_decl);
 
       cfun->machine->use_fast_prologue_epilogue_nregs = count;
       /* The fast prologue uses move instead of push to save registers.  This
@@ -8024,9 +8025,9 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
 	 slow to use many of them.  */
       if (count)
 	count = (count - 1) * FAST_PROLOGUE_INSN_COUNT;
-      if (cfun->function_frequency < FUNCTION_FREQUENCY_NORMAL
+      if (node->frequency < NODE_FREQUENCY_NORMAL
 	  || (flag_branch_probabilities
-	      && cfun->function_frequency < FUNCTION_FREQUENCY_HOT))
+	      && node->frequency < NODE_FREQUENCY_HOT))
         cfun->machine->use_fast_prologue_epilogue = false;
       else
         cfun->machine->use_fast_prologue_epilogue
@@ -26706,7 +26707,7 @@ ix86_pad_returns (void)
 	    replace = true;
 	  /* Empty functions get branch mispredict even when the jump destination
 	     is not visible to us.  */
-	  if (!prev && cfun->function_frequency > FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
+	  if (!prev && !optimize_function_for_size_p (cfun))
 	    replace = true;
 	}
       if (replace)
diff --git a/gcc/final.c b/gcc/final.c
index e2b7461bbbea..5011b6c5cacf 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -4374,14 +4374,17 @@ rest_of_clean_state (void)
       else
 	{
 	  const char *aname;
+	  struct cgraph_node *node = cgraph_node (current_function_decl);
 
 	  aname = (IDENTIFIER_POINTER
 		   (DECL_ASSEMBLER_NAME (current_function_decl)));
 	  fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
-	     cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+	     node->frequency == NODE_FREQUENCY_HOT
 	     ? " (hot)"
-	     : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+	     : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
 	     ? " (unlikely executed)"
+	     : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+	     ? " (executed once)"
 	     : "");
 
 	  flag_dump_noaddr = flag_dump_unnumbered = 1;
diff --git a/gcc/function.c b/gcc/function.c
index f78bc98af28c..949480ca9d08 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4115,8 +4115,6 @@ allocate_struct_function (tree fndecl, bool abstract_p)
 
   cfun = GGC_CNEW (struct function);
 
-  cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
-
   init_eh_for_function ();
 
   if (init_machine_status)
diff --git a/gcc/function.h b/gcc/function.h
index fb2965a2c6b7..e5e033847185 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -176,17 +176,6 @@ typedef struct ipa_opt_pass_d *ipa_opt_pass;
 DEF_VEC_P(ipa_opt_pass);
 DEF_VEC_ALLOC_P(ipa_opt_pass,heap);
 
-enum function_frequency {
-  /* This function most likely won't be executed at all.
-     (set only when profile feedback is available or via function attribute). */
-  FUNCTION_FREQUENCY_UNLIKELY_EXECUTED,
-  /* The default value.  */
-  FUNCTION_FREQUENCY_NORMAL,
-  /* Optimize this function hard
-     (set only when profile feedback is available or via function attribute). */
-  FUNCTION_FREQUENCY_HOT
-};
-
 struct GTY(()) varasm_status {
   /* If we're using a per-function constant pool, this is it.  */
   struct rtx_constant_pool *pool;
@@ -538,10 +527,6 @@ struct GTY(()) function {
      function.  */
   unsigned int va_list_fpr_size : 8;
 
-  /* How commonly executed the function is.  Initialized during branch
-     probabilities pass.  */
-  ENUM_BITFIELD (function_frequency) function_frequency : 2;
-
   /* Nonzero if function being compiled can call setjmp.  */
   unsigned int calls_setjmp : 1;
 
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index cb87143e4ac6..6f229681b2c5 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -286,6 +286,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   bp_pack_value (bp, node->process, 1);
   bp_pack_value (bp, node->alias, 1);
   bp_pack_value (bp, node->finalized_by_frontend, 1);
+  bp_pack_value (bp, node->frequency, 2);
   lto_output_bitpack (ob->main_stream, bp);
   bitpack_delete (bp);
 
@@ -544,6 +545,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
   node->process = bp_unpack_value (bp, 1);
   node->alias = bp_unpack_value (bp, 1);
   node->finalized_by_frontend = bp_unpack_value (bp, 1);
+  node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
 }
 
 
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 6afad5b612c2..4f9fca336fbb 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1314,7 +1314,6 @@ input_function (tree fn_decl, struct data_in *data_in,
   fn->has_nonlocal_label = bp_unpack_value (bp, 1);
   fn->calls_alloca = bp_unpack_value (bp, 1);
   fn->calls_setjmp = bp_unpack_value (bp, 1);
-  fn->function_frequency = (enum function_frequency) bp_unpack_value (bp, 2);
   fn->va_list_fpr_size = bp_unpack_value (bp, 8);
   fn->va_list_gpr_size = bp_unpack_value (bp, 8);
   bitpack_delete (bp);
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index c9220254db99..e9ae494f3b7f 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -1866,7 +1866,6 @@ output_function (struct cgraph_node *node)
   bp_pack_value (bp, fn->has_nonlocal_label, 1);
   bp_pack_value (bp, fn->calls_alloca, 1);
   bp_pack_value (bp, fn->calls_setjmp, 1);
-  bp_pack_value (bp, fn->function_frequency, 2);
   bp_pack_value (bp, fn->va_list_fpr_size, 8);
   bp_pack_value (bp, fn->va_list_gpr_size, 8);
   lto_output_bitpack (ob->main_stream, bp);
diff --git a/gcc/passes.c b/gcc/passes.c
index a6e5af508415..e503dc64bcc6 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1361,14 +1361,17 @@ pass_init_dump_file (struct opt_pass *pass)
       if (dump_file && current_function_decl)
 	{
 	  const char *dname, *aname;
+	  struct cgraph_node *node = cgraph_node (current_function_decl);
 	  dname = lang_hooks.decl_printable_name (current_function_decl, 2);
 	  aname = (IDENTIFIER_POINTER
 		   (DECL_ASSEMBLER_NAME (current_function_decl)));
 	  fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
-	     cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+	     node->frequency == NODE_FREQUENCY_HOT
 	     ? " (hot)"
-	     : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+	     : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
 	     ? " (unlikely executed)"
+	     : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+	     ? " (executed once)"
 	     : "");
 	}
       return initializing_dump;
diff --git a/gcc/predict.c b/gcc/predict.c
index eb5ddef2e387..29e0e2fcd997 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -113,15 +113,19 @@ static const struct predictor_info predictor_info[]= {
 static inline bool
 maybe_hot_frequency_p (int freq)
 {
+  struct cgraph_node *node = cgraph_node (current_function_decl);
   if (!profile_info || !flag_branch_probabilities)
     {
-      if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
+      if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
         return false;
-      if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT)
+      if (node->frequency == NODE_FREQUENCY_HOT)
         return true;
     }
   if (profile_status == PROFILE_ABSENT)
     return true;
+  if (node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+      && freq <= (ENTRY_BLOCK_PTR->frequency * 2 / 3))
+    return false;
   if (freq < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
     return false;
   return true;
@@ -161,11 +165,16 @@ cgraph_maybe_hot_edge_p (struct cgraph_edge *edge)
       && (edge->count
 	  <= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
     return false;
-  if (lookup_attribute ("cold", DECL_ATTRIBUTES (edge->callee->decl))
-      || lookup_attribute ("cold", DECL_ATTRIBUTES (edge->caller->decl)))
+  if (edge->caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
+      || edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
+    return false;
+  if (optimize_size)
     return false;
-  if (lookup_attribute ("hot", DECL_ATTRIBUTES (edge->caller->decl)))
+  if (edge->caller->frequency == NODE_FREQUENCY_HOT)
     return true;
+  if (edge->caller->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+      && edge->frequency < CGRAPH_FREQ_BASE * 3 / 2)
+    return false;
   if (flag_guess_branch_prob
       && edge->frequency <= (CGRAPH_FREQ_BASE
       			     / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION)))
@@ -191,7 +200,7 @@ probably_never_executed_bb_p (const_basic_block bb)
   if (profile_info && flag_branch_probabilities)
     return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
   if ((!profile_info || !flag_branch_probabilities)
-      && cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
+      && cgraph_node (current_function_decl)->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
     return true;
   return false;
 }
@@ -202,8 +211,9 @@ bool
 optimize_function_for_size_p (struct function *fun)
 {
   return (optimize_size
-	  || (fun && (fun->function_frequency
-		      == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)));
+	  || (fun && fun->decl
+	      && (cgraph_node (fun->decl)->frequency
+		  == NODE_FREQUENCY_UNLIKELY_EXECUTED)));
 }
 
 /* Return true when current function should always be optimized for speed.  */
@@ -2148,27 +2158,36 @@ void
 compute_function_frequency (void)
 {
   basic_block bb;
+  struct cgraph_node *node = cgraph_node (current_function_decl);
 
   if (!profile_info || !flag_branch_probabilities)
     {
+      int flags = flags_from_decl_or_type (current_function_decl);
       if (lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl))
 	  != NULL)
-        cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED;
+        node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
       else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl))
 	       != NULL)
-        cfun->function_frequency = FUNCTION_FREQUENCY_HOT;
+        node->frequency = NODE_FREQUENCY_HOT;
+      else if (flags & ECF_NORETURN)
+        node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
+      else if (MAIN_NAME_P (DECL_NAME (current_function_decl)))
+        node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
+      else if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
+	       || DECL_STATIC_DESTRUCTOR (current_function_decl))
+        node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
       return;
     }
-  cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED;
+  node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
   FOR_EACH_BB (bb)
     {
       if (maybe_hot_bb_p (bb))
 	{
-	  cfun->function_frequency = FUNCTION_FREQUENCY_HOT;
+	  node->frequency = NODE_FREQUENCY_HOT;
 	  return;
 	}
       if (!probably_never_executed_bb_p (bb))
-	cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
+	node->frequency = NODE_FREQUENCY_NORMAL;
     }
 }
 
@@ -2176,6 +2195,7 @@ compute_function_frequency (void)
 static void
 choose_function_section (void)
 {
+  struct cgraph_node *node = cgraph_node (current_function_decl);
   if (DECL_SECTION_NAME (current_function_decl)
       || !targetm.have_named_sections
       /* Theoretically we can split the gnu.linkonce text section too,
@@ -2191,10 +2211,10 @@ choose_function_section (void)
   if (flag_reorder_blocks_and_partition)
     return;
 
-  if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT)
+  if (node->frequency == NODE_FREQUENCY_HOT)
     DECL_SECTION_NAME (current_function_decl) =
       build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME);
-  if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
+  if (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
     DECL_SECTION_NAME (current_function_decl) =
       build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME),
 		    UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 59661a7d5096..0c1293e65171 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -2014,7 +2014,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, gcov_type count)
   cfun->last_verified = src_cfun->last_verified;
   cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
   cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
-  cfun->function_frequency = src_cfun->function_frequency;
   cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
   cfun->stdarg = src_cfun->stdarg;
   cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index f6db2415a366..a7a9e253850f 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -2738,9 +2738,10 @@ computation_cost (tree expr, bool speed)
   unsigned cost;
   /* Avoid using hard regs in ways which may be unsupported.  */
   int regno = LAST_VIRTUAL_REGISTER + 1;
-  enum function_frequency real_frequency = cfun->function_frequency;
+  struct cgraph_node *node = cgraph_node (current_function_decl);
+  enum node_frequency real_frequency = node->frequency;
 
-  cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
+  node->frequency = NODE_FREQUENCY_NORMAL;
   crtl->maybe_hot_insn_p = speed;
   walk_tree (&expr, prepare_decl_rtl, &regno, NULL);
   start_sequence ();
@@ -2748,7 +2749,7 @@ computation_cost (tree expr, bool speed)
   seq = get_insns ();
   end_sequence ();
   default_rtl_profile ();
-  cfun->function_frequency = real_frequency;
+  node->frequency = real_frequency;
 
   cost = seq_cost (seq, speed);
   if (MEM_P (rslt))
-- 
GitLab