예제 #1
0
/* Return true if we should ignore the basic block for purposes of tracing.  */
static bool
ignore_bb_p (basic_block bb)
{
  if (bb->index < NUM_FIXED_BLOCKS)
    return true;
  if (!maybe_hot_bb_p (bb))
    return true;
  return false;
}
예제 #2
0
/* Return true if we should ignore the basic block for purposes of tracing.  */
static bool
ignore_bb_p (basic_block bb)
{
  if (bb->index < 0)
    return true;
  if (!maybe_hot_bb_p (bb))
    return true;
  return false;
}
static inline int 
coalesce_cost_edge (edge e)
{
  if (e->flags & EDGE_ABNORMAL)
    return MUST_COALESCE_COST;

  return coalesce_cost (EDGE_FREQUENCY (e), 
			maybe_hot_bb_p (e->src), 
			EDGE_CRITICAL_P (e));
}
예제 #4
0
static bool
rtl_value_profile_transformations (void)
{
  rtx insn, next;
  int changed = false;

  for (insn = get_insns (); insn; insn = next)
    {
      next = NEXT_INSN (insn);

      if (!INSN_P (insn))
	continue;

      /* Scan for insn carrying a histogram.  */
      if (!find_reg_note (insn, REG_VALUE_PROFILE, 0))
	continue;

      /* Ignore cold areas -- we are growing a code.  */
      if (!maybe_hot_bb_p (BLOCK_FOR_INSN (insn)))
	continue;

      if (dump_file)
	{
	  fprintf (dump_file, "Trying transformations on insn %d\n",
		   INSN_UID (insn));
	  print_rtl_single (dump_file, insn);
	}

      /* Transformations:  */
      if (flag_value_profile_transformations
	  && (mod_subtract_transform (insn)
	      || divmod_fixed_value_transform (insn)
	      || mod_pow2_value_transform (insn)))
	changed = true;
#ifdef HAVE_prefetch
      if (flag_speculative_prefetching
	  && speculative_prefetching_transform (insn))
	changed = true;
#endif
    }

  if (changed)
    {
      commit_edge_insertions ();
      allocate_reg_info (max_reg_num (), FALSE, FALSE);
    }

  return changed;
}
예제 #5
0
static bool
copy_bb_p (basic_block bb, int code_may_grow)
{
  int size = 0;
  int max_size = uncond_jump_length;
  rtx insn;
  int n_succ;
  edge e;

  if (!bb->frequency)
    return false;
  if (!bb->pred || !bb->pred->pred_next)
    return false;
  if (!cfg_layout_can_duplicate_bb_p (bb))
    return false;

  /* Avoid duplicating blocks which have many successors (PR/13430).  */
  n_succ = 0;
  for (e = bb->succ; e; e = e->succ_next)
    {
      n_succ++;
      if (n_succ > 8)
	return false;
    }

  if (code_may_grow && maybe_hot_bb_p (bb))
    max_size *= 8;

  for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
       insn = NEXT_INSN (insn))
    {
      if (INSN_P (insn))
	size += get_attr_length (insn);
    }

  if (size <= max_size)
    return true;

  if (rtl_dump_file)
    {
      fprintf (rtl_dump_file,
	       "Block %d can't be copied because its size = %d.\n",
	       bb->index, size);
    }

  return false;
}
static inline int 
coalesce_cost_bb (basic_block bb)
{
  return coalesce_cost (bb->frequency, maybe_hot_bb_p (bb), false);
}
예제 #7
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.  */
static void
unswitch_single_loop (struct loops *loops, 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;

    /* 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;
    }

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

    /* 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;
    }

    /* 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;
    }

    /* Do not unswitch in cold areas.  */
    if (!maybe_hot_bb_p (loop->header))
    {
        if (dump_file)
            fprintf (dump_file, ";; Not unswitching, not hot area\n");
        return;
    }

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

    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;
        }

        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 (loops, e);
            free (bbs);
            repeat = 1;
        }
        else if (cond == const0_rtx)
        {
            /* Remove true path.  */
            e = BRANCH_EDGE (bbs[i]);
            remove_path (loops, 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 (loops, loop, bbs[i], cond, cinsn);
    gcc_assert (nloop);

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

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

    free (bbs);
}
예제 #8
0
static bool
speculative_prefetching_transform (rtx insn)
{
  rtx histogram, value;
  gcov_type val, count, all;
  edge e;
  rtx mem, address;
  int write;

  if (!maybe_hot_bb_p (BLOCK_FOR_INSN (insn)))
    return false;

  if (!find_mem_reference (insn, &mem, &write))
    return false;

  address = XEXP (mem, 0);
  if (side_effects_p (address))
    return false;
      
  if (CONSTANT_P (address))
    return false;

  for (histogram = REG_NOTES (insn);
       histogram;
       histogram = XEXP (histogram, 1))
    if (REG_NOTE_KIND (histogram) == REG_VALUE_PROFILE
	&& XEXP (XEXP (histogram, 0), 0) == GEN_INT (HIST_TYPE_CONST_DELTA))
      break;

  if (!histogram)
    return false;

  histogram = XEXP (XEXP (histogram, 0), 1);
  value = XEXP (histogram, 0);
  histogram = XEXP (histogram, 1);
  /* Skip last value referenced.  */
  histogram = XEXP (histogram, 1);
  val = INTVAL (XEXP (histogram, 0));
  histogram = XEXP (histogram, 1);
  count = INTVAL (XEXP (histogram, 0));
  histogram = XEXP (histogram, 1);
  all = INTVAL (XEXP (histogram, 0));

  /* With that few executions we do not really have a reason to optimize the
     statement, and more importantly, the data about differences of addresses
     are spoiled by the first item that had no previous value to compare
     with.  */
  if (all < 4)
    return false;

  /* We require that count be at least half of all; this means
     that for the transformation to fire the value must be constant
     at least 50% of time (and 75% gives the guarantee of usage).  */
  if (!rtx_equal_p (address, value) || 2 * count < all)
    return false;

  /* If the difference is too small, it does not make too much sense to
     prefetch, as the memory is probably already in cache.  */
  if (val >= NOPREFETCH_RANGE_MIN && val <= NOPREFETCH_RANGE_MAX)
    return false;

  if (dump_file)
    fprintf (dump_file, "Speculative prefetching for insn %d\n",
	     INSN_UID (insn));

  e = split_block (BLOCK_FOR_INSN (insn), PREV_INSN (insn));
  
  insert_insn_on_edge (gen_speculative_prefetch (address, val, write), e);

  return true;
}
static bool
loop_prefetch_arrays (struct loop *loop)
{
  struct mem_ref_group *refs;
  unsigned ahead, ninsns, time, unroll_factor;
  HOST_WIDE_INT est_niter;
  struct tree_niter_desc desc;
  bool unrolled = false, no_other_refs;

  if (!maybe_hot_bb_p (loop->header))
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "  ignored (cold area)\n");
      return false;
    }

  /* Step 1: gather the memory references.  */
  refs = gather_memory_references (loop, &no_other_refs);

  /* Step 2: estimate the reuse effects.  */
  prune_by_reuse (refs);

  if (!anything_to_prefetch_p (refs))
    goto fail;

  determine_loop_nest_reuse (loop, refs, no_other_refs);

  /* Step 3: determine the ahead and unroll factor.  */

  /* FIXME: the time should be weighted by the probabilities of the blocks in
     the loop body.  */
  time = tree_num_loop_insns (loop, &eni_time_weights);
  ahead = (PREFETCH_LATENCY + time - 1) / time;
  est_niter = estimated_loop_iterations_int (loop, false);

  /* The prefetches will run for AHEAD iterations of the original loop.  Unless
     the loop rolls at least AHEAD times, prefetching the references does not
     make sense.  */
  if (est_niter >= 0 && est_niter <= (HOST_WIDE_INT) ahead)
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file,
		 "Not prefetching -- loop estimated to roll only %d times\n",
		 (int) est_niter);
      goto fail;
    }

  mark_nontemporal_stores (loop, refs);

  ninsns = tree_num_loop_insns (loop, &eni_size_weights);
  unroll_factor = determine_unroll_factor (loop, refs, ninsns, &desc,
					   est_niter);
  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "Ahead %d, unroll factor %d\n", ahead, unroll_factor);

  /* Step 4: what to prefetch?  */
  if (!schedule_prefetches (refs, unroll_factor, ahead))
    goto fail;

  /* Step 5: unroll the loop.  TODO -- peeling of first and last few
     iterations so that we do not issue superfluous prefetches.  */
  if (unroll_factor != 1)
    {
      tree_unroll_loop (loop, unroll_factor,
			single_dom_exit (loop), &desc);
      unrolled = true;
    }

  /* Step 6: issue the prefetches.  */
  issue_prefetches (refs, unroll_factor, ahead);

fail:
  release_mem_refs (refs);
  return unrolled;
}