Beispiel #1
0
static unsigned
determine_unroll_factor (struct loop *loop, struct mem_ref_group *refs,
                         unsigned ahead, unsigned ninsns,
                         struct tree_niter_desc *desc)
{
    unsigned upper_bound, size_factor, constraint_factor;
    unsigned factor, max_mod_constraint, ahead_factor;
    struct mem_ref_group *agp;
    struct mem_ref *ref;

    upper_bound = PARAM_VALUE (PARAM_MAX_UNROLL_TIMES);

    /* First check whether the loop is not too large to unroll.  */
    size_factor = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / ninsns;
    if (size_factor <= 1)
        return 1;

    if (size_factor < upper_bound)
        upper_bound = size_factor;

    max_mod_constraint = 1;
    for (agp = refs; agp; agp = agp->next)
        for (ref = agp->refs; ref; ref = ref->next)
            if (should_issue_prefetch_p (ref)
                    && ref->prefetch_mod > max_mod_constraint)
                max_mod_constraint = ref->prefetch_mod;

    /* Set constraint_factor as large as needed to be able to satisfy the
       largest modulo constraint.  */
    constraint_factor = max_mod_constraint;

    /* If ahead is too large in comparison with the number of available
       prefetches, unroll the loop as much as needed to be able to prefetch
       at least partially some of the references in the loop.  */
    ahead_factor = ((ahead + SIMULTANEOUS_PREFETCHES - 1)
                    / SIMULTANEOUS_PREFETCHES);

    /* Unroll as much as useful, but bound the code size growth.  */
    if (constraint_factor < ahead_factor)
        factor = ahead_factor;
    else
        factor = constraint_factor;
    if (factor > upper_bound)
        factor = upper_bound;

    if (!should_unroll_loop_p (loop, desc, factor))
        return 1;

    return factor;
}
Beispiel #2
0
static unsigned
determine_unroll_factor (struct loop *loop, struct mem_ref_group *refs,
			 unsigned ninsns, struct tree_niter_desc *desc,
			 HOST_WIDE_INT est_niter)
{
  unsigned upper_bound;
  unsigned nfactor, factor, mod_constraint;
  struct mem_ref_group *agp;
  struct mem_ref *ref;

  /* First check whether the loop is not too large to unroll.  We ignore
     PARAM_MAX_UNROLL_TIMES, because for small loops, it prevented us
     from unrolling them enough to make exactly one cache line covered by each
     iteration.  Also, the goal of PARAM_MAX_UNROLL_TIMES is to prevent
     us from unrolling the loops too many times in cases where we only expect
     gains from better scheduling and decreasing loop overhead, which is not
     the case here.  */
  upper_bound = PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS) / ninsns;

  /* If we unrolled the loop more times than it iterates, the unrolled version
     of the loop would be never entered.  */
  if (est_niter >= 0 && est_niter < (HOST_WIDE_INT) upper_bound)
    upper_bound = est_niter;

  if (upper_bound <= 1)
    return 1;

  /* Choose the factor so that we may prefetch each cache just once,
     but bound the unrolling by UPPER_BOUND.  */
  factor = 1;
  for (agp = refs; agp; agp = agp->next)
    for (ref = agp->refs; ref; ref = ref->next)
      if (should_issue_prefetch_p (ref))
	{
	  mod_constraint = ref->prefetch_mod;
	  nfactor = least_common_multiple (mod_constraint, factor);
	  if (nfactor <= upper_bound)
	    factor = nfactor;
	}

  if (!should_unroll_loop_p (loop, desc, factor))
    return 1;

  return factor;
}