diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 77d63554876f771ab849daa2eef222fd70302355..07f762981453b0f5ef8b628a0dc8fb5598b083f8 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 c5e0f3d940c14a342e9020ce41241507c159f54d..b58d4ee5516d71336dc52153a32d06bf1fb8a3ab 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 6bc565a2d174b99513b2c335bac1e5dd4b6fe66c..9b9bf4d42d71c158b742da62c3d98cc6eac89b1c 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 3e887f81612be1fdb556fac023436b5099a80413..d13ab18313da71e5237d1ec54dd22bb93cf3d19b 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 e2b7461bbbea18a3f3a66b460381ff753c43d0e1..5011b6c5cacf02b5b38164cd326714ea9acc51ff 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 f78bc98af28c5cf6b3d2fdec33ce9ca9dd9c1b44..949480ca9d0826232432f2dbe05201b592032759 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 fb2965a2c6b74340ec4396f494fd55c168911cbe..e5e033847185a4e9491fd02865e0f23eae9fb3a7 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 cb87143e4ac62b2f4b610a19f96a8029d619a2b1..6f229681b2c51bc3005269f44064f4ba72b4fc0e 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 6afad5b612c2729d203e80debcf1d4b426d2d398..4f9fca336fbbcf17c7389b60358237d8fdb16afb 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 c9220254db99cbcfb81c87a65f9d69bfb937672b..e9ae494f3b7fa02f41a6226d12155225ad73821b 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 a6e5af5084156300a93749e2fd1daa80e8683237..e503dc64bcc6f27f6235fccb0c07bd5d29f9c009 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 eb5ddef2e3871b0c71bdbbb46ed299d478294a53..29e0e2fcd99720f08018827442d1c5d151e7f8d3 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 59661a7d5096cf3cf5d470babd0a22ae7ab1a417..0c1293e65171907417469b175293273890179759 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 f6db2415a36650c1abbc685052268d18c45c92fe..a7a9e253850f4e88d90e6d4b9d10555c8ab19f74 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))