예제 #1
0
/* Unswitch single LOOP.  COND_CHECKED holds list of conditions we already
   unswitched on and are therefore known to be true in this LOOP.  NUM is
   number of unswitchings done; do not allow it to grow too much, it is too
   easy to create example on that the code would grow exponentially.
   Returns true LOOP was unswitched.  */
static bool 
unswitch_single_loop (struct loop *loop, rtx cond_checked, int num)
{
  basic_block *bbs;
  struct loop *nloop;
  unsigned i;
  rtx cond, rcond = NULL_RTX, conds, rconds, acond, cinsn;
  int repeat;
  edge e;
  HOST_WIDE_INT iterations;

  /* Do not unswitch too much.  */
  if (num > PARAM_VALUE (PARAM_MAX_UNSWITCH_LEVEL))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching anymore, hit max level\n");
      return false;
    }

  /* Only unswitch innermost loops.  */
  if (loop->inner)
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, not innermost loop\n");
      return false;
    }

  /* We must be able to duplicate loop body.  */
  if (!can_duplicate_loop_p (loop))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, can't duplicate loop\n");
      return false;
    }

  /* The loop should not be too large, to limit code growth.  */
  if (num_loop_insns (loop) > PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, loop too big\n");
      return false;
    }

  /* Do not unswitch in cold areas.  */
  if (optimize_loop_for_size_p (loop))
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, not hot area\n");
      return false;
    }

  /* Nor if the loop usually does not roll.  */
  iterations = estimated_loop_iterations_int (loop);
  if (iterations >= 0 && iterations <= 1)
    {
      if (dump_file)
	fprintf (dump_file, ";; Not unswitching, loop iterations < 1\n");
      return false;
    }

  do
    {
      repeat = 0;
      cinsn = NULL_RTX;

      /* Find a bb to unswitch on.  */
      bbs = get_loop_body (loop);
      iv_analysis_loop_init (loop);
      for (i = 0; i < loop->num_nodes; i++)
	if ((cond = may_unswitch_on (bbs[i], loop, &cinsn)))
	  break;

      if (i == loop->num_nodes)
	{
	  free (bbs);
	  return false;
	}

      if (cond != const0_rtx
	  && cond != const_true_rtx)
	{
	  rcond = reversed_condition (cond);
	  if (rcond)
	    rcond = canon_condition (rcond);

	  /* Check whether the result can be predicted.  */
	  for (acond = cond_checked; acond; acond = XEXP (acond, 1))
	    simplify_using_condition (XEXP (acond, 0), &cond, NULL);
	}

      if (cond == const_true_rtx)
	{
	  /* Remove false path.  */
	  e = FALLTHRU_EDGE (bbs[i]);
	  remove_path (e);
	  free (bbs);
	  repeat = 1;
	}
      else if (cond == const0_rtx)
	{
	  /* Remove true path.  */
	  e = BRANCH_EDGE (bbs[i]);
	  remove_path (e);
	  free (bbs);
	  repeat = 1;
	}
    } while (repeat);

  /* We found the condition we can unswitch on.  */
  conds = alloc_EXPR_LIST (0, cond, cond_checked);
  if (rcond)
    rconds = alloc_EXPR_LIST (0, rcond, cond_checked);
  else
    rconds = cond_checked;

  if (dump_file)
    fprintf (dump_file, ";; Unswitching loop\n");

  /* Unswitch the loop on this condition.  */
  nloop = unswitch_loop (loop, bbs[i], copy_rtx_if_shared (cond), cinsn);
  gcc_assert (nloop);

  /* Invoke itself on modified loops.  */
  unswitch_single_loop (nloop, rconds, num + 1);
  unswitch_single_loop (loop, conds, num + 1);

  free_EXPR_LIST_node (conds);
  if (rcond)
    free_EXPR_LIST_node (rconds);

  free (bbs);

  return true;
}
예제 #2
0
static bool
doloop_optimize (struct loop *loop)
{
    enum machine_mode mode;
    rtx doloop_seq, doloop_pat, doloop_reg;
    rtx iterations, count;
    rtx iterations_max;
    rtx start_label;
    rtx condition;
    unsigned level, est_niter;
    struct niter_desc *desc;
    unsigned word_mode_size;
    unsigned HOST_WIDE_INT word_mode_max;

    if (dump_file)
        fprintf (dump_file, "Doloop: Processing loop %d.\n", loop->num);

    /* APPLE LOCAL begin lno */
    /* Ignore large loops.  */
    if (loop->ninsns > (unsigned) PARAM_VALUE (PARAM_MAX_DOLOOP_INSNS))
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: The loop is too large.\n");
        return false;
    }
    /* APPLE LOCAL end lno */

    iv_analysis_loop_init (loop);

    /* Find the simple exit of a LOOP.  */
    desc = get_simple_loop_desc (loop);

    /* Check that loop is a candidate for a low-overhead looping insn.  */
    if (!doloop_valid_p (loop, desc))
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: The loop is not suitable.\n");
        return false;
    }
    mode = desc->mode;

    est_niter = 3;
    if (desc->const_iter)
        est_niter = desc->niter;
    /* If the estimate on number of iterations is reliable (comes from profile
       feedback), use it.  Do not use it normally, since the expected number
       of iterations of an unrolled loop is 2.  */
    if (loop->header->count)
        est_niter = expected_loop_iterations (loop);

    if (est_niter < 3)
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: Too few iterations (%u) to be profitable.\n",
                     est_niter);
        return false;
    }

    count = copy_rtx (desc->niter_expr);
    iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
    iterations_max = GEN_INT (desc->niter_max);
    level = get_loop_level (loop) + 1;

    /* Generate looping insn.  If the pattern FAILs then give up trying
       to modify the loop since there is some aspect the back-end does
       not like.  */
    start_label = block_label (desc->in_edge->dest);
    doloop_reg = gen_reg_rtx (mode);
    doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
                                 GEN_INT (level), start_label);

    word_mode_size = GET_MODE_BITSIZE (word_mode);
    word_mode_max
        = ((unsigned HOST_WIDE_INT) 1 << (word_mode_size - 1) << 1) - 1;
    if (! doloop_seq
            && mode != word_mode
            /* Before trying mode different from the one in that # of iterations is
            computed, we must be sure that the number of iterations fits into
             the new mode.  */
            && (word_mode_size >= GET_MODE_BITSIZE (mode)
                || desc->niter_max <= word_mode_max))
    {
        if (word_mode_size > GET_MODE_BITSIZE (mode))
        {
            count = simplify_gen_unary (ZERO_EXTEND, word_mode,
                                        count, mode);
            iterations = simplify_gen_unary (ZERO_EXTEND, word_mode,
                                             iterations, mode);
            iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode,
                                                 iterations_max, mode);
        }
        else
        {
            count = lowpart_subreg (word_mode, count, mode);
            iterations = lowpart_subreg (word_mode, iterations, mode);
            iterations_max = lowpart_subreg (word_mode, iterations_max, mode);
        }
        PUT_MODE (doloop_reg, word_mode);
        doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max,
                                     GEN_INT (level), start_label);
    }
    if (! doloop_seq)
    {
        if (dump_file)
            fprintf (dump_file,
                     "Doloop: Target unwilling to use doloop pattern!\n");
        return false;
    }

    /* If multiple instructions were created, the last must be the
       jump instruction.  Also, a raw define_insn may yield a plain
       pattern.  */
    doloop_pat = doloop_seq;
    if (INSN_P (doloop_pat))
    {
        while (NEXT_INSN (doloop_pat) != NULL_RTX)
            doloop_pat = NEXT_INSN (doloop_pat);
        if (JUMP_P (doloop_pat))
            doloop_pat = PATTERN (doloop_pat);
        else
            doloop_pat = NULL_RTX;
    }

    if (! doloop_pat
            || ! (condition = doloop_condition_get (doloop_pat)))
    {
        if (dump_file)
            fprintf (dump_file, "Doloop: Unrecognizable doloop pattern!\n");
        return false;
    }

    doloop_modify (loop, desc, doloop_seq, condition, count);
    return true;
}