OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [predict.c] - Diff between revs 154 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Branch prediction routines for the GNU compiler.
/* Branch prediction routines for the GNU compiler.
   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
/* References:
/* References:
 
 
   [1] "Branch Prediction for Free"
   [1] "Branch Prediction for Free"
       Ball and Larus; PLDI '93.
       Ball and Larus; PLDI '93.
   [2] "Static Branch Frequency and Program Profile Analysis"
   [2] "Static Branch Frequency and Program Profile Analysis"
       Wu and Larus; MICRO-27.
       Wu and Larus; MICRO-27.
   [3] "Corpus-based Static Branch Prediction"
   [3] "Corpus-based Static Branch Prediction"
       Calder, Grunwald, Lindsay, Martin, Mozer, and Zorn; PLDI '95.  */
       Calder, Grunwald, Lindsay, Martin, Mozer, and Zorn; PLDI '95.  */
 
 
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "rtl.h"
#include "rtl.h"
#include "tm_p.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "basic-block.h"
#include "insn-config.h"
#include "insn-config.h"
#include "regs.h"
#include "regs.h"
#include "flags.h"
#include "flags.h"
#include "output.h"
#include "output.h"
#include "function.h"
#include "function.h"
#include "except.h"
#include "except.h"
#include "toplev.h"
#include "toplev.h"
#include "recog.h"
#include "recog.h"
#include "expr.h"
#include "expr.h"
#include "predict.h"
#include "predict.h"
#include "coverage.h"
#include "coverage.h"
#include "sreal.h"
#include "sreal.h"
#include "params.h"
#include "params.h"
#include "target.h"
#include "target.h"
#include "cfgloop.h"
#include "cfgloop.h"
#include "tree-flow.h"
#include "tree-flow.h"
#include "ggc.h"
#include "ggc.h"
#include "tree-dump.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "tree-pass.h"
#include "timevar.h"
#include "timevar.h"
#include "tree-scalar-evolution.h"
#include "tree-scalar-evolution.h"
#include "cfgloop.h"
#include "cfgloop.h"
 
 
/* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
/* real constants: 0, 1, 1-1/REG_BR_PROB_BASE, REG_BR_PROB_BASE,
                   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
                   1/REG_BR_PROB_BASE, 0.5, BB_FREQ_MAX.  */
static sreal real_zero, real_one, real_almost_one, real_br_prob_base,
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;
             real_inv_br_prob_base, real_one_half, real_bb_freq_max;
 
 
/* Random guesstimation given names.  */
/* Random guesstimation given names.  */
#define PROB_VERY_UNLIKELY      (REG_BR_PROB_BASE / 100 - 1)
#define PROB_VERY_UNLIKELY      (REG_BR_PROB_BASE / 100 - 1)
#define PROB_EVEN               (REG_BR_PROB_BASE / 2)
#define PROB_EVEN               (REG_BR_PROB_BASE / 2)
#define PROB_VERY_LIKELY        (REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
#define PROB_VERY_LIKELY        (REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
#define PROB_ALWAYS             (REG_BR_PROB_BASE)
#define PROB_ALWAYS             (REG_BR_PROB_BASE)
 
 
static void combine_predictions_for_insn (rtx, basic_block);
static void combine_predictions_for_insn (rtx, basic_block);
static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int);
static void dump_prediction (FILE *, enum br_predictor, int, basic_block, int);
static void estimate_loops_at_level (struct loop *, bitmap);
static void estimate_loops_at_level (struct loop *, bitmap);
static void propagate_freq (struct loop *, bitmap);
static void propagate_freq (struct loop *, bitmap);
static void estimate_bb_frequencies (struct loops *);
static void estimate_bb_frequencies (struct loops *);
static void predict_paths_leading_to (basic_block, int *, enum br_predictor, enum prediction);
static void predict_paths_leading_to (basic_block, int *, enum br_predictor, enum prediction);
static bool last_basic_block_p (basic_block);
static bool last_basic_block_p (basic_block);
static void compute_function_frequency (void);
static void compute_function_frequency (void);
static void choose_function_section (void);
static void choose_function_section (void);
static bool can_predict_insn_p (rtx);
static bool can_predict_insn_p (rtx);
 
 
/* Information we hold about each branch predictor.
/* Information we hold about each branch predictor.
   Filled using information from predict.def.  */
   Filled using information from predict.def.  */
 
 
struct predictor_info
struct predictor_info
{
{
  const char *const name;       /* Name used in the debugging dumps.  */
  const char *const name;       /* Name used in the debugging dumps.  */
  const int hitrate;            /* Expected hitrate used by
  const int hitrate;            /* Expected hitrate used by
                                   predict_insn_def call.  */
                                   predict_insn_def call.  */
  const int flags;
  const int flags;
};
};
 
 
/* Use given predictor without Dempster-Shaffer theory if it matches
/* Use given predictor without Dempster-Shaffer theory if it matches
   using first_match heuristics.  */
   using first_match heuristics.  */
#define PRED_FLAG_FIRST_MATCH 1
#define PRED_FLAG_FIRST_MATCH 1
 
 
/* Recompute hitrate in percent to our representation.  */
/* Recompute hitrate in percent to our representation.  */
 
 
#define HITRATE(VAL) ((int) ((VAL) * REG_BR_PROB_BASE + 50) / 100)
#define HITRATE(VAL) ((int) ((VAL) * REG_BR_PROB_BASE + 50) / 100)
 
 
#define DEF_PREDICTOR(ENUM, NAME, HITRATE, FLAGS) {NAME, HITRATE, FLAGS},
#define DEF_PREDICTOR(ENUM, NAME, HITRATE, FLAGS) {NAME, HITRATE, FLAGS},
static const struct predictor_info predictor_info[]= {
static const struct predictor_info predictor_info[]= {
#include "predict.def"
#include "predict.def"
 
 
  /* Upper bound on predictors.  */
  /* Upper bound on predictors.  */
  {NULL, 0, 0}
  {NULL, 0, 0}
};
};
#undef DEF_PREDICTOR
#undef DEF_PREDICTOR
 
 
/* Return true in case BB can be CPU intensive and should be optimized
/* Return true in case BB can be CPU intensive and should be optimized
   for maximal performance.  */
   for maximal performance.  */
 
 
bool
bool
maybe_hot_bb_p (basic_block bb)
maybe_hot_bb_p (basic_block bb)
{
{
  if (profile_info && flag_branch_probabilities
  if (profile_info && flag_branch_probabilities
      && (bb->count
      && (bb->count
          < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
          < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
    return false;
    return false;
  if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
  if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
    return false;
    return false;
  return true;
  return true;
}
}
 
 
/* Return true in case BB is cold and should be optimized for size.  */
/* Return true in case BB is cold and should be optimized for size.  */
 
 
bool
bool
probably_cold_bb_p (basic_block bb)
probably_cold_bb_p (basic_block bb)
{
{
  if (profile_info && flag_branch_probabilities
  if (profile_info && flag_branch_probabilities
      && (bb->count
      && (bb->count
          < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
          < profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
    return true;
    return true;
  if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
  if (bb->frequency < BB_FREQ_MAX / PARAM_VALUE (HOT_BB_FREQUENCY_FRACTION))
    return true;
    return true;
  return false;
  return false;
}
}
 
 
/* Return true in case BB is probably never executed.  */
/* Return true in case BB is probably never executed.  */
bool
bool
probably_never_executed_bb_p (basic_block bb)
probably_never_executed_bb_p (basic_block bb)
{
{
  if (profile_info && flag_branch_probabilities)
  if (profile_info && flag_branch_probabilities)
    return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
    return ((bb->count + profile_info->runs / 2) / profile_info->runs) == 0;
  return false;
  return false;
}
}
 
 
/* Return true if the one of outgoing edges is already predicted by
/* Return true if the one of outgoing edges is already predicted by
   PREDICTOR.  */
   PREDICTOR.  */
 
 
bool
bool
rtl_predicted_by_p (basic_block bb, enum br_predictor predictor)
rtl_predicted_by_p (basic_block bb, enum br_predictor predictor)
{
{
  rtx note;
  rtx note;
  if (!INSN_P (BB_END (bb)))
  if (!INSN_P (BB_END (bb)))
    return false;
    return false;
  for (note = REG_NOTES (BB_END (bb)); note; note = XEXP (note, 1))
  for (note = REG_NOTES (BB_END (bb)); note; note = XEXP (note, 1))
    if (REG_NOTE_KIND (note) == REG_BR_PRED
    if (REG_NOTE_KIND (note) == REG_BR_PRED
        && INTVAL (XEXP (XEXP (note, 0), 0)) == (int)predictor)
        && INTVAL (XEXP (XEXP (note, 0), 0)) == (int)predictor)
      return true;
      return true;
  return false;
  return false;
}
}
 
 
/* Return true if the one of outgoing edges is already predicted by
/* Return true if the one of outgoing edges is already predicted by
   PREDICTOR.  */
   PREDICTOR.  */
 
 
bool
bool
tree_predicted_by_p (basic_block bb, enum br_predictor predictor)
tree_predicted_by_p (basic_block bb, enum br_predictor predictor)
{
{
  struct edge_prediction *i;
  struct edge_prediction *i;
  for (i = bb->predictions; i; i = i->ep_next)
  for (i = bb->predictions; i; i = i->ep_next)
    if (i->ep_predictor == predictor)
    if (i->ep_predictor == predictor)
      return true;
      return true;
  return false;
  return false;
}
}
 
 
/* Return true when the probability of edge is reliable.
/* Return true when the probability of edge is reliable.
 
 
   The profile guessing code is good at predicting branch outcome (ie.
   The profile guessing code is good at predicting branch outcome (ie.
   taken/not taken), that is predicted right slightly over 75% of time.
   taken/not taken), that is predicted right slightly over 75% of time.
   It is however notoriously poor on predicting the probability itself.
   It is however notoriously poor on predicting the probability itself.
   In general the profile appear a lot flatter (with probabilities closer
   In general the profile appear a lot flatter (with probabilities closer
   to 50%) than the reality so it is bad idea to use it to drive optimization
   to 50%) than the reality so it is bad idea to use it to drive optimization
   such as those disabling dynamic branch prediction for well predictable
   such as those disabling dynamic branch prediction for well predictable
   branches.
   branches.
 
 
   There are two exceptions - edges leading to noreturn edges and edges
   There are two exceptions - edges leading to noreturn edges and edges
   predicted by number of iterations heuristics are predicted well.  This macro
   predicted by number of iterations heuristics are predicted well.  This macro
   should be able to distinguish those, but at the moment it simply check for
   should be able to distinguish those, but at the moment it simply check for
   noreturn heuristic that is only one giving probability over 99% or bellow
   noreturn heuristic that is only one giving probability over 99% or bellow
   1%.  In future we might want to propagate reliability information across the
   1%.  In future we might want to propagate reliability information across the
   CFG if we find this information useful on multiple places.   */
   CFG if we find this information useful on multiple places.   */
static bool
static bool
probability_reliable_p (int prob)
probability_reliable_p (int prob)
{
{
  return (profile_status == PROFILE_READ
  return (profile_status == PROFILE_READ
          || (profile_status == PROFILE_GUESSED
          || (profile_status == PROFILE_GUESSED
              && (prob <= HITRATE (1) || prob >= HITRATE (99))));
              && (prob <= HITRATE (1) || prob >= HITRATE (99))));
}
}
 
 
/* Same predicate as above, working on edges.  */
/* Same predicate as above, working on edges.  */
bool
bool
edge_probability_reliable_p (edge e)
edge_probability_reliable_p (edge e)
{
{
  return probability_reliable_p (e->probability);
  return probability_reliable_p (e->probability);
}
}
 
 
/* Same predicate as edge_probability_reliable_p, working on notes.  */
/* Same predicate as edge_probability_reliable_p, working on notes.  */
bool
bool
br_prob_note_reliable_p (rtx note)
br_prob_note_reliable_p (rtx note)
{
{
  gcc_assert (REG_NOTE_KIND (note) == REG_BR_PROB);
  gcc_assert (REG_NOTE_KIND (note) == REG_BR_PROB);
  return probability_reliable_p (INTVAL (XEXP (note, 0)));
  return probability_reliable_p (INTVAL (XEXP (note, 0)));
}
}
 
 
static void
static void
predict_insn (rtx insn, enum br_predictor predictor, int probability)
predict_insn (rtx insn, enum br_predictor predictor, int probability)
{
{
  gcc_assert (any_condjump_p (insn));
  gcc_assert (any_condjump_p (insn));
  if (!flag_guess_branch_prob)
  if (!flag_guess_branch_prob)
    return;
    return;
 
 
  REG_NOTES (insn)
  REG_NOTES (insn)
    = gen_rtx_EXPR_LIST (REG_BR_PRED,
    = gen_rtx_EXPR_LIST (REG_BR_PRED,
                         gen_rtx_CONCAT (VOIDmode,
                         gen_rtx_CONCAT (VOIDmode,
                                         GEN_INT ((int) predictor),
                                         GEN_INT ((int) predictor),
                                         GEN_INT ((int) probability)),
                                         GEN_INT ((int) probability)),
                         REG_NOTES (insn));
                         REG_NOTES (insn));
}
}
 
 
/* Predict insn by given predictor.  */
/* Predict insn by given predictor.  */
 
 
void
void
predict_insn_def (rtx insn, enum br_predictor predictor,
predict_insn_def (rtx insn, enum br_predictor predictor,
                  enum prediction taken)
                  enum prediction taken)
{
{
   int probability = predictor_info[(int) predictor].hitrate;
   int probability = predictor_info[(int) predictor].hitrate;
 
 
   if (taken != TAKEN)
   if (taken != TAKEN)
     probability = REG_BR_PROB_BASE - probability;
     probability = REG_BR_PROB_BASE - probability;
 
 
   predict_insn (insn, predictor, probability);
   predict_insn (insn, predictor, probability);
}
}
 
 
/* Predict edge E with given probability if possible.  */
/* Predict edge E with given probability if possible.  */
 
 
void
void
rtl_predict_edge (edge e, enum br_predictor predictor, int probability)
rtl_predict_edge (edge e, enum br_predictor predictor, int probability)
{
{
  rtx last_insn;
  rtx last_insn;
  last_insn = BB_END (e->src);
  last_insn = BB_END (e->src);
 
 
  /* We can store the branch prediction information only about
  /* We can store the branch prediction information only about
     conditional jumps.  */
     conditional jumps.  */
  if (!any_condjump_p (last_insn))
  if (!any_condjump_p (last_insn))
    return;
    return;
 
 
  /* We always store probability of branching.  */
  /* We always store probability of branching.  */
  if (e->flags & EDGE_FALLTHRU)
  if (e->flags & EDGE_FALLTHRU)
    probability = REG_BR_PROB_BASE - probability;
    probability = REG_BR_PROB_BASE - probability;
 
 
  predict_insn (last_insn, predictor, probability);
  predict_insn (last_insn, predictor, probability);
}
}
 
 
/* Predict edge E with the given PROBABILITY.  */
/* Predict edge E with the given PROBABILITY.  */
void
void
tree_predict_edge (edge e, enum br_predictor predictor, int probability)
tree_predict_edge (edge e, enum br_predictor predictor, int probability)
{
{
  gcc_assert (profile_status != PROFILE_GUESSED);
  gcc_assert (profile_status != PROFILE_GUESSED);
  if ((e->src != ENTRY_BLOCK_PTR && EDGE_COUNT (e->src->succs) > 1)
  if ((e->src != ENTRY_BLOCK_PTR && EDGE_COUNT (e->src->succs) > 1)
      && flag_guess_branch_prob && optimize)
      && flag_guess_branch_prob && optimize)
    {
    {
      struct edge_prediction *i = ggc_alloc (sizeof (struct edge_prediction));
      struct edge_prediction *i = ggc_alloc (sizeof (struct edge_prediction));
 
 
      i->ep_next = e->src->predictions;
      i->ep_next = e->src->predictions;
      e->src->predictions = i;
      e->src->predictions = i;
      i->ep_probability = probability;
      i->ep_probability = probability;
      i->ep_predictor = predictor;
      i->ep_predictor = predictor;
      i->ep_edge = e;
      i->ep_edge = e;
    }
    }
}
}
 
 
/* Remove all predictions on given basic block that are attached
/* Remove all predictions on given basic block that are attached
   to edge E.  */
   to edge E.  */
void
void
remove_predictions_associated_with_edge (edge e)
remove_predictions_associated_with_edge (edge e)
{
{
  if (e->src->predictions)
  if (e->src->predictions)
    {
    {
      struct edge_prediction **prediction = &e->src->predictions;
      struct edge_prediction **prediction = &e->src->predictions;
      while (*prediction)
      while (*prediction)
        {
        {
          if ((*prediction)->ep_edge == e)
          if ((*prediction)->ep_edge == e)
            *prediction = (*prediction)->ep_next;
            *prediction = (*prediction)->ep_next;
          else
          else
            prediction = &((*prediction)->ep_next);
            prediction = &((*prediction)->ep_next);
        }
        }
    }
    }
}
}
 
 
/* Return true when we can store prediction on insn INSN.
/* Return true when we can store prediction on insn INSN.
   At the moment we represent predictions only on conditional
   At the moment we represent predictions only on conditional
   jumps, not at computed jump or other complicated cases.  */
   jumps, not at computed jump or other complicated cases.  */
static bool
static bool
can_predict_insn_p (rtx insn)
can_predict_insn_p (rtx insn)
{
{
  return (JUMP_P (insn)
  return (JUMP_P (insn)
          && any_condjump_p (insn)
          && any_condjump_p (insn)
          && EDGE_COUNT (BLOCK_FOR_INSN (insn)->succs) >= 2);
          && EDGE_COUNT (BLOCK_FOR_INSN (insn)->succs) >= 2);
}
}
 
 
/* Predict edge E by given predictor if possible.  */
/* Predict edge E by given predictor if possible.  */
 
 
void
void
predict_edge_def (edge e, enum br_predictor predictor,
predict_edge_def (edge e, enum br_predictor predictor,
                  enum prediction taken)
                  enum prediction taken)
{
{
   int probability = predictor_info[(int) predictor].hitrate;
   int probability = predictor_info[(int) predictor].hitrate;
 
 
   if (taken != TAKEN)
   if (taken != TAKEN)
     probability = REG_BR_PROB_BASE - probability;
     probability = REG_BR_PROB_BASE - probability;
 
 
   predict_edge (e, predictor, probability);
   predict_edge (e, predictor, probability);
}
}
 
 
/* Invert all branch predictions or probability notes in the INSN.  This needs
/* Invert all branch predictions or probability notes in the INSN.  This needs
   to be done each time we invert the condition used by the jump.  */
   to be done each time we invert the condition used by the jump.  */
 
 
void
void
invert_br_probabilities (rtx insn)
invert_br_probabilities (rtx insn)
{
{
  rtx note;
  rtx note;
 
 
  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
    if (REG_NOTE_KIND (note) == REG_BR_PROB)
    if (REG_NOTE_KIND (note) == REG_BR_PROB)
      XEXP (note, 0) = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (note, 0)));
      XEXP (note, 0) = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (note, 0)));
    else if (REG_NOTE_KIND (note) == REG_BR_PRED)
    else if (REG_NOTE_KIND (note) == REG_BR_PRED)
      XEXP (XEXP (note, 0), 1)
      XEXP (XEXP (note, 0), 1)
        = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (XEXP (note, 0), 1)));
        = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (XEXP (note, 0), 1)));
}
}
 
 
/* Dump information about the branch prediction to the output file.  */
/* Dump information about the branch prediction to the output file.  */
 
 
static void
static void
dump_prediction (FILE *file, enum br_predictor predictor, int probability,
dump_prediction (FILE *file, enum br_predictor predictor, int probability,
                 basic_block bb, int used)
                 basic_block bb, int used)
{
{
  edge e;
  edge e;
  edge_iterator ei;
  edge_iterator ei;
 
 
  if (!file)
  if (!file)
    return;
    return;
 
 
  FOR_EACH_EDGE (e, ei, bb->succs)
  FOR_EACH_EDGE (e, ei, bb->succs)
    if (! (e->flags & EDGE_FALLTHRU))
    if (! (e->flags & EDGE_FALLTHRU))
      break;
      break;
 
 
  fprintf (file, "  %s heuristics%s: %.1f%%",
  fprintf (file, "  %s heuristics%s: %.1f%%",
           predictor_info[predictor].name,
           predictor_info[predictor].name,
           used ? "" : " (ignored)", probability * 100.0 / REG_BR_PROB_BASE);
           used ? "" : " (ignored)", probability * 100.0 / REG_BR_PROB_BASE);
 
 
  if (bb->count)
  if (bb->count)
    {
    {
      fprintf (file, "  exec ");
      fprintf (file, "  exec ");
      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, bb->count);
      fprintf (file, HOST_WIDEST_INT_PRINT_DEC, bb->count);
      if (e)
      if (e)
        {
        {
          fprintf (file, " hit ");
          fprintf (file, " hit ");
          fprintf (file, HOST_WIDEST_INT_PRINT_DEC, e->count);
          fprintf (file, HOST_WIDEST_INT_PRINT_DEC, e->count);
          fprintf (file, " (%.1f%%)", e->count * 100.0 / bb->count);
          fprintf (file, " (%.1f%%)", e->count * 100.0 / bb->count);
        }
        }
    }
    }
 
 
  fprintf (file, "\n");
  fprintf (file, "\n");
}
}
 
 
/* We can not predict the probabilities of outgoing edges of bb.  Set them
/* We can not predict the probabilities of outgoing edges of bb.  Set them
   evenly and hope for the best.  */
   evenly and hope for the best.  */
static void
static void
set_even_probabilities (basic_block bb)
set_even_probabilities (basic_block bb)
{
{
  int nedges = 0;
  int nedges = 0;
  edge e;
  edge e;
  edge_iterator ei;
  edge_iterator ei;
 
 
  FOR_EACH_EDGE (e, ei, bb->succs)
  FOR_EACH_EDGE (e, ei, bb->succs)
    if (!(e->flags & (EDGE_EH | EDGE_FAKE)))
    if (!(e->flags & (EDGE_EH | EDGE_FAKE)))
      nedges ++;
      nedges ++;
  FOR_EACH_EDGE (e, ei, bb->succs)
  FOR_EACH_EDGE (e, ei, bb->succs)
    if (!(e->flags & (EDGE_EH | EDGE_FAKE)))
    if (!(e->flags & (EDGE_EH | EDGE_FAKE)))
      e->probability = (REG_BR_PROB_BASE + nedges / 2) / nedges;
      e->probability = (REG_BR_PROB_BASE + nedges / 2) / nedges;
    else
    else
      e->probability = 0;
      e->probability = 0;
}
}
 
 
/* Combine all REG_BR_PRED notes into single probability and attach REG_BR_PROB
/* Combine all REG_BR_PRED notes into single probability and attach REG_BR_PROB
   note if not already present.  Remove now useless REG_BR_PRED notes.  */
   note if not already present.  Remove now useless REG_BR_PRED notes.  */
 
 
static void
static void
combine_predictions_for_insn (rtx insn, basic_block bb)
combine_predictions_for_insn (rtx insn, basic_block bb)
{
{
  rtx prob_note;
  rtx prob_note;
  rtx *pnote;
  rtx *pnote;
  rtx note;
  rtx note;
  int best_probability = PROB_EVEN;
  int best_probability = PROB_EVEN;
  int best_predictor = END_PREDICTORS;
  int best_predictor = END_PREDICTORS;
  int combined_probability = REG_BR_PROB_BASE / 2;
  int combined_probability = REG_BR_PROB_BASE / 2;
  int d;
  int d;
  bool first_match = false;
  bool first_match = false;
  bool found = false;
  bool found = false;
 
 
  if (!can_predict_insn_p (insn))
  if (!can_predict_insn_p (insn))
    {
    {
      set_even_probabilities (bb);
      set_even_probabilities (bb);
      return;
      return;
    }
    }
 
 
  prob_note = find_reg_note (insn, REG_BR_PROB, 0);
  prob_note = find_reg_note (insn, REG_BR_PROB, 0);
  pnote = &REG_NOTES (insn);
  pnote = &REG_NOTES (insn);
  if (dump_file)
  if (dump_file)
    fprintf (dump_file, "Predictions for insn %i bb %i\n", INSN_UID (insn),
    fprintf (dump_file, "Predictions for insn %i bb %i\n", INSN_UID (insn),
             bb->index);
             bb->index);
 
 
  /* We implement "first match" heuristics and use probability guessed
  /* We implement "first match" heuristics and use probability guessed
     by predictor with smallest index.  */
     by predictor with smallest index.  */
  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
  for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
    if (REG_NOTE_KIND (note) == REG_BR_PRED)
    if (REG_NOTE_KIND (note) == REG_BR_PRED)
      {
      {
        int predictor = INTVAL (XEXP (XEXP (note, 0), 0));
        int predictor = INTVAL (XEXP (XEXP (note, 0), 0));
        int probability = INTVAL (XEXP (XEXP (note, 0), 1));
        int probability = INTVAL (XEXP (XEXP (note, 0), 1));
 
 
        found = true;
        found = true;
        if (best_predictor > predictor)
        if (best_predictor > predictor)
          best_probability = probability, best_predictor = predictor;
          best_probability = probability, best_predictor = predictor;
 
 
        d = (combined_probability * probability
        d = (combined_probability * probability
             + (REG_BR_PROB_BASE - combined_probability)
             + (REG_BR_PROB_BASE - combined_probability)
             * (REG_BR_PROB_BASE - probability));
             * (REG_BR_PROB_BASE - probability));
 
 
        /* Use FP math to avoid overflows of 32bit integers.  */
        /* Use FP math to avoid overflows of 32bit integers.  */
        if (d == 0)
        if (d == 0)
          /* If one probability is 0% and one 100%, avoid division by zero.  */
          /* If one probability is 0% and one 100%, avoid division by zero.  */
          combined_probability = REG_BR_PROB_BASE / 2;
          combined_probability = REG_BR_PROB_BASE / 2;
        else
        else
          combined_probability = (((double) combined_probability) * probability
          combined_probability = (((double) combined_probability) * probability
                                  * REG_BR_PROB_BASE / d + 0.5);
                                  * REG_BR_PROB_BASE / d + 0.5);
      }
      }
 
 
  /* Decide which heuristic to use.  In case we didn't match anything,
  /* Decide which heuristic to use.  In case we didn't match anything,
     use no_prediction heuristic, in case we did match, use either
     use no_prediction heuristic, in case we did match, use either
     first match or Dempster-Shaffer theory depending on the flags.  */
     first match or Dempster-Shaffer theory depending on the flags.  */
 
 
  if (predictor_info [best_predictor].flags & PRED_FLAG_FIRST_MATCH)
  if (predictor_info [best_predictor].flags & PRED_FLAG_FIRST_MATCH)
    first_match = true;
    first_match = true;
 
 
  if (!found)
  if (!found)
    dump_prediction (dump_file, PRED_NO_PREDICTION,
    dump_prediction (dump_file, PRED_NO_PREDICTION,
                     combined_probability, bb, true);
                     combined_probability, bb, true);
  else
  else
    {
    {
      dump_prediction (dump_file, PRED_DS_THEORY, combined_probability,
      dump_prediction (dump_file, PRED_DS_THEORY, combined_probability,
                       bb, !first_match);
                       bb, !first_match);
      dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability,
      dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability,
                       bb, first_match);
                       bb, first_match);
    }
    }
 
 
  if (first_match)
  if (first_match)
    combined_probability = best_probability;
    combined_probability = best_probability;
  dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true);
  dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true);
 
 
  while (*pnote)
  while (*pnote)
    {
    {
      if (REG_NOTE_KIND (*pnote) == REG_BR_PRED)
      if (REG_NOTE_KIND (*pnote) == REG_BR_PRED)
        {
        {
          int predictor = INTVAL (XEXP (XEXP (*pnote, 0), 0));
          int predictor = INTVAL (XEXP (XEXP (*pnote, 0), 0));
          int probability = INTVAL (XEXP (XEXP (*pnote, 0), 1));
          int probability = INTVAL (XEXP (XEXP (*pnote, 0), 1));
 
 
          dump_prediction (dump_file, predictor, probability, bb,
          dump_prediction (dump_file, predictor, probability, bb,
                           !first_match || best_predictor == predictor);
                           !first_match || best_predictor == predictor);
          *pnote = XEXP (*pnote, 1);
          *pnote = XEXP (*pnote, 1);
        }
        }
      else
      else
        pnote = &XEXP (*pnote, 1);
        pnote = &XEXP (*pnote, 1);
    }
    }
 
 
  if (!prob_note)
  if (!prob_note)
    {
    {
      REG_NOTES (insn)
      REG_NOTES (insn)
        = gen_rtx_EXPR_LIST (REG_BR_PROB,
        = gen_rtx_EXPR_LIST (REG_BR_PROB,
                             GEN_INT (combined_probability), REG_NOTES (insn));
                             GEN_INT (combined_probability), REG_NOTES (insn));
 
 
      /* Save the prediction into CFG in case we are seeing non-degenerated
      /* Save the prediction into CFG in case we are seeing non-degenerated
         conditional jump.  */
         conditional jump.  */
      if (!single_succ_p (bb))
      if (!single_succ_p (bb))
        {
        {
          BRANCH_EDGE (bb)->probability = combined_probability;
          BRANCH_EDGE (bb)->probability = combined_probability;
          FALLTHRU_EDGE (bb)->probability
          FALLTHRU_EDGE (bb)->probability
            = REG_BR_PROB_BASE - combined_probability;
            = REG_BR_PROB_BASE - combined_probability;
        }
        }
    }
    }
  else if (!single_succ_p (bb))
  else if (!single_succ_p (bb))
    {
    {
      int prob = INTVAL (XEXP (prob_note, 0));
      int prob = INTVAL (XEXP (prob_note, 0));
 
 
      BRANCH_EDGE (bb)->probability = prob;
      BRANCH_EDGE (bb)->probability = prob;
      FALLTHRU_EDGE (bb)->probability = REG_BR_PROB_BASE - prob;
      FALLTHRU_EDGE (bb)->probability = REG_BR_PROB_BASE - prob;
    }
    }
  else
  else
    single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
    single_succ_edge (bb)->probability = REG_BR_PROB_BASE;
}
}
 
 
/* Combine predictions into single probability and store them into CFG.
/* Combine predictions into single probability and store them into CFG.
   Remove now useless prediction entries.  */
   Remove now useless prediction entries.  */
 
 
static void
static void
combine_predictions_for_bb (basic_block bb)
combine_predictions_for_bb (basic_block bb)
{
{
  int best_probability = PROB_EVEN;
  int best_probability = PROB_EVEN;
  int best_predictor = END_PREDICTORS;
  int best_predictor = END_PREDICTORS;
  int combined_probability = REG_BR_PROB_BASE / 2;
  int combined_probability = REG_BR_PROB_BASE / 2;
  int d;
  int d;
  bool first_match = false;
  bool first_match = false;
  bool found = false;
  bool found = false;
  struct edge_prediction *pred;
  struct edge_prediction *pred;
  int nedges = 0;
  int nedges = 0;
  edge e, first = NULL, second = NULL;
  edge e, first = NULL, second = NULL;
  edge_iterator ei;
  edge_iterator ei;
 
 
  FOR_EACH_EDGE (e, ei, bb->succs)
  FOR_EACH_EDGE (e, ei, bb->succs)
    if (!(e->flags & (EDGE_EH | EDGE_FAKE)))
    if (!(e->flags & (EDGE_EH | EDGE_FAKE)))
      {
      {
        nedges ++;
        nedges ++;
        if (first && !second)
        if (first && !second)
          second = e;
          second = e;
        if (!first)
        if (!first)
          first = e;
          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
     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
     edges.  It is possible to predict generic case too, but we have to
     ignore first match heuristics and do more involved combining.  Implement
     ignore first match heuristics and do more involved combining.  Implement
     this later.  */
     this later.  */
  if (nedges != 2)
  if (nedges != 2)
    {
    {
      if (!bb->count)
      if (!bb->count)
        set_even_probabilities (bb);
        set_even_probabilities (bb);
      bb->predictions = NULL;
      bb->predictions = NULL;
      if (dump_file)
      if (dump_file)
        fprintf (dump_file, "%i edges in bb %i predicted to even probabilities\n",
        fprintf (dump_file, "%i edges in bb %i predicted to even probabilities\n",
                 nedges, bb->index);
                 nedges, bb->index);
      return;
      return;
    }
    }
 
 
  if (dump_file)
  if (dump_file)
    fprintf (dump_file, "Predictions for bb %i\n", bb->index);
    fprintf (dump_file, "Predictions for bb %i\n", bb->index);
 
 
  /* We implement "first match" heuristics and use probability guessed
  /* We implement "first match" heuristics and use probability guessed
     by predictor with smallest index.  */
     by predictor with smallest index.  */
  for (pred = bb->predictions; pred; pred = pred->ep_next)
  for (pred = bb->predictions; pred; pred = pred->ep_next)
    {
    {
      int predictor = pred->ep_predictor;
      int predictor = pred->ep_predictor;
      int probability = pred->ep_probability;
      int probability = pred->ep_probability;
 
 
      if (pred->ep_edge != first)
      if (pred->ep_edge != first)
        probability = REG_BR_PROB_BASE - probability;
        probability = REG_BR_PROB_BASE - probability;
 
 
      found = true;
      found = true;
      if (best_predictor > predictor)
      if (best_predictor > predictor)
        best_probability = probability, best_predictor = predictor;
        best_probability = probability, best_predictor = predictor;
 
 
      d = (combined_probability * probability
      d = (combined_probability * probability
           + (REG_BR_PROB_BASE - combined_probability)
           + (REG_BR_PROB_BASE - combined_probability)
           * (REG_BR_PROB_BASE - probability));
           * (REG_BR_PROB_BASE - probability));
 
 
      /* Use FP math to avoid overflows of 32bit integers.  */
      /* Use FP math to avoid overflows of 32bit integers.  */
      if (d == 0)
      if (d == 0)
        /* If one probability is 0% and one 100%, avoid division by zero.  */
        /* If one probability is 0% and one 100%, avoid division by zero.  */
        combined_probability = REG_BR_PROB_BASE / 2;
        combined_probability = REG_BR_PROB_BASE / 2;
      else
      else
        combined_probability = (((double) combined_probability) * probability
        combined_probability = (((double) combined_probability) * probability
                                * REG_BR_PROB_BASE / d + 0.5);
                                * REG_BR_PROB_BASE / d + 0.5);
    }
    }
 
 
  /* Decide which heuristic to use.  In case we didn't match anything,
  /* Decide which heuristic to use.  In case we didn't match anything,
     use no_prediction heuristic, in case we did match, use either
     use no_prediction heuristic, in case we did match, use either
     first match or Dempster-Shaffer theory depending on the flags.  */
     first match or Dempster-Shaffer theory depending on the flags.  */
 
 
  if (predictor_info [best_predictor].flags & PRED_FLAG_FIRST_MATCH)
  if (predictor_info [best_predictor].flags & PRED_FLAG_FIRST_MATCH)
    first_match = true;
    first_match = true;
 
 
  if (!found)
  if (!found)
    dump_prediction (dump_file, PRED_NO_PREDICTION, combined_probability, bb, true);
    dump_prediction (dump_file, PRED_NO_PREDICTION, combined_probability, bb, true);
  else
  else
    {
    {
      dump_prediction (dump_file, PRED_DS_THEORY, combined_probability, bb,
      dump_prediction (dump_file, PRED_DS_THEORY, combined_probability, bb,
                       !first_match);
                       !first_match);
      dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability, bb,
      dump_prediction (dump_file, PRED_FIRST_MATCH, best_probability, bb,
                       first_match);
                       first_match);
    }
    }
 
 
  if (first_match)
  if (first_match)
    combined_probability = best_probability;
    combined_probability = best_probability;
  dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true);
  dump_prediction (dump_file, PRED_COMBINED, combined_probability, bb, true);
 
 
  for (pred = bb->predictions; pred; pred = pred->ep_next)
  for (pred = bb->predictions; pred; pred = pred->ep_next)
    {
    {
      int predictor = pred->ep_predictor;
      int predictor = pred->ep_predictor;
      int probability = pred->ep_probability;
      int probability = pred->ep_probability;
 
 
      if (pred->ep_edge != EDGE_SUCC (bb, 0))
      if (pred->ep_edge != EDGE_SUCC (bb, 0))
        probability = REG_BR_PROB_BASE - probability;
        probability = REG_BR_PROB_BASE - probability;
      dump_prediction (dump_file, predictor, probability, bb,
      dump_prediction (dump_file, predictor, probability, bb,
                       !first_match || best_predictor == predictor);
                       !first_match || best_predictor == predictor);
    }
    }
  bb->predictions = NULL;
  bb->predictions = NULL;
 
 
  if (!bb->count)
  if (!bb->count)
    {
    {
      first->probability = combined_probability;
      first->probability = combined_probability;
      second->probability = REG_BR_PROB_BASE - combined_probability;
      second->probability = REG_BR_PROB_BASE - combined_probability;
    }
    }
}
}
 
 
/* Predict edge probabilities by exploiting loop structure.
/* Predict edge probabilities by exploiting loop structure.
   When RTLSIMPLELOOPS is set, attempt to count number of iterations by analyzing
   When RTLSIMPLELOOPS is set, attempt to count number of iterations by analyzing
   RTL otherwise use tree based approach.  */
   RTL otherwise use tree based approach.  */
static void
static void
predict_loops (struct loops *loops_info, bool rtlsimpleloops)
predict_loops (struct loops *loops_info, bool rtlsimpleloops)
{
{
  unsigned i;
  unsigned i;
 
 
  if (!rtlsimpleloops)
  if (!rtlsimpleloops)
    scev_initialize (loops_info);
    scev_initialize (loops_info);
 
 
  /* Try to predict out blocks in a loop that are not part of a
  /* Try to predict out blocks in a loop that are not part of a
     natural loop.  */
     natural loop.  */
  for (i = 1; i < loops_info->num; i++)
  for (i = 1; i < loops_info->num; i++)
    {
    {
      basic_block bb, *bbs;
      basic_block bb, *bbs;
      unsigned j;
      unsigned j;
      unsigned n_exits;
      unsigned n_exits;
      struct loop *loop = loops_info->parray[i];
      struct loop *loop = loops_info->parray[i];
      struct niter_desc desc;
      struct niter_desc desc;
      unsigned HOST_WIDE_INT niter;
      unsigned HOST_WIDE_INT niter;
      edge *exits;
      edge *exits;
 
 
      exits = get_loop_exit_edges (loop, &n_exits);
      exits = get_loop_exit_edges (loop, &n_exits);
 
 
      if (rtlsimpleloops)
      if (rtlsimpleloops)
        {
        {
          iv_analysis_loop_init (loop);
          iv_analysis_loop_init (loop);
          find_simple_exit (loop, &desc);
          find_simple_exit (loop, &desc);
 
 
          if (desc.simple_p && desc.const_iter)
          if (desc.simple_p && desc.const_iter)
            {
            {
              int prob;
              int prob;
              niter = desc.niter + 1;
              niter = desc.niter + 1;
              if (niter == 0)        /* We might overflow here.  */
              if (niter == 0)        /* We might overflow here.  */
                niter = desc.niter;
                niter = desc.niter;
              if (niter
              if (niter
                  > (unsigned int) PARAM_VALUE (PARAM_MAX_PREDICTED_ITERATIONS))
                  > (unsigned int) PARAM_VALUE (PARAM_MAX_PREDICTED_ITERATIONS))
                niter = PARAM_VALUE (PARAM_MAX_PREDICTED_ITERATIONS);
                niter = PARAM_VALUE (PARAM_MAX_PREDICTED_ITERATIONS);
 
 
              prob = (REG_BR_PROB_BASE
              prob = (REG_BR_PROB_BASE
                      - (REG_BR_PROB_BASE + niter /2) / niter);
                      - (REG_BR_PROB_BASE + niter /2) / niter);
              /* Branch prediction algorithm gives 0 frequency for everything
              /* Branch prediction algorithm gives 0 frequency for everything
                 after the end of loop for loop having 0 probability to finish.  */
                 after the end of loop for loop having 0 probability to finish.  */
              if (prob == REG_BR_PROB_BASE)
              if (prob == REG_BR_PROB_BASE)
                prob = REG_BR_PROB_BASE - 1;
                prob = REG_BR_PROB_BASE - 1;
              predict_edge (desc.in_edge, PRED_LOOP_ITERATIONS,
              predict_edge (desc.in_edge, PRED_LOOP_ITERATIONS,
                            prob);
                            prob);
            }
            }
        }
        }
      else
      else
        {
        {
          struct tree_niter_desc niter_desc;
          struct tree_niter_desc niter_desc;
 
 
          for (j = 0; j < n_exits; j++)
          for (j = 0; j < n_exits; j++)
            {
            {
              tree niter = NULL;
              tree niter = NULL;
 
 
              if (number_of_iterations_exit (loop, exits[j], &niter_desc, false))
              if (number_of_iterations_exit (loop, exits[j], &niter_desc, false))
                niter = niter_desc.niter;
                niter = niter_desc.niter;
              if (!niter || TREE_CODE (niter_desc.niter) != INTEGER_CST)
              if (!niter || TREE_CODE (niter_desc.niter) != INTEGER_CST)
                niter = loop_niter_by_eval (loop, exits[j]);
                niter = loop_niter_by_eval (loop, exits[j]);
 
 
              if (TREE_CODE (niter) == INTEGER_CST)
              if (TREE_CODE (niter) == INTEGER_CST)
                {
                {
                  int probability;
                  int probability;
                  int max = PARAM_VALUE (PARAM_MAX_PREDICTED_ITERATIONS);
                  int max = PARAM_VALUE (PARAM_MAX_PREDICTED_ITERATIONS);
                  if (host_integerp (niter, 1)
                  if (host_integerp (niter, 1)
                      && tree_int_cst_lt (niter,
                      && tree_int_cst_lt (niter,
                                          build_int_cstu (NULL_TREE, max - 1)))
                                          build_int_cstu (NULL_TREE, max - 1)))
                    {
                    {
                      HOST_WIDE_INT nitercst = tree_low_cst (niter, 1) + 1;
                      HOST_WIDE_INT nitercst = tree_low_cst (niter, 1) + 1;
                      probability = ((REG_BR_PROB_BASE + nitercst / 2)
                      probability = ((REG_BR_PROB_BASE + nitercst / 2)
                                     / nitercst);
                                     / nitercst);
                    }
                    }
                  else
                  else
                    probability = ((REG_BR_PROB_BASE + max / 2) / max);
                    probability = ((REG_BR_PROB_BASE + max / 2) / max);
 
 
                  predict_edge (exits[j], PRED_LOOP_ITERATIONS, probability);
                  predict_edge (exits[j], PRED_LOOP_ITERATIONS, probability);
                }
                }
            }
            }
 
 
        }
        }
      free (exits);
      free (exits);
 
 
      bbs = get_loop_body (loop);
      bbs = get_loop_body (loop);
 
 
      for (j = 0; j < loop->num_nodes; j++)
      for (j = 0; j < loop->num_nodes; j++)
        {
        {
          int header_found = 0;
          int header_found = 0;
          edge e;
          edge e;
          edge_iterator ei;
          edge_iterator ei;
 
 
          bb = bbs[j];
          bb = bbs[j];
 
 
          /* Bypass loop heuristics on continue statement.  These
          /* Bypass loop heuristics on continue statement.  These
             statements construct loops via "non-loop" constructs
             statements construct loops via "non-loop" constructs
             in the source language and are better to be handled
             in the source language and are better to be handled
             separately.  */
             separately.  */
          if ((rtlsimpleloops && !can_predict_insn_p (BB_END (bb)))
          if ((rtlsimpleloops && !can_predict_insn_p (BB_END (bb)))
              || predicted_by_p (bb, PRED_CONTINUE))
              || predicted_by_p (bb, PRED_CONTINUE))
            continue;
            continue;
 
 
          /* Loop branch heuristics - predict an edge back to a
          /* Loop branch heuristics - predict an edge back to a
             loop's head as taken.  */
             loop's head as taken.  */
          if (bb == loop->latch)
          if (bb == loop->latch)
            {
            {
              e = find_edge (loop->latch, loop->header);
              e = find_edge (loop->latch, loop->header);
              if (e)
              if (e)
                {
                {
                  header_found = 1;
                  header_found = 1;
                  predict_edge_def (e, PRED_LOOP_BRANCH, TAKEN);
                  predict_edge_def (e, PRED_LOOP_BRANCH, TAKEN);
                }
                }
            }
            }
 
 
          /* Loop exit heuristics - predict an edge exiting the loop if the
          /* Loop exit heuristics - predict an edge exiting the loop if the
             conditional has no loop header successors as not taken.  */
             conditional has no loop header successors as not taken.  */
          if (!header_found)
          if (!header_found)
            {
            {
              /* For loop with many exits we don't want to predict all exits
              /* For loop with many exits we don't want to predict all exits
                 with the pretty large probability, because if all exits are
                 with the pretty large probability, because if all exits are
                 considered in row, the loop would be predicted to iterate
                 considered in row, the loop would be predicted to iterate
                 almost never.  The code to divide probability by number of
                 almost never.  The code to divide probability by number of
                 exits is very rough.  It should compute the number of exits
                 exits is very rough.  It should compute the number of exits
                 taken in each patch through function (not the overall number
                 taken in each patch through function (not the overall number
                 of exits that might be a lot higher for loops with wide switch
                 of exits that might be a lot higher for loops with wide switch
                 statements in them) and compute n-th square root.
                 statements in them) and compute n-th square root.
 
 
                 We limit the minimal probability by 2% to avoid
                 We limit the minimal probability by 2% to avoid
                 EDGE_PROBABILITY_RELIABLE from trusting the branch prediction
                 EDGE_PROBABILITY_RELIABLE from trusting the branch prediction
                 as this was causing regression in perl benchmark containing such
                 as this was causing regression in perl benchmark containing such
                 a wide loop.  */
                 a wide loop.  */
 
 
              int probability = ((REG_BR_PROB_BASE
              int probability = ((REG_BR_PROB_BASE
                                  - predictor_info [(int) PRED_LOOP_EXIT].hitrate)
                                  - predictor_info [(int) PRED_LOOP_EXIT].hitrate)
                                 / n_exits);
                                 / n_exits);
              if (probability < HITRATE (2))
              if (probability < HITRATE (2))
                probability = HITRATE (2);
                probability = HITRATE (2);
              FOR_EACH_EDGE (e, ei, bb->succs)
              FOR_EACH_EDGE (e, ei, bb->succs)
                if (e->dest->index < NUM_FIXED_BLOCKS
                if (e->dest->index < NUM_FIXED_BLOCKS
                    || !flow_bb_inside_loop_p (loop, e->dest))
                    || !flow_bb_inside_loop_p (loop, e->dest))
                  predict_edge (e, PRED_LOOP_EXIT, probability);
                  predict_edge (e, PRED_LOOP_EXIT, probability);
            }
            }
        }
        }
 
 
      /* Free basic blocks from get_loop_body.  */
      /* Free basic blocks from get_loop_body.  */
      free (bbs);
      free (bbs);
    }
    }
 
 
  if (!rtlsimpleloops)
  if (!rtlsimpleloops)
    {
    {
      scev_finalize ();
      scev_finalize ();
      current_loops = NULL;
      current_loops = NULL;
    }
    }
}
}
 
 
/* Attempt to predict probabilities of BB outgoing edges using local
/* Attempt to predict probabilities of BB outgoing edges using local
   properties.  */
   properties.  */
static void
static void
bb_estimate_probability_locally (basic_block bb)
bb_estimate_probability_locally (basic_block bb)
{
{
  rtx last_insn = BB_END (bb);
  rtx last_insn = BB_END (bb);
  rtx cond;
  rtx cond;
 
 
  if (! can_predict_insn_p (last_insn))
  if (! can_predict_insn_p (last_insn))
    return;
    return;
  cond = get_condition (last_insn, NULL, false, false);
  cond = get_condition (last_insn, NULL, false, false);
  if (! cond)
  if (! cond)
    return;
    return;
 
 
  /* Try "pointer heuristic."
  /* Try "pointer heuristic."
     A comparison ptr == 0 is predicted as false.
     A comparison ptr == 0 is predicted as false.
     Similarly, a comparison ptr1 == ptr2 is predicted as false.  */
     Similarly, a comparison ptr1 == ptr2 is predicted as false.  */
  if (COMPARISON_P (cond)
  if (COMPARISON_P (cond)
      && ((REG_P (XEXP (cond, 0)) && REG_POINTER (XEXP (cond, 0)))
      && ((REG_P (XEXP (cond, 0)) && REG_POINTER (XEXP (cond, 0)))
          || (REG_P (XEXP (cond, 1)) && REG_POINTER (XEXP (cond, 1)))))
          || (REG_P (XEXP (cond, 1)) && REG_POINTER (XEXP (cond, 1)))))
    {
    {
      if (GET_CODE (cond) == EQ)
      if (GET_CODE (cond) == EQ)
        predict_insn_def (last_insn, PRED_POINTER, NOT_TAKEN);
        predict_insn_def (last_insn, PRED_POINTER, NOT_TAKEN);
      else if (GET_CODE (cond) == NE)
      else if (GET_CODE (cond) == NE)
        predict_insn_def (last_insn, PRED_POINTER, TAKEN);
        predict_insn_def (last_insn, PRED_POINTER, TAKEN);
    }
    }
  else
  else
 
 
  /* Try "opcode heuristic."
  /* Try "opcode heuristic."
     EQ tests are usually false and NE tests are usually true. Also,
     EQ tests are usually false and NE tests are usually true. Also,
     most quantities are positive, so we can make the appropriate guesses
     most quantities are positive, so we can make the appropriate guesses
     about signed comparisons against zero.  */
     about signed comparisons against zero.  */
    switch (GET_CODE (cond))
    switch (GET_CODE (cond))
      {
      {
      case CONST_INT:
      case CONST_INT:
        /* Unconditional branch.  */
        /* Unconditional branch.  */
        predict_insn_def (last_insn, PRED_UNCONDITIONAL,
        predict_insn_def (last_insn, PRED_UNCONDITIONAL,
                          cond == const0_rtx ? NOT_TAKEN : TAKEN);
                          cond == const0_rtx ? NOT_TAKEN : TAKEN);
        break;
        break;
 
 
      case EQ:
      case EQ:
      case UNEQ:
      case UNEQ:
        /* Floating point comparisons appears to behave in a very
        /* Floating point comparisons appears to behave in a very
           unpredictable way because of special role of = tests in
           unpredictable way because of special role of = tests in
           FP code.  */
           FP code.  */
        if (FLOAT_MODE_P (GET_MODE (XEXP (cond, 0))))
        if (FLOAT_MODE_P (GET_MODE (XEXP (cond, 0))))
          ;
          ;
        /* Comparisons with 0 are often used for booleans and there is
        /* Comparisons with 0 are often used for booleans and there is
           nothing useful to predict about them.  */
           nothing useful to predict about them.  */
        else if (XEXP (cond, 1) == const0_rtx
        else if (XEXP (cond, 1) == const0_rtx
                 || XEXP (cond, 0) == const0_rtx)
                 || XEXP (cond, 0) == const0_rtx)
          ;
          ;
        else
        else
          predict_insn_def (last_insn, PRED_OPCODE_NONEQUAL, NOT_TAKEN);
          predict_insn_def (last_insn, PRED_OPCODE_NONEQUAL, NOT_TAKEN);
        break;
        break;
 
 
      case NE:
      case NE:
      case LTGT:
      case LTGT:
        /* Floating point comparisons appears to behave in a very
        /* Floating point comparisons appears to behave in a very
           unpredictable way because of special role of = tests in
           unpredictable way because of special role of = tests in
           FP code.  */
           FP code.  */
        if (FLOAT_MODE_P (GET_MODE (XEXP (cond, 0))))
        if (FLOAT_MODE_P (GET_MODE (XEXP (cond, 0))))
          ;
          ;
        /* Comparisons with 0 are often used for booleans and there is
        /* Comparisons with 0 are often used for booleans and there is
           nothing useful to predict about them.  */
           nothing useful to predict about them.  */
        else if (XEXP (cond, 1) == const0_rtx
        else if (XEXP (cond, 1) == const0_rtx
                 || XEXP (cond, 0) == const0_rtx)
                 || XEXP (cond, 0) == const0_rtx)
          ;
          ;
        else
        else
          predict_insn_def (last_insn, PRED_OPCODE_NONEQUAL, TAKEN);
          predict_insn_def (last_insn, PRED_OPCODE_NONEQUAL, TAKEN);
        break;
        break;
 
 
      case ORDERED:
      case ORDERED:
        predict_insn_def (last_insn, PRED_FPOPCODE, TAKEN);
        predict_insn_def (last_insn, PRED_FPOPCODE, TAKEN);
        break;
        break;
 
 
      case UNORDERED:
      case UNORDERED:
        predict_insn_def (last_insn, PRED_FPOPCODE, NOT_TAKEN);
        predict_insn_def (last_insn, PRED_FPOPCODE, NOT_TAKEN);
        break;
        break;
 
 
      case LE:
      case LE:
      case LT:
      case LT:
        if (XEXP (cond, 1) == const0_rtx || XEXP (cond, 1) == const1_rtx
        if (XEXP (cond, 1) == const0_rtx || XEXP (cond, 1) == const1_rtx
            || XEXP (cond, 1) == constm1_rtx)
            || XEXP (cond, 1) == constm1_rtx)
          predict_insn_def (last_insn, PRED_OPCODE_POSITIVE, NOT_TAKEN);
          predict_insn_def (last_insn, PRED_OPCODE_POSITIVE, NOT_TAKEN);
        break;
        break;
 
 
      case GE:
      case GE:
      case GT:
      case GT:
        if (XEXP (cond, 1) == const0_rtx || XEXP (cond, 1) == const1_rtx
        if (XEXP (cond, 1) == const0_rtx || XEXP (cond, 1) == const1_rtx
            || XEXP (cond, 1) == constm1_rtx)
            || XEXP (cond, 1) == constm1_rtx)
          predict_insn_def (last_insn, PRED_OPCODE_POSITIVE, TAKEN);
          predict_insn_def (last_insn, PRED_OPCODE_POSITIVE, TAKEN);
        break;
        break;
 
 
      default:
      default:
        break;
        break;
      }
      }
}
}
 
 
/* Set edge->probability for each successor edge of BB.  */
/* Set edge->probability for each successor edge of BB.  */
void
void
guess_outgoing_edge_probabilities (basic_block bb)
guess_outgoing_edge_probabilities (basic_block bb)
{
{
  bb_estimate_probability_locally (bb);
  bb_estimate_probability_locally (bb);
  combine_predictions_for_insn (BB_END (bb), bb);
  combine_predictions_for_insn (BB_END (bb), bb);
}
}


/* Return constant EXPR will likely have at execution time, NULL if unknown.
/* Return constant EXPR will likely have at execution time, NULL if unknown.
   The function is used by builtin_expect branch predictor so the evidence
   The function is used by builtin_expect branch predictor so the evidence
   must come from this construct and additional possible constant folding.
   must come from this construct and additional possible constant folding.
 
 
   We may want to implement more involved value guess (such as value range
   We may want to implement more involved value guess (such as value range
   propagation based prediction), but such tricks shall go to new
   propagation based prediction), but such tricks shall go to new
   implementation.  */
   implementation.  */
 
 
static tree
static tree
expr_expected_value (tree expr, bitmap visited)
expr_expected_value (tree expr, bitmap visited)
{
{
  if (TREE_CONSTANT (expr))
  if (TREE_CONSTANT (expr))
    return expr;
    return expr;
  else if (TREE_CODE (expr) == SSA_NAME)
  else if (TREE_CODE (expr) == SSA_NAME)
    {
    {
      tree def = SSA_NAME_DEF_STMT (expr);
      tree def = SSA_NAME_DEF_STMT (expr);
 
 
      /* If we were already here, break the infinite cycle.  */
      /* If we were already here, break the infinite cycle.  */
      if (bitmap_bit_p (visited, SSA_NAME_VERSION (expr)))
      if (bitmap_bit_p (visited, SSA_NAME_VERSION (expr)))
        return NULL;
        return NULL;
      bitmap_set_bit (visited, SSA_NAME_VERSION (expr));
      bitmap_set_bit (visited, SSA_NAME_VERSION (expr));
 
 
      if (TREE_CODE (def) == PHI_NODE)
      if (TREE_CODE (def) == PHI_NODE)
        {
        {
          /* All the arguments of the PHI node must have the same constant
          /* All the arguments of the PHI node must have the same constant
             length.  */
             length.  */
          int i;
          int i;
          tree val = NULL, new_val;
          tree val = NULL, new_val;
 
 
          for (i = 0; i < PHI_NUM_ARGS (def); i++)
          for (i = 0; i < PHI_NUM_ARGS (def); i++)
            {
            {
              tree arg = PHI_ARG_DEF (def, i);
              tree arg = PHI_ARG_DEF (def, i);
 
 
              /* If this PHI has itself as an argument, we cannot
              /* If this PHI has itself as an argument, we cannot
                 determine the string length of this argument.  However,
                 determine the string length of this argument.  However,
                 if we can find an expected constant value for the other
                 if we can find an expected constant value for the other
                 PHI args then we can still be sure that this is
                 PHI args then we can still be sure that this is
                 likely a constant.  So be optimistic and just
                 likely a constant.  So be optimistic and just
                 continue with the next argument.  */
                 continue with the next argument.  */
              if (arg == PHI_RESULT (def))
              if (arg == PHI_RESULT (def))
                continue;
                continue;
 
 
              new_val = expr_expected_value (arg, visited);
              new_val = expr_expected_value (arg, visited);
              if (!new_val)
              if (!new_val)
                return NULL;
                return NULL;
              if (!val)
              if (!val)
                val = new_val;
                val = new_val;
              else if (!operand_equal_p (val, new_val, false))
              else if (!operand_equal_p (val, new_val, false))
                return NULL;
                return NULL;
            }
            }
          return val;
          return val;
        }
        }
      if (TREE_CODE (def) != MODIFY_EXPR || TREE_OPERAND (def, 0) != expr)
      if (TREE_CODE (def) != MODIFY_EXPR || TREE_OPERAND (def, 0) != expr)
        return NULL;
        return NULL;
      return expr_expected_value (TREE_OPERAND (def, 1), visited);
      return expr_expected_value (TREE_OPERAND (def, 1), visited);
    }
    }
  else if (TREE_CODE (expr) == CALL_EXPR)
  else if (TREE_CODE (expr) == CALL_EXPR)
    {
    {
      tree decl = get_callee_fndecl (expr);
      tree decl = get_callee_fndecl (expr);
      if (!decl)
      if (!decl)
        return NULL;
        return NULL;
      if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
      if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
          && DECL_FUNCTION_CODE (decl) == BUILT_IN_EXPECT)
          && DECL_FUNCTION_CODE (decl) == BUILT_IN_EXPECT)
        {
        {
          tree arglist = TREE_OPERAND (expr, 1);
          tree arglist = TREE_OPERAND (expr, 1);
          tree val;
          tree val;
 
 
          if (arglist == NULL_TREE
          if (arglist == NULL_TREE
              || TREE_CHAIN (arglist) == NULL_TREE)
              || TREE_CHAIN (arglist) == NULL_TREE)
            return NULL;
            return NULL;
          val = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
          val = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
          if (TREE_CONSTANT (val))
          if (TREE_CONSTANT (val))
            return val;
            return val;
          return TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
          return TREE_VALUE (TREE_CHAIN (TREE_OPERAND (expr, 1)));
        }
        }
    }
    }
  if (BINARY_CLASS_P (expr) || COMPARISON_CLASS_P (expr))
  if (BINARY_CLASS_P (expr) || COMPARISON_CLASS_P (expr))
    {
    {
      tree op0, op1, res;
      tree op0, op1, res;
      op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
      op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
      if (!op0)
      if (!op0)
        return NULL;
        return NULL;
      op1 = expr_expected_value (TREE_OPERAND (expr, 1), visited);
      op1 = expr_expected_value (TREE_OPERAND (expr, 1), visited);
      if (!op1)
      if (!op1)
        return NULL;
        return NULL;
      res = fold_build2 (TREE_CODE (expr), TREE_TYPE (expr), op0, op1);
      res = fold_build2 (TREE_CODE (expr), TREE_TYPE (expr), op0, op1);
      if (TREE_CONSTANT (res))
      if (TREE_CONSTANT (res))
        return res;
        return res;
      return NULL;
      return NULL;
    }
    }
  if (UNARY_CLASS_P (expr))
  if (UNARY_CLASS_P (expr))
    {
    {
      tree op0, res;
      tree op0, res;
      op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
      op0 = expr_expected_value (TREE_OPERAND (expr, 0), visited);
      if (!op0)
      if (!op0)
        return NULL;
        return NULL;
      res = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr), op0);
      res = fold_build1 (TREE_CODE (expr), TREE_TYPE (expr), op0);
      if (TREE_CONSTANT (res))
      if (TREE_CONSTANT (res))
        return res;
        return res;
      return NULL;
      return NULL;
    }
    }
  return NULL;
  return NULL;
}
}


/* Get rid of all builtin_expect calls we no longer need.  */
/* Get rid of all builtin_expect calls we no longer need.  */
static void
static void
strip_builtin_expect (void)
strip_builtin_expect (void)
{
{
  basic_block bb;
  basic_block bb;
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      block_stmt_iterator bi;
      block_stmt_iterator bi;
      for (bi = bsi_start (bb); !bsi_end_p (bi); bsi_next (&bi))
      for (bi = bsi_start (bb); !bsi_end_p (bi); bsi_next (&bi))
        {
        {
          tree stmt = bsi_stmt (bi);
          tree stmt = bsi_stmt (bi);
          tree fndecl;
          tree fndecl;
          tree arglist;
          tree arglist;
 
 
          if (TREE_CODE (stmt) == MODIFY_EXPR
          if (TREE_CODE (stmt) == MODIFY_EXPR
              && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR
              && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR
              && (fndecl = get_callee_fndecl (TREE_OPERAND (stmt, 1)))
              && (fndecl = get_callee_fndecl (TREE_OPERAND (stmt, 1)))
              && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
              && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
              && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
              && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
              && (arglist = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1))
              && (arglist = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1))
              && TREE_CHAIN (arglist))
              && TREE_CHAIN (arglist))
            {
            {
              TREE_OPERAND (stmt, 1) = TREE_VALUE (arglist);
              TREE_OPERAND (stmt, 1) = TREE_VALUE (arglist);
              update_stmt (stmt);
              update_stmt (stmt);
            }
            }
        }
        }
    }
    }
}
}


/* Predict using opcode of the last statement in basic block.  */
/* Predict using opcode of the last statement in basic block.  */
static void
static void
tree_predict_by_opcode (basic_block bb)
tree_predict_by_opcode (basic_block bb)
{
{
  tree stmt = last_stmt (bb);
  tree stmt = last_stmt (bb);
  edge then_edge;
  edge then_edge;
  tree cond;
  tree cond;
  tree op0;
  tree op0;
  tree type;
  tree type;
  tree val;
  tree val;
  bitmap visited;
  bitmap visited;
  edge_iterator ei;
  edge_iterator ei;
 
 
  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
    return;
    return;
  FOR_EACH_EDGE (then_edge, ei, bb->succs)
  FOR_EACH_EDGE (then_edge, ei, bb->succs)
    if (then_edge->flags & EDGE_TRUE_VALUE)
    if (then_edge->flags & EDGE_TRUE_VALUE)
      break;
      break;
  cond = TREE_OPERAND (stmt, 0);
  cond = TREE_OPERAND (stmt, 0);
  if (!COMPARISON_CLASS_P (cond))
  if (!COMPARISON_CLASS_P (cond))
    return;
    return;
  op0 = TREE_OPERAND (cond, 0);
  op0 = TREE_OPERAND (cond, 0);
  type = TREE_TYPE (op0);
  type = TREE_TYPE (op0);
  visited = BITMAP_ALLOC (NULL);
  visited = BITMAP_ALLOC (NULL);
  val = expr_expected_value (cond, visited);
  val = expr_expected_value (cond, visited);
  BITMAP_FREE (visited);
  BITMAP_FREE (visited);
  if (val)
  if (val)
    {
    {
      if (integer_zerop (val))
      if (integer_zerop (val))
        predict_edge_def (then_edge, PRED_BUILTIN_EXPECT, NOT_TAKEN);
        predict_edge_def (then_edge, PRED_BUILTIN_EXPECT, NOT_TAKEN);
      else
      else
        predict_edge_def (then_edge, PRED_BUILTIN_EXPECT, TAKEN);
        predict_edge_def (then_edge, PRED_BUILTIN_EXPECT, TAKEN);
      return;
      return;
    }
    }
  /* Try "pointer heuristic."
  /* Try "pointer heuristic."
     A comparison ptr == 0 is predicted as false.
     A comparison ptr == 0 is predicted as false.
     Similarly, a comparison ptr1 == ptr2 is predicted as false.  */
     Similarly, a comparison ptr1 == ptr2 is predicted as false.  */
  if (POINTER_TYPE_P (type))
  if (POINTER_TYPE_P (type))
    {
    {
      if (TREE_CODE (cond) == EQ_EXPR)
      if (TREE_CODE (cond) == EQ_EXPR)
        predict_edge_def (then_edge, PRED_TREE_POINTER, NOT_TAKEN);
        predict_edge_def (then_edge, PRED_TREE_POINTER, NOT_TAKEN);
      else if (TREE_CODE (cond) == NE_EXPR)
      else if (TREE_CODE (cond) == NE_EXPR)
        predict_edge_def (then_edge, PRED_TREE_POINTER, TAKEN);
        predict_edge_def (then_edge, PRED_TREE_POINTER, TAKEN);
    }
    }
  else
  else
 
 
  /* Try "opcode heuristic."
  /* Try "opcode heuristic."
     EQ tests are usually false and NE tests are usually true. Also,
     EQ tests are usually false and NE tests are usually true. Also,
     most quantities are positive, so we can make the appropriate guesses
     most quantities are positive, so we can make the appropriate guesses
     about signed comparisons against zero.  */
     about signed comparisons against zero.  */
    switch (TREE_CODE (cond))
    switch (TREE_CODE (cond))
      {
      {
      case EQ_EXPR:
      case EQ_EXPR:
      case UNEQ_EXPR:
      case UNEQ_EXPR:
        /* Floating point comparisons appears to behave in a very
        /* Floating point comparisons appears to behave in a very
           unpredictable way because of special role of = tests in
           unpredictable way because of special role of = tests in
           FP code.  */
           FP code.  */
        if (FLOAT_TYPE_P (type))
        if (FLOAT_TYPE_P (type))
          ;
          ;
        /* Comparisons with 0 are often used for booleans and there is
        /* Comparisons with 0 are often used for booleans and there is
           nothing useful to predict about them.  */
           nothing useful to predict about them.  */
        else if (integer_zerop (op0)
        else if (integer_zerop (op0)
                 || integer_zerop (TREE_OPERAND (cond, 1)))
                 || integer_zerop (TREE_OPERAND (cond, 1)))
          ;
          ;
        else
        else
          predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, NOT_TAKEN);
          predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, NOT_TAKEN);
        break;
        break;
 
 
      case NE_EXPR:
      case NE_EXPR:
      case LTGT_EXPR:
      case LTGT_EXPR:
        /* Floating point comparisons appears to behave in a very
        /* Floating point comparisons appears to behave in a very
           unpredictable way because of special role of = tests in
           unpredictable way because of special role of = tests in
           FP code.  */
           FP code.  */
        if (FLOAT_TYPE_P (type))
        if (FLOAT_TYPE_P (type))
          ;
          ;
        /* Comparisons with 0 are often used for booleans and there is
        /* Comparisons with 0 are often used for booleans and there is
           nothing useful to predict about them.  */
           nothing useful to predict about them.  */
        else if (integer_zerop (op0)
        else if (integer_zerop (op0)
                 || integer_zerop (TREE_OPERAND (cond, 1)))
                 || integer_zerop (TREE_OPERAND (cond, 1)))
          ;
          ;
        else
        else
          predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, TAKEN);
          predict_edge_def (then_edge, PRED_TREE_OPCODE_NONEQUAL, TAKEN);
        break;
        break;
 
 
      case ORDERED_EXPR:
      case ORDERED_EXPR:
        predict_edge_def (then_edge, PRED_TREE_FPOPCODE, TAKEN);
        predict_edge_def (then_edge, PRED_TREE_FPOPCODE, TAKEN);
        break;
        break;
 
 
      case UNORDERED_EXPR:
      case UNORDERED_EXPR:
        predict_edge_def (then_edge, PRED_TREE_FPOPCODE, NOT_TAKEN);
        predict_edge_def (then_edge, PRED_TREE_FPOPCODE, NOT_TAKEN);
        break;
        break;
 
 
      case LE_EXPR:
      case LE_EXPR:
      case LT_EXPR:
      case LT_EXPR:
        if (integer_zerop (TREE_OPERAND (cond, 1))
        if (integer_zerop (TREE_OPERAND (cond, 1))
            || integer_onep (TREE_OPERAND (cond, 1))
            || integer_onep (TREE_OPERAND (cond, 1))
            || integer_all_onesp (TREE_OPERAND (cond, 1))
            || integer_all_onesp (TREE_OPERAND (cond, 1))
            || real_zerop (TREE_OPERAND (cond, 1))
            || real_zerop (TREE_OPERAND (cond, 1))
            || real_onep (TREE_OPERAND (cond, 1))
            || real_onep (TREE_OPERAND (cond, 1))
            || real_minus_onep (TREE_OPERAND (cond, 1)))
            || real_minus_onep (TREE_OPERAND (cond, 1)))
          predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, NOT_TAKEN);
          predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, NOT_TAKEN);
        break;
        break;
 
 
      case GE_EXPR:
      case GE_EXPR:
      case GT_EXPR:
      case GT_EXPR:
        if (integer_zerop (TREE_OPERAND (cond, 1))
        if (integer_zerop (TREE_OPERAND (cond, 1))
            || integer_onep (TREE_OPERAND (cond, 1))
            || integer_onep (TREE_OPERAND (cond, 1))
            || integer_all_onesp (TREE_OPERAND (cond, 1))
            || integer_all_onesp (TREE_OPERAND (cond, 1))
            || real_zerop (TREE_OPERAND (cond, 1))
            || real_zerop (TREE_OPERAND (cond, 1))
            || real_onep (TREE_OPERAND (cond, 1))
            || real_onep (TREE_OPERAND (cond, 1))
            || real_minus_onep (TREE_OPERAND (cond, 1)))
            || real_minus_onep (TREE_OPERAND (cond, 1)))
          predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, TAKEN);
          predict_edge_def (then_edge, PRED_TREE_OPCODE_POSITIVE, TAKEN);
        break;
        break;
 
 
      default:
      default:
        break;
        break;
      }
      }
}
}
 
 
/* Try to guess whether the value of return means error code.  */
/* Try to guess whether the value of return means error code.  */
static enum br_predictor
static enum br_predictor
return_prediction (tree val, enum prediction *prediction)
return_prediction (tree val, enum prediction *prediction)
{
{
  /* VOID.  */
  /* VOID.  */
  if (!val)
  if (!val)
    return PRED_NO_PREDICTION;
    return PRED_NO_PREDICTION;
  /* Different heuristics for pointers and scalars.  */
  /* Different heuristics for pointers and scalars.  */
  if (POINTER_TYPE_P (TREE_TYPE (val)))
  if (POINTER_TYPE_P (TREE_TYPE (val)))
    {
    {
      /* NULL is usually not returned.  */
      /* NULL is usually not returned.  */
      if (integer_zerop (val))
      if (integer_zerop (val))
        {
        {
          *prediction = NOT_TAKEN;
          *prediction = NOT_TAKEN;
          return PRED_NULL_RETURN;
          return PRED_NULL_RETURN;
        }
        }
    }
    }
  else if (INTEGRAL_TYPE_P (TREE_TYPE (val)))
  else if (INTEGRAL_TYPE_P (TREE_TYPE (val)))
    {
    {
      /* Negative return values are often used to indicate
      /* Negative return values are often used to indicate
         errors.  */
         errors.  */
      if (TREE_CODE (val) == INTEGER_CST
      if (TREE_CODE (val) == INTEGER_CST
          && tree_int_cst_sgn (val) < 0)
          && tree_int_cst_sgn (val) < 0)
        {
        {
          *prediction = NOT_TAKEN;
          *prediction = NOT_TAKEN;
          return PRED_NEGATIVE_RETURN;
          return PRED_NEGATIVE_RETURN;
        }
        }
      /* Constant return values seems to be commonly taken.
      /* Constant return values seems to be commonly taken.
         Zero/one often represent booleans so exclude them from the
         Zero/one often represent booleans so exclude them from the
         heuristics.  */
         heuristics.  */
      if (TREE_CONSTANT (val)
      if (TREE_CONSTANT (val)
          && (!integer_zerop (val) && !integer_onep (val)))
          && (!integer_zerop (val) && !integer_onep (val)))
        {
        {
          *prediction = TAKEN;
          *prediction = TAKEN;
          return PRED_NEGATIVE_RETURN;
          return PRED_NEGATIVE_RETURN;
        }
        }
    }
    }
  return PRED_NO_PREDICTION;
  return PRED_NO_PREDICTION;
}
}
 
 
/* Find the basic block with return expression and look up for possible
/* Find the basic block with return expression and look up for possible
   return value trying to apply RETURN_PREDICTION heuristics.  */
   return value trying to apply RETURN_PREDICTION heuristics.  */
static void
static void
apply_return_prediction (int *heads)
apply_return_prediction (int *heads)
{
{
  tree return_stmt = NULL;
  tree return_stmt = NULL;
  tree return_val;
  tree return_val;
  edge e;
  edge e;
  tree phi;
  tree phi;
  int phi_num_args, i;
  int phi_num_args, i;
  enum br_predictor pred;
  enum br_predictor pred;
  enum prediction direction;
  enum prediction direction;
  edge_iterator ei;
  edge_iterator ei;
 
 
  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
    {
    {
      return_stmt = last_stmt (e->src);
      return_stmt = last_stmt (e->src);
      if (TREE_CODE (return_stmt) == RETURN_EXPR)
      if (TREE_CODE (return_stmt) == RETURN_EXPR)
        break;
        break;
    }
    }
  if (!e)
  if (!e)
    return;
    return;
  return_val = TREE_OPERAND (return_stmt, 0);
  return_val = TREE_OPERAND (return_stmt, 0);
  if (!return_val)
  if (!return_val)
    return;
    return;
  if (TREE_CODE (return_val) == MODIFY_EXPR)
  if (TREE_CODE (return_val) == MODIFY_EXPR)
    return_val = TREE_OPERAND (return_val, 1);
    return_val = TREE_OPERAND (return_val, 1);
  if (TREE_CODE (return_val) != SSA_NAME
  if (TREE_CODE (return_val) != SSA_NAME
      || !SSA_NAME_DEF_STMT (return_val)
      || !SSA_NAME_DEF_STMT (return_val)
      || TREE_CODE (SSA_NAME_DEF_STMT (return_val)) != PHI_NODE)
      || TREE_CODE (SSA_NAME_DEF_STMT (return_val)) != PHI_NODE)
    return;
    return;
  for (phi = SSA_NAME_DEF_STMT (return_val); phi; phi = PHI_CHAIN (phi))
  for (phi = SSA_NAME_DEF_STMT (return_val); phi; phi = PHI_CHAIN (phi))
    if (PHI_RESULT (phi) == return_val)
    if (PHI_RESULT (phi) == return_val)
      break;
      break;
  if (!phi)
  if (!phi)
    return;
    return;
  phi_num_args = PHI_NUM_ARGS (phi);
  phi_num_args = PHI_NUM_ARGS (phi);
  pred = return_prediction (PHI_ARG_DEF (phi, 0), &direction);
  pred = return_prediction (PHI_ARG_DEF (phi, 0), &direction);
 
 
  /* Avoid the degenerate case where all return values form the function
  /* Avoid the degenerate case where all return values form the function
     belongs to same category (ie they are all positive constants)
     belongs to same category (ie they are all positive constants)
     so we can hardly say something about them.  */
     so we can hardly say something about them.  */
  for (i = 1; i < phi_num_args; i++)
  for (i = 1; i < phi_num_args; i++)
    if (pred != return_prediction (PHI_ARG_DEF (phi, i), &direction))
    if (pred != return_prediction (PHI_ARG_DEF (phi, i), &direction))
      break;
      break;
  if (i != phi_num_args)
  if (i != phi_num_args)
    for (i = 0; i < phi_num_args; i++)
    for (i = 0; i < phi_num_args; i++)
      {
      {
        pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
        pred = return_prediction (PHI_ARG_DEF (phi, i), &direction);
        if (pred != PRED_NO_PREDICTION)
        if (pred != PRED_NO_PREDICTION)
          predict_paths_leading_to (PHI_ARG_EDGE (phi, i)->src, heads, pred,
          predict_paths_leading_to (PHI_ARG_EDGE (phi, i)->src, heads, pred,
                                    direction);
                                    direction);
      }
      }
}
}
 
 
/* Look for basic block that contains unlikely to happen events
/* Look for basic block that contains unlikely to happen events
   (such as noreturn calls) and mark all paths leading to execution
   (such as noreturn calls) and mark all paths leading to execution
   of this basic blocks as unlikely.  */
   of this basic blocks as unlikely.  */
 
 
static void
static void
tree_bb_level_predictions (void)
tree_bb_level_predictions (void)
{
{
  basic_block bb;
  basic_block bb;
  int *heads;
  int *heads;
 
 
  heads = XNEWVEC (int, last_basic_block);
  heads = XNEWVEC (int, last_basic_block);
  memset (heads, ENTRY_BLOCK, sizeof (int) * last_basic_block);
  memset (heads, ENTRY_BLOCK, sizeof (int) * last_basic_block);
  heads[ENTRY_BLOCK_PTR->next_bb->index] = last_basic_block;
  heads[ENTRY_BLOCK_PTR->next_bb->index] = last_basic_block;
 
 
  apply_return_prediction (heads);
  apply_return_prediction (heads);
 
 
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      block_stmt_iterator bsi = bsi_last (bb);
      block_stmt_iterator bsi = bsi_last (bb);
 
 
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
        {
        {
          tree stmt = bsi_stmt (bsi);
          tree stmt = bsi_stmt (bsi);
          switch (TREE_CODE (stmt))
          switch (TREE_CODE (stmt))
            {
            {
              case MODIFY_EXPR:
              case MODIFY_EXPR:
                if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
                if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
                  {
                  {
                    stmt = TREE_OPERAND (stmt, 1);
                    stmt = TREE_OPERAND (stmt, 1);
                    goto call_expr;
                    goto call_expr;
                  }
                  }
                break;
                break;
              case CALL_EXPR:
              case CALL_EXPR:
call_expr:;
call_expr:;
                if (call_expr_flags (stmt) & ECF_NORETURN)
                if (call_expr_flags (stmt) & ECF_NORETURN)
                  predict_paths_leading_to (bb, heads, PRED_NORETURN,
                  predict_paths_leading_to (bb, heads, PRED_NORETURN,
                                            NOT_TAKEN);
                                            NOT_TAKEN);
                break;
                break;
              default:
              default:
                break;
                break;
            }
            }
        }
        }
    }
    }
 
 
  free (heads);
  free (heads);
}
}
 
 
/* Predict branch probabilities and estimate profile of the tree CFG.  */
/* Predict branch probabilities and estimate profile of the tree CFG.  */
static unsigned int
static unsigned int
tree_estimate_probability (void)
tree_estimate_probability (void)
{
{
  basic_block bb;
  basic_block bb;
  struct loops loops_info;
  struct loops loops_info;
 
 
  flow_loops_find (&loops_info);
  flow_loops_find (&loops_info);
  if (dump_file && (dump_flags & TDF_DETAILS))
  if (dump_file && (dump_flags & TDF_DETAILS))
    flow_loops_dump (&loops_info, dump_file, NULL, 0);
    flow_loops_dump (&loops_info, dump_file, NULL, 0);
 
 
  add_noreturn_fake_exit_edges ();
  add_noreturn_fake_exit_edges ();
  connect_infinite_loops_to_exit ();
  connect_infinite_loops_to_exit ();
  calculate_dominance_info (CDI_DOMINATORS);
  calculate_dominance_info (CDI_DOMINATORS);
  calculate_dominance_info (CDI_POST_DOMINATORS);
  calculate_dominance_info (CDI_POST_DOMINATORS);
 
 
  tree_bb_level_predictions ();
  tree_bb_level_predictions ();
 
 
  mark_irreducible_loops (&loops_info);
  mark_irreducible_loops (&loops_info);
  predict_loops (&loops_info, false);
  predict_loops (&loops_info, false);
 
 
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      edge e;
      edge e;
      edge_iterator ei;
      edge_iterator ei;
 
 
      FOR_EACH_EDGE (e, ei, bb->succs)
      FOR_EACH_EDGE (e, ei, bb->succs)
        {
        {
          /* Predict early returns to be probable, as we've already taken
          /* Predict early returns to be probable, as we've already taken
             care for error returns and other cases are often used for
             care for error returns and other cases are often used for
             fast paths through function.  */
             fast paths through function.  */
          if (e->dest == EXIT_BLOCK_PTR
          if (e->dest == EXIT_BLOCK_PTR
              && TREE_CODE (last_stmt (bb)) == RETURN_EXPR
              && TREE_CODE (last_stmt (bb)) == RETURN_EXPR
              && !single_pred_p (bb))
              && !single_pred_p (bb))
            {
            {
              edge e1;
              edge e1;
              edge_iterator ei1;
              edge_iterator ei1;
 
 
              FOR_EACH_EDGE (e1, ei1, bb->preds)
              FOR_EACH_EDGE (e1, ei1, bb->preds)
                if (!predicted_by_p (e1->src, PRED_NULL_RETURN)
                if (!predicted_by_p (e1->src, PRED_NULL_RETURN)
                    && !predicted_by_p (e1->src, PRED_CONST_RETURN)
                    && !predicted_by_p (e1->src, PRED_CONST_RETURN)
                    && !predicted_by_p (e1->src, PRED_NEGATIVE_RETURN)
                    && !predicted_by_p (e1->src, PRED_NEGATIVE_RETURN)
                    && !last_basic_block_p (e1->src))
                    && !last_basic_block_p (e1->src))
                  predict_edge_def (e1, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
                  predict_edge_def (e1, PRED_TREE_EARLY_RETURN, NOT_TAKEN);
            }
            }
 
 
          /* Look for block we are guarding (ie we dominate it,
          /* Look for block we are guarding (ie we dominate it,
             but it doesn't postdominate us).  */
             but it doesn't postdominate us).  */
          if (e->dest != EXIT_BLOCK_PTR && e->dest != bb
          if (e->dest != EXIT_BLOCK_PTR && e->dest != bb
              && dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
              && dominated_by_p (CDI_DOMINATORS, e->dest, e->src)
              && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e->dest))
              && !dominated_by_p (CDI_POST_DOMINATORS, e->src, e->dest))
            {
            {
              block_stmt_iterator bi;
              block_stmt_iterator bi;
 
 
              /* The call heuristic claims that a guarded function call
              /* The call heuristic claims that a guarded function call
                 is improbable.  This is because such calls are often used
                 is improbable.  This is because such calls are often used
                 to signal exceptional situations such as printing error
                 to signal exceptional situations such as printing error
                 messages.  */
                 messages.  */
              for (bi = bsi_start (e->dest); !bsi_end_p (bi);
              for (bi = bsi_start (e->dest); !bsi_end_p (bi);
                   bsi_next (&bi))
                   bsi_next (&bi))
                {
                {
                  tree stmt = bsi_stmt (bi);
                  tree stmt = bsi_stmt (bi);
                  if ((TREE_CODE (stmt) == CALL_EXPR
                  if ((TREE_CODE (stmt) == CALL_EXPR
                       || (TREE_CODE (stmt) == MODIFY_EXPR
                       || (TREE_CODE (stmt) == MODIFY_EXPR
                           && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR))
                           && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR))
                      /* Constant and pure calls are hardly used to signalize
                      /* Constant and pure calls are hardly used to signalize
                         something exceptional.  */
                         something exceptional.  */
                      && TREE_SIDE_EFFECTS (stmt))
                      && TREE_SIDE_EFFECTS (stmt))
                    {
                    {
                      predict_edge_def (e, PRED_CALL, NOT_TAKEN);
                      predict_edge_def (e, PRED_CALL, NOT_TAKEN);
                      break;
                      break;
                    }
                    }
                }
                }
            }
            }
        }
        }
      tree_predict_by_opcode (bb);
      tree_predict_by_opcode (bb);
    }
    }
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    combine_predictions_for_bb (bb);
    combine_predictions_for_bb (bb);
 
 
  strip_builtin_expect ();
  strip_builtin_expect ();
  estimate_bb_frequencies (&loops_info);
  estimate_bb_frequencies (&loops_info);
  free_dominance_info (CDI_POST_DOMINATORS);
  free_dominance_info (CDI_POST_DOMINATORS);
  remove_fake_exit_edges ();
  remove_fake_exit_edges ();
  flow_loops_free (&loops_info);
  flow_loops_free (&loops_info);
  if (dump_file && (dump_flags & TDF_DETAILS))
  if (dump_file && (dump_flags & TDF_DETAILS))
    dump_tree_cfg (dump_file, dump_flags);
    dump_tree_cfg (dump_file, dump_flags);
  if (profile_status == PROFILE_ABSENT)
  if (profile_status == PROFILE_ABSENT)
    profile_status = PROFILE_GUESSED;
    profile_status = PROFILE_GUESSED;
  return 0;
  return 0;
}
}


/* __builtin_expect dropped tokens into the insn stream describing expected
/* __builtin_expect dropped tokens into the insn stream describing expected
   values of registers.  Generate branch probabilities based off these
   values of registers.  Generate branch probabilities based off these
   values.  */
   values.  */
 
 
void
void
expected_value_to_br_prob (void)
expected_value_to_br_prob (void)
{
{
  rtx insn, cond, ev = NULL_RTX, ev_reg = NULL_RTX;
  rtx insn, cond, ev = NULL_RTX, ev_reg = NULL_RTX;
 
 
  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
    {
    {
      switch (GET_CODE (insn))
      switch (GET_CODE (insn))
        {
        {
        case NOTE:
        case NOTE:
          /* Look for expected value notes.  */
          /* Look for expected value notes.  */
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EXPECTED_VALUE)
          if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EXPECTED_VALUE)
            {
            {
              ev = NOTE_EXPECTED_VALUE (insn);
              ev = NOTE_EXPECTED_VALUE (insn);
              ev_reg = XEXP (ev, 0);
              ev_reg = XEXP (ev, 0);
              delete_insn (insn);
              delete_insn (insn);
            }
            }
          continue;
          continue;
 
 
        case CODE_LABEL:
        case CODE_LABEL:
          /* Never propagate across labels.  */
          /* Never propagate across labels.  */
          ev = NULL_RTX;
          ev = NULL_RTX;
          continue;
          continue;
 
 
        case JUMP_INSN:
        case JUMP_INSN:
          /* Look for simple conditional branches.  If we haven't got an
          /* Look for simple conditional branches.  If we haven't got an
             expected value yet, no point going further.  */
             expected value yet, no point going further.  */
          if (!JUMP_P (insn) || ev == NULL_RTX
          if (!JUMP_P (insn) || ev == NULL_RTX
              || ! any_condjump_p (insn))
              || ! any_condjump_p (insn))
            continue;
            continue;
          break;
          break;
 
 
        default:
        default:
          /* Look for insns that clobber the EV register.  */
          /* Look for insns that clobber the EV register.  */
          if (ev && reg_set_p (ev_reg, insn))
          if (ev && reg_set_p (ev_reg, insn))
            ev = NULL_RTX;
            ev = NULL_RTX;
          continue;
          continue;
        }
        }
 
 
      /* Collect the branch condition, hopefully relative to EV_REG.  */
      /* Collect the branch condition, hopefully relative to EV_REG.  */
      /* ???  At present we'll miss things like
      /* ???  At present we'll miss things like
                (expected_value (eq r70 0))
                (expected_value (eq r70 0))
                (set r71 -1)
                (set r71 -1)
                (set r80 (lt r70 r71))
                (set r80 (lt r70 r71))
                (set pc (if_then_else (ne r80 0) ...))
                (set pc (if_then_else (ne r80 0) ...))
         as canonicalize_condition will render this to us as
         as canonicalize_condition will render this to us as
                (lt r70, r71)
                (lt r70, r71)
         Could use cselib to try and reduce this further.  */
         Could use cselib to try and reduce this further.  */
      cond = XEXP (SET_SRC (pc_set (insn)), 0);
      cond = XEXP (SET_SRC (pc_set (insn)), 0);
      cond = canonicalize_condition (insn, cond, 0, NULL, ev_reg,
      cond = canonicalize_condition (insn, cond, 0, NULL, ev_reg,
                                     false, false);
                                     false, false);
      if (! cond || XEXP (cond, 0) != ev_reg
      if (! cond || XEXP (cond, 0) != ev_reg
          || GET_CODE (XEXP (cond, 1)) != CONST_INT)
          || GET_CODE (XEXP (cond, 1)) != CONST_INT)
        continue;
        continue;
 
 
      /* Substitute and simplify.  Given that the expression we're
      /* Substitute and simplify.  Given that the expression we're
         building involves two constants, we should wind up with either
         building involves two constants, we should wind up with either
         true or false.  */
         true or false.  */
      cond = gen_rtx_fmt_ee (GET_CODE (cond), VOIDmode,
      cond = gen_rtx_fmt_ee (GET_CODE (cond), VOIDmode,
                             XEXP (ev, 1), XEXP (cond, 1));
                             XEXP (ev, 1), XEXP (cond, 1));
      cond = simplify_rtx (cond);
      cond = simplify_rtx (cond);
 
 
      /* Turn the condition into a scaled branch probability.  */
      /* Turn the condition into a scaled branch probability.  */
      gcc_assert (cond == const_true_rtx || cond == const0_rtx);
      gcc_assert (cond == const_true_rtx || cond == const0_rtx);
      predict_insn_def (insn, PRED_BUILTIN_EXPECT,
      predict_insn_def (insn, PRED_BUILTIN_EXPECT,
                        cond == const_true_rtx ? TAKEN : NOT_TAKEN);
                        cond == const_true_rtx ? TAKEN : NOT_TAKEN);
    }
    }
}
}


/* Check whether this is the last basic block of function.  Commonly
/* Check whether this is the last basic block of function.  Commonly
   there is one extra common cleanup block.  */
   there is one extra common cleanup block.  */
static bool
static bool
last_basic_block_p (basic_block bb)
last_basic_block_p (basic_block bb)
{
{
  if (bb == EXIT_BLOCK_PTR)
  if (bb == EXIT_BLOCK_PTR)
    return false;
    return false;
 
 
  return (bb->next_bb == EXIT_BLOCK_PTR
  return (bb->next_bb == EXIT_BLOCK_PTR
          || (bb->next_bb->next_bb == EXIT_BLOCK_PTR
          || (bb->next_bb->next_bb == EXIT_BLOCK_PTR
              && single_succ_p (bb)
              && single_succ_p (bb)
              && single_succ (bb)->next_bb == EXIT_BLOCK_PTR));
              && single_succ (bb)->next_bb == EXIT_BLOCK_PTR));
}
}
 
 
/* Sets branch probabilities according to PREDiction and
/* Sets branch probabilities according to PREDiction and
   FLAGS. HEADS[bb->index] should be index of basic block in that we
   FLAGS. HEADS[bb->index] should be index of basic block in that we
   need to alter branch predictions (i.e. the first of our dominators
   need to alter branch predictions (i.e. the first of our dominators
   such that we do not post-dominate it) (but we fill this information
   such that we do not post-dominate it) (but we fill this information
   on demand, so -1 may be there in case this was not needed yet).  */
   on demand, so -1 may be there in case this was not needed yet).  */
 
 
static void
static void
predict_paths_leading_to (basic_block bb, int *heads, enum br_predictor pred,
predict_paths_leading_to (basic_block bb, int *heads, enum br_predictor pred,
                          enum prediction taken)
                          enum prediction taken)
{
{
  edge e;
  edge e;
  edge_iterator ei;
  edge_iterator ei;
  int y;
  int y;
 
 
  if (heads[bb->index] == ENTRY_BLOCK)
  if (heads[bb->index] == ENTRY_BLOCK)
    {
    {
      /* This is first time we need this field in heads array; so
      /* This is first time we need this field in heads array; so
         find first dominator that we do not post-dominate (we are
         find first dominator that we do not post-dominate (we are
         using already known members of heads array).  */
         using already known members of heads array).  */
      basic_block ai = bb;
      basic_block ai = bb;
      basic_block next_ai = get_immediate_dominator (CDI_DOMINATORS, bb);
      basic_block next_ai = get_immediate_dominator (CDI_DOMINATORS, bb);
      int head;
      int head;
 
 
      while (heads[next_ai->index] == ENTRY_BLOCK)
      while (heads[next_ai->index] == ENTRY_BLOCK)
        {
        {
          if (!dominated_by_p (CDI_POST_DOMINATORS, next_ai, bb))
          if (!dominated_by_p (CDI_POST_DOMINATORS, next_ai, bb))
            break;
            break;
          heads[next_ai->index] = ai->index;
          heads[next_ai->index] = ai->index;
          ai = next_ai;
          ai = next_ai;
          next_ai = get_immediate_dominator (CDI_DOMINATORS, next_ai);
          next_ai = get_immediate_dominator (CDI_DOMINATORS, next_ai);
        }
        }
      if (!dominated_by_p (CDI_POST_DOMINATORS, next_ai, bb))
      if (!dominated_by_p (CDI_POST_DOMINATORS, next_ai, bb))
        head = next_ai->index;
        head = next_ai->index;
      else
      else
        head = heads[next_ai->index];
        head = heads[next_ai->index];
      while (next_ai != bb)
      while (next_ai != bb)
        {
        {
          next_ai = ai;
          next_ai = ai;
          ai = BASIC_BLOCK (heads[ai->index]);
          ai = BASIC_BLOCK (heads[ai->index]);
          heads[next_ai->index] = head;
          heads[next_ai->index] = head;
        }
        }
    }
    }
  y = heads[bb->index];
  y = heads[bb->index];
 
 
  /* Now find the edge that leads to our branch and aply the prediction.  */
  /* Now find the edge that leads to our branch and aply the prediction.  */
 
 
  if (y == last_basic_block)
  if (y == last_basic_block)
    return;
    return;
  FOR_EACH_EDGE (e, ei, BASIC_BLOCK (y)->succs)
  FOR_EACH_EDGE (e, ei, BASIC_BLOCK (y)->succs)
    if (e->dest->index >= NUM_FIXED_BLOCKS
    if (e->dest->index >= NUM_FIXED_BLOCKS
        && dominated_by_p (CDI_POST_DOMINATORS, e->dest, bb))
        && dominated_by_p (CDI_POST_DOMINATORS, e->dest, bb))
      predict_edge_def (e, pred, taken);
      predict_edge_def (e, pred, taken);
}
}


/* This is used to carry information about basic blocks.  It is
/* This is used to carry information about basic blocks.  It is
   attached to the AUX field of the standard CFG block.  */
   attached to the AUX field of the standard CFG block.  */
 
 
typedef struct block_info_def
typedef struct block_info_def
{
{
  /* Estimated frequency of execution of basic_block.  */
  /* Estimated frequency of execution of basic_block.  */
  sreal frequency;
  sreal frequency;
 
 
  /* To keep queue of basic blocks to process.  */
  /* To keep queue of basic blocks to process.  */
  basic_block next;
  basic_block next;
 
 
  /* Number of predecessors we need to visit first.  */
  /* Number of predecessors we need to visit first.  */
  int npredecessors;
  int npredecessors;
} *block_info;
} *block_info;
 
 
/* Similar information for edges.  */
/* Similar information for edges.  */
typedef struct edge_info_def
typedef struct edge_info_def
{
{
  /* In case edge is a loopback edge, the probability edge will be reached
  /* In case edge is a loopback edge, the probability edge will be reached
     in case header is.  Estimated number of iterations of the loop can be
     in case header is.  Estimated number of iterations of the loop can be
     then computed as 1 / (1 - back_edge_prob).  */
     then computed as 1 / (1 - back_edge_prob).  */
  sreal back_edge_prob;
  sreal back_edge_prob;
  /* True if the edge is a loopback edge in the natural loop.  */
  /* True if the edge is a loopback edge in the natural loop.  */
  unsigned int back_edge:1;
  unsigned int back_edge:1;
} *edge_info;
} *edge_info;
 
 
#define BLOCK_INFO(B)   ((block_info) (B)->aux)
#define BLOCK_INFO(B)   ((block_info) (B)->aux)
#define EDGE_INFO(E)    ((edge_info) (E)->aux)
#define EDGE_INFO(E)    ((edge_info) (E)->aux)
 
 
/* Helper function for estimate_bb_frequencies.
/* Helper function for estimate_bb_frequencies.
   Propagate the frequencies for LOOP.  */
   Propagate the frequencies for LOOP.  */
 
 
static void
static void
propagate_freq (struct loop *loop, bitmap tovisit)
propagate_freq (struct loop *loop, bitmap tovisit)
{
{
  basic_block head = loop->header;
  basic_block head = loop->header;
  basic_block bb;
  basic_block bb;
  basic_block last;
  basic_block last;
  unsigned i;
  unsigned i;
  edge e;
  edge e;
  basic_block nextbb;
  basic_block nextbb;
  bitmap_iterator bi;
  bitmap_iterator bi;
 
 
  /* For each basic block we need to visit count number of his predecessors
  /* For each basic block we need to visit count number of his predecessors
     we need to visit first.  */
     we need to visit first.  */
  EXECUTE_IF_SET_IN_BITMAP (tovisit, 0, i, bi)
  EXECUTE_IF_SET_IN_BITMAP (tovisit, 0, i, bi)
    {
    {
      edge_iterator ei;
      edge_iterator ei;
      int count = 0;
      int count = 0;
 
 
       /* The outermost "loop" includes the exit block, which we can not
       /* The outermost "loop" includes the exit block, which we can not
          look up via BASIC_BLOCK.  Detect this and use EXIT_BLOCK_PTR
          look up via BASIC_BLOCK.  Detect this and use EXIT_BLOCK_PTR
          directly.  Do the same for the entry block.  */
          directly.  Do the same for the entry block.  */
      bb = BASIC_BLOCK (i);
      bb = BASIC_BLOCK (i);
 
 
      FOR_EACH_EDGE (e, ei, bb->preds)
      FOR_EACH_EDGE (e, ei, bb->preds)
        {
        {
          bool visit = bitmap_bit_p (tovisit, e->src->index);
          bool visit = bitmap_bit_p (tovisit, e->src->index);
 
 
          if (visit && !(e->flags & EDGE_DFS_BACK))
          if (visit && !(e->flags & EDGE_DFS_BACK))
            count++;
            count++;
          else if (visit && dump_file && !EDGE_INFO (e)->back_edge)
          else if (visit && dump_file && !EDGE_INFO (e)->back_edge)
            fprintf (dump_file,
            fprintf (dump_file,
                     "Irreducible region hit, ignoring edge to %i->%i\n",
                     "Irreducible region hit, ignoring edge to %i->%i\n",
                     e->src->index, bb->index);
                     e->src->index, bb->index);
        }
        }
      BLOCK_INFO (bb)->npredecessors = count;
      BLOCK_INFO (bb)->npredecessors = count;
    }
    }
 
 
  memcpy (&BLOCK_INFO (head)->frequency, &real_one, sizeof (real_one));
  memcpy (&BLOCK_INFO (head)->frequency, &real_one, sizeof (real_one));
  last = head;
  last = head;
  for (bb = head; bb; bb = nextbb)
  for (bb = head; bb; bb = nextbb)
    {
    {
      edge_iterator ei;
      edge_iterator ei;
      sreal cyclic_probability, frequency;
      sreal cyclic_probability, frequency;
 
 
      memcpy (&cyclic_probability, &real_zero, sizeof (real_zero));
      memcpy (&cyclic_probability, &real_zero, sizeof (real_zero));
      memcpy (&frequency, &real_zero, sizeof (real_zero));
      memcpy (&frequency, &real_zero, sizeof (real_zero));
 
 
      nextbb = BLOCK_INFO (bb)->next;
      nextbb = BLOCK_INFO (bb)->next;
      BLOCK_INFO (bb)->next = NULL;
      BLOCK_INFO (bb)->next = NULL;
 
 
      /* Compute frequency of basic block.  */
      /* Compute frequency of basic block.  */
      if (bb != head)
      if (bb != head)
        {
        {
#ifdef ENABLE_CHECKING
#ifdef ENABLE_CHECKING
          FOR_EACH_EDGE (e, ei, bb->preds)
          FOR_EACH_EDGE (e, ei, bb->preds)
            gcc_assert (!bitmap_bit_p (tovisit, e->src->index)
            gcc_assert (!bitmap_bit_p (tovisit, e->src->index)
                        || (e->flags & EDGE_DFS_BACK));
                        || (e->flags & EDGE_DFS_BACK));
#endif
#endif
 
 
          FOR_EACH_EDGE (e, ei, bb->preds)
          FOR_EACH_EDGE (e, ei, bb->preds)
            if (EDGE_INFO (e)->back_edge)
            if (EDGE_INFO (e)->back_edge)
              {
              {
                sreal_add (&cyclic_probability, &cyclic_probability,
                sreal_add (&cyclic_probability, &cyclic_probability,
                           &EDGE_INFO (e)->back_edge_prob);
                           &EDGE_INFO (e)->back_edge_prob);
              }
              }
            else if (!(e->flags & EDGE_DFS_BACK))
            else if (!(e->flags & EDGE_DFS_BACK))
              {
              {
                sreal tmp;
                sreal tmp;
 
 
                /*  frequency += (e->probability
                /*  frequency += (e->probability
                                  * BLOCK_INFO (e->src)->frequency /
                                  * BLOCK_INFO (e->src)->frequency /
                                  REG_BR_PROB_BASE);  */
                                  REG_BR_PROB_BASE);  */
 
 
                sreal_init (&tmp, e->probability, 0);
                sreal_init (&tmp, e->probability, 0);
                sreal_mul (&tmp, &tmp, &BLOCK_INFO (e->src)->frequency);
                sreal_mul (&tmp, &tmp, &BLOCK_INFO (e->src)->frequency);
                sreal_mul (&tmp, &tmp, &real_inv_br_prob_base);
                sreal_mul (&tmp, &tmp, &real_inv_br_prob_base);
                sreal_add (&frequency, &frequency, &tmp);
                sreal_add (&frequency, &frequency, &tmp);
              }
              }
 
 
          if (sreal_compare (&cyclic_probability, &real_zero) == 0)
          if (sreal_compare (&cyclic_probability, &real_zero) == 0)
            {
            {
              memcpy (&BLOCK_INFO (bb)->frequency, &frequency,
              memcpy (&BLOCK_INFO (bb)->frequency, &frequency,
                      sizeof (frequency));
                      sizeof (frequency));
            }
            }
          else
          else
            {
            {
              if (sreal_compare (&cyclic_probability, &real_almost_one) > 0)
              if (sreal_compare (&cyclic_probability, &real_almost_one) > 0)
                {
                {
                  memcpy (&cyclic_probability, &real_almost_one,
                  memcpy (&cyclic_probability, &real_almost_one,
                          sizeof (real_almost_one));
                          sizeof (real_almost_one));
                }
                }
 
 
              /* BLOCK_INFO (bb)->frequency = frequency
              /* BLOCK_INFO (bb)->frequency = frequency
                                              / (1 - cyclic_probability) */
                                              / (1 - cyclic_probability) */
 
 
              sreal_sub (&cyclic_probability, &real_one, &cyclic_probability);
              sreal_sub (&cyclic_probability, &real_one, &cyclic_probability);
              sreal_div (&BLOCK_INFO (bb)->frequency,
              sreal_div (&BLOCK_INFO (bb)->frequency,
                         &frequency, &cyclic_probability);
                         &frequency, &cyclic_probability);
            }
            }
        }
        }
 
 
      bitmap_clear_bit (tovisit, bb->index);
      bitmap_clear_bit (tovisit, bb->index);
 
 
      e = find_edge (bb, head);
      e = find_edge (bb, head);
      if (e)
      if (e)
        {
        {
          sreal tmp;
          sreal tmp;
 
 
          /* EDGE_INFO (e)->back_edge_prob
          /* EDGE_INFO (e)->back_edge_prob
             = ((e->probability * BLOCK_INFO (bb)->frequency)
             = ((e->probability * BLOCK_INFO (bb)->frequency)
             / REG_BR_PROB_BASE); */
             / REG_BR_PROB_BASE); */
 
 
          sreal_init (&tmp, e->probability, 0);
          sreal_init (&tmp, e->probability, 0);
          sreal_mul (&tmp, &tmp, &BLOCK_INFO (bb)->frequency);
          sreal_mul (&tmp, &tmp, &BLOCK_INFO (bb)->frequency);
          sreal_mul (&EDGE_INFO (e)->back_edge_prob,
          sreal_mul (&EDGE_INFO (e)->back_edge_prob,
                     &tmp, &real_inv_br_prob_base);
                     &tmp, &real_inv_br_prob_base);
        }
        }
 
 
      /* Propagate to successor blocks.  */
      /* Propagate to successor blocks.  */
      FOR_EACH_EDGE (e, ei, bb->succs)
      FOR_EACH_EDGE (e, ei, bb->succs)
        if (!(e->flags & EDGE_DFS_BACK)
        if (!(e->flags & EDGE_DFS_BACK)
            && BLOCK_INFO (e->dest)->npredecessors)
            && BLOCK_INFO (e->dest)->npredecessors)
          {
          {
            BLOCK_INFO (e->dest)->npredecessors--;
            BLOCK_INFO (e->dest)->npredecessors--;
            if (!BLOCK_INFO (e->dest)->npredecessors)
            if (!BLOCK_INFO (e->dest)->npredecessors)
              {
              {
                if (!nextbb)
                if (!nextbb)
                  nextbb = e->dest;
                  nextbb = e->dest;
                else
                else
                  BLOCK_INFO (last)->next = e->dest;
                  BLOCK_INFO (last)->next = e->dest;
 
 
                last = e->dest;
                last = e->dest;
              }
              }
          }
          }
    }
    }
}
}
 
 
/* Estimate probabilities of loopback edges in loops at same nest level.  */
/* Estimate probabilities of loopback edges in loops at same nest level.  */
 
 
static void
static void
estimate_loops_at_level (struct loop *first_loop, bitmap tovisit)
estimate_loops_at_level (struct loop *first_loop, bitmap tovisit)
{
{
  struct loop *loop;
  struct loop *loop;
 
 
  for (loop = first_loop; loop; loop = loop->next)
  for (loop = first_loop; loop; loop = loop->next)
    {
    {
      edge e;
      edge e;
      basic_block *bbs;
      basic_block *bbs;
      unsigned i;
      unsigned i;
 
 
      estimate_loops_at_level (loop->inner, tovisit);
      estimate_loops_at_level (loop->inner, tovisit);
 
 
      /* Do not do this for dummy function loop.  */
      /* Do not do this for dummy function loop.  */
      if (EDGE_COUNT (loop->latch->succs) > 0)
      if (EDGE_COUNT (loop->latch->succs) > 0)
        {
        {
          /* Find current loop back edge and mark it.  */
          /* Find current loop back edge and mark it.  */
          e = loop_latch_edge (loop);
          e = loop_latch_edge (loop);
          EDGE_INFO (e)->back_edge = 1;
          EDGE_INFO (e)->back_edge = 1;
       }
       }
 
 
      bbs = get_loop_body (loop);
      bbs = get_loop_body (loop);
      for (i = 0; i < loop->num_nodes; i++)
      for (i = 0; i < loop->num_nodes; i++)
        bitmap_set_bit (tovisit, bbs[i]->index);
        bitmap_set_bit (tovisit, bbs[i]->index);
      free (bbs);
      free (bbs);
      propagate_freq (loop, tovisit);
      propagate_freq (loop, tovisit);
    }
    }
}
}
 
 
/* Convert counts measured by profile driven feedback to frequencies.
/* Convert counts measured by profile driven feedback to frequencies.
   Return nonzero iff there was any nonzero execution count.  */
   Return nonzero iff there was any nonzero execution count.  */
 
 
int
int
counts_to_freqs (void)
counts_to_freqs (void)
{
{
  gcov_type count_max, true_count_max = 0;
  gcov_type count_max, true_count_max = 0;
  basic_block bb;
  basic_block bb;
 
 
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    true_count_max = MAX (bb->count, true_count_max);
    true_count_max = MAX (bb->count, true_count_max);
 
 
  count_max = MAX (true_count_max, 1);
  count_max = MAX (true_count_max, 1);
  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
    bb->frequency = (bb->count * BB_FREQ_MAX + count_max / 2) / count_max;
    bb->frequency = (bb->count * BB_FREQ_MAX + count_max / 2) / count_max;
  return true_count_max;
  return true_count_max;
}
}
 
 
/* Return true if function is likely to be expensive, so there is no point to
/* Return true if function is likely to be expensive, so there is no point to
   optimize performance of prologue, epilogue or do inlining at the expense
   optimize performance of prologue, epilogue or do inlining at the expense
   of code size growth.  THRESHOLD is the limit of number of instructions
   of code size growth.  THRESHOLD is the limit of number of instructions
   function can execute at average to be still considered not expensive.  */
   function can execute at average to be still considered not expensive.  */
 
 
bool
bool
expensive_function_p (int threshold)
expensive_function_p (int threshold)
{
{
  unsigned int sum = 0;
  unsigned int sum = 0;
  basic_block bb;
  basic_block bb;
  unsigned int limit;
  unsigned int limit;
 
 
  /* We can not compute accurately for large thresholds due to scaled
  /* We can not compute accurately for large thresholds due to scaled
     frequencies.  */
     frequencies.  */
  gcc_assert (threshold <= BB_FREQ_MAX);
  gcc_assert (threshold <= BB_FREQ_MAX);
 
 
  /* Frequencies are out of range.  This either means that function contains
  /* Frequencies are out of range.  This either means that function contains
     internal loop executing more than BB_FREQ_MAX times or profile feedback
     internal loop executing more than BB_FREQ_MAX times or profile feedback
     is available and function has not been executed at all.  */
     is available and function has not been executed at all.  */
  if (ENTRY_BLOCK_PTR->frequency == 0)
  if (ENTRY_BLOCK_PTR->frequency == 0)
    return true;
    return true;
 
 
  /* Maximally BB_FREQ_MAX^2 so overflow won't happen.  */
  /* Maximally BB_FREQ_MAX^2 so overflow won't happen.  */
  limit = ENTRY_BLOCK_PTR->frequency * threshold;
  limit = ENTRY_BLOCK_PTR->frequency * threshold;
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      rtx insn;
      rtx insn;
 
 
      for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
      for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
           insn = NEXT_INSN (insn))
           insn = NEXT_INSN (insn))
        if (active_insn_p (insn))
        if (active_insn_p (insn))
          {
          {
            sum += bb->frequency;
            sum += bb->frequency;
            if (sum > limit)
            if (sum > limit)
              return true;
              return true;
        }
        }
    }
    }
 
 
  return false;
  return false;
}
}
 
 
/* Estimate basic blocks frequency by given branch probabilities.  */
/* Estimate basic blocks frequency by given branch probabilities.  */
 
 
static void
static void
estimate_bb_frequencies (struct loops *loops)
estimate_bb_frequencies (struct loops *loops)
{
{
  basic_block bb;
  basic_block bb;
  sreal freq_max;
  sreal freq_max;
 
 
  if (!flag_branch_probabilities || !counts_to_freqs ())
  if (!flag_branch_probabilities || !counts_to_freqs ())
    {
    {
      static int real_values_initialized = 0;
      static int real_values_initialized = 0;
      bitmap tovisit;
      bitmap tovisit;
 
 
      if (!real_values_initialized)
      if (!real_values_initialized)
        {
        {
          real_values_initialized = 1;
          real_values_initialized = 1;
          sreal_init (&real_zero, 0, 0);
          sreal_init (&real_zero, 0, 0);
          sreal_init (&real_one, 1, 0);
          sreal_init (&real_one, 1, 0);
          sreal_init (&real_br_prob_base, REG_BR_PROB_BASE, 0);
          sreal_init (&real_br_prob_base, REG_BR_PROB_BASE, 0);
          sreal_init (&real_bb_freq_max, BB_FREQ_MAX, 0);
          sreal_init (&real_bb_freq_max, BB_FREQ_MAX, 0);
          sreal_init (&real_one_half, 1, -1);
          sreal_init (&real_one_half, 1, -1);
          sreal_div (&real_inv_br_prob_base, &real_one, &real_br_prob_base);
          sreal_div (&real_inv_br_prob_base, &real_one, &real_br_prob_base);
          sreal_sub (&real_almost_one, &real_one, &real_inv_br_prob_base);
          sreal_sub (&real_almost_one, &real_one, &real_inv_br_prob_base);
        }
        }
 
 
      mark_dfs_back_edges ();
      mark_dfs_back_edges ();
 
 
      single_succ_edge (ENTRY_BLOCK_PTR)->probability = REG_BR_PROB_BASE;
      single_succ_edge (ENTRY_BLOCK_PTR)->probability = REG_BR_PROB_BASE;
 
 
      /* Set up block info for each basic block.  */
      /* Set up block info for each basic block.  */
      tovisit = BITMAP_ALLOC (NULL);
      tovisit = BITMAP_ALLOC (NULL);
      alloc_aux_for_blocks (sizeof (struct block_info_def));
      alloc_aux_for_blocks (sizeof (struct block_info_def));
      alloc_aux_for_edges (sizeof (struct edge_info_def));
      alloc_aux_for_edges (sizeof (struct edge_info_def));
      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
        {
        {
          edge e;
          edge e;
          edge_iterator ei;
          edge_iterator ei;
 
 
          FOR_EACH_EDGE (e, ei, bb->succs)
          FOR_EACH_EDGE (e, ei, bb->succs)
            {
            {
              sreal_init (&EDGE_INFO (e)->back_edge_prob, e->probability, 0);
              sreal_init (&EDGE_INFO (e)->back_edge_prob, e->probability, 0);
              sreal_mul (&EDGE_INFO (e)->back_edge_prob,
              sreal_mul (&EDGE_INFO (e)->back_edge_prob,
                         &EDGE_INFO (e)->back_edge_prob,
                         &EDGE_INFO (e)->back_edge_prob,
                         &real_inv_br_prob_base);
                         &real_inv_br_prob_base);
            }
            }
        }
        }
 
 
      /* First compute probabilities locally for each loop from innermost
      /* First compute probabilities locally for each loop from innermost
         to outermost to examine probabilities for back edges.  */
         to outermost to examine probabilities for back edges.  */
      estimate_loops_at_level (loops->tree_root, tovisit);
      estimate_loops_at_level (loops->tree_root, tovisit);
 
 
      memcpy (&freq_max, &real_zero, sizeof (real_zero));
      memcpy (&freq_max, &real_zero, sizeof (real_zero));
      FOR_EACH_BB (bb)
      FOR_EACH_BB (bb)
        if (sreal_compare (&freq_max, &BLOCK_INFO (bb)->frequency) < 0)
        if (sreal_compare (&freq_max, &BLOCK_INFO (bb)->frequency) < 0)
          memcpy (&freq_max, &BLOCK_INFO (bb)->frequency, sizeof (freq_max));
          memcpy (&freq_max, &BLOCK_INFO (bb)->frequency, sizeof (freq_max));
 
 
      sreal_div (&freq_max, &real_bb_freq_max, &freq_max);
      sreal_div (&freq_max, &real_bb_freq_max, &freq_max);
      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
        {
        {
          sreal tmp;
          sreal tmp;
 
 
          sreal_mul (&tmp, &BLOCK_INFO (bb)->frequency, &freq_max);
          sreal_mul (&tmp, &BLOCK_INFO (bb)->frequency, &freq_max);
          sreal_add (&tmp, &tmp, &real_one_half);
          sreal_add (&tmp, &tmp, &real_one_half);
          bb->frequency = sreal_to_int (&tmp);
          bb->frequency = sreal_to_int (&tmp);
        }
        }
 
 
      free_aux_for_blocks ();
      free_aux_for_blocks ();
      free_aux_for_edges ();
      free_aux_for_edges ();
      BITMAP_FREE (tovisit);
      BITMAP_FREE (tovisit);
    }
    }
  compute_function_frequency ();
  compute_function_frequency ();
  if (flag_reorder_functions)
  if (flag_reorder_functions)
    choose_function_section ();
    choose_function_section ();
}
}
 
 
/* Decide whether function is hot, cold or unlikely executed.  */
/* Decide whether function is hot, cold or unlikely executed.  */
static void
static void
compute_function_frequency (void)
compute_function_frequency (void)
{
{
  basic_block bb;
  basic_block bb;
 
 
  if (!profile_info || !flag_branch_probabilities)
  if (!profile_info || !flag_branch_probabilities)
    return;
    return;
  cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED;
  cfun->function_frequency = FUNCTION_FREQUENCY_UNLIKELY_EXECUTED;
  FOR_EACH_BB (bb)
  FOR_EACH_BB (bb)
    {
    {
      if (maybe_hot_bb_p (bb))
      if (maybe_hot_bb_p (bb))
        {
        {
          cfun->function_frequency = FUNCTION_FREQUENCY_HOT;
          cfun->function_frequency = FUNCTION_FREQUENCY_HOT;
          return;
          return;
        }
        }
      if (!probably_never_executed_bb_p (bb))
      if (!probably_never_executed_bb_p (bb))
        cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
        cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
    }
    }
}
}
 
 
/* Choose appropriate section for the function.  */
/* Choose appropriate section for the function.  */
static void
static void
choose_function_section (void)
choose_function_section (void)
{
{
  if (DECL_SECTION_NAME (current_function_decl)
  if (DECL_SECTION_NAME (current_function_decl)
      || !targetm.have_named_sections
      || !targetm.have_named_sections
      /* Theoretically we can split the gnu.linkonce text section too,
      /* Theoretically we can split the gnu.linkonce text section too,
         but this requires more work as the frequency needs to match
         but this requires more work as the frequency needs to match
         for all generated objects so we need to merge the frequency
         for all generated objects so we need to merge the frequency
         of all instances.  For now just never set frequency for these.  */
         of all instances.  For now just never set frequency for these.  */
      || DECL_ONE_ONLY (current_function_decl))
      || DECL_ONE_ONLY (current_function_decl))
    return;
    return;
 
 
  /* If we are doing the partitioning optimization, let the optimization
  /* If we are doing the partitioning optimization, let the optimization
     choose the correct section into which to put things.  */
     choose the correct section into which to put things.  */
 
 
  if (flag_reorder_blocks_and_partition)
  if (flag_reorder_blocks_and_partition)
    return;
    return;
 
 
  if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT)
  if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT)
    DECL_SECTION_NAME (current_function_decl) =
    DECL_SECTION_NAME (current_function_decl) =
      build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME);
      build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME);
  if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
  if (cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED)
    DECL_SECTION_NAME (current_function_decl) =
    DECL_SECTION_NAME (current_function_decl) =
      build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME),
      build_string (strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME),
                    UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
                    UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
}
}
 
 
static bool
static bool
gate_estimate_probability (void)
gate_estimate_probability (void)
{
{
  return flag_guess_branch_prob;
  return flag_guess_branch_prob;
}
}
 
 
struct tree_opt_pass pass_profile =
struct tree_opt_pass pass_profile =
{
{
  "profile",                            /* name */
  "profile",                            /* name */
  gate_estimate_probability,            /* gate */
  gate_estimate_probability,            /* gate */
  tree_estimate_probability,            /* execute */
  tree_estimate_probability,            /* execute */
  NULL,                                 /* sub */
  NULL,                                 /* sub */
  NULL,                                 /* next */
  NULL,                                 /* next */
  0,                                     /* static_pass_number */
  0,                                     /* static_pass_number */
  TV_BRANCH_PROB,                       /* tv_id */
  TV_BRANCH_PROB,                       /* tv_id */
  PROP_cfg,                             /* properties_required */
  PROP_cfg,                             /* properties_required */
  0,                                     /* properties_provided */
  0,                                     /* properties_provided */
  0,                                     /* properties_destroyed */
  0,                                     /* properties_destroyed */
  0,                                     /* todo_flags_start */
  0,                                     /* todo_flags_start */
  TODO_ggc_collect | TODO_verify_ssa,                   /* todo_flags_finish */
  TODO_ggc_collect | TODO_verify_ssa,                   /* todo_flags_finish */
  0                                      /* letter */
  0                                      /* letter */
};
};
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.