OSDN Git Service

PR tree-optimization/53239
[pf3gnuchains/gcc-fork.git] / gcc / predict.c
index f85786e..c12b45f 100644 (file)
@@ -1,5 +1,5 @@
 /* Branch prediction routines for the GNU compiler.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -43,7 +43,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "function.h"
 #include "except.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "recog.h"
 #include "expr.h"
 #include "predict.h"
@@ -66,8 +66,10 @@ along with GCC; see the file COPYING3.  If not see
 static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
             real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
-/* Random guesstimation given names.  */
-#define PROB_VERY_UNLIKELY     (REG_BR_PROB_BASE / 100 - 1)
+/* Random guesstimation given names.
+   PROV_VERY_UNLIKELY should be small enough so basic block predicted
+   by it gets bellow HOT_BB_FREQUENCY_FRANCTION.  */
+#define PROB_VERY_UNLIKELY     (REG_BR_PROB_BASE / 2000 - 1)
 #define PROB_EVEN              (REG_BR_PROB_BASE / 2)
 #define PROB_VERY_LIKELY       (REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
 #define PROB_ALWAYS            (REG_BR_PROB_BASE)
@@ -75,8 +77,7 @@ static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
 static void combine_predictions_for_insn (rtx, basic_block);
 static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int);
 static void predict_paths_leading_to (basic_block, enum br_predictor, enum prediction);
-static void compute_function_frequency (void);
-static void choose_function_section (void);
+static void predict_paths_leading_to_edge (edge, enum br_predictor, enum prediction);
 static bool can_predict_insn_p (const_rtx);
 
 /* Information we hold about each branch predictor.
@@ -108,32 +109,80 @@ static const struct predictor_info predictor_info[]= {
 #undef DEF_PREDICTOR
 
 /* Return TRUE if frequency FREQ is considered to be hot.  */
-static bool
+
+static inline bool
 maybe_hot_frequency_p (int freq)
 {
+  struct cgraph_node *node = cgraph_get_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 (freq < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
+  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 < ENTRY_BLOCK_PTR->frequency / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
     return false;
   return true;
 }
 
+/* Return TRUE if frequency FREQ is considered to be hot.  */
+
+static inline bool
+maybe_hot_count_p (gcov_type count)
+{
+  if (profile_status != PROFILE_READ)
+    return true;
+  /* Code executed at most once is not hot.  */
+  if (profile_info->runs >= count)
+    return false;
+  return (count
+         > profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION));
+}
+
 /* Return true in case BB can be CPU intensive and should be optimized
    for maximal performance.  */
 
 bool
 maybe_hot_bb_p (const_basic_block bb)
 {
+  if (profile_status == PROFILE_READ)
+    return maybe_hot_count_p (bb->count);
+  return maybe_hot_frequency_p (bb->frequency);
+}
+
+/* Return true if the call can be hot.  */
+
+bool
+cgraph_maybe_hot_edge_p (struct cgraph_edge *edge)
+{
   if (profile_info && flag_branch_probabilities
-      && (bb->count
-         < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
+      && (edge->count
+         <= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
     return false;
-  return maybe_hot_frequency_p (bb->frequency);
+  if (edge->caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
+      || edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
+    return false;
+  if (edge->caller->frequency > NODE_FREQUENCY_UNLIKELY_EXECUTED
+      && edge->callee->frequency <= NODE_FREQUENCY_EXECUTED_ONCE)
+    return false;
+  if (optimize_size)
+    return false;
+  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)))
+    return false;
+  return true;
 }
 
 /* Return true in case BB can be CPU intensive and should be optimized
@@ -142,42 +191,199 @@ maybe_hot_bb_p (const_basic_block bb)
 bool
 maybe_hot_edge_p (edge e)
 {
-  if (profile_info && flag_branch_probabilities
-      && (e->count
-         < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
-    return false;
+  if (profile_status == PROFILE_READ)
+    return maybe_hot_count_p (e->count);
   return maybe_hot_frequency_p (EDGE_FREQUENCY (e));
 }
 
-/* Return true in case BB is cold and should be optimized for size.  */
+
+/* Return true in case BB is probably never executed.  */
 
 bool
-probably_cold_bb_p (const_basic_block bb)
+probably_never_executed_bb_p (const_basic_block bb)
 {
-  if (profile_info && flag_branch_probabilities
-      && (bb->count
-         < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
-    return true;
+  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_get_node (current_function_decl)->frequency
+         == NODE_FREQUENCY_UNLIKELY_EXECUTED))
+    return true;
+  return false;
+}
+
+/* Return true if NODE should be optimized for size.  */
+
+bool
+cgraph_optimize_for_size_p (struct cgraph_node *node)
+{
+  if (optimize_size)
+    return true;
+  if (node && (node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED))
+    return true;
+  else
+    return false;
+}
+
+/* Return true when current function should always be optimized for size.  */
+
+bool
+optimize_function_for_size_p (struct function *fun)
+{
+  if (optimize_size)
     return true;
-  if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
+  if (!fun || !fun->decl)
+    return false;
+  return cgraph_optimize_for_size_p (cgraph_get_node (fun->decl));
+}
+
+/* Return true when current function should always be optimized for speed.  */
+
+bool
+optimize_function_for_speed_p (struct function *fun)
+{
+  return !optimize_function_for_size_p (fun);
+}
+
+/* Return TRUE when BB should be optimized for size.  */
+
+bool
+optimize_bb_for_size_p (const_basic_block bb)
+{
+  return optimize_function_for_size_p (cfun) || !maybe_hot_bb_p (bb);
+}
+
+/* Return TRUE when BB should be optimized for speed.  */
+
+bool
+optimize_bb_for_speed_p (const_basic_block bb)
+{
+  return !optimize_bb_for_size_p (bb);
+}
+
+/* Return TRUE when BB should be optimized for size.  */
+
+bool
+optimize_edge_for_size_p (edge e)
+{
+  return optimize_function_for_size_p (cfun) || !maybe_hot_edge_p (e);
+}
+
+/* Return TRUE when BB should be optimized for speed.  */
+
+bool
+optimize_edge_for_speed_p (edge e)
+{
+  return !optimize_edge_for_size_p (e);
+}
+
+/* Return TRUE when BB should be optimized for size.  */
+
+bool
+optimize_insn_for_size_p (void)
+{
+  return optimize_function_for_size_p (cfun) || !crtl->maybe_hot_insn_p;
+}
+
+/* Return TRUE when BB should be optimized for speed.  */
+
+bool
+optimize_insn_for_speed_p (void)
+{
+  return !optimize_insn_for_size_p ();
+}
+
+/* Return TRUE when LOOP should be optimized for size.  */
+
+bool
+optimize_loop_for_size_p (struct loop *loop)
+{
+  return optimize_bb_for_size_p (loop->header);
+}
+
+/* Return TRUE when LOOP should be optimized for speed.  */
+
+bool
+optimize_loop_for_speed_p (struct loop *loop)
+{
+  return optimize_bb_for_speed_p (loop->header);
+}
+
+/* Return TRUE when LOOP nest should be optimized for speed.  */
+
+bool
+optimize_loop_nest_for_speed_p (struct loop *loop)
+{
+  struct loop *l = loop;
+  if (optimize_loop_for_speed_p (loop))
     return true;
+  l = loop->inner;
+  while (l && l != loop)
+    {
+      if (optimize_loop_for_speed_p (l))
+        return true;
+      if (l->inner)
+        l = l->inner;
+      else if (l->next)
+        l = l->next;
+      else
+        {
+         while (l != loop && !l->next)
+           l = loop_outer (l);
+         if (l != loop)
+           l = l->next;
+       }
+    }
   return false;
 }
 
-/* Return true in case BB is probably never executed.  */
+/* Return TRUE when LOOP nest should be optimized for size.  */
+
 bool
-probably_never_executed_bb_p (const_basic_block bb)
+optimize_loop_nest_for_size_p (struct loop *loop)
 {
-  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)
+  return !optimize_loop_nest_for_speed_p (loop);
+}
+
+/* Return true when edge E is likely to be well predictable by branch
+   predictor.  */
+
+bool
+predictable_edge_p (edge e)
+{
+  if (profile_status == PROFILE_ABSENT)
+    return false;
+  if ((e->probability
+       <= PARAM_VALUE (PARAM_PREDICTABLE_BRANCH_OUTCOME) * REG_BR_PROB_BASE / 100)
+      || (REG_BR_PROB_BASE - e->probability
+          <= PARAM_VALUE (PARAM_PREDICTABLE_BRANCH_OUTCOME) * REG_BR_PROB_BASE / 100))
     return true;
   return false;
 }
 
+
+/* Set RTL expansion for BB profile.  */
+
+void
+rtl_profile_for_bb (basic_block bb)
+{
+  crtl->maybe_hot_insn_p = maybe_hot_bb_p (bb);
+}
+
+/* Set RTL expansion for edge profile.  */
+
+void
+rtl_profile_for_edge (edge e)
+{
+  crtl->maybe_hot_insn_p = maybe_hot_edge_p (e);
+}
+
+/* Set RTL expansion to default mode (i.e. when profile info is not known).  */
+void
+default_rtl_profile (void)
+{
+  crtl->maybe_hot_insn_p = true;
+}
+
 /* Return true if the one of outgoing edges is already predicted by
    PREDICTOR.  */
 
@@ -199,18 +405,27 @@ rtl_predicted_by_p (const_basic_block bb, enum br_predictor predictor)
 
 static struct pointer_map_t *bb_predictions;
 
+/*  Structure representing predictions in tree level. */
+
+struct edge_prediction {
+    struct edge_prediction *ep_next;
+    edge ep_edge;
+    enum br_predictor ep_predictor;
+    int ep_probability;
+};
+
 /* Return true if the one of outgoing edges is already predicted by
    PREDICTOR.  */
 
 bool
-tree_predicted_by_p (const_basic_block bb, enum br_predictor predictor)
+gimple_predicted_by_p (const_basic_block bb, enum br_predictor predictor)
 {
   struct edge_prediction *i;
   void **preds = pointer_map_contains (bb_predictions, bb);
 
   if (!preds)
     return false;
-  
+
   for (i = (struct edge_prediction *) *preds; i; i = i->ep_next)
     if (i->ep_predictor == predictor)
       return true;
@@ -218,7 +433,7 @@ tree_predicted_by_p (const_basic_block bb, enum br_predictor predictor)
 }
 
 /* Return true when the probability of edge is reliable.
-  
+
    The profile guessing code is good at predicting branch outcome (ie.
    taken/not taken), that is predicted right slightly over 75% of time.
    It is however notoriously poor on predicting the probability itself.
@@ -305,7 +520,7 @@ rtl_predict_edge (edge e, enum br_predictor predictor, int probability)
 
 /* Predict edge E with the given PROBABILITY.  */
 void
-tree_predict_edge (edge e, enum br_predictor predictor, int probability)
+gimple_predict_edge (edge e, enum br_predictor predictor, int probability)
 {
   gcc_assert (profile_status != PROFILE_GUESSED);
   if ((e->src != ENTRY_BLOCK_PTR && EDGE_COUNT (e->src->succs) > 1)
@@ -328,7 +543,7 @@ void
 remove_predictions_associated_with_edge (edge e)
 {
   void **preds;
-  
+
   if (!bb_predictions)
     return;
 
@@ -477,7 +692,7 @@ combine_predictions_for_insn (rtx insn, basic_block bb)
   rtx *pnote;
   rtx note;
   int best_probability = PROB_EVEN;
-  int best_predictor = END_PREDICTORS;
+  enum br_predictor best_predictor = END_PREDICTORS;
   int combined_probability = REG_BR_PROB_BASE / 2;
   int d;
   bool first_match = false;
@@ -500,7 +715,8 @@ combine_predictions_for_insn (rtx insn, basic_block bb)
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
     if (REG_NOTE_KIND (note) == REG_BR_PRED)
       {
-       int predictor = INTVAL (XEXP (XEXP (note, 0), 0));
+       enum br_predictor predictor = ((enum br_predictor)
+                                      INTVAL (XEXP (XEXP (note, 0), 0)));
        int probability = INTVAL (XEXP (XEXP (note, 0), 1));
 
        found = true;
@@ -546,7 +762,8 @@ combine_predictions_for_insn (rtx insn, basic_block bb)
     {
       if (REG_NOTE_KIND (*pnote) == REG_BR_PRED)
        {
-         int predictor = INTVAL (XEXP (XEXP (*pnote, 0), 0));
+         enum br_predictor predictor = ((enum br_predictor)
+                                        INTVAL (XEXP (XEXP (*pnote, 0), 0)));
          int probability = INTVAL (XEXP (XEXP (*pnote, 0), 1));
 
          dump_prediction (dump_file, predictor, probability, bb,
@@ -588,7 +805,7 @@ static void
 combine_predictions_for_bb (basic_block bb)
 {
   int best_probability = PROB_EVEN;
-  int best_predictor = END_PREDICTORS;
+  enum br_predictor best_predictor = END_PREDICTORS;
   int combined_probability = REG_BR_PROB_BASE / 2;
   int d;
   bool first_match = false;
@@ -609,7 +826,7 @@ combine_predictions_for_bb (basic_block bb)
          first = e;
       }
 
-  /* When there is no successor or only one choice, prediction is easy. 
+  /* When there is no successor or only one choice, prediction is easy.
 
      We are lazy for now and predict only basic blocks with two outgoing
      edges.  It is possible to predict generic case too, but we have to
@@ -636,15 +853,40 @@ combine_predictions_for_bb (basic_block bb)
         by predictor with smallest index.  */
       for (pred = (struct edge_prediction *) *preds; pred; pred = pred->ep_next)
        {
-         int predictor = pred->ep_predictor;
+         enum br_predictor predictor = pred->ep_predictor;
          int probability = pred->ep_probability;
 
          if (pred->ep_edge != first)
            probability = REG_BR_PROB_BASE - probability;
 
          found = true;
+         /* First match heuristics would be widly confused if we predicted
+            both directions.  */
          if (best_predictor > predictor)
-           best_probability = probability, best_predictor = predictor;
+           {
+              struct edge_prediction *pred2;
+             int prob = probability;
+
+              for (pred2 = (struct edge_prediction *) *preds; pred2; pred2 = pred2->ep_next)
+              if (pred2 != pred && pred2->ep_predictor == pred->ep_predictor)
+                {
+                  int probability2 = pred->ep_probability;
+
+                  if (pred2->ep_edge != first)
+                    probability2 = REG_BR_PROB_BASE - probability2;
+
+                  if ((probability < REG_BR_PROB_BASE / 2) !=
+                      (probability2 < REG_BR_PROB_BASE / 2))
+                    break;
+
+                  /* If the same predictor later gave better result, go for it! */
+                  if ((probability >= REG_BR_PROB_BASE / 2 && (probability2 > probability))
+                      || (probability <= REG_BR_PROB_BASE / 2 && (probability2 < probability)))
+                    prob = probability2;
+                }
+             if (!pred2)
+               best_probability = prob, best_predictor = predictor;
+           }
 
          d = (combined_probability * probability
               + (REG_BR_PROB_BASE - combined_probability)
@@ -686,7 +928,7 @@ combine_predictions_for_bb (basic_block bb)
     {
       for (pred = (struct edge_prediction *) *preds; pred; pred = pred->ep_next)
        {
-         int predictor = pred->ep_predictor;
+         enum br_predictor predictor = pred->ep_predictor;
          int probability = pred->ep_probability;
 
          if (pred->ep_edge != EDGE_SUCC (bb, 0))
@@ -712,8 +954,6 @@ predict_loops (void)
   loop_iterator li;
   struct loop *loop;
 
-  scev_initialize ();
-
   /* Try to predict out blocks in a loop that are not part of a
      natural loop.  */
   FOR_EACH_LOOP (li, loop, 0)
@@ -727,7 +967,7 @@ predict_loops (void)
       exits = get_loop_exit_edges (loop);
       n_exits = VEC_length (edge, exits);
 
-      for (j = 0; VEC_iterate (edge, exits, j, ex); j++)
+      FOR_EACH_VEC_ELT (edge, exits, j, ex)
        {
          tree niter = NULL;
          HOST_WIDE_INT nitercst;
@@ -754,7 +994,7 @@ predict_loops (void)
             the loop, use it to predict this exit.  */
          else if (n_exits == 1)
            {
-             nitercst = estimated_loop_iterations_int (loop, false);
+             nitercst = max_stmt_executions_int (loop, false);
              if (nitercst < 0)
                continue;
              if (nitercst > max)
@@ -820,7 +1060,7 @@ predict_loops (void)
                 EDGE_PROBABILITY_RELIABLE from trusting the branch prediction
                 as this was causing regression in perl benchmark containing such
                 a wide loop.  */
-               
+
              int probability = ((REG_BR_PROB_BASE
                                  - predictor_info [(int) PRED_LOOP_EXIT].hitrate)
                                 / n_exits);
@@ -832,12 +1072,10 @@ predict_loops (void)
                  predict_edge (e, PRED_LOOP_EXIT, probability);
            }
        }
-      
+
       /* Free basic blocks from get_loop_body.  */
       free (bbs);
     }
-
-  scev_finalize ();
 }
 
 /* Attempt to predict probabilities of BB outgoing edges using local
@@ -947,36 +1185,38 @@ guess_outgoing_edge_probabilities (basic_block bb)
   combine_predictions_for_insn (BB_END (bb), bb);
 }
 \f
-/* Return constant EXPR will likely have at execution time, NULL if unknown. 
-   The function is used by builtin_expect branch predictor so the evidence
-   must come from this construct and additional possible constant folding.
-  
-   We may want to implement more involved value guess (such as value range
-   propagation based prediction), but such tricks shall go to new
-   implementation.  */
+static tree expr_expected_value (tree, bitmap);
+
+/* Helper function for expr_expected_value.  */
 
 static tree
-expr_expected_value (tree expr, bitmap visited)
+expr_expected_value_1 (tree type, tree op0, enum tree_code code,
+                      tree op1, bitmap visited)
 {
-  if (TREE_CONSTANT (expr))
-    return expr;
-  else if (TREE_CODE (expr) == SSA_NAME)
+  gimple def;
+
+  if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS)
     {
-      tree def = SSA_NAME_DEF_STMT (expr);
+      if (TREE_CONSTANT (op0))
+       return op0;
+
+      if (code != SSA_NAME)
+       return NULL_TREE;
+
+      def = SSA_NAME_DEF_STMT (op0);
 
       /* If we were already here, break the infinite cycle.  */
-      if (bitmap_bit_p (visited, SSA_NAME_VERSION (expr)))
+      if (!bitmap_set_bit (visited, SSA_NAME_VERSION (op0)))
        return NULL;
-      bitmap_set_bit (visited, SSA_NAME_VERSION (expr));
 
-      if (TREE_CODE (def) == PHI_NODE)
+      if (gimple_code (def) == GIMPLE_PHI)
        {
          /* All the arguments of the PHI node must have the same constant
             length.  */
-         int i;
+         int i, n = gimple_phi_num_args (def);
          tree val = NULL, new_val;
 
-         for (i = 0; i < PHI_NUM_ARGS (def); i++)
+         for (i = 0; i < n; i++)
            {
              tree arg = PHI_ARG_DEF (def, i);
 
@@ -999,111 +1239,184 @@ expr_expected_value (tree expr, bitmap visited)
            }
          return val;
        }
-      if (TREE_CODE (def) != GIMPLE_MODIFY_STMT
-         || GIMPLE_STMT_OPERAND (def, 0) != expr)
-       return NULL;
-      return expr_expected_value (GIMPLE_STMT_OPERAND (def, 1), visited);
-    }
-  else if (TREE_CODE (expr) == CALL_EXPR)
-    {
-      tree decl = get_callee_fndecl (expr);
-      if (!decl)
-       return NULL;
-      if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
-         && DECL_FUNCTION_CODE (decl) == BUILT_IN_EXPECT)
+      if (is_gimple_assign (def))
        {
-         tree val;
+         if (gimple_assign_lhs (def) != op0)
+           return NULL;
+
+         return expr_expected_value_1 (TREE_TYPE (gimple_assign_lhs (def)),
+                                       gimple_assign_rhs1 (def),
+                                       gimple_assign_rhs_code (def),
+                                       gimple_assign_rhs2 (def),
+                                       visited);
+       }
 
-         if (call_expr_nargs (expr) != 2)
+      if (is_gimple_call (def))
+       {
+         tree decl = gimple_call_fndecl (def);
+         if (!decl)
            return NULL;
-         val = CALL_EXPR_ARG (expr, 0);
-         if (TREE_CONSTANT (val))
-           return val;
-         return CALL_EXPR_ARG (expr, 1);
+         if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
+           switch (DECL_FUNCTION_CODE (decl))
+             {
+             case BUILT_IN_EXPECT:
+               {
+                 tree val;
+                 if (gimple_call_num_args (def) != 2)
+                   return NULL;
+                 val = gimple_call_arg (def, 0);
+                 if (TREE_CONSTANT (val))
+                   return val;
+                 return gimple_call_arg (def, 1);
+               }
+
+             case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N:
+             case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_1:
+             case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_2:
+             case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4:
+             case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8:
+             case BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_16:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8:
+             case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16:
+               /* Assume that any given atomic operation has low contention,
+                  and thus the compare-and-swap operation succeeds.  */
+               return boolean_true_node;
+           }
        }
+
+      return NULL;
     }
-  if (BINARY_CLASS_P (expr) || COMPARISON_CLASS_P (expr))
+
+  if (get_gimple_rhs_class (code) == GIMPLE_BINARY_RHS)
     {
-      tree op0, op1, res;
-      op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
+      tree res;
+      op0 = expr_expected_value (op0, visited);
       if (!op0)
        return NULL;
-      op1 = expr_expected_value (TREE_OPERAND (expr, 1), visited);
+      op1 = expr_expected_value (op1, visited);
       if (!op1)
        return NULL;
-      res = fold_build2 (TREE_CODE (expr), TREE_TYPE (expr), op0, op1);
+      res = fold_build2 (code, type, op0, op1);
       if (TREE_CONSTANT (res))
        return res;
       return NULL;
     }
-  if (UNARY_CLASS_P (expr))
+  if (get_gimple_rhs_class (code) == GIMPLE_UNARY_RHS)
     {
-      tree op0, res;
-      op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
+      tree res;
+      op0 = expr_expected_value (op0, visited);
       if (!op0)
        return NULL;
-      res = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr), op0);
+      res = fold_build1 (code, type, op0);
       if (TREE_CONSTANT (res))
        return res;
       return NULL;
     }
   return NULL;
 }
+
+/* Return constant EXPR will likely have at execution time, NULL if unknown.
+   The function is used by builtin_expect branch predictor so the evidence
+   must come from this construct and additional possible constant folding.
+
+   We may want to implement more involved value guess (such as value range
+   propagation based prediction), but such tricks shall go to new
+   implementation.  */
+
+static tree
+expr_expected_value (tree expr, bitmap visited)
+{
+  enum tree_code code;
+  tree op0, op1;
+
+  if (TREE_CONSTANT (expr))
+    return expr;
+
+  extract_ops_from_tree (expr, &code, &op0, &op1);
+  return expr_expected_value_1 (TREE_TYPE (expr),
+                               op0, code, op1, visited);
+}
+
 \f
-/* Get rid of all builtin_expect calls we no longer need.  */
-static void
-strip_builtin_expect (void)
+/* Get rid of all builtin_expect calls and GIMPLE_PREDICT statements
+   we no longer need.  */
+static unsigned int
+strip_predict_hints (void)
 {
   basic_block bb;
+  gimple ass_stmt;
+  tree var;
+
   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator bi;
-      for (bi = bsi_start (bb); !bsi_end_p (bi); bsi_next (&bi))
+      gimple_stmt_iterator bi;
+      for (bi = gsi_start_bb (bb); !gsi_end_p (bi);)
        {
-         tree stmt = bsi_stmt (bi);
-         tree fndecl;
-         tree call;
-
-         if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-             && (call = GIMPLE_STMT_OPERAND (stmt, 1))
-             && TREE_CODE (call) == CALL_EXPR
-             && (fndecl = get_callee_fndecl (call))
-             && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-             && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
-             && call_expr_nargs (call) == 2)
+         gimple stmt = gsi_stmt (bi);
+
+         if (gimple_code (stmt) == GIMPLE_PREDICT)
            {
-             GIMPLE_STMT_OPERAND (stmt, 1) = CALL_EXPR_ARG (call, 0);
-             update_stmt (stmt);
+             gsi_remove (&bi, true);
+             continue;
            }
+         else if (gimple_code (stmt) == GIMPLE_CALL)
+           {
+             tree fndecl = gimple_call_fndecl (stmt);
+
+             if (fndecl
+                 && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+                 && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+                 && gimple_call_num_args (stmt) == 2)
+               {
+                 var = gimple_call_lhs (stmt);
+                 if (var)
+                   {
+                     ass_stmt
+                       = gimple_build_assign (var, gimple_call_arg (stmt, 0));
+                     gsi_replace (&bi, ass_stmt, true);
+                   }
+                 else
+                   {
+                     gsi_remove (&bi, true);
+                     continue;
+                   }
+               }
+           }
+         gsi_next (&bi);
        }
     }
+  return 0;
 }
 \f
 /* Predict using opcode of the last statement in basic block.  */
 static void
 tree_predict_by_opcode (basic_block bb)
 {
-  tree stmt = last_stmt (bb);
+  gimple stmt = last_stmt (bb);
   edge then_edge;
-  tree cond;
-  tree op0;
+  tree op0, op1;
   tree type;
   tree val;
+  enum tree_code cmp;
   bitmap visited;
   edge_iterator ei;
 
-  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
+  if (!stmt || gimple_code (stmt) != GIMPLE_COND)
     return;
   FOR_EACH_EDGE (then_edge, ei, bb->succs)
     if (then_edge->flags & EDGE_TRUE_VALUE)
       break;
-  cond = TREE_OPERAND (stmt, 0);
-  if (!COMPARISON_CLASS_P (cond))
-    return;
-  op0 = TREE_OPERAND (cond, 0);
+  op0 = gimple_cond_lhs (stmt);
+  op1 = gimple_cond_rhs (stmt);
+  cmp = gimple_cond_code (stmt);
   type = TREE_TYPE (op0);
   visited = BITMAP_ALLOC (NULL);
-  val = expr_expected_value (cond, visited);
+  val = expr_expected_value_1 (boolean_type_node, op0, cmp, op1, visited);
   BITMAP_FREE (visited);
   if (val)
     {
@@ -1118,9 +1431,9 @@ tree_predict_by_opcode (basic_block bb)
      Similarly, a comparison ptr1 == ptr2 is predicted as false.  */
   if (POINTER_TYPE_P (type))
     {
-      if (TREE_CODE (cond) == EQ_EXPR)
+      if (cmp == EQ_EXPR)
        predict_edge_def (then_edge, PRED_TREE_POINTER, NOT_TAKEN);
-      else if (TREE_CODE (cond) == NE_EXPR)
+      else if (cmp == NE_EXPR)
        predict_edge_def (then_edge, PRED_TREE_POINTER, TAKEN);
     }
   else
@@ -1129,7 +1442,7 @@ tree_predict_by_opcode (basic_block bb)
      EQ tests are usually false and NE tests are usually true. Also,
      most quantities are positive, so we can make the appropriate guesses
      about signed comparisons against zero.  */
-    switch (TREE_CODE (cond))
+    switch (cmp)
       {
       case EQ_EXPR:
       case UNEQ_EXPR:
@@ -1140,8 +1453,7 @@ tree_predict_by_opcode (basic_block bb)
          ;
        /* Comparisons with 0 are often used for booleans and there is
           nothing useful to predict about them.  */
-       else if (integer_zerop (op0)
-                || integer_zerop (TREE_OPERAND (cond, 1)))
+       else if (integer_zerop (op0) || integer_zerop (op1))
          ;
        else
          predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, NOT_TAKEN);
@@ -1157,7 +1469,7 @@ tree_predict_by_opcode (basic_block bb)
        /* Comparisons with 0 are often used for booleans and there is
           nothing useful to predict about them.  */
        else if (integer_zerop (op0)
-                || integer_zerop (TREE_OPERAND (cond, 1)))
+                || integer_zerop (op1))
          ;
        else
          predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, TAKEN);
@@ -1173,23 +1485,23 @@ tree_predict_by_opcode (basic_block bb)
 
       case LE_EXPR:
       case LT_EXPR:
-       if (integer_zerop (TREE_OPERAND (cond, 1))
-           || integer_onep (TREE_OPERAND (cond, 1))
-           || integer_all_onesp (TREE_OPERAND (cond, 1))
-           || real_zerop (TREE_OPERAND (cond, 1))
-           || real_onep (TREE_OPERAND (cond, 1))
-           || real_minus_onep (TREE_OPERAND (cond, 1)))
+       if (integer_zerop (op1)
+           || integer_onep (op1)
+           || integer_all_onesp (op1)
+           || real_zerop (op1)
+           || real_onep (op1)
+           || real_minus_onep (op1))
          predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, NOT_TAKEN);
        break;
 
       case GE_EXPR:
       case GT_EXPR:
-       if (integer_zerop (TREE_OPERAND (cond, 1))
-           || integer_onep (TREE_OPERAND (cond, 1))
-           || integer_all_onesp (TREE_OPERAND (cond, 1))
-           || real_zerop (TREE_OPERAND (cond, 1))
-           || real_onep (TREE_OPERAND (cond, 1))
-           || real_minus_onep (TREE_OPERAND (cond, 1)))
+       if (integer_zerop (op1)
+           || integer_onep (op1)
+           || integer_all_onesp (op1)
+           || real_zerop (op1)
+           || real_onep (op1)
+           || real_minus_onep (op1))
          predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, TAKEN);
        break;
 
@@ -1199,6 +1511,7 @@ tree_predict_by_opcode (basic_block bb)
 }
 
 /* Try to guess whether the value of return means error code.  */
+
 static enum br_predictor
 return_prediction (tree val, enum prediction *prediction)
 {
@@ -1243,10 +1556,10 @@ return_prediction (tree val, enum prediction *prediction)
 static void
 apply_return_prediction (void)
 {
-  tree return_stmt = NULL;
+  gimple return_stmt = NULL;
   tree return_val;
   edge e;
-  tree phi;
+  gimple phi;
   int phi_num_args, i;
   enum br_predictor pred;
   enum prediction direction;
@@ -1256,26 +1569,20 @@ apply_return_prediction (void)
     {
       return_stmt = last_stmt (e->src);
       if (return_stmt
-         && TREE_CODE (return_stmt) == RETURN_EXPR)
+         && gimple_code (return_stmt) == GIMPLE_RETURN)
        break;
     }
   if (!e)
     return;
-  return_val = TREE_OPERAND (return_stmt, 0);
+  return_val = gimple_return_retval (return_stmt);
   if (!return_val)
     return;
-  if (TREE_CODE (return_val) == GIMPLE_MODIFY_STMT)
-    return_val = GIMPLE_STMT_OPERAND (return_val, 1);
   if (TREE_CODE (return_val) != SSA_NAME
       || !SSA_NAME_DEF_STMT (return_val)
-      || TREE_CODE (SSA_NAME_DEF_STMT (return_val)) != PHI_NODE)
+      || gimple_code (SSA_NAME_DEF_STMT (return_val)) != GIMPLE_PHI)
     return;
-  for (phi = SSA_NAME_DEF_STMT (return_val); phi; phi = PHI_CHAIN (phi))
-    if (PHI_RESULT (phi) == return_val)
-      break;
-  if (!phi)
-    return;
-  phi_num_args = PHI_NUM_ARGS (phi);
+  phi = SSA_NAME_DEF_STMT (return_val);
+  phi_num_args = gimple_phi_num_args (phi);
   pred = return_prediction (PHI_ARG_DEF (phi, 0), &direction);
 
   /* Avoid the degenerate case where all return values form the function
@@ -1289,8 +1596,8 @@ apply_return_prediction (void)
       {
        pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
        if (pred != PRED_NO_PREDICTION)
-         predict_paths_leading_to (PHI_ARG_EDGE (phi, i)->src, pred,
-                                   direction);
+         predict_paths_leading_to_edge (gimple_phi_arg_edge (phi, i), pred,
+                                        direction);
       }
 }
 
@@ -1302,51 +1609,48 @@ static void
 tree_bb_level_predictions (void)
 {
   basic_block bb;
+  bool has_return_edges = false;
+  edge e;
+  edge_iterator ei;
+
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+    if (!(e->flags & (EDGE_ABNORMAL | EDGE_FAKE | EDGE_EH)))
+      {
+        has_return_edges = true;
+       break;
+      }
 
   apply_return_prediction ();
 
   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator bsi = bsi_last (bb);
+      gimple_stmt_iterator gsi;
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi);)
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         tree stmt = bsi_stmt (bsi);
+         gimple stmt = gsi_stmt (gsi);
          tree decl;
-         bool next = false;
 
-         switch (TREE_CODE (stmt))
+         if (is_gimple_call (stmt))
+           {
+             if ((gimple_call_flags (stmt) & ECF_NORETURN)
+                 && has_return_edges)
+               predict_paths_leading_to (bb, PRED_NORETURN,
+                                         NOT_TAKEN);
+             decl = gimple_call_fndecl (stmt);
+             if (decl
+                 && lookup_attribute ("cold",
+                                      DECL_ATTRIBUTES (decl)))
+               predict_paths_leading_to (bb, PRED_COLD_FUNCTION,
+                                         NOT_TAKEN);
+           }
+         else if (gimple_code (stmt) == GIMPLE_PREDICT)
            {
-             case GIMPLE_MODIFY_STMT:
-               if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR)
-                 {
-                   stmt = GIMPLE_STMT_OPERAND (stmt, 1);
-                   goto call_expr;
-                 }
-               break;
-             case CALL_EXPR:
-call_expr:;
-               if (call_expr_flags (stmt) & ECF_NORETURN)
-                 predict_paths_leading_to (bb, PRED_NORETURN,
-                                           NOT_TAKEN);
-               decl = get_callee_fndecl (stmt);
-               if (decl
-                   && lookup_attribute ("cold",
-                                        DECL_ATTRIBUTES (decl)))
-                 predict_paths_leading_to (bb, PRED_COLD_FUNCTION,
-                                           NOT_TAKEN);
-               break;
-             case PREDICT_EXPR:
-               predict_paths_leading_to (bb, PREDICT_EXPR_PREDICTOR (stmt),
-                                         PREDICT_EXPR_OUTCOME (stmt));
-               bsi_remove (&bsi, true);
-               next = true;
-               break;
-             default:
-               break;
+             predict_paths_leading_to (bb, gimple_predict_predictor (stmt),
+                                       gimple_predict_outcome (stmt));
+             /* Keep GIMPLE_PREDICT around so early inlining will propagate
+                hints to callers.  */
            }
-         if (!next)
-           bsi_next (&bsi);
        }
     }
 }
@@ -1365,16 +1669,96 @@ assert_is_empty (const void *key ATTRIBUTE_UNUSED, void **value,
 }
 #endif
 
-/* Predict branch probabilities and estimate profile of the tree CFG.  */
-static unsigned int
+/* Predict branch probabilities and estimate profile for basic block BB.  */
+
+static void
+tree_estimate_probability_bb (basic_block bb)
+{
+  edge e;
+  edge_iterator ei;
+  gimple last;
+
+  FOR_EACH_EDGE (e, ei, bb->succs)
+    {
+      /* Predict early returns to be probable, as we've already taken
+        care for error returns and other cases are often used for
+        fast paths through function.
+
+        Since we've already removed the return statements, we are
+        looking for CFG like:
+
+        if (conditional)
+        {
+        ..
+        goto return_block
+        }
+        some other blocks
+        return_block:
+        return_stmt.  */
+      if (e->dest != bb->next_bb
+         && e->dest != EXIT_BLOCK_PTR
+         && single_succ_p (e->dest)
+         && single_succ_edge (e->dest)->dest == EXIT_BLOCK_PTR
+         && (last = last_stmt (e->dest)) != NULL
+         && gimple_code (last) == GIMPLE_RETURN)
+       {
+         edge e1;
+         edge_iterator ei1;
+
+         if (single_succ_p (bb))
+           {
+             FOR_EACH_EDGE (e1, ei1, bb->preds)
+               if (!predicted_by_p (e1->src, PRED_NULL_RETURN)
+                   && !predicted_by_p (e1->src, PRED_CONST_RETURN)
+                   && !predicted_by_p (e1->src, PRED_NEGATIVE_RETURN))
+                 predict_edge_def (e1, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
+           }
+         else
+           if (!predicted_by_p (e->src, PRED_NULL_RETURN)
+               && !predicted_by_p (e->src, PRED_CONST_RETURN)
+               && !predicted_by_p (e->src, PRED_NEGATIVE_RETURN))
+             predict_edge_def (e, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
+       }
+
+      /* Look for block we are guarding (ie we dominate it,
+        but it doesn't postdominate us).  */
+      if (e->dest != EXIT_BLOCK_PTR && e->dest != bb
+         && dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
+         && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e->dest))
+       {
+         gimple_stmt_iterator bi;
+
+         /* The call heuristic claims that a guarded function call
+            is improbable.  This is because such calls are often used
+            to signal exceptional situations such as printing error
+            messages.  */
+         for (bi = gsi_start_bb (e->dest); !gsi_end_p (bi);
+              gsi_next (&bi))
+           {
+             gimple stmt = gsi_stmt (bi);
+             if (is_gimple_call (stmt)
+                 /* Constant and pure calls are hardly used to signalize
+                    something exceptional.  */
+                 && gimple_has_side_effects (stmt))
+               {
+                 predict_edge_def (e, PRED_CALL, NOT_TAKEN);
+                 break;
+               }
+           }
+       }
+    }
+  tree_predict_by_opcode (bb);
+}
+
+/* Predict branch probabilities and estimate profile of the tree CFG.
+   This function can be called from the loop optimizers to recompute
+   the profile information.  */
+
+void
 tree_estimate_probability (void)
 {
   basic_block bb;
 
-  loop_optimizer_init (0);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    flow_loops_dump (dump_file, NULL, 0);
-
   add_noreturn_fake_exit_edges ();
   connect_infinite_loops_to_exit ();
   /* We use loop_niter_by_eval, which requires that the loops have
@@ -1384,90 +1768,14 @@ tree_estimate_probability (void)
 
   bb_predictions = pointer_map_create ();
   tree_bb_level_predictions ();
-
-  mark_irreducible_loops ();
   record_loop_exits ();
+
   if (number_of_loops () > 1)
     predict_loops ();
 
   FOR_EACH_BB (bb)
-    {
-      edge e;
-      edge_iterator ei;
-
-      FOR_EACH_EDGE (e, ei, bb->succs)
-       {
-         /* Predict early returns to be probable, as we've already taken
-            care for error returns and other cases are often used for
-            fast paths through function. 
-
-            Since we've already removed the return statements, we are
-            looking for CFG like:
+    tree_estimate_probability_bb (bb);
 
-              if (conditional)
-                {
-                  ..
-                  goto return_block
-                }
-              some other blocks
-            return_block:
-              return_stmt.  */
-         if (e->dest != bb->next_bb
-             && e->dest != EXIT_BLOCK_PTR
-             && single_succ_p (e->dest)
-             && single_succ_edge (e->dest)->dest == EXIT_BLOCK_PTR
-             && TREE_CODE (last_stmt (e->dest)) == RETURN_EXPR)
-           {
-             edge e1;
-             edge_iterator ei1;
-
-             if (single_succ_p (bb))
-               {
-                 FOR_EACH_EDGE (e1, ei1, bb->preds)
-                   if (!predicted_by_p (e1->src, PRED_NULL_RETURN)
-                       && !predicted_by_p (e1->src, PRED_CONST_RETURN)
-                       && !predicted_by_p (e1->src, PRED_NEGATIVE_RETURN))
-                     predict_edge_def (e1, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
-               }
-              else
-               if (!predicted_by_p (e->src, PRED_NULL_RETURN)
-                   && !predicted_by_p (e->src, PRED_CONST_RETURN)
-                   && !predicted_by_p (e->src, PRED_NEGATIVE_RETURN))
-                 predict_edge_def (e, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
-           }
-
-         /* Look for block we are guarding (ie we dominate it,
-            but it doesn't postdominate us).  */
-         if (e->dest != EXIT_BLOCK_PTR && e->dest != bb
-             && dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
-             && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e->dest))
-           {
-             block_stmt_iterator bi;
-
-             /* The call heuristic claims that a guarded function call
-                is improbable.  This is because such calls are often used
-                to signal exceptional situations such as printing error
-                messages.  */
-             for (bi = bsi_start (e->dest); !bsi_end_p (bi);
-                  bsi_next (&bi))
-               {
-                 tree stmt = bsi_stmt (bi);
-                 if ((TREE_CODE (stmt) == CALL_EXPR
-                      || (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-                          && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1))
-                             == CALL_EXPR))
-                     /* Constant and pure calls are hardly used to signalize
-                        something exceptional.  */
-                     && TREE_SIDE_EFFECTS (stmt))
-                   {
-                     predict_edge_def (e, PRED_CALL, NOT_TAKEN);
-                     break;
-                   }
-               }
-           }
-       }
-      tree_predict_by_opcode (bb);
-    }
   FOR_EACH_BB (bb)
     combine_predictions_for_bb (bb);
 
@@ -1477,13 +1785,37 @@ tree_estimate_probability (void)
   pointer_map_destroy (bb_predictions);
   bb_predictions = NULL;
 
-  strip_builtin_expect ();
   estimate_bb_frequencies ();
   free_dominance_info (CDI_POST_DOMINATORS);
   remove_fake_exit_edges ();
+}
+
+/* Predict branch probabilities and estimate profile of the tree CFG.
+   This is the driver function for PASS_PROFILE.  */
+
+static unsigned int
+tree_estimate_probability_driver (void)
+{
+  unsigned nb_loops;
+
+  loop_optimizer_init (0);
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    flow_loops_dump (dump_file, NULL, 0);
+
+  mark_irreducible_loops ();
+
+  nb_loops = number_of_loops ();
+  if (nb_loops > 1)
+    scev_initialize ();
+
+  tree_estimate_probability ();
+
+  if (nb_loops > 1)
+    scev_finalize ();
+
   loop_optimizer_finalize ();
   if (dump_file && (dump_flags & TDF_DETAILS))
-    dump_tree_cfg (dump_file, dump_flags);
+    gimple_dump_cfg (dump_file, dump_flags);
   if (profile_status == PROFILE_ABSENT)
     profile_status = PROFILE_GUESSED;
   return 0;
@@ -1495,7 +1827,8 @@ tree_estimate_probability (void)
 static void
 predict_paths_for_bb (basic_block cur, basic_block bb,
                      enum br_predictor pred,
-                     enum prediction taken)
+                     enum prediction taken,
+                     bitmap visited)
 {
   edge e;
   edge_iterator ei;
@@ -1507,13 +1840,42 @@ predict_paths_for_bb (basic_block cur, basic_block bb,
     if (e->src->index >= NUM_FIXED_BLOCKS
        && !dominated_by_p (CDI_POST_DOMINATORS, e->src, bb))
     {
+      edge e2;
+      edge_iterator ei2;
+      bool found = false;
+
+      /* Ignore fake edges and eh, we predict them as not taken anyway.  */
+      if (e->flags & (EDGE_EH | EDGE_FAKE))
+       continue;
       gcc_assert (bb == cur || dominated_by_p (CDI_POST_DOMINATORS, cur, bb));
-      predict_edge_def (e, pred, taken);
+
+      /* See if there is an edge from e->src that is not abnormal
+        and does not lead to BB.  */
+      FOR_EACH_EDGE (e2, ei2, e->src->succs)
+       if (e2 != e
+           && !(e2->flags & (EDGE_EH | EDGE_FAKE))
+           && !dominated_by_p (CDI_POST_DOMINATORS, e2->dest, bb))
+         {
+           found = true;
+           break;
+         }
+
+      /* If there is non-abnormal path leaving e->src, predict edge
+        using predictor.  Otherwise we need to look for paths
+        leading to e->src.
+
+        The second may lead to infinite loop in the case we are predicitng
+        regions that are only reachable by abnormal edges.  We simply
+        prevent visiting given BB twice.  */
+      if (found)
+        predict_edge_def (e, pred, taken);
+      else if (bitmap_set_bit (visited, e->src->index))
+       predict_paths_for_bb (e->src, e->src, pred, taken, visited);
     }
   for (son = first_dom_son (CDI_POST_DOMINATORS, cur);
        son;
        son = next_dom_son (CDI_POST_DOMINATORS, son))
-    predict_paths_for_bb (son, bb, pred, taken);
+    predict_paths_for_bb (son, bb, pred, taken, visited);
 }
 
 /* Sets branch probabilities according to PREDiction and
@@ -1523,7 +1885,38 @@ static void
 predict_paths_leading_to (basic_block bb, enum br_predictor pred,
                          enum prediction taken)
 {
-  predict_paths_for_bb (bb, bb, pred, taken);
+  bitmap visited = BITMAP_ALLOC (NULL);
+  predict_paths_for_bb (bb, bb, pred, taken, visited);
+  BITMAP_FREE (visited);
+}
+
+/* Like predict_paths_leading_to but take edge instead of basic block.  */
+
+static void
+predict_paths_leading_to_edge (edge e, enum br_predictor pred,
+                              enum prediction taken)
+{
+  bool has_nonloop_edge = false;
+  edge_iterator ei;
+  edge e2;
+
+  basic_block bb = e->src;
+  FOR_EACH_EDGE (e2, ei, bb->succs)
+    if (e2->dest != e->src && e2->dest != e->dest
+       && !(e->flags & (EDGE_EH | EDGE_FAKE))
+       && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e2->dest))
+      {
+       has_nonloop_edge = true;
+       break;
+      }
+  if (!has_nonloop_edge)
+    {
+      bitmap visited = BITMAP_ALLOC (NULL);
+      predict_paths_for_bb (bb, bb, pred, taken, visited);
+      BITMAP_FREE (visited);
+    }
+  else
+    predict_edge_def (e, pred, taken);
 }
 \f
 /* This is used to carry information about basic blocks.  It is
@@ -1576,9 +1969,6 @@ propagate_freq (basic_block head, bitmap tovisit)
       edge_iterator ei;
       int count = 0;
 
-       /* The outermost "loop" includes the exit block, which we can not
-         look up via BASIC_BLOCK.  Detect this and use EXIT_BLOCK_PTR
-         directly.  Do the same for the entry block.  */
       bb = BASIC_BLOCK (i);
 
       FOR_EACH_EDGE (e, ei, bb->preds)
@@ -1593,6 +1983,9 @@ propagate_freq (basic_block head, bitmap tovisit)
                     e->src->index, bb->index);
        }
       BLOCK_INFO (bb)->npredecessors = count;
+      /* When function never returns, we will never process exit block.  */
+      if (!count && bb == EXIT_BLOCK_PTR)
+       bb->count = bb->frequency = 0;
     }
 
   memcpy (&BLOCK_INFO (head)->frequency, &real_one, sizeof (real_one));
@@ -1665,11 +2058,11 @@ propagate_freq (basic_block head, bitmap tovisit)
       if (e)
        {
          sreal tmp;
-           
+
          /* EDGE_INFO (e)->back_edge_prob
             = ((e->probability * BLOCK_INFO (bb)->frequency)
             / REG_BR_PROB_BASE); */
-           
+
          sreal_init (&tmp, e->probability, 0);
          sreal_mul (&tmp, &tmp, &BLOCK_INFO (bb)->frequency);
          sreal_mul (&EDGE_INFO (e)->back_edge_prob,
@@ -1688,7 +2081,7 @@ propagate_freq (basic_block head, bitmap tovisit)
                  nextbb = e->dest;
                else
                  BLOCK_INFO (last)->next = e->dest;
-               
+
                last = e->dest;
              }
          }
@@ -1754,7 +2147,7 @@ counts_to_freqs (void)
   gcov_type count_max, true_count_max = 0;
   basic_block bb;
 
-  FOR_EACH_BB (bb)
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
     true_count_max = MAX (bb->count, true_count_max);
 
   count_max = MAX (true_count_max, 1);
@@ -1813,7 +2206,7 @@ estimate_bb_frequencies (void)
   basic_block bb;
   sreal freq_max;
 
-  if (!flag_branch_probabilities || !counts_to_freqs ())
+  if (profile_status != PROFILE_READ || !counts_to_freqs ())
     {
       static int real_values_initialized = 0;
 
@@ -1873,67 +2266,51 @@ estimate_bb_frequencies (void)
       free_aux_for_edges ();
     }
   compute_function_frequency ();
-  if (flag_reorder_functions)
-    choose_function_section ();
 }
 
 /* Decide whether function is hot, cold or unlikely executed.  */
-static void
+void
 compute_function_frequency (void)
 {
   basic_block bb;
+  struct cgraph_node *node = cgraph_get_node (current_function_decl);
+  if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
+      || MAIN_NAME_P (DECL_NAME (current_function_decl)))
+    node->only_called_at_startup = true;
+  if (DECL_STATIC_DESTRUCTOR (current_function_decl))
+    node->only_called_at_exit = true;
 
   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;
     }
 }
 
-/* Choose appropriate section for the function.  */
-static void
-choose_function_section (void)
-{
-  if (DECL_SECTION_NAME (current_function_decl)
-      || !targetm.have_named_sections
-      /* Theoretically we can split the gnu.linkonce text section too,
-        but this requires more work as the frequency needs to match
-        for all generated objects so we need to merge the frequency
-        of all instances.  For now just never set frequency for these.  */
-      || DECL_ONE_ONLY (current_function_decl))
-    return;
-
-  /* If we are doing the partitioning optimization, let the optimization
-     choose the correct section into which to put things.  */
-
-  if (flag_reorder_blocks_and_partition)
-    return;
-
-  if (cfun->function_frequency == FUNCTION_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)
-    DECL_SECTION_NAME (current_function_decl) =
-      build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME),
-                   UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
-}
-
 static bool
 gate_estimate_probability (void)
 {
@@ -1945,8 +2322,8 @@ tree
 build_predict_expr (enum br_predictor predictor, enum prediction taken)
 {
   tree t = build1 (PREDICT_EXPR, void_type_node,
-                  build_int_cst (NULL, predictor));
-  PREDICT_EXPR_OUTCOME (t) = taken;
+                  build_int_cst (integer_type_node, predictor));
+  SET_PREDICT_EXPR_OUTCOME (t, taken);
   return t;
 }
 
@@ -1956,13 +2333,13 @@ predictor_name (enum br_predictor predictor)
   return predictor_info[predictor].name;
 }
 
-struct gimple_opt_pass pass_profile = 
+struct gimple_opt_pass pass_profile =
 {
  {
   GIMPLE_PASS,
-  "profile",                           /* name */
+  "profile_estimate",                  /* name */
   gate_estimate_probability,           /* gate */
-  tree_estimate_probability,           /* execute */
+  tree_estimate_probability_driver,    /* execute */
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
@@ -1974,3 +2351,48 @@ struct gimple_opt_pass pass_profile =
   TODO_ggc_collect | TODO_verify_ssa                   /* todo_flags_finish */
  }
 };
+
+struct gimple_opt_pass pass_strip_predict_hints =
+{
+ {
+  GIMPLE_PASS,
+  "*strip_predict_hints",              /* name */
+  NULL,                                        /* gate */
+  strip_predict_hints,                 /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_BRANCH_PROB,                      /* tv_id */
+  PROP_cfg,                            /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  TODO_ggc_collect | TODO_verify_ssa                   /* todo_flags_finish */
+ }
+};
+
+/* Rebuild function frequencies.  Passes are in general expected to
+   maintain profile by hand, however in some cases this is not possible:
+   for example when inlining several functions with loops freuqencies might run
+   out of scale and thus needs to be recomputed.  */
+
+void
+rebuild_frequencies (void)
+{
+  timevar_push (TV_REBUILD_FREQUENCIES);
+  if (profile_status == PROFILE_GUESSED)
+    {
+      loop_optimizer_init (0);
+      add_noreturn_fake_exit_edges ();
+      mark_irreducible_loops ();
+      connect_infinite_loops_to_exit ();
+      estimate_bb_frequencies ();
+      remove_fake_exit_edges ();
+      loop_optimizer_finalize ();
+    }
+  else if (profile_status == PROFILE_READ)
+    counts_to_freqs ();
+  else
+    gcc_unreachable ();
+  timevar_pop (TV_REBUILD_FREQUENCIES);
+}